summaryrefslogtreecommitdiff
path: root/bin/ksh
diff options
context:
space:
mode:
Diffstat (limited to 'bin/ksh')
-rw-r--r--bin/ksh/BUG-REPORTS110
-rw-r--r--bin/ksh/CONTRIBUTORS6
-rw-r--r--bin/ksh/ChangeLog244
-rw-r--r--bin/ksh/IAFA-PACKAGE4
-rw-r--r--bin/ksh/NEWS37
-rw-r--r--bin/ksh/NOTES29
-rw-r--r--bin/ksh/PROJECTS26
-rw-r--r--bin/ksh/README4
-rw-r--r--bin/ksh/c_ksh.c63
-rw-r--r--bin/ksh/c_sh.c78
-rw-r--r--bin/ksh/c_test.c7
-rw-r--r--bin/ksh/edit.c204
-rw-r--r--bin/ksh/edit.h7
-rw-r--r--bin/ksh/emacs.c80
-rw-r--r--bin/ksh/eval.c6
-rw-r--r--bin/ksh/exec.c312
-rw-r--r--bin/ksh/expr.c148
-rw-r--r--bin/ksh/io.c22
-rw-r--r--bin/ksh/jobs.c77
-rw-r--r--bin/ksh/ksh_stat.h3
-rw-r--r--bin/ksh/lex.c13
-rw-r--r--bin/ksh/mail.c6
-rw-r--r--bin/ksh/main.c12
-rw-r--r--bin/ksh/misc.c12
-rw-r--r--bin/ksh/proto.h17
-rw-r--r--bin/ksh/sh.h48
-rw-r--r--bin/ksh/syn.c13
-rw-r--r--bin/ksh/table.c6
-rw-r--r--bin/ksh/table.h16
-rw-r--r--bin/ksh/tests/arith.t79
-rw-r--r--bin/ksh/tests/regress.t24
-rw-r--r--bin/ksh/tests/th8
-rw-r--r--bin/ksh/tests/th.sh8
-rw-r--r--bin/ksh/tests/version.t2
-rw-r--r--bin/ksh/trap.c49
-rw-r--r--bin/ksh/tree.c4
-rw-r--r--bin/ksh/tree.h9
-rw-r--r--bin/ksh/var.c79
-rw-r--r--bin/ksh/version.c4
-rw-r--r--bin/ksh/vi.c59
40 files changed, 1404 insertions, 531 deletions
diff --git a/bin/ksh/BUG-REPORTS b/bin/ksh/BUG-REPORTS
index 2b98b829d48..f889fe108a8 100644
--- a/bin/ksh/BUG-REPORTS
+++ b/bin/ksh/BUG-REPORTS
@@ -1,4 +1,4 @@
-$OpenBSD: BUG-REPORTS,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: BUG-REPORTS,v 1.2 1996/08/19 20:08:39 downsj 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 *,
@@ -23,7 +23,7 @@ problems believed to be fixed marked by x.
* pdksh 5.0.8, - (reported by Sean Hogan): attempting file name completion
on a word with a single backquote causes a "no closing quote" error and
- looses the partially entered command (vi mode).
+ loses the partially entered command (vi mode).
[see Mail.2:48]
* pdksh 5.0.10, - (reported by Andrew Moore): no overflow checking is done
@@ -47,7 +47,7 @@ problems believed to be fixed marked by x.
shell (at&t ksh will).
[see Mail.7:32,Mail.9:65]
-* pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have \ as quote
+* pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs/vi doesn't have \ as quote
character.
[see Mail.7:87]
@@ -65,7 +65,6 @@ problems believed to be fixed marked by x.
* enhancements that haven't been merged yet
- Mail.6:36-39,78,84 recursive function diffs
- - Mail.7:7 partial sigwinch diffs
* pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= on word with ~
but no /, beeps (or prints final path comonent?).
@@ -84,11 +83,24 @@ problems believed to be fixed marked by x.
multiline commands - should go to start of command.
[see Mail.XXX:XXX]
-* pdksh 5.2.5, - (reported by Adrian M): configuration on Linux FT fails.
+* pdksh 5.2.5, - (reported by Adrian Marsh): configuration on Linux FT fails.
Caused by configure script using -g flag - gcc passes -lg to ld, ld fails
to find -lg (autoconf or Linux FT bug).
[see Mail.XXX:XXX]
+* pdksh 5.2.7, - (reported by Adrian Marsh): typeset -L20u xxx is ok is ksh88
+ but not in pdksh.
+ [see Mail.XXX:XXX]
+
+* pdksh 5.2.7, - (reported by Gabor Zahemszky): TMOUT doesn't effect
+ select and read operations.
+ [see Mail.XXX:XXX]
+
+* pdksh 5.2.7, - (reported by Gabor Zahemszky): exec 3<&p doesn't close
+ shells copy of the coprocess file desc.
+ [see Mail.XXX:XXX]
+
+
--------------------- put fixed problems below this line ---------------------
x pdksh 5.0.3, NetBSD 0.9a (reported by Simon J. Gerraty): pipelines
@@ -926,3 +938,91 @@ x pdksh 5.2.5, - (reported by Gabor Zahemszky): vi: # removes comment
and executes if command already commented.
[see Mail.XXX:XXX]
[fixed in 5.2.6: added vi.c(do_comment)]
+
+x pdksh 5.2.7, - (reported by Adrian Marsh): test doesn't have == operator.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: added == to c_test.c operator table]
+
+x pdksh 5.2.7, - (reported by Mike Jetzer): pdksh sets/exports COLUMNS/LINES
+ which causes applications not to respond to window size changes.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: COLUMNS/LINES no longer exported automatically]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): getopts sets OPTIND differently
+ that at&t ksh when a bad option is given.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: OPTIND not set if option was bad - fragile fix - may go away]
+
+x pdksh 5.2.7, - (reported with fix by Marc Olzheim): sh version shouldn't
+ have mail check stuff, macro expansion in PS[0-9].
+ [fixed in 5.2.8: added lots of ifdefs]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): sub commands in PS1 cause
+ a warning message to be printed.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: lex.c(set_prompt) - don't print the warning message]
+
+x pdksh 5.2.7, - (reported by Tom Watson): some environment variables
+ (eg, PATH) are converted to uppercase on 16-bit int machine.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: struct tbl.flag (32 bit thing) was being treated as an
+ int in some places]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): unset always returns 0 - should
+ return 1 if variable/function is not set.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: fixed c_sh.c(c_unset)]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): select should only print the
+ menu the first time, if REPLAY is empty, or if a blank line is entered.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: fixed up exec.c(execute,do_selectargs)]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): shell reports "cannot execute"
+ error if file exists, even if . not in path.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: fixed up exec.c(comexec)]
+
+x pdksh 5.1.3, - (reported with partial fix by ra@rhi.hi.is): shell doesn't
+ listen to sigwinch.
+ [see Mail.7:7 and related]
+ [fixed in 5.2.8: changed edit.c(x_init) to catch sigwinch]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): typeset doesn't report
+ variables that have attributes (like export) but no values.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: fixed up c_ksh.c(c_typeset)]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): error message printed as
+ a result of "set -o nounset" is different from at7t ksh.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: fixed error messges in eval.c]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): vi/emacs: when listing
+ command/file completions, should go back at most one space. Also, should
+ allow completions on zero length names.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: fixed edit.c(x_locate_word); now allows zero-length
+ file completions (but not command)]
+
+* pdksh 5.2.7, - (reported by Gabor Zahemszky): emacs: <esc># doesn't do
+ the comment thing.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: added emacs.c(x_comment) et al.]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): arithmatic expressions
+ containing variables not expanded as in at&t ksh. eg, "x=1+2, let y=x"
+ fails.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: added evaling/INEXPREVAL/ET_RECURSIVE code to expr.c]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): unsetting the 0th element
+ of an array kills the whole array.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: var.c(unset) - allow ARRAY to be preserved]
+
+x pdksh 5.2.7, - (reported by Gabor Zahemszky): unsetting a function while
+ it is being executed can result in core dump.
+ [see Mail.XXX:XXX]
+ [fixed in 5.2.8: table.c(texpand) - dont free if FINUSE is set]
+
diff --git a/bin/ksh/CONTRIBUTORS b/bin/ksh/CONTRIBUTORS
index 3b549ca6a3c..34a1e6e6caa 100644
--- a/bin/ksh/CONTRIBUTORS
+++ b/bin/ksh/CONTRIBUTORS
@@ -1,4 +1,4 @@
-$OpenBSD: CONTRIBUTORS,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: CONTRIBUTORS,v 1.2 1996/08/19 20:08:40 downsj 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
@@ -87,7 +87,11 @@ Other contributors:
* Paul Borman (<prb@bsdi.com>): j_exit: send HUP, then CONT; HUP fg process.
* DaviD W. Sanderson (<dws@ssec.wisc.edu>): patches to allow { .. } instead
of in .. esac in case statements.
+ * ? (<ra@rhi.hi.is>): partial patches to handle SIGWINCH for command line
+ editing.
* Jason Tyler (<jason@nc.bhpese.oz.au>): fixes for bugs in fc.
* 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.
diff --git a/bin/ksh/ChangeLog b/bin/ksh/ChangeLog
index 430eaebb5dc..a5bab4fa1f0 100644
--- a/bin/ksh/ChangeLog
+++ b/bin/ksh/ChangeLog
@@ -1,8 +1,248 @@
-$OpenBSD: ChangeLog,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: ChangeLog,v 1.2 1996/08/19 20:08:41 downsj Exp $
+
+Mon Aug 19 14:26:08 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * made pdksh-5.2.8 distribution
+
+Mon Aug 19 11:38:16 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * table.c(texpand): don't free entry if FINUSE is set.
+
+ * var.c(unset): preserve ARRAY and DEFINED if unsetting foo[0].
+
+Thu Aug 15 15:08:52 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * jobs.c(sm_sigchld,sm_default): moved to sh.h.
+ * sh.h(Coproc_id, struct coproc): new typedef; added njobs and
+ id fields to struct coproc.
+ * exec.c(execute): case TCOPROC: re-did coprocess stuff to use
+ njobs/coprocess id.
+ * jobs.c(struct Job): added coproc_id field.
+ * jobs.c(exchild): initialize coproc_id to 0; set job coproc_id
+ and increment coproc.njobs in parent.
+ * jobs.c(checkjob): check coproc_id and close co-process input/output
+ if needed.
+
+ * exec.c(iosetup): only play with coprocess fds if this is an
+ empty exec.
+ * c_sh.c(c_read): commented out coproc_readw_close() call and eof call.
+ * c_ksh.c(c_print): commented out closing coprocess fd on EPIPE.
+
+ * jobs.c(exchild): in parent, last part of job: use orig_flags (not
+ flags) when checking XCOPROC.
+
+Thu Aug 15 15:00:42 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * io.c(get_coproc_fd,cleanup_coproc): renamed to coproc_getfd() and
+ coproc_cleanup(), respecitively; changed all calls.
+
+Tue Aug 13 16:56:59 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * expr.c(O_COMMA,P_COMMA): new enums.
+ * expr.c(evalexpr): added case for O_COMMA.
+
+Tue Aug 13 15:18:28 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * expr.c(do_ppmm): new function to handle ++/--.
+ * expr.c(evalexpr): call do_ppmm() in P_PRIMARY code.
+ * expr.c(LAST_BINOP): deleted.
+ * expr.c(IS_BINOP): new define.
+ * expr.c(evalexpr): use IS_BINOP.
+ * expr.c(O_PLUSPLUS,O_MINUSMUNS,opinfo[]): new enums; updated opinfo
+ * expr.c(ET_LVALUE,ET_RDONLY): new enums.
+
+ * expr.c(token): var code: don't increment cp in iter part of for loop,
+ do it in body; don't correct for off by 1 in array or !noasign code.
+ * table.h(EXPRLVALUE): new define.
+ * expr.c(token): var code: set EXPRLVALUE flag if noassign.
+ * expr.c(intvar): copy temp var if EXPRLVALUE set.
+ * expr.c(assign_check): new function.
+ * expr.c(evalexpr): if assign-op, call assign_check().
+
+Tue Aug 13 11:02:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * vi.c(do_comment),edit.c(x_do_comment): made do_comment generic,
+ renamed and moved to edit.c; changed all calls.
+ * emacs.c(x_ftab[]): added x_comment.
+ * emacs.c(x_defbindings[]): added XFUNC_comment as <esc>#.
+ * emacs.c(x_comment): new function.
+
+Mon Aug 12 16:13:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * expr.c(ET_BADVAR): deleted.
+ * expr.c(ET_RECURSIVE, struct expr.evaling),table.h(EXPRNEVAL): added.
+ * expr.c(v_evaluate): if curstate.evaling set, clear EXPRINEVAL.
+ * expr.c(evalerr): added ET_RECURSIVE case, removed ET_BADVAR case.
+ * expr.c(intvar): do recursion check, call v_evaluate() on value.
+
+Mon Aug 12 14:25:23 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * io.c(coproc_read_close): call coproc_readw_close() instead of
+ duplicating code.
+
+Mon Aug 12 11:21:39 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * edit.c(x_locate_word): changed to allow at most 1 leading blank
+ before the word.
+ * edit.c(x_file_glob,x_command_glob,add_glob): allow zero length word.
+ * edit.c(x_cf_glob): allow zero length globs on when doing file
+ completion.
+
+ * edit.c(x_complete_word): #if 0 - it isn't used...
+ * edit.c(x_file_glob,x_command_glob,x_locate_word): made static.
+
+ * eval.c(varsub): changed FNOUNSET error from "unset variable"
+ to "parameter no set", ala at&t ksh.
+
+ * c_ksh.c(c_typeset): print variables that aren't set (just
+ leave out the =...).
+
+Mon Aug 12 11:03:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * exec.c(findfunc): removed redundent DEFINED check after tsearch().
+
+Fri Aug 9 22:16:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * jobs.c(j_change): when turning off FMONITOR and not FTALKING,
+ changed SS_RESTORE_CURR to SS_RESTORE_ORIG.
+
+ * edit.c(x_sigwinch): new function.
+ * edit.c(x_init): set up signal handler for SIGWINCH; moved
+ code to get window size into x_sigwinch(); call x_sigwinch().
+ * emacs.c(xx_cols): new variable.
+ * emacs.c(x_init): set xx_cols_to x_cols; change all uses of x_cols
+ to xx_cols.
+ * vi.c(display): when displaying morec, changed x_cols-2 to
+ pwidth+winwidth+1.
+
+Fri Aug 9 12:49:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * table.h(FKSH): new define.
+ * tree.h(struct op): put evalflags into new union u, added ksh_func
+ to union; changed all uses of evalflags.
+ * syn.c(function_body): set u.ksh_func.
+ * exec.c(execute): changed define() arg to t (was t->left).
+ * exec.c(define): copy t->left (was t); set FKSH in flag if is
+ a ksh function.
+ * exec.c(comexec): don't keep assignments for x() style functions.
+ * exec.c(comexec: case CFUNC: set kshname ($0) for ksh style functions
+ only (was FPOSIX).
+
+ * exec.c(execute): case TAND/TOR: pass XERROK on when executing right
+ hand side.
+
+ * jobs.c(exchild): deleted redundant code to set j->flags
+ (near new_job() call).
+
+ * sh.h(ksh_tmout),main.c(alarm_init),trap.c(alarm_init,alarm_catcher):
+ ifdef'd KSH.
+
+ * sh.h(SS_SHTRAP,Trap.shtrap): added.
+ * trap.c(trapsig): if shtrap is non-zero, call it.
+ * trap.c(setsig): set shtrap if SS_SHTRAP set.
+ * jobs.c(j_init),trap.c(alarm_init): pass SS_SHTRAP.
+ * jobs.c(j_sigchld),trap.c(alarm_catcher): don't call trapsig().
+ * trap.c(Sigact_alarm): removed.
+
+Thu Aug 8 15:57:14 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * exec.c(comexec): case CEXEC: print cannot execute error only
+ if / in pathname; also, set exit code to 126.
+
+ * exec.c(do_selectargs): added print_menu arg; only print
+ menu if this is set, or if REPLY is null; removed "while isspace"
+ loop.
+ * exec.c(execute): case TSELECT: call do_selectargs with print_menu
+ of TRUE on first call only.
+
+ * exec.c(define): added was_set variable and logic.
+ * c_sh.c(c_unset): return 1 if variable/function to be unset wasn't
+ set to begin with.
+
+Wed Jul 31 10:33:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * sh.h(Tflag): new type.
+ * sh.h(builtin_flag): changed type to Tflag.
+ * table.h(struct tbl): changed type of flag field to Tflag.
+ * c_ksh.c(typeset): changed type of flag, fset, fclr to Tflag.
+ * c_ksh.c(c_alias): changed type of xflag to Tflag.
+ * exec.c(comexec): changed type of old_inuse to Tflag.
+ * exec.c(builtin): changed type of flag to Tflag.
+ * var.c(typeset): changed set, clr args to Tflag; convert second
+ arg of call to local() to boolean.
+
+Wed Jul 31 10:26:25 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * sh.h(C_QUOTE): new define.
+ * sh.h(ctypes[]),misc.c(ctypes[]): changed from char to short.
+ * misc.c(initctypes): set C_QUOTE bits in ctypes[].
+ * misc.c(print_value_quoted): use C_QUOTE.
+
+Mon Jul 29 11:38:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * lex.c(set_prompt): don't print warning message if setjmp returns
+ non-zero.
+
+Fri Jul 26 10:16:27 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * lex.c(set_prompt): don't do ! and parameter expansion if !KSH.
+
+ * table.h(V_MAIL,V_MAILPATH,V_MAILCHECK): ifdef KSH.
+ * var.c(initvar,setspec,unsetspec): ifdef KSH use of MAIL stuff.
+ * mail.c: ifdef KSH whole file.
+ * main.c(shell): ifdef KSH call to mcheck().
+ * main.c(initcoms[]): ifdef KSH the MAILCHECK=600.
+ (based on patches from Marc Olzheim).
+
+ * exec.c(PS4_SUBSTITUTE): new macro.
+ * exec.c(execute, comexec, iosetup): use PS4_SUBSTITUTE.
+
+Thu Jul 25 17:19:17 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * sh.h(F_VIESCCOMPLETE): new define.
+ * misc.c(options[]): added vi-esccomplete.
+ * vi.c(classify[]): make ^[ a repeatable command.
+ * vi.c(vi_cmd): check F_VIESCCOMPLETE for ^[.
+
+Mon Jul 22 16:54:38 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * c_ksh.c(c_getopts): return if variable is readonly; don't change
+ OPTIND if option is bad (fragile).
+ * c_sh.c(c_brkcont): use ksh_getopt(); changed error message if
+ n <= 0.
+ * c_sh.c(c_dot,c_eval,c_exitreturn): use ksh_getopt().
+ * misc.c(ksh_getopt): print `unknown option' instead of `bad option'.
+
+Mon Jul 22 16:08:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * edit.c(x_init): do NOT export COLUMNS/LINES - causes more problems
+ than it fixes.
+
+Mon Jul 22 15:49:35 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * syn.c(get_command): fixed test for '< foo (command)' so it
+ works.
+
+Fri Jun 21 09:57:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * aclocal.m4(KSH_OPENDIR_CHECK): include dirent.h if HAVE_DIRENT_H
+ defined (was DIRENT || _POSIX_VERSION).
+ * aclocal.m4(KSH_UNISTD_H): don't test HAVE_DIRENT_H when including
+ dirent.h.
+
+Wed Jun 12 11:02:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
+
+ * c_test.c(b_ops[]): added "==" entry (ksh93ism).
+
+Mon Jun 10 14:00:21 1996 Michael Rendell (michael@lyman.cs.mun.ca)
+
+ * ksh_stat.h: undef S_ISSOCK if STAT_MACROS_BROKEN defined.
+ * aclocal.m4(AC_HEADER_STAT): redefine autoconf's version to handle
+ FreeBSD's S_ISSOCK.
Tue Jun 4 08:41:19 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
- * made pdksh-5.2.6 distribution
+ * made pdksh-5.2.7 distribution
* vi.c(CMDLEN): changed from 16 back to 1024.
diff --git a/bin/ksh/IAFA-PACKAGE b/bin/ksh/IAFA-PACKAGE
index fd04bc405bf..26a19b94d19 100644
--- a/bin/ksh/IAFA-PACKAGE
+++ b/bin/ksh/IAFA-PACKAGE
@@ -1,7 +1,7 @@
-$OpenBSD: IAFA-PACKAGE,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: IAFA-PACKAGE,v 1.2 1996/08/19 20:08:42 downsj Exp $
Title: pdksh
-Version: 5.2.7
+Version: 5.2.8
Description: A public domain implementation of the Korn shell (ksh88),
a UNIX command line interpreter / scripting language; the few
missing ksh features are being added and the shell is being
diff --git a/bin/ksh/NEWS b/bin/ksh/NEWS
index 4daaaf1ac67..9c5f173d6ba 100644
--- a/bin/ksh/NEWS
+++ b/bin/ksh/NEWS
@@ -1,4 +1,39 @@
-$OpenBSD: NEWS,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: NEWS,v 1.2 1996/08/19 20:08:42 downsj Exp $
+
+Version 5.2.8
+
+* bug fixes
+ * configuration: handle FreeBSD's strange S_ISSOCK.
+ * test: added == operator.
+ * configuration: fixed opendir/dirent usage.
+ * redirections before subshells handled correctly.
+ * COLUMNS/LINES are no longer exported when they are automatically set.
+ * mail checks and PS1/PS4 expansions removed if compiled as sh.
+ * subcommands in PS1 no longer genereate bogus warning messages.
+ * environment variables not longer messed up on 16-bit machines.
+ * unset: now returns non-zero if variable/function isn't set.
+ * select: only prints menu first time, if REPLY is null or on blank line.
+ * check for `cannot execute' imporved, error message says why.
+ * typeset: now reports variables with attributes but now value.
+ * vi/emacs file completion: does directory listing on zero length names.
+ * arithmetic: non-numeric parameters expanded recursively.
+ * arithmetic: identifiers in unevaluated part of ?:,&&,|| parsed correctly.
+ * functions: unsetting a function within itself is now safe.
+ * arrays: unsetting element 0 of an array no longer kills the whole array.
+ * co-processes now behave like ksh93 co-processes (and less like ksh88).
+
+* functions declared with "function foo" are treated differently (from those
+ declared with "foo()"): $0 is (not) set to the function name, assignments
+ before function calls aren't (are) kept in the parent shell.
+
+* vi: added vi-esccomplete option for people who want ESC-ESC completion.
+
+* vi/emacs: now notice window size changes (but not while editing a line).
+
+* emacs: <esc># now does the comment/uncomment thing.
+
+* arithmetic: ++, -- and , added.
+
Version 5.2.7
diff --git a/bin/ksh/NOTES b/bin/ksh/NOTES
index 45bab7b2752..96a2af3aada 100644
--- a/bin/ksh/NOTES
+++ b/bin/ksh/NOTES
@@ -1,4 +1,4 @@
-$OpenBSD: NOTES,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: NOTES,v 1.2 1996/08/19 20:08:43 downsj Exp $
General features of at&t ksh that are not (yet) in pdksh:
- exported aliases.
@@ -6,10 +6,12 @@ General features of at&t ksh that are not (yet) in pdksh:
- set -t.
- signals/traps not cleared during functions.
- trap DEBUG, local ERR and EXIT traps in functions.
- - ERRNO, LINENO, LINES parameters.
+ - ERRNO, LINENO parameters.
- doesn't have posix file globbing (eg, [[:alpha:]], etc.).
- use of an `agent' to execute unreadable/setuid/setgid shell scripts
(don't ask).
+ - read/select aren't hooked in to the the command line editor
+ - the last command of a pipeline is not run in the parent shell
Known bugs (see also BUG-REPORTS and PROJECTS files):
Variable parsing, Expansion:
@@ -46,11 +48,6 @@ Known differences between pdksh & at&t ksh (that may change)
prints a message and exits. (Also, in at&t ksh, setting TMOUT has no
effect after the sequence "TMOUT=60; unset TMOUT", which could be
useful - pdksh may do this in the future).
- - co-processes: in at&t ksh, accessing the co-process in a redirection
- always closes the shells copies of the file descriptors; in pdksh
- only redirections in an empty exec command has this effect. This
- may change if the at&t style proves more useful (doubt it, though)
- or if many scripts depend on it.
- in pdksh, if the last command of a pipeline is a shell builtin, it is
not executed in the parent shell, so "echo a b | read foo bar" does not
set foo and bar in the parent shell (at&t ksh will).
@@ -59,6 +56,9 @@ Known differences between pdksh & at&t ksh (that may change)
it is the same as set -o.
- in pdksh emacs mode, ^T does what gnu emacs does, not what at&t ksh
does.
+ - in ksh93, `. name' calls a function (defined with function) with POSIX
+ semantics (instead of ksh semantics). in pdksh, . does not call
+ functions.
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
@@ -79,7 +79,7 @@ Known differences between pdksh & at&t ksh (that are not likely to change)
uses isspace()), at&t ksh only skips blanks.
- at&t ksh allows attributes of read-only variables to be changed,
pdksh allows only the export attribute to be set.
- - at&t ksh allows set -A of readonly variables, pdksh does not.
+ - (some) at&t ksh allows set -A of readonly variables, pdksh does not.
- at&t ksh allows command assignments of readonly variables (eg, YY=2 cat),
pdksh does not.
- at&t ksh does not exit scripts when an implicit assignment to an integer
@@ -165,6 +165,19 @@ Known differences between pdksh & at&t ksh (that are not likely to change)
- pwd: in at&t ksh, it ignores arguments; in pdksh, it complains when given
arguments.
- the at&t ksh does not do command substition on PS1, pdksh does.
+ - ksh93 allows ". foo" to run the function foo if there is no file
+ called foo (go figure).
+ - field splitting (IFS): ksh88/ksh93 strip leading non-white space IFS
+ chars, pdksh (and POSIX, I think) leave them intact. e.g.
+ $ IFS="$IFS:"; read x; echo "<$x>"
+ ::
+ prints "<>" in at&t ksh, "<::>" in pdksh.
+ - command completion: at&t ksh will do completion on a blank line (matching
+ all commands), pdksh does not (as this isn't very useful - use * if
+ you really want the list).
+ - co-processes: if ksh93, the write portion of the co-process output is
+ closed when the most recently started co-process exits. pdksh closes
+ it when all the co-processes using it have exited.
Oddities in ksh (pd & at&t):
- array references inside (())/$(()) are strange:
diff --git a/bin/ksh/PROJECTS b/bin/ksh/PROJECTS
index 52913caf817..271dc3ccad9 100644
--- a/bin/ksh/PROJECTS
+++ b/bin/ksh/PROJECTS
@@ -1,4 +1,4 @@
-$OpenBSD: PROJECTS,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: PROJECTS,v 1.2 1996/08/19 20:08:44 downsj Exp $
Things to be done in pdksh (see also the NOTES file):
@@ -40,7 +40,7 @@ Things to be done in pdksh (see also the NOTES file):
* trap code
* add the DEBUG trap.
* fix up signal handling code. In particular, fatal vs tty signals,
- have single routine to call to check for pending/fatal traps, etc.
+ have signal routine to call to check for pending/fatal traps, etc.
* parsing
* the time keyword needs to be hacked to accept options (!) since
@@ -64,12 +64,8 @@ Things to be done in pdksh (see also the NOTES file):
freed when a variable is unset.
* functions
- POSIX and at&t ksh functions are different in that POSIX functions
- don't change disable/restore traps and option parsing (OPTIND/OPTARG
- plus internal state) isn't saved/restored. The suggestion made in
- POSIX.2 rationale is to have x() { .. } do the POSIX thing, and have
- function x { ..} do the at&t ksh thing. So, should have two types of
- functions.
+ finish the differences between function x and x(): trap EXIT, traps
+ in general, treatment of OPTIND/OPTARG,
* history
There are two versions of the history code, COMPLEX_HISTORY and
@@ -102,31 +98,19 @@ Things to be done in pdksh (see also the NOTES file):
otherwise) (see POSIX.2:3.8.1). Some of this has been taken
care of, but more needs doing.
- * POSIX says if an exec fails, the exit code should be 127 (not found)
- or 126 (not executable)...
-
* remove static limits created by fixed sized arrays
(eg, getsc_(line[]), ident[], heres[], PATH, states(lex.c),
buffer size in emacs/vi code)
* merge the emacs and vi code (should reduce the size of the shell and
- make maintenance easier).
+ make maintenance easier); handle SIGWINCH while editing a line.
[John Rochester is working on the merge]
* add POSIX globbing (eg, [[:alnum:]]), see POSIX.2:2.8.3.2.
- * catch SIGWINCH and update the COLUMNS and LINES parameters (also,
- need to let the command line editor know of change - ideally this
- would work even if the editor was currently reading commands).
-
* teach shf_vfprintf() about long long's (%lld); also make %p use
long longs if appropriate.
* add \[...\] parsing to prompt printing (don't count width of chars
inside the \[..\] - used to keep escape sequences in prompts from
messing up command-line-editor's idea of where the cursor is)
-
- * file(command) completion list in vi/emacs: change so a number-prefix
- picks one of the possibilities (eg, if in vi: foo^[= lists fooa, foob
- and fooc as possible completions, ^[2= would choose the second
- possibility (foob)).
diff --git a/bin/ksh/README b/bin/ksh/README
index d22b8e40c84..86575be9c34 100644
--- a/bin/ksh/README
+++ b/bin/ksh/README
@@ -1,6 +1,6 @@
-$OpenBSD: README,v 1.1 1996/08/14 06:19:10 downsj Exp $
+$OpenBSD: README,v 1.2 1996/08/19 20:08:44 downsj Exp $
-Last updated June '96 for pdksh-5.2.6.
+Last updated August '96 for pdksh-5.2.8.
(check ftp://ftp.cs.mun.ca:/pub/pdksh/ or
http://www.cs.mun.ca/~michael/pdksh/ for new versions/patches)
diff --git a/bin/ksh/c_ksh.c b/bin/ksh/c_ksh.c
index 01bef267466..ea27c7ddcbe 100644
--- a/bin/ksh/c_ksh.c
+++ b/bin/ksh/c_ksh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: c_ksh.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
+/* $OpenBSD: c_ksh.c,v 1.2 1996/08/19 20:08:45 downsj Exp $ */
/*
* built-in Korn commands: c_*
@@ -280,7 +280,7 @@ c_print(wp)
break;
#ifdef KSH
case 'p':
- if ((fd = get_coproc_fd(W_OK, &emsg)) < 0) {
+ if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
bi_errorf("-p: %s", emsg);
return 1;
}
@@ -378,9 +378,9 @@ c_print(wp)
Xfree(xs, xp);
} else {
int n, len = Xlength(xs, xp);
+#ifdef KSH
int UNINITIALIZED(opipe);
-#ifdef KSH
/* Ensure we aren't killed by a SIGPIPE while writing to
* a coprocess. at&t ksh doesn't seem to do this (seems
* to just check that the co-process is alive, which is
@@ -404,16 +404,22 @@ c_print(wp)
continue;
}
#ifdef KSH
- if (errno == EPIPE)
- coproc_write_close(fd);
+ /* This doesn't really make sense - could
+ * break scripts (print -p generates
+ * error message).
+ *if (errno == EPIPE)
+ * coproc_write_close(fd);
+ */
#endif /* KSH */
return 1;
}
s += n;
len -= n;
}
+#ifdef KSH
if (flags & PO_COPROC)
restore_pipe(opipe);
+#endif /* KSH */
}
return 0;
@@ -559,12 +565,13 @@ c_typeset(wp)
{
struct block *l = e->loc;
struct tbl *vp, **p;
- int fset = 0, fclr = 0;
+ Tflag fset = 0, fclr = 0;
int thing = 0, func = 0, local = 0;
const char *options = "L#R#UZ#fi#lrtux"; /* see comment below */
char *fieldstr, *basestr;
int field, base;
- int optc, flag;
+ int optc;
+ Tflag flag;
int pflag = 0;
switch (**wp) {
@@ -757,8 +764,6 @@ c_typeset(wp)
for (l = e->loc; l; l = l->next) {
for (p = tsort(&l->vars); (vp = *p++); )
for (; vp; vp = vp->u.array) {
- if (!(vp->flag&ISSET))
- continue;
if (flag && (vp->flag & flag) == 0)
continue;
/* no arguments */
@@ -777,9 +782,9 @@ c_typeset(wp)
if ((vp->flag&TRACE))
shprintf("-t ");
if ((vp->flag&LJUST))
- shprintf("-L%d ", vp->field);
+ shprintf("-L%d ", vp->u2.field);
if ((vp->flag&RJUST))
- shprintf("-R%d ", vp->field);
+ shprintf("-R%d ", vp->u2.field);
if ((vp->flag&ZEROFIL))
shprintf("-Z ");
if ((vp->flag&LCASEV))
@@ -800,7 +805,7 @@ c_typeset(wp)
shprintf("%s[%d]", vp->name, vp->index);
else
shprintf("%s", vp->name);
- if (thing == '-') {
+ if (thing == '-' && (vp->flag&ISSET)) {
char *s = str_val(vp);
shprintf("=");
@@ -824,7 +829,8 @@ c_alias(wp)
char **wp;
{
struct table *t = &aliases;
- int rv = 0, rflag = 0, tflag, Uflag = 0, xflag = 0;
+ int rv = 0, rflag = 0, tflag, Uflag = 0;
+ Tflag xflag = 0;
int optc;
while ((optc = ksh_getopt(wp, &builtin_opt, "drtUx")) != EOF)
@@ -910,7 +916,8 @@ c_alias(wp)
afree((void*)ap->val.s, APERM);
}
/* ignore values for -t (at&t ksh does this) */
- newval = tflag ? search(alias, path, X_OK) : val;
+ newval = tflag ? search(alias, path, X_OK, (int *) 0)
+ : val;
if (newval) {
ap->val.s = str_save(newval, APERM);
ap->flag |= ALLOC|ISSET;
@@ -1281,26 +1288,32 @@ c_getopts(wp)
buf[0] = optc < 0 ? '?' : optc;
buf[1] = '\0';
}
- vq = global(var);
- if (vq->flag & RDONLY)
- bi_errorf("%s is readonly", var);
- if (Flag(FEXPORT))
- typeset(var, EXPORT, 0, 0, 0);
- setstr(vq, buf);
- getopts_noset = 1;
- setint(global("OPTIND"), (long) user_opt.optind);
- getopts_noset = 0;
+ /* at&t ksh does not change OPTIND if it was an unknown option.
+ * Scripts counting on this are prone to break... (ie, don't count
+ * on this staying).
+ */
+ if (optc != '?') {
+ getopts_noset = 1;
+ setint(global("OPTIND"), (long) user_opt.optind);
+ getopts_noset = 0;
+ }
if (user_opt.optarg == (char *) 0)
unset(global("OPTARG"), 0);
else
setstr(global("OPTARG"), user_opt.optarg);
- if (optc < 0)
+ vq = global(var);
+ if (vq->flag & RDONLY) {
+ bi_errorf("%s is readonly", var);
return 1;
+ }
+ if (Flag(FEXPORT))
+ typeset(var, EXPORT, 0, 0, 0);
+ setstr(vq, buf);
- return 0;
+ return optc < 0 ? 1 : 0;
}
#ifdef EMACS
diff --git a/bin/ksh/c_sh.c b/bin/ksh/c_sh.c
index 7fd2a645b12..691abee19bf 100644
--- a/bin/ksh/c_sh.c
+++ b/bin/ksh/c_sh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: c_sh.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
+/* $OpenBSD: c_sh.c,v 1.2 1996/08/19 20:08:46 downsj Exp $ */
/*
* built-in Bourne commands
@@ -26,14 +26,19 @@ c_shift(wp)
register struct block *l = e->loc;
register int n;
long val;
+ char *arg;
- if (wp[1]) {
- evaluate(wp[1], &val, FALSE);
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ arg = wp[builtin_opt.optind];
+
+ if (arg) {
+ evaluate(arg, &val, FALSE);
n = val;
} else
n = 1;
if (n < 0) {
- bi_errorf("%s: bad number", wp[1]);
+ bi_errorf("%s: bad number", arg);
return (1);
}
if (l->argc < n) {
@@ -175,19 +180,22 @@ c_dot(wp)
int argc;
int i;
- if ((cp = wp[1]) == NULL)
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+
+ if ((cp = wp[builtin_opt.optind]) == NULL)
return 0;
- file = search(cp, path, R_OK);
+ file = search(cp, path, R_OK, (int *) 0);
if (file == NULL) {
bi_errorf("%s: not found", cp);
return 1;
}
/* Set positional parameters? */
- if (wp[2]) {
- argv = ++wp;
+ if (wp[builtin_opt.optind + 1]) {
+ argv = wp + builtin_opt.optind;
argv[0] = e->loc->argv[0]; /* preserve $0 */
- for (argc = -1; *wp++; argc++)
+ for (argc = 0; argv[argc + 1]; argc++)
;
} else {
argc = 0;
@@ -245,7 +253,7 @@ c_read(wp)
switch (optc) {
#ifdef KSH
case 'p':
- if ((fd = get_coproc_fd(R_OK, &emsg)) < 0) {
+ if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
bi_errorf("-p: %s", emsg);
return 1;
}
@@ -290,9 +298,15 @@ c_read(wp)
#ifdef KSH
/* If we are reading from the co-process for the first time,
- * make sure the other side of the pipe is closed first.
+ * make sure the other side of the pipe is closed first. This allows
+ * the detection of eof.
+ *
+ * This is not compatiable with at&t ksh... the fd is kept so another
+ * coproc can be started with same ouput, however, this means eof
+ * can't be detected... This is why it is closed here.
+ * If this call is removed, remove the eof check below, too.
+ * coproc_readw_close(fd);
*/
- coproc_readw_close(fd);
#endif /* KSH */
if (history)
@@ -387,7 +401,10 @@ c_read(wp)
Xfree(xs, xp);
}
#ifdef KSH
- /* if this is the co-process fd, close the file descriptor */
+ /* if this is the co-process fd, close the file descriptor
+ * (can get eof if and only if all processes are have died, ie,
+ * coproc.njobs is 0 and the pipe is closed).
+ */
if (c == EOF && !ecode)
coproc_read_close(fd);
#endif /* KSH */
@@ -401,8 +418,10 @@ c_eval(wp)
{
register struct source *s;
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
s = pushs(SWORDS, ATEMP);
- s->u.strv = wp+1;
+ s->u.strv = wp + builtin_opt.optind;
return shell(s, FALSE);
}
@@ -466,10 +485,15 @@ c_exitreturn(wp)
char **wp;
{
int how = LEXIT;
+ char *arg;
- if (wp[1] != NULL && !getn(wp[1], &exstat)) {
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ arg = wp[builtin_opt.optind];
+
+ if (arg != NULL && !getn(arg, &exstat)) {
exstat = 1;
- warningf(TRUE, "%s: bad number", wp[1]);
+ warningf(TRUE, "%s: bad number", arg);
}
if (wp[0][0] == 'r') { /* return */
struct env *ep;
@@ -501,15 +525,20 @@ c_brkcont(wp)
{
int n, quit;
struct env *ep, *last_ep = (struct env *) 0;
+ char *arg;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ arg = wp[builtin_opt.optind];
- if (!wp[1])
+ if (!arg)
n = 1;
- else if (!bi_getn(wp[1], &n))
+ else if (!bi_getn(arg, &n))
return 1;
quit = n;
if (quit <= 0) {
/* at&t ksh does this for non-interactive shells only - weird */
- bi_errorf("bad option `%s'", wp[1]);
+ bi_errorf("%s: bad value", arg);
return 1;
}
@@ -586,6 +615,7 @@ c_unset(wp)
{
register char *id;
int optc, unset_var = 1;
+ int ret = 0;
while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
switch (optc) {
@@ -603,14 +633,18 @@ c_unset(wp)
if (unset_var) { /* unset variable */
struct tbl *vp = global(id);
+ if (!(vp->flag & ISSET))
+ ret = 1;
if ((vp->flag&RDONLY)) {
bi_errorf("%s is read only", vp->name);
return 1;
}
unset(vp, strchr(id, '[') ? 1 : 0);
- } else /* unset function */
- define(id, (struct op *)NULL);
- return 0;
+ } else { /* unset function */
+ if (define(id, (struct op *) NULL))
+ ret = 1;
+ }
+ return ret;
}
int
diff --git a/bin/ksh/c_test.c b/bin/ksh/c_test.c
index 7ac8c03a007..63a0c94e80c 100644
--- a/bin/ksh/c_test.c
+++ b/bin/ksh/c_test.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: c_test.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
+/* $OpenBSD: c_test.c,v 1.2 1996/08/19 20:08:47 downsj Exp $ */
/*
* test(1); version 7-like -- author Erik Baalbergen
@@ -27,7 +27,7 @@
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
"-L"|"-h"|"-S"|"-H";
- binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
"-nt"|"-ot"|"-ef"|
"<"|">" # rules used for [[ .. ]] expressions
;
@@ -69,6 +69,9 @@ static const struct t_op u_ops [] = {
};
static const struct t_op b_ops [] = {
{"=", TO_STEQL },
+#ifdef KSH
+ {"==", TO_STEQL },
+#endif /* KSH */
{"!=", TO_STNEQ },
{"<", TO_STLT },
{">", TO_STGT },
diff --git a/bin/ksh/edit.c b/bin/ksh/edit.c
index c009ed726d0..12e4fed77d5 100644
--- a/bin/ksh/edit.c
+++ b/bin/ksh/edit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: edit.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
+/* $OpenBSD: edit.c,v 1.2 1996/08/19 20:08:47 downsj Exp $ */
/*
* Command line editing - common code
@@ -20,7 +20,21 @@
#include <ctype.h>
#include "ksh_stat.h"
-static char vdisable_c;
+
+#if defined(TIOCGWINSZ)
+static RETSIGTYPE x_sigwinch ARGS((int sig));
+static int got_sigwinch;
+static void check_sigwinch ARGS((void));
+#endif /* TIOCGWINSZ */
+
+static int x_file_glob ARGS((int flags, const char *str, int slen,
+ char ***wordsp));
+static int x_command_glob ARGS((int flags, const char *str, int slen,
+ char ***wordsp));
+static int x_locate_word ARGS((const char *buf, int buflen, int pos,
+ int *startp, int *is_command));
+
+static char vdisable_c;
/* Called from main */
@@ -32,26 +46,15 @@ x_init()
= edchars.eof = -1;
/* default value for deficient systems */
edchars.werase = 027; /* ^W */
-#ifdef TIOCGWINSZ
- {
- struct winsize ws;
-
- if (ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) {
- struct tbl *vp;
- if (ws.ws_col) {
- x_cols = ws.ws_col < MIN_COLS ? MIN_COLS
- : ws.ws_col;
-
- if ((vp = typeset("COLUMNS", EXPORT, 0, 0, 0)))
- setint(vp, (long) ws.ws_col);
- }
- if (ws.ws_row
- && (vp = typeset("LINES", EXPORT, 0, 0, 0)))
- setint(vp, (long) ws.ws_row);
- }
- }
+#ifdef TIOCGWINSZ
+# ifdef SIGWINCH
+ if (setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_SHTRAP))
+ sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
+# endif /* SIGWINCH */
+ check_sigwinch();
#endif /* TIOCGWINSZ */
+
#ifdef EMACS
x_init_emacs();
#endif /* EMACS */
@@ -74,6 +77,46 @@ x_init()
#endif /* _POSIX_VDISABLE */
}
+#if defined(TIOCGWINSZ)
+static RETSIGTYPE
+x_sigwinch(sig)
+ int sig;
+{
+ got_sigwinch = 1;
+ return RETSIGVAL;
+}
+
+static void
+check_sigwinch ARGS((void))
+{
+ if (got_sigwinch) {
+ struct winsize ws;
+
+ got_sigwinch = 0;
+ if (procpid == kshpid && ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) {
+ struct tbl *vp;
+
+ /* Do NOT export COLUMNS/LINES. Many applications
+ * check COLUMNS/LINES before checking ws.ws_col/row,
+ * so if the app is started with C/L in the environ
+ * and the window is then resized, the app won't
+ * see the change cause the environ doesn't change.
+ */
+ if (ws.ws_col) {
+ x_cols = ws.ws_col < MIN_COLS ? MIN_COLS
+ : ws.ws_col;
+
+ if ((vp = typeset("COLUMNS", 0, 0, 0, 0)))
+ setint(vp, (long) ws.ws_col);
+ }
+ if (ws.ws_row
+ && (vp = typeset("LINES", 0, 0, 0, 0)))
+ setint(vp, (long) ws.ws_row);
+ }
+ }
+}
+#endif /* TIOCGWINSZ */
+
/*
* read an edited command line
*/
@@ -84,6 +127,11 @@ x_read(buf, len)
{
int i;
+#if defined(TIOCGWINSZ)
+ if (got_sigwinch)
+ check_sigwinch();
+#endif /* TIOCGWINSZ */
+
x_mode(TRUE);
#ifdef EMACS
if (Flag(FEMACS) || Flag(FGMACS))
@@ -330,6 +378,61 @@ set_editmode(ed)
}
/* ------------------------------------------------------------------------- */
+/* Misc common code for vi/emacs */
+
+/* Handle the commenting/uncommenting of a line.
+ * Returns:
+ * 1 if a carriage return is indicated (comment added)
+ * 0 if no return (comment removed)
+ * -1 if there is an error (not enough room for comment chars)
+ * If successful, *lenp contains the new length. Note: cursor should be
+ * moved to the start of the line after (un)commenting.
+ */
+int
+x_do_comment(buf, bsize, lenp)
+ char *buf;
+ int bsize;
+ int *lenp;
+{
+ int i, j;
+ int len = *lenp;
+
+ if (len == 0)
+ return 1; /* somewhat arbitrary - it's what at&t ksh does */
+
+ /* Already commented? */
+ if (buf[0] == '#') {
+ int saw_nl = 0;
+
+ for (j = 0, i = 1; i < len; i++) {
+ if (!saw_nl || buf[i] != '#')
+ buf[j++] = buf[i];
+ saw_nl = buf[i] == '\n';
+ }
+ *lenp = j;
+ return 0;
+ } else {
+ int n = 1;
+
+ /* See if there's room for the #'s - 1 per \n */
+ for (i = 0; i < len; i++)
+ if (buf[i] == '\n')
+ n++;
+ if (len + n >= bsize)
+ return -1;
+ /* Now add them... */
+ for (i = len, j = len + n; --i >= 0; ) {
+ if (buf[i] == '\n')
+ buf[--j] = '#';
+ buf[--j] = buf[i];
+ }
+ buf[0] = '#';
+ *lenp += n;
+ return 1;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
/* Common file/command completion code for vi/emacs */
@@ -338,7 +441,9 @@ static void glob_table ARGS((const char *pat, XPtrV *wp, struct table *tp));
static void glob_path ARGS((int flags, const char *pat, XPtrV *wp,
const char *path));
-/* XXX not used... */
+#if 0 /* not used... */
+int x_complete_word ARGS((const char *str, int slen, int is_command,
+ int *multiple, char **ret));
int
x_complete_word(str, slen, is_command, nwordsp, ret)
const char *str;
@@ -364,6 +469,7 @@ x_complete_word(str, slen, is_command, nwordsp, ret)
x_free_words(nwords, words);
return prefix_len;
}
+#endif /* 0 */
void
x_print_expansions(nwords, words, is_command)
@@ -422,8 +528,7 @@ x_print_expansions(nwords, words, is_command)
* - sets *wordsp to array of matching strings
* - returns number of matching strings
*/
-/* XXX static? */
-int
+static int
x_file_glob(flags, str, slen, wordsp)
int flags;
const char *str;
@@ -436,7 +541,7 @@ x_file_glob(flags, str, slen, wordsp)
XPtrV w;
struct source *s, *sold;
- if (slen <= 0)
+ if (slen < 0)
return 0;
toglob = add_glob(str, slen);
@@ -507,8 +612,7 @@ path_order_cmp(aa, bb)
return t ? t : a->path_order - b->path_order;
}
-/* XXX static? */
-int
+static int
x_command_glob(flags, str, slen, wordsp)
int flags;
const char *str;
@@ -522,7 +626,7 @@ x_command_glob(flags, str, slen, wordsp)
XPtrV w;
struct block *l;
- if (slen <= 0)
+ if (slen < 0)
return 0;
toglob = add_glob(str, slen);
@@ -605,8 +709,7 @@ x_command_glob(flags, str, slen, wordsp)
#define IS_WORDC(c) !isspace(c)
-/* XXX static? */
-int
+static int
x_locate_word(buf, buflen, pos, startp, is_commandp)
const char *buf;
int buflen;
@@ -617,25 +720,28 @@ x_locate_word(buf, buflen, pos, startp, is_commandp)
int p;
int start, end;
- if (pos == buflen)
- pos--;
- if (pos < 0 || pos >= buflen) {
+ /* Bad call? Probably should report error */
+ if (pos < 0 || pos > buflen) {
*startp = pos;
*is_commandp = 0;
return 0;
}
- /* Go backwards 'til we are in a word */
- for (start = pos; start >= 0 && !IS_WORDC(buf[start]); start--)
- ;
- /* No word found? */
- if (start < 0)
- return 0;
- /* Keep going backwards to start of word */
- for (; start >= 0 && IS_WORDC(buf[start]); start--)
- ;
- start++;
+ if (pos == buflen) {
+ if (pos == 0) { /* empty buffer? */
+ *startp = pos;
+ *is_commandp = 1;
+ return 0;
+ }
+ pos--;
+ }
+ start = pos;
+ /* Keep going backwards to start of word (has effect of allowing
+ * one blank after the end of a word)
+ */
+ for (; start > 0 && IS_WORDC(buf[start - 1]); start--)
+ ;
/* Go forwards to end of word */
for (end = start; end < buflen && IS_WORDC(buf[end]); end++)
;
@@ -682,11 +788,15 @@ x_cf_glob(flags, buf, buflen, pos, startp, endp, wordsp, is_commandp)
int is_command;
len = x_locate_word(buf, buflen, pos, startp, &is_command);
- if (len == 0)
- return 0;
-
if (!(flags & XCF_COMMAND))
is_command = 0;
+ /* Don't do command globing on zero length strings - it takes too
+ * long and isn't very useful. File globs are more likely to be
+ * useful, so allow these.
+ */
+ if (len == 0 && is_command)
+ return 0;
+
nwords = (is_command ? x_command_glob : x_file_glob)(flags,
buf + *startp, len, &words);
if (nwords == 0) {
@@ -713,7 +823,7 @@ add_glob(str, slen)
char *toglob;
char *s;
- if (slen <= 0)
+ if (slen < 0)
return (char *) 0;
toglob = str_nsave(str, slen + 1, ATEMP); /* + 1 for "*" */
@@ -880,7 +990,7 @@ glob_path(flags, pat, wp, path)
/* Check that each match is executable... */
words = (char **) XPptrv(*wp);
for (i = j = oldsize; i < newsize; i++) {
- if (search_access(words[i], X_OK) >= 0) {
+ if (search_access(words[i], X_OK, (int *) 0) >= 0) {
words[j] = words[i];
if (!(flags & XCF_FULLPATH))
memmove(words[j], words[j] + pathlen,
diff --git a/bin/ksh/edit.h b/bin/ksh/edit.h
index c60b4121666..fd29701cc06 100644
--- a/bin/ksh/edit.h
+++ b/bin/ksh/edit.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: edit.h,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
+/* $OpenBSD: edit.h,v 1.2 1996/08/19 20:08:48 downsj Exp $ */
/* NAME:
* edit.h - globals for edit modes
@@ -50,13 +50,10 @@ void x_putc ARGS((int c));
void x_puts ARGS((const char *s));
bool_t x_mode ARGS((bool_t onoff));
int promptlen ARGS((const char *cp, const char **spp));
-int x_complete_word ARGS((const char *str, int slen, int is_command, int *multiple, char **ret));
+int x_do_comment ARGS((char *buf, int bsize, int *lenp));
void x_print_expansions ARGS((int nwords, char *const *words, int is_command));
-int x_locate_word ARGS((const char *buf, int buflen, int pos, int *startp, int *is_command));
int x_cf_glob ARGS((int flags, const char *buf, int buflen, int pos, int *startp,
int *endp, char ***wordsp, int *is_commandp));
-int x_file_glob ARGS((int flags, const char *str, int slen, char ***wordsp));
-int x_command_glob ARGS((int flags, const char *str, int slen, char ***wordsp));
int x_longest_prefix ARGS((int nwords, char *const *words));
int x_basename ARGS((const char *s, const char *se));
void x_free_words ARGS((int nwords, char **words));
diff --git a/bin/ksh/emacs.c b/bin/ksh/emacs.c
index a682f32fb5b..f572f87b5f6 100644
--- a/bin/ksh/emacs.c
+++ b/bin/ksh/emacs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: emacs.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
+/* $OpenBSD: emacs.c,v 1.2 1996/08/19 20:08:48 downsj Exp $ */
/*
* Emacs-like command line editing and history
@@ -94,6 +94,7 @@ static int x_adj_ok;
*/
static int x_adj_done;
+static int xx_cols;
static int x_col;
static int x_displen;
static int x_arg; /* general purpose arg */
@@ -138,10 +139,8 @@ static void x_adjust ARGS((void));
static void x_e_ungetc ARGS((int c));
static int x_e_getc ARGS((void));
static void x_e_putc ARGS((int c));
-#ifdef DEBUG
-static int x_debug_info ARGS((void));
-#endif /* DEBUG */
static void x_e_puts ARGS((const char *s));
+static int x_comment ARGS((int c));
static int x_fold_case ARGS((int c));
static char *x_lastcp ARGS((void));
static void do_complete ARGS((int flags, Comp_type type));
@@ -213,6 +212,7 @@ static const struct x_ftab x_ftab[] = {
{ x_fold_lower, "downcase-word", XF_ARG },
{ x_fold_upper, "upcase-word", XF_ARG },
{ x_set_arg, "set-arg", XF_NOBIND },
+ { x_comment, "comment", 0 },
#ifdef SILLY
{ x_game_of_life, "play-game-of-life", 0 },
#else
@@ -265,6 +265,7 @@ static struct x_defbindings const x_defbindings[] = {
{ XFUNC_yank, 0, CTRL('Y') },
{ XFUNC_meta_yank, 1, 'y' },
{ XFUNC_literal, 0, CTRL('^') },
+ { XFUNC_comment, 1, '#' },
#if defined(BRL) && defined(TIOCSTI)
{ XFUNC_stuff, 0, CTRL('T') },
#else
@@ -342,10 +343,11 @@ x_emacs(buf, len)
x_histp = histptr + 1;
x_last_command = XFUNC_error;
+ xx_cols = x_cols;
x_col = promptlen(prompt, &p);
prompt_skip = p - prompt;
x_adj_ok = 1;
- x_displen = x_cols - 2 - x_col;
+ x_displen = xx_cols - 2 - x_col;
x_adj_done = 0;
pprompt(prompt, 0);
@@ -542,7 +544,7 @@ x_delete(nc, force_push)
* there is no need to ' ','\b'.
* But if we must, make sure we do the minimum.
*/
- if ((i = x_cols - 2 - x_col) > 0)
+ if ((i = xx_cols - 2 - x_col) > 0)
{
j = (j < i) ? j : i;
i = j;
@@ -1031,6 +1033,10 @@ x_draw_line(c)
}
+/* Redraw (part of) the line. If limit is < 0, the everything is redrawn
+ * on a NEW line, otherwise limit is the screen column up to which needs
+ * redrawing.
+ */
static void
x_redraw(limit)
int limit;
@@ -1049,12 +1055,12 @@ x_redraw(limit)
pprompt(prompt + prompt_skip, 0);
x_col = promptlen(prompt, (const char **) 0);
}
- x_displen = x_cols - 2 - x_col;
+ x_displen = xx_cols - 2 - x_col;
xlp_valid = FALSE;
cp = x_lastcp();
x_zots(xbp);
if (xbp != xbuf || xep > xlp)
- limit = x_cols;
+ limit = xx_cols;
if (limit >= 0)
{
if (xep > xlp)
@@ -1062,7 +1068,7 @@ x_redraw(limit)
else
i = limit - (xlp - xbp);
- for (j = 0; j < i && x_col < (x_cols - 2); j++)
+ for (j = 0; j < i && x_col < (xx_cols - 2); j++)
x_e_putc(' ');
i = ' ';
if (xep > xlp) /* more off screen */
@@ -1832,12 +1838,12 @@ x_adjust()
{
x_adj_done++; /* flag the fact that we were called. */
/*
- * we had a problem if the prompt length > x_cols / 2
+ * we had a problem if the prompt length > xx_cols / 2
*/
if ((xbp = xcp - (x_displen / 2)) < xbuf)
xbp = xbuf;
xlp_valid = FALSE;
- x_redraw(x_cols);
+ x_redraw(xx_cols);
x_flush();
}
@@ -1876,7 +1882,7 @@ x_e_putc(c)
{
if (c == '\r' || c == '\n')
x_col = 0;
- if (x_col < x_cols)
+ if (x_col < xx_cols)
{
x_putc(c);
switch(c)
@@ -1894,7 +1900,7 @@ x_e_putc(c)
break;
}
}
- if (x_adj_ok && (x_col < 0 || x_col >= (x_cols - 2)))
+ if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
{
x_adjust();
}
@@ -1902,19 +1908,20 @@ x_e_putc(c)
#ifdef DEBUG
static int
-x_debug_info()
+x_debug_info(c)
+ int c;
{
- x_flush();
- printf("\nksh debug:\n");
- printf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
- x_col, x_cols, x_displen);
- printf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
- printf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
- printf("\txlp == 0x%lx\n", (long) xlp);
- printf("\txlp == 0x%lx\n", (long) x_lastcp());
- printf(newline);
- x_redraw(-1);
- return 0;
+ x_flush();
+ shellf("\nksh debug:\n");
+ shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
+ x_col, xx_cols, x_displen);
+ shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
+ shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
+ shellf("\txlp == 0x%lx\n", (long) xlp);
+ shellf("\txlp == 0x%lx\n", (long) x_lastcp());
+ shellf(newline);
+ x_redraw(-1);
+ return 0;
}
#endif
@@ -1961,6 +1968,29 @@ x_set_arg(c)
}
+/* Comment or uncomment the current line. */
+static int
+x_comment(c)
+ int c;
+{
+ int oldsize = x_size_str(xbuf);
+ int len = xep - xbuf;
+ int ret = x_do_comment(xbuf, xend - xbuf, &len);
+
+ if (ret < 0)
+ x_e_putc(BEL);
+ else {
+ xep = xbuf + len;
+ *xep = '\0';
+ xcp = xbp = xbuf;
+ x_redraw(oldsize);
+ if (ret > 0)
+ return x_newline('\n');
+ }
+ return KSTD;
+}
+
+
/* NAME:
* x_prev_histword - recover word from prev command
*
diff --git a/bin/ksh/eval.c b/bin/ksh/eval.c
index da952584d96..b8b339eccda 100644
--- a/bin/ksh/eval.c
+++ b/bin/ksh/eval.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: eval.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: eval.c,v 1.2 1996/08/19 20:08:49 downsj Exp $ */
/*
* Expansion - quoting, separation, substitution, globbing
@@ -723,7 +723,7 @@ varsub(xp, sp, word, stypep)
c = strlen(p);
}
if (Flag(FNOUNSET) && c == 0 && !zero_ok)
- errorf("%s: unset variable", sp);
+ errorf("%s: parameter not set", sp);
*stypep = 0; /* unqualified variable/string substitution */
xp->str = str_save(ulton((unsigned long)c, 10), ATEMP);
return XSUB;
@@ -813,7 +813,7 @@ varsub(xp, sp, word, stypep)
state = XBASE; /* expand word instead of variable value */
if (Flag(FNOUNSET) && xp->str == null
&& (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
- errorf("%s: unset variable", sp);
+ errorf("%s: parameter not set", sp);
return state;
}
diff --git a/bin/ksh/exec.c b/bin/ksh/exec.c
index 7563b2bb9d0..ce4ca7668c5 100644
--- a/bin/ksh/exec.c
+++ b/bin/ksh/exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: exec.c,v 1.2 1996/08/19 20:08:50 downsj Exp $ */
/*
* execute command tree
@@ -9,14 +9,21 @@
#include <ctype.h>
#include "ksh_stat.h"
+/* Does ps4 get parameter substitutions done? */
+#ifdef KSH
+# define PS4_SUBSTITUTE(s) substitute((s), 0)
+#else
+# define PS4_SUBSTITUTE(s) (s)
+#endif /* KSH */
+
static int comexec ARGS((struct op *t, struct tbl *volatile tp, char **ap,
int volatile flags));
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));
+static int iosetup ARGS((struct ioword *iop, struct tbl *tp));
static int herein ARGS((char *hname, int sub));
#ifdef KSH
-static char *do_selectargs ARGS((char **ap));
+static char *do_selectargs ARGS((char **ap, bool_t print_menu));
#endif /* KSH */
#ifdef KSH
static int dbteste_isa ARGS((Test_env *te, Test_meta meta));
@@ -80,6 +87,14 @@ execute(t, flags)
if (t == NULL)
return 0;
+ /* Is this the end of a pipeline? If so, we want to evaluate the
+ * command arguments
+ bool_t eval_done = FALSE;
+ if ((flags&XFORK) && !(flags&XEXEC) && (flags&XPCLOSE)) {
+ eval_done = TRUE;
+ tp = eval_execute_args(t, &ap);
+ }
+ */
if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
return exchild(t, flags, -1); /* run in sub-process */
@@ -96,10 +111,10 @@ execute(t, flags)
/* POSIX says expand command words first, then redirections,
* and assignments last..
*/
- ap = eval(t->args, t->evalflags | DOBLANK | DOGLOB | DOTILDE);
+ ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
if (Flag(FXTRACE) && ap[0]) {
shf_fprintf(shl_out, "%s",
- substitute(str_val(global("PS4")), 0));
+ PS4_SUBSTITUTE(str_val(global("PS4"))));
for (i = 0; ap[i]; i++)
shf_fprintf(shl_out, "%s%s", ap[i],
ap[i + 1] ? space : newline);
@@ -118,7 +133,7 @@ execute(t, flags)
/* do redirection, to be restored in quitenv() */
if (t->ioact != NULL)
for (iowp = t->ioact; *iowp != NULL; iowp++) {
- if (iosetup(*iowp) < 0) {
+ if (iosetup(*iowp, tp) < 0) {
exstat = rv = 1;
/* Redirection failures for special commands
* cause (non-interactive) shell to exit.
@@ -179,10 +194,31 @@ execute(t, flags)
#ifdef KSH
case TCOPROC:
{
+# ifdef JOB_SIGS
+ sigset_t omask;
+# endif /* JOB_SIGS */
+
+# ifdef JOB_SIGS
+ /* Block sigchild as we are using things changed in the
+ * signal handler
+ */
+ sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
+ e->type = E_ERRH;
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (i) {
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+ quitenv();
+ unwind(i);
+ /*NOTREACHED*/
+ }
+# endif /* JOB_SIGS */
+ /* Already have a (live) co-process? */
if (coproc.job && coproc.write >= 0)
errorf("coprocess already exists");
+
/* Can we re-use the existing co-process pipe? */
- cleanup_coproc(TRUE);
+ coproc_cleanup(TRUE);
+
/* do this before opening pipes, in case these fail */
e->savefd[0] = savefd(0, 0);
e->savefd[1] = savefd(1, 0);
@@ -191,6 +227,7 @@ execute(t, flags)
ksh_dup2(pv[0], 0, FALSE);
close(pv[0]);
coproc.write = pv[1];
+ coproc.job = (void *) 0;
if (coproc.readw >= 0)
ksh_dup2(coproc.readw, 1, FALSE);
@@ -199,9 +236,19 @@ execute(t, flags)
coproc.read = pv[0];
ksh_dup2(pv[1], 1, FALSE);
coproc.readw = pv[1]; /* closed before first read */
+ coproc.njobs = 0;
+ /* create new coprocess id */
+ ++coproc.id;
}
-
- /* exchild() closes coproc.* in child after fork */
+# ifdef JOB_SIGS
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+ e->type = E_EXEC; /* no more need for error handler */
+# endif /* JOB_SIGS */
+
+ /* exchild() closes coproc.* in child after fork,
+ * will also increment coproc.njobs when the
+ * job is actually created.
+ */
flags &= ~XEXEC;
exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
coproc.readw);
@@ -221,7 +268,7 @@ execute(t, flags)
case TAND:
rv = execute(t->left, XERROK);
if (t->right != NULL && (rv == 0) == (t->type == TAND))
- rv = execute(t->right, 0);
+ rv = execute(t->right, flags & XERROK);
else
flags |= XERROK;
break;
@@ -250,6 +297,8 @@ execute(t, flags)
case TFOR:
#ifdef KSH
case TSELECT:
+ {
+ volatile bool_t is_first = TRUE;
#endif /* KSH */
ap = (t->vars != NULL) ?
eval(t->vars, DOBLANK|DOGLOB|DOTILDE)
@@ -286,10 +335,11 @@ execute(t, flags)
struct tbl *vq;
for (;;) {
- if ((cp = do_selectargs(ap)) == (char *) 0) {
+ 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);
@@ -297,6 +347,7 @@ execute(t, flags)
rv = execute(t->left, flags & XERROK);
}
}
+ }
#endif /* KSH */
break;
@@ -348,7 +399,7 @@ execute(t, flags)
break;
case TFUNCT:
- rv = define(t->str, t->left);
+ rv = define(t->str, t);
break;
case TTIME:
@@ -483,15 +534,17 @@ comexec(t, tp, ap, flags)
break;
tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
}
- /* todo: POSIX says assignments preceding a function are kept, at&t
- * ksh does not do this
- */
- if (keepasn_ok && (!ap[0] || (tp && tp->flag & KEEPASN)))
+ if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
type_flags = 0;
else {
/* create new variable/function block */
newblock();
- type_flags = LOCAL|LOCAL_COPY|EXPORT;
+ /* ksh functions don't keep assignments, POSIX functions do. */
+ if (keepasn_ok && tp && tp->type == CFUNC
+ && !(tp->flag & FKSH))
+ type_flags = 0;
+ else
+ type_flags = LOCAL|LOCAL_COPY|EXPORT;
}
if (Flag(FEXPORT))
type_flags |= EXPORT;
@@ -500,7 +553,7 @@ comexec(t, tp, ap, flags)
if (Flag(FXTRACE)) {
if (i == 0)
shf_fprintf(shl_out, "%s",
- substitute(str_val(global("PS4")), 0));
+ PS4_SUBSTITUTE(str_val(global("PS4"))));
shf_fprintf(shl_out, "%s%s", cp,
t->vars[i + 1] ? space : newline);
if (!t->vars[i + 1])
@@ -529,24 +582,30 @@ comexec(t, tp, ap, flags)
case CFUNC: /* function call */
{
volatile int old_xflag;
- volatile int old_inuse;
+ volatile Tflag old_inuse;
const char *volatile old_kshname;
if (!(tp->flag & ISSET)) {
struct tbl *ftp;
if (!tp->u.fpath) {
- /* XXX: exit code 126 vs 127 */
- warningf(TRUE,
+ if (tp->u2.errno_) {
+ warningf(TRUE,
+ "%s: can't find function definition file - %s",
+ cp, strerror(tp->u2.errno_));
+ rv = 126;
+ } else {
+ warningf(TRUE,
"%s: can't find function definition file", cp);
- rv = 127;
+ rv = 127;
+ }
break;
}
if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {
warningf(TRUE,
"%s: can't open function definition file %s - %s",
cp, tp->u.fpath, strerror(errno));
- rv = 126;
+ rv = 127;
break;
}
if (!(ftp = findfunc(cp, hash(cp), FALSE))
@@ -561,9 +620,11 @@ comexec(t, tp, ap, flags)
tp = ftp;
}
- /* posix says $0 remains unchanged, at&t ksh changes it */
+ /* ksh functions set $0 to function name, POSIX functions leave
+ * $0 unchanged.
+ */
old_kshname = kshname;
- if (!Flag(FPOSIX))
+ if (tp->flag & FKSH)
kshname = ap[0];
e->loc->argv = ap;
for (i = 0; *ap++ != NULL; i++)
@@ -588,7 +649,8 @@ comexec(t, tp, ap, flags)
Flag(FXTRACE) = old_xflag;
tp->flag = (tp->flag & ~FINUSE) | old_inuse;
/* Were we deleted while executing? If so, free the execution
- * tree. Unfortunately, the table entry is never re-used.
+ * tree. todo: Unfortunately, the table entry is never re-used
+ * until the lookup table is expanded.
*/
if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
if (tp->flag & ALLOC) {
@@ -619,38 +681,26 @@ comexec(t, tp, ap, flags)
case CEXEC: /* executable command */
case CTALIAS: /* tracked alias */
if (!(tp->flag&ISSET)) {
- /*
- * mlj addition:
- *
- * If you specify a full path to a file
- * (or type the name of a file in .) which
- * doesn't have execute priv's, it used to
- * just say "not found". Kind of annoying,
- * particularly if you just wrote a script
- * but forgot to say chmod 755 script.
- *
- * This should probably be done in eaccess(),
- * but it works here (at least I haven't noticed
- * changing errno here breaking something
- * else).
- *
- * So, we assume that if the file exists, it
- * doesn't have execute privs; else, it really
- * is not found.
+ /* errno_ will be set if the named command was found
+ * but could not be executed (permissions, no execute
+ * bit, directory, etc). Print out a (hopefully)
+ * useful error message and set the exit status to 126.
*/
- if (access(cp, F_OK) < 0)
+ if (tp->u2.errno_) {
+ warningf(TRUE, "%s: cannot execute - %s", cp,
+ strerror(tp->u2.errno_));
+ rv = 126; /* POSIX */
+ } else {
warningf(TRUE, "%s: not found", cp);
- else
- warningf(TRUE, "%s: cannot execute", cp);
- /* XXX posix says 126 if in path and cannot execute */
- rv = 127;
+ rv = 127;
+ }
break;
}
/* set $_ to program's full path */
setstr(typeset("_", LOCAL|EXPORT, 0, 0, 0), tp->val.s);
- if ((flags&XEXEC)) {
+ if (flags&XEXEC) {
j_exit();
if (!(flags&XBGND) || Flag(FMONITOR)) {
setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
@@ -683,7 +733,7 @@ scriptexec(tp, ap)
shell = str_val(global(EXECSHELL_STR));
if (shell && *shell)
- shell = search(shell, path, X_OK);
+ shell = search(shell, path, X_OK, (int *) 0);
if (!shell || !*shell)
shell = EXECSHELL;
@@ -746,7 +796,7 @@ scriptexec(tp, ap)
if (a1)
*tp->args-- = a1;
# ifdef OS2
- if (a0 != a2 && search_access(a0, X_OK))
+ if (a0 != a2 && search_access(a0, X_OK, (int *) 0))
a0 = a2;
# endif /* OS2 */
shell = a0;
@@ -762,7 +812,7 @@ scriptexec(tp, ap)
shell = str_val(global("EXECSHELL"));
if (shell && *shell)
- shell = search(shell, path, X_OK);
+ shell = search(shell, path, X_OK, (int *) 0);
if (!shell || !*shell) {
shell = p;
*tp->args-- = "/c";
@@ -809,7 +859,7 @@ findfunc(name, h, create)
for (l = e->loc; l; l = l->next) {
tp = tsearch(&l->funs, name, h);
- if (tp && (tp->flag & DEFINED))
+ if (tp)
break;
if (!l->next && create) {
tp = tenter(&l->funs, name, h);
@@ -823,25 +873,31 @@ findfunc(name, h, create)
}
/*
- * define function
+ * define function. Returns 1 if function is being undefined (t == 0) and
+ * function did not exist, returns 0 otherwise.
*/
int
define(name, t)
const char *name;
struct op *t;
{
- register struct tbl *tp;
+ struct tbl *tp;
+ int was_set = 0;
- tp = findfunc(name, hash(name), TRUE);
+ while (1) {
+ tp = findfunc(name, hash(name), TRUE);
- /* If this function is currently being executed, we zap this
- * table entry so findfunc() won't see it
- */
- if (tp->flag & FINUSE) {
- tp->name[0] = '\0';
- tp->flag &= ~DEFINED; /* ensure it won't be found */
- tp->flag |= FDELETE;
- return define(name, t);
+ if (tp->flag & ISSET)
+ was_set = 1;
+ /* If this function is currently being executed, we zap this
+ * table entry so findfunc() won't see it
+ */
+ if (tp->flag & FINUSE) {
+ tp->name[0] = '\0';
+ tp->flag &= ~DEFINED; /* ensure it won't be found */
+ tp->flag |= FDELETE;
+ } else
+ break;
}
if (tp->flag & ALLOC) {
@@ -851,11 +907,13 @@ define(name, t)
if (t == NULL) { /* undefine */
tdelete(tp);
- return 0;
+ return was_set ? 0 : 1;
}
- tp->val.t = tcopy(t, tp->areap);
+ tp->val.t = tcopy(t->left, tp->areap);
tp->flag |= (ISSET|ALLOC);
+ if (t->u.ksh_func)
+ tp->flag |= FKSH;
return 0;
}
@@ -869,7 +927,7 @@ builtin(name, func)
int (*func) ARGS((char **));
{
register struct tbl *tp;
- int flag;
+ Tflag flag;
/* see if any flags should be set for this builtin */
for (flag = 0; ; name++) {
@@ -920,10 +978,12 @@ findcom(name, flags)
if (!tp && (flags & FC_FUNC)) {
tp = findfunc(name, h, FALSE);
if (tp && !(tp->flag & ISSET)) {
- if ((fpath = str_val(global("FPATH"))) == null)
+ if ((fpath = str_val(global("FPATH"))) == null) {
tp->u.fpath = (char *) 0;
- else
- tp->u.fpath = search(name, fpath, R_OK);
+ tp->u2.errno_ = 0;
+ } else
+ tp->u.fpath = search(name, fpath, R_OK,
+ &tp->u2.errno_);
}
}
if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
@@ -964,13 +1024,14 @@ findcom(name, flags)
tp->flag = DEFINED; /* make ~ISSET */
}
npath = search(name, flags & FC_DEFPATH ? def_path : path,
- X_OK);
+ X_OK, &tp->u2.errno_);
if (npath) {
tp->val.s = tp == &temp ? npath : str_save(npath, APERM);
tp->flag |= ISSET|ALLOC;
} else if ((flags & FC_FUNC)
&& (fpath = str_val(global("FPATH"))) != null
- && (npath = search(name, fpath, R_OK)) != (char *) 0)
+ && (npath = search(name, fpath, R_OK,
+ &tp->u2.errno_)) != (char *) 0)
{
/* An undocumented feature of at&t ksh is that it
* searches FPATH if a command is not found, even
@@ -1008,20 +1069,29 @@ flushcom(all)
/* Check if path is something we want to find. Returns -1 for failure. */
int
-search_access(path, mode)
+search_access(path, mode, errnop)
const char *path;
int mode;
+ int *errnop; /* set if candidate found, but not suitable */
{
#ifndef OS2
- int ret = eaccess(path, mode);
+ int ret, err = 0;
struct stat statb;
- /* if executable pipes come along, this will have to change */
- if (ret == 0 && (mode == X_OK)
- && (stat(path, &statb) < 0 || !S_ISREG(statb.st_mode)
- /* This 'cause access() says root can execute everything */
- || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
+ if (stat(path, &statb) < 0)
+ return -1;
+ ret = eaccess(path, mode);
+ if (ret < 0)
+ err = errno; /* File exists, but we can't access it */
+ else if (mode == X_OK && (!S_ISREG(statb.st_mode)
+ /* This 'cause access() says root can execute everything */
+ || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
+ {
ret = -1;
+ err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
+ }
+ if (err && errnop)
+ *errnop = err;
return ret;
#else /* !OS2 */
/*
@@ -1050,7 +1120,7 @@ search_access(path, mode)
if ((p = strrchr((p = ksh_strrchr_dirsep(mpath)) ? p : mpath, '.'))) {
if (mode == X_OK)
mode = R_OK;
- return search_access1(mpath, mode);
+ return search_access1(mpath, mode, errnop);
}
/* Try appending the various suffixes. Different suffixes for
* read and execute 'cause we don't want to read an executable...
@@ -1058,7 +1128,7 @@ search_access(path, mode)
sfx = mode == R_OK ? rsuffixes : xsuffixes;
for (i = 0; sfx[i]; i++) {
strcpy(tp, p = sfx[i]);
- if (search_access1(mpath, R_OK) == 0)
+ if (search_access1(mpath, R_OK, errnop) == 0)
return 0;
*tp = '\0';
}
@@ -1068,17 +1138,25 @@ search_access(path, mode)
#ifdef OS2
static int
-search_access1(path, mode)
+search_access1(path, mode, errnop)
const char *path;
int mode;
+ int *errnop; /* set if candidate found, but not suitable */
{
- int ret = eaccess(path, mode);
+ int ret, err = 0;
struct stat statb;
- /* if executable pipes come along, this will have to change */
- if (ret == 0 && (mode == X_OK || mode == R_OK)
- && (stat(path, &statb) < 0 || !S_ISREG(statb.st_mode)))
+ if (stat(path, &statb) < 0)
+ return -1;
+ ret = eaccess(path, mode);
+ if (ret < 0)
+ err = errno; /* File exists, but we can't access it */
+ else if (!S_ISREG(statb.st_mode)) {
ret = -1;
+ err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
+ }
+ if (err && errnop)
+ *errnop = err;
return ret;
}
#endif /* OS2 */
@@ -1087,16 +1165,19 @@ search_access1(path, mode)
* search for command with PATH
*/
char *
-search(name, path, mode)
+search(name, path, mode, errnop)
const char *name;
const char *path;
int mode; /* R_OK or X_OK */
+ int *errnop; /* set if candidate found, but not suitable */
{
const char *sp, *p;
char *xp;
XString xs;
int namelen;
+ if (errnop)
+ *errnop = 0;
#ifdef OS2
/* Xinit() allocates 8 additional bytes, so appended suffixes won't
* overflow the memory.
@@ -1106,18 +1187,18 @@ search(name, path, mode)
memcpy(Xstring(xs, xp), name, namelen);
if (ksh_strchr_dirsep(name)) {
- if (search_access(Xstring(xs, xp), mode) >= 0)
+ if (search_access(Xstring(xs, xp), mode, errnop) >= 0)
return Xstring(xs, xp); /* not Xclose() - see above */
Xfree(xs, xp);
return NULL;
}
/* Look in current context always. (os2 style) */
- if (search_access(Xstring(xs, xp), mode) == 0)
+ if (search_access(Xstring(xs, xp), mode, errnop) == 0)
return Xstring(xs, xp); /* not Xclose() - xp may be wrong */
#else /* OS2 */
if (ksh_strchr_dirsep(name)) {
- if (search_access(name, mode) == 0)
+ if (search_access(name, mode, errnop) == 0)
return (char *) name;
return NULL;
}
@@ -1140,7 +1221,7 @@ search(name, path, mode)
sp = p;
XcheckN(xs, xp, namelen);
memcpy(xp, name, namelen);
- if (search_access(Xstring(xs, xp), mode) == 0)
+ if (search_access(Xstring(xs, xp), mode, errnop) == 0)
#ifdef OS2
return Xstring(xs, xp); /* Not Xclose() - see above */
#else /* OS2 */
@@ -1177,8 +1258,9 @@ call_builtin(tp, wp)
* set up redirection, saving old fd's in e->savefd
*/
static int
-iosetup(iop)
+iosetup(iop, tp)
register struct ioword *iop;
+ struct tbl *tp;
{
register int u = -1;
char *cp = iop->name;
@@ -1197,7 +1279,7 @@ iosetup(iop)
if (Flag(FXTRACE))
shellf("%s%s\n",
- substitute(str_val(global("PS4")), 0),
+ PS4_SUBSTITUTE(str_val(global("PS4"))),
snptreef((char *) 0, 32, "%R", &iotmp));
switch (iotype) {
@@ -1287,23 +1369,19 @@ iosetup(iop)
close(u);
return -1;
}
- if (iotype == IODUP) {
+ if (iotype != IODUP)
+ close(u);
#ifdef KSH
- if (iop->flag & IORDUP) /* possible <&p */
- /* Ensure other side of read pipe is
- * closed so EOF can be read properly
- */
- coproc_readw_close(u);
- else /* possible >&p */
- /* If co-process input is duped,
- * close shell's copy
- */
+ /* Touching any co-process fd in an empty exec
+ * causes the shell to close its copies
+ */
+ else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
+ if (iop->flag & IORDUP) /* possible exec <&p */
+ coproc_read_close(u);
+ else /* possible exec >&p */
coproc_write_close(u);
-#else /* KSH */
- ;
+ }
#endif /* KSH */
- } else
- close(u);
}
if (u == 2) /* Clear any write errors */
shf_reopen(2, SHF_WR, shl_out);
@@ -1387,27 +1465,35 @@ herein(hname, sub)
* print the args in column form - assuming that we can
*/
static char *
-do_selectargs(ap)
+do_selectargs(ap, print_menu)
register char **ap;
+ bool_t print_menu;
{
static const char *const read_args[] = {
"read", "-r", "REPLY", (char *) 0
};
char *s;
- int i, UNINITIALIZED(argct);
+ int i, argct;
+ for (argct = 0; ap[argct]; argct++)
+ ;
while (1) {
- argct = pr_menu(ap);
+ /* Menu is printed if
+ * - this is the first time around the select loop
+ * - the user enters a blank line
+ * - the REPLY parameter is empty
+ */
+ if (print_menu || !*str_val(global("REPLY")))
+ pr_menu(ap);
shellf("%s", str_val(global("PS3")));
if (call_builtin(findcom("read", FC_BI), (char **) read_args))
return (char *) 0;
s = str_val(global("REPLY"));
- while (*s && isspace(*s))
- s++;
if (*s) {
i = atoi(s);
return (i >= 1 && i <= argct) ? ap[i - 1] : null;
}
+ print_menu = 1;
}
}
diff --git a/bin/ksh/expr.c b/bin/ksh/expr.c
index bd94ca68f27..2d70ed1cd1d 100644
--- a/bin/ksh/expr.c
+++ b/bin/ksh/expr.c
@@ -1,21 +1,10 @@
-/* $OpenBSD: expr.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: expr.c,v 1.2 1996/08/19 20:08:50 downsj Exp $ */
/*
* Korn expression evaluation
*/
/*
* todo: better error handling: if in builtin, should be builtin error, etc.
- * todo: add ++ --
- * todo: recursive variable expansion (y=1;x=y; let x)
- how to deal with allowing:
- i=0
- set -A x 'x[1]' 'x[2]' 'x[3]' 99
- let z=x[i+=1]
- echo $z
- 99
- and disallowing:
- x='y[x]'
- let z=x
*/
#include "sh.h"
@@ -24,8 +13,10 @@
/* The order of these enums is constrained by the order of opinfo[] */
enum token {
+ /* some (long) unary operators */
+ O_PLUSPLUS = 0, O_MINUSMINUS,
/* binary operators */
- O_EQ = 0, O_NE,
+ O_EQ, O_NE,
/* assignments are assumed to be in range O_ASN .. O_BORASN */
O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
@@ -39,6 +30,7 @@ enum token {
O_BXOR,
O_BOR,
O_TERN,
+ O_COMMA,
/* things after this aren't used as binary operators */
/* unary that are not also binaries */
O_BNOT, O_LNOT,
@@ -47,7 +39,7 @@ enum token {
/* things that don't appear in the opinfo[] table */
VAR, LIT, END, BAD
};
-#define LAST_BINOP O_TERN
+#define IS_BINOP(op) (((int)op) >= O_EQ && ((int)op) <= O_COMMA)
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
enum prec {
@@ -63,9 +55,10 @@ enum prec {
P_LAND, /* && */
P_LOR, /* || */
P_TERN, /* ?: */
- P_ASSIGN /* = *= /= %= += -= <<= >>= &= ^= |= */
+ P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */
+ P_COMMA /* , */
};
-#define MAX_PREC P_ASSIGN
+#define MAX_PREC P_COMMA
struct opinfo {
char name[4];
@@ -78,6 +71,8 @@ struct opinfo {
* of enum token too.
*/
static const struct opinfo opinfo[] = {
+ { "++", 2, P_PRIMARY }, /* before + */
+ { "--", 2, P_PRIMARY }, /* before - */
{ "==", 2, P_EQUALITY }, /* before = */
{ "!=", 2, P_EQUALITY }, /* before ! */
{ "=", 1, P_ASSIGN }, /* keep assigns in a block */
@@ -108,6 +103,7 @@ static const struct opinfo opinfo[] = {
{ "^", 1, P_BXOR },
{ "|", 1, P_BOR },
{ "?", 1, P_TERN },
+ { ",", 1, P_COMMA },
{ "~", 1, P_PRIMARY },
{ "!", 1, P_PRIMARY },
{ "(", 1, P_PRIMARY },
@@ -122,12 +118,16 @@ struct expr_state {
const char *expression; /* expression being evaluated */
const char *tokp; /* lexical position */
enum token tok; /* token from token() */
- int noassign; /* don't do assignments (for ?:) */
+ int noassign; /* don't do assigns (for ?:,&&,||) */
struct tbl *val; /* value from token() */
+ struct tbl *evaling; /* variable that is being recursively
+ * expanded (EXPRINEVAL flag set)
+ */
Expr_state *volatile prev; /* previous state */
};
-enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_BADVAR, ET_STR };
+enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
+ ET_LVALUE, ET_RDONLY, ET_STR };
static Expr_state *es;
@@ -135,6 +135,9 @@ static void evalerr ARGS((enum error_type type, const char *str))
GCC_FUNC_ATTR(noreturn);
static struct tbl *evalexpr ARGS((enum prec prec));
static void token ARGS((void));
+static struct tbl *do_ppmm ARGS((enum token op, struct tbl *vasn,
+ bool_t is_prefix));
+static void assign_check ARGS((enum token op, struct tbl *vasn));
static struct tbl *tempvar ARGS((void));
static struct tbl *intvar ARGS((struct tbl *vp));
@@ -174,11 +177,15 @@ v_evaluate(vp, expr, error_ok)
curstate.expression = curstate.tokp = expr;
curstate.noassign = 0;
curstate.prev = es;
+ curstate.evaling = (struct tbl *) 0;
es = &curstate;
newenv(E_ERRH);
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
+ /* Clear EXPRINEVAL in of any variables we were playing with */
+ if (curstate.evaling)
+ curstate.evaling->flag &= ~EXPRINEVAL;
quitenv();
es = curstate.prev;
if (i == LAEXPR) {
@@ -248,8 +255,18 @@ evalerr(type, str)
warningf(TRUE, "%s: bad number `%s'", es->expression, str);
break;
- case ET_BADVAR:
- warningf(TRUE, "%s: value of variable `%s' not a number",
+ case ET_RECURSIVE:
+ warningf(TRUE, "%s: expression recurses on parameter `%s'",
+ es->expression, str);
+ break;
+
+ case ET_LVALUE:
+ warningf(TRUE, "%s: %s requires lvalue",
+ es->expression, str);
+ break;
+
+ case ET_RDONLY:
+ warningf(TRUE, "%s: %s applied to read only variable",
es->expression, str);
break;
@@ -289,6 +306,10 @@ evalexpr(prec)
if (es->tok != CLOSE_PAREN)
evalerr(ET_STR, "missing )");
token();
+ } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
+ token();
+ vl = do_ppmm(op, es->val, TRUE);
+ token();
} else if (op == VAR || op == LIT) {
vl = es->val;
token();
@@ -296,20 +317,22 @@ evalexpr(prec)
evalerr(ET_UNEXPECTED, (char *) 0);
/*NOTREACHED*/
}
+ if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
+ vl = do_ppmm(es->tok, vl, FALSE);
+ token();
+ }
return vl;
}
vl = evalexpr(((int) prec) - 1);
- while ((int) (op = es->tok) <= (int) LAST_BINOP && opinfo[(int) op].prec == prec) {
+ for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
+ op = es->tok)
+ {
token();
vasn = vl;
if (op != O_ASN) /* vl may not have a value yet */
vl = intvar(vl);
if (IS_ASSIGNOP(op)) {
- if (vasn->name[0] == '\0')
- evalerr(ET_STR, "assignment to non-lvalue");
- else if (vasn->flag & RDONLY)
- evalerr(ET_STR,
- "assignment to read only variable");
+ assign_check(op, vasn);
vr = intvar(evalexpr(P_ASSIGN));
} else if (op != O_TERN && op != O_LAND && op != O_LOR)
vr = intvar(evalexpr(((int) prec) - 1));
@@ -409,7 +432,7 @@ evalexpr(prec)
token();
if (e)
es->noassign++;
- vr = evalexpr(MAX_PREC);
+ vr = evalexpr(P_TERN);
if (e)
es->noassign--;
vl = e ? vl : vr;
@@ -418,6 +441,9 @@ evalexpr(prec)
case O_ASN:
res = vr->val.i;
break;
+ case O_COMMA:
+ res = vr->val.i;
+ break;
}
if (IS_ASSIGNOP(op)) {
vr->val.i = res;
@@ -447,20 +473,21 @@ token()
if (c == '\0')
es->tok = END;
else if (letter(c)) {
- for (; letnum(c); c = *cp++)
- ;
+ for (; letnum(c); c = *cp)
+ cp++;
if (c == '[') {
int len;
- len = array_ref_len(cp - 1);
+ len = array_ref_len(cp);
if (len == 0)
evalerr(ET_STR, "missing ]");
cp += len;
}
- if (es->noassign)
+ if (es->noassign) {
es->val = tempvar();
- else {
- tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP);
+ es->val->flag |= EXPRLVALUE;
+ } else {
+ tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP);
es->val = global(tvar);
afree(tvar, ATEMP);
}
@@ -494,6 +521,41 @@ token()
es->tokp = cp;
}
+/* Do a ++ or -- operation */
+static struct tbl *
+do_ppmm(op, vasn, is_prefix)
+ enum token op;
+ struct tbl *vasn;
+ bool_t is_prefix;
+{
+ struct tbl *vl;
+ int oval;
+
+ assign_check(op, vasn);
+
+ vl = intvar(vasn);
+ oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
+ if (vasn->flag & INTEGER)
+ setint_v(vasn, vl);
+ else
+ setint(vasn, vl->val.i);
+ if (!is_prefix) /* undo the inc/dec */
+ vl->val.i = oval;
+
+ return vl;
+}
+
+static void
+assign_check(op, vasn)
+ enum token op;
+ struct tbl *vasn;
+{
+ if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
+ evalerr(ET_LVALUE, opinfo[op].name);
+ else if (vasn->flag & RDONLY)
+ evalerr(ET_RDONLY, opinfo[op].name);
+}
+
static struct tbl *
tempvar()
{
@@ -517,22 +579,18 @@ intvar(vp)
/* try to avoid replacing a temp var with another temp var */
if (vp->name[0] == '\0'
- && (vp->flag & (ISSET|INTEGER)) == (ISSET|INTEGER))
+ && (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
return vp;
vq = tempvar();
- vq->type = 0;
if (setint_v(vq, vp) == NULL) {
- evalerr(ET_BADVAR, vp->name);
- /*
- if ((vp->flag&ISSET) && vp->val.s && *(vp->val.s)) {
- evalerr("bad number");
- } else {
- vq->flag |= (ISSET|INTEGER);
- vq->type = 10;
- vq->val.i = 0;
- }
- */
+ if (vp->flag & EXPRINEVAL)
+ evalerr(ET_RECURSIVE, vp->name);
+ es->evaling = vp;
+ vp->flag |= EXPRINEVAL;
+ v_evaluate(vq, str_val(vp), FALSE);
+ vp->flag &= ~EXPRINEVAL;
+ es->evaling = (struct tbl *) 0;
}
return vq;
}
diff --git a/bin/ksh/io.c b/bin/ksh/io.c
index 492c82e3b99..a5bfe1569a9 100644
--- a/bin/ksh/io.c
+++ b/bin/ksh/io.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: io.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: io.c,v 1.2 1996/08/19 20:08:51 downsj Exp $ */
/*
* shell buffered IO and formatted output
@@ -324,7 +324,7 @@ check_fd(name, mode, emsgp)
}
#ifdef KSH
else if (name[0] == 'p' && !name[1])
- return get_coproc_fd(mode, emsgp);
+ return coproc_getfd(mode, emsgp);
#endif /* KSH */
if (emsgp)
*emsgp = "illegal file descriptor name";
@@ -337,6 +337,8 @@ void
coproc_init()
{
coproc.read = coproc.readw = coproc.write = -1;
+ coproc.njobs = 0;
+ coproc.id = 0;
}
/* Called by c_read() when eof is read - close fd if it is the co-process fd */
@@ -345,12 +347,9 @@ coproc_read_close(fd)
int fd;
{
if (coproc.read >= 0 && fd == coproc.read) {
+ coproc_readw_close(fd);
close(coproc.read);
coproc.read = -1;
- if (coproc.readw >= 0) {
- close(coproc.readw);
- coproc.readw = -1;
- }
}
}
@@ -361,7 +360,7 @@ void
coproc_readw_close(fd)
int fd;
{
- if (coproc.read >= 0 && fd == coproc.read && coproc.readw >= 0) {
+ if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
close(coproc.readw);
coproc.readw = -1;
}
@@ -384,7 +383,7 @@ coproc_write_close(fd)
* (Used by check_fd() and by c_read/c_print to deal with -p option).
*/
int
-get_coproc_fd(mode, emsgp)
+coproc_getfd(mode, emsgp)
int mode;
const char **emsgp;
{
@@ -397,12 +396,13 @@ get_coproc_fd(mode, emsgp)
return -1;
}
-/* called to close file descriptors related to the coprocess (if any) */
+/* called to close file descriptors related to the coprocess (if any)
+ * Should be called with SIGCHLD blocked.
+ */
void
-cleanup_coproc(reuse)
+coproc_cleanup(reuse)
int reuse;
{
- coproc.job = (void *) 0;
/* This to allow co-processes to share output pipe */
if (!reuse || coproc.readw < 0 || coproc.read < 0) {
if (coproc.read >= 0) {
diff --git a/bin/ksh/jobs.c b/bin/ksh/jobs.c
index d40a092ac4b..e1c11fcd04a 100644
--- a/bin/ksh/jobs.c
+++ b/bin/ksh/jobs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: jobs.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: jobs.c,v 1.2 1996/08/19 20:08:52 downsj Exp $ */
/*
* Process and job control
@@ -140,6 +140,7 @@ struct job {
clock_t usrtime; /* user time used by job */
Proc *proc_list; /* process list */
Proc *last_proc; /* last process in list */
+ Coproc_id coproc_id; /* 0 or id of coprocess output pipe */
#ifdef TTY_PGRP
TTY_state ttystate; /* saved tty state for stopped jobs */
#endif /* TTY_PGRP */
@@ -177,7 +178,6 @@ static int child_max; /* CHILD_MAX */
#ifdef JOB_SIGS
-static sigset_t sm_default, sm_sigchld;
/* held_sigchld is set if sigchld occurs before a job is completely started */
static int held_sigchld;
#endif /* JOB_SIGS */
@@ -234,7 +234,8 @@ j_init(mflagset)
sigemptyset(&sm_sigchld);
sigaddset(&sm_sigchld, SIGCHLD);
- setsig(&sigtraps[SIGCHLD], j_sigchld, SS_RESTORE_ORIG|SS_FORCE);
+ setsig(&sigtraps[SIGCHLD], j_sigchld,
+ SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
#else /* JOB_SIGS */
/* Make sure SIGCHLD isn't ignored - can do odd things under SYSV */
setsig(&sigtraps[SIGCHLD], SIG_DFL, SS_RESTORE_ORIG|SS_FORCE);
@@ -253,9 +254,12 @@ j_init(mflagset)
if (Flag(FMONITOR) || Flag(FTALKING)) {
int i;
- /* j_change() sets these to SS_RESTORE_DFL if FMONITOR */
+ /* the TF_SHELL_USES test is a kludge that lets us know if
+ * if the signals have been changed by the shell.
+ */
for (i = NELEM(tt_sigs); --i >= 0; ) {
sigtraps[tt_sigs[i]].flags |= TF_SHELL_USES;
+ /* j_change() sets this to SS_RESTORE_DFL if FMONITOR */
setsig(&sigtraps[tt_sigs[i]], SIG_IGN,
SS_RESTORE_IGN|SS_FORCE);
}
@@ -397,9 +401,6 @@ j_change()
} else {
# ifdef TTY_PGRP
ttypgrp_ok = 0;
- /* the TF_SHELL_USES test is a kludge that lets us know if
- * if the signals have been changed by the shell.
- */
if (Flag(FTALKING))
for (i = NELEM(tt_sigs); --i >= 0; )
setsig(&sigtraps[tt_sigs[i]], SIG_IGN,
@@ -410,7 +411,7 @@ j_change()
|TF_ORIG_DFL))
setsig(&sigtraps[tt_sigs[i]],
(sigtraps[tt_sigs[i]].flags & TF_ORIG_IGN) ? SIG_IGN : SIG_DFL,
- SS_RESTORE_CURR|SS_FORCE);
+ SS_RESTORE_ORIG|SS_FORCE);
}
# endif /* TTY_PGRP */
if (!Flag(FTALKING))
@@ -483,12 +484,9 @@ exchild(t, flags, close_fd)
j->ppid = procpid;
j->age = ++njobs;
j->proc_list = p;
+ j->coproc_id = 0;
last_job = j;
last_proc = p;
- if (flags & XXCOM)
- j->flags |= JF_XXCOM;
- else if (!(flags & XBGND))
- j->flags |= JF_FG;
put_job(j, PJ_PAST_STOPPED);
}
@@ -535,8 +533,8 @@ exchild(t, flags, close_fd)
dotty = 1;
# ifdef NEED_PGRP_SYNC
if (j_sync_open) {
- close(j_sync_pipe[ischild ? 1 : 0]);
- j_sync_pipe[ischild ? 1 : 0] = -1;
+ close(j_sync_pipe[ischild]);
+ j_sync_pipe[ischild] = -1;
dosync = ischild;
}
# endif /* NEED_PGRP_SYNC */
@@ -571,18 +569,19 @@ exchild(t, flags, close_fd)
#endif /* JOBS */
/* used to close pipe input fd */
- if (close_fd >= 0 && (((orig_flags & XPCLOSE) && i != 0)
- || ((orig_flags & XCCLOSE) && i == 0)))
+ if (close_fd >= 0 && (((orig_flags & XPCLOSE) && !ischild)
+ || ((orig_flags & XCCLOSE) && ischild)))
close(close_fd);
- if (i == 0) { /* child */
+ if (ischild) { /* child */
+#ifdef KSH
+ /* Do this before restoring signal */
+ if (orig_flags & XCOPROC)
+ coproc_cleanup(FALSE);
+#endif /* KSH */
#ifdef JOB_SIGS
sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
#endif /* JOB_SIGS */
cleanup_parents_env();
-#ifdef KSH
- if (orig_flags & XCOPROC)
- cleanup_coproc(FALSE);
-#endif /* KSH */
#ifdef TTY_PGRP
/* If FMONITOR or FTALKING is set, these signals are ignored,
* if neither FMONITOR nor FTALKING are set, the signals have
@@ -604,9 +603,9 @@ exchild(t, flags, close_fd)
setsig(&sigtraps[SIGQUIT], SIG_IGN,
SS_RESTORE_IGN|SS_FORCE);
if (!(orig_flags & (XPIPEI | XCOPROC))) {
- i = open("/dev/null", 0);
- (void) ksh_dup2(i, 0, TRUE);
- close(i);
+ int fd = open("/dev/null", 0);
+ (void) ksh_dup2(fd, 0, TRUE);
+ close(fd);
}
}
remove_job(j, "child"); /* in case of `jobs` command */
@@ -634,8 +633,11 @@ exchild(t, flags, close_fd)
#endif /* TTY_PGRP */
j_startjob(j);
#ifdef KSH
- if (flags & XCOPROC)
- coproc.job = (void *) j;
+ if (orig_flags & XCOPROC) {
+ j->coproc_id = coproc.id;
+ coproc.njobs++; /* n jobs using co-process output */
+ coproc.job = (void *) j; /* j using co-process input */
+ }
#endif /* KSH */
if (flags & XBGND) {
j_set_async(j);
@@ -1268,8 +1270,6 @@ j_sigchld(sig)
WAIT_T status;
struct tms t0, t1;
- trapsig(sig);
-
#ifdef JOB_SIGS
/* Don't wait for any processes if a job is partially started.
* This is so we don't do away with the process group leader
@@ -1386,9 +1386,24 @@ check_job(j)
* remove_job() since neither may be called for non-interactive
* shells.
*/
- if ((j->state == PEXITED || j->state == PSIGNALLED)
- && coproc.job == (void *) j)
- coproc.job = (void *) 0;
+ if (j->state == PEXITED || j->state == PSIGNALLED) {
+ /* No need to keep co-process input any more
+ * (at leasst, this is what ksh93d thinks)
+ */
+ if (coproc.job == j) {
+ coproc.job = (void *) 0;
+ /* XXX would be nice to get the closes out of here
+ * so they aren't done in the signal handler.
+ * Would mean a check in coproc_getfd() to
+ * do "if job == 0 && write >= 0, close write".
+ */
+ coproc_write_close(coproc.write);
+ }
+ /* Do we need to keep the output? */
+ if (j->coproc_id && j->coproc_id == coproc.id
+ && --coproc.njobs == 0)
+ coproc_readw_close(coproc.read);
+ }
#endif /* KSH */
j->flags |= JF_CHANGED;
diff --git a/bin/ksh/ksh_stat.h b/bin/ksh/ksh_stat.h
index 0c6e5244f57..447b7b3f385 100644
--- a/bin/ksh/ksh_stat.h
+++ b/bin/ksh/ksh_stat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ksh_stat.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: ksh_stat.h,v 1.2 1996/08/19 20:08:54 downsj Exp $ */
/* Wrapper around the ugly sys/stat includes/ifdefs */
@@ -15,6 +15,7 @@
# undef S_ISCHR
# undef S_ISBLK
# undef S_ISFIFO
+# undef S_ISSOCK
# undef S_ISLNK
#endif /* STAT_MACROS_BROKEN */
diff --git a/bin/ksh/lex.c b/bin/ksh/lex.c
index 06e912fae09..74ed0748fef 100644
--- a/bin/ksh/lex.c
+++ b/bin/ksh/lex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lex.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: lex.c,v 1.2 1996/08/19 20:08:55 downsj Exp $ */
/*
* lexical analysis and source input
@@ -968,6 +968,7 @@ set_prompt(to, s)
switch (to) {
case PS1: /* command */
+#ifdef KSH
/* Substitute ! and !! here, before substitutions are done
* so ! in expanded variables are not expanded.
* NOTE: this is not what at&t ksh does (it does it after
@@ -993,12 +994,20 @@ set_prompt(to, s)
newenv(E_ERRH);
if (ksh_sigsetjmp(e->jbuf, 0)) {
prompt = safe_prompt;
- warningf(TRUE, "error during expansion of PS1");
+ /* Don't print an error - assume it has already
+ * been printed. Reason is we may have forked
+ * to run a command and the child may be
+ * unwinding its stack through this code as it
+ * exits.
+ */
} else
prompt = str_save(substitute(ps1, 0),
saved_atemp);
quitenv();
}
+#else /* KSH */
+ prompt = str_val(global("PS1"));
+#endif /* KSH */
break;
case PS2: /* command continuation */
diff --git a/bin/ksh/mail.c b/bin/ksh/mail.c
index 3422a5873cc..a26bde87579 100644
--- a/bin/ksh/mail.c
+++ b/bin/ksh/mail.c
@@ -1,10 +1,13 @@
-/* $OpenBSD: mail.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: mail.c,v 1.2 1996/08/19 20:08:55 downsj Exp $ */
/*
* Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
* John R. MacMillan
*/
+#include "config.h"
+
+#ifdef KSH
#include "sh.h"
#include "ksh_stat.h"
#include "ksh_time.h"
@@ -183,3 +186,4 @@ mbox_t *mbp;
unset(vp, 0);
}
+#endif /* KSH */
diff --git a/bin/ksh/main.c b/bin/ksh/main.c
index 10290b31135..74118b7f037 100644
--- a/bin/ksh/main.c
+++ b/bin/ksh/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: main.c,v 1.2 1996/08/19 20:08:56 downsj Exp $ */
/*
* startup, main loop, enviroments and error handling
@@ -41,9 +41,9 @@ static const char *const initcoms [] = {
"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
"typeset", "-r", version_param, NULL,
"typeset", "-ri", "PPID", NULL,
- "typeset", "-i", "OPTIND=1", "MAILCHECK=600",
+ "typeset", "-i", "OPTIND=1",
#ifdef KSH
- "SECONDS=0", "RANDOM", "TMOUT=0",
+ "MAILCHECK=600", "RANDOM", "SECONDS=0", "TMOUT=0",
#endif /* KSH */
NULL,
"alias",
@@ -278,7 +278,7 @@ main(argc, argv)
* This changes the behavior of 'ksh arg' to search
* the users search path but it can't be helped.
*/
- s->file = search(argv[argi++], path, R_OK);
+ s->file = search(argv[argi++], path, R_OK, (int *) 0);
if (!s->file || !*s->file)
s->file = argv[argi - 1];
#else
@@ -406,7 +406,9 @@ main(argc, argv)
if (Flag(FTALKING)) {
hist_init(s);
+#ifdef KSH
alarm_init();
+#endif /* KSH */
} else
Flag(FTRACKALL) = 1; /* set after ENV */
@@ -568,7 +570,9 @@ shell(s, toplevel)
if (interactive) {
j_notify();
+#ifdef KSH
mcheck();
+#endif /* KSH */
set_prompt(PS1, s);
}
diff --git a/bin/ksh/misc.c b/bin/ksh/misc.c
index dcf7cc9bf63..dcbd8130b18 100644
--- a/bin/ksh/misc.c
+++ b/bin/ksh/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: misc.c,v 1.2 1996/08/19 20:08:57 downsj Exp $ */
/*
* Miscellaneous functions
@@ -14,7 +14,7 @@
# define UCHAR_MAX 0xFF
#endif
-char ctypes [UCHAR_MAX+1]; /* type bits for unsigned char */
+short ctypes [UCHAR_MAX+1]; /* type bits for unsigned char */
static int do_gmatch ARGS((const unsigned char *s, const unsigned char *p,
const unsigned char *se, const unsigned char *pe,
@@ -31,7 +31,7 @@ setctypes(s, t)
{
register int i;
- if ((t&C_IFS)) {
+ if (t & C_IFS) {
for (i = 0; i < UCHAR_MAX+1; i++)
ctypes[i] &= ~C_IFS;
ctypes[0] |= C_IFS; /* include \0 in C_IFS */
@@ -56,6 +56,7 @@ initctypes()
setctypes(" \t\n", C_IFSWS);
setctypes("=-+?", C_SUBOP1);
setctypes("#%", C_SUBOP2);
+ setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE);
}
/* convert unsigned long to base N string */
@@ -168,6 +169,7 @@ const struct option options[] = {
{ "viraw", 0, OF_ANY }, /* no effect */
{ "vi-show8", 0, OF_ANY }, /* non-standard */
{ "vi-tabcomplete", 0, OF_ANY }, /* non-standard */
+ { "vi-esccomplete", 0, OF_ANY }, /* non-standard */
#endif
{ "xtrace", 'x', OF_ANY },
{ NULL, 0, 0 }
@@ -982,7 +984,7 @@ ksh_getopt(argv, go, options)
go->buf[0] = c;
go->optarg = go->buf;
} else {
- warningf(TRUE, "%s%s-%c: bad option",
+ warningf(TRUE, "%s%s-%c: unknown option",
(go->flags & GF_NONAME) ? "" : argv[0],
(go->flags & GF_NONAME) ? "" : ": ", c);
if (go->flags & GF_ERROR)
@@ -1055,7 +1057,7 @@ print_value_quoted(s)
/* Test if any quotes are needed */
for (p = s; *p; p++)
- if (!letnum(*p) && *p != '/')
+ if (ctype(*p, C_QUOTE))
break;
if (!*p) {
shprintf("%s", s);
diff --git a/bin/ksh/proto.h b/bin/ksh/proto.h
index 067f28c64d0..a290e18a205 100644
--- a/bin/ksh/proto.h
+++ b/bin/ksh/proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proto.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: proto.h,v 1.2 1996/08/19 20:08:57 downsj Exp $ */
/*
* prototypes for PD-KSH
@@ -73,8 +73,9 @@ int define ARGS((const char *name, struct op *t));
void builtin ARGS((const char *name, int (*func)(char **)));
struct tbl * findcom ARGS((const char *name, int flags));
void flushcom ARGS((int all));
-char * search ARGS((const char *name, const char *path, int mode));
-int search_access ARGS((const char *path, int mode));
+char * search ARGS((const char *name, const char *path, int mode,
+ int *errnop));
+int search_access ARGS((const char *path, int mode, int *errnop));
int pr_menu ARGS((char *const *ap));
/* expr.c */
int evaluate ARGS((const char *expr, long *rval, int error_ok));
@@ -124,8 +125,8 @@ void coproc_init ARGS((void));
void coproc_read_close ARGS((int fd));
void coproc_readw_close ARGS((int fd));
void coproc_write_close ARGS((int fd));
-int get_coproc_fd ARGS((int mode, const char **emsgp));
-void cleanup_coproc ARGS((int reuse));
+int coproc_getfd ARGS((int mode, const char **emsgp));
+void coproc_cleanup ARGS((int reuse));
#endif /* KSH */
struct temp *maketemp ARGS((Area *ap));
/* jobs.c */
@@ -150,9 +151,11 @@ Source * pushs ARGS((int type, Area *areap));
void set_prompt ARGS((int to, Source *s));
void pprompt ARGS((const char *cp, int ntruncate));
/* mail.c */
+#ifdef KSH
void mcheck ARGS((void));
void mbset ARGS((char *p));
void mpset ARGS((char *mptoparse));
+#endif /* KSH */
/* main.c */
int include ARGS((const char *name, int argc, char **argv,
int intr_ok));
@@ -215,7 +218,9 @@ struct tbl ** tsort ARGS((struct table *tp));
/* trace.c */
/* trap.c */
void inittraps ARGS((void));
+#ifdef KSH
void alarm_init ARGS((void));
+#endif /* KSH */
Trap * gettrap ARGS((const char *name));
RETSIGTYPE trapsig ARGS((int i));
void intrcheck ARGS((void));
@@ -249,7 +254,7 @@ void setstr ARGS((struct tbl *vq, const char *s));
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));
-struct tbl * typeset ARGS((const char *var, int set, int clr, int field, int base));
+struct tbl * typeset ARGS((const char *var, Tflag set, Tflag clr, int field, int base));
void unset ARGS((struct tbl *vp, int array_ref));
char * skip_varname ARGS((const char *s, int aok));
char *skip_wdvarname ARGS((const char *s, int aok));
diff --git a/bin/ksh/sh.h b/bin/ksh/sh.h
index b7fcde1ac93..f6578427d9c 100644
--- a/bin/ksh/sh.h
+++ b/bin/ksh/sh.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sh.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: sh.h,v 1.2 1996/08/19 20:08:58 downsj Exp $ */
/*
* Public Domain Bourne/Korn shell
@@ -331,6 +331,9 @@ typedef int bool_t;
#define sizeofN(type, n) (sizeof(type) * (n))
#define BIT(i) (1<<(i)) /* define bit in flag */
+/* Table flag type - needs > 16 and < 32 bits */
+typedef INT32 Tflag;
+
#define NUFILE 10 /* Number of user-accessible files */
#define FDBASE 10 /* First file usable by Shell */
@@ -477,6 +480,7 @@ enum sh_flag {
FVIRAW, /* always read in raw mode (ignored) */
FVISHOW8, /* display chars with 8th bit set as is (versus M-) */
FVITABCOMPLETE, /* enable tab as file name completion char */
+ FVIESCCOMPLETE, /* enable ESC as file name completion in command mode */
#endif
FXTRACE, /* -x: execution trace */
FNFLAGS /* (place holder: how many flags are there) */
@@ -523,6 +527,7 @@ typedef struct trap {
int volatile set; /* trap pending */
int flags; /* TF_* */
handler_t cursig; /* current handler (valid if TF_ORIG_* set) */
+ handler_t shtrap; /* shell signal handler */
} Trap;
/* values for Trap.flags */
@@ -541,10 +546,11 @@ typedef struct trap {
#define SS_RESTORE_MASK 0x3 /* how to restore a signal before an exec() */
#define SS_RESTORE_CURR 0 /* leave current handler in place */
#define SS_RESTORE_ORIG 1 /* restore original handler */
-#define SS_RESTORE_DFL 2 /* restore SIG_DFL */
-#define SS_RESTORE_IGN 3 /* restore SIG_IGN */
+#define SS_RESTORE_DFL 2 /* restore to SIG_DFL */
+#define SS_RESTORE_IGN 3 /* restore to SIG_IGN */
#define SS_FORCE BIT(3) /* set signal even if original signal ignored */
#define SS_USER BIT(4) /* user is doing the set (ie, trap command) */
+#define SS_SHTRAP BIT(5) /* trap for internal use (CHLD,ALRM,WINCH) */
#define SIGEXIT_ 0 /* for trap EXIT */
#define SIGERR_ SIGNALS /* for trap ERR */
@@ -558,6 +564,7 @@ extern Trap sigtraps[SIGNALS+1];
#endif /* !FROM_TRAP_C */
+#ifdef KSH
/*
* TMOUT support
*/
@@ -569,6 +576,7 @@ enum tmout_enum {
};
EXTERN unsigned int ksh_tmout;
EXTERN enum tmout_enum ksh_tmout_state I__(TMOUT_EXECUTING);
+#endif /* KSH */
/* For "You have stopped jobs" message */
@@ -578,16 +586,17 @@ EXTERN int really_exit;
/*
* fast character classes
*/
-#define C_ALPHA 0x01 /* a-z_A-Z */
-#define C_DIGIT 0x02 /* 0-9 */
-#define C_LEX1 0x04 /* \0 \t\n|&;<>() */
-#define C_VAR1 0x08 /* *@#!$-? */
-#define C_IFSWS 0x10 /* \t \n (IFS white space) */
-#define C_SUBOP1 0x20 /* "=-+?" */
-#define C_SUBOP2 0x40 /* "#%" */
-#define C_IFS 0x80 /* $IFS */
-
-extern char ctypes [];
+#define C_ALPHA BIT(0) /* a-z_A-Z */
+#define C_DIGIT BIT(1) /* 0-9 */
+#define C_LEX1 BIT(2) /* \0 \t\n|&;<>() */
+#define C_VAR1 BIT(3) /* *@#!$-? */
+#define C_IFSWS BIT(4) /* \t \n (IFS white space) */
+#define C_SUBOP1 BIT(5) /* "=-+?" */
+#define C_SUBOP2 BIT(6) /* "#%" */
+#define C_IFS BIT(7) /* $IFS */
+#define C_QUOTE BIT(8) /* \n\t"#$&'()*;<>?[\`| (needing quoting) */
+
+extern short ctypes [];
#define ctype(c, t) !!(ctypes[(unsigned char)(c)]&(t))
#define letter(c) ctype(c, C_ALPHA)
@@ -623,20 +632,29 @@ EXTERN Getopt builtin_opt; /* for shell builtin commands */
#ifdef KSH
/* This for co-processes */
+
+typedef INT32 Coproc_id; /* something that won't (realisticly) wrap */
struct coproc {
int read; /* pipe from co-process's stdout */
int readw; /* other side of read (saved temporarily) */
int write; /* pipe to co-process's stdin */
- void *job; /* 0 if no co-process, or co-process died */
+ Coproc_id id; /* id of current output pipe */
+ int njobs; /* number of live jobs using output pipe */
+ void *job; /* 0 or job of co-process using input pipe */
};
EXTERN struct coproc coproc;
#endif /* KSH */
+/* Used in jobs.c and by coprocess stuff in exec.c */
+#ifdef JOB_SIGS
+EXTERN sigset_t sm_default, sm_sigchld;
+#endif /* JOB_SIGS */
+
extern const char ksh_version[];
/* name of called builtin function (used by error functions) */
EXTERN char *builtin_argv0;
-EXTERN int builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */
+EXTERN Tflag builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */
/* current working directory, and size of memory allocated for same */
EXTERN char *current_wd;
diff --git a/bin/ksh/syn.c b/bin/ksh/syn.c
index bd5db3740dd..8779c315841 100644
--- a/bin/ksh/syn.c
+++ b/bin/ksh/syn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: syn.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: syn.c,v 1.2 1996/08/19 20:08:59 downsj Exp $ */
/*
* shell parser (C version)
@@ -224,7 +224,7 @@ get_command(cf)
syniocf &= ~(KEYWORD|ALIAS);
t = newtp(TCOM);
while (1) {
- cf = (t->evalflags ? ARRAYVAR : 0)
+ cf = (t->u.evalflags ? ARRAYVAR : 0)
| (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);
switch (tpeek(cf)) {
case REDIR:
@@ -241,7 +241,7 @@ get_command(cf)
if (iopn == 0 && XPsize(vars) == 0
&& XPsize(args) == 0
&& assign_command(ident))
- t->evalflags = DOVACHECK;
+ t->u.evalflags = DOVACHECK;
if ((XPsize(args) == 0 || Flag(FKEYWORD))
&& is_wdvarassign(yylval.cp))
XPput(vars, yylval.cp);
@@ -254,7 +254,7 @@ get_command(cf)
* allows (not POSIX, but not disallowed)
*/
afree(t, ATEMP);
- if (XPsize(args) == 0 && XPsize(vars) != 0) {
+ if (XPsize(args) == 0 && XPsize(vars) == 0) {
ACCEPT;
goto Subshell;
}
@@ -334,7 +334,7 @@ get_command(cf)
case WHILE:
case UNTIL:
multiline_push(&old_multiline, c);
- t = newtp((c == WHILE) ? TWHILE: TUNTIL);
+ t = newtp((c == WHILE) ? TWHILE : TUNTIL);
t->left = c_list();
t->right = dogroup();
multiline_pop(&old_multiline);
@@ -552,6 +552,7 @@ function_body(name, ksh_func)
}
t = newtp(TFUNCT);
t->str = Xclose(xs, xp);
+ t->u.ksh_func = ksh_func;
/* 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
@@ -763,7 +764,7 @@ newtp(type)
t = (struct op *) alloc(sizeof(*t), ATEMP);
t->type = type;
- t->evalflags = 0;
+ t->u.evalflags = 0;
t->args = t->vars = NULL;
t->ioact = NULL;
t->left = t->right = NULL;
diff --git a/bin/ksh/table.c b/bin/ksh/table.c
index 03558fa137a..3b2861bb63f 100644
--- a/bin/ksh/table.c
+++ b/bin/ksh/table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: table.c,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
+/* $OpenBSD: table.c,v 1.2 1996/08/19 20:08:59 downsj Exp $ */
/*
* dynamic hashed associative table for commands and variables
@@ -64,7 +64,7 @@ texpand(tp, nsize)
p += tp->size;
*p = tblp;
tp->nfree--;
- } else {
+ } else if (!(tblp->flag & FINUSE)) {
afree((void*)tblp, tp->areap);
}
afree((void*)otblp, tp->areap);
@@ -125,7 +125,7 @@ tenter(tp, n, h)
p->flag = 0;
p->type = 0;
p->areap = tp->areap;
- p->field = 0;
+ p->u2.field = 0;
p->u.array = (struct tbl *)0;
memcpy(p->name, n, len);
diff --git a/bin/ksh/table.h b/bin/ksh/table.h
index 1dfc08942fa..753339c33bc 100644
--- a/bin/ksh/table.h
+++ b/bin/ksh/table.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: table.h,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: table.h,v 1.2 1996/08/19 20:09:00 downsj Exp $ */
/* $From: table.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */
@@ -13,7 +13,7 @@ struct table {
};
struct tbl { /* table item */
- INT32 flag; /* flags */
+ Tflag flag; /* flags */
int type; /* command type (see below), base (if INTEGER),
* or offset from val.s of value (if EXPORT) */
Area *areap; /* area to allocate from */
@@ -24,7 +24,10 @@ struct tbl { /* table item */
struct op *t; /* "function" tree */
} val; /* value */
int index; /* index for an array */
- int field; /* field with for -L/-R/-Z */
+ union {
+ int field; /* field with for -L/-R/-Z */
+ int errno_; /* CEXEC/CTALIAS */
+ } u2;
union {
struct tbl *array; /* array values */
char *fpath; /* temporary path to undef function */
@@ -54,12 +57,15 @@ struct tbl { /* table item */
#define INT_L BIT(20) /* long integer (no-op) */
#define IMPORT BIT(21) /* flag to typeset(): no arrays, must have = */
#define LOCAL_COPY BIT(22) /* with LOCAL - copy attrs from existing var */
+#define EXPRINEVAL BIT(23) /* contents currently being evaluated */
+#define EXPRLVALUE BIT(24) /* useable as lvalue (temp flag) */
/* flag bits used for taliases/builtins/aliases/keywords/functions */
#define KEEPASN BIT(8) /* keep command assignments (eg, var=x cmd) */
#define FINUSE BIT(9) /* function being executed */
#define FDELETE BIT(10) /* function deleted while it was executing */
-#define SPEC_BI BIT(11) /* a POSIX special builtin */
-#define REG_BI BIT(12) /* a POSIX regular builtin */
+#define FKSH BIT(11) /* function defined with function x (vs x()) */
+#define SPEC_BI BIT(12) /* a POSIX special builtin */
+#define REG_BI BIT(13) /* a POSIX regular builtin */
/* command types */
#define CNONE 0 /* undefined */
diff --git a/bin/ksh/tests/arith.t b/bin/ksh/tests/arith.t
new file mode 100644
index 00000000000..e18ea2e9d78
--- /dev/null
+++ b/bin/ksh/tests/arith.t
@@ -0,0 +1,79 @@
+name: arith-lazy-1
+description:
+ Check that only one side of ternary operator is evaluated
+stdin:
+ x=i+=2
+ y=j+=2
+ typeset -i i=1 j=1
+ echo $((1 ? 20 : (x+=2)))
+ echo $i,$x
+ echo $((0 ? (y+=2) : 30))
+ echo $j,$y
+expected-stdout:
+ 20
+ 1,i+=2
+ 30
+ 1,j+=2
+---
+
+name: arith-lazy-2
+description:
+ Check that assignments not done on non-evaluated side of ternary
+ operator
+stdin:
+ x=i+=2
+ y=j+=2
+ typeset -i i=1 j=1
+ echo $((1 ? 20 : (x+=2)))
+ echo $i,$x
+ echo $((0 ? (y+=2) : 30))
+ echo $i,$y
+expected-stdout:
+ 20
+ 1,i+=2
+ 30
+ 1,j+=2
+---
+
+name: arith-ternary-prec-1
+description:
+ Check precidance of ternary operator vs assignment
+stdin:
+ typeset -i x=2
+ y=$((1 ? 20 : x+=2))
+expected-exit: e != 0
+expected-stderr-pattern:
+ /.*:.*1 \? 20 : x\+=2.*lvalue.*\n$/
+---
+
+name: arith-ternary-prec-2
+description:
+ Check precidance of ternary operator vs assignment
+stdin:
+ typeset -i x=2
+ echo $((0 ? x+=2 : 20))
+expected-stdout:
+ 20
+---
+
+name: arith-div-assoc-1
+description:
+ Check associativity of division operator
+stdin:
+ echo $((20 / 2 / 2))
+expected-stdout:
+ 5
+---
+
+name: arith-assop-assoc-1
+description:
+ Check associativity of assignment-operator operator
+stdin:
+ typeset -i i=1 j=2 k=3
+ echo $((i += j += k))
+ echo $i,$j,$k
+expected-stdout:
+ 6
+ 6,5,3
+---
+
diff --git a/bin/ksh/tests/regress.t b/bin/ksh/tests/regress.t
index 95fe97b6b7c..d78a02641de 100644
--- a/bin/ksh/tests/regress.t
+++ b/bin/ksh/tests/regress.t
@@ -639,3 +639,27 @@ expected-exit: e != 0
expected-stderr-pattern:
/.*read *only.*/
---
+
+name: regression-43
+description:
+ Can subshells be prefixed by redirections (historical shells allow
+ this)
+stdin:
+ < /dev/null (cat -n)
+---
+
+name: regression-44
+description:
+ getopts sets OPTIND correctly for unparsed option
+stdin:
+ set -- -a -a -x
+ while getopts :a optc; do
+ echo "OPTARG=$OPTARG, OPTIND=$OPTIND, optc=$optc."
+ done
+ echo done
+expected-stdout:
+ OPTARG=, OPTIND=2, optc=a.
+ OPTARG=, OPTIND=3, optc=a.
+ OPTARG=x, OPTIND=3, optc=?.
+ done
+---
diff --git a/bin/ksh/tests/th b/bin/ksh/tests/th
index 496058ccd4e..340cbe2d5dc 100644
--- a/bin/ksh/tests/th
+++ b/bin/ksh/tests/th
@@ -169,7 +169,13 @@ foreach $env (('USER', 'LOGNAME', 'HOME', 'PATH', 'SHELL')) {
$new_env{$env} = $ENV{$env} if defined $ENV{$env};
}
%old_env = %ENV;
-%ENV = %new_env;
+
+# The following doesn't work with perl5... Need to do it explicitly - yuck.
+#%ENV = %new_env;
+foreach $k (keys(%ENV)) {
+ delete $ENV{$k};
+}
+$ENV{$k} = $v while ($k,$v) = each %new_env;
die "$prog: couldn't make directory $tempdir - $!\n" if !mkdir($tempdir, 0777);
diff --git a/bin/ksh/tests/th.sh b/bin/ksh/tests/th.sh
index 6e40c19dcf9..f26b8699e94 100644
--- a/bin/ksh/tests/th.sh
+++ b/bin/ksh/tests/th.sh
@@ -4,12 +4,18 @@
# Simple script to find perl and run it
#
+# Avoid common problems with ENV (though perl shouldn't let it through)
+unset ENV
+
+x=x
+[ -x /bin/sh ] 2> /dev/null || x=f
+
IFS=:$IFS
perl=
for i in $PATH; do
[ X"$i" = X ] && i=.
for j in perl perl4 perl5 ; do
- [ -x "$i/$j" ] && perl=$i/$j && break 2
+ [ -$x "$i/$j" ] && perl=$i/$j && break 2
done
done
diff --git a/bin/ksh/tests/version.t b/bin/ksh/tests/version.t
index aed94d01760..0ec6fbac7b5 100644
--- a/bin/ksh/tests/version.t
+++ b/bin/ksh/tests/version.t
@@ -4,5 +4,5 @@ description:
stdin:
echo $KSH_VERSION
expected-stdout:
- @(#)PD KSH v5.2.7 96/06/04
+ @(#)PD KSH v5.2.8 96/08/19
---
diff --git a/bin/ksh/trap.c b/bin/ksh/trap.c
index e4ecdd39efa..7933f2d7e31 100644
--- a/bin/ksh/trap.c
+++ b/bin/ksh/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: trap.c,v 1.2 1996/08/19 20:09:00 downsj Exp $ */
/*
* signal handling
@@ -19,9 +19,7 @@ Trap sigtraps[SIGNALS+1] = {
{ SIGERR_, "ERR", "Error handler" },
};
-static RETSIGTYPE alarm_catcher ARGS((int sig));
-
-static struct sigaction Sigact_ign, Sigact_trap, Sigact_alarm;
+static struct sigaction Sigact_ign, Sigact_trap;
void
inittraps()
@@ -43,8 +41,6 @@ inittraps()
Sigact_ign.sa_handler = SIG_IGN;
Sigact_trap = Sigact_ign;
Sigact_trap.sa_handler = trapsig;
- Sigact_alarm = Sigact_ign;
- Sigact_alarm.sa_handler = alarm_catcher;
sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
@@ -59,20 +55,21 @@ inittraps()
setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
}
+#ifdef KSH
+static RETSIGTYPE alarm_catcher ARGS((int sig));
+
void
alarm_init()
{
sigtraps[SIGALRM].flags |= TF_SHELL_USES;
setsig(&sigtraps[SIGALRM], alarm_catcher,
- SS_RESTORE_ORIG|SS_FORCE);
+ SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
}
static RETSIGTYPE
alarm_catcher(sig)
int sig;
{
- trapsig(sig);
-#ifdef KSH
if (ksh_tmout_state == TMOUT_READING) {
int left = alarm(0);
@@ -82,12 +79,9 @@ alarm_catcher(sig)
} else
alarm(left);
}
-#endif /* KSH */
-#ifdef V7_SIGNALS
- sigaction(sig, &Sigact_alarm, (struct sigaction *) 0);
-#endif /* V7_SIGNALS */
return RETSIGVAL;
}
+#endif /* KSH */
Trap *
gettrap(name)
@@ -125,6 +119,8 @@ trapsig(i)
fatal_trap = 1;
intrsig = 1;
}
+ if (p->shtrap)
+ (*p->shtrap)(i);
#ifdef V7_SIGNALS
if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
sigaction(i, &Sigact_trap, (struct sigaction *) 0);
@@ -363,22 +359,37 @@ setsig(p, f, flags)
if (p->signal == SIGEXIT_ || p->signal == SIGERR_)
return 1;
+ /* First time setting this signal? If so, get and note the current
+ * setting.
+ */
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
sigaction(p->signal, &Sigact_ign, &sigact);
p->flags |= sigact.sa_handler == SIG_IGN ?
TF_ORIG_IGN : TF_ORIG_DFL;
p->cursig = SIG_IGN;
}
- if ((p->flags & TF_ORIG_IGN) && (flags & SS_USER)
- && !(flags & SS_FORCE) && !Flag(FTALKING))
+
+ /* Generally, an ignored signal stays ignored, except if
+ * - the user of an interactive shell wants to change it
+ * - the shell wants for force a change
+ */
+ if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE)
+ && (!(flags & SS_USER) || !Flag(FTALKING)))
return 0;
- if (!(flags & SS_USER)) {
- if (!(flags & SS_FORCE) && (p->flags & TF_ORIG_IGN))
- return 0;
- }
setexecsig(p, flags & SS_RESTORE_MASK);
+ /* This is here 'cause there should be a way of clearing shtraps, but
+ * don't know if this is a sane way of doing it. At the moment,
+ * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
+ */
+ if (!(flags & SS_USER))
+ p->shtrap = (handler_t) 0;
+ if (flags & SS_SHTRAP) {
+ p->shtrap = f;
+ f = trapsig;
+ }
+
if (p->cursig != f) {
p->cursig = f;
sigemptyset(&sigact.sa_mask);
diff --git a/bin/ksh/tree.c b/bin/ksh/tree.c
index 3ceb7756cf7..105158787b3 100644
--- a/bin/ksh/tree.c
+++ b/bin/ksh/tree.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tree.c,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: tree.c,v 1.2 1996/08/19 20:09:01 downsj Exp $ */
/*
* command tree climbing
@@ -478,7 +478,7 @@ tcopy(t, ap)
r = (struct op *) alloc(sizeof(struct op), ap);
r->type = t->type;
- r->evalflags = t->evalflags;
+ r->u.evalflags = t->u.evalflags;
r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
diff --git a/bin/ksh/tree.h b/bin/ksh/tree.h
index 29be89ccc4a..863061dd91d 100644
--- a/bin/ksh/tree.h
+++ b/bin/ksh/tree.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tree.h,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: tree.h,v 1.2 1996/08/19 20:09:02 downsj Exp $ */
/*
* command trees for compile/execute
@@ -15,7 +15,10 @@
*/
struct op {
short type; /* operation type, see below */
- short evalflags; /* eval() flags for arg expansion */
+ union { /* WARNING: newtp(), tcopy() use evalflags = 0 to clear union */
+ short evalflags; /* TCOM: arg expansion eval() flags */
+ short ksh_func; /* TFUNC: function x (vs x()) */
+ } u;
char **args; /* arguments to a command */
char **vars; /* variable assignments */
struct ioword **ioact; /* IO actions (eg, < > >>) */
@@ -31,7 +34,7 @@ struct op {
#define TCOM 1 /* command */
#define TPAREN 2 /* (c-list) */
#define TPIPE 3 /* a | b */
-#define TLIST 4 /* a [&;] b */
+#define TLIST 4 /* a ; b */
#define TOR 5 /* || */
#define TAND 6 /* && */
#define TBANG 7 /* ! */
diff --git a/bin/ksh/var.c b/bin/ksh/var.c
index 8a4922b4903..b31b41d48a1 100644
--- a/bin/ksh/var.c
+++ b/bin/ksh/var.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: var.c,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: var.c,v 1.2 1996/08/19 20:09:02 downsj Exp $ */
#include "sh.h"
#include "ksh_time.h"
@@ -82,9 +82,6 @@ initvar()
} names[] = {
{ "COLUMNS", V_COLUMNS },
{ "IFS", V_IFS },
- { "MAIL", V_MAIL },
- { "MAILCHECK", V_MAILCHECK },
- { "MAILPATH", V_MAILPATH },
{ "OPTIND", V_OPTIND },
{ "PATH", V_PATH },
{ "POSIXLY_CORRECT", V_POSIXLY_CORRECT },
@@ -98,6 +95,9 @@ initvar()
{ "VISUAL", V_VISUAL },
#endif /* EDIT */
#ifdef KSH
+ { "MAIL", V_MAIL },
+ { "MAILCHECK", V_MAILCHECK },
+ { "MAILPATH", V_MAILPATH },
{ "RANDOM", V_RANDOM },
{ "SECONDS", V_SECONDS },
{ "TMOUT", V_TMOUT },
@@ -247,7 +247,7 @@ local(n, copy)
h = hash(n);
if (!letter(*n)) {
vp = &vtemp;
- vp->flag = (DEFINED|RDONLY);
+ vp->flag = DEFINED|RDONLY;
vp->type = 0;
vp->areap = ATEMP;
return vp;
@@ -265,7 +265,7 @@ local(n, copy)
|LCASEV|UCASEV_AL|INT_U|INT_L);
if (vq->flag & INTEGER)
vp->type = vq->type;
- vp->field = vq->field;
+ vp->u2.field = vq->u2.field;
}
}
if (array)
@@ -352,7 +352,8 @@ setstr(vq, s)
if (s >= vq->val.s
&& s <= vq->val.s + strlen(vq->val.s))
internal_errorf(TRUE,
- "setstr: assigning to self");
+ "setstr: %s=%s: assigning to self",
+ vq->name, s);
afree((void*)vq->val.s, vq->areap);
}
vq->flag &= ~(ISSET|ALLOC);
@@ -486,9 +487,9 @@ formatstr(vp, s)
olen = strlen(s);
if (vp->flag & (RJUST|LJUST)) {
- if (!vp->field) /* default field width */
- vp->field = olen;
- nlen = vp->field;
+ if (!vp->u2.field) /* default field width */
+ vp->u2.field = olen;
+ nlen = vp->u2.field;
} else
nlen = olen;
@@ -502,14 +503,14 @@ formatstr(vp, s)
while (q > s && isspace(q[-1]))
--q;
slen = q - s;
- if (slen > vp->field) {
- s += slen - vp->field;
- slen = vp->field;
+ if (slen > vp->u2.field) {
+ s += slen - vp->u2.field;
+ slen = vp->u2.field;
}
shf_snprintf(p, nlen + 1,
((vp->flag & ZEROFIL) && digit(*s)) ?
"%0*s%.*s" : "%*s%.*s",
- vp->field - slen, null, slen, s);
+ vp->u2.field - slen, null, slen, s);
} else {
/* strip leading spaces/zeros */
while (isspace(*s))
@@ -518,7 +519,7 @@ formatstr(vp, s)
while (*s == '0')
s++;
shf_snprintf(p, nlen + 1, "%-*.*s",
- vp->field, vp->field, s);
+ vp->u2.field, vp->u2.field, s);
}
} else
memcpy(p, s, olen + 1);
@@ -568,7 +569,7 @@ export(vp, val)
struct tbl *
typeset(var, set, clr, field, base)
register const char *var;
- int clr, set;
+ Tflag clr, set;
int field, base;
{
register struct tbl *vp;
@@ -616,7 +617,8 @@ typeset(var, set, clr, field, base)
|| strcmp(tvar, "SHELL") == 0))
errorf("%s: restricted", tvar);
- vp = (set&LOCAL) ? local(tvar, set & LOCAL_COPY) : global(tvar);
+ vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? TRUE : FALSE)
+ : global(tvar);
set &= ~(LOCAL|LOCAL_COPY);
vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
@@ -668,7 +670,7 @@ typeset(var, set, clr, field, base)
if ((set & INTEGER) && base > 0 && (!val || t != vp))
t->type = base;
if (set & (LJUST|RJUST|ZEROFIL))
- t->field = field;
+ t->u2.field = field;
if (fake_assign) {
setstr(t, s);
if (free_me)
@@ -719,9 +721,10 @@ unset(vp, array_ref)
}
vp->u.array = (struct tbl *) 0;
}
- vp->flag &= SPECIAL; /* Should ``unspecial'' some vars */
+ /* If foo[0] is being unset, the remainder of the array is kept... */
+ vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
if (vp->flag & SPECIAL)
- unsetspec(vp);
+ unsetspec(vp); /* responsible for `unspecial'ing var */
}
/* return a pointer to the first char past a legal variable name (returns the
@@ -901,15 +904,6 @@ setspec(vp)
case V_OPTIND:
getopts_reset((int) intval(vp));
break;
- case V_MAIL:
- mbset(str_val(vp));
- break;
- case V_MAILPATH:
- mpset(str_val(vp));
- break;
- case V_MAILCHECK:
- /* mail_check_set(intval(vp)); */
- break;
case V_POSIXLY_CORRECT:
change_flag(FPOSIX, OF_SPECIAL, 1);
break;
@@ -953,6 +947,15 @@ setspec(vp)
break;
#endif /* EDIT */
#ifdef KSH
+ case V_MAIL:
+ mbset(str_val(vp));
+ break;
+ case V_MAILPATH:
+ mpset(str_val(vp));
+ break;
+ case V_MAILCHECK:
+ /* mail_check_set(intval(vp)); */
+ break;
case V_RANDOM:
vp->flag &= ~SPECIAL;
srand((unsigned int)intval(vp));
@@ -985,12 +988,6 @@ unsetspec(vp)
setctypes(" \t\n", C_IFS);
ifs0 = ' ';
break;
- case V_MAIL:
- mbset((char *) 0);
- break;
- case V_MAILPATH:
- mpset((char *) 0);
- break;
case V_TMPDIR:
/* should not become unspecial */
if (tmpdir) {
@@ -999,6 +996,12 @@ unsetspec(vp)
}
break;
#ifdef KSH
+ case V_MAIL:
+ mbset((char *) 0);
+ break;
+ 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
@@ -1057,7 +1060,7 @@ arraysearch(vp, val)
new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
new->type = vp->type;
new->areap = vp->areap;
- new->field = vp->field;
+ new->u2.field = vp->u2.field;
new->index = val;
if (curr != new) { /* not reusing old array entry */
prev->u.array = new;
@@ -1123,6 +1126,10 @@ set_array(var, reset, vals)
if (reset > 0)
/* trash existing values and attributes */
unset(vp, 0);
+ /* todo: would be nice for assignment to completely succeed or
+ * completely fail. Only really effects integer arrays:
+ * evaluation of some of vals[] may fail...
+ */
for (i = 0; vals[i]; i++) {
vq = arraysearch(vp, i);
setstr(vq, vals[i]);
diff --git a/bin/ksh/version.c b/bin/ksh/version.c
index 5c71a81d14b..edd71480d4c 100644
--- a/bin/ksh/version.c
+++ b/bin/ksh/version.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: version.c,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: version.c,v 1.2 1996/08/19 20:09:03 downsj Exp $ */
/*
* value of $KSH_VERSION (or $SH_VERSION)
@@ -7,4 +7,4 @@
#include "sh.h"
const char ksh_version [] =
- "@(#)PD KSH v5.2.7 96/06/04";
+ "@(#)PD KSH v5.2.8 96/08/19";
diff --git a/bin/ksh/vi.c b/bin/ksh/vi.c
index c4b2aeeee33..4fc7b75c511 100644
--- a/bin/ksh/vi.c
+++ b/bin/ksh/vi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vi.c,v 1.1 1996/08/14 06:19:12 downsj Exp $ */
+/* $OpenBSD: vi.c,v 1.2 1996/08/19 20:09:04 downsj Exp $ */
/*
* vi command editing
@@ -57,7 +57,6 @@ static void rewindow ARGS((void));
static int newcol ARGS((int ch, int col));
static void display ARGS((char *wb1, char *wb2, int leftside));
static void ed_mov_opt ARGS((int col, char *wb));
-static int do_comment ARGS((void));
static int expand_word ARGS((int command));
static int complete_word ARGS((int command, int count));
static int print_expansions ARGS((struct edstate *e, int command));
@@ -94,7 +93,7 @@ const unsigned char classify[128] = {
/* 02 ^P ^Q ^R ^S ^T ^U ^V ^W */
C_, 0, C_|U_, 0, 0, 0, C_, 0,
/* 03 ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
- C_, 0, 0, 0, 0, 0, 0, 0,
+ C_, 0, 0, C_|Z_, 0, 0, 0, 0,
/* 04 <space> ! " # $ % & ' */
M_, 0, 0, C_, M_, M_, 0, 0,
/* 05 ( ) * + , - . / */
@@ -1121,7 +1120,13 @@ vi_cmd(argcnt, cmd)
}
case '#':
- return do_comment();
+ {
+ int ret = x_do_comment(es->cbuf, es->cbufsize,
+ &es->linelen);
+ if (ret >= 0)
+ es->cursor = 0;
+ return ret;
+ }
case '=': /* at&t ksh */
case Ctrl('e'): /* Nonstandard vi/ksh */
@@ -1135,6 +1140,8 @@ vi_cmd(argcnt, cmd)
/* FALLTHROUGH */
case Ctrl('['): /* some annoying at&t ksh's */
+ if (!Flag(FVIESCCOMPLETE))
+ return -1;
case '\\': /* at&t ksh */
case Ctrl('f'): /* Nonstandard vi/ksh */
complete_word(1, argcnt);
@@ -1887,7 +1894,7 @@ display(wb1, wb2, leftside)
else
mc = ' ';
if (mc != morec) {
- ed_mov_opt(x_cols - 2, wb1);
+ ed_mov_opt(pwidth + winwidth + 1, wb1);
x_putc(mc);
cur_col++;
morec = mc;
@@ -1920,48 +1927,6 @@ ed_mov_opt(col, wb)
cur_col = col;
}
-/* Handle the commenting/uncommenting of a line */
-static int
-do_comment()
-{
- int i, j;
-
- if (es->linelen == 0)
- return 1; /* somewhat arbitrary - it's what at&t ksh does */
-
- /* Already commented? */
- if (es->cbuf[0] == '#') {
- int saw_nl = 0;
-
- for (j = 0, i = 1; i < es->linelen; i++) {
- if (!saw_nl || es->cbuf[i] != '#')
- es->cbuf[j++] = es->cbuf[i];
- saw_nl = es->cbuf[i] == '\n';
- }
- es->linelen = j;
- es->cursor = 0;
- return 0;
- } else {
- int n = 1;
-
- /* See if there's room for the #'s - 1 per \n */
- for (i = 0; i < es->linelen; i++)
- if (es->cbuf[i] == '\n')
- n++;
- if (es->linelen + n >= es->cbufsize)
- return -1;
- /* Now add them... */
- for (i = es->linelen, j = es->linelen + n; --i >= 0; ) {
- if (es->cbuf[i] == '\n')
- es->cbuf[--j] = '#';
- es->cbuf[--j] = es->cbuf[i];
- }
- es->cbuf[0] = '#';
- es->linelen += n;
- es->cursor = 0;
- return 1;
- }
-}
/* replace word with all expansions (ie, expand word*) */
static int