diff options
Diffstat (limited to 'bin/pdksh')
81 files changed, 0 insertions, 44904 deletions
diff --git a/bin/pdksh/BUG-REPORTS b/bin/pdksh/BUG-REPORTS deleted file mode 100644 index 1295a31fefb..00000000000 --- a/bin/pdksh/BUG-REPORTS +++ /dev/null @@ -1,1117 +0,0 @@ -$OpenBSD: BUG-REPORTS,v 1.5 1996/11/21 07:59:24 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 *, -problems believed to be fixed marked by x. - -* pdksh 5.0.3, MIPS RISC/os 5.0 (bsd universe) (noted by Michael Rendell): - for interactive, job controlled shells, the kernel's tty state gets twisted - in such a way that all output is lost (eg, if ttyXX is wedged then - "echo hi > /dev/ttyXX" from a seperate login appears to succeed but produces - no output on ttyXX). - Work around is to run a program and hit ^C. - -* pdksh 5.0.1, NetBSD 0.9a? (reported by Simon J. Gerraty): problem with - job control not finding tty - [from Mail.1:71]: - Also, I have noticed (with 5.0.1 anyway) that if as root I su to a - user I get: - root:511$ su foobar - warning: won't have full job control - [1] + Stopped (tty output) stty erase ^? - foobar:1$ - -* 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 - loses the partially entered command (vi mode). - [see Mail.2:48] - -* pdksh 5.0.10, - (reported by Andrew Moore): no overflow checking is done - in integer parsing code. - [see Mail.3:78] - -* pdksh 5.0.6+5.1.2, BSD43/MachTen (reported by Dan Menchaca): ksh freezes up - terminal after a while after printing process exit message. 5.1.2 causes - system to hang after executing two commands. - [see Mail.3:96,5:42] - -* pdksh 5.1.3, - (reported by Brad Warkentin & others): 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). - [see Mail.7:32,Mail.9:65] - -* pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs/vi doesn't have \ as quote - character. - [see Mail.7:87] - -* pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs default bindings doesn't - have vt52 arrow keys or vt100 alternate keypad mode bindings. - [see Mail.7:87] - -* pdksh 5.1.3, SCO 3.2.2 (reported by Gabor Zahemszky): shell hangs - waiting for finished process to finish. - [see Mail.7:87] - -* pdksh 5.2.0, - (reported by Gabor Zahemszky): ^V in vi leaves cursor at - start of the line. - [see Mail.8:43] - -* enhancements that haven't been merged yet - - Mail.6:36-39,78,84 recursive function diffs (add hard limit on - depeth of recursion) - -* pdksh 5.2.3, - (reported by David Gast(? gast@twinsun.com)): history (fc, - et al) don't work in shell scripts. - [see Mail.10:49] - -* pdksh 5.2.4, - (reported by Gabor Zahemszky): echo ${foo[*]#/} generates - bad substsitution error, newer ksh's don't (older ones do); - error includes {...#@(/)}. - [see Mail.XXX:XXX] - -* pdksh 5.2.4, - (reported by Gabor Zahemszky): emacs: ^P steps through - multiline commands - should go to start of command. - [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.8, - : extended pattern globing doesn't handle nested parens (). - -* pdksh 5.2.10, - (reported by Simon J. Gerraty): in emacs, <ESC><ESC> applied - to a word with a macro does not complete the word (only expands the macro). - [see Mail.XXX] - ---------------------- put fixed problems below this line --------------------- - -x pdksh 5.0.3, NetBSD 0.9a (reported by Simon J. Gerraty): pipelines - occasionally hang. - [from Mail.1:71]: - Yes, I just built 5.0.3 on zen (NetBSD) and the menu stuff worked fine. - However I've just done: - - sjg:910$ diff -cb /etc/profile profile | more - - And it has been sitting there ever since. - [... gdb output indicating process groups set up ok - presumed problem is - with tty process group] - [Fixed in 5.0.4 - do tcsetpgrp() in both parent and child for first process] - -x pdksh 5.0.2, ISC unix 3.01 (reported by Sean Hogan): set +o monitor (in - interactive shell?) closes tty - [from Mail.1:64]: - I'm having two problems with the job control code, which I believe might - be related. The first one is that "set +o monitor" closes the tty, - which causes the shell to exit since its input is gone. According to - the code, that would imply that FTALKING has mysteriously been turned - off (jobs.c:343). But my understanding of the code is that FTALKING - would only be clear for background processes, and set would be done by - the shell. Do you have any insights here? It's not a big deal of course; - I don't need to turn off monitor anyway. - [fixed in 5.0.5 - problem was tty process group was being restored so - shell could no longer read from tty] - -x pdksh 5.0.4, - (reported by Simon J. Gerraty and Sean Hogan): - test "" -a x would fail. - [fixed in 5.0.5 - t_wp being unnecessarily decremented in primary()] - -x pdksh 5.0.4, -: test -p foo would always fail. - [fixed in 5.0.5 - spell S_ISFIFO correctly] - -x pdksh 5.0.4, -: test ! ! foo would generate error (unexpected !) - [fixed in 5.0.5 - nexpr() always calls nexpr(), changes to posix code] - -x pdksh 5.0.4, -: set -i would generate an internal error. - [fixed in 5.0.5 - use OF_SET in creating set_opts] - -x pdksh 5.0.4, -: let 0>22 would evaluate to true (and 0<22 false) - [fixed in 5.0.5 - reversed order of O_LT and O_GT in enum] - -x pdksh 5.0.4, - (reported by Sean Hogan): echo does not process escape - characters (ie, echo "foo\c" doesn't to the sysV thing) - [see Mail.1:98] - [fixed in 5.0.5 - echo now behaves like sysv echo] - -x pdksh 5.0.4, - (reported by Sean Hogan): tty process groups not restored - properly (vi, :sh, exit causes vi to received SIGTTOU). - [see Mail.1:98] - [fixed in 5.0.5 - restore tty process group in j_exit] - -x pdksh 5.0.4, - (reported by Sean Hogan): the exit command does not do the - stopped jobs check. - [see Mail.1:94,95,98] - [fixed in 5.0.5 - added LSHELL, hack c_exitreturn to use it] - -x pdksh 5.0.3, ISC unix 3.01 (reported by Sean Hogan): if notify is set, - running cat & produces "[1] + Stopped (tty input) cat", but jobs, fg, - etc. don't know about the job. - [from Mail.1:76] - I get [1] + Stopped (tty input) cat. Interestingly, "jobs" reports - nothing, and "fg" doesn't see it either. But it's definitely there in - the ps output. It only responds to kill -9, nothing else. I guess this - is a side track? - [see also Mail.1:97,Mail.2:2,3] - [fixed in 5.0.6 - don't remove stopped jobs in the notify code of check_job()] - -x pdksh 5.0.5, - (reported by Sean Hogan): repeated history commands were being - echoed after the command was executed. - [see Mail.2:5,6] - [fixed in 5.0.6 - call shf_flush() in case SHIST: of yylex()] - -x pdksh 5.0.5, -: wait with no arguments would hang forever. - [fixed in 5.0.6 - only wait for running jobs in waitfor()] - -x pdksh 5.0.2, HP-UX 9.01 (reported by Sean Hogan): scipts occasionally get - stopped with SIGTTIN - [from Mail.1:68]: - I noticed another small problem today, which is that occasionally - (on an HP 9000/715, HP-UX 9.01, cc from the ANSI C developer set) - a background process which is definitely not reading from its input - stops with SIGTTIN. I first noticed this with a nohup'ed process, but - it periodically happens without as well. The process is a perl script, - if that makes any difference. Have you seen this on your HP(s)? - [hasn't been seen in 5.0.3: Mail.1:73,76] - [not a shell bug, see Mail.2:14,15] - -x pdksh 5.0.6, - (reported by Gordan Larson, Ed Ferguson): shell does not - compile when VI isn't defined. - [see Mail.2:22,40] - [fixed in 5.0.7 - fixed up lex.c] - -x pdksh 5.0.6, - (reported by Gordan Larson): ksh.1 font typo. - [see Mail.2:23] - [fixed in 5.0.7] - -x pdksh 5.0.6, FreeBSd 1.1.5 (reported by Thomas Gellekum): CLK_TCK is defined - to wrong value on FreeBSD; no depend target in Makefile; update /etc/shells - in install target. - [see Mail.2:28] - [fixed in 5.0.7 - include <limits.h> in sh.h to get the right value; added - depend target; print warning if ksh not in /etc/shells] - -x pdksh 5.0.6, - (reported by Michael Haardt): shell does not compile if JOBS - not defined. - [see Mail.2:32] - [fixed in 5.0.7 - added ifdefs to jobs.c(check_job)] - -x pdksh 5.0.6, - (reported by Nick Holloway): exit status of command - substitution is lost (known problem). - [from Mail.2:33]: - This is a variation on a theme of bug number 10 (and is one reason why - currently ksh can not be used for Linux's MAKEDEV). - - The exit status from command substitution is not available when used with - variable assignment. - - x=`false` && echo "Non-zero exit status lost". - [fixed in 5.0.7 - instead of faking :, set rv to subst_exstat] - -x pdksh 5.0.7 - (reported by Sean Hogan): CMASK redefined in emacs.c - [see Mail.2:44] - [fixed in 5.0.8 changed CMASK to CHARMASK] - -x pdksh 5.0.7 - (reported by Sean Hogan): "r" (fc -e -) doesn't work. - [see Mail.2:45] - [fixed in 5.0.8 - increment wp, change strcmp() test] - -x pdksh 5.0.7 - (reported by Thomas Gellekum): make install typeo. - [see Mail.2:46] - [fixed in 5.0.8 - added missing $] - -x pdksh 5.0.8 - (reported by Sean Hogan): "FOO=bar exec blah" does not - put FOO in environment. - [see Mail.2:50] - [fixed in 5.0.9 - re-arranged exec/command/builtin code in comexec()] - -x pdksh 5.0.8, QNX 4.2 (reported by Brian Campbell): "exec > /dev/null" - generates an error. - [see Mail.2:51] - [see Mail.2.58 - caused by ambitious compiler using same label for c_exec() - and c_builtin()] - [fixed in 5.0.9 - c_exec() no longer an empty function.] - -x pdksh 5.0.8, - (reported by Brian Campbell): "echo a{b," prints a "Missing }" - error - at&t ksh does not. at&t ksh always has brace-expansion on (unless - set -o nogolob). - [see Mail.2:51] - [fixed in 5.0.9 - brace expansion now compatible with at&t ksh] - -x pdksh 5.0.8, - (reported by Sean Hogan): ulimit output garbled; syntax error - in c_ulimit.c; no configure check for HAVE_SETRLIMIT. - [see Mail.2:64] - [fixed in 5.0.9 - use shprintf instead of shellf to print values; add - setrlimit() check to configure] - -x pdksh 5.0.7, - (reported by Jan Djarv): `echo > /foo/bar' causes a script to - exit - POSIX says it shouldn't. - [see Mail.2:60] - [fixed in 5.0.9 - iosetup returns error code, error messages cleaned up, etc] - -x pdksh 5.0.8, - : `more /etc/passwd &' followed by fg messes up tty settings. - [fixed in 5.0.9 - only save new tty settings if job originally started in fg] - -x pdksh 5.0.9, - (reported by Andrew Moore): a blank line causes $? to be - set to zero, newline after a here-document marker isn't read. - [see Mail.3:5,6] - [fixed in 5.0.10 - don't execute null trees, read the newline] - -x pdksh 5.0.9, - (reported by Michael Sullivan): mail checking reports you - have mail, when there is only old mail. - [fixed in 5.0.10 - use atime/mtime instead of size] - -x pdksh 5.0.9, - (reported by Chris Oates): if RANDOM is in ksh's environ - when it starts, the shell dumps core. - [see Mail.3:7,8] - [fixed in 5.0.10 - var.c(typeset): free t->val.s instead of - t->val.s + t->type] - -x pdksh 5.0.9, - (reported by Seah Hogan): ISC 3.01's make is confused by - a backslash followed by a blank line. - [see Mail.3:9,13] - [fixed in 5.0.10 - changed make depend target to change blank lines to sh.h] - -x pdksh 5.0.9, - (reported by Andrew Moore): commands without a newline cause - syntax errors - sh/ksh execute the commands. - [see Mail.3:15] - [fixed in 5.0.10 - have yyparse() accept newline and EOF] - -x pdksh 5.0.9, - (reported by Andrew Moore): empty arithmetic expressions not - accepted. - [see Mail.3:15,17] - [fixed in 5.0.10 - v_evaluate(): if first token is END, changed to literal 0] - -x pdksh 5.0.9, - (reported by Andrew Moore): nulls in input are not ignored. - [see Mail.3:15] - [fixed in 5.0.10 - added strip_nuls() function and calls to it] - -x pdksh 5.0.9, - (reported by Andrew Moore): \241 (M-!) not passed through - command substitutions. - [see Mail.3:15] - [fixed in 5.0.10 - evaluate(): cast c to a char before comparing to MAGIC] - -x pdksh 5.0.9, - (reported by Andrew Moore): newlines after here-documents - are read twice; shell reports an error if newline is missing. - [see Mail.3:25] - [fixed in 5.0.10 - fixed up readhere()] - -x pdksh 5.0.9, - (reported with fix by Mike Jetzer): 'r r' repeats the r - command forever. - [see Mail.3:38] - [fixed in 5.0.10 - start the search from the previous command] - -x pdksh 5.0.9, - (reported by Mike Jetzer): edit of multi-line commands - does not result in single history entry. - [see Mail.3:38] - [fixed in 5.0.10 - use hist_append() to add second+ lines] - -x pdksh 5.0.9, - (reported by Dale DePriest): ksh_times.h uses BROKEN_TIMES - [see Mail.3:43] - [fixed in 5.0.10 - changed ksh_times.h] - -x pdksh 5.0.9, - (reported by J. T. Conklin): using [ instead of test is slow. - [see Mail.3:46] - [fixed in 5.0.10 - put in kludgy check for [ in eval.c(glob)] - -x pdksh 5.0.9, - (reported by Michael Haardt): signals do not interrupt - read commands. - [see Mail.3:20] - [fixed in 5.0.10 - changed c_read() to check for fatal signals after EINTR] - -x pdksh 5.0.10, BSDI (reported by David Tamkin): use of _POSIX_VDISABLE in - tty.h causes compiler error. - [see Mail.3:67] - [fixed in 5.0.10.1 - new variable vdisable_c set/used in edit.c] - -x pdksh 5.0.8, - (reported by Donald Craig): on systems with both union wait - and waitpid(), waitpid() is passed a union wait pointer instead of an int - pointer. - [see Mail.2:54] - [fixed in 5.1 - added ksh_waitpid() define; cast status arg as needed.] - -x pdksh 5.0.10, - (reported by David Tamkin): space in vi command mode does - nothing. - [see Mail.3:76] - [fixed in 5.1 - vi.c(classify[]) table got changed by accident.] - -x pdksh 5.0.10, - (reported by Danial Quinlan): forward-word and - delete-word-forward functions in emacs don't go to the right place. - [see Mail.3:79] - [Fixed in 5.1 - changed order of loops in emacs.c(x_fword())] - -x pdksh 5.0.10, - (reported by David Tamkin): eof in multiline command - causes shell to exit, even if ignoreeof is set. - [see Mail.3:76] - [Fixed in 5.1 - reset eof after longjmp() in main.c(shell)] - -x pdksh 5.0.9, Ultrix 4.2 (reported by Matthew Nethook): type-ahead while - shell is waiting for a command to finish is temporarily lost until a - program that reads from stdin or goes a stty/gtty is run. - [see Mail.3:61,62] - [Fixed in 5.1 - changed aclocal.m4 to not define HAVE_TERMIOS_H on ultrix] - -x pdksh 5.0.10, - (reported by David Tamkin): if INT is trapped, ^C in - vi/emacs won't flush buffer/re-issue new prompt. - [see Mail.3:5,76] - [Fixed in 5.1 - use unwind() in vi/emacs to get back to shell()] - -x pdksh 5.0.10, - (reported by Dale DePriest): in emacs mode, file completions - resulting in long names (>256) cause core dumps - [see Mail.3:72] - [Fixed in 5.1 - use dynamically sized buffers in emacs code] - -x pdksh 5.0.10, - (reported by Dale DePriest): in emacs mode, command - completions (^[=) resulting in multiple hits caused internal memory error. - [see Mail.4:8] - [Fixed in 5.1 - don't call list_stash() twice in compl_command] - -x pdksh 5.0.10, - (reported by Dave Hatton): autoloading functions fail - on the first attempt, then work. - [see Mail.4:10] - [Fixed in 5.1 - in findcom(), check for include() returning non-0 (was 0)] - -x pdksh 5.0.10, - (reported by Art Pina via Dale DePriest): when SECONDS - parameter is assigned, it always acts as if 0 were assigned. - [see Mail.4:12] - [Fixed in 5.1 - set internal seconds variable to time - assigned value] - -x pdksh 5.1.0 - (reported by Larry Bouzane): for/select loops don't allow - {..} to be used instead of do...done. - [see Mail.4:16] - [Fixed in 5.1.1 - changed syn.c(dogroup) to allow {/} instead of do/done] - -x pdksh 5.1.0 - (reported by Andrew Moore and Larry Bouzane): a command ending - in ; or & that is not followed by a newline causes a syntax error. - [see Mail.4:126,128] - [Fixed in 5.1.1 - don't call syntaxerr() in get_command() if EOF is read] - -x pdksh 5.1.0, - (reported by Simon J. Gerraty): ksh died reading history - file (complex history, in hist_skip_backup()). - [see Mail.4:24] - [Fixed in 5.1.1 - hist_skip_back(): don't start past the end of the buffer] - -x pdksh 5.1.0 BSDI 1.1 (reported by Karl Denninger): after receipt of SIGHUP, - shell waits for foreground process to complete. - [see Mail.4:50,57] - [Fixed in 5.1.1 - added fatal_trap flag, check in jobs.c(j_waitj)] - -x pdksh 5.1.0 - (reported by Bob Manson): a leading non-white-space IFS - character does cause a field to be delimited. - [see Mail.4:68] - [Fixed in 5.1.2 - changed expand() to do the right thing.] - -x pdksh 5.1.2, -: ^c during $ENV or .profile kills shell; should just go - to prompt. - [see Mail.5:14] - [fixed in 5.2.4 - added intr_ok flag to main.c(include)] - -x pdksh 5.1.2, - (reported by Dan Quinlan): when shell prints out - execution trees (typeset -f), if botches elif statements. - [see Mail.5:17] - [fixed in 5.1.3 - changed tree.c(ptree) to deal with elif.] - -x pdksh 5.1.2, - (reported by Dale DePriest): fc -l -- -40 fails if there - are fewer than 40 commands. - [see Mail.5:19] - [fixed in 5.1.3 - changed history.c(histget) to allow out of range numbers] - -x pdksh 5.1.2, - (reported by Art Mills): file completion in command mode - doesn't work on a single character. - [see Mail.5:13] - [fixed in 5.1.3 - in vi.c(vi_cmd) call complete_word() with 1 not 0] - -x pdksh 5.1.2, - (reported by Dan Quinlan): an error in a let statement - causes shell to exit function/script. at&t ksh just prints error and - returns from let. - [see Mail.5:17] - [fixed in 5.2.3 - added error_ok arg to evaluate() and v_evaluate()] - -x pdksh 5.1.2, - (reported by Art Mills): if markdirs option is set, file - completion in vi adds two slashes to directories. - [see Mail.5:35] - [fixed in 5.1.3 - vi.c(complete_word), don't add / if file ends in one] - -x pdksh 5.1.2, - (reported by Dale DePriest): history read from history file - have negitive numbers and can't be accessed (fc thinks neg numbers are - relative). - [see Mail.5:39] - [fixed in 5.1.3 - EASY_HISTORY/hist_init: increment line for each line] - -x pdksh 5.1.2, - (reported by David Tamkin): FPATH isn't searched if PATH - search can't find command (undocumented at&t ksh feature). - [see Mail.5:45] - [fixed in 5.1.3 - exec.c(findcom) search FPATH if PATH search fails] - -x pdksh 5.1.2, - (reported by Dan Quinlan): output typeset -f isn't - very pretty (no indenting done). - [see Mail.5:17] - [fixed in 5.1.3 - indenting added to ptree routines] - -x pdksh 5.0.9, ISC 3.2 (reported by cobra@guarany.cpd.unb.br): Running the - following script with pdksh crashes the machine: - cat > /tmp/foobar - The same command in an interactive pdksh does not cause a crash. - [see Mail.3:21,Mail.5:62] - [Fixed by Interactive - it is caused by an OS bug for which there is a patch] - -x pdksh 5.1.3, linux - (reported by Dan Quinlan): doesn't compile under new - linux due to declaration conflict between basename() in unistd.h and - pdksh'd basename. - [see Mail.5:90] - [fixed in 5.2.0 - changed basename() to arrayname()] - -x pdksh 5.1.3, - (reported by William Hudacek): very long prompts cause - vi command line editor grief. - [see Mail.6:2] - [fixed in 5.2.0 - initial part of prompt is stripped if its too long] - -x pdksh 5.1.3, - (reported by Roberto Zacheo): when set -u, variable trimming - with always causes an error. - [see Mail.6:21] - [fixed in 5.2.0 - fixed varsub() to test if variable is null] - -x pdksh 5.1.3, - (reported by David Tamkin): when a fucntion is autoloaded, - ksh complains the definition file didn't define the function, even if it did. - [see Mail.6:52] - [fixed in 5.2.0 - exec.c(comexec): when checking if defined, use cp, - -x pdksh 5.1.3, ICS unix 3.2 (reported by Robert Clark): auto configuration - test for memmove doesn't work - [see Mail.6:65] - [fixed in 5.2.0 - special cases added for memmove, bcopy, memset] - -x pdksh 5.1.3, Unixware (Intel-SVR4.2) (reported by Thanh Ma): auto - configuration test for memset doesn't work; same for rlimit type. - [see Mail.6:67] - [fixed in 5.2.0 - special cases added for memmove, bcopy, memset; rlim_t - configuration stuff re-arranged] - -x pdksh 5.1.3, - (reported by Mike Jetzer + fix): . in vi doesn't work - after history motion or after one command is completed and another is being - edited. - [see Mail.6:85] - [fixed in 5.2.0 - fix up classify table, special case for empty initial - insert] - -x pdksh 5.1.3, - Janjaap van Velthooven: ^v (version) missing in vi mode. - [see Mail.6:98] - [fixed in 5.2.0 - added] - -x pdksh 5.1.3, - : y% on or before right bracket/paren/brace doesn't yank the - brackets - just what is in the brackets... - [fixed in 5.2.0 - changes to vi.c(domove,vi_cmd)] - -x pdksh 5.1.3, - (reported by Rob Mayoff): [[ ]] command doesn't do lazy - evaluation. - [see Mail.7:2] - [fixed in 5.2.1 - test routines re-arranged to deal with this] - -x pdksh 5.1.3, - (reported by Will Renkel): "r | more" doesn't work (nothing - is sent to more). - [see Mail.7:13] - [fixed in 5.2.0 - history commands now done in c_fc, not pushed onto input - stack] - -x pdksh 5.1.3, - (reported by Rod Byrne, John Rochester): if a program leaves - the non-blocking (O_NONBLOCK) flag set after it exists, the shell - exits (multiple eofs). - [see Mail.7:15,16,51] - [fixed in 5.2.0: O_NONBLOCK is reset if read fails with EAGAIN,EWOULDBLOCK] - -x pdksh 5.1.3, - (reported by Dale DePriest + fix): emacs: can't delete chars - from pattern in incremental search mode. - [see Mail.7:17] - [fixed in 5.2.0 - handle it] - -x pdksh 5.1.3, Linux 1.2.2 (reported by Fritz Heinrichmeyer + fix): siglist.sh - doesn't work due to bug in bash 1.4.3 (trap is called incorrectly in - subshell causing temp file to be removed prematurely). - [see Mail.7:21] - [fixed in 5.2.0 - clear all traps in subshell so file isn't removed] - -x pdksh 5.1.3, - (reported by Dale DePriest + fix): emacs: can't prefix - commands with more than single digit; many commands don't use nnumber - prefix. - [see Mail.7:26,40] - [fixed in 5.2.0 - x_set_arg reads sequence of numbers, other commands - changed to use x_arg] - -x pdksh 5.1.3, - (reported by Dale DePriest): fc command line parsing - (and its interaction with history alias) doesn't act like at&t ksh: - history -40 gives bad option 4 error. - [see Mail.7:41,49] - [fixed in 5.2.1 - kludge parsing of -40 (numbers are option letters)] - -x pdksh 5.1.3, - (reported by Dale DePriest): if PS1 contains paramaters that - get expanded, and if those parameters contain any ! characters, the !'s get - changed to history numbers. - [see Mail.7:44] - [fixed in 5.2.0 - substitution done after ! and !! substitution] - -x pdksh 5.1.3, - (reported by Steve Wallis): set -a (set -o allexport) has - no effect. - [see Mail.7:47] - [fixed in 5.2.0 - changes to c_read, c_getopts, and comexec] - -x pdksh 5.1.3, - (reported by Alexander S. Jones): (sleep 10000&) waits for - the sleep to complete. - [see Mail.7:54] - [fixed in 5.2.0 - execute() case TASYNC clears EXEC flag in call to execute] - -x pdksh 5.1.3, - (reported by Will Renkel): positional parameters can't be - accessed within temporary variable assignments (eg, "FOO=$1 blah" doesn't - set FOO to $1. - [see Mail.7:57] - [fixed in 5.2.0 - var.c(newblock) - copy argc/argv from previous environment] - -x pdksh 5.1.3, SCO unix ? (reported by Sean Hogan): job control stuff doesn't - work as sco doesn't do job control operations on /dev/tty. - [see Mail.7:30,43,69,70,74] - [fixed in 5.2.0 - don't try opening /dev/tty if on SCO] - -x pdksh 5.1.3, - (reported with fix by Mike Jetzer): vi globing tacks - * at the end of files even if there are globing chars in last component - of filename (at&t ksh does not). - [see Mail.7:71] - [fixed in 5.2.0 - don't append * if there are unescaped globing chars] - -x pdksh 5.1.3, - (reported with fix by Gabor Zahemszky): typoes in acconfig.h, - sh.h uses SVR3_PGRP insteda of SYSV_PGRP. - [see Mail.7:87] - [fixed in 5.2.0] - -x pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have ^[^]. - [see Mail.7:87] - [fixed in 5.2.0 - added search-char-backward] - -x pdksh 5.2.0, - (reported by David Tamkin): pwd -P doesn't strip .. and . - properly. - [see Mail.7:98] - [fixed in 5.2.0 - include ksh_stat.h in c_ksh.c] - -x pdksh 5.2.0, - (reported by Dale DePriest): unistd.h config test - doesn't include sys/types before dirent.h. - [see Mail.8:2] - [fixed in 5.2.0] - -x pdksh 5.2.0, - (reported by Robert Gallant): emacs file/command completion - code can clobber memory. - [see Mail.8:11] - [fixed in 5.2.1 - wrong variable being checked in buffer growing in - emacs.c(compl_file,compl_command)] - -x pdksh 5.2.0, - (reported by David Tamkin): when CDPATH set and cd'ing to a - directory that doesn't exist, the error message contains the last element - of the CDPATH. - [see Mail.8:8] - [fixed in 5.2.0 - fixed error message] - -x pdksh 5.2.0, - (reported by David Tamkin): if PS1 has an error in it - (eg, parameter expansion error), the shell loops forever printing - the error. - [see Mail.8:32] - [fixed in 5.2.3 - create error handling environment while expanding PS1] - -x pdksh 5.2.0, Coherent machines (reported by Gabor Zahemszky): insert after - movement in emacs mode replaces all chars with first char on line. - System's bcopy doesn't handle overlapping src/dst. - [see Mail.8:38,43] - [fixed in 5.2.1 - check for broken memmove/bcopy in aclocal.m4] - -x pdksh 5.2.0, - (reported by Gabor Zahemszky): ^[= in vi prints empty - strings for directory matches if markdirs is set. - [see Mail.8:48] - [fixed in 5.2.1 - skip trailing /'s before looking for last /] - -x pdksh 5.2.0, - (reported by Gabor Zahemszky): <ESC>^H bound to del-back-char - not del-back-word - [see Mail.8:50-52] - [fixed in 5.2.1 - fixed x_emacs_keys] - -x pdksh 5.2.1, - (reported by David Tamkin): compile fails due to lack - of c_test.h - [see Mail.8:58] - [fixed in 5.2.2 - fixed put c_test.h in distribution] - -x pdksh 5.2.2, - (reported by Simon J. Gerraty): hist_source not being - initialized in complex history. - [see Mail.8:64] - [fixed in 5.2.3 - set it in second hist_init()] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): set -A does not reset - the array contents. - [see Mail.8:65] - [fixed in 5.2.3 - changed var.c(unset) to unset whole array if appropriate] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): getopts stops after an error; - at&t ksh carries on with next option. - [see Mail.8:65] - [fixed in 5.2.3 - remove GI_DONE flag from ksh_getopt()] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): getopts prints shell name - twice in error messages. - [see Mail.8:65] - [fixed in 5.2.3 - added GI_NONAME flag] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): pdksh's test doesn't know about - /dev/fd/n. - [see Mail.8:65] - [fixed in 5.2.3 - added test_stat() and test_eaccess()] - -x pdksh 5.2.2, - (reported by Thomas Gellekum): config test for memmove/bcopy - missing semi-colon - [see Mail.8:67] - [fixed in 5.2.3] - -x pdksh 5.2.2, - (reported by Donald Craig): fc string doesn't find string - if it is the most recent command. - [see Mail.8:76] - [fixed in 5.2.3 - fixed off by one error in history.c(hist_get)] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): pdksh doesn't do the - "You have running jobs" when user attempts to log out. - [see Mail.8:74] - [fixed in 5.2.3 - added set -o nohup option with supporting code] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): configure test for - broken memmove/bcopy doesn't work. - [see Mail.8:93] - [fixed in 5.2.3 - fixed test to copy overlapping buffers] - -x pdksh 5.1.3, - (reported by <wendt@sv5.mch.sni.de>): doesn't compile on - solaris 5.x with COMPLEX_HISTORY defined. - [see Mail.8:98] - [fixed in 5.2.3 - undef COMPLEX_HISTORY if flock not available] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): tilde expansion not preformed - in word part of ${foo[-+=?} substitution. - [see Mail.9:7] - [fixed in 5.2.3 - allow ~foo to end in a close brace] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): "fc 30" edits from 30 to - most recent history (should be just 30). - [see Mail.9:7] - [fixed in 5.2.3 - if !-l and no last given, use first] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): [many problems with man page] - [see Mail.9:12] - [fixed in 5.2.3 - fixed problems] - -x pdksh 5.2.2, - (reported by Gabor Zahemszky): #else followed by non-comment - in sigact.c. - [see Mail.9:13] - [fixed in 5.2.3 - turn it into a comment] - -x pdksh 5.2.2, - (reported with fix by Gabor Zahemszky): two argument form of - cd doesn't work. - [see Mail.9:14] - [fixed in 5.2.3 - in c_cd(), use current_wd not path] - -x pdksh 5.2.2, - (reported with fix by Gabor Zahemszky): command -V doesn't - report reserved words. - [see Mail.9:30] - [fixed in 5.2.3 - in c_whence(), look for reserved words if vflag set] - -x pdksh 5.2.3, - (reported by Dale DePriest): at&t's tbl wants space - between font specification and end of table descrption (ie, fB . not - fB.). - [see Mail.9:41] - [fixed in 5.2.4 - put spaces in] - -x pdksh 5.2.3, - (reported by David Tamkin & Claus L{gel Rasmussen): PS1 - isn't imported from environment anymore. - [see Mail.9:43,76] - [fixed in 5.2.4 - main: don't set PS1 if it is already set] - -x pdksh 5.2.3, - (reported by Gary Rafe): If PS1 contains newlines, vi - editing mode dones't redraw lines properly. - [see Mail.9:63] - [fixed in 5.2.4 - added prompt_skip stuff to vi/emacs] - -x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): cd: error message if - directory didn't exist was wrong. - [see Mail.9:66] - [fixed in 5.2.4 - print correct string in error message] - -x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): vi: <ESC>* shouldn't append - a * if word contains a $. - [see Mail.9:66] - [fixed in 5.2.4 - vi.c(glob_word): check for $ in word, check for null - expansion] - -x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): vi: <ESC>= doesn't - list expansions in column form. - [see Mail.9:66] - [fixed in 5.2.4 - use pr_menu to print things nicely] - -x pdksh 5.2.3, - (reported Larry Bouzane): should be a way of installing - binary/man page as pdksh instead of ksh. - [see Mail.9:100] - [fixed in 5.2.4 - use the --enable-shell=pdksh option to configure] - -x pdksh 5.2.3, - (reported by Gabor Zahemszky): [many problems with man - page] - [see Mail.10:20] - [fixed in 5.2.4 - fixed problems] - -x pdksh 5.2.3, - (reported by Gabor Zahemszky): exec 1<&9 reports - error with ">&9" in it. - [see Mail.10:20] - [fixed in 5.2.4 - changed iosetup()] - -x pdksh 5.2.3, - (reported by Gabor Zahemszky): man page doesn't document - /dev/fd/N - [see Mail.10:20] - [fixed in 5.2.4 - updated manual] - -x pdksh 5.2.3, - (reported by Ted Coady): [[ foo/bar = foo* ]] - fails; should succeed. - [see Mail.10:32] - [fixed in 5.2.4 - fixed problem in exec.c(dbteste_getopnd)] - -x pdksh 5.2.3, - (reported by Ruei-wun Tu): make on NeXT/NeXTSTEP 3.3 - doesn't understand .PRECIOUS target and so does nothing. - [see Mail.10:43] - [fixed in 5.2.4 - moved .PRECIOUS after all in Makefile.in] - -x pdksh 5.2.3, - (reported & fixed by Paul Borman): shell doesn't kill - foreground process when SIGHUP received; Also, CONT sent before HUP. - [see Mail.10:44] - [fixed in 5.2.4 - j_exit now sends HUP to foreground process] - -x pdksh 5.2.3, AIX 3.2.5 (reported by Ian Portsmouth): C compiler compains - about sigtraps[] being re-declared in trap.c. - [see Mail.10:73] - [fixed in 5.2.4 - use cpp define to avoid bogus re-declaration error] - -x pdksh 5.2.3, - (reported by Michael Haardt): ENV should not be - included if shell is compiled as sh and posix option not set. - [see Mail.10:83] - [fixed in 5.2.4 - only include ENV if POSIX, if compiled as sh] - -x pdksh 5.2.3, - (reported & fixed by DaviD W. Sanderson): case statements - don't allow {/} in place of IN/ESAC. - [see Mail.10:77,78] - [fixed in 5.2.4 - allow {/} in case statements] - -x pdksh 5.2.3, - (reported by Larry Daffner): $? is incorrectly zero'd - at start of traps. - [see Mail.11:9] - [fixed in 5.2.4 - don't clear exstat in main.c(shell)] - -x pdksh 5.2.3, - (reported by Frank "Crash" Edwards): configure on linux XXX - doesn't detect the presence of lstat(). - [see Mail.11:36] - [fixed in 5.2.4 - change configure to include <sys/stat.h> in lstat() test] - -x pdksh 5.2.3, - (reported by Gabor Zahemszky): typeset -f dumps core - in the after using autoload functions. - [see Mail.11:74?] - [fixed in 5.2.4 - c_typeset no longer traverses the array link for functions] - -x pdksh 5.2.3, - (reported by Gabor Zahemszky): typeset -f does not report - undefined autoload functions - [see Mail.11:74?] - [fixed in 5.2.4 - c_typeset: don't ignore unset functions] - -x pdksh 5.2.3, - (reported by Dale DePriest): alias -t -r does not - reset aliases. - [see Mail.11:99] - [fixed in 5.2.4 - c_alias: call ksh_getopt_reset() before calling c_unalias] - -x pdksh 5.2.3, - (reported & fixed by Jason Tyler): 'echo abc^Jfc -e - a=b e' - echos b, not bbc. - [see Mail.11:100?] - [fixed in 5.2.4 - hist_replace: use s, not last] - -x pdksh 5.2.3, - (reported by Jason Tyler): 'fc -e -' when there is - no history causes infinite loop. - [see Mail.11:100?] - [fixed in 5.2.4 - histbackup: allow histptr to go below history] - -x pdksh 5.2.4, - (reported by David Tamkin): jmp_buf is used instead of - sigjmp_buf. - [see Mail.XXX:XXX] - [fixed in 5.2.5 - added ksh_jmp_buf and defined appropriately] - -x pdksh 5.2.4, - (reported by Stephen Coffin): /<RETURN> in vi mode does not - repeat last search. - [see Mail.XXX:XXX] - [fixed in 5.2.5 - vi.c(vi_hook) - make it repeat last search] - -x pdksh 5.2.4, - (reported by Gabor Zahemszky): functions containing select - commands aren't printed correctly by typeset. - [see Mail.XXX:XXX] - [fixed in 5.2.5 - tree.c(ptree) - add case for TSELECT] - -x pdksh 5.2.4, - (reported & fixed by Stefan Dalibor): COLUMNS isn't set on - shell start up (and window size is ignored) 'cause tty_fd isn't valid when - x_init() is called. - [see Mail.XXX:XXX] - [fixed in 5.2.5 - call x_init() after j_init() is called] - -x pdksh 5.2.4, - (reported by Will Renkel): "echo -" just prints a blank - line - should print the minus. - [see Mail.XXX:XXX] - [fixed in 5.2.5 - c_ksh.c(c_print): don't do argument parsing on lone -] - -x pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have ^[*. - [see Mail.7:87] - [fixed in 5.2.5] - -x pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= doesn't append - a / after directories. - [see Mail.9:66] - [fixed in 5.2.5] - -x pdksh 5.2.0, - (reported by Gabor Zahemszky): can set readonly variables - via command assignments (eg, "readonly x=y; x=z /bin/echo hi" should - fail and doesn't). - [see Mail.8:50,65] - [fixed in 5.2.5 - LOCAL_COPY flag passed from comexec() down to local()] - -x pdksh 5.2.4, - (reported by Tom Karches): history: "r old=new", with - no commands prefix given, prints "fc: too mnay arguments" - it should - do the subst on the previous command. - [see Mail.XXX:XXX] - [fixed in 5.2.5] - -x pdksh 5.2.3, - (reported by Vigen Pogosyan): assignments in $(( ... )) - remember the base that was assigned in pdksh - does not in at&t ksh. - [see Mail.10:54] - [fixed in 5.2.5: uset setint() in expr.c(evalexpr)] - -x pdksh 5.2.4, - (reported by Gabor Zahemszky): emacs: ^O steps down - two lines (should be 1). - [see Mail.XXX:XXX] - [fixed in 5.2.5: convert history line to command number, then convert back] - -x pdksh 5.2.3, - (reported by David Gast(? gast@twinsun.com)): fc -ln -1 -1 - reports the current command, not the previous command. - [see Mail.10:49] - [fixed in 5.2.5] - -x pdksh 5.2.3, - (reported by Matthew Green): foo=`^Jecho bar` doesn't - set foo to bar (foo is empty). - [see Mail.XXX:XXX] - [fixed in 5.2.5: syn.c: set multiline.on when source is SSTRING] - -x pdksh 5.2.5, - (reported by Gabor Zahemszky): continue/break: if n - is too big, shell prints internal error message. - [see Mail.XXX:XXX] - [fixed in 5.2.6: fix c_brkcont to use last loop if n is too big] - -x pdksh 5.2.5, - (reported by Gabor Zahemszky): set: +o in ksh93 - prints command that sets various options. - [see Mail.XXX:XXX] - [fixed in 5.2.6: changed misc.c(printoptions)] - -x pdksh 5.2.5, - (reported by Gabor Zahemszky): COLUMNS/LINES variables - are not exported. - [see Mail.XXX:XXX] - [fixed in 5.2.6: use typeset() in edit.c(x_init) to export COLUMNS/LINES] - -x pdksh 5.2.5, - (reported by Gabor Zahemszky): emacs: <ESC><ESC> puts - space after completed directories. - [see Mail.XXX:XXX] - [fixed in 5.2.6: check for single/non-directory match in emacs.c(do_complete)] - -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] - -* 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] - [fixed in 5.2.8: coprocess stuff made to act like ksh93 co-processes] - -x pdksh 5.2.8, - (reported with fix by Lars Hecking): doesn't compile as - sh - c_ksh.c and jobs.c boom out. - [see Mail.XXX:XXX] - [fixed in 5.2.9: added ifdef KSH to appropriate places] - -x pdksh 5.2.8, - (reported by Paolo Zeppegno): assignments containing brackets - are treated as commands. - [see Mail.XXX:XXX] - [fixed in 5.2.9: fixed bug in vars.c(skip_wdvarname).] - -x 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] - [fixed in 5.2.9: changed autoconf's -g test to do linking as well.] - -x pdksh 5.2.8, Solaris 2.5.1 (reported by Stefan Dalibor): 2 tests - (xxx-exec-environment-1 and 2) fail because printenv isn't found. - [see Mail.XXX:XXX] - [fixed in 5.2.9: changed test to use env instead] - -x pdksh 5.2.8, - (reported by Stefan Dalibor): shell assumes 80 columns when - it starts up if COLUMNS is set correctly in the environ. - [see Mail.XXX:XXX] - [fixed in 5.2.9: fixed so window size is checked at startup] - -x pdksh 5.2.8, NeXT machines (reported by Kai Wong): clock_t, which lives - in sys/time.h, isn't found by configure (causes warning messages). - [fixed in 5.2.9: configure now checks in sys/time.h] - -x pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= on word with ~ - but no /, beeps (or prints final path comonent?). - [see Mail.9:66] - [fixed in 5.2.9: fixed edit.c(add_glob) so no * is appended to ~username] - -x pdksh 5.1.3, NeXT machines (reported by Jason Baugher): job control doesn't - work on NeXT machines (both m68k and x86 based) in rlogin sessions. - (caused by open("/dev/tty") failing - rlogin on NeXT doesn't set up - controlling tty properly). - [see Mail.7:29] - [fixed in 5.2.9: added hack to main to get a controlling tty] - -x pdksh 5.2.8, NeXT 3.2 (reported by Andrew S Townley): the output of the - siglist.sh script fills the disk. Also, the signal list generated (by the - fixed script) is mostly empty. - [see Mail.XXX] - [fixed in 5.2.9: fixed siglist.sh script to avoid infinite loops. Added - comment to README warning of problem with NeXT's native cc -E] - -x pdksh 5.2.9, - (reported by Loris Talpo): long prompts are messed up in - vi mode. - [see Mail.XXX] - [fixed in 5.2.9: lex.c(pprompt) was broken] - -x pdksh 5.2.9, - (reported by Will Renkel): a double backslash followed - by a newline in an unquoted here document results in one of the backslashes - and the newline being stripped. - [see Mail.XXX] - [fixed in 5.2.10: fixed backslash-newline processing in lex.c] - -x pdksh 5.2.9, - (reported by Han Holl): read x?prompt doesn't work - on non-interactive shells when the input is from a tty. - [see Mail.XXX] - [fixed in 5.2.10: changed test in c_read() from FTALKING to isatty] - -x pdksh 5.2.10, - (reported by Dale DePriest): expanding aliases causes - extra input. - [see Mail.XXX] - [fixed in 5.2.11: fixed syn.c(c_list).] - -x pdksh 5.2.10, - (reported by John Rochester): window size changes don't - happen on Dec unix (osf) because TIOCGWINSZ is defined in <sys/ioctl.h> - not in <termios.h>. - [see Mail.XXX] - [fixed in 5.2.12: sys/ioctl.h included with termios.h/termio.h if possible] - -x pdksh 5.2.11, - (reported by Randy Bouzane): aliases in command substitutions - result in code dumps. - [see Mail.XXX] - [fixed in 5.2.12: lex.c(getsc__): break if eof is read] - -x pdksh 5.2.11, - (reported by Will Renkel): aliases containing ;<newline> - or <newline><newline> aren't fully read/executed. - [see Mail.XXX] - [fixed in 5.2.12: syn.c(get_command): call inalias()] - -x pdksh 5.2.11, SGI/IRIX 5.2 (reported by bert@xpilot.com): pipelines - containing built in commands hang forever. - [see Mail.XXX] - [fixed in 5.2.12: fixed pgrp sync code in jobs.c] - -x pdksh 5.2.11, - (reported by Herbert Thielen via Larry Daffner): shell leaves - temp files around when executing shell scripts that have functions with - here documents which end in an exec. - [see Mail.XXX] - [fixed in 5.2.12: call main.c(cleanup_proc_env()) from exec.c(execute()).] - diff --git a/bin/pdksh/CONTRIBUTORS b/bin/pdksh/CONTRIBUTORS deleted file mode 100644 index edf32c0db35..00000000000 --- a/bin/pdksh/CONTRIBUTORS +++ /dev/null @@ -1,103 +0,0 @@ -$OpenBSD: CONTRIBUTORS,v 1.3 1996/10/01 02:05:25 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 -code. Hopefully it is correct and no contributors have been left out -(file a bug report if you spot a problem :-)). - -Release history: - * Eric Gisin (egisin@math.uwaterloo.ca), created pdksh, using - Charles Forsyth's public domain V7 shell as a base; also used parts - of the BRL shell (written by Doug A Gwyn, Doug Kingston, Ron Natalie, - Arnold Robbins, Lou Salkind, and others?, circa '87; the parts used in - pdksh included getopts, test builtin, ulimit, tty setting/getting, emacs - editing, and job control; the test builtin was based on code by Erik - Baalbergen). - '87..'89 ? - Released versions: .. 3.2 - * John R MacMillan (@yonge.csri.toronto.edu:chance!john@sq.sq.com) - takes over as maintainer - dates? - Released versions: 3.3 (?) - * Simon J. Gerraty (sjg@zen.void.oz.au) takes over as maintainer - Nov '91..July '94 ? - Released versions: 4.0 .. 4.9 - * Michael Rendell (michael@cs.mun.ca) takes over as maintainer - July, 1994 - Released versions: 5.0 .. 5.2 - -Major contributions: - * John R MacMillan (@yonge.csri.toronto.edu:chance!john@sq.sq.com), ?: - cleaned up configuration, many bug fixes (see misc/Changes.jrm). - * Simon Gerraty, (sjg@zen.void.oz.au), Nov '91..?: much improved emacs mode - ala at&t ksh, 386bsd port, sigaction routines for non-POSIX systems - (see misc/ChangeLog.sjg and misc/ReadME.sjg). - * Peter Collinson (pc@hillside.co.uk), July '92: added select, at&t ksh - style history file, original csh-style {} globbing, BSD/386 port, - misc bug fixes. - * Larry Bouzane (larry@compusult.nf.ca), Mar '89..'93: re-wrote job control, - added async job notification, added CDPATH and other cd fixes, misc bug - fixes. - * John Rochester (jr@cs.mun.ca), '87: wrote vi command line editor; various - bug fixes/enhancements. - * Jeff Sparkes (jsparkes@bnr.ca), Mar '89..Mar '90: added arrays, - merged John Rochester's vi code into pdksh, misc bug fixes. - * Michael Haardt (u31b3hs@POOL.Informatik.RWTH-Aachen.DE), Sept '94: - organized man page, filled in many of its copious blank spots; added - KSH ifdefs. - * Dale DePriest (daled@cadence.com): ported to OS/2 (initially based on - port of pdksh4.9 to OS/2 by Kai Rommel (rommel@ars.muc.de)); maintains - OS/2 port; misc bug fixes. - -Other contributors: - * Piercarlo Grandi (pcg@aber.ac.uk), Dec '93: fixes for linux port - * Neil Smithline (Neil.Smithline@eng.sun.com), Aug '92: emacs-style - filename completion. - * Mike Jetzer [mlj] (jetzer@studsys.mscs.mu.edu), ?;Nov '94: fixes for vi - mode (see misc/Changes.mlj), added v to vi, fixes for history; fixed - command redoing in vi; fixes to vi globbing. - * Robert J Gibson: mailbox checking code that was adapted for pdksh by - John R. MacMillan. - * ? (guy@demon.co.uk), ?: promptlen() function. - * J.T. Conklin (jtc@cygnus.com): POSIXized test builtin; miscellaneous - fixes/enhancements. - * Sean Hogan (sean@neweast.ca): fixes for ICS 3.0 Unix, found and helped - fix numerous problems. - * Gordan Larson (hoh@approve.se): fix to compile sans VI, ksh.1 typo. - * Thomas Gellekum (thomas@ghpc8.ihf.rwth-aachen.de): fixes for Makefile - typos, fixed CLK_TCK for FreeBSD, man page fixes. - * Ed Ferguson (Ed.Ferguson@dseg.ti.com): fix to compile sans VI. - * Brian Campbell (brianc@qnx.com): fixes to compile under QNX and - to compile with dmake. - * (guy@netapp.com), Oct '94: patch to use gmacs flag. - * Andrew Moore (alm@netcom.com): reported many bugs, fixes. - * William Bader (wbader@CSEE.Lehigh.Edu): fix to compile on SCO Unix - (strut winsize). - * Mike Long (mike.long@analog.com): makefile fix - use $manext, not 1. - * Art Mills (aem@hpbs9162.bio.hp.com): bug fix for vi file completion in - command mode. - * Tory Bollinger (tboll@authstin.ibm.com): allow ~ in vi mode to take - a count. - * Frank Edwards (<crash@azhrei.EEC.COM>): added macros to vi (@char). - * Fritz Heinrichmeyer (<Fritz.Heinrichmeyer@FernUni-Hagen.de>): fixes - to allow compile under Linux 1.4.3. - * Gabor Zahemszky (<zgabor@CoDe.hu>): SVR3_PGRP vs SYSV_PGRP, many - bug reports and man page fixes. - * Dave Kinchlea (<kinch@julian.uwo.ca>): DEFAULT_ENV patches. - * 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. - * Lars Hecking (<lhecking@nmrc.ucc.ie>): fixes so shell compiles as sh - again. - * Bill Kish (<kish@browncow.com>): added prompt delimiter hack for - hidden characters (eg, escape codes). - * Andrew S. Townley (<atownley@informix.com>): fixes for NeXT machines: - get a controlling if one needed, use correct profile. diff --git a/bin/pdksh/ChangeLog b/bin/pdksh/ChangeLog deleted file mode 100644 index b515993f3aa..00000000000 --- a/bin/pdksh/ChangeLog +++ /dev/null @@ -1,1071 +0,0 @@ -$OpenBSD: ChangeLog,v 1.5 1996/11/21 07:59:25 downsj Exp $ - -Tue Oct 29 11:34:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.12 distribution - -Fri Oct 25 11:59:48 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_cmd): case Cntl('i'): dont fall through, call complete_word(). - -Tue Oct 22 17:38:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * table.h(USERATTRIB): new define. - * c_ksh.c(c_typeset): report unset params only if it has some - interesting attributes. - -Tue Oct 22 15:54:39 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(exchild): changed NEED_PGRP_SYNC code so j_sync_pipe[1] isn't - left open in 2nd+ children. - -Tue Oct 22 12:59:49 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(main): memset() env to 0. - -Mon Oct 21 12:53:44 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(cleanup_proc_env): new function. - * exec.c(execute): call cleanup_proc_env() before calling ksh_execve(). - -Fri Oct 11 22:53:57 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(display): use ch not e->buf[cur] when printing character. - -Fri Oct 11 13:26:11 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_TIMES_CHECK,KSH_DUP2_CLEXEC_CHECK,KSH_OPENDIR_CHECK): - changed sense of test so "yes" result is printed if you have a good - system. - * aclocal.m4(KSH_C_FUNC_ATTR): changed return type of test_cnst to int. - -Fri Oct 11 13:05:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * syn.c(get_command): added inalias() call when setting cf = CONTIN. - -Thu Oct 10 16:22:03 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(getsc__): case SALIAS: if we read eof, break, don't continue. - -Tue Oct 8 13:14:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_TERM): added SYS_IOCTL_WITH_TERMIOS, - SYS_IOCTL_WITH_TERMIO tests. - * tty.h: include <sys/ioctl.h> with <termios.h>/<termio.h> - if possible. - -Tue Oct 8 11:42:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.11 distribution - -Tue Oct 8 11:02:54 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * syn.c(inalias): new function. - * syn.c(c_list): call inalias() instead of testing source->type. - -Mon Oct 7 17:00:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.10 distribution - -Mon Oct 7 16:23:53 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_sh.c(c_read): when printing prompt, use isatty, not FTALKING. - -Wed Oct 2 12:00:51 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(yylex): redirection stuff: save result of getsc() == '-' - and use it for ungetsc(). - - * lex.h(struct source): moved ugbuf out of union so it can be used - with alias stuff. - * lex.c(getsc__) case SALIAS: instead of appending a space, get the - next character and stuff it in ugbuf. - - * lex.c(getsc_,getsc__): getsc_() renamed to getsc__(). - * lex.c(getsc_,getsc): getsc() macro renamed to getsc_(). - * lex.c(backslash_skip,ignore_backslash_newline): new variables. - * lex.c(getsc): new macro that checks backslash_skip. - * lex.c(getsc_bn_,getsc_bn): getsc_bn() macro deleted (all calls - replaced with getsc()); getsc_bn_ renamed to getsc_bn. - * lex.c(ungetsc_,ungetsc): ungetsc() macro deleted; renamed ungetsc_() - to ungetsc(). - * lex.c(yylex,ungetsc,getsc_bn): set and use backslash_skip, - ignore_backslash_newline. - * lex.c(yylex): removed special cases for backslash-newline sequence, - explicitly ignore backslash followed by eof. - -Mon Sep 30 17:14:41 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.9 distribution - -Mon Sep 30 12:52:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(pprompt): fixed usage of ntruncate. - -Thu Sep 19 17:43:33 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(KSH_SYSTEM_PROFILE): new define. - * main.c(main): use KSH_SYSTEM_PROFILE. - - * aclocal.m4(KSH_OS_TYPE): added case for NEXT. - -Thu Sep 19 15:39:54 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * tty.c(tty_init): added hack for NeXT's rlogin's missing controlling - tty. - -Mon Sep 16 11:18:10 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.c(add_glob): don't append a * to a ~username. - - * edit.c(x_init): set got_sigwinch before calling check_sigwinch(). - -Wed Sep 11 14:38:38 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_let): ifdef'd KSH. - * lex.h(SDPAREN),lex.c: ifdef'd KSH all uses of SDPAREN. - * lex.h(MDPAREN),syn.c: ifdef'd KSH all uses of MDPAREN. - -Mon Sep 9 16:18:03 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(AC_PROG_CC): replaced autoconf's version with - modified version. - - * configure.in(clock_t): check in sys/time.h as well. - * ksh_times.h: include ksh_time.h. - * ksh_time.h,ksh_times.h: added ifndef KSH_TIME_H/KSH_TIMES_H. - -Fri Sep 6 13:20:24 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.c(promptlen): X\r hack for delimiting hidden characters - in prompt. - (Based on fix from Bill Kish) - -Tue Sep 3 11:03:26 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * Makefile.in: removed options.h from HDRS (also removed file). - -Thu Aug 29 10:04:01 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_MEMMOVE): added return 0 to end of main(). - -Fri Aug 23 14:23:50 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4,ksh_stat.h: changed S_IFFIFO to S_IFIFO. - -Fri Aug 23 09:58:09 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(skip_wdvarname): don't check for array if first char - isn't [. - -Thu Aug 22 12:51:25 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c: added ifdef KSH around Coproc_id/j->coproc_id usagae. - * c_ksh.c(c_read): added ifdef KSH around opipe. - -Tue Aug 20 09:41:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * configure.in: fixed quoting of sed LDSTATIC expression. - -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.7 distribution - - * vi.c(CMDLEN): changed from 16 back to 1024. - -Sun Jun 2 11:54:46 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.6 distribution - -Sun Jun 2 11:46:56 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(search_access): changed ordering of xsuffixes[], rsuffixes[]; - removed code that used xsuffixes[] when suffix is present. - * lex.c(getsc_line): set O_TEXT/O_BINARY if os/2. - * main.c(remove_temps): added os2 ifdefs. - [Changes from Dale DePriest.] - -Tue May 21 14:18:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_cmd): case '#': call do_comment() to do work. - * vi.c(do_comment): new function. - * vi.c(putbuf,grabhist,grabsearch): fixed pesimestic off-by-1 error - (cbufsize - 1 -> cbufsize). - * vi.c(vi_hook): case VCMD: case -1: added refresh(0). - * vi.c(vi_cmd): case 'P': don't move cursor back if nothing added. - -Tue May 21 12:03:34 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c(do_complete): don't add space if single match and - it doesn't end with a /. - -Tue May 21 11:51:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.c(x_init): use typeset to set EXPORT attribute for - COLUMNS/LINES. - -Tue May 21 11:40:12 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(parseargs): option setting: ignore context if option - isn't being changed. - * misc.c(printoptions): for non-verbose mode: print a set command - (eg, set -o vi -o ...) instead of just the option names. - -Tue May 21 11:14:27 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_sh.c(c_brkcont): if n is too big, use last enclosing loop. - -Fri May 10 09:27:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(Getopt): changed field p from int to unsigned. - -Tue May 7 12:10:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.5 distribution - -Tue May 7 11:45:37 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * syn.c(compile): set multiline if source is SSTRING. - * syn.c(yyparse): don't peek before calling c_list() - build - TEOF if c_list() fails and c is 0. - * syn.c(c_list): remove SSTRING test. - * syn.c(get_command): if EOF is reached, free iops,args,vars. - * syn.c(syntaxerr): set multiline.on to false when it is used; - don't use multiline.on if start token is 0. - -Tue May 7 10:11:41 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(c_fc,hist_execute): moved calls to histbackup() from - c_fc() to hist_execute(). - * history.c(hist_get): number: took out +1 correction as histbackup - hasn't been done yet; string: added -1 correction to ensure - current fc command isn't searched. - * history.c(hist_get_newest,hist_get_oldest): don't find the - current (fc) command; removed print_err argument (was always - true). - * history.c(hist_get,hist_get_newest): added allow_cur argument; - changed all calls. - -Mon May 6 09:55:29 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c(x_nextcmdp): renamed to x_nextcmd, changed from - char ** to int. - * emacs.c(x_nl_next_com): save absolute command number, not - relative position in history array (which changes). - * emacs.c(x_emacs): convert x_nextcmd back to relative position. - * emacs.c(x_init_emacs): initialize x_nextcmd to -1. - -Sun May 5 13:10:48 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * expr.c(evalexpr): when assigning a non-integer, call setint() - (not setstr(..., strval(...))). - -Sun May 5 12:16:11 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * mail.c(maddmsg): changed name to mprintit(); now prints message - directly instead of saving in a linked list; changed all calls. - * mail.c(mprint): deleted; deleted all calls. - * mail.c(mmsgs,struct mailmsg): deleted. - -Sun May 5 11:52:05 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.h(SF_TTY): new flag. - * lex.h(STTY): deleted. - * main.c(main): if tty, use SSTDIN, set SF_TTY. - * main.c(shell): check SF_TTY instead of STTY. - * lex.c(getsc_): call getsc_line for SSTDIN/SFILE. - * lex.c(getsc_line): new function (merged old STTY/SSTDIN/SFILE code). - -Fri May 3 11:24:17 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(shell): changed exit_atend to toplevel. Changed interactive - to be falking&toplevel (was talking&s->type==STTY). - -Fri May 3 10:59:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(getint): only allow one base (ie, disallow 2#4#5). - -Thu May 2 21:31:23 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(array_index_calc): new function - * var.c(global): call array_index_calc(); moved $2 code into - if (!letter(c))... - * var.c(local): call array_index_calc(); added copy argument & code; - changed all calls. - * table.h(LOCAL_COPY): new define. - * exec.c(comexec): maybe pass LOCAL_COPY to typeset(). - -Thu May 2 16:34:29 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c: command completion changes. - * emacs.c(Comp_type,CT_LIST,CT_COMPLETE,CT_COMPLIST): new type. - * emacs.c(x_ins): return type changed to int; return -1 if - string can't be inserted. - * emacs.c(x_do_ins): new function. - * emacs.c(add_stash,list_stash,compl_dec,compl_file,compl_command, - str_match): deleted; changed callers to use do_complete(). - * emacs.c(do_complete,x_expand): new functions. - * emacs.c(x_ftab[],x_defbindings[]): added entry for file-expand; - bound to <ESC>*. - -Thu May 2 15:31:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(set_prompt): pass strlen() + 1 to shf_sopen. - (fix from Arnon Kanfi). - -Wed Apr 24 11:50:52 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(c_fc): -e -: don't increment wp past null; allow - pat=replace arg with "-1" type argument. - (based on fix from Jason Tyler). - -Mon Apr 15 11:58:34 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * table.c(tenter),alloc.c(alloc): changed use of offsetof() so field - parameter is a constant expression. - * sh.h: took out undef of offsetof on CRAYs. - -Fri Apr 12 16:01:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(JF_USETTYMODE): renamed JR_ORIGFG to JF_USETTYMODE. - * jobs.c(j_waitj): clear JF_USETTYMODE if fg job is stopped. - -Sun Apr 7 12:35:30 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh(c_print): echo: don't treat a lone minus as an option. - -Sat Apr 6 00:09:37 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ulimit.c(c_ulimit.c): always pass 2 args to ulimit(). - * ksh_sigsetjmp(): changed all uses to be simple expressions - seems - to be required by the cray C compiler. - * sh.h(offsetof): undef if on a cray. - (based on fixes from Dave Kinchlea) - -Sat Mar 23 13:58:12 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * siglist.in: added WAITING,LWP,FREEZE,THAW,CANCEL - -Thu Mar 7 23:26:37 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.c(x_init): set LINES if possible. - -Thu Mar 7 23:01:55 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(main): call x_init() after j_init() - (based on fix from Stefan Dalibor). - -Thu Mar 7 16:13:10 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_OS_TYPE): check for TitanOS (use cc -43). - * aclocal.m4(KSH_SIGNAL_TYPE): for bsd41 signals, check if signal - interrupt read(). - -Thu Mar 7 13:59:29 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(strstr),missing.c(strstr): changed args to const. - -Wed Mar 6 17:21:36 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * io.c(errorf,bi_errorf): changed null pointer string check to - empty string; changed all calls (due to new error gcc warnings). - -Wed Mar 6 17:15:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(search_access): files aren't executable if they don't - have any execute bits. - * ksh_stat.h: added S_IXUSR,S_IXGRP,S_IXOTH. - * exec.c(search_access,search_access1): OS2: changed the meaning - of these two functions (search_access1 now called from search_access). - -Wed Mar 6 16:23:23 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * tree.c(ptree): add case for TSELECT. - -Wed Mar 6 12:40:34 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(Z_,is_zeroarg): new defines. - * vi.c(classify): use Z_ for G, g, _, |, v, ^I, ^F. - * vi.c(vi_cmd): use is_zerocount(). - * vi.c(complete_word): if command prefixed by a count, complete - to count'th expansion (as reported by print_expansions()). - -Tue Mar 5 14:43:48 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(GF_NONE,GF_EXCHECK,GF_GLOBBED,GF_MARKDIR): new defines. - * eval.c(glob_str): added markdirs argument; changed all calls; - made function non-static. - * eval.c(glob): added markdirs argument; changed all calls. - * tree.h(DOMARKDIRS): new define. - * eval.c(expand): set DOMARKDIRS if FMARKDIRS. - * edit.c(x_complete_word,x_print_expansions,x_file_glob,x_command_glob, - x_locate_word,x_cf_glob,x_add_glob,x_longest_prefix,x_free_words): - new functions. - * proto,edit.h: moved functions defined in edit.c to edit.h. - * vi.c(struct edstate): moved to top of file. - * vi.c(print_expansions): added struct edstate argument; changed all - calls. - * vi.c(struct glob,Glob,globstr,glob_word,): deleted - * vi.c(vi_pprompt): new function; changed all calls of pprompt() in - vi.c to use vi_pprompt(). - * vi.c(x_vi): moved to top of file. - * vi.c(expand_word,complete_word): free buf if it is not null. - * vi.c(expand_word,complete_word,print_expansions): changed - to use new edit.c functions. - -Tue Feb 20 11:02:05 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * table.c(twalk,tnext,struct tstate),table.h(struct tstate): moved - struct tstate from table.c to table.h; changed twalk,tnext to take - struct tstate* argument; changed all calls; deleted static tstate - variable. - -Sat Feb 17 12:28:11 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_hook): case VSEARCH: if new pattern is empty, repeat last - search. - -Sat Feb 10 15:59:28 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * table.h(struct arg_info): new struct. - * table.h(struct block): changed argv, argc fields to argi. - -Sat Feb 10 15:12:47 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - ANSI C name space requirements: - - * vi.c(isbad,iscmd,islong,ismove,issrch,isundoable,iswordch): changed - to is_bad,is_cmd,is_long,is_move,is_srch,is_undoable,is_wordch. - * emacs.c(iscfs,ismfs): changed to is_cfs, is_mfs. - * emacs.c(strmatch): changed to str_match. - * sh.h(strchr_dirsep,strrchr_dirsep): changed to ksh_strchr_dirsep, - ksh_strtchr_dirsep; changed all calls. - * missing.c(strichars[]): changed to ichars[]. - * var.c(strint,strval): changed to setint_v, str_val. - * missing.c(strsave,strnsave): changed to str_save,str_nsave. - -Fri Feb 9 11:30:15 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(main): remove envp parameter; declare and use environ. - - * c_ksh.c(c_print): octal digit escape sequences must start with \0. - -Sat Feb 3 15:35:41 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_cmd,classify[]): made ^I a command. - -Fri Feb 2 10:40:32 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.h(struct source): added u.freeme field. - * lex.c(getsc_): case SREREAD: free u.freeme iff start isn't u.ugbuf. - -Thu Feb 1 15:27:06 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_test.h(Test_env): added end union. - * c_test.c(c_test): keep track of end postition using end.wp; - don't write on wp. - - * emacs.c(x_mapin): changed to dup string, then munge; return duped; - changed all calls. - - * eval.c(homedir): deleted getpwnam() declaration - can't believe - its needed anywhere (we shall see, though). - - * sh.h(handler_t): use ARGS for prototype; use h - * sh.h(struct trap),trap.c(setsig,settrap),sigact.c,sigact.h: - use handler_t. - * history.c,c_sh.c,c_ksh.c: removed register declaration from - c_*() functions. - * exec.c(builtin),proto.h(builtin): use prototype for func. - * misc.c(qsortp,qsort1),proto.h(qsortp): use prototype for f. - - * c_ksh.c(ksh_getopt): made options arg const. - * tree.c(fptreef,snptreef,vfptreef): made fmt arg const. - * jobs.c(waitfor,j_kill,j_resume,j_lookup,j_jobs): made cp arg const. - * shf.c(shf_snprintf,shf_smprintf,shf_vfprintf): made fmt arg const. - * c_test.h(Test_env.error),c_test.c(ptest_error): made msg arg const. - * c_test.c(test_stat,test_eaccess): made path arg const. - * c_test.c(ptest_getopnd,dbteste_getopnd): made return value const. - * c_test.c(ptest_eval,test_eval,dbteste_eval,dbtestp_eval,test_primary): - made opnd1,opnd2 arg const. - * c_test.c(test_isop): made s arg const. - - * misc.c(bi_getn,getn): made as arg const. - * misc.c(getn): made as arg const. - * misc.c(gmatch): made s/p arg const. - * misc.c(has_globbing): made xp/xpe arg const. - * misc.c(do_gmatch): made s/p/se/pe arg const. - * misc.c(cclass): made p arg const. - -Thu Feb 1 14:54:32 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.h, sh.h, tty.h: changed _I_ to I__. - * edit.h, edit.c: changed _D_ to D__. - - * jobs.c,shf.c,tty.c: include ksh_stat.h (POSIX: needed for open). - - * sigact.c: use ARGS instead of __P; comment out __P defines. - - * shf.c: include math.h if FP. - * shf.c(my_ceil): remove modf() declaration. - * shf.c(shf_fvprintf): comment out frexp() declaration; changed - exp to expo. - - * jobs.c(struct job, j_utime, j_stime): changed utime/stime to - usrtime/systime; change j_utime/j_stime to j_usrtime/j_systime. - -Wed Jan 31 16:13:44 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.c(x_getc): cast return value to int to avoid warnings on - strange compilers. - * exec.c(funcfunc): changed second arg to unsigned int (was int). - * syn.c(elsepart): move return NULL to end of function (avoids - warning from some compilers). - * vi.c(classify[]): changed type to unsigned char. - * shf.c(shf_smprintf): delete unused variable n. - * aclocal.m4(KSH_TIMES_CHECK): define INT32 in test code. - * aclocal.m4(KSH_SIGNAL_CHECK): typeo: had bsd42 instead of bsd41. - * sh.h(MAGIC): changed to 7 to increase portability. - * jobs.c(tcsetpgrp,tcgetpgrp): define if TTY_PGRP (was TIOCSPGRP). - -Tue Jan 23 11:40:25 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(ksh_jmp_buf): new define. - -Thu Jan 18 15:03:19 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(hist_replace): fixed substitution code (again). - -Wed Jan 17 20:10:02 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.4 distribution - - * main.c(initcoms): changed hash alias to "hash=alias -t". - - * exec.c(do_selectargs): deleted c_read() declaration. - - * c_ksh(c_alias): call ksh_getopt_reset() before calling c_unalias(). - -Wed Jan 17 19:47:55 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(histbackup): changed "histptr > history" - to "histptr >= history". - - * history.c(hist_replace): removed un-needed "last" - use "s" instead. - (based on fix from Jason Tyler). - -Thu Jan 11 15:59:46 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_whence,c_command),main.c(initcoms[]): removed ifdef KSH - (type is a builtin in sys-5 sh). - -Wed Jan 10 11:49:59 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * Makefile.in: added NEWS.os2 to OS2FILES. - - * version.c: include "sh.h" (needed for const define). - - * exec.c(pr_menu): made non-static. - * vi.c(print_expansions): gather expansions into an arrat - and use pr_menu(). - (fixes from Mike Jetzer). - - * vi.c(redraw_line): added newline option; changed all calls. - -Wed Jan 10 10:21:06 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(classify): made 'U' a C_. - * vi.c(ohnum): new variable. - * vi.c(vi_reset): set ohnum to hlast. - * vi.c(grabhist): set ohnum. - * vi.c(vi_cmd): case n,N,/,? set ohnum; added case 'U'. - * vi.c(edit_reset): clear holdlen. - (based on fix from Dale DePriest). - -Tue Jan 9 11:23:36 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c(iscfs): make ', " seperators. - (fix from Dale DePriest). - - * conf-end.h: deleted stuff to undef HISTORY, VI, EMACS, etc if - KSH wasn't defined (now done in configure). - - * sh.h(GI_NONAME): changed to GF_NONAME; changed all uses. - - * configure.in: added AC_ARG_PROGRAM. - * Makefile.in: replaced binprefix and manprefix with - program_transform stuff. - -Mon Jan 8 11:42:46 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(struct temp): added shf field. - * io.c(maketemp): changed to use O_EXCL; keep trying if open - fails (due to O_EXCL); fill in shf field; changed all calls. - - * main.c(include): added intr_ok flag; changed all calls. - - * main.c(main): if compiled as sh and posix option not set, do not - include $ENV. - - * trap.c: define FROM_TRAP_C before including sh.h. - * sh.h: don't declare sigtraps if FROM_TRAP_C declared. - - * c_ksh.c(c_cd): fixed error message. - * vi.c(glob_word): don't add * if word contains a $. - (Based on fixes from Mike Jetzer). - - * eval.c(tilde): if HOME,PWD,OLDPWD aren't set, don't expand - ~,~+/~-. - -Fri Jan 5 12:15:58 NST 1996 Michael Rendell (michael@garfield.cs.mun.ca) - - * c_ksh.c(c_typeset): seperate loop for printing functions - (do not traverse array link). - * c_ksh.c(c_typeset): list functions: do not ignore unset functions. - * exec.c(findfunc): set val.t to 0 when creating new entry. - * exec.c(define): if FINUSE, use tail recursion. - -Thu Jan 4 11:10:22 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(globstr): deleted ifdef'd out code. - -Sun Dec 10 11:07:52 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(yylex): added case for STBRACE; wrap word part of - trim substitution in @(..). - * eval.c(trimsub): deleted code to wrap pattern in @(..); changed - '%' code to use strnsave(). - -Fri Dec 8 22:55:56 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(trimsub): if trim pattern contains a |, wrap pattern - in @(...). - * lex.c(yylex): make | special when incounted in a ${...} - substitution. - -Fri Dec 8 11:52:38 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c: ifdef'd HISTFILE, HISTSIZE stuff with HISTORY (was KSH). - - * *.c,*.h: ifdef'd coprocess stuff with KSH. - -Thu Dec 7 14:41:06 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * options.h(BRACEEXPAND): changed to BRACE_EXPAND; changed all - references. - -Thu Dec 7 13:54:20 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * exec.c(do_selectargs): don't print newline on eof. - -Thu Dec 7 10:23:30 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * c_ksh.c(c_print): added -f for OS2. - * tree.h(DODIRSWP),eval.c: deleted define and all uses of it. - * exec.c(scriptexec): ... - * io.c(check_fd): set O_TEXT/O_BINARY flag for OS2. - * main.c(main): set O_BINARY/O_TEXT, search path for arg. - * emacs.c(compl_file): call opendir with buf, not dirnam. - (based on changes from Dale DePriest). - -Wed Nov 29 15:50:36 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * eval.c(expand,debunk): handle extended pattern matching stuff. - * eval.c(debunk): now has two arguments, changed all calls. - * eval.c(globit): changed to use has_globbing. - * eval.c(copy_non_glob): deleted. - - * misc.c(has_globbing): new function. - * misc.c(cclass): changed argument to unsigned char *; handle - extended pattern matching. - * misc.c(do_gmatch): new function (taken from gmatch()). - * misc.c(gmatch): changed to call do_gmatch. - * misc.c(do_gmatch): added cases for extended pattern matching - (*(foo|bar), etc.). - * misc.c(pat_scan): new function. - - * lex.c(yylex): added SPATTERN case. - - * lex.c(arraysub): changed to assume just past the leading [ - (was assuming about to read [); changed all calls; changed - to use getsc_bn(). - - * lex.c(ungetsc): added argument; changed all calls; can now unget - arbitrary number of characters. - * lex.c(ungetsc_): new function. - - * lex.h(struct source): added start field, removed u.start field, - changed all uses. - * lex.c(getsc_): case STTY: skip blank line only if this is first line - of a command (eg, not part of here documennt, etc.). - - * lex.c(yylex): case SHEREDELIM,SHEREDQUOTE: ignore \newline. - * lex.c(readhere,get_brace_var): ignore \newline. - * lex.c(getsc_bn,getsc_bn_): new define/function. - - * exec.c(iosetup): don't enforce noclobber for non-regular files. - - * tree.h(OPAT,SPAT,CPAT): new defines. - * tree.c(tputS,wdscan): added cases for OPAT,SPAT,CPAT. - - * lex.c(yylex): moved case '[' from Subst: switch to case SBASE:. - -Tue Nov 14 11:00:48 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * syn.c(get_command,caselist): moved parsing of IN/ESAC into - caselist; allow {/} instead of IN/ESAC; - * syn.c(casepart): new parameter: endtok. - * lex.c(yylex): allow } as well as ESAC when ESACONLY set. - (changes based on fix from DaviD W. Sanderson). - -Tue Nov 14 10:22:17 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * main.c(shell): do not zero exstat at start of routine. - - * exec.c(execute): removed redundent "exstat = rv" before - unwind(LERROR). - -Thu Nov 9 15:01:54 NST 1995 Michael Rendell (michael@angel.cs.mun.ca) - - * var.c(arrayname): made argument const. - * var.c(typeset): made var argument const. - * var.c(export): made val argument const. - * tree.c(wdscan): changed return type to non-const (added casts). - -Thu Nov 9 14:39:49 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_alias),c_sh.c(c_set): made args[] array const. - * c_ulimt.c(c_ulimit): made limits[] array const. - * edit.c(x_mode): x_cur_mode no longer explicitly initialized to 0. - * emacs.c(x_tab,x_atab): no longer explicitly initialized to 0. - * exec.c(comexec): made texec non-static, non-initialized. - * history.c(hist_finish): once no longer explicitly initialized to 0. - * io.c(maketemp): io no longer explicitly initialized to 0. - * jobs.c(job_list,last_job,async_job,free_jobs,free_procs): no longer - explicitly initialized to 0. - * jobs.c(lookup_msgs[],tt_sigs[]): made array const. - * mail.c(mplist,mbox,mlastchkd,mmsgs): no longer explicitly - initialized to 0. - * vi.c(expand_word,complete_word): buf no longer explicitly - initialized to 0. - * vi.c(classify[]): made array const. - -Tue Nov 7 11:08:01 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * mkman: new script - * Makefile.in: use mkman to generate ksh.1 - * ksh.Man,ksh.1: renamed ksh.1 to ksh.Man - * ksh.Man: changed way sh/ksh option handled. - (changes based on fix from Michael Haardt). - -Tue Sep 19 09:53:53 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(j_stopped): deleted function. - * jobs.c(j_exit): send SIGCONT, then SIGHUP; send SIGHUP if - job is in foreground. - (based on fix from Paul Borman) - - * Makefile.in: move .PRECIOUS to after all. - -Wed Sep 13 15:00:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(dbteste_getopnd): changed tests from TO_STLT/TO_STGT - to TO_STEQL/TO_STNEQ. - -Thu Aug 31 11:54:02 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(exchild): if fork fails, allow user to ^C out of loop. - -Tue Aug 29 09:40:37 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(iosetup): don't do globing if not interactive (POSIX). - - * exec.c(iosetup): print <& or >& as appropriate in error message. - - * tree.h(IONAMEXP): new define. - * tree.c(pioact): handle IONAMEXP. - * exec.c(iosetup): set IONAMEXP. - - * io.c(savefd): added noclose parameter; changed all calls. - * exec.c(iosetup): move call to savefd() to after the open(); - re-arranged the dup'ing (failed dups reported). - - * main.c(shell): call quitenv() before internal_error(). - -Sun Aug 13 21:38:44 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(ksh_sigsetjmp,ksh_siglongjmp): new defines; changed - all uses of setjmp/longjmp to these. - * configure.in: added checks for sigsetjmp() and _setjmp(). - -Wed Jul 26 10:08:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ulimit.c(c_ulimit): added -p ("maxproc", RLIMIT_NPROC) - (fix from Simon J. Gerraty). - -Thu Jun 29 10:22:51 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.c(promptlen): added spp parameter; changed all calls. - * vi.c(prompt_skip): new variable. - * vi.c(edit_reset): set prompt_skip; use prompt_skip in all calls - to pprompt(). - -Sat Jun 24 15:55:03 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * IAFA-PACKAGE: new file. - * Makefile.in: added IAFA-PACKAGE to DISTFILES. - -Mon Jun 19 10:04:52 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(initcoms[]): added EXTRA_INITCOMS. - -Fri Jun 16 12:33:10 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(search_access1): use FILECMP() instead of strcmp(). - - * sh.h(FIELCHCONV): OS2 version: added isascii(). - * misc.c(gmatch); took unsigned out again for sc and pc. - - * main.c(main): don't set PS1 if it's already set; set it if - we are root and prompt doesn't contain a #. - diff --git a/bin/pdksh/ChangeLog.0 b/bin/pdksh/ChangeLog.0 deleted file mode 100644 index 23dc38eb028..00000000000 --- a/bin/pdksh/ChangeLog.0 +++ /dev/null @@ -1,3589 +0,0 @@ -$OpenBSD: ChangeLog.0,v 1.1 1996/08/14 06:19:10 downsj Exp $ - -Thu Jun 15 11:02:06 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.3 distribution - - * c_ksh.c(c_whence): search keyword table if vflag set. - - * tree.h(DOVACHECK): new define. - * eval.c(expand): check DOVACHECK flag. - * exec.c(execute): when calling eval(), or in t->evalflags. - * syn.c(get_command): set evalflags to DOVACHECK instead of DOASNTILDE. - -Wed Jun 14 09:27:19 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_cd): two argument format: use current_wd, not path - when appending elen bytes. - (fix from Gabor Zahemszky). - -Tue Jun 13 15:54:11 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(c_fc): if last not specified and !-l, use first as last. - - * eval.c(maybe_expand_tilde): allow CSUBST to end tilde word. - - * misc.c(gmatch): made sc and pc unsigned. - -Fri Jun 2 11:55:40 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * configure.in: added flock to AC_CHECK_FUNCS call. - * conf-end.h: undef COMPLEX_HISTORY if !HAVE_FLOCK. - -Tue May 30 20:38:47 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(SEEK_SET,SEEK_CUR,SEEK_END): define if not defined. - * history.c: change L_XTND to SEEK_END. - -Tue May 30 17:01:34 NDT 1995 John Rochester (jr@panda.cs.mun.ca) - - * shf.c(shf_seek): new function. - * shf.h(shf_seek): new prototype. - -Tue May 30 16:42:41 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_DEV_FD): new test. - * acconfig.h(HAVE_DEV_FD): new define. - * configure.in: call KSH_DEV_FD. - - * c_test.h(TO_FILAXST): new enum. - * c_test.c(test_stat,test_eaccess): new functions for /dev/fd/n - handling. - * c_test.c(test_evalop): call test_stat() and test_eaccess() - instead of stat() and eaccess() in most places; added case - for TO_FILAXST. - -Tue May 30 16:06:21 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_MEMMOVE): fixed test so copies overlap. - -Sun May 28 11:11:03 NDT 1995 John Rochester (jr@panda.cs.mun.ca) - - * sh.h(safe_prompt): new variable. - * main.c(initsubs): removed PS1. - * main.c(main): initialize safe_prompt; initialize PS1 from - safe_prompt. - * lex.c(set_prompt): create new env while expanding PS1 - if expansion - fails, use safe_prompt. - -Sat May 27 20:59:02 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c: put comments around token after #endif. - -Thu May 25 10:10:45 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * c_test.c(test_eval): case TO_OPTION: negate test if option starts - with a !, always fail if option doesn't exist. - - * sh.h(FNOHUP): new define. - * misc.c(options[]): "nohup" new option. - * jobs.c(j_stopped,j_stopped_running): name of j_stopped changed - to j_stopped_running; changed all calls; check for/warn about - running jobs if appropriate. - * jobs.c(j_exit): check for/kill running jobs if appropriate. - * main.c(shell),c_sh.c(c_exit): un-ifdef JOBS the j_stopped_running() - call and really_exit initialization/clearing. - -Wed May 24 10:06:14 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * options.h(DEFAULT_ENV): new define. - * main.c(main): if ENV isn't set and DEFAULT_ENV is defined, include - the later. - (based on patches from Dave Kinchlea). - - * sh.h(LAEXPR): new define. - * expr.c(evaluate): changed return type to error indicator; added - rval and error_ok arguments; changed all calls (c_sh.c(c_shift), - c_ulimit.c(c_ulimit),eval.c(expand),var.c(global,local)). - * expr.c(v_evaluate): added error_ok argument; changed return value - to error indicator; call unwind() if !error_ok. - * expr.c(evalerr): changed errorf() to warningf(); call unwind(LAEXPR). - * c_test.c(test_eval): merged code for integer operations to have - two calls to evaluate(). - - * io.c(warningf): print trailing newline; changed all calls. - - * history.c(hist_get): string search: use histptr, not histptr - 1. - -Tue May 23 11:07:50 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(GI_NONAME): new define. - * misc.c(ksh_getopts): honour GI_NONAME flag. - * c_ksh.c(getopts_reset): set GI_NONAME flag. - - * exec.c(comexec): don't change $0 if FPOSIX flag set. - - * misc.c(ksh_getopt): don't use GI_DONE to allow parsing past - bad options. - * sh.h(GI_DONE): deleted define. - - * var.c(unset): added array_ref parameter; unset/free whole array - if not an array_reference; changed all calls. - * c_sh.c(c_unset): set array_ref parameter if there is a [ in the name. - -Mon May 22 10:33:14 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(hist_init): complex version: initialize hist_source - (fix from Simon J. Gerraty). - -Sat May 20 11:06:15 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.2 distribution - - * Makefile.in: added c_test.h to HDRS. - -Fri May 19 12:35:18 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.1 distribution - - * emacs.c(v_version): ignore typed character if it is a space. - * emacs.c(x_emacs_keys): bind <ESC>erase-char to delete-back-word - (was delete-back-char). - * emacs.c(x_defkeybindings[]): bound list-file to ^X^Y and - newline-and-next to ^O, as per man page. - - * c_ksh.c(c_whence): changed "is a keyword" to "is a reserved word". - - * sh.h: changed SVSV_PGRP to SYSV_PGRP. - - * vi.c(vi_cmd): uncommented case for ^[ to make it easy to enable - completion. - -Mon May 15 15:25:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(c_fc): accept -40 as -- -40. - * main.c(initcoms[]): take -- out of history alias. - - * vi.c(print_expansions): handle trailing slash correctly (don't - print empty strings). - - * c_ksh.c(c_cd): put back ksh_get_wd() call for os/2. - - * misc.c(ksh_get_wd): changed buf to b in call to getcwd(). - -Tue May 9 13:57:31 NDT 1995 Michael Rendell (michael@dragon.cs.mun.ca) - - * c_test.h: new file. - * c_test.c: major code restructuring: common parsing/evaluation - routines call/called-by three sets of routines: one for - normal test (and [..]), one for parsing [[ .. ]] one for - evaluating [[ .. ]]. - * c_test.c(oexpr,aexpr,nexpr,primary,is_op): renamed to test_oexpr, - test_aexpr, test_nexpr, test_primary, test_isop. - * c_test.c(eval_unop,eval_binop): combined into new test_eval function. - * c_test.c(syntax): renamed to ptest_error, - * c_test.c(ptest_isa,ptest_getopnd,ptest_eval): new functions. - * syn.c(syntaxerr): added extra arg; changed all calls. - * syn.c(db_parse,db_oaexpr,db_nexpr,db_primary): deleted. - * syn.c(dbtestp_isa,dbtestp_getopnd,dbtestp_eval,dbtestp_error): added. - * syn.c(get_command): case DBRACKET: changed to call new routines. - * tree.c(ptree): case DBRACKET: changed. - * exec.c(execute): case DBRACKET: changed. - * exec.c(dbteste_isa,dbteste_getopnd,dbteste_eval,dbteste_error): added. - -Fri May 5 17:10:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c(compl_file,compl_command): fixed buffer growing code. - -Thu May 4 22:44:01 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca) - - * aclocal.m4(KSH_UNISTD_H): include <sys/types.h> and only include - <dirent.h> if HAVE_DIRENT_H is defined. - -Thu May 4 21:19:15 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca) - - * c_ksh.c: include "ksh_stat.h". - * c_ksh.c(c_cd): don't do physical chdir if S_ISLNK not defined. - -Wed May 3 10:08:32 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.2.0 distribution - - * misc.c: include <ctype.h>. - * misc.c(gmatch): added isfile argument; changed all calls. - * sh.h(FILECHCONV): (os2 version) - use isupper. - * emacs.c(strmatch): don't increment in FILECHCONV. - - * aclocal.m4(KSH_HEADER_SYS_WAIT): new macro. - * configure.in: use KSH_HEADER_SYS_WAIT instead of AC_HEADER_SYS_WAIT. - * ksh_wait.h: if POSIX_SYS_WAIT not defined, undef W* macros. - -Tue May 2 12:10:39 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c,emacs-gen.sh,emacs-c.in,emacs.out,Makefile.in: changed emacs - source munging to create emacs.out which is included by emacs.c - rather then munging emacs.c itself. - - * lex.c(pprompt): flush shl_out. - - * vi.c(glob_word): if path has *?[, don't add * (was if last component). - - * emacs.c(x_search_char): renamed to x_search_char_forw. - * emacs.c(x_search_char_back): new function; bound to ^[^]. - - * sh.h: changed SVR3_PGRP to SYSV_PGRP. - (fixes from Gabor Zahemszky). - -Tue May 2 10:09:57 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_cd): deleted OS2 ifdefs. - * path.c(make_path): use ISRELPATH instead of ISABSPATH - * path.c(simplify_path): use ISROOTEDPATH instead of ISABSPATH. - * sh.h(ISABSPATH,ISROOTEDPATH,ISRELPATH): changed/new defines. - - * aclocal.m4(AC_LANG_C,AC_LANG_CPLUSPLUS,AC_TRY_RUN): copied - from autoconf's acgeneral.m4, changed to handle .exe suffix. - * aclocal.m4(KSH_OS_TYPE): os2 case: set $ac_exe_suffix. - * configure.in: substitute ac_exe_suffix. - * Makefile.in: changed references to E to exe_suffix, set to - ac_exe_suffix - - * c_ksh.c(c_cd): ifdef S_ISLNK second use of get_phys_path(). - * edit.c(x_mode): removed ifndef OS2. - (fixes from Dale DePriest) - * exec.c(search_access1): add .sh to suffix lists. - * vi.c(vi_insert,vi_hook): OS2: changes to allow arrow keys work - in insert mode. - -Mon May 1 16:28:44 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * path.c(ksh_get_wd): getcwd() case, return alloc'd buffer, not - a malloc'd one. - -Mon May 1 09:41:56 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4: changed HAVE_SYS_RESOURCES_H to HAVE_SYS_RESOURCE_H. - - * aclocal.m4(KSH_OS_TYPE): new macro. - * aclocal.m4(KSH_OS2_EMX): deleted. - * configure.in: deleted calls to AC_AIX,AC_MINIX,AC_ISC_POSIX, - KSH_OS2_EMX; replaced with KSH_OS_TYPE. - * acconfig.h(OS_ISC,OS_SCO): new undefs. - * sh.h: changed use of isc386 to OS_ISC - * edit.c: changed use of M_UNIX to OS_SCO. - -Sat Apr 29 21:10:54 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca) - - * vi.c(glob_word): don't append * if there are unescaped globing - characters in the last component of the filename; some redundent - code eliminated. - (based on fix from Michael Jetzer). - -Fri Apr 28 16:10:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(globit): save/restore actual DIRSEP char - don't use DIRSEP. - - * c_ulimit.c: removed ARGS from declaration of ulimit to avoid - portability problems (osf/1 has ulimit(int,...), os2 has - ulimit(int,long)). - - * tty.c(tty_init): added __SCO__ defines to avoid opening /dev/tty. - - * configure.in,aclocal.m4,acconfig.h: added KSH_OS2_EMX test. - * os2/config.h, os2/configure.cmd, os2/make.sed: updated for new - autoconf. - -Tue Apr 25 12:20:45 NDT 1995 Michael Rendell (michael@dragon.cs.mun.ca) - - * configure.in: added sys/param.h test; changed getcwd test to getwd. - * c_ksh.c(c_pwd): new function. - * sh.h(current_wd, current_wd_size): new variables. - * c_ksh.c(c_cd): changed to handle -L, -P. - * main.c(main): use set_current_wd when setting $PWD; - instead of changing to / when can't get pwd, print warning; - deleted pwd alias; don't make PWD and OLDPWD reaedonly. - * path.c(simplify_path): changed to handle relative paths. - * path.c(make_path): added phys_path argument to support cd -P. - * path.c(set_current_wd,get_phys_path,do_phys_path): new functions. - * misc.c(ksh_get_wd): new function. - * missing.c(getcwd): deleted. - * misc.c(options[]),sh.h: added "physical", FPHYSICAL. - -Mon Apr 24 14:33:03 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * shf.c(shf_smprintf): new function. - - * expand.h(Xsize): new define. - -Fri Apr 21 21:22:44 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca) - - * sh.h: changed SIZEOF_long to SIZEOF_LONG. - * exec.c(scriptexec): if OS2 ifdefed code, changed ISDIRSEP to - explicit /. - -Thu Apr 20 21:18:12 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(hist_get) if n < 0, use n + 1 to account for histbackup(). - - * lex.c(set_prompt): added source argument; changed all calls; - changed to do ! and !! substitutions when setting PS1. - * lex.c(pprompt): ifdef'd out code to deal with ! and !!. - - * shf.c(shf_puts): new routine. - * exec.c(herein), lex.c(getsc_): changed to use shf_puts. - -Thu Apr 20 15:50:35 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * siglist.sh: clear traps in subshell to cover for bug in bash 1.4.3 - (based on fix from Fritz Heinrichmeyer). - -Wed Apr 19 12:04:59 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(classify): cleaned up table; filled in U_ flag for commands - that don't modify things. - * vi.c(first_insert, saved_inslen): new variables. - * vi.c(vi_reset): don't reset yanklen, inslen, lastcmd, lastac; - set first_insert, saved_inslen. - * vi.c(vi_insert): added code to handle first insertion to allow - redoing commands from last edit. - (based on fixes from Michael Jetzer). - - * vi.c(VVERSION): new state. - * vi.c(classify): cleared C_ flag for 032 (^Z); set it for ^V. - * vi.c(nextstate): added VVERSION. - * vi.c(vi_hook): cases for VVERSION. - * sh.h(ksh_version): new declaration; removed declaration from - all other files. - - * Makefile.in: removed rcs-ci, rcs-diff targets; put RCSFILES - into DISTFILES and removed former. - - * var.c(newblock): copy argc/argv from previous env if it exists. - -Tue Apr 18 23:10:32 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(exchild): report internal error if execute() returns in child. - * exec.c(execute): case TASYNC: clear exec flag in call to execute(). - -Tue Apr 18 12:05:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c(x_bind): added list argument. - * c_ksh.c(c_bind): added -l (list) option. - - * emacs.c,emacs-c.in: moved emacs.c to emacs-c.in. - * Makefile: add rule to create emacs.c from emacs-c.in. - * emacs-gen.sh: new file. - * emacs.c(struct x_defbindings, x_defbindings[]): new struct/array. - * emacs.c(struct x_ftab, x_ftab[]): removed x_db_tab, x_db_char; - initialize x_ftab[] via script. - * emacs.c(x_init_emacs): changed to load key bindings from - x_defbindings. - * emacs.c(Findex): added typedef. - * emacs.c(x_tab[]): changed to index into x_ftab; changed all refernces. - * emacs.c(xft_*): changed to XFUNC_*. - * emacs.c(XF_PREFIX): new flag, used for x_meta1, 2, 3. - * emacs.c(KPREF,KNULL): deleted (no functional use), changed - references to KSTD. - * emacs.c(x_last_command): changed type to Findex. - * emacs.c(x_emacs): set x_last_command to 0 at start; removed - same from case KEOL. - - * emacs.c(XF_ARG): new flag for struct ftab. - * emacs.c(x_ftab[]): filled in XF_ARG for appropriate commands. - * emacs.c(x_arg_defaulted): new variable. - * emacs.c(x_emacs,x_set_arg): set x_arg_defaulted. - * emacs.c(x_bword, x_fword,x_fold_case): removed use of x_last_command. - * emacs.c(x_fold_upper,x_fold_lower,x_fold_capitailze): trivial - functions that call x_fold_case; changed x_ftab[] to use these - instead of x_fold_case so arbitrary keys can be bound to them. - * emacs.c(x_fold_case): changed to assume argument is 'L', 'U', or 'C'. - * emacs.c(x_del_back,x_del_char,x_prev_histword,x_prev_com,x_next_com, - x_kill,x_insert): use x_arg and x_arg_defaulted. - * emacs.c(x_delete): don't change mark point (xmp) if <= cp; added - force_push argument; changed all calls. - -Mon Apr 17 10:30:12 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * emacs.c(x_e_getc): changed to handle macroptr, ungetting characters. - * emacs.c(x_e_ungetc): new function. - * emacs.c(x_emacs): let x_e_getc() take care of macroptr. - * emacs.c(x_version,x_search_hist): use x_e_ungetc() instead of - macroptr. - * emacs.c(x_set_arg): handle string of digits. - - * emacs.c(x_search_hist): handle deleting chars from search string. - (fix from Dale DePriest) - * emacs.c(x_search): added sameline paramater. - * emacs.c(x_search_list): changes x_zots() to x_e_puts(); make - deleting in empty pattern break out of search. - - * vi.c(domove): case '%': adjust ncursor forward only if matching - opening bracket (so when cursor is on the B in "(fooBar)", c% - changes the openbracket as well. - * vi.c(vi_cmd): case y/d/c: special case to move end point ahead - if move cmd is % and match was to the left of the cursor. - -Thu Apr 13 10:34:26 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(complete_word): no bell on ambiguous matches (user can - tell its ambiguous 'cause there is not space or slash appended) - - * configure.in,aclocal.m4: added KSH_MEMMOVE, KSH_MEMSET tests - to fix problems with compiler builtins. - - * misc.c(blocking_read, reset_nonblock) new routines. - * sh.h: deleted O_NONBLOCK ifdefs/defines. - * main.c(main),lex.c(getsc_),edit.c(x_getc),shf.c(shf_fillbuf): - use reset_nonblock(). - (fix based on code from John Rochester) - -Tue Apr 11 14:36:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(c_fc): mostly POSIXized. - * history.c(hist_execute,hist_get_newest,hist_get_oldest): new routines. - * history.c(hist_get,histget): changed histget to hist_get. - * history.c(hist_replace,histrpl): changed histrpl to hist_replace. - * lex.h(SHIST,histpush): deleted; deleted all references. - * history.c(histget): add approx check for history that hasn't - happened yet. - - * misc.c(getn): allow leading plus (eg, +3). - - * main.c(initcoms[]): defined history as "fc -l --". - - * conf-end.h(JOBS): don't define if no posix or bsd process groups - (was if SIGCONT not defined). - -Mon Apr 10 14:51:54 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(comexec),c_ksh.c(c_getopts),c_sh.c(c_read): use FEXPORT flag. - - * ksh_wait.h: changed to work with autoconf 2.x AC_HEADER_SYS_WAIT - - if sys/wait.h uses union wait, don't include it. - -Thu Apr 6 12:19:58 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * tty.c(tty_init): print warning if open of /dev/tty fails. - -Sat Mar 4 01:20:03 NST 1995 Michael Rendell (michael@garfield.cs.mun.ca) - - * io.c(maketemp): create valid dos filenames. - -Mon Feb 27 11:04:32 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * Changed from autoconf 1.x to autoconf 2.x. - * acconfig.h: included old config.h.top and config.h.bot. - * config.h.top, config.h.bot: deleted; deleted all references. - * install.sh: changed to install-sh; changed all references. - * Makefile.in: use @CPPFLAGS@, @CFLAGS@, @LDFLAGS@; - use @configure_input@; remove config.log and config.cache in - distclean; use @prefix@ and @exec_prefix@. - * ksh_dir.h: changed to use new autoconf defines; changed NLENGTH() - to NAMLEN(); changed all references. - -Mon Feb 27 9:31:02 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(ISABSPATH): new macro. - * var.c(setspec): use ISABSPATH() when setting tmpdir. - - * emacs.c(compl_file): added OS2 ifdefs. - * exec.c(scriptexec): OS2: ignore path specified in #! scripts. - * sh.h(ksh_dupbase): OS2: now same as unix. - * trap.c(sigtraps[],inittraps): remove OS2 defines. - * trap.c(alarm_catcher): V7_SIGNALS: use sig, not i. - (Fixes from Dale DePriest) - -Mon Feb 27 10:06:00 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * configure.in: test for resource.h. - * c_ulimit.c: include ksh_time.h instead of sys/time.h; use - HAVE_SYS_RESOURCE_H when including sys/resource.h - (was HAVE_SETRLIMIT). - * aclocal.m4(KSH_RLIM_T): check sys/resources.h for rlim_t. - -Fri Feb 24 17:30:16 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(struct macro_state, macro): new structure/variable. - * vi.c(vi_hook, vi_cmd): use macro state info to allow nested macros, - detect recursive macros. - -Wed Feb 22 21:20:43 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_whence): "an export" instead of "a export". - * vi.c(classify[]): added @<char>. - * vi.c(vi_hook,vi_cmd): added support for @<char> (macros). - (fixes from Frank Edwards). - -Sun Feb 19 11:57:20 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(comexec): case CFUNC: use cp (not tp->name) when checking if - an autoloaded function was defined; save/restore kshname before/after - function call. - * var.c(popblock): don't set kshname to e->loc->argv[0] - it isn't - always right. - -Fri Feb 10 12:36:16 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(parse_args): check OF_SET when building set_opts (was - checking OF_CMDLINE). - - * conf-end.h(JOBS): don't define if SIGCONT not defined. - - * sh.h(FLOGIN) new enum. - * misc.c(options[],parse_args): added login option; set FLOGIN if - name in argv[0] starts with -. - * main.c(main): use FLOGIN flag; changed the way OS2 code looks - for profile. - -Wed Feb 1 09:55:40 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * expr.c(varsub): in FUNSET test, don't always fail # and % - substitutions (test for unset variable). - -Wed Jan 25 09:22:15 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(MIN_COLS): new define. - * sh.h(MIN_EDIT_SPACE): new define. - * vi.c(prompt_trunc): new variable. - * vi.c(edit_resize): calculate how much of prompt to truncate. - * lex.c(pprompt): added new argument; changed all calls. - * lex.c(yylex),emacs.c(x_emacs),vi.c(x_vi): move pprompt() inside - x_emacs(), x_vi() or just before read in yylex(). - -Tue Jan 24 12:35:18 NST 1995 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(parse_args): changed arrayname variable to array. - * var.c(basename): changed name of function to arrayname(); - changed all references (Based on fix from Dan Quinlan). - -Fri Dec 30 10:34:50 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * ksh.1: modifications to generate two man pages: sh and ksh - (Fixes from Michael Harrdt). - -Wed Dec 28 16:55:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(complete_word): don't check for globing characters. - -Wed Dec 28 10:32:18 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(search_access1): don't use ret variable; move "." to end - of xsuffixes/rsuffixes. - * os2.c(_execve): OS2: fixed typo. - * sh.h(FILENCMP): changed stricmp to strnicmp. - * os2/config.h: added define for rlim_t. - * os2/make.sed: changed > null to > nul. - * Makefile.in(dist): generate os2/makefile after running Dist-fixup. - (Fixes from Dale DePriest) - -Thu Dec 22 15:06:06 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.1.3 distribution - - * *.c: removed RCSids. - -Wed Dec 21 11:55:01 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * table.h(struct tbl): changed array field to union of array/fname; - changed all references. - * c_ksh.c(c_whence): print undefined function path. - * exec.c(comexec): do autoloading of undefined functions; print - error if function can't be found. - * exec.c(findcom): fill in tp->u.fname for undefined functions; - search FPATH if search of PATH fails. - * table.h(FC_NOAUTOLOAD): deleted define; removed all references. - -Tue Dec 20 14:16:16 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(herein): check if name is null. - * lex.h(HEREDELIM,SHEREDELIM,SHEREDQUOTE): new defines. - * lex.c(yylex): added code for HEREDELIM. - * syn.c(synio): use HEREDELIM. - * lex.c(readhere): changed to allow \n in here-delimiter. - - * tree.c(tputS): quote ", ` and $ inside "-quotes. - * tree.c(ptree,pioact): made static. - * tree.c(ptree,fptreef,vfptreef): added indent argument; changed to - use indent argument; changed all calls. - * tree.h(struct ioword): added delim field. - * tree.c(iocopy),syn.c(synio,syntaxerr): deal with delim field. - * tree.c(pioact): print contents of here documents. - - * c_ksh.c(c_typeset): typeset -f foo: set exit code to 1 if function - not found. - -Mon Dec 19 15:14:02 NST 1994 Michael Rendell (michael@garfield.cs.mun.ca) - - * history.c(histinit): increment line number for each history line. - - * exec.c(iosetup): OS2: if open /dev/null fails, try nul instead. - * Makefile.in(debugtools,install,uninstall): make check-pgrp last; - use $E. - * eval.c(eval,expand): OS2: added DODIRSWP code. - * main.c(main): OS2: only include $HOME/kshrc.ksh if interactive. - * sh.h(FILENCMP,FILECMP,FILECHCONV): new defines. - * misc.c(gmatch),vi.c(grabsearch,complete_word),emacs.c(compl_file): - OS2: case insensitive compares. - (fixes from Dale DePriest). - -Mon Dec 19 09:54:42 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_cmd): make ~ honour argcnt (fix from Troy Bollinger). - - * vi.c(complete_word): don't add trailing / if there is already one. - * vi.c(glob_word): return rval, not 0. - -Thu Dec 15 11:06:01 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_cmd): call complete_word() with argument of 1 not 0. - -Tue Dec 13 12:07:50 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(histget): made static; added approx argument; changed - all calls. - -Tue Dec 13 10:58:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * Makefile.in(mandir): use $(manext), not 1 (fix from Mike Long). - -Mon Dec 12 20:55:53 NST 1994 John Rochester (jr@panda.cs.mun.ca) - - * tree.c(ptree): print TELIF part of if statements - -Fri Dec 9 15:21:36 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * trap.c(inittraps): OS2: don't trap SIGTERM (temproary fix). - - * exec.c(search_access1): OS2: fixed to check for valid suffix - and change mode from X_OK to R_OK if appropriate. - - * edit.c: include <sys/stream.h>, <sys/ptem.h> for SCO unix - (fix from William Bader). - - * c_ulimit.c(c_ulimit): changed type of val from long to rlim_t - (fix from Thomas Gellekum and J.T.Conklin). - * aclocal.m4(KSH_RLIM_T): new test for rlim_t. - * configure.in: use KSH_RLIM_T. - * acconfig.h: added rlim_t. - -Thu Dec 8 12:20:25 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * expr.c(evalexpr): changed div-by-zero test to only derefernce vr - if operation is a divide. - -Mon Dec 5 14:42:52 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(search): OS2: typo - changed namlen to namelen. - * exec.c(search_access): OS2: check execute bit explicitly. - * main.c(main): OS2: don't include ./profile.ksh. - * options.h(DEFAULT_PATH): OS2: added /os2 to path. - * sh.h(ksh_getdup): OS2: define to getdup(); prototype for getdup(). - * Makefile.in(dist): create os2 Makefile based on distribution - Makefile.in. - -Mon Dec 5 12:17:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.1.2 distribution - - * eval.c(globit): when searching directory, re-calculate end of - string based on prefix length. - -Fri Dec 2 11:07:48 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * syn.c(wordlist): if token isn't 'in', don't reject ;. - - * eval.c(expand): leading non-white-space IFS chars no cause initial - empty field. - -Thu Dec 1 12:04:00 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.1.1 distribution - -Thu Dec 1 10:50:38 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(TF_FATAL,fatal_trap): new define,variable. - * trap.c(inittraps,trapsig,fatal_trap_check,trap_pending,runtrap, - settrap): use TF_FATAL, fatal_trap. - * trap.c(runtraps): changed argument from bool to TF_* flag; changed - all calls. - * jobs.c(j_waitj): check fatal_trap flag. - -Wed Nov 30 11:20:03 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * conf-end.h: new file. - * config.h.bot: moved guts to conf-end.h. - - * emacs.c(struct x_ftab): changed type of xf_db_char from char to int. - * emacs.c(x_emacs): changed type of c from char to int. - * emacs.c(X_NTAB): new define. - * emacs.c(x_bind,x_init_eamcs): new X_NTAB, X_TABSZ. - * emacs.c(x_prefix3, x_meta3): ifdef OS2. - * emacs.c(x_bind): ifdef OS2; mask *a1 with CHARMASK. - - * exec.c(search_access): new function. - * exec.c(search): use search_access() instead of duplicating test. - * exec.c(search,search_access1): ifdef OS2. - - * Makefile.in(OS2FILES): new macro. - * Makefile.in(dist): add OS2FILES to distribution. - - * options.h(DEFAULT_PATH): ifdef OS2. - * edit.c(x_getc,x_mode): ifdef OS2. - * path.c(make_path): ifdef OS2. - -Tue Nov 29 16:51:35 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(EXECSHELL,EXECSHELL_STR): ifdef OS2. - * exec.c(scriptexec): use EXECSHELL_STR (was "EXECSHELL"). - - * trap.c(sigtraps[]): ifdef OS2. - * lex.c(yylex): ifdef OS2. - * misc.c(change_flag): ifdef OS2. - * history.c(HISTFILE): ifdef OS2. - * eval.c(homedir): ifdef OS2. - * c_sh.c(shbuiltins[]): ifdef OS2. - - * sh.h(ksh_execve,ksh_dupbase): new defines. - - * jobs.c(exchild): ifdef use of nice. - -Tue Nov 29 12:32:26 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(globit,copy_non_glob): changed to pass/use &xp it can change - (memory can be re-allocated). - - * ksh_dir.h(NLENGTH): new macro. - * eval.c(globit): use NLENGTH macro. - - * alloc.c(aresize): removed redundent np and optr variables. - -Mon Nov 28 14:55:49 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * config.h.bot(HISTORY): new define. - * lex.c(getsc_): ifdef HISTORY. - * history.c: ifdef HISTORY (dummy histsave, init_histvec and - hist_finish routines). - * c_ksh.c(kshbuiltins): c_fc: ifdef KSH - * lex.h(HISTORY): changed to HISTORYSIZE; changed all references. - - * options.h(KSH): new define. - * config.h.bot: changed to deal with KSH define. - * exec.c(do_select,pr_menu): ifdef KSH. - * exec.c(execute): case TSELECT: ifdef KSH. - * c_ksh.c(c_whence,c_command,kshbuiltins[]): ifdef KSH. - * main.c(initcoms[],main): ifdef some aliases, SECONDS/RANDOM/TMOUT. - * syn.c(get_command): case TDBRACKET: ifdef KSH. - * syn.c(db_parse,db_aoexpr,db_nexpr,dp_primary): ifdef KSH. - * syn.c(tokentab[]): "select", "[[" ifdef KSH. - * var.c(special,getspec,setspec,unsetspec): ifdef KSH. - * ksh.1: ifdef KSH; misc fixups. - (changes mostly from Michael Haardt). - -Mon Nov 28 14:27:34 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(skip_varname,special,global,local), table.c(hash,tsearch, - tenter): made argument and return value const. - - * main.c(version_param[]): new variable. - * main.c(initcoms[],main): use version_param instead of "KSH_VERSION". - - * history.c(histsave): EASY_HISTORY: changed to take same arguments - as COMPLEX_HISTORY histsave(); changed all calls, removing - unneeded ifdefs. - - * vi.c(x_vi), emacs.c(x_emacs): changed unwind() call from LINTR - to LSHELL so newline isn't printed twice - also lets runtrap() - set the exit code. - - * vi.c(vi_cmd): increment source line if saving to history. - -Fri Nov 25 14:43:57 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * syn.c(get_command): don't generate a syntax error if EOF is read. - - * configure.in: add LDSTATIC to LDFALGS if the former is set. - - * history.c(hist_skip_back): start at the end of the buffer, not - one past the end (fix from Simon J. Gerraty). - -Thu Nov 24 09:53:49 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * syn.c(get_command,dogroup): allow { ...;} to be used instead - of do ...;done in for/select loops. - -Wed Nov 23 09:09:43 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.1.0 distribution - - * var.c(setspec): set seconds to current time - assigned value, - not just current time. - - * emacs.c(x_copy_arg): deleted ifdef'd out code (x_prev_histword() - does what it was supposed to do). - - * emacs.c(compl_command): don't call list_stash() twice (happened - if type == 2 and multi set). - -Tue Nov 22 10:26:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_test.c(eval_unop): don't assume S_ISBLK, S_ISCHR, S_ISUID, - S_ISGID are defined. - - * path.c(make_path): avoid addeding extra /'s in paths; avoid - infinate loop if result buffer not big enough. - - * main.c(main): setting PWD: avoid calling setstr() with the - current value of PWD. - - * var.c(typeset): set free_me to 0 if t is integer. - - * emacs.c(x_search_hist): added overflow checking to fixed sized - buffers. - * emacs.c(compl_file,compl_command): removed fixed sized buffers. - - * vi.c(x_vi), emacs.c(x_emacs): on interrupt, unwind instead of - calling runtraps(). - - * vi.c(vi_cmd): added 'g' command to goto the most recent command. - - * c_sh.c(c_read), c_ksh.c(c_print): always increment source->line when - saving history. - -Mon Nov 21 10:45:34 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(do_selectargs): removed use of pmenu variable (redundent) - use isspace() instead of IFS chars; include <ctype.h>. - - * aclocal.m4(KSH_TERM_CHECK): do not allow HAVE_TERMIOS_H check to - succeed on ultrix (avoid type-ahead loss). - - * emacs.c(x_fword): cahnged loop to skip non word chars, then word - chars (was the opposite). - - * main.c(shell): after error/interrupt/etc, reset an EOF if ignoreeof - option is set. - - * vi.c(classify[]): changed space (040) from C_|U_ to M_ - (got broken in 5.0.10). - - * ksh_wait.h(ksh_waitpid): new define. - * jobs.c(waitpid): moved define to ksh_wait.h; changed use of - waitpid() to ksh_waitpid(). - - * history.c(hist_skip_back),io.c(maketemp): use procpid instead of - getpid(). - -Fri Nov 18 16:08:09 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(FSHOW8): inverted meaning: now if set, do the M- stuff - (done so 8 bit char sets work by default). - - * main.c(main): set exstat to 127 if command file can't be opened. - - * main.c(main): use argv[0] instead of kshname when deciding - whether to include profiles. - -Fri Nov 18 14:25:11 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.10.1 distribution - - * tty.h: deleted KSH_VDISABLE; moved _POSIX_VDISABLE stuff to edit.c. - * edit.c(x_init): calculate value for vdisable_c. - * edit.c(x_mode): use vdisable_c instead of KSH_VDISABLE. - -Thu Nov 17 12:09:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.10 distribution - - * lex.c(getsc_),edit.c(x_getc): call runtraps(FALSE) if read is - interrupted. - * vi.c(x_vi),emacs.c(x_emacs): call runtraps(FALSE) (was TRUE). - -Wed Nov 16 09:48:54 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(execute,scriptexec): call __setostype(0)/(1) before/after - execve() on ISC machines. - - * trap.c(trap_pending): new fuction. - * jobs.c(j_waitj): use trap_pending(); return -<signal-number> if - interrupted. - * jobs.c(waitfor): added sigp argument; changed all calls. - * c_sh.c(c_wait): use signal number set by waitfor() to set exit status. - - * shf.c(SHF_INTERRUPT): no longer calls intrcheck() - now sets - error flag and returns EOF. - * c_sh.c(c_read): re-arranged to have single shf_getc() call; if read - interrupted and signal is fatal (fatal_trap_check()), make read - return with appropriate exit code. - * trap.c(fatal_trap_check()): new function. - * trap.c(inittraps()): catch and cleanup on SIGHUP; don't force the - setting of SIGINT,SIGQUIT,SIGTERM,SIGHUP. - - * table.c(tenter): changed to use strlen()/memcpy() instead of loops. - - * var.c(initvar): new function. - * main.c(main): call initvar(). - * var.c(special): changed to use hash table for lookup. - - * main.c(main),syn.c(initkeywords): moved table initialization - from main() to initkeywords(). - -Tue Nov 15 10:01:20 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(copy_non_glob): new routine. - * eval.c(globit): changed to use copy_non_glob() instead of strchr(). - - * misc.c(cclass): if [..] pattern has no closing ], do literal - compare of character with [ (used to always fail). - - * eval.c(globit): handle symbolic links in the check code. - - * configure.in: added check for lstat(). - * ksh_stat.h: defined lstat to be stat if lstat is not available. - - * exec.c(search): return Xclose() instead of Xstring(). - -Mon Nov 14 16:28:41 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * ksh_times.h: changed BROKEN_TIMES to TIMES_BROKEN. - - * c_test.c(syntax): removed \n from error messages. - - * eval.c(glob,globit): changed to use dynamicly allocated string - instead of a fixed sized buffer. - -Thu Nov 10 10:47:55 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * history.c(sethistsize): don't set size if new size is < 0; fixed - offset calculation so histptr is not way beyond the end of array; - if history is shrinking, save newest history back. - - * vi.c(vi_hook): case VSEARCH: call restore_cbuf() after \n or \r. - - * main.c(quitenv): call restfd() even if fd < 0 to re-close fd. - - * exec.c(execute): commented out code that set savefd[0/1] to -1 - if input/output was a pipeline. - - * missing.c(dup2_fixup): deleted function. - * sh.h(dup2->dup2_fixup): deleted define. - * io.c(ksh_dup2): new function; changed all dup2() calls to ksh_dup2(). - -Wed Nov 9 11:11:31 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * edit.h(struct edchars): added eof field. - * edit.c(x_init): initialize eof fields. - * vi.c(x_vi): changed ^D to edchars.eof. - * vi.c(vi_cmd): make I/cc/S skip blanks. - - * history.c(histsave): EASY_HISTORY: use memmove() to copy pointers - back one. - - * vi.c(vi_cmd): make G act the same as at&t ksh. - * vi.c(ismeta,O_): deleted macros; removed all references to O_. - * vi.c(classify[]): add ^X and ^F to command mode. - -Tue Nov 8 11:15:01 NST 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * main.c(initsubs[]): don't set SHELL. - - * vi.c(vi_cmd): added v command (start up vi). - * vi.c(vi_hook): added case for vi_cmd() returning 2. - * vi.c(grabsearch): set anchored flag if pattern starts with ^. - (based on fixes from Michael Jetzer). - - * history.c(findhist): added anchored argument; changed all calls. - * history.c(histget): start searching from histptr-1; changed to - call findhist() to do searching. - * history.c(c_fc): changed to print multiline commands correctly. - (based on fixes from Michael Jetzer). - -Fri Nov 4 10:30:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(yylex): when pushing alias sources, allocate from existing - source's area. - - * lex.c(struct source): added areap field. - * lex.c(pushs): added area argument; changed all calls. - * history.c(histrpl): changed constant sized hline[] to expandable - string; removed hline/hsize parameters; changed all calls; put - newline at end of string. - * history.c(c_fc): changed to use dynamically sized buffer when reading - commands; strip nulls after read. - * history.c(histbackup): made static. - - * trap.c(block_pipe): if handler is SIG_DFL, change it to SIG_IGN. - - * lex.c(readhere): changed to allow eof after end-of-file marker - (bug report from Andrew Moore). - -Thu Nov 3 09:09:39 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * io.c(coproc_read_close,coproc_write_close): new functions. - * c_sh.c(c_read): call coproc_read_close() when eof is read. - * c_ksh.c(c_print): set PO_COPROC if fd is coproc.write; call - coproc_write_close() if write fails due to EPIPE. - * exec.c(iosetup): call coproc_write_close() after #>&p. - * sh.h(EF_COPROC_DUPED): deleted. - * sh.h(struct coproc): deleted isopen field. - * io.c(cleanup_coproc): do not use isopen field. - * c_sh.c(c_exec): deleted EF_COPROC_DUPED code. - * exec.c(TCOPROC): don't set isopen; don't start new coprocess if - old job exists and write pipe hasn't been closed. - - * misc.c(str_zcpy): new function. - * lex.c(getsc_): made line[] buffer local/static; use str_zcpy() - to fill line[]. - * history.c(c_fc): use local hline buffer instead of global line[]; - use str_zcpy() to fill hline[]; - * history.c(histrpl): added hline and hsize parameters; changed all - calls. - * history.c(hist_init): EASY_HISTORY: use local hilne buffer instead - of global line[]. - * lex.h(line[]): deleted. - * syn.c(compile): do not set s->str to null for STTY and SHIST. - -Wed Nov 2 11:48:36 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(getsc_): case SDDPAREN: set csstate before going to - SPAREN state. - - * Makefile.in(RCSFILES): removed POSIX from list (now covered in - man page). - -Tue Nov 1 09:27:46 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(comsub): save/restore source before/after compile(). - - * c_ulimit.c(c_ulimit): allow value to be arithmetic expression - (as per Korn book). - - * c_sh.c(c_read): call set_prompt() before printing prompt. - - * expr.c(v_evaluate): treat an empty expression as 0. - -Mon Oct 31 09:23:57 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(grabhist,grabsearch): check that history line doesn't overflow - edit buffer. - - * history.c(hist_finish): (EASY_HISTORY) changed for-loop condition to - prevent passing the end of history. - - * eval.c(expand): when stuffing MAGIC, cast c to char. - - * misc.c(strip_nuls): new function. - * lex.c(getsc_): case STTY/SFILE/SSTDIN: call strip_nuls() after - reading commands. - - * edit.c(set_editmode): reversed strstr() arguments - check for - vi/emacs in $EDITOR/$VISUAL string. - - * syn.c(yyparse): allow EOF as well as newline after a command. - * lex.c(getsc_): case SSTRING: don't fake newline - -Sun Oct 30 10:55:20 NST 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_print): echo: check for -n, -e and -E options. - - * exec.c(comexec): don't allow command -p if restricted. - -Fri Oct 28 10:24:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(typeset): in fake_assign code, was freeing t->val.s + t->type - instead of t->val.s - now uses free_me variable instead of aflag. - - * Makefile.in(depend): change blank lines in depend output to sh.h - so dumb make(1)s won't die. - - * mail.c: changed checking to use atime/mtime instead of size; changed - struct mbox mb_size field to mb_mtime, changed all references. - - * main.c(shell): do not execute (or set the exit status for) a null - command. - * lex.c(readhere): read the newline after the eof marker. - -Wed Oct 26 09:11:08 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(globit): added FMARKDIRS support. - - * emacs.c(x_ftab[]): added entries for ansi arrow key bindings. - - * exec.c(execute,iosetup): move tracing of redirections from - execute() to iosetup() so expanded name can be printed. - - * exec.c(execute): case TDBRACKET: read was being called instead of - test. - - * ksh_stat.h(S_ISCDF): new define. - * c_test.c: added -H for context dependent files (HP bizarreness). - - * main.c(initcoms[]): added alias local=typeset. - - * Makefile.in(stamp-h,config.status): added double quotes CONFIG_FILES - and LDSTATIC assignments for dmake. - * aclocal.m4(KSH_SYS_SIGLIST): do something with sys_siglist so it - isn't optimized away. - * aclocal.m4(KSH_CLOCK_T): do extra check for clock_t in sys/times.h. - * acconfig.h(CLOCK_T_IN_SYS_TIMES_H): new define. - * sh.h(SIGNALS): use _SIGMAX if NSIG, _MINIX not defined. - (fixes from Brian Campbell <brianc@qnx.com>) - - * emacs.c(x_transpose): changed behavior if FGMACS flag set - (fix from <guy@netapp.com>). - -Tue Oct 25 17:11:58 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * tty.c(KSH_VDISABLE): new define. - * edit.c(x_init): use KSH_VDISABLE. - -Tue Oct 25 09:55:09 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.9 distribution - - * c_ulimit.c(c_ulimit): changed SOFT, HARD from enum to defines - to avoid problems with ancient compilers. - - * vi.c(CHAR_LEN,char_len): changed macro to function; added FVISHOW8 - support. - * misc.c(options[]), sh.h(FVISHOW8): added FVISHOW8 option. - -Sun Oct 23 11:02:26 NDT 1994 Michael Rendell (michael@maple.cs.mun.ca) - - * main.c(shell): keep unwinding if LINTR and not interactive. - - * lex.c(yylex): do redumentery quote parsing for $(..). - -Thu Oct 20 11:02:27 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(execute): case TSELECT: set rv to 1 if eof is read. - * exec.c(execute): case TFOR/TSELECT/TWHILE/TUNTIL: set rv to 0 before - entering loop, but after setjmp incase of a continue; rv to 0 - after a break. - * exec.c(execute): case TFOR/TSELECT: do readonly check before - assigning value. - * c_ksh.c(c_getopts): do readonly check before assigning value. - - * misc.c(print_columns),c_ksh.c(kill_fmt_entry), - misc.c(options_fmt_entry),exec.c(select_fmt_entry): new functions. - * c_ksh.c(c_kill),misc.c(printoptions),exec.c(pr_menu): use - print_columns() call a call-back routine to format information - in columns. - -Wed Oct 19 10:26:25 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * misc.c(cclass): require MAGIC before - and ]. - * eval.c(expand): prefix - and ] with MAGIC if appropriate. - - * var.c(typeset): don't allow export flag of readonly variables - to be cleared. - - * eval.c(globit): added call to intrcheck(). - -Mon Oct 17 11:48:05 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * lex.c(readhere): check for and report write errors. - -Sun Oct 16 16:10:59 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_ksh.c(c_cd): don't allow cd if restricted. - * exec.c(comexec): if restricted and command contains /, print error. - * exec.c(ioestup): if restricted, don't allow file creations. - * main.c(is_restricted): new function. - * main.c(main): save and reset FRESTRICTED during .profile/ENV reading; - set FRESTRICTED if argv[0] or SHELL refers to restricted shell; - make PATH, ENV, SHELL readonly if restricted. - * var.c(typeset): check for restricted shell and PATH/ENV/SHELL. - -Thu Oct 13 21:01:14 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(shell): only call j_notify() for interactive shells. - - * c_sh.c(c_read): check if variable is readonly before assigning - value. - -Wed Oct 12 14:08:46 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.h(COPROC),tree.h(TCOPROC,XCOPROC): added defines. - * lex.c(yylex): return COPROC for |& token. - * syn.c(tokentab): added COPROC. - * syn.c(c_list): accept COPROC, create TCOPROC node. - * tree.c(ptree): added case for TCOPROC. - * exec.c(execute): added case for TCOPROC. - * io.c(check_fd,get_coproc_fd): new functions. - * c_sh.c(c_read),c_ksh.c(c_print): changed to use check_fd(); - added -p option; for c_print() ensure SIGPIPE doesn't kill shell. - * exec.c(iosetup): changed to use check_fd() for IODUP; when - checking fore close, require exactly the string '-', not any - string starting with '-'; added strerror() to error message. - * jobs.c(exchild): don't open /dev/null if XCOPROC; close - coproc.read/write/childread in child if XCOPROC; don't pass - XCOPROC flag on to execute(); set coproc.job to job in parent - if XCOPROC. - * jobs.c(check_job): clear coproc.job if said job dies. - * trap.c(block_pipe,restore_pipe): new functions. - * sh.h(struct coproc, EF_COPROC_DUPED): new structure and define. - * c_sh.c(c_exec): if EF_COPROC_DUPED set, clean up co-process stuff. - - * main.c(cleanup_parents_env): new function. - * jobs.c(exchild): call cleanup_parents_env() after fork(). - - * tree.h(IORDUP): new define. - * lex.c(yylex): changed redirection parsing to not accept & only after - a single < or >; set IORDUP flag for x<&y; fixed <</<>/>> check to - not allow >< (again). - * tree.c(pioact): use IORDUP flag to print <& or >&. - - * jobs.c(exchild): set JF_ORIGFG flag if job started in foreground. - * jobs.c(j_waitj): don't get default tty settings if JF_ORIGFG not - set. - - * misc.c(parse_args): treat -A as a flag that is handled later - (used to require argument); do array setting after argument - sorting. - * var.c(set_array): changed second argument from 0/1 flag to - -1/1 flag; changed all calls. - -Thu Oct 6 11:55:27 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * table.c(tinit): added initial table size argument; call texpand - if size isn't 0; changed all calls. - * main.c(main): try to make sure table size is big enough for - builtins and keywords (cut down on amount of re-hashing). - - * eval.c(expand): added next and prev fields to struct SubType; - removed fixed length subtype array, changed code to allocate - SubTypes as needed. - -Wed Oct 5 09:25:06 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * main.c(main): moved initio() above inittraps() as later can print - stuff. - - * table.h(IMPORT): new flag. - * var.c(typeset): if IMPORT flag set, don't allow array references, - insist on assignment. - * var.c(import): deleted function. - * main.c(main): use typeset() instead of import(). - - * sh.h: include expand.h. - * expand.h(Xnleft): new define. - * expand.h(struct XString, Xinit): added areap field; added area - argument to Xinit; changed all calls. - * lex.h(struct source): added xs field. - * shf.c(shf_gets,shf_getse): changed name fromshf_gets to shf_getse; - return pointer to null byte instead of start of buffer. - * lex.c(pushs): if type is SFILE or SSTDIN, initialize s->xs. - * lex.c(getsc_): case SFILE/SSTDIN: use s->xs instead of fixed - size line buffer. - - * syn.c(compile): don't change s->str if SFILE. - * main.c(main): call pushs() explicitly for each of SSTRING, - SFILE, SSTDIN, STTY. - - * aclocal.m4(KSH_GCC_FUNC_ATTR): changed GCC_FUNC_ATTR to - HAVE_GCC_FUNC_ATTR. - * config.h.bot: changed use of GCC_FUNC_ATTR; deleted - GCC_FA_NORETURN, GCC_FA_CONST, GCC_FA_FORMAT defines, created - generic GCC_FUNC_ATTR define; changed all uses of GCC_FA_*. - - * main.c(main): set s->file for SSTDIN input. - - * main.c(shell): pass LERROR on if not interactive. - - * expand.h(Xcheck,XcheckN): added XcheckN define, changed Xcheck - to use XcheckN; made XcheckN call Xcheck_grow_() do do any real work - (to cut down on code size). - * misc.c(Xcheck_grow_): new function. - * exec.c(search),c_sh.c(c_read): changed to use Xstring() routines - (used to use the fixed size buffer line[]). - * exec.c(findcom): avoid re-saving search() result in ATEMP. - -Tue Oct 4 15:32:37 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * jobs.c(j_jobs): return int value indicating error/ok; changed - all calls. - - * misc.c(getn): added int * argument to hold result; changed - return value to indicate success/failure; changed all calls. - * misc.c(bi_getn): new function. - * misc.c(getn_): deleted function. - - * io.c(internal_error,error_prefix,warningf): new functions. - * *.c: changed errorf() calls reporting internal errors to - use internal_error() function; changed many shellf()s to - warningf(). - * io.c(errorf),lex.c(yyerror): changed to use error_prefix(). - - * alloc.c(aprint): ifdef'd out. - * tree.c(phash): deleted function. - -Mon Oct 3 15:08:24 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * sh.h(kshname): new variable - * main.c(main): changed name to kshname, deleted local variable. - * exec.c(comsub): update kshname. - * var.c(popblock): restore kshname. - * io.c(errorf,bi_errorf): print shell name before error message. - - * c_ksh.c(c_cd): print new directory on stdout, not stderr. - - * sh.h(GI_MINUS): new define. - * misc.c(ksh_getopts): changed so once - or + introduces option, - all options must start with same character. - - * sh.h(builtin_argv0): new variable. - * exec.c(call_builtin): set/clear builtin_argv0, builtin_flag; changed - argument to a struct tbl *; changed all calls. - * io.c(bi_errorf): new function. - * c_ksh.c,c_sh.c,c_ulimit.c,emacs.c,history.c,jobs.c: changed all uses - of errorf() to bi_errorf(). - * emacs.c(x_bind): changed return value to int; changed all calls. - * history.c(histrpl): return 0 if there is an error; changed all calls. - * misc.c(parse_args): use bi_errorf(); return -1 for error; changed all - calls. - * misc.c(ksh_getopts): call bi_errorf instead of errorf which means - ksh_getopts() may return after an error, so changed all calls to - check for '?' return. - - * exec.c(iosetup): use shellf() to report errors and return value - indicating success or failure. - * exec.c(execute): if iosetup fails, cause fatal error for special - builtins, return otherwise; print PS4 and redirections. - -Fri Sep 30 15:17:37 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_ulimit.c(c_ulimit): accept unlimited as a valid value. - - * c_test.c(c_test): changed posix special case code to use - while loop. - - * c_ksh.c(c_whence): for whence -p, don't look for built-ins or - fuctions. - -Thu Sep 29 10:34:59 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_ksh.c(c_alias): added -r option so the sysv-bounre shell - hash -r will work. - - * eval.c(debunk): use strchr() to find first MAGIC, if any. - -Wed Sep 28 15:34:32 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * sh.h(O_NONBLOCK): define to O_NDELAY or FNDELAY if not defined. - * main.c(main): if stdin is O_NONBLOCK'd, clear O_NONBLOCK. - - * misc.c(options[], parse_args): make -c a normal flag, not an option - with an argument (POSIX); deleted cargp argument to parse_args(). - * main.c(main): print error if -c and no arguments left. - - * lex.h(SSTDIN): new define. - * lex.c(yylex): added case for SSTDIN. - * main.c(main): if -s flag used, set source type to SSTDIN. - -Tue Sep 27 08:52:11 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * lex.c(get_brace_var): new function. - * lex.c(yylex): removed most ${..} parsing - leave it to expand(); - use get_brace_var() to read the variable part of a ${..} expression. - * tree.c(tputs,wdscan): case OSUBST: delete code that understood - partially compiled ${..}. - * sh.h(C_SUBOP,C_SUBOP1,C_SUBOP2): changed C_SUBOP to C_SUBOP1, - added C_SUBOP2. - * misc.c(initctypes): removed # and % from C_SUBOP; changed C_SUBOP to - C_SUBOP1; added C_SUBOP2. - * eval.c(varsub): look at word part of substitution to figure out - type of substitution; check for bad substitutions; check for unset - variables for #/% substitutions. - * eval.c(struct SubType): changed type field to stype; changed quote - field to short; added f field. - * tree.h(DOTEMP_): new define. - * eval.c(expand): case CSUBST: case '=': deleted bad substitution - error (now handled in varsub); case OSUBST: removed special handling - of trimming - varsub() does it now; when pushing/poping state (st), - save/restore value of f; set f to DOPAT when trimming; case CSUBST: - case '=': restore original position in string, substitute the value - of the variable (as opposed to the value that was assigned to the - variable); case OSUBST: if '?' qualifier, turn off DOBLANK when - expandined word part; define DOTEMP_ when expanding word part - of ${..[#%=?]..}; deleted first_eq and tstart - replaced with - tilde_ok and saw_eq. - - * eval.c(expand): tilde expansion: use tstart variable instead of cp; - changed '?' error message to be like at&t ksh; don't test if strval() - returns NULL - it doesn't. - - * var.c(strval): if !ISSET, instead of returning null, set s to null. - - * exec.c(comexec): case TDBRACKET: don't pass DOASNTILDE to evalstr(). - - * exec.c(scriptexec): changed line[] to buf[] so it doesn't get - confused with global the line[]. - - * main.c(initsubs): initialize PS4. - * edit.c(x_getc): cast char to unsigned before returning. - -Mon Sep 26 11:06:55 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * eval.c(globit): call strnsave instead of strsave; if file has - trailing /, use stat() to check that it is a directory. - - * eval.c(expand): case CSUBST: case #/%: deleted duplicate *dp = 0; - case CSUBST: case =: copy string and call debunk() to oust MAGICs. - - * misc.c(print_value_quoted): deleted bogus shf_shlout argument to - shprintf(); deleted unneeded test (p != s). - - * main.c(main): turn on FBRACEEXPAND. - * misc.c(change_flag): turn FBRACEEXPAND off if turning FPOSIX on. - - * vi.c(x_vi): use x_vi_zotc() to print ^D. - * vi.c(CHAR_LEN): new define. - * vi.c(vi_hook): use CHAR_LEN() instead of inline tests for - c < ' ' || c== 0x7f; search editing: display M- if necessary. - * vi.c(display): changed to deal tiwh meta-characters. - - * vi.c(x_vi_zotc): print M- for meta chars. - * emacs.c(x_e_getc): new function; changed all x_getc() calls to - x_e_getc() calls. - * edit.c(x_getc): don't and out upper bit. - - * sh.h(OPAREN,CPAREN,OBRACK,CBRACK,OBRACE,CBRACE): new defines - * expr.c(OPAREN,CPAREN): re-named to OPEN_PAREN, CLOSE_PAREN. - - * eval.c(debunk): changed to convert MAGIC MAGIC -> MAGIC. - * eval.c(expand): removed ismagic_bracket stuff - not needed. - * eval.c(expand): always restore value of quote when CSUBST - reached; don't set DOGLOB in fdo if trimming. - -Sat Sep 24 11:46:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * tree.h(DOBRACE_): new define. - * eval.c(expand): changed check for leading ! in [..] to be more - robust (old test could have looked before start of string). - * eval.c(expand,maybe_expand_tilde): case ~: moved code into a function - (maybe_expand_tilde). - * eval.c(expand): expand alternations after macros, before globing - (was before macros). - * eval.c(alt_expand): changed to be called after macro expansion. - * eval.c(alt_scan,alt_count): deleted (no longer needed). - - * misc.c(cclass): return NULL (no match) if first char in a range - is greater than the second. - * eval.c(expand): when building strings, stuff literal MAGIC chars. - -Thu Sep 22 15:05:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(comexec): re-arranged handling of builtin and exec; - handle command (and command -p, etc.); deleted comexec_flags - variable; made function static again; removed fcflags argument. - * table.h(FC_NOBLOCK): deleted define. - * c_sh.c(c_exec): changed empty function to deal with preserving I/O - redirects (code taken from comexec()). - * c_ksh.c(c_command): new function - calls c_whence. - * c_ksh.c(c_whence): removed code to deal with command -p. - - * Makefile.in: changed [ to test. - * shf.h: changed errno structure member to errno_; changed all uses - (fixes for QNX from Brian Campbell). - - * c_test.c(enum Op): deleted trailing comma (some compilers complain). - * proto.h: added volatile to tp arg of comexec() prototype. - -Thu Sep 22 11:08:31 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.8 distribution - - * Makefile.in(install): added missing dollar (fix from Thomas Gellekum). - - * emacs.c: changed CMASK to CHARMASK to avoid conflicts with some - system headers (eg, HP-UX 9.01 <sys/param.h>). Reported by Sean - Hogan. - - * history.c(c_fc): wp not being incremented; -e strcmp() test reversed - (reported by Sean Hogan). - -Thu Sep 21 21:12:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.7 distribution - -Tue Sep 20 09:56:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * history.c(c_fc): use ksh_getopt() to parse arguments. - * c_ksh.c(c_bind): use ksh_getopt() to parse arguments. - - * main.c(initcoms[]): changed hash alias from alias -t - to alias -t --. - - * misc.c(print_value_quoted): don't use quotes if no special - characters. - - * c_ksh.c(c_whence): added POSIX command command. - - * c_sh.c(c_label): removed check for null wp. - - * exec.c(comexec): added new flags argument (FC_*); - don't call newblock() if FC_NOBLOCK set; pass flags on to - findcom(); changed all calls; made comexc() a non-static - function. - - * table.h:(FC_SPECBI,FC_FUNC,FC_REGBI,FC_UNREGBI,FC_PATH,FC_DEFPATH, - FC_NOAUTOLOAD,FC_NOBLOCK): new defines. - * exec.c(findcom): merged insert/justsearch/autoload arguments - into one flags argument; changed code to check various flags; - changed all calls. - -Sat Sep 17 20:17:59 NDT 1994 Michael Rendell (michael@garfield.cs.mun.ca) - - * exec.c(comexec): print error if builtin has no command. - - * exec.c(execute): before doing redirections, check for TCOM and - evaluate arguments and determine if it is a special builtin; - print arguments (using PS4) if FXTRACE set; case TCOM: simply call - comexec(). - * exec.c(comexec): deleted vp argument; only call newblock() if - needed (ie, !special, !empty); evaluate assignments and put - in environment one at a time; print environment (using PS4) if - FXTRACE set; removed code to turn empty command into :; - removed environment setting code in switch statement. - * exec.c(echo): deleted function. - - * lex.c(yylex): only honour CMDWORD if FPOSIX set. - - * c_sh.c(shbuiltins): removed = attribute from false/true commands. - - * sh.h(E_TCOM): delete define - not used. - - * sh.h(null),var.c: use EXTERN for initialization of null. - * sh.h(space,newline,slash): new variables (" ", "\n", "/") - use these everwhere instead of "", " ", "\n", "/". - * path.c: include sh.h. - - * exec.c(execute): combined TFOR/TSELECT cases. - -Fri Sep 16 11:32:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.h(CMDWORD): new define to prevent continued alias expansion in - non-command contexts. - * lex.c(yylex): only set ALIAS if SF_ALIAS and CMDWORD are set. - * syn.c(get_command): case LWORD/REDIR: pass CMDWORD if argc is 0. - - * exec.c(comexec): if there is no command, do assignments and set - the return value to subst_exstat (used to fake a : command). - - * sh.h(subst_exstat): new variable. - * exec.c(execute): case TCOM: clear subst_exstat before doing eval()s. - * eval.c(expand): set subst_exstat to return value of waitlast(). - * c_sh.c(c_set): if !FPOSIX, return subst_exstat instead of 0. - - * exec.c(execute): removed redundent "exstat = rv;" near if FERREXIT. - * exec.c(comexec): case CFUNC: for normal function completion, set - i to 0 and rv to return value of execute() (was i=LRETURN,exstat=..). - - * main.c(include): return -1 if file could not be found/opened, - otherwise, the exit status of the last command is returned; - changed all calls. - * c_sh.c(c_dot): print error if include() returns < 0. - - * var.c(setspec): ifdef EDIT'd V_VISUAL, V_EDITOR cases. - - * misc.c(parse_args): no longer accept set -o alternations as - a substitute for set -o braceexpand. - - * jobs.c(j_exit): when restoring tty process group, also restore - our process group. - - * config.h.bot: define JOB_SIGS iff we have modern signal and wait - routines. - * jobs.c: use ifdef JOB_SIGS instead of ifdef JOBS when setting - signal masks and routines or using waitpid; define TTY_PGRP and - NEED_PGRP_SYNC seperately from JOBS. - * jobs.c(j_kill): only send SIGCONT if job is stopped. - * jobs.c(j_jobs): remove exited/signaled jobs even if !FMONITOR, - un-ifdef JOBS same. - - * jobs.c(check_job): ifdef FNOTIFY with JOBS (noted by - Michael Haardt <u31b3hs@POOL.Informatik.RWTH-Aachen.DE>). - * jobs.c(j_notify,j_waitj): put ifdef JOBS around use of FMONITOR. - * main.c(shell): removed ifdef JOBS from declaration of interactive. - - * ksh_limval.h,sh.h: moved include of <limits.h> from ksh_limval.h - to sh.h since some machines define CLK_TCK there. - -Thu Sep 15 09:58:14 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * vi.c(vi_cmd): took out ESC as file completion char in command mode - (too annoying). - - * jobs.c(exchild): if starting a job in the background and FBGNICE - is set, call nice(). - - * Makefile.in: changed maxext to manext (fix from Thomas Gellekum - <thomas@ghpc8.ihf.rwth-aachen.de>); in the install target, check - if the path of the installed shell is in /etc/shells and - complain if it isn't; added depend target, removed old $(OBJS) - and trap.o dependencies. - -Wed Sep 14 09:39:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(options[]): changed position of vi-tabcomplete option. - - * lex.c(yylex): ifdef use of FVI/FEMACS/FGMACES with VI/EMACS - (fix from Gordan Larson <hoh@approve.se>). - - * ksh.1(DESCRIPTION): added missing P in \fP - (fix from Gordan Larson <hoh@approve.se>). - -Tue Sep 13 11:01:47 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.6 distribution - -Mon Sep 12 11:39:07 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(scriptexec): changed so it will compile if SHARPBANG is - defined; fixed error message; shell argument is everything up to - a newline; don't listen to #! line unless it ends in a newline. - - * syn.c(get_command): case FOR: changed VARASN to ARRAYVAR. - - * jobs.c(waitfor): restore signal mask before returning if named job - isn't own own; when waiting for unspecified jobs, only consider - running jobs; don't pass JW_STOPPEDWAIT flag to j_wait. - - * table.h(V_TMPDIR,tmpdir): new define/variable. - * var.c(setspec, unsetspec): added case for V_TMPDIR. - * io.c(maketemp): use tmpdir variable if it is set, else use /tmp. - - * var.c(popblock): if poping a variable that wasn't set in the old - environment, call unsetspec(). - -Fri Sep 9 10:37:18 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(PATHMAX): increased value from 256 to 1024. - - * main.c(main): moved initialization of name to start of main; - if getcwd() fails, use name in error message and call shf_flush(). - - * io.c(maketemp): check/use TMPDIR variable instead of /tmp; allocate - temp structure and path in one chunk. - - * c_ksh.c(c_cd): when checking for no home directory, compare - against null, not (char *) 0. - -Thu Sep 8 10:52:59 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(yylex): case SHIST: flush shl_out after printing command. - - * jobs.c(check_job): when notifing, do not remove job if it is stopped. - -Wed Sep 7 10:55:35 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.5 distribution - - * main.c(shell): commented out shf_flush(shl_out) - shouldn't be - needed since -v flushes itself. - -Tue Sep 6 09:30:57 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * sh.h(LSHELL,really_exit): new define/variable. - * c_sh.c(c_exitreturn): if how is LEXIT, check if there are stopped - jobs and, if so, unwind with LSHELL (also check/set really_exit). - * main.c(shell): added case for LSHELL - stop unwinding if shell - is interactive; changed local reallyquit to global really_exit. - * main.c(include),exec.c(comexec): added case for LSHELL. - - * c_sh.c(c_exitreturn): quitenv() for LRETURN as well as LEXIT. - - * sh.h(TF_CHANGED): new define. - * trap.c(runtrap): default EXIT/ERR trap during execution and restore - original if TF_CHANGED not set. - * trap.c(settrap): set TF_CHANGED when setting trap. - - * jobs.c(j_stopped): check that job created by current process; print - "You have stopped jobs" message. - * main.c(shell): don't print you have stopped jobs message. - - * main.c(initcoms): removed echo alias. - * c_ksh.c(kshbuiltins): added echo as a builtin. - * c_ksh.c(c_print): if wp[0] is echo, act like strict sysv echo; - added \a (BEL) escape sequence. - - * syn.c(function_body): new function; calls get_command() to get - the body of a function (old code did nested { } block which - caused problems with how redirections after the block were - handled). - * syn.c(get_command): call function body to deal with foo() and - function foo. - - * jobs.c(restore_ttypgrp): new variable. - * jobs.c(j_change): set restore_ttypgrp if process group is set. - * jobs.c(j_exit): if necessary, restore tty process group for main - shell. - -Fri Sep 2 21:32:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * main.c(main): set FPRIVILEGED if uid (gid) doesn't match euid (egid); - don't include $HOME/.profile if FPRIVILEGED; include - /etc/suid_profile instead of $ENV if FPRIVILEGED. - * misc.c(change_flag): if clearing FPRIVILEGED flag, set euid (egid) - to uid (gid). - -Fri Sep 2 21:10:23 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * main.c(main): don't include $ENV if uid (gid) doesn't match - euid (egid) (from J.T.Conklin). - -Fri Sep 2 12:07:14 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * syn.c(get_command): removed MPAREN case, taken care of in '(' case, - as per POSIX.2 which says () is two operators, not one. - * lex.c(yylex): don't check for/return MPAREN. - * lex.h(MPAREN): deleted define. - - * configure.in: add test for library routine confstr(); add - header test for paths.h. - * sh.h: include paths.h if available; define DEFAULT__PATH. - * table.h(def_path): new variable. - * options.h(DEFAULT_PATH): new define. - * main.c(main): initialize value of def_path; set path to def_path; - remove PATH initalization from initsubs; do not set value of HOME - variable (POSIX); allow SHELL, PS1, PS2, PS3 to have empty values - (at&t ksh). - * var.c(unsetspec): when unsetting PATH, set path to def_path. - - * jobs.c(j_waitj): restore proc mask before calling error if - 1st tcsetpgrp() fails. - -Thu Sep 1 10:28:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * Makefile.in: added check-sig.c, check-fd.c and check-pgrp.c - to RCSFILES; added rules for compiling the above; added debugtools - target to compile them all. - - * c_test.c(arg0,t_error,T_ERR_EXIT): new variables/defines. - * c_test.c(c_test): set arg0 to wp[0], t_error to 0; after - calling eval_binop() or oexpr() check t_error and if set, - return T_ERR_EXIT. - * c_test.c(syntax): set t_error exit; use shellf() instead of - errorf(); use arg0 instead of "test"; delete GCC_FA_NORETURN - attribute; changed all calls to return after calling. - * c_test.c(oexpr,aexpr,primary): check terror after calling - oexpr(), aexpr(), nexpr(). - - * c_test.c(primary): if unary operator is -t and there is no - argument, don't increment t_wp; if missing closing parenthesis, - show next operand (if any) in error message. - * c_test.c(eval_unop): default case, print t_wp[-2] (was -1). - * c_test.c(c_test): set t_wp before calling eval_binop() incase - there is an erorr. - * c_test.c(syntax): print first message even if op is an empty string. - -Wed Aug 31 11:48:51 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * expr.c(O_LT, O_GT): reverse order of enums to match opinfo table. - - * c_test.c(nexpr): always call !nexpr() (never !primary()). - * c_test.c(c_test): switch on argc-1 to make code match POSIX - description; make 4 arg case fall into 3 arg case, and 3 arg case - fall into 2 arg case. - * c_test.c(is_not,is_and,is_or): new defines. - * c_test.c(c_test,oexpr,aexpr,nexpr): use is_not,is_and and is_or. - * c_test.c(primary): don't decrement t_wp in final string case. - - * c_test.c(eval_unop): change S_ISIFO to S_ISFIFO and S_ISFITO - to S_ISFIFO. - - * misc.c(parse_args): use OF_SET when initializing set_opts. - -Wed Aug 31 09:32:39 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * made pdksh-5.0.4 distribution - - * jobs.c(j_change): do not restore tty process group when turning - off job control; no need to save original tty process group; - deleted orig_ttypgrp variable. (fixes bug in which turning off - job control causes an interactive shell to exit) - -Tue Aug 30 14:43:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(KSH_OPENDIR_CHECK): always include sys/types.h; - set return value according to what failed. - -Tue Aug 30 11:17:09 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * missing.c(strerror): for systems without sys_errlist[], report - error number if unknown. - - * Makefile.in: added BUG-REPORTS to DISTFILES. - - * jobs.c(exchild): do tcsetpgrp() in both parent and child after - the first process is created (may need to change to every child). - - * aclocal.m4(KSH_PGRP_SYNC): new test - defines NEED_PGRP_SYNC. - * acconfig.h: added define for NEED_PGRP_SYNC. - * configure.in: use KSH_PGRP_SYNC test. - * jobs.c(exchild,j_startjob,j_sync_open,j_sync_pipe): if NEED_PGRP_SYNC - is defined, use a pipe to block the first process in a pipeline - until the whole pipeline is set up. - -Mon Aug 29 09:15:00 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * jobs.c(exchild): for background, unmonitored jobs, don't open - /dev/null if input is a pipe. - - * jobs.c(exchild): for background, unmonitored jobs, use setsig() - instead of setexecsig() to set up SIGQUIT and SIGINT; changed - restoration of SIGTSTP,SIGTTIN,SIGTTOU - set them to DFL if - monitoring and not a `..` command, otherwise leave them alone. - * jobs.c(j_init): only use SIGTSTP,SIGTTIN,SIGTTOU if talking - or monitoring - if just talking leave signals ignored. - * jobs.c(j_change): if going into job control, set TF_SHELL_USES - flag for sigtraps[SIGTSTP,SIGTTIN,SIGTTOU]; if leaving job control - ignore signals if interactive, else restore original signals. - - * table.h(SPEC_BI, REG_BI): new defines. - * exec.c(builtin): check for * or + in front of builtin names and set - SPEC_BI or REG_BI if found. - * exec.c(findcom): search for special builtins first, then functions, - then regular builtins, then PATH search. - * c_sh.c(shbuiltins[]),c_ksh(kshbuiltins[]): add */+ in front of POSIX - special/regular builtins; add = infront of unset; - remove = from alias. - * c_sh.c(c_label): set exit value according to name (for true/false). - * c_sh.c(shbuiltins[]): add entries for true and false. - * main.c(initcoms[]): deleted true/false aliases. - - * aclocal.m4(KSH_OPENDIR_CHECK): new test - see if opendir() will - open non-directories. - * configure.in,acconfig.h: added KSH_OPENDIR_CHECK. - * missing.c,ksh_dir.h(ksh_opendir): new define/function. - * eval.c(globit),emacs.c(compl_file): use ksh_opendir() instead of - opendir(). - - * main.c(include): save source filename since search() uses line[] - for the filename and shell() trashes line[]. - - * table.h(FINUSE,FDELETE) new defines. - * exec.c(execute): case CFUNC: re-arranged code so normal return goes - through setjmp() switch; use FDELETE/FINUSE flags to avoid problems - with a function being undefined or redefined during its execution. - * exec.c(define): if FINUSE is set, set FDELETED and find a new table - entry. - -Fri Aug 26 21:58:25 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.c(getsc_): flush output after write when echoing. - - * Makefile.in(dist): after creating distrubution, use pathchk -p - to check file names. - -Fri Aug 26 10:28:20 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * made pdksh-5.0.3 distribution - - * expr.c(IS_ASSIGNOP): new define. - * expr.c(evalexpr): use IS_ASSIGNOP (bug fix). - - * exec.c(execute): case TFOR,TSELECT: change e->type just - before setjmp() to avoid problems with bad jmpbufs. - - * jobs.c(startlast): new function. - * jobs.c(waitlast): print error if job not started. - * eval.c(comsub): call startlast() after execute(). - * jobs.c(exchild,j_startjob,j_sync_pipe): when starting a pipeline - use a pipe to ensure the first process doesn't die before - the last process is started. - - * exec.c(execute): case TFUNC: set/clear FXTRACE according to - tp->flag & TRACE, and restore old value when function completes. - - * c_test.c,exec.c,io.c,mail.c,vi.c: changed all uses of - (x&S_IFMT) == S_IF* to the equivilent S_IS* (for ISC unix). - * c_test.c(eval_unop): if system doesn't have symlinks or sockets - (S_ISLNK,S_ISSOCK), return 0 (used to cause internal error). - * ksh_stat.h(S_ISVTX): define if sys/stat.h doesn't. - - * sigaction.c(Signal,signal): ifdef'd Signal() and signal() out as - they cause header file conflicts on some systems (eg, signal() - in ISC unix); also ifdef'd out other routines not used by ksh - (ie, sigdelset, sigfillset, sigismember, sigpending). - -Thu Aug 25 11:50:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_test.c(primary): always check that *t_wp isn't 0 before using it. - - * eval.c(homedir): cache home directory values. - - * exec.c(findcom): search builtins before tracked aliases. - - * table.h(commands,taliases): changed name of commands to taliases. - - * c_ksh.c(c_unalias): changed to use ksh_getopt(); added -t and -a - options; exit with non-zero value if non-alias name unaliased - (POSIX). - - * main.c(initcoms[]): alias hash to 'alias -t -'; added autoload alias - as well; set selected comands to be tracked aliases (eg, grep, - ls, who, vi, emacs, etc.). - - * c_ksh.c(c_alias): when printing aliases, check ISSET, not DEFINED - flag (so unset tracked aliases won't cause problems); changed - to use ksh_getopt(); added -t flag; added -x flag (does nothing). - * c_ksh.c(c_hash): deleted function; removed all references. - - * table.h(CTALIAS): new define. - * exec.c(findcom): added search argument for whence -p; fixed - introduced bug preventing tracking of commands when insert set; - changed all calls; when creating tracked aliases, set type to CTALIAS - (was CEXEC). - * exec.c(findcom,flushcom): when freeing old tracked aliases, use - APERM, not commands.areap. - * c_ksh.c(c_whence): changed to use ksh_getopt(); assume findcom() - never returns 0 and never returns tp->type == CNONE; made output - closer to at&t ksh output; combined vflag/!vflag switch statements; - added case for CTALIAS. - * exec.c(findcom): set tracked alias type to CTALIAS. - - * c_ksh.c(c_print): added -s option; changed to use Xstring() routines - and write() instead of shf routines; returns non-zero if there - was a write error. - - * jobs.c(struct job): changed pid_t lpid field to Proc *last_proc; - changed all uses. - * jobs.c(check_job): use j->last_proc instead of lp. - * jobs.c(j_waitj): when checking for fake ^C, test j->last_proc - status to see if it was signaled and use WTERMSIG to get signal. - - * main.c: initialize integer TMOUT parameter to 0; call alarm_init() - if FTALKING. - * trap.c(alarm_init,alarm_catcher): new functions. - * trap.c(runtraps): if ksh_tmout_leave is set, exit. - * sh.h(TMOUT_EXECUTING,TMOUT_READING,TMOUT_LEAVING,ksh_tmout, - ksh_tmout_state): new enum values/variables. - * table.h(V_TMOUT): new define. - * var.c(special,setspec,unsetspec): added V_TMOUT entry. - * edit.c(x_getc): call intrcheck() if read interrupted. - -Thu Aug 25 09:36:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_test.c(c_test): for argc cases 4 and 5, return the complement - of the expressioin result; for [[ .. ]] expressions, don't parse - based on argc; deleted struct t_op.op_flags field and related - defines UNOP,BINOP,ACCEPT_BE,ISTEST,ISDBRACKET,ISBOTH - changed all - uses to test the value of isdbracket. - * c_test.c(filstat): moved body of filstat() into eval_unop(), deleted - filstat(). - - * c_test.c: incorperated changes from J.T. Conlin (jtc@cygnus.com) - for POSIXization of test builtin. - -Wed Aug 24 12:16:25 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * new-version.sh: new file - updates date in version.c - * Makefile.in: added new-version.sh to RCSFILES; call new-version.sh - in dist: target. - -Tue Aug 23 09:28:10 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * made pdksh-5.0.2 distribution - - * jobs.c(exchild): don't call restoresigs(). - * exec.c(execute): do call restoresigs() (just before execve()). - - * c_sh.c(c_trap): ifdef'd out code to print default traps. Too ugly - and it isn't clear POSIX needs it. - - * c_ksh.c(c_print): put -e option back in for echo emulation (-R). - - * c_sh.c(c_shift): generate error if n < 0. - - * c_sh.c(c_trap): use shellf instead of errorf to report errors - (so we can return a value instead of unwinding - POSIX). - - * exec.c(execute): if command fails and !FERREXIT, call - trapsig(SIGERR_). - - * c_sh.c(c_exit,c_return,c_exitreturn): combined c_exit and c_return - functions. - -Mon Aug 22 09:39:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * eval.c(expand): case XARG: set word to IFS_WORD to force null - words to be created. - - * lex.c(yylex): added indquotes flag and code for `...` parsing - (to deal with "`...`" the way sh/at&t-ksh does). - - * trap.c(runtrap): don't reset ERR trap. - - * sh.h: combnied SS_USER/SS_FORCE flags with RESTORE_CURR et. al. - flags; changed RESTORE_* to SS_RESTORE_*. - * trap.c(setsig): combined restore, force and user flags; changed - all calls. - * trap.c(setexecsig): use SS_RESTORE_* values as argument. - - * table.h: changed LCASE to LCASEV (and UCASE_AL to UCASEV_AL) to - avoid problems with ioctl/tty LCASE define. - - * sh.h(struct env): deleted interactive field. - * main.c(shell),exec.c(iopsetup): deleted e->interactive assignment. - - * sh.h: made e a struct env * (was struct env); changed all references. - * main.c(newenv): copy loc, flags and interactive fields explicitly. - - * var.c(newblock): allocate block structure, don't assume already - exists. - * var.c(popblock): free old block structure. - * main.c(main): set e->loc to 0 before calling newblock(). - * exec.c(comexec): let newblock() allocate new structure; deleted - l variable (changed references to e->loc). - * table.h: deleted globals variable. - - * c_ksh.c(c_print): treat a lone - like --. - - * main.c(main),trap.c(inittraps): move SIGINT,SIGQUIT,SIGTERM signal - initialization to inittraps() and do it regardless of FTALKING. - - * trap.c(settrap): deleted force trap since probably will never - add -f flag to trap. - - * main.c(unwind): if we are dieing of SIGINT or SIGTERM, kill - ourselves with a signal. - - * vi.c(x_vi),emacs(x_emacs): if ^C read, call trapsig()/runtraps(); - don't return -2. - * edit.c(x_read): don't check for -2 return value. - * vi.c(x_vi): check for quit char (^\) and fake SIGQUIT. - - * exec.c(comexec): made flags argument volatile. - - * misc.c(getn_): new function. - * c_sh.c(c_exit,c_return): call quitenv() before unwind()ing; - moved c_exit() next to c_return(); use getn_() instead of getn(). - - * main.c(shell): added exit_atend argument to deal with POSIX trap exit - semantics; changed all calls. - * sh.h: added STOP_RETURN macro. - * c_sh.c(c_return): determine if we are returning or exiting before - unwind()ing so POSIX trap exit semantics are honored. - - * jobs.c(j_sigchld): call trapsig() instead of messing with sigtraps[]. - * trap.c(trapsig): don't restore signal handler if it wasn't set to - trapsig. - - * sh.h: added TF_TTY_INTR flag. - * trap.c(inittrap): set TF_TTY_INTR for SIGINT. - * jobs.c(j_waitj): if - - * jobs.c,sh.h: deleted SA_RESTART ifdefs; moved SIGCLD->SIGCHLD ifdefs - from jobs.c to sh.h. - -Sat Aug 20 15:26:24 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * sh.h: added KSH_SA_FLAGS define. - * trap.c(inittrap,setsig): set sa_flags field to KSH_SA_FLAGS. - * sigact.c(sigaction): if using BSD42_SIGNALS, set the SV_INTERRUPT - flag. - * configure.in: deleted AC_RESTARTABLE_SYSCALLS. - * config.h.bot: add error message to prevent compilation if using - BSD41 signals. - - * shf.h: added SHF_INTERRUPT flag. - * shf.c(shf_fillbuf,shf_putchar,shf_write,shf_emptybuf): call - intrcheck() if read()/write() interrupted and SHF_INTERRUPT set. - * c_sh.c(c_read): use SHF_INTERRUPT flag. - * lex.c(getsc_): call intrcheck() if read() interrupted. - - * main.c(main),trap.c(inittrap): moved Sigact* initialization - from main() to inittrap(); made Sigact_trap/Sigact_ign static; - deleted Sigact and Sigact_dfl. - * sh.h: deleted declarations of Sigact*. - - * main.c(shell): deleted sigaction call - no longer needed. - - * sh.h: added RESTORE_CURR, RESTORE_ORIG, RESTORE_DFL and RESTORE_IGN - defines. - - * trap.c(intrcheck): new function. - * trap.c(runtraps): added intr argument; clear trap/intrsig - before running traps; changed all calls. - * trap.c(runtrap): save/restore exstat when running trap. - * jobs.c(j_waitj): changed interrupt test to check intrsig - and return -1. - * jobs.c(waitfor): if j_waitj() returns -1, call intrcheck(). - * jobs.c(j_change): use setsig() instead of sigaction() to - set up SIGTTIN,SIGTTOU,SIGTSTP. - - * trap.c(inittraps): initialize flags for INT/QUIT/TERM. - * sh.h(intrsig): new variable. - * trap.c(trapsig): set intrsig if signal has TF_DFL_INTR flag set; - deleted longjmp(). - * trap.c(runtraps): clear intrsig. - * trap.c(runtrap): if signal is defaulted and TF_DFL_INTR is - set, set exstat and call unwind(); return if signal ignored; - reset an ERR trap before executing it. - * trap.c(cleartraps): deleted special case for EXIT; reset - command traps using settrap(); clear intrsig. - * trap.c(restoresigs): only deal with traps that have the TF_EXEC_IGN - flag set (others take care of themselves). - - * trap.c(sigtraps[]): added ERR trap. - * trap.c(gettrap): deleted #if 0'd ERR/EXIT check. - * trap.c(gettrap,runtrap,cleartraps,restoresigs): use SIGNAL+1 to - go through trap table. - * sh.h(SIGEXIT_,SIGERR_): new defines. - * c_kill.c(c_kill): test for signals > 128 (was >= 128) - * c_sh.c(c_trap): when printing traps, use SIGNALS+1. - - * sh.h(struct trap): replaced ourtrap and sig_dfl fields with - flags field; defined TF_SHELL_USES, etc. for flags field; added - cursig field. - * sh.h(struct env): replaced func_parse field with - flags field; defined EF_FUNC_PARSE, EF_BRKCONT_PASS for flags - field; defined STOP_BRKCONT(); changed uses of func_parse - (get_command()/readhere()). - * c_sh.c(c_brkcont): use STOP_BRKCONT(), EF_BRKCONT_PASS; call - unwind() to do the work. - -Fri Aug 19 09:59:43 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * trap.c(settrap): new function - does most of what c_trap did. - * c_sh.c(c_trap): changed to use settrap(); print out default - actions as well as caught/ignored actions. - * trap.c,c_sh.c(setsig): moved setsig from c_sh.c to trap.c and - made it static; added force and user arguments; don't do anything - for EXIT and ERR. - * main.c(main): use sigtrap() instead of ignoresig(). - * trap.c(ignoresig): deleted function. - - * exec.c(execute): case TSELECT: don't change SIGINT signal handler. - - * proto.h: use GCC_FA_NORETURN on aerror(). - * syn.c(yyparse): made function static and void. - - * exec.c(herein): changed error() calls to errorf()s; use error() - in error handler; call shf_close() instead of shf_fdclose(). - - * tree.h,sh.h: moved LBREAK/LCONTIN from tree.h to sh.h; - added LEXIT, LRETURN, LERROR, and LINTR defines; changed values - of LBREAK/LCONTIN; changed all calls to longjmp() and setjmp(). - * exec.c(execute): put Break: label after main switch, changed - goto Break[0-9] to Break; deleted Break[0-9] labels. - * exec.c(execute): changed FOR, SELECT, WHILE, DO loop setjmps - to explicitly check for LBREAK/LCONTIN, otherwise call unwind(). - * exec.c(execute): case TFUNC: added setjmp switch statement to take - care of various L* values. - * main.c(include,shell): added setjmp switch statement to take care of - various L* values. - * main.c(unwind): added L* parameter to pass on to longjmp(); - changed all calls. - * c_sh.c(c_return): just call unwind(LRETURN); - * main.c(unwind): put code from leave() in E_NONE case. - * main.c(error,leave): deleted functions; replace all calls with - unwind(LLEAVE or LERROR). - * *.c(longjmp): replaced all calls with unwind(L..) (except the - call in unwind()). - - * shf.h: add areap field to struct shf. - * shf.c(shf_fdopen,shf_sopen): initialize areap - * shf.c(shf_emptybuf,shf_close,shf_sclose,shf_finish): use areap - instead of ATEMP. - - * shf.c(shf_sopen): if buf is 0 and writing and DYNMAIC, allocate - a buffer; if writing, save room for a trailing null. - * shf.c(shf_sclose): new function. - * shf.c(shf_snprintf),tree.c(snptreef): use shf_sclose(). - * tree.c(snptreef): changed return type to char *; if buffer - is null, pass SHF_DYNAMIC to shf_sopen(); return (possibly - allocated) string. - * syn.c(syntaxerr): use snptreef() instead of ident. - - * tree.h: new define TDBRACKET; new defines DB_NORM,DB_OR,DB_AND, - DB_BE,DB_PAT. - * tree.c(ptree): added case for TDBRACKET. - * syn.c(get_command): case DBRACKET: make TDBRACKET command; - at end of function, null terminate args/vars if TDBRACKET. - * c_test.c(is_db_patop): new function. - * syn.c(db_primary): set type of arg to DB_PAT if is_db_patop() - returns true. - * exec.c(execute): added case for TDBRACKET. - - * syn.c(get_command): case MDPAREN: make arg[0] an allocated stuffed - string (was a literal string). - -Thu Aug 18 11:06:49 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_test.c(is_op,is_binop,is_unop): new functions to test for - unary/binary operators. - * c_test.c(oexpr,aexpr,nexpr,primary): no longer take argument - - call is_unop/is_binop directly. - * c_test.c(ISDBRACKET,ISTEST,ISBOTH,ACCEPT_BE): new defines. - * c_test.c(struct t_op): changed op_type field to op_flags. - * c_test.c(ops[]): broke into two arrays: u_ops and b_ops; - set flag field to ISDBRACKET/ISTEST/ISBOTH as appropriate. - * c_test.c(t_lex): deleted function. - * c_test.c(primary): before checking for unary operator, check - for -BE (binary expression next) if appropriate. - - * c_test.c: made operator type an enum to make it easier to add - operators; changed oexpr/aexpr/nexpr/primary/filstat/t_lex - operand/return types. - * c_test.c(struct t_op): changed op_text from char * to char [4]. - * c_test.c(primary): case FILTT: using digit(**t_wp) causes core dump - when there is no arg - just test if *t_wp is 0; move test into - filstat(). - * c_test.c(primary): use *opnd1 != 0 instead of strlen(opnd1) (3 - instances). - - * tree.c(wdscan,wdcopy): changed string argument to const; changed - return type of wdscan to const. - - * eval.c(expand): case CSUBST: case '?': use st->var->anme instead - of cp to allow proper nesting. - * eval.c(expand): case OSUBST: don't change cp - declare local - variable. - * eval.c(expand): case COMSUB: deleted Xsavepos() call; XCOM: deleted - Xrestpos() call. - * eval.c(expand): save the position of the first unquoted = for tilde - expansion. - * eval.c(expand): case '~': use sp == (cp+2) instead of dp == Xstring - so we aren't fooled by ''~ or ${foo}~; sp[-1]/sp[-2] and firsteq - for the DOASNTILDE after first = or unquoted : test. - - * tree.h(struct op): changed noexpand field to evalflags; changed - all uses. - * exec.c(execute): if t->evalflags is non-zero, pass them to eval(). - - * lex.h: added DBRACKET define for [[ keyword. - * syn.c(get_command): added case for DBRACKET. - * syn.c(db_parse,db_oaexpr,db_nexpr,db_primary): new functions - to parse [[ .. ]] expressions. - * syn.c(tokentab[]): added [[/DBRACKET keyword. - * c_test.c(is_db_unop,is_db_binop): new functions to test if arg - is [[ .. ]] unary/binary operator. - - * syn.c(syntaxerr): call REJECT; before token; removed REJECT - before all calls to syntaxerr(). - * syn.c(get_command): removed syntax error kludge. - -Wed Aug 17 11:07:40 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca) - - * c_test.c(struct ops): changed -U to -O. - - * tree.h: added new defined DOASNTILDE. - * eval.c(expand): case '~': changed !(f&DOBLANK) to f&DOASNTILDE. - * exec.c(execute): case TCOM: pass DOASNTILDE when evaluating vars - and when expanding args when t->noexpand is set. - - * exec.c(execute): case TCASE: pass DOTILDE to both evalstr() calls - (POSIX). - - * syn.c(get_command): don't check for redirections before determining - command type; handle REDIR where LWORD are handled; default case - always returns; pass ARRAYVAR flag to tpeek() if t->noexpand; - don't allow redirections before "x()" function; don't allow - redirection before keywords; allow a '(' in the case LWORD/REDIR: - if no variables or arguments (POSIX doesn't allow this, but - at&t ksh/bourne sh do). - * lex.h(ARRAYVAR): new define. - * lex.c(yylex): parse x[1 & 2] as one word if VARASN|ARRAYVAR. - - * var.c(is_wdvarname): added aok argument; changed all calls. - * syn.c(get_command): case FOR/SELECT: check identifier is valid. - - * c_sh.c(c_trap): use print_value_quoted() to print traps; - use ksh_getopt() to skip possible --. - * trap.c(gettrap): allow digits only if signal numbers match - POSIX values (ie, HUP=1,INT=2,QUIT=3,ABRT=6,KILL=9,ALRM=14,TERM=15). - - * misc.c(print_value_quoted): new function to print strings with - appropriate quoting. - * c_ksh.c(c_typeset,c_alias): use print_value_quoted() when printing - values. - - * lex.h: added new ESACONLY flag - only accept ESAC keyword. - * lex.c(yylex): check for ESACONLY flag when doing keyword search. - * syn.c(caselist): pass ESACONLY flag to tpeek(). - -Tue Aug 16 10:17:47 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.h(struct source); changed echo field to generic flags field; - defined SF_ECHO and SF_ALIASEND. - * lex.c(_getsc): case SALIAS: use isspace() to check for trailing - space in alias; if alias does not end in a space, return a fake - space to keep the current alias in the source list - this allows - recursive alias detection; set SF_ALIAS in next source if alias - does end if space. - * lex.c(yylex): deleted expanding_alias, rec_alias_cnt and - rec_alias_table variables; check for recursive aliases by checking - the source list; don't use EXPALIAS flag; if SF_ALIAS is set in - current source, set ALIAS flag and clear SF_ALAIS; deleted global - alias variable. - * table.h: deleted EXPALIAS define. - * main.c(shell): changed s->echo to set/clr of SF_ECHO in s->flags. - - * table.h: added aliases and keywords tables; deleted lexicals table - (POSIX says they are seperate). - * syn.c(keywords,initkeywords): changed name of keywords() function - to initkeywords(); changed all calls; add to keywords table instead - of lexicals table. - * main.c(main): initialized aliases/keywords tables; deleted - initialization of lexicals table. - * c_ksh.c(c_whence,c_alias,c_unalias),lex.c(yylex): use - keywords/aliases tables instead of lexicals table; removed unneeded - type == CALIAS checks. - - * var.c(getint): new function, largely take from strint(). - * var.c(strint): call getint() to do most of the work; if vq - was an allocated string, free the string and clear the alloc - flag. - * var.c(intval): call getint() instead of strint(). - - * mail.c(mcheck): use getint() instead of strint() when getting - value of MAILCHECK. - - * var.c(skip_varname): added argument to allow array references; - changed all calls. - * var.c(set_array): remove valid variable name check - done in - parse_args(). - - * var.c(strint): check if getspec()/setspec() need to be called. - * var.c(intval): remove getspec()/INTEGER checks - let strint() do it. - - * var.c(skip_wdvarname,is_wdvarname,is_wdvarassign): new - functions. - * lex.h(VARASN): new define indicating variable assignment expected, - currently used to parse "x[1 & 2]" as one token - may be used - in future in returning AWORD (assignment word) to the parser. - * lex.c(yylex): Subst: case '[': use is_wdvarname() in determining - whether to parse an array dereference; do not require an = after the - dereference (typeset -r x[1 & 2] is legal). - * syn.c(many functions): pass VARASN to token/musthave/tpeek/synio - when ever the next token might be the first word of a simple - command. - * syn.c(get_command): case LWORD: use is_wdvarassign() to distinguish - variable assignments from normal arguments; allow aliases after - redirections and variable assignments; generate syntax error - for "foo=bar bogusfunction()"; allow array variables in for - and select statements. - * lex.c: make global alias variable static (no longer used by - get_command()). - - * syn.c(get_command): put MDPAREN into its own case. - - * lex.c(yylex): deleted place holder for tilde expansion. - - * tree.h(struct tree): added noexpand field for - alias/export/readonly/typeset. - * syn.c(newtp),tree.c(tcopy): initialize/copy noexpand field. - * syn.c(get_command): case LWORD: set noexpand if assign_command() - returns true. - * syn.c(assign_command): new function - returns true if command - is alias, export, readonly or typeset. - * exec.c(execute): case TCOM: don't pass DOTILDE flag when - expanding t->vars; don't do field splitting/globbing/tilde expansion - of t->args if t->noexpand is set. - - * table.h: re-grouped the struct tbl flags into common, variable, - funtion, builtin/alias, etc (some values overlap); new flag - names: KEEPASN (was overloaded with TRACE) and NOEXPAND. - * exec.c(comexec,builtin): changed TRACE to KEEPASN. - - * tree.c(tcopy): when copying t->str, use strsave(), not wdcopy() - if not copying a TCASE. - - * c_ksh.c(c_typeset): added -p flag for POSIX export/readonly. - - * eval.c(expand): expand tilde in place; don't do tilde expansion - on results of substitution (POSIX); only do tilde expansion - if login name is unquoted (POSIX); don't check for fdo&DOTILDE - when a word is completed. - * eval.c(tilde): changed to return home directory of a given login name - (taking care of null/+/-) (old version copied string, scanning - for, and replacing, magic tildes). - - * exec.c(findcom): don't create commands table entries when - not inserting; when doing access test of tracked alias, - check for ISSET, not ALLOC (but test ALLOC before calling afree). - * exec.c(search): use strcpy() instead of loop. - -Mon Aug 15 14:46:58 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_print): added at&t ksh -R flag; deleted -e flag; - changed to use ksh_getopt(). - * main.c(initcoms[]): changed echo alias from 'print -' to 'print -R'. - - * sh.h: new variable procpid; added pid field to struct temp. - * jobs.c: changed references to my_pid to procpid; deleted my_pid - variable. - * io.c(maketemp): initialize pid field from procpid. - * main.c(remove_temps): only remove temporary files created by - the current process. - -Sun Aug 14 11:47:05 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c: added var field to struct Expand and struct SubType; deleted - struct SubType.name field. - * var.c(expand): case OSUBST: use x.var/st->var field to save result - of global() for use in case CSUBST - this avoids problems with - x[i+=1] being evaluated twice; check to see if value is being - assigned to non-variable (eg, ${*:=aja}) or read-only variable. - * var.c(varsub): set value of xp->var; possibly generate error if - FNOUNSET set when expanding ${#*}, ${#var}, or ${#array[*]}. - - * table.h: added struct tbl.areap field to get rid of lastarea - problems; deleted lastarea variable; changted all refernces - to lastarea to var->areap. - * table.c(tenter): initialize areap field. - * var.c(arraysearch): deleted area parameter; initialize areap field. - * var.c(global,local,intval,setint): initialize areap field of vtemp. - -Fri Aug 12 10:54:51 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * expr.c: re-wrote e*() functions using single function and table; - token() now does table lookup; added full C expressions (sans - pre/post increment, sizeof). - - * table.h(INT_U,INT_L): new flags. - * var.c(strval): handle INT_U. - * c_ksh.c(c_typeset): add exclusions for INT_U/INT_L; - add -U option for unsigned (non-at&t ksh). - - * var.c(set_array): use global() instead of local(); - - * var.c(global): when parsing $123, don't limit number to 1000. - - * expr.c(v_evaluate): like old evaluate, but assigns result to - specified variable. - * expr.c(evaluate): changed to use v_evaluate(). - * expr.c(e0): when parsing literals, use strint() instead of setstr(). - - * var.c(setstr): when assigning to integers, use v_evaluate() instead - of strint(). - -Thu Aug 11 11:33:17 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(strint): don't change anything until number completely - parsed; don't clear ISSET flag if parsing fails; fail parse - if non-integer/non-letter found; default base if copying from - integer variable; set ISSET if parsing succeeds. - - * expr.c(tempvar): set vp->val.i to 0. - * expr.c(token): when skipping a literal number, don't allow _; - use isspace() to skip. - * expr.c(asn): use strint()/setstr() instead of setint(). - * expr.c(e0): added unary ~ and + (posix). - - * var.c(global,local): always call substitute on contents of [..]; - free sub when finished eval. - - * ksh_limval.h: new file. - * shf.c: use ksh_limval.h. - * Makefile.in: added ksh_limval.h to HDRS. - -Wed Aug 10 10:57:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_whence): case CFUNC: print exported/traced/undefined, - do not print function definition. - * exec.c(findcom): new argument indicated if functions to be - autoloaded; changed all calls. - - * misc.c(ksh_getopt): added # option modifier for typeset. - * c_ksh.c(c_typeset): changed to use ksh_getopt(); added - -L, -R, -Z, -l, -u flags; quote variable values when printing; - generally re-arranged function. - * table.h: added LJUST,RJUST,ZEROFIL,LCASE,RCASE; deleted FUNCT. - * exec.c(findfunc): new function. - * exec.c(define,findcom): use findfunc(); skeleton autoload code. - * var.c(typeset): added two arguments for initial field width and - base; changed all calls; deal with LJUST,.. flags; re-arrange to - have one loop iterating over array; do readonly check before - changing attributes. - * var.c(strval): deal with LJUST,.. flags when getting integers. - * var.c(setstr): deal with LJUST,.. flags when setting strings. - * var.c(setstr): deal with LJUST,.. flags when setting strings. - * var.c(arraysearch,tenter): initialize {new,p}->field to 0. - * table.h: added struct tbl.field. - - * siglist.in: changed signal messages to be more or less the - same as sys_siglist[]; moved SIGUNUSED before SIGBUS. - * jobs.c(j_print): assume sigtrap[].mess always valid; use - sigtrap[].mess directly for stopped processes. - - * aclocal.m4(KSH_SYS_SIGLIST): new macro like KSH_SYS_ERRLIST. - * configure.in: use KSH_SYS_SIGLIST instead of AC_SYS_SIGLIST_DECLARED. - -Tue Aug 9 10:28:45 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * version.c: removed RCS logs since version numbers don't match - release numbers. - - * configure.in: added AC_PROG_CPP - * Makefile.in: added rules for generating siglist.out - * siglist.in,siglist.sh: new files. - * trap.c(inittraps,deftraps[]): deleted deftraps[]; initialize - sigtraps[] directly by including siglist.out. - - * tree.h: added EXPRSUB for $((..)), re-numbered defines. - * tree.c(tputS,wdscan): added case for EXPRSUB. - * eval.c(expand,alt_count,alt_scan): added case for EXPRSUB. - * lex.h: added SDDPAREN for $((..)). - * lex.c(yylex): added case for SDDPAREN. - - * lex.c(yylex): case SPAREN: match parenthesis using counter instead - of pushing/poping states. - - * lex.h: re-numbered S* defines to be sequential; added SREREAD. - * lex.c(yyerror): pop SREREADs. - * lex.c(getsc_): added case for SREREAD. - * lex.c(arraysub): changed to save whatever is read and return a value - indicating if brackets matched; changed all calls. - * lex.c(yylex): if brackets in array reference are not balanced, - or if array reference not followed by an =, re-read the input. - -Mon Aug 8 21:20:08 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h: fix lseek prototype (from sjg@zen.void.oz.au) - - * configure.in,jobs.c: added HAVE_SYSCONF; don't use sysconf() unless - HAVE_SYSCONF defined (for NetBSD-Feb12 from sjg@zen.void.oz.au). - - * jobs.c(put_job): removed PJ_ON_END case and define (not used). - -Wed Jul 27 10:19:42 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-5.0.1 distribution - - * exec.c(comexec): when doing exec has no command, fall through - and do variable assignments. - - * c_ksh.c(c_let): complain if there are no arguments. - - * exec.c(comexec): if XEXEC is set, exit after executing - (builtin/function) command; deleted FERREXIT code; don't set - exstat. - * exec.c(execute): handle FERREXIT; set exstat to rv for all - cases. - - * lex.c,syn.c: changed calls to errorf to yyerror (except the - on in yyerror()). - * lex.h(struct source): added errline field. - * lex.c(yyerror): now a varargs function; if source->errline field is - non-zero, print it instead of source->line. - * syn.c(syntaxerr): set source->errline if read EOF in a multiline - command. - -Tue Jul 26 11:22:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * lex.h(SYNTAXERR,INP): deleted macros. - * lex.h(HISTORY): upped to 128 as per POSIX. - * lex.h,syn.c(multiline): moved from lex.h to syn.c. - * tree.c(vfptreef): added %R to format I/O redirections. - * tree.c(pioact): don't output unit more than once; print unit - only if it isn't the default for the action; print only - one opening quote for quoted here documents; print <> for - read-write (was ><). - * syn.c(zzerr, syntaxerr): replaced zzerr function with new syntaxerr - function; changed uses of SYNTAXERR to syntaxerr() calls; print - out the last unused token; if in a multiline command when EOF - encountered, print token that was unmatched. - - * tree.h(TBANG),lex.h(BANG): for POSIX ! keyword - * tree.c(ptree),exec.c(execute): added case for TBANG. - * syn.c(restab[]): added ! keyword. - * syn.c(get_command): added case for BANG (!). - - * tree.h(XERROK): new define to allow non-zero exits to be - ignored in certian circumstances (set -e). - * exec.c(execute): pass XERROK to recursive execute() calls; set - XERROK when evaluating conditional part of if/while/until/&&/||. - * exec.c(comexec): pass XERROK on to functions; don't exit if - XERROK is set. - - * jobs.c(async_pid): new variable needed since async_job may go - away, but $! should still be expanded. - * jobs.c(j_async): return async_pid. - * jobs.c(j_set_async): set async_pid. - -Mon Jul 25 14:15:25 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(parse_args): changed to use ksh_getopt(). - - * c_sh(c_set): deleted call to resetopts() - neither POSIX nor - at&t ksh touch OPTIND when positional parameters are changed. - * exec.c(comexec): changed resetopts() call to getopts_reset(1) - this - is not a proper fix - should declare a local optind. - - * misc.c(builtin_getopt,ksh_getopt): renamed builtin_getopt to - ksh_getopt (shorter); changed to use state structure instead - of static variables; changed all calls; optionally allow + to - introduce an option; don't skip lone - (or +) in arguments - set - optind to point to it. - * misc.c(ksh_getopt_reset): changed to use state structure instead - of static variables. - * sh.h(Getopt): new structure for ksh_getopt() state. - * exec.c(call_builtin): call ksh_getopt_reset(). - * c_ksh.c(c_getopts,getopts_reset): new getopts implementation that is - POSIX complient and uses ksh_getopt() routine. - * var.c(setspec): call getopts_reset() when OPTIND set. - * getopts.c: deleted file. - * Makefile.in: deleted getopts.c and getopts.o. - * options.h(FASCIST): deleted option. - -Thu Jul 21 09:52:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-4.9+mun.5 distribution - - * syn.c(get_command),shf.c(shf_fdopen,shf_sopen,shf_emptybuf): - added cast to alloc()/aresize() calls. - * sh.h: changed enum flags_enum to enum flags. - * misc.c(change_flag): changed type of first argument to enum flag. - * edit.c(set_editmode): change type of static array to enum flag. - - * edit.c(x_init): initialize tty chars to -1, except for werase, - which is set to ^W. - * edit(x_mode): split oldedchars structure declaration and - initalization (some old compilers don't like them combined). - - * c_test.c: made -h work like -L. - -Wed Jul 20 11:12:52 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * config.h.top: moved compile options into options.h; include - options.h. - * options.h: new file. - - * c_ksh.c(c_fgbg): if !FPOSIX, set return job exit status. - - * jobs.c(j_jobs,j_notify): use JF_REMOVE to flag jobs to delete - after all notification done (to prevent multiple + or - jobs). - - * jobs.c(put_job): new funtion, takes argument to specify where - to put job; changed all calls to put_job_on_front and - put_job_on_end to use this; put background processes just - after stopped jobs (instead of at end) (POSIX). - * jobs.c(put_job_on_front,put_job_on_end): deleted. - -Tue Jul 19 10:33:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * aclocal.m4(AC_MMAP): copied from autoconf's acspecific.m4 and - modified to use the MAP_FILE flag if available. - - * misc.c(change_flag): ifdef use of FVI/FEMACS/FGMACS. - -Mon Jul 18 13:19:29 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(async): deleted. - * var.c(global): call j_async() instead of using async global. - * jobs.c(j_async,j_set_async()): new functions. - * jobs.c(j_startjob): new function. - * jobs.c(exchild,j_waitlast): call j_startjob() to start job. - * jobs.c(j_sigchld): if any jobs aren't started, note signal - occured and return without calling wait. - * jobs.c(j_resume): allow un-reported dead jobs to be fg'd/bg'd; - if backgrounding, set async job. - * jobs.c(j_jobs,j_notify,j_waitj,check_job,remove_job): re-wrote to - deal with posix `known processes'. - * jobs.c(j_lookup()): if number specified, see if it is a lpid first, - then check for pgrp. - * jobs.c(new_job): added functionality of j_newjob(). - * jobs.c(j_newjob): deleted function and all calls. - - * tty.c(tty_init,tty_close): new functions which initialize - tty_fd, tty_state and tty_devtty. - * jobs.c(j_init,j_change): use tty_init()/tty_close(); changed - references of ttyfd to tty_fd; moved tty_fd, tty_state and - tty_devtty to tty.h; call tty_init() if !FMONITOR; save/restore - tty modes on foreground job completion if FTALKING (was FMONITOR). - * edit.h(X_chars): new structure for tty driver characters (replaces - ed_erase, ed_kill, ed_werase, ed_intr, ed_quit); moved prototypes - for emacs.c and vi.c from proto.h to edit.h; changed all references - to ed_* to edchars.*. - * edit.c(x_mode): use tty_state instead of cborig; re-initialize - tty state from tty_state whenever entering xmode; save tty characters - in edchars structure. - * edit.c(x_init): now called from main(); initializes edchars, x_cols, - and calls x_init_emacs. - * emacs.c(x_init_emacs): changed erase,kill,werase,intr,quit arguments - to X_chars argument. - -Fri Jul 15 10:35:13 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * io.c(restfd): only flush if fd is 2; use dup2() instead of - fcntl(F_DUPFD) (2 system calls instead of 3). - - * ksh_wait.h(WEXITSTATUS): changed mask from 0x7f to 0xff. - - * tty.h: added TTY_state structure. - * tty.c: new file - contains get_tty() and set_tty(). - * edit.c(x_init,x_mode): use get_tty() and set_tty(). - * jobs.c(j_waitj,j_resume): save/restore tty modes of stopped - jobs, as per POSIX.1, B.2, job control; for foreground jobs, - save tty state after successful completion, restore tty state - after non-successful completion (signaled, non-0 exit, stopped). - - * misc.c(options): changed "alternations" to "braceexpand" (this - is what bash uses - no need to invent new option names); changed - ALTERNATIONS define to BRACEEXPAND, same for FALTERNATIONS to - FBRACEEXPAND. - - * jobs.c(check_job): if process died of SIGINT or SIGPIPE, leave - job state as PEXITED (not PSIGNALLED). - * jobs.c(j_print): if printing short notice, ignore SIGPIPE the - way SIGINT is ignored. - - * exec.c(comexec): flush shl_out after 'not found' message. - - * c_ksh(c_kill): re-wrote function (again) to handle posix - options (-s, --, etc.) and posix -l output. - - * configure.in: added strcasecmp function check. - * missing.c(strcasecmp): define strcasecmp function if not available. - * trap.c(gettrap): use strcasecmp when comparing signal names. - - * var.c(global): expand $! to nothing if there haven't been any - asynchronous processes started yet. - - * misc.c(options): added posix option (set automatically if - POSIXLY_CORRECT env variable is set or if POSIXLY_CORRECT config - define is defined) - * var.c(special,setspec): added POSIXLY_CORRECT. - * config.h.top: added POSIXLY_CORRECT define. - * main.c(main): set FPOSIX if POSIXLY_CORRECT is defined. - * POSIX: new file describing what the posix flag controls. - -Thu Jul 14 10:53:15 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c,sh.h(killpg): moved killpg define to sh.h. - - * jobs.c(exchild): set async variable when starting background - processes. - * jobs.c(j_resume): print [job-num] before command when backgrounding; - print to stdout instead of stderr. - * c_ksh.c(c_fgbg): call builtin_getopt to skip possible --, complain - about unknown options. - - * jobs.c(held_sigchld): new global variable. - * jobs.c(j_sigchld): if any jobs aren't started, set held_sigchld and - return. - * jobs.c(exchild,waitlast): after setting JF_START, if held_sigchld - set, call j_sigchld(). - - * jobs.c(exchild): added/initialized ppid field to struct job; deleted - global is_child. - * jobs.c(waitfor): don't wait for a process that isn't a child of - the current process. - * jobs.c(j_exit): kill stopped jobs owned by current process only. - - * jobs.c(check_job): don't do monitor stuff for XXCOM jobs, but do - set up notification. - * jobs.c(j_waitj): added JW_NOTIFY flag to print job notification - messages. - - * jobs.c(exchild): remove !XPIPEI condition - we now close pipe so - pipeline doesn't have to call waitlast(). - * exec.c(execute): case TPIPE: no need to restore 0 or call waitlast() - since exchild() handles everything. - - * jobs.c(remove_job): set last_job to 0 if we are removing it. - * jobs.c(waitlast): check if last_job is 0. - - * jobs.c(struct job): combined started, waiting, interactive - field into flags field; added JF_* flags; changed JW_NONOTIFY - to JW_NOTIFY and changed all calls to j_waitj() to reverse - this flag. - - * jobs.c(exchild): ignore SIGTSTP, TTIN, TTOU for `command` jobs. - -Wed Jul 13 09:28:34 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(main): when checking if FMONITOR set on command line, - use 127 instead of -1 (signed vs unsigned char problem). - - * tree.h: renumbered, XEXEC, XFORK, ... and DOBLANK, DOGLOB, ... - to use bits in order (instead of 0 5 2 4...). - * jobs.c(j_init): don't set sigtrap[SIGCHLD].sig_dfl = 1 as a - forked child may be a shell that needs to trap SIGCHLD. - - * tree.h(XPCLOSE,XCCLOSE): flags for close in parent, close in child. - * jobs.c(exchild): added third argument - a file descriptor - if - flags has XPCLOSE, close fd in parent, if flags has XCCLOSE, close - in child. - * exec.c(execute): pass input side of pipe to exchild() so it can - be closed in the child. - -Tue Jul 12 10:21:57 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * main.c(main): let ignoresig() handle SIGTERM. - * jobs.c(exchild): let restoresigs handle SIGTERM. - - * lex.c(yylex): don't parse array references inside double quotes - (partial fix). - - * emacs.c(x_print): use shprintf instead of shellf so the output - of bind can be redirected. - - * trap.c(deftraps): added SIGINFO (from jconklin@netcom.com). - -Fri Jul 8 09:37:51 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-4.9+mun.4 distribution - - * Makefine.in: added $(LDSTATIC) to LDFALGS to make static - linking easier (suggested by sjg); use cp -p when creating - distributions to preserve file dates. - * configure.in: set LDSTATIC in Makefile if present in environ - when configure is run. - - * sigact.c(sigsuspend): when calling 4.2bsd sigpause, pass *mask, - not mask. - - * main.c(main): fixed up initialization of PWD (free memory, print - more informative message). - - * misc.c(getcwd): range check backwards. - - * c_sh.c(setsig): set sa_flags/sa_mask. - - * edit.c(init_editmode),main.c,proto.h: deleted function - not needed - since VISUAL/EDITOR are special. - - * lex.c(set_prompt),table.h: take out PS3. - - * c_sh.c(c_umask): handle multiple actions in symbolic mode clauses - (eg, u+r-w); handle X (eg, o+X); ignore s (eg, u+s). - - * shf.c(shf_fillbuf): continue reading if we get an EINTR. - * shf.c(shf_emptybuf,shf_write,shf_putchar): continue writing if we - get an EINTR. - -Thu Jul 7 10:19:24 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sigaction,sigprocmask: changed NULL third argument to - (struct sigaction *) 0. - * sh.h(kshpid): changed type from int to pid_t. - * proto.h(do_ulimit): removed do_ulimit() declaration. - * vi.c(complete_word): removed unused variable pos. - * syn.c(pipeline,elsepart): removed unused variable c. - * jobs.c(exchild): deleted variable s (assigned but not used). - * history(hist_init),shf.c(shf_gets): changed variable e to end - because there is a global e. - * exec.c(do_selectargs): removed secondarg argument; changed return - (char *) 1 to (char *) 0; changed all calls. - - * io.c(canseek): use fd argument instead of 0. - - * lex.c(readhere): don't use fixed sized buffer (line). - - * expand.h: changed multi-statement macros to use do {..} while (0); - changed temporary variable vp to vp__ to avoid lint complaints. - - * aclocal.m4(KSH_DUP2_CHECK): define F_GETFD/F_SETFD if not - already defined. - - * etc/profile, etc/ksh.kshrc: replaced with new versions from - Simon J. Gerraty (sjg@zen.void.oz.au). - -Wed Jul 6 10:09:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(killpg),configure.in: restored use of killpg() - some - systems don't understand kill(-pgrp, signal) (ultrix 2.2); - added test for killpg() in configure.in. - - * trap.c(inittraps): changed initialization of sigtraps - was - using -1 in deftraps[] as end of table marker but some systems - (eg, ultrix 2.2) define signals with -1 values (SIGPWR). - - * Makefile.in(mandir,install): fixed mandir value; added / - in man installation; prefixed ksh.1 with $(srcdir). - - * jobs.c(j_init): Ignore failure of TIOCSETD. - - * misc.c(options[]): changed "vicomplete" to "vitabcomplete". - - * emacs.c(x_e_putc,x_e_puts,x_debug_info): x_e_putc()/x_e_puts() are - the x_putc()/x_puts() functions from ksh4.9 edit.c (they got lost - in the merge); same for x_debug_info(); changed x_e_putc/x_e_puts - to call x_putc/x_puts. - -Mon Jul 4 09:29:05 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-4.9+mun.3 distribution - - * main.c(remove_temps): use unlink() instead of remove(); delete - remove() define. - - * sh.h(func_heredocs, struct env): added func_heredocs for here - documents in functions; added func_parse field to struct env - - set when a function is being parsed. - * lex.c(readhere): if e.func_parse, save temp file in func_heredocs. - * syn.c(get_command): increment/decrement func_parse when parsing - functions. - * main.c(remove_temps,reclaim,leave): added remove_temps(); make - reclaim() call remove_temps(); make leave() clean up function - here documents. - - * aclocal.m4(KSH_TIMES_CHECK): new test - define TIMES_BROKEN - if times() doesn't exist or if it always returns 0. - * acconfig.h(TIMES_BROKEN): new define. - * missing.c(ksh_times): new function. - * ksh_times.h: new file. - * c_sh.c,jobs.c: changed <sys/times.h> to "ksh_times.h" - * c_sh.c,ksh_time.h(CLK_TCK): moved CLK_TCK define from c_sh.c - to ksh_time.h (needed in missing.c). - - * syn.c(get_command): case TIME: don't call pipeline() with CONTIN - flag. - - * c_sh.c(c_times): combined some printfs(). - - * jobs.c(j_jobs,j_kill,j_resume,waitfor): block SIGCHLD before - calling j_lookup() or looking at jobs list - avoids potential - problems with remove_job() being called in signal handler. - -Sun Jul 3 11:09:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * exec.c(do_selectargs, selread, pr_menu): re-wrote do_selectargs to - let c_read() to most of the work; deleted selread; make pr_menu - calculate width/ncolumns each call so select can be used recursively. - - * configure.in, aclocal.m4(KSH_TERMIOS_H, KSH_TERM_CHECK): replaced - KSH_TERMIOS_H with KSH_TERM_CHECK; removed calls to - tcgetpgrp/tcsetpgrp - there is a seperate test for this. - - * main.c(main), sh.h: move getcwd() declaration to sh.h. - - * eval.c(expand,varsub): added XNULLSUB case to deal with "$@" - (and "${foo[@]}") when $# (or ${#foo}) is 0. - - * eval.c(expand,varsub): removed free_me field - let reclaim() take - care of it. - -Wed Mar 9 00:50:12 1994 Simon J. Gerraty (sjg@zen.void.oz.au) - - * var.c (setstr): don't set ALLOC flag if vp.s is NULL. - -Thu Jun 30 10:16:44 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_sh.c(c_read): ignore null characters; use builtin_getopt() - instead of explicit parsing; removed -e option (neither at&t ksh - nor POSIX have this); added -s option (put line in history, at&t ksh); - if no variable specified, use REPLY (at&t ksh). - - * exec.c(do_selectargs): use Xstring macros to deal with saving - input (was static, growing, buffers); flush shl_out after - shellf(). - - * vi.c(expand_word,complete_word): deleted call to free_edstate - since already done by restore_edstate(). - * var.c(global): in 'if !letter(c)' block, deleted !c from - 'if (!c || !n[1])' - don't know why it was added since it makes - no difference to what is returned. - - * syn.c(dogroup): removed onlydone argument since it is only - used in the while/until statements, where "while command; done" - is not allowed anyway; Changed all calls. - - * misc.c(options[]): allow -i to be specified on the command - line. - - * exec.c(iosetup): if stderr (fd 2) is being re-directed, - re-open shl_out to clear any errors. - * main.c(quitenv): if restoring fd 2, clear any write errors - * io.c(initio): initialize shl_out, shl_spare for writing - (was SHF_GETFL). - - * main.c(main): ignore SIGQUIT if talking. - -Wed Jun 29 11:11:34 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_sh.c(c_exit): removed jobs/really quit stuff - exit should - always exit. - * main.c(shell): made reallyquit a local variable. - * sh.h(reallyquit): deleted reallyquit - - * exec.c(comexec), main.c(main), misc.c(change_flag), jobs.c: - ifdef'd use of FMONITOR. - * sh.h, misc.c: define FMONITOR option only if JOBS defined. - - * c_sh.c(c_wait): POSIXized: option parsing (of no options); - return 0 if not given any arguments; deal with multiple arguments. - * jobs.c(j_lookup): changed second argument to return an integer - error code, added defines for error codes, added error message - array; changed all calls to use new conventions. - * jobs.c(waitfor): returns -1 if job not found; added argument - to specify if notification messages should be suppressed. - * jobs.c(j_waitj): added flags argument instead of intr argument; - added JW_STOPPEDWAIT flag to wait for stopped jobs to complete; - added JW_NONOTIFY flag to suppress notification of normal - job termination. - -Tue Jun 28 16:13:10 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ksh.c(c_jobs): added -n and -p options, allow job ids to be - specified for -l option. - * jobs.c(j_jobs): added new arguments to deal with -n and -p options. - - * shf.h(SHF_BSIZE): reduced size to 512 to reduce memory requirements - (I/O is used mostly for one line messages). - - * config.h.bot: removed necessity for tty process groups to define - JOBS, added necessity of signal blocking/pausing. - -Mon Jun 27 21:49:52 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * jobs.c(exchild,j_print,j_waitj,j_jobs,check_job): exchild() - removed - commented out shf_flush() calls; j_print() - print a space between - status reports when lflag < 0, changed flag argument to use - long/medium/short defines; Changed Job.notify field to use - long/medium/short defines; j_waitj() - instead of calling j_print(), - set j->notify to print the job; j_jobs() - clear j->notify so user - won't be notified twice if a job finishes before a jobs command; - check_job() - put job on front of list only if it is stopped. - - * main.c(main): pass flag to j_init() indicating if -m flag set/cleared - on command line; don't initialize ttyfd. - * sh.h: delete ttyfd. - * jobs.c(j_init,ttyfd,check_job): made ttyfd static; re-worked j_init() - to initialize ttyfd, initialize FMONITOR if not set by command line, - initialize shl_j for asynchronous job notification; - check_job() - use shl_j, look through saved fds to find real - standard-error. - - * jobs.c(TTY_PGRP, ttypgrps_ok): modified conditions so job control - is useful without tty process groups; added ttypgrps_ok flag that - indicates if tty process groups should be set up; modifications so - job control useful if ttypgrps_ok not set. - - * main.c(main): set FTALKING if 0 and 2 are tty as specified in POSIX - (was 0 and 1). - - * misc.c(parse_args): do POSIX option processing for -A, -c and -o - (allow -onoglob, -ctrue). - * main.c(main): don't set up shl_stdout before/after parse_args() since - lone -o on command line no longer accepted; remove code to allow - -c with no options to read from stdin (at&t khs does this but POSIX - requires an option to -c). - -Thu Jun 23 17:46:54 NDT 1994 John Rochester (jr@panda.cs.mun.ca) - - * trap.c(cleartraps): added special case for clearing trap 0 from - ksh-4.9 sources. - -Thu Jun 23 10:17:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(builtin_getopt): print error messages for unknown option, - missing option; reset state if argv is 0. - * c_ulimit.c(c_ulimit): let builtin_getopt() print error messages. - * exec.c(call_builtin): call builtin_getopt() with 0 argv. - - * c_sh.c(c_unset): added -v option (POSIX); use builtin_getopt() to - parse arguments; removed bogus comment about global() and special - variables; don't allow read-only variables to be unset (POSIX). - - * var.c(unset, unsetspec): when unsetting a special variable, call - unsetspec(); unsetspec() new function. - * mail.c(mbset, mcheck): check that path is not 0 before calling stat - (so mbset() can be called with 0 when MAIL is unset); deleted #if 0'd - declarations of munset, mballoc and maddmsg. - - * misc.c(parse_args): pass argv+i+1 to set_array (not argv+i); when - skipping arguments, leave i just before the NULL. - - * exec.c(echo): flush shl_out when done. - - * shf.c(shf_close): always used to return EOF. - - * trap.c(trapsig): skip error handlers when checking for PARSE or LOOP. - -Wed Jun 22 10:24:09 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * sh.h(C_IFSWS), misc.c(initctypes): added and initialized C_IFSWS - (IFS white space). - * c_sh.c(c_read): print continuation prompt if line ends in backslash; - multiple non-white-space IFS chars delimit fields; strip trailing - IFS-white-space from last variable; watch out for backslash followed - by EOF. - * eval.c(expand): only do field splitting on the results of - parameter/command substition (POSIX, !v7-sh); multiple - non-white-space IFS chars delimit fields. - - * eval.c(expand,alt_expand): removed NOALT tests since it could - never be set; added return after call to alt_expand() in expand(). - -Mon Jun 6 10:12:41 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * misc.c(setctypes, initctypes): setctypes - don't allow leading null - in IFS (IFS="" could cause problems, 0 is already added); - initctypes - don't use a leading null. - - * sh.h, eval.c: move definition of ifs0 from eval.c to sh.h; handle - null ifs0. - * var.c(setspec): set ifs0 to first character of IFS. - - * lex.c(yylex): when parsing ${..}, array references were not being - null terminated. - -Fri Jun 3 12:28:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * var.c(export): changed to use memcpy() instead of loops. - - * eval.c(varsub, expand): check for #foo[@] in addition to #foo[*]; - handle ${foo[*]} and ${foo[@]} - added free_me field to struct Expand - so pointer vector can get freed. - - * c_sh.c(c_dot), main.c(include): set up positional parameters if - any are specified; Added argc,argv args to include(); changed all - calls to include(); change include() to return 0 or 1 - caller - can check exstat if desired; c_dot() should return 1 if can't open - file (was -1). - - * c_sh.c(c_brkcont): warning message could call getn() with NULL - save - original number and print it. - - * main.c(main): set $0 to first argument when -c used, ie, - "sh -c cmd-string this-is-$0 argumernts..." - - * exec.c(iosetup): print "cannot open" if IOHERE fails. - - * io.c(errorf): set exstat to 1. - - * exec.c(search): assume mode is R_OK or X_OK (not 0/1 - 0 is F_OK, we - want R_OK); changed all calls to pass R_OK/X_OK. - sh.h: define R_OK,W_OK,X_OK,F_OK if not defined. - eaccess(): changed all calls to use [RWXF]_OK. - - * sh.h(flag[], shell_flags[], Flag()): Renamed flag[] array to - shell_flags[] to avoid conflicts with other uses of flag; Changed - all references to flag[] to Flag(); defined Flag() to cast its arg - to an int (for old pcc based C compilers). - - * vi.c(iswordch): use letnum() instead of isalnum || _. - - * misc.c(parse_args): call set_array() to deal with -A flag. - * var.c(set_array): new function. - - -Fri Jun 3 10:22:26 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * eval.c(substitute): afree(s). - - * var.c(global,local), sh.h: ARRAYMAX: new define - max index of an - array; changed 511 constants to this; changed global() and local() - to use array_ref_len() instead of arraysub(). - - * expr.c(token): deleted unneeded arraysub() decl. - - * lex.c(arraysub), proto.h: made static, removed unused arguments, - changed callers; removed prototype from proto.h. - - * ChangeLog: changed descriptions from func(file) to file(func). - -Wed Jun 1 09:17:50 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * made pdksh-4.9+mun.2 distribution - - * Makefile.in: added RCSFILES macro and rcs-ci target. - - * configure.in: add termio.h to the AC_HAVE_HEADERS() call. - - * sh.h, main.c, edit.c, misc.c: use EXTERN for aperm, x_cols, - builtin_optind and builtin_optarg in sh.h, delete definitions - in main.c, edit.c and misc.c. - - * io.c(maketemp): changed sizeof(PATH) to sizeof(path). - - * aclocal.m4(KSH_VOID,KSH_DUP2_CHECK): test that a void * variable - can be used (Ultrix 2.2 compiler doesn't do this); added ifdef - HAVE_FCNTL_H to dup2 test. - - * aclocal.m4, configure.in, sh.h, tree.c, io.c, shf.c: added - new config test KSH_PROTOTYPES to check for function prototypes - (MIPS RICS/os 5.0 C compiler isn't STDC and it can't mix <stddef.h> - with <varargs.h>). Removed stdarg.h test (now redundent). Changed - all varargs functions to use HAVE_PROTOTYPES instead of - HAVE_STDARG_H && STDC. - - * eval.c(alt_scan): changed type of endc param from char to int to - avoid problems with mixing prototype declarations and K&R - definitions. - - * main.c(main), sh.h: added plain getcwd() decl to main(), removed - ARGS() version from sh.h (some systems have getcwd() but don't - declare it, some have getcwd() with a size_t arg 2, some have - an int arg 2). - - * misc.c(memset,memmove): changed the second memset() to memmove(). - - * c_sh.c(clocktos): changed #if CLK_TCK ... to if (CLK_TCK.. since - CLK_TCK is not always defined to a number (may be a _sysconf())). - -Tue May 31 10:49:16 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * configure.in, Makefile.in: added code to set GCC_WARNFLAGS from - $(srcdir)/Warn-flags if gcc is being used; Took -Wall, etc. - out of CFLAGS, took -Dno_RCSids out of DEFS. Added install.sh to - DISTFILES, grabbed copy of install.sh from autoconf (who grabbed - it from X11R5). - - * io.c(errorf,shellf,shprintf),shf.c(shf_fprintf,shf_snprintf), - tree.c(fptreef,snptreef): don't use ansi decls with old style - varargs; changed ifdef __STDC__ to ifdef HAVE_STDARG_H. - - * jobs.c(j_init): changed getpgrp() call to getpgID(), defined getpgID() - appropriately for BSD vs POSIX/SYSV getpgrp. - - * expand.h, ksh_dir.h, ksh_stat.h, ksh_time.h, ksh_wait.h, shf.h, - tty.h: added RCS $Id: ChangeLog.0,v 1.1 1996/08/14 06:19:10 downsj Exp $'s. - - * acconfig.h: updated SIGSET_T comment: unisgned int -> unsigned. - - * aclocal.m4(KSH_CLOCK_T,KSH_TIME_T,KSH_SIGSET_T): make sure - type is a word (same fix as was done for more_t, et.al.). - - * aclocal.m4(KSH_VOLATILE): check that the compiler can deal with - volatile pointers (dec/pmax ultrix 4.2 compiler can't). - - * misc.c(parse_args): added skelatal code for dealing with -A. - - * var.c,proto.h(skip_varname): new function; deleted isassign() - function, which is no longer called. Changed typeset(var.c) - to use skip_varname(). - - * var.c(strint): fail if base is not in the range 2..36; set variable - base according to first base seen; generate an error if a non-alnum - char is seen (1^A was the same as 11). - - * var.c(strval): for integer variables, output base if != 10. - - * sh.h: fixed typo in x_cols define (#defined -> #define). - -Fri May 27 16:49:29 NDT 1994 Micharl Rendell (michael@panda.cs.mun.ca) - - * made pdksh-4.9+mun.1 distribution - - * finished autoconf'ing source code. - -Fri May 20 16:47:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * c_ulimit.c(c_ulimit) (was do_ulimit.c(do_ulimit)): major rework; - deal with combinations of getrusage and ulimit, use options at&t - ksh uses (-SHa..). - * misc.c(builtin_getopt): yet another getopt routine for builtin - commands - * misc.c(parse_args), c_sh.c(c_set), main.c(main): custom option - parsing routine for command line/set options. Lots of changes - to main() to incorporate this (easier to follow). - * c_test.c(c_test): added -e (file exists) test. - -Fri May 5 12:16:46 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca) - - * numerous changes from old Notes.4-9 file: - - c_ksh.c: - - calls to errorf identify what function the error is in - (eg, errorf("print: bad -u option");) - - added array stuff (lots of places) - - table.c - - lex.c - - var.c: +arraysearch(), +basename() - - c_sh.c(c_exit), main.c(shell), sh.h: - - added reallyquit flag to deal with stopped jobs at exit time; - only two exit commands (or eofs) in a row will work. in - shell(), set exstat from execute value. - - c_ksh.c(c_print): - - handle \\ at end of string better (don't skip the null) - - c_ksh.c(c_whence): - - stop looking as soon as we get a failure - - pass flag[FTRACKALL] to findcom() instead of 0 - - c_ksh.c(c_alias): - - print '%s alias not found' if not found - - c_ksh.c(c_jobs): - - handle -l option (list pid) - - c_ksh.c(c_kill): - - two column -l output to try to keep it on one screen - - c_sh.c(c_read): - - skip IFS at start of line "echo ' a b' |(read a b; echo $a)" - should print a, not nothing. - - changed EOF check to set all vars to null (same way \n is - handled) - - eval.c(comsub): - - after compile(), return if t is NULL - - use setfileno() instead of fileno(x) = .. (see sh.h changes); - - exec.c(iosetup): - - set exstat if redirect fails - - exec.c(fd_clexec): - - check that fd >= 0 - - exec.c: - - change SHARPBANG ifdef code - everyone uses scriptexec(). - ifdef is put around open/read/parse code in scriptexec(). - [code cleanup] - - exec.c(search): - - eaccess test out side of loop: must be regular file to exec it - (like test in loop) - - eval.c(expand): - - added while getc() == 0 in XCOM - [a null in the output of a file would be treated as eof and - waitlast would not be called] - - eval.c(trimsub): - - '%' subst: use ATEMP, not APERM - - eval.c(tilde): use Xinit et. al., instead of fixed length buffer - - getopts.c(getopt): rename getopt() to ksh_getopt() to avoid - problems with prototypes in system #include files. - - io.c(fopenshf): - - call clearerr(fd) if already open - - use F_GETFL to determine appropriate mode for fdopen() call - instead of opening everything for read/write - - use ifdef _FSTDIO instead of ifdef _BSDI (_FSTDIO is used in - 4.4bsd, NetBSD, FreeBSD and other non BSDI environs) - - lex.c(ungetsc): don't decrement if str == null, remove nullstr hack - - lex.c(yylex): - - \ at eol: call Xfree before goto Again - - use memset() to clear ident, instead of while loop - - syn.c(get_command): renamed from command() to get_command() to - avoid conflicts with command(main.c). - - sym.c(get_command): - - allow A=B <alias-name> to work (alias was not being expanded) - - allow `if .. if .. fi fi' to work (no ; after group terminator - (fi , esac, done, ), }) - - allow `alias FI=fi ; if .. if .. fi FI' to work (alias - expansion after group terminator) - - do not assume resize returns same pointer - - tree.c(pioact): - - handle IORDWR case - - added leading quote for file in IOHERE case - - var.c(special): - - add MAILCHECK check - - var.c(setspec): - - add MAILCHECK case (doesn't do anything yet) - - var.c(strint): - - handle null vp->val.s - - eval.c(sh.h, expand), misc.c(options[]): - - enable alternations only if alternations flag set - (set -o alternations). This is so (att ksh) scripts that don't - expect alternations won't break. - - added notify option (asynchronous job completion notification) - - added vicomplete to enable tab char as file name completion - char in vi (this is likely to go away - exits for historical - reasons) - - jobs.c, main.c, sh.c, trap.c: - - define/use SIG_HDLR instead of void - - eval.c(expand): alt_expand() does not return a value so don't test - it, just return. Also changed decl of alt_expand() to reflect - reality. - - emacs.c(x_emacs): first return returns random value (i); change to - return 0. Also changed the way interrupts are returned to called - (return -2 means interrupt). - - c_sh.c(c_brkcont): at&t ksh allows breaks/continues outside of - loops, 4.9 prints an error and breaks out of all env's (if, case, - etc.). Fixed to act like at&t (ie, allow bogus continues), except - a warning message is printed. (Some HP-UX shell scripts actually - have continues outside of loops...) - - main.c(shell): parameter s should be volatile as it is used after a - setjmp. - - edit.c(promptlen): handle tabs, backspaces... - - cleaner fix to the ^C/source->line problem: in pprompt(lex.c), - convert ! to source->line+1 (same in promptlen(edit.c)), increment - source->line after a (non-empty, non-eof) line has been read - (before call to histsave()). To be pedantic, also adjust - position of source->line++ in SHIST in case PS9 is ever used. - Remove code in shell(main.c) that does the source->line--, - remove the source->line-- for eof and empty line in from - getsc_(lex.c). - - trap.c(sigtrap[]): do not depend on signal number matching position - in initialization array. Use second table in which order does not - matter to initialize sigtrap[] array. Easier to read/port, and - generally less fragile. requires call to inittraps() in main.c. - - trap.c(cleartraps): need to clear Sigact flags/mask after use - (actually, declare a local struct sigact and use that instead of - Sigact) - - exec.c(execute): case TSELECT: no USE_SIGACT code for call to - signal(); case TPIPE: don't call waitlast() if XXCOM since - waitlast() will be called in expand(); 4.9 code that set and - then cleared the XEXEC flag in the TPIPE case not added since - it was ifdef'd out, also the code to not exit if XPIPEI flag - set was not added; 4.9 XXWHL flag not added (don't flush stdin - if in a while loop) since this problem fixed (I hope) by shf stuff. - - ttyfd{sh.h/lex.c}: use EXTERN/_I_ to initialize ttyfd. Remove from - lex.c - - interrupted reads: instead of testing sigchld_caught after reads - fail, continue them if errno == EINTR. - - edit.c(x_getc): check for EINTR, and continue reading if so. - - lex.c(getsc_): check for EINTR, and continue reading if so. - (don't check return of x_read() - check has already been done) - - exec.c(selread): check for EINTR, and continue reading if so. - - history changes: - - history.c: - - histrpl(): bounds check doesn't take global flag into - account - move check into loop and past loop. - - c_fc(): if pattern is the empty string, histrpl() - goes into infinate loop. Start searching for = after first - char (this is what at&t ksh seems to do). - - c_fc(): `fc -l first' should list at most 16 - commands according to at&t manual. - - findhist(): re-wrote: shorter, easier to follow. Now - returns an int. (used only by vi code) - - use COMPLEX_HISTORY's allocated history array in - EASY_HISTORY: common init_histvec(), sethistfile() and - sethistsize() functions. - In the process, hist_open() went away. Use histsize - instead of HISTORY in hist_init() and hist_finish() - #ifdefs in lex.h, table.h, - var.c disappear, history variable definitions in lex.c - disappear. - - hist_init(COMPLEX_HISTORY): move hstarted = 1 to after the - FTALKING test. - - hist_finish(): don't open hname if its null - - histrpl(): made static, use ARGS in decl - - made current and curpos static - - changes to allow embedded newlines in commands: - - histsave(): trash only trailing newline - - hist_init(): read in null terminated lines instead of - newline terminated - - hist_finish(): write null terminated lines - - make multiple line command appear in single history line - (EASY_HISTORY only): - - added histappend() to append new command to last - command - - added call to histappend() in getsc_(lex.c) (also: only - adjust source->line if not multiline). - - lex.h: - - remove second decl of history if !EASY_HISTORY - - tree.c(ptree): case TCOM: check if t->vars or t->args is 0 - - vi.c(x_vi): ^D anywhere in command line is eof ($ foobar^D exits). - at&t ksh ignores ^D in middle of line - - edit.c: - - don't need to include string.h - included in stdh.h - - init_editmode(): in at&t ksh, VISUAL takes precenence over - EDITOR, so put it first. Also, at&t ksh doesn't use FCEDIT so - trash it. - - moved initialization of ed_* from x_read() to x_init() since - thats where they are set from tty structs. - - x_init(): set ed_intrc, ed_quitc for _BSD & _POSIX_TERM ifdefs - - send output to shlout (instead of stdout - at&t ksh writes to - stderr) - - made x_do_init static. - - exit.c(x_getc), lex.c(yylex): restart interrupted reads in - x_getc(), changed read-restart in yylex() to only effect call - to read(). - - syn.c(thenpart): then THEN is not optional - generate a syntax - error if no THEN. (ie, `if true ; fi' is not legal). - - syn.c(get_command): don't accept keywords after re-directory (eg, - `> /dev/null if true ; then echo hi ; fi' is not legal). - - vi.c: handle \ and ^[ in command mode ala at&t ksh (filename - completion) - - syn.c(thenpart), syn.c(elsepart): calling token(0) when they want a - keyword (always worked 'cause tpeek() is always called before, with - the keyword flag). Fix: call token(KEYWORD|ALIAS) (at&t ksh does - alias expansion here). Question: pass CONTIN as well? - - syn.c(get_command): LWORD/MPAREN case: do alias expansion when - getting open brace ({). CASE case: ditto for `in' and `esac'. - IF case: ditto for `fi'. FUNCTION case: dito for open brace ({). - - syn.c(dogroup): alias expansion when getting `do' and `done'. - - syn.c(wordlist): alias expansion when getting `in'. - - syn.c(nested): alias expansion when getting `)', `}' - - syn.c(casepart): alias expansion when getting `esac' or `;;'. - Also removed use of cf variable - it does nothing. - - eval.c(expand): case CSUBST: '#'/'%' - increment st so nested - substitutions work. - - var.c(typeset): INTEGER && no assignment: memory was being freed - and then used (there was even a comment saying it was being - done...) - - lex.c, lex.h, exec.c, main.c: - added shf_{open,fdopen,close,gets}() routines so stdio wasn't - used. When reading a command file under osf/1, stdio would - mess up the read pointer when a child exited: the exit flushed - all open files and flushing a file open for reading changes the - current read position (does a seek to where the next char would - be read). This position is then used by the parent process, - who thinks the read position is still at the end of the buffer - it read. - - c_sh.c: - use shf_*() routines avoids two bugs in read: - - on sunos 4.1.3, a read would gobble up a stdio buffer and - never put it back (ie, lseek backwards). Neither a - fflush() nor a fseek(x, 0L, 1) fixed the problem. - (see Bug 26) - - on linux, stdio knows its current offset and seeks there - before reading a buffer. This causes grief when the shell - replaces file descriptors behind stdio's back (ie, all the - time). - $ read x << EOF - hi - EOF - $ cat > /dev/tty << EOF - 1:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - 2:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - 3:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - EOF - $ - the cat picks up reading at the offset where the read - command left off (ie, at bcdefg... - the 1:a are skipped). - - exec.c(comexec): built-in c_exec && no args: close the saved fd's - (were thrown away). Also, set close-on-exec flag for fd's > 2, - as per at&t manual. - - lex.c(yylex): only accept 1 digit before a redirection (eg, 1> is - ok, 1abc> is not) - - exec.c(iosetup): only accept 1 digit after a dup-redirection - (eg, >&1 is ok, >&1abc is not) - - exec.c(iosetup): use O_APPEND flag for >> redirections; use O_CREAT - flag for <> redirections. (re-organized to accumulate open() flags - and do one open() call); changed error message to know about dup - failing. - - c_sh.c(c_umask): umask should have leading 0 - doesn't when umask - has 3 digits (eg, `umask 222; umask' prints 222 instead of 0222) - - c_sh.c(setsig): declare local struct sigaction and use it so - sa_flags doesn't have to be cleared (also to try to keep away from - global vars). - - main.c(main): - - don't go set TALKING if name starts with -. - - read $HOME/.profile (not .profile) - - main.c(main): re-wrote option parsing code - - edit.c(init_editmode): don't check FCEDIT - - if set -o vi/emacs/gmacs on command line, don't set edit mode from - FCEDIT/EDITOR/etc. - - var.c(setspec): FCEDIT should not magicly change edit mode; VISUAL - and EDITOR should (EDITOR only if VISUAL is not set) - - changed noclobber char from ! to | (this is what at&t ksh uses) - - exec.c(iosetup): use O_EXCL flag if FNOCLOBBER set and >| not used - - c_sh.c(c_set): don't clear FERREXIT if FTALKING is set; although - some ksh manuals say -e is ignored for interactive shells, they - all seem to honour the -e flag for interactive shells. - - vi.c: reset history position to the end after a line is modified - - `(( 1 + 2 ))' no longer prints `+: bad expression'! - - lex.c(yylex): added parenthesis counting so `(( ((1+2)) ))' no - longer generates a syntax error - - expr.c(intvar): if strint() fails, give bad number error - (`let 1+foo' should fail) - - `echo hi 1abc123> /dev/tty' no longer interpreted as - `echo hi 1> /dev/tty' (is `echo hi 1abc123 > /dev/tty') - - `echo hi 1<> /tmp/does-not-exist' now works (used to say cannot - open) - - c_sh.c(c_umask): umask now takes symbolic arguments (g-r, +w, etc.) - - c_ksh.c(c_whence): pass flag[FTRACKALL] to findcom() instead of 1. - - `echo hi >< bar' now produces an error - - jobs.c(j_lookup): now checks for ambiguous job specifications; - callers now get an error message. - - c_ksh.c(c_fgbg): multiple jobs can be specified - - emacs.c(x_transpose): move past transposed chars like (gnu) emacs - does - - main.c(main): don't copy initcoms (messes up memory allocated for - shf_iob[] in initio(), should not be necessary) - - main.c(main), var.c(import), var.c(typeset), c_ksh.c(c_alias), - expr.c(token), misc.c(strnsave): added strnsave() function; use it - instead of writing nulls in the middle of strings; main() no longer - copies startup commands before executing them. - - vi.c: wbuf[] no longer a fixed size (was hard coded to 80 chars). - - alloc.c(aresize): if passed a null pointer, don't free it - - expand.h: restored usage description and NOTE from previous version - - alloc.c, table.h, table.c: - - changed struct fields named `free' to nfree (struct table) and - freelist (struct Block) to allow memory debugging - (involves #defining free) - - main.c(main): smart initialization of PWD (ensures it is always - valid). - - lex.h, table.h, tree.h: removed redundent function declarations - (were also in proto.h) - - sh.h: increased LINE from 256 to 1024 - - main.c(include), sh.h(E_INC), c_sh.c(c_return): added hack so a - return in a included file returns to the includer instead of - exiting the shell. Very useful in $ENV scripts and profiles, - eg, so the whole script does not have to be parsed for - non-interactive shells. - This is not compatible with the at&t ksh, whose man page says - return is the same as exit outside of functions. May be modified - in the future. (note that at&t ksh parses a .'ed file before - executing anything, so a premature return would not speed its - parsing, which is why the return hack was added to pdksh) - - exec.c(iosetup): don't save fd if already saved (and don't - generate an error) - - exec.c(findcom): in if (..ALLOC && eaccess), test for - ALLOC redundent - always call afree() diff --git a/bin/pdksh/IAFA-PACKAGE b/bin/pdksh/IAFA-PACKAGE deleted file mode 100644 index 879682c0a61..00000000000 --- a/bin/pdksh/IAFA-PACKAGE +++ /dev/null @@ -1,17 +0,0 @@ -$OpenBSD: IAFA-PACKAGE,v 1.5 1996/11/21 07:59:25 downsj Exp $ - -Title: pdksh -Version: 5.2.12 -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 - POSIXized. -Author: (Eric Gisin), (Charles Forsyth), (John R MacMillan), - sjg@zen.void.oz.au (Simon J. Gerraty), - michael@cs.mun.ca (Michael Rendell), (plus many others) -Maintained-by: michael@cs.mun.ca (Michael Rendell) -Maintained-at: ftp://ftp.cs.mun.ca:/pub/pdksh/ -Platforms: Written in C, runs on most UNIX boxes (uses GNU autoconf; - works best in a POSIX or BSD environment). Also runs on OS/2. -Copying-Policy: Freely Redistributable (mostly public domain, some copyrighted) -Keywords: pdksh, ksh, Korn, shell, command line interpreter diff --git a/bin/pdksh/INSTALL b/bin/pdksh/INSTALL deleted file mode 100644 index afd11fa04cb..00000000000 --- a/bin/pdksh/INSTALL +++ /dev/null @@ -1,151 +0,0 @@ -$OpenBSD: INSTALL,v 1.1 1996/08/14 06:19:10 downsj Exp $ - -[This file is the generic GNU autoconf/configure installation description, - see the README for pdksh specific configuration/installation information] - - This is a generic INSTALL file for utilities distributions. -If this package does not come with, e.g., installable documentation or -data files, please ignore the references to them below. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation, and -creates the Makefile(s) (one in each subdirectory of the source -directory). In some packages it creates a C header file containing -system-dependent definitions. It also creates a file `config.status' -that you can run in the future to recreate the current configuration. - -To compile this package: - -1. Configure the package for your system. - - Normally, you just `cd' to the directory containing the package's -source code and type `./configure'. If you're using `csh' on an old -version of System V, you might need to type `sh configure' instead to -prevent `csh' from trying to execute `configure' itself. - - Running `configure' takes awhile. While it is running, it -prints some messages that tell what it is doing. If you don't want to -see any messages, run `configure' with its standard output redirected -to `/dev/null'; for example, `./configure >/dev/null'. - - To compile the package in a different directory from the one -containing the source code, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. If -for some reason `configure' is not in the source code directory that -you are configuring, then it will report that it can't find the source -code. In that case, run `configure' with the option `--srcdir=DIR', -where DIR is the directory that contains the source code. - - By default, `make install' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PATH'. Alternately, you can do so by consistently -giving a value for the `prefix' variable when you run `make', e.g., - make prefix=/usr/gnu - make prefix=/usr/gnu install - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH' or set the `make' -variable `exec_prefix' to PATH, the package will use PATH as the prefix -for installing programs and libraries. Data files and documentation -will still use the regular prefix. Normally, all files are installed -using the same prefix. - - Some packages pay attention to `--with-PACKAGE' options to -`configure', where PACKAGE is something like `gnu-as' or `x' (for the -X Window System). They may also pay attention to `--enable-FEATURE' -options, where FEATURE indicates an optional part of the package. The -README should mention any `--with-' and `--enable-' options that the -package recognizes. - - `configure' also recognizes the following options: - -`--help' - Print a summary of the options to `configure', and exit. - -`--quiet' -`--silent' - Do not print messages saying which checks are being made. - -`--verbose' - Print the results of the checks. - -`--version' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--x-includes=DIR' - X include files are in DIR. - -`--x-libraries=DIR' - X library files are in DIR. - - `configure' also accepts and ignores some other options. - - On systems that require unusual options for compilation or linking -that the package's `configure' script does not know about, you can give -`configure' initial values for variables by setting them in the -environment. In Bourne-compatible shells, you can do that on the -command line like this: - - CC='gcc -traditional' LIBS=-lposix ./configure - -On systems that have the `env' program, you can do it like this: - - env CC='gcc -traditional' LIBS=-lposix ./configure - - Here are the `make' variables that you might want to override with -environment variables when running `configure'. - - For these variables, any value given in the environment overrides the -value that `configure' would choose: - - - Variable: CC - C compiler program. The default is `cc'. - - - Variable: INSTALL - Program to use to install files. The default is `install' if you - have it, `cp' otherwise. - - For these variables, any value given in the environment is added to -the value that `configure' chooses: - - - Variable: DEFS - Configuration options, in the form `-Dfoo -Dbar...'. Do not use - this variable in packages that create a configuration header file. - - - Variable: LIBS - Libraries to link with, in the form `-lfoo -lbar...'. - - If you need to do unusual things to compile the package, we encourage -you to figure out how `configure' could check whether to do them, and -mail diffs or instructions to the address given in the README so we -can include them in the next release. - -2. Type `make' to compile the package. If you want, you can override -the `make' variables CFLAGS and LDFLAGS like this: - - make CFLAGS=-O2 LDFLAGS=-s - -3. If the package comes with self-tests and you want to run them, -type `make check'. If you're not sure whether there are any, try it; -if `make' responds with something like - make: *** No way to make target `check'. Stop. -then the package does not come with self-tests. - -4. Type `make install' to install programs, data files, and -documentation. - -5. You can remove the program binaries and object files from the -source directory by typing `make clean'. To also remove the -Makefile(s), the header file containing system-dependent definitions -(if the package uses one), and `config.status' (all the files that -`configure' created), type `make distclean'. - - The file `configure.in' is used to create `configure' by a program -called `autoconf'. You only need it if you want to regenerate -`configure' using a newer version of `autoconf'. diff --git a/bin/pdksh/LEGAL b/bin/pdksh/LEGAL deleted file mode 100644 index 78dd76f95dc..00000000000 --- a/bin/pdksh/LEGAL +++ /dev/null @@ -1,36 +0,0 @@ -$OpenBSD: LEGAL,v 1.1 1996/08/14 06:19:10 downsj Exp $ - -pdksh is provided AS IS, with NO WARRANTY, either expressed or implied. - -The vast majority of the code that makes pdksh is in the public domain. -The exceptions are: - sigact.c and sigact.h - These are covered by copyrighten by Simon J. Gerraty; - the copyright notice for these files is as follows: - This is free software. It comes with NO WARRANTY. - Permission to use, modify and distribute this source code - is granted subject to the following conditions. - 1/ that that the above copyright notice and this notice - are preserved in all copies and that due credit be given - to the author. - 2/ that any changes to this code are clearly commented - as such so that the author does get blamed for bugs - other than his own. - aclocal.m4 - This is covered by the GNU General Public Licence (GPL) - as it contains modified versions of macros that come with - GNU autoconf. As this is used solely for configuration, - the pdksh code itself is not covered by the GPL. - The following is taken from autoconf 2.x documentation - (info autoconf questions distributing) concerning use - of autoconf in programs: - - There are no restrictions on how the configuration - scripts that Autoconf produces may be distributed - or used. In Autoconf version 1, they were covered by - the GNU General Public License. We still encourage - software authors to distribute their work under terms - like those of the GPL, but doing so is not required - to use Autoconf. - -That's it. Short and simple. diff --git a/bin/pdksh/Makefile b/bin/pdksh/Makefile deleted file mode 100644 index 85145ad30ed..00000000000 --- a/bin/pdksh/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# $OpenBSD: Makefile,v 1.8 1996/11/30 23:54:36 downsj Exp $ - -PROG= ksh -SRCS= alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c \ - eval.c exec.c expr.c history.c io.c jobs.c lex.c mail.c \ - main.c misc.c missing.c path.c shf.c syn.c table.c trap.c \ - tree.c tty.c var.c version.c vi.c - -DEFS= -DHAVE_CONFIG_H -CFLAGS+=${DEFS} -I. -I${.CURDIR} -DKSH -MAN= ksh.1 sh.1 - -CLEANFILES+= siglist.out emacs.out - -LINKS= ${BINDIR}/ksh ${BINDIR}/rksh -LINKS+= ${BINDIR}/ksh ${BINDIR}/sh -MLINKS= ksh.1 rksh.1 - -.depend trap.o: siglist.out -.depend emacs.o: emacs.out - -siglist.out: config.h sh.h siglist.in siglist.sh - /bin/sh ${.CURDIR}/siglist.sh \ - "${CPP} ${CPPFLAGS} ${DEFS} -I${.CURDIR}" \ - < ${.CURDIR}/siglist.in > siglist.out - -emacs.out: emacs.c - /bin/sh ${.CURDIR}/emacs-gen.sh ${.CURDIR}/emacs.c > emacs.out - -.include <bsd.prog.mk> diff --git a/bin/pdksh/NEWS b/bin/pdksh/NEWS deleted file mode 100644 index f1115015719..00000000000 --- a/bin/pdksh/NEWS +++ /dev/null @@ -1,603 +0,0 @@ -$OpenBSD: NEWS,v 1.5 1996/11/21 07:59:26 downsj Exp $ - -Version 5.2.12 - -* bug fixes - * editing: shell recognizes window resizes on Dec alphas (config problem). - * alias: no longer dumps core if alias is in a command substitution. - * alias: everything after ;\n or \n\n was ignored in aliases. - * exec: temp files used by here docs in functions now cleaned up on exec. - * possible core dump when cleaning up environment fixed. - * vi: set -o vi-show8 now does what it was supposed to do (cat -v like). - * job control: process group synchronization (needed on systems with - broken setpgrp()) now works when the pipeline contains built in commands. - * vi: if set -o vi-tabcomplete, tab works in command mode as well. - * set/typeset: unset parameters are only reported if they have attributes. - - -Version 5.2.11 - -* bug fixes - * aliases: expansion was reading an extra character (bug added in 5.2.10). - - -Version 5.2.10 - -* bug fixes - * parsing: handling of backslash-newline fixed (esp. in here documents). - * read: prints prompt if non-interactive and input is a tty. - - -Version 5.2.9 - -* bug fixes - * config: using LDSTATIC no longer generates config error. - * config: can compile as sh again (--enable-shell=sh). - * config: should compile on machines with broken "gcc -g" - * config: fixed test for broken S_IFIFO. - * config: fixed test for getwd() routine. - * config: better NeXT support (signal list generated correctly, clock_t - type detected, enable job control in rlogin sessions) - * parsing: assignments containing brackets ([]) not treated as commands. - * editing: terminal column width determined correctly on startup. - * vi: long prompts truncated (more or less) correctly. - * file completion: files of the form ~user (no /'s) expanded correctly. - -* at&t ksh method for delimiting hidden characters in prompt added (i.e., - start prompt with non-printing char and \r, use char to delimit esc codes). - - -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 generate 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' improved, 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 - -* bug fixes - * vi: commands can be longer that 16 chars... - - -Version 5.2.6 - -* bug fixes - * break/continue: if too big a number is given, last enclosing loop is used. - * set: set +o now generates a set command that can be saved and executed. - * COLUMNS/LINES are now exported when they are automatically set. - * emacs: completion: space not added after directory names. - * vi: # command inserts # after each newline; # on commented line - undoes the commenting. - * some regression tests made less sensitive to their environment. - * should compile on os/2 again. - - -Version 5.2.5 - -* bug fixes - * configuration: if sig_setjmp() being used, use sigjmp_buf. - * configuration: test for times() fixed. - * configuration: ANSI usage of setjmp() and offsetof(). - * echo/print: octal number in \ sequence must start with a 0. - * echo: don't treat a lone minus as an option. - * typeset -f: correctly prints functions with select statements. - * vi: / with no pattern repeats last search. - * vi: repeat counts no longer effect file completion/expansion. - * vi: tab-completion now also works in command mode. - * emacs/vi: ^O key now read as ^O on suns/alphas (was eaten by tty driver). - * emacs: now has file expansion (^[*). - * emacs: ^O goes to next command, not next next command. - * COLUMNS/LINES: environment variables now set on start up. - * variables: command line assignments can't change readonly variables. - * arithmetic: giving multiple bases (5#4#3) no longer allowed. - * arithmetic: when assigning a non-integer variables, base no longer shown. - * history: fixed replacement bug introduced in last release. - * history: -1 refers to the previous command, not current fc command. - * parsing: correctly handles command substitutions starting with a newline. - -* full command completion added (both vi and emacs). - - -Version 5.2.4 - -* bug fixes - * PS1 imported from environment again. - * vi handles prompts with embedded newlines. - * errors redirecting stderr aren't lost. - * redirection errors for <&n no longer reported as to >&n. - * don't do globbing on re-direction targets if not interactive (POSIX). - * pattern matching in [[ foo = foo*bar ]] now works again. - * HUP signals are passed on to jobs running in the foreground. - * $? now valid (ie, not 0) in trap handlers, `...` expressions, etc. - * noclobber doesn't effect redirections to non-regular files (eg, /dev/null) - * \newline in here-document delimiters handled correctly. - * typeset -f now reports unloaded autoload functions properly. - * ~,~+,~- are not expanded if HOME,PWD,OLDPWD are unset. - * vi completion/expansion: * not appeded if word contains $. - * cd: error message contains correct directory string. - * vi expansion list: printed in column form ala at&t ksh. - * ^C while reading .profile/$ENV nolonger causes shell to exit. - * option errors for build-in commands now include command name. - * emacs completion/expansion: ' and " are treated as word delimiters. - * fc: replacements (a=b) no longer truncates the command. - * alias: alias -t -r now cleans out the tracked alias table. - -* compile-time configuration changed: configure script --enable-XXX options - replace the old options.h file. Use "configure --help" for information - on what the options do (they are basicly the same as what was in the - options.h file). Shell can be configured as a (almost) plain bourne - shell using the --enable-shell=sh (also generates appropriate man page). - Installed name of program (ksh or sh) can be modified using configure's - --program-* options. - -* ulimit: added -p (maxproc) option. - -* case statements can use the old syntax of {,} instead of in,esac. - -* extended file globbing added (eg, f*(bar|Bar) matches f, fbar fBarbar, etc). - -* trim expressions can be of the form ${parameter#pattern1|pattern2|...}. - -* if compiled as sh, $ENV included only if posix option is set. - -* vi: U command added (undo all changes on line). - -* the Bugs script has been replaced by a new regression testing system, kept - in the tests/ directory (contains a perl script which sets up a test - environment and runs tests, and a bunch of tests). - - -Version 5.2.3 - -* bug fixes - * arrays: set -A and unset now unset whole array. - * history(complex version): fixed core caused by uninitialized hist_source. - * getopts: will continue parsing options if called after error. - * getopts: doesn't print shell name twice in error message. - * posix: if posix option is set, $0 is always the name of the shell. - * history: "fc -s foo" now finds foo if it is the most recent command. - * let: expression errors no longer cause scripts to exit. - * PS1: does not go into infinite loop if there is an expansion error. - * configure: memmove/bcopy test has a change of working now. - * configure: check for flock(), undefine COMPLEX_HISTORY if not found. - * substitution: tilde substitution works in word part of ${var[-+=?]word}. - * history: "fc <number>" now edits <number>, not <number> to most recent. - * cd: two argument form works again. - * special commands taking assignments (alias,set,etc.): field splitting, - file globbing, etc. suppressed only for args that look like assignments. - * command: -V now finds reserved words. - -* added support for Korn's /dev/fd tests - -* new compile time option: DEFAULT_ENV - if defined, it names a file to - include if $ENV is not set. - -* test -o option: if option starts with a !, the test is negated. The test - always fails if the option doesn't exist (so [ -o foo -o -o !foo ] is true - iff option foo exists). - -* new option: set -o nohup (currently on by default) - if set, running jobs - are not kill -HUP'd when a login shell exits; if clear, they are. In - future, this will be clear by default (to act like at&t ksh) - if you don't - (won't) like this, add "[ -o !nohup ] && set -o nohup" to your .profile. - -Version 5.2.2 - -* bug fixes - * included c_test.h in distribution (opps). - -Version 5.2.1 - -* bug fixes - * emacs: buffer no longer overflowed when completing file names/commands. - * emacs: <ESC><tty-erase-char> now bound to delete-back-word (was ...-char). - * emacs: ignores a space char after ^V (version), as in at&t ksh. - * emacs: ^O bound to newline-and-next, ^X^Y bound to list-file. - * emacs: emacs words now include underscore. - * vi: set -o markdirs, directories and ^[= now get along. - * cd: -P no longer leaves .. and . in PWD. - * cd: if CDPATH set and can't cd, error doesn't contain any of CDPATH. - * cd: sets PWD properly, on machines without getwd(). - * configuration: unistd.h test fixed (include sys/types before dirent.h). - * configuration: detects memmove/bcopy's that don't handle overlaps. - * [[ ... ]] does lazy evaluation (eg, [[ ! -f foo || $(<foo) = bar ]] does - not evaluate $(<foo) if foo doesn't exist). - - -Version 5.2.0 - -* bug fixes - * vi: completion now allows globbing characters. - * vi: can deal with very long prompts. - * vi: . (redo) works after j, k, return. - * vi: [dyc]% causing backwards motion now gets correct start/end position. - * vi: complete_word (<ESC>\) no longer rings bell on ambiguous matches. - * vi: globbing doesn't append * if last component of file has globbing chars. - * emacs: most commands now take arguments, arguments can be multi digit. - * emacs: newline-and-next command works more correctly. - * after set -u, trimming substitutions no longer automatically fail. - * set -i no longer reports an internal error. - * FPATH: no longer incorrectly complains about function not being defined. - by a file; when it connectly complains, shell name in error is correct. - * set -a; set -o allexport: these now do something. - * shell deals with non-blocking input (clears non-blocking flag). - * autoconf: fixed memmove/memcpy tests. - * ! translation in prompt now done before parameter substitution. - * siglist.sh works around bug in bash 1.4.3. - * correct positional parameters accessible in local assignments. - * (sleep 100&) no longer waits for sleep to complete. - -* fc -s option added (same as -e -). - -* vi: ^V command (version) added. - -* vi: @<char> macros added (@X executes vi commands in alias _X). - -* emacs: bind -l lists all command names. - -* emacs: goto-history command added. - -* emacs: search-char function changed to search-char-forward; - added search-char-backward (bound to <ESC>^]). - -* cd and pwd take -L and -P options; added set -o physical option - (PWD,OLDPWD no longer readonly). - -* new command line -l option tells shell it is a login session. - -* os2 changes completed. - -* uses autoconf 2.x (was using 1.x). - -Version 5.1.3 - -* bug fixes - * fixed bug in arithmetic expression evaluation (||,&& caused core dump). - * ulimit code now uses rlim_t or quad_t, if appropriate. - * vi: file completion in command mode of single character filename works. - * vi: file completion with markdirs set resulted in two trailing /'s. - * vi: completion/expansion/listing acts like at&t ksh when expand fails. - * vi: ~ takes count. - * lines from history file are no longer negative (easy history). - * Makefile now uses manual extension consistently. - * fc now allows out of range relative (negative) numbers. - * functions with elif now printed correctly. - * FPATH now searched if PATH search fails, as in at&t ksh. - -* typeset -f output is readable (and more correct) - -* compiles under SCO unix - -* more os/2 changes integrated - -Version 5.1.2 - -* bug fixes - * for i; do ...; done now accepted. - * leading non-white-space IFS chars no longer ignored (now delimit fields). - * fixed globbing code so echo /usr/*/make works. - -Version 5.1.1 - -* bug fixes - * { ..;} allowed instead of do ..;done in for/select loops - * EOF after ; or & no longer causes syntax error - * complex history: when shrinking history file, keeps inside buffer space. - * vi editing: `v' on modified line no longer changes command numbering. - * ^C in vi/emacs no longer prints two newlines. - * long arguments (> 255) with globbing characters don't cause core dumps. - -* new (un)option, KSH, which compiles out ksh code (for producing minimal sh). - -* os/2 changes partly merged. - -Version 5.1.0 - -* bug fixes - * problem caused by _POSIX_VDISABLE on BSDI machines fixed - * exit status set to 127 if command file could not be opened - * profile files processed if basename argv[0] starts with (was $0) - * PWD now imported properly from environment. - * emacs code now either uses dynamic buffers or does overflow checking. - * emacs forward-word and delete-forward-word now work like other emacs's. - * ^C/^\ in vi/emacs work like at&t ksh (prompt reprinted, even if trapped). - * history number to command mapping now constant (numbers used to change). - * configuration: BSD tty now used on ultrix (avoids type ahead problem) - * eof in the middle of multiline commands now ignored if ignoreeof set. - * vi space command now works again. - * pointer mismatch compiler warning for waitpid() call dealt with. - * emacs internal memory error in command completion fixed. - * autoloaded functions now work first try. - * SECONDS parameter now acts like in at&t ksh. - -* sense of vi-show8 option changed: 8-bit characters are printed as is by - default; turning on vi-show8 now causes chars with 8th bit set to be - prefixed with M-. - -* missing sections in man page added (now basicly complete) - -* emacs ^V command added: prints ksh version - -* vi g command added: moves to most recent history - -Version 5.0.10 - -* bug fixes - * [[ ]] construct unbroken. - * the newline after a here document marker is now read properly. - * blank lines no longer cause $? to be set to 0. - * mail checking now uses atime/mtime instead of size. - * changing attributes of exported parameters no longer causes core dump. - * the last command in a file does not have to end in a newline. - * empty expressions now treated as 0 (previously generated an error). - * nul bytes stripped from input. - * 0241 (M-!) in a command substitution no longer lost. - * when read used in startup file, line continuation no longer causes crash. - * very long commands in history no longer cause vi to overwrite memory. - * easy history: when saving history, avoid going past the end of history. - * emacs mode no longer entered if EDITOR/VISUAL set to null string. - * command -p disabled in restricted mode. - * closed file descriptors are re-closed after a redirection. - * lone [ (test command) no longer causes globbing code to search directory. - * if TIMES_BROKEN is defined, ksh_times no longer recurses infinitely. - * `r r' no longer repeats r command forever. - * make depend no longer generates backslash followed by a blank line. - * globbing code now deals with symlinks that point to non-existent files. - * if the ] is missing in a pattern, the [ matches the [ character. - * syntax errors in test no longer have two newlines. - * in vi, G now goes to the oldest history (was newest). - * configuration: test for sys_siglist now harder for optimizers to break. - * configuration: look for clock_t in sys/times.h. - * configuration: use _SIGMAX, if available, for # of signals. - * SIGHUP now causes builtin read command to exit. - * wait builtin now returns whenever a traped signal occurs as per POSIX. - -* v command now works in vi; anchored searches now work in vi mode (/^ptrn); - multi-line commands displayed correctly by history. - -* echo is now schizophrenic: accepts -n/-e/-E and backslash sequences. - -* test -H file added (checks for context dependent files on HPs). - -* set -o gmacs and markdirs honoured. - -* ansi arrow keys in default emacs key bindings. - -* ulimit now takes arithmetic expression (as per Korn book). - -* co-processes changed to be more compatible with at&t ksh. - -Version 5.0.9 - -* bug fixes - * FOO is put in the environment for FOO=bar exec blah. - * compiles under QNX and with dmake. - * the file pattern [!a--]* is now invalid (POSIX) (used to match everything) - * echo "${foo:-"a"}*" no longer the same as echo a*. - * alternation (brace expansion) fixes: - * brace expansion done after variable expansion, as in csh/at&t ksh. - * `echo a{b,c' no longer gives "Missing }" error (it echos a{b,c). - * expansion only done if there is a comma (ie, `echo {a}' prints {a}). - * globbing/expansion code passes 0x80 unharmed. - * "echo ${XX=a*b}" no longer sets XX to "a\200*b". - * "echo ${unset-a*b}" no longer has \200 in the error message. - * bad substitution error generated for things like ${x:a}, ${x^a}, etc. - * `x="a cdef"; echo ${x#a c}' now prints "def" instead of "a a cdef". - * on systems where /etc/passwd//// is a valid name, echo /etc/pass*/ no - longer matches /etc/passwd. - * trace output (set -x) flushed correctly, PS4 initialized. - * ulimit output ungarbled, code to use {set,get}ulimit (if available) - enabled. - * tilde expansion done in word part of ${foo-~/bar} - * when reading stdin (ie, ksh -s), no longer reads too much. - * shell handles i/o redirection and errors in builtin commands as per - POSIX (still have to sort out variable assignment errors). - * starting jobs that save/change/restore tty settings in the background - no longer messes up tty settings when job finishes. - * the pattern [a'-'z] now matches three characters, not 26, and - the pattern [ab']'] also matches three characters. - -* a mostly complete man page! (work is still in progress) - -* quoting inside $(..) mostly works. - -* error reporting has been orthogonalized. - -* brace expansion on by default (can be disabled with set +o braceexpand, or - set -o posix). - -* output of "set -o" now fits on a normal screen. - -* co-processes added (|&, read -p, print -p, etc.). - -* restricted mode added (for what its worth). - -* vi now prints meta characters with M- prefix, unless vi-show8 option is on. - -Version 5.0.8 - -* bug fixes - * two problems in fc (introduced in 5.0.7) - * install target in Makefile missing a dollar - -Version 5.0.7 - -* POSIX command command added - -* a few bug fixes - * now compiles with various options undefined (eg, VI, EMACS, JOBS). - * fixed typos in Makefile.in (maxext -> manext) and ksh.1 (\f -> \fP). - * CLK_TCK defined to correct value for FreeBSD 1.1.5 (and earlier?). - * original process group restored when an exec is done. - * the exit value of set is that of the last $(...) on the command line. - * ditto for a command with no command (eg, x=`false`). - * command variable assignments done before path search (so PATH=... x works) - and are added as they are processed (so A=1 B=$A works). - * variable assignments infront of function calls are exported to programs - inside the function. - * aliases with trailing space are only honoured in command contexts - if in posix mode. - -* make depend target added; install target warns if ksh not in /etc/shells. - -* set -o bgnice now does something. - -* vi mode: ESC is no longer a file completion command (too annoying). - -Version 5.0.6 - -* most reported bugs/problems fixed (all but two). - -* temporary files now created in $TMPDIR (if it is a sane path). - -Version 5.0.5 - -* function parsing POSIXized (function bodies can be any compound command, - redirections after functions effect function invocation, not the - instantiation, the () in a function definition now parsed as two tokens). - -* exit bultin now does stopped jobs check. - -* set -p/-o priviliged supported. - -* test builtin now believed to be completely posix. - -* a default path is now used when PATH is not set (defined in options.h). - -Version 5.0.4 - -* configuration checks for buggy opendir()s and setpgrp()s. - -* autoloading functions now supported. - -* functions can safely redefine themselves. - -Version 5.0.3 - -* hash command changed to "alias -t"; whence -p added; print -s added - (all as in at&t ksh); unalias -a added (POSIX). - -* test builtin POSIX complient - -* TMOUT parameter supported (at&t ksh: timeout interactive shells) - -Version 5.0.2 - -* trap/error handling changed to eliminate longjmp()s from signal handlers; - trap ERR added. - -* ksh conditional expressions ([[ .. ]]) supported. - -* arithmetic expressions (let, $((..)), etc.) now understand full C - integer expressions (except ++/-- and sizeof()). - -* typeset -L -R -Z -u -l added (as in at&t ksh) - -* at&t/posix $(( .. )) arithmetic expansions supported. - -Version 5.0.1 - -* set -e no longer effects commands executed as part of if/while/until/&&/||/! - condition. - -* posix ! keyword now recognized. - -* posix getopts; if not in posix mode, getopts will accept options starting - with + (at&t kshism) - -* syntax error messages improved (says what was unexpected/unmatched) - -Version 4.9+mun.5 - -* all known bugs related to job control fixed: - * fg,bg,jobs,wait,kill commands fully POSIX complient - * signals are no longer reported for foreground jobs killed by SIGINT and - SIGPIPE - * pipeline process groups now created more reliablely (was a problem - if first process exited before second process exec'd). - * "(: ; cat /etc/termcap) | sleep" nolonger hangs - -* save/restore tty mode if command succeeds/fails, respectively. Edit - mode (emacs,vi) no longer use old tty mode information - -* test command: added -h - -* alternations option renamed to braceexpand (eg, use set -o braceexpand). - Old usage (set -o alternations) still accepted (will disappear in next - version). - -* trap/kill now accept upper and lower case signal names. - -Version 4.9+mun.3 - -* here documents in functions now work properly - -* read command: added -s option, use REPLY if no variable specified - -* don't accept "while command; done" as a valid command - -* fg,bg,jobs,wait,kill commands mostly POSIX complient. - -* unset command: added POSIX -v option - -* set command: added -A option - -* handle ${array[@]} and ${array[*]} - -* compiles with old bsd 4.2 compiler (pcc) - -* new versions of etc/profile and etc/ksh.profile - -Version 4.9+mun.2 (versus 4.9) - -* directory/file structure has been re-arranged: - * moved files from sh directory up a level, deleted sh directory - * created misc directory, old ChangeLog,README,.. files moved to misc - -* now uses GNU autoconf for compilation. - -* no longer uses stdio FILE *'s for I/O redirection (most stdio - usage has been removed). Solves many porting problems caused by - dup'd file descriptors, forked processes and exiting. - -* removed lint from code (compiles with very few warning with gcc -O -Wall - -Wno-comment) - -* has array support (needs work but is pretty functional). - -* ulimit command now more functional on more machines. Compatable with at&t ksh. - -* command line and set option parsing cleaned up, POSIXized. - -* POSIX IFS handling. - -* many many small bug fixes (see ChangeLog) diff --git a/bin/pdksh/NOTES b/bin/pdksh/NOTES deleted file mode 100644 index 17f29108eda..00000000000 --- a/bin/pdksh/NOTES +++ /dev/null @@ -1,514 +0,0 @@ -$OpenBSD: NOTES,v 1.3 1996/10/01 02:05:29 downsj Exp $ - -General features of at&t ksh that are not (yet) in pdksh: - - exported aliases. - - exported functions. - - set -t. - - signals/traps not cleared during functions. - - trap DEBUG, local ERR and EXIT traps in functions. - - 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: - - some specials behave differently when unset (eg, IFS behaves like - " \t\n") others lose their special meaning. IFS/PATH taken care of, - still need to sort out some others (eg, TMOUT). - Parsing,Lexing: - - line numbers in errors are wrong for nested construct. Need to - keep track of the line a command started on (can use for LINENO - parameter as well). - - a $(..) expression nested inside double quotes inside another $(..) - isn't parsed correctly (eg, $(echo "foo$(echo ")")") ) - Commands,Execution: - - setting special parameters that have side effects when - changed/restored (ie, HISTFILE, OPTIND, RANDOM) in front - of a command (eg, HISTFILE=/foo/bar echo hi) effects the parent - shell. Note that setting other (not so special) parameters - does not effect the parent shell. - - `echo hi | exec cat -n' causes at&t to exit, `exec echo hi | cat -n' - does not. pdksh exits for neither. Don't think POSIX requires - an exit, but not sure. - - `echo foo | read bar; echo $bar' prints foo in at&t ksh, nothing - in pdksh (ie, the read is done in a seperate process in pdksh). - Misc: - -Known differences between pdksh & at&t ksh (that may change) - - vi: - - `^U': at&t: kills only what has been inserted, pdksh: kills to - start of line - - at&t ksh login shells say "Warning: you have running jobs" if you - try to exit when there are running jobs. An immediate second attempt - to exit will kill the jobs and exit. pdksh does not print a warning, - nor does it kill running jobs when it exits (it does warn/kill for - stopped jobs). - - TMOUT: at&t prints warning, then waits another 60 seconds. If on screwed - up serial line, the output could cause more input, so pdksh just - 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). - - 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). - This may get fixed in the future, but it may take a while. - - in pdksh, set +o lists the options that are currently set, in at&t ksh - 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. - - test: "test -f foo bar blah" is the same as "test -f foo" (the extra - arguments, of which there must be at least 2, are ignored) - pdksh - generates an error message (unexpected operator/operand "bar") as it - should. Sometimes used to test file globs (e.g., if test -f *.o; ...). - - if the command 'sleep 5 && /bin/echo blah' is run interactively and - is the sleep is stopped (^Z), the echo is run immediately in pdksh. - In at&t ksh, the whole thing is stopped. - -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 - (unless it's traped of course) - - typeset: - - at&t ksh overloads -u/-l options: for integers, means unsigned/long, - for strings means uppercase/lowercase; pdksh just has the - upper/lower case (which can be useful for integers when base > 10). - unsigned/long really should have their own options. - - at&t ksh can't have justified integer variables - (eg, typeset -iR5 j=10), pdksh can. - - in pdksh, number arguments for -L/-R/-Z/-i must follow the option - character, at&t allows it at the end of the option group (eg, - at&t ksh likes "typeset -iu5 j", pdksh wants "typeset -i5 -u j" - or "typeset -ui5 j"). Also, pdksh allows "typeset -i 5 j" (same - as "typeset -i5 j"), at&t ksh does not allow this. - - typeset -R: pdksh strips trailing space type characters (ie, - 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. - - (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 - variable fails due to an expression error: eg, - echo 2+ > /tmp/x - unset x; typeset -i x - read x < /tmp/x - echo still here - prints an error and then prints "still here", similarly for - unset x; typeset -i x - set +A x 1 2+ 3 - echo still here - and - unset x y; typeset -i x y; set +A y 10 20 30 - set +A x 1 1+y[2+] 3 - echo still here - pdksh exits a script in all the above cases. (note that both shells - exit for: - unset x; typeset -i x - for x in 1 2+ 3; do echo x=$x; done - echo still here - ). - - at&t ksh seems to allow function calls inside expressions - (eg, typeset -i x='y(2)') but they do not seem to be regular functions - nor math functions (eg, pow, exp) - anyone known anything about this? - - `set -o nounset; unset foo; echo ${#foo}`: at&t ksh prints 0; pdksh - generates error. Same for ${#foo[*]} and ${#foo[@]}. - - . file: at&t ksh parses the whole file before executing anything, - pdksh executes as it parses. This means aliases defined in the file - will affect how pdksh parses the file, but won't affect how at&t ksh - parses the file. Also means pdksh will not parse statements occuring - after a (executed) return statement. - - a return in $ENV in at&t ksh will cause the shell to exit, while in - pdksh it will stop executing the script (this is consistent with - what a return in .profile does in both shells). - - at&t ksh does file globbing for `echo "${foo:-"*"}"`, pdksh does not - (POSIX would seem to indicate pdksh is right). - - at&t ksh thinks ${a:##foo} is ok, pdksh doesn't. - - at&t does tilde expansion on here-document delimiters, pdksh does - not. eg. - $ cat << ~michael - ~michael - $ - works for pdksh, not for at&t ksh (POSIX seems to agree with pdksh). - - in at&t ksh, tracked aliases have the export flag implicitly set - and tracked aliases and normal aliases live in the same name space - (eg, "alias" will list both tracked and normal aliases). - in pdksh, -t does not imply -x (since -x doesn't do anything yet), and - tracked/normal aliases live in seperate name spaces. - in at&t ksh, alias accepts + options (eg, +x, +t) - pdksh does not. - in pdksh, alias has a -d option to allow examination/changing of - cached ~ entries, also unalias has -d and -t options (unalias -d - is useful if the ~ cache gets out of date - not sure how at&t deals - with this problem (it does cache ~ entries)). - - at&t ksh will stop a recursive function after about 60 calls; pdksh - will not since the limit is arbitrary and can't be controlled - by the user (hit ^C if you get in trouble). - - the wait command (with and without arguments) in at&t ksh will wait for - stopped jobs when job control is enabled. pdksh doesn't. - - at&t ksh automatically sets the bgnice option for interactive shells; - pdksh does not. - - in at&t ksh, "eval `false`; echo $?" prints 1, pdksh prints 0 (which - is what POSIX says it should). Same goes for "wait `false`; echo $?". - (same goes for "set `false`; echo $?" if posix option is set - some - scripts that use the old getopt depend on this, so be careful about - setting the posix option). - - in at&t ksh, print -uX and read -uX are interrperted as -u with no - argument (defaults to 1 and 0 respectively) and -X (which may or - may not be a valid flag). In pdksh, -uX is interpreted as file - descriptor X. - - in at&t ksh, some signals (HUP, INT, QUIT) cause the read to exit, others - (ie, everything else) do not. When it does cause exiting, anything read - to that point is used (usually an empty line) and read returns with 0 - status. pdksh currently does similar things, but for TERM as well and - the exit status is 128+<signal-number> - in future, pdksh's read will - do this for all signals that are normally fatal as required by POSIX. - (POSIX does not require the setting of variables to null so applications - shouldn't rely on this). - - in pdksh, ! substitution done before variable substitution; in at&t ksh - it is done after substitution (and therefor may do ! substitutions on - the result of variable substitutions). POSIX doesn't say which is to be - done. - - 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: - $(( x[2] )) does the expected, $(( $x[2] )) doesn't. - - `typeset -R3 X='x '; echo "($X)"` produces ( x) - trailing - spaces are stripped. - - typeset -R turns off Z flag. - - both shells have the following mis-feature: - $ x='function xx { - cat -n <<- EOF - here we are in xx - EOF - }' - $ (eval "$x"; (sleep 2; xx) & echo bye) - [1] 1234 - bye - $ xx: /tmp/sh1234.1: cannot open - - bizarre special handling of alias/export/readonly/typeset arguments - $ touch a=a; typeset a=[ab]; echo "$a" - a=[ab] - $ x=typeset; $x a=[ab]; echo "$a" - a=a - $ - - both ignore SIGTSTP,SIGTTIN,SIGTTOU in exec'd processes when talking - and not monitoring (at&t ksh kind of does this). Doesn't really make - sense. - (Note that ksh.att -ic 'set +m; check-sigs' shows TSTP et al aren't - ignored, while ksh.att -ic 'set +m^J check-sigs' does... very strange) - - when tracing (set -x), and a command's stderr is redirected, the trace - output is also redirected. so "set -x; echo foo 2> /tmp/O > /dev/null" - will create /tmp/foo with the lines "+ > /dev/null" and "+ echo foo". - - undocumented at&t ksh feature: FPATH is searched after PATH if no - executable is found, even if typeset -uf wasn't used. - -at&t ksh bugs: - [various versions: - MIPS m120 RISC/os 5.0: Version 11/16/88d - Dec alpha osf/1 v1.3: OSF/1 Version 11/16/88d NLS - HP pa HP-UX 9.01: Version 11/16/88 - ] - - (only hpux) - $ _[2]=hi - Bus error (core dumped) - - (only riscos, hpux) - $ typeset x[ - $ - - (only osf/1) - $ A=B cat << EOF - .$A. - EOF - Segmentation fault(coredump) - $ - - (only osf/1) - $ read "?foo " - foo Foo - $ set | grep Foo - =Foo - $ - - (all) - $ typeset -i A - $ typeset -L3 A - $ typeset -l A - Illegal instruction (core dumped) - - (all) - $ for i in a b c ; do echo $i, ${i[2]}, ${i[10]} ; done - a, , - a, , b - a, , c - $ - - (all) - $ echo ${abc:-G { I } K } - G { I K } - $ - $ abc=hi - $ echo ${abc:-G { I } K } - hi K } - $ - The second echo should only have printed `hi'. - - (all) - $ echo ${abc:- > foo} - syntax error: > unexpected - $ - - (all? hpux) read reads too much from pipe (when pipe isn't stdin) - print 'hi\nthere' | ksh 8<&0 0< /dev/tty - $ read -u8 x - $ print $x - hi - $ cat 0<&8 - $ read -u8 y - $ print $y - there - $ - - (all) - $ umask 0 - $ umask - 00 - $ - - (osf, mips, !hpux) - $ exec alias - alias: not found - (shell dead) - - (all) non-white space IFS in non-substitution not preserved - $ IFS="$IFS:" - $ echo : "$@" # this is ok - : - $ echo :"$@" # this should print : too (me thinks) - - $ - - (only osf/1) - $ set +m - $ sleep 1 & # wait for a sec or two - $ jobs - Memory fault (core dumped) - - (all) - $ (sleep 1 & echo hi) & - [1] 123 - $ [1] 234 - hi - - (osf/1, mips) - $ getopts abc optc -a -b -c - $ getopts abc optc -a -b -c - $ getopts abc optc -a - Memory fault (core dumped) - - (osf/1) POSIX says OPTIND shall be initialized to 1 - $ echo $OPTIND - 0 - $ - - (osf/1 + others?) - $ typeset -ri r=10 - $ let r=12 - $ echo $r - 12 - $ - - (osf/1 + others?) - $ typeset -i a - $ typeset -L3 a - Memory fault (core dumped) - - (osf/1 + others?): -L strips leading \ \t\n\r, -R only strips trailing - spaces - $ typeset -L3 x - $ x=' ^I^J^M 2' - $ echo "($x)" - (2 ) - $ typeset -R3 y - $ x='2^I^J^M ' - $ echo "($x)" - (^I^J^M) - $ - - (osf/1 + others?) - $ typeset +i RANDOM - Memory fault (core dumped) - - (osf/1 + others?): -L/-R/-Z clear -l/-u after assignment and vise versa - $ typeset -u x=ab - $ echo "($x)" - (AB) - $ typeset -L4 x=def - $ echo "($x)" - (DEF ) - $ typeset | grep ' x$' - leftjust 4 x - $ - $ typeset -L4 x=def - $ echo "($x)" - (def ) - $ typeset -u x=ab - $ echo "($x)" - (AB ) - $ typeset | grep ' x$' - uppercase x - $ - $ typeset -i x - $ x='2()' - $ x='()' - $ x='2(4)' - - (osf/1, others?) - $ unset foo - $ echo "${foo:-"*"}" - <results of * expansion> - $ - - (osf/1, others?) - $ alias blah - blah: alias not found - $ alias -x blah | grep blah - blah - $ type blah - Memory fault (core dumped) - - (osf/1, others?) - $ trap 'echo hi; false' ERR - $ false - hi - hi - .... - Memory fault (core dumped) - - (osf/1, others?) - $ typeset +i ERRNO - Memory fault (core dumped) - - (osf/1, others?) - $ X=abcdef - $ echo ${X#a{b,c}e} # does not match {} inside word part of ${..#..} - abcdefe} - $ - - (osf/1, others?) - $ x=f=abcdef - $ echo ${f#a|abc} - def - $ echo ${f#abc|a} - bcdef - $ echo ${f#abc|a|d} - abcdef - $ - - (osf/1, hp-ux, others?) - $ i() echo hi - $ typeset -f - function i - { - hi - $ - - (osf/1, others?) - $ function X { - echo start of X - function Y { - echo in Y - } - echo end of X - } - $ X - start of X - end of X - $ typeset -f - function X - { - echo start of X - function Y { - echo in Y - } - echo end of X - } - function Y - { - echo in Y - echo end of X - } - } - $ - - (osf/1, others?) - $ while read x; do print -r "A $x"; done |& - [1] 18212 - $ exec 8<&p - $ kill %1 - Memory fault - - (osf/1, others?) Error only happens for builtin commands (/bin/echo works) - $ while read x; do print -r "A $x"; done |& - [1] 18212 - $ echo hi <&p - hi - $ echo hi <&p - ksh: p: bad file unit number - $ while read x; do print -r "A $x"; done |& - ksh: process already exists - $ - - (osf/1, others?) in restricted shells, command -p should not work. - $ PATH=/tmp ksh -r - $ print hi | command -p cat -n - 1 hi - $ - - (osf/1, others?) error message wrong for autoload files that don't define - functions - $ FPATH=/tmp - $ echo echo hi there > /tmp/aja - $ aja - hi there - ksh: echo: not found - $ - -POSIX sh questions (references are to POSIX 1003.2-1992) - - arithmetic expressions: how are empty expressions treated? - (eg, echo $(( ))). at&t ksh (and now pdksh) echo 0. - Same question goes for `test "" -eq 0' - does this generate an error - or, if not, what is the exit code? - - should tilde expansion occur after :'s in the word part of ${..=..}? - (me thinks it should) - - if a signal is received during the execution of a built-in, - does the builtin command exit or the whole shell? - - is it legal to execute last command of pipeline in current - execution environment (eg, can "echo foo | read bar" set - bar?) - - what action should be taken if there is an error doing a dup due - to system limits (eg, not enough feil destriptors): is this - a "redirection error" (in which case a script will exit iff the - error occured while executing a special built-in)? - IMHO, shell should exit script. Couldn't find a blanket statement - like "if shell encounters an unexpected system error, it shall - exit non-interactive scripts"... - -POSIX sh bugs (references are to POSIX 1003.2-1992) - - in vi insert mode, ^W deletes to beginning of line or to the first - blank/punct character (para at line 9124, section 3). This means - "foo ^W" will do nothing. This is inconsistent with the vi - spec, which says delete preceding word including and interceding - blanks (para at line 5189, section 5). - - parameter expansion, section 3.6.2, line 391: `in each case that a - value of word is needed (..), word shall be subjected to tilde - expansion, parameter expansion, ...'. Various expansions should not - be performed if parameter is in double quotes. - - the getopts description says assigning OPTIND a value other than 1 - produces undefined results, while the rationale for getopts suggests - saving/restoring the OPTIND value inside functions (since POSIX - functions don't do the save/restore automatically). Restoring - OPTIND is kind of dumb since getopts may have been in the middle - of parsing a group of flags (eg, -abc). - - unclear whether arithmetic expressions (eg, $((..))) should - understand C integer constants (ie, 0x123, 0177). at&t ksh doesn't - and neither does pdksh. - - `...` definition (3.6.3) says nothing about backslash followed by - a newline, which sh and at&t ksh strip out completely. e.g., - $ show-args `echo 'X - Y'` - Number of args: 1 - 1: <XY> - $ - POSIX would indicate the backslash-newline would be preserved. - - does not say how "cat << ''" is to be treated (illegal, read 'til - blank line, or read 'til eof). at&t ksh reads til eof, bourne shell - reads 'til blank line. pdksh reads 'til blank line. diff --git a/bin/pdksh/PROJECTS b/bin/pdksh/PROJECTS deleted file mode 100644 index 917960ca4a0..00000000000 --- a/bin/pdksh/PROJECTS +++ /dev/null @@ -1,112 +0,0 @@ -$OpenBSD: PROJECTS,v 1.3 1996/10/01 02:05:30 downsj Exp $ - -Things to be done in pdksh (see also the NOTES file): - - * builtin utilities: - pdksh has most if not all POSIX/at&t ksh builtins, but they need to - be checked that they conform to POSIX/at&t manual. Part of the - process is changing the builtins to use the ksh_getopt() routine. - - The following builtins, which are defined by POSIX, haven't been - examined: - eval time - - The first pass has been done on the following commands: - . : alias bg break cd continue echo exec exit export false fc fg - getopts jobs kill pwd read readonly return set shift trap true umask - unalias unset wait - - The second pass (ie, believed to be completely POSIX) has been done on - the following commands: - test - - (ulimit also needs to be examined to check it fits the posix style) - - * test suite - Ideally, as the builtin utilities are being POSIXized, short tests - should be written to be used in regression testing. The tests - directory contains some tests, but many more need to be written. - - * internationalization - Need to handle with the LANG and LC_* environment variables. This - involves changes to ensure <ctype.h> macros are being used (currently - uses its own macros in many places), figuring out how to deal with - bases (for integer arithmetic, eg, 12#1A), and (the nasty one) doing - string look ups for error messages, etc.. It probably isn't worth - translating strings to other languages yet as the code is likely - to change a lot in the near future, but it would be good to have the - code set up so string tables can be used. - - * trap code - * add the DEBUG trap. - * fix up signal handling code. In particular, fatal vs tty signals, - have signal routine to call to check for pending/fatal traps, etc. - - * parsing - * the time keyword needs to be hacked to accept options (!) since - POSIX says it shall accept the -p option and must skip a -- argument - (end of options). Yuck. - - * lexing - the lexing may need a re-write since it currently doesn't parse $( .. ), - $(( .. )), (( ... )) properly. - * need to ignore contents of quoted strings (and escaped chars?) - inside $( .. ) and $(( .. )) when counting parentheses. - * need to put bounds check on states[] array (if it still exists after - the re-write) - - * variables - * The "struct tbl" that is currently used for variables needs work since - more information (eg, array stuff, fields) are needed for variables - but not for the other things that use "struct tbl". - * Arrays need to be implemented differently: currently does a linear - search of a linked list to find element i; the linked list is not - freed when a variable is unset. - - * 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 - EASY_HISTORY, which need to be merged. COMPLEX does at&t style history - where the history file is written after each command and checked when - ever looking through the history (in case another shell has added - something). EASY simply reads the history file at startup and writes - it before exiting. - * re-write the COMPLEX_HISTORY code so mmap() not needed (currently - can't be used on machines without mmap()). - * Add multiline knowledge to COMPLEX_HISTORY (see EASY_HISTORY - stuff). - * change COMPLEX_HISTORY code so concurrent history files are - controlled by an option (set -o history-concurrent?). Delete - the EASY_HISTORY code. - * bring history code up to POSIX standards (see POSIX description - of fc, etc.). - - * documentation - Some sort of tutorial with examples would be good. Texinfo is probably - the best medium for this. Also, the man page could be converted to - texinfo (if the tutorial and man page are put in the same texinfo - page, they should be somewhat distinct - i.e., the tutorial should - be a separate thread - but there should be cross references between the - two). - - * miscellaneous - * POSIX specifies what happens when various kinds of errors occur - in special built-ins commands vs regular commands (builtin or - otherwise) (see POSIX.2:3.8.1). Some of this has been taken - care of, but more needs doing. - - * 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); 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. - - * teach shf_vfprintf() about long long's (%lld); also make %p use - long longs if appropriate. diff --git a/bin/pdksh/README b/bin/pdksh/README deleted file mode 100644 index f12f85b0ede..00000000000 --- a/bin/pdksh/README +++ /dev/null @@ -1,190 +0,0 @@ -$OpenBSD: README,v 1.5 1996/11/21 07:59:26 downsj Exp $ - -Last updated October '96 for pdksh-5.2.12. - (check ftp://ftp.cs.mun.ca:/pub/pdksh/ or - http://www.cs.mun.ca/~michael/pdksh/ for new versions/patches) - -PD-ksh is a mostly complete AT&T ksh look-alike (see NOTES file for a list -of things not supported). Work is currently underway to make it fully -compatible with both POSIX and AT&T ksh (when the two don't conflict). - -Since pdksh is free and compiles and runs on most common unix systems, it -is very useful in creating a consistent user interface across multiple -machines. For example, in the CS dept. of MUN, pdksh is installed on a -variety of machines including Suns, HPs, DecStations, pcs running Linux, -etc., and is the login shell of ~5200 users. - -PDksh is currently being maintained by Michael Rendell (michael@cs.mun.ca), -who took over from Simon J. Gerraty (sjg@zen.void.oz.au) at the later's -suggestion. A short list of things that have been added since the last -public pdksh release (4.9) are auto-configuration, arrays, $(( .. )), -[[ .. ]], variable attributes, co-processes, extended file globbing, -many POSIXisms and many bug fixes. See the NEWS and ChangeLog files for -other features added and bugs fixed. - -Note that pdksh is provided AS IS, with NO WARRANTY, either expressed or -implied. Also note that although the bulk of the code in pdksh is in the -public domain, some files are copyrighten (but freely distributable) and -subject to certain conditions (eg, don't remove copyright, document any -changes, etc.). See the LEGAL file for details. - -If you would like to be notified via email of new releases as they become -available, send mail to pdksh-request@cs.mun.ca with subject -"send release notifications" (or "don't send release notifications" to stop -them). - - -Files of interest: - NEWS short list of noticeable changes in various versions. - CONTRIBUTORS short history of pdksh, people who contributed, etc. - NOTES lists of known bugs in pdksh, at&t ksh, and posix. - PROJECTS list of things that need to be done in pdksh. - BUG-REPORTS list of recently reported bugs that have been fixed - and all reported bugs that haven't been fixed. - LEGAL A file detailing legal issues concerning pdksh. - etc/* system profile and kshrc files used by Simon J. Gerraty. - misc/README* readme files from previous versions. - misc/Changes* changelog files from previous versions. - os2/* files and info needed to compile ksh on os/2. - tests/* pdksh's regression testing system. - - -Compiling/Installing: - - The quick way: - ./configure - make - make check # optional - make install # will install /usr/local/bin/ksh - # and /usr/local/man/man1/ksh.1 - [add path-to-installed-pdksh to /etc/shells] - - The more detailed description: - * run "configure --help | your-favorite-pager" and look at the - --enable-* and --disable-* options (they are at the end). - Select any you options you wish to enable/disable - (most people can skip this step). - * run configure: this is a GNU autoconf configure script that will generate - a Makefile and a config.h. Some of the useful options to configure are: - --prefix=PATH indicates the directory tree under which the binary - and man page are installed (ie, PATH/bin/ksh and - PATH/man/man1/ksh.1). - The default prefix is /usr/local. - --exec-prefix=PATH overrides --prefix for machine dependent files - (ie, the ksh binary) - --program-prefix=pd install binary and man page as pdksh and pdksh.1 - --verbose show what is being defined as script runs - Note that you don't have to build in the source directory. To build - in a separate directory, do something like: - $ mkdir objs - $ cd objs - $ ../configure --verbose - .... - $ make - See the file INSTALL for a more complete description of configure and its - generic options (ksh specific options are documented in the --help output) - * miscellaneous configuration notes: - * If your make doesn't understand VPATH, you must compile in - the source directory. - * On DecStations, MIPS and SONY machines with older C compilers that - can't handle "int * volatile x", you should use gcc or turn off - optimization. The problem is configure defines volatile to nothing - since the compiler can't handle it properly, but the compiler does - optimizations that the volatile is meant to prevent. So. Use gcc. - * On MIPS RISC/os 5.0 systems, sysv environment, <signal.h> is - messed up - it defines sigset_t, but not any of the rest of - the posix signals (the sigset_t typedef should be in the - ifdef KERNEL section) - also doesn't have waitpid() or wait3(). - Things compile up ok in the svr4 environment, but it dumps core - in __start (perhaps our system doesn't have the full svr4 - environ?). Try compiling in the bsd43 environ instead (still not - perfect - see BUG-REPORTS file), using gcc - cc has problems with - macro expansions in the argument of a macro (in this case, the ARGS - macro). - * On TitanOS (Stardent/Titan), use `CC="cc -43" configure ...'. - When configure finishes, edit config.h, undef HAVE_DIRENT_H and - define HAVE_SYS_DIR_H (the dirent.h header file is broken). - * On Linux (red hat distribution), check that /dev/tty has mode 0666 - (not mode 0644). If it has the wrong permissions, ksh will print - warnings about not being able to do job control. - * on NeXT machines (3.2, probably other releases), the siglist.out file - won't be generated correctly if you try to use the system's compiler - (it has a broken cc -E and strange header files). There are two - ways to make it work: - 1) if you have gcc, use it (for everything). Alternatively, - force configure to use it for CPP, i.e., use - CPP="gcc -E" configure ... - 2) Force configure to use some extra CPPFLAGS, using - CPPFLAGS="XXX" configure ... - where XXX is obtained from running "cc -v YYY.c" on some - C file. Look at the options passed to cpp (there are lots - of them...) and replace the XXX above with them. - Make sure you do a "make distclean" (or "rm config.cache") if - you re-run configure with a difference CPP or CPPFLAGS. - Also note that if you are building multiple arch binaries, you - will have to specify both CC and CPP. - * run make: everything should compile and link without problems. - * run make check: this fires up a perl script that checks for some known - and some fixed bugs. The script prints pass/fail for tests it expected - to pass/fail, and PASS/FAIL for tests it expected to fail/pass. If you - don't have perl, or if your perl doesn't work (most common problem is - the .ph header files are missing or broken), you can run - ENV= path-to-pdksh-executable misc/Bugs path-to-pdksh-executable - instead. - * run make install: this installs ksh (in /usr/local/bin/ksh by default, - or where ever you told configure to put things). - * add path-to-installed-pdksh to /etc/shells if it's not already there. - This is only needed if you intend to use pdksh as a login shell (things - like ftp won't allow users to connect in if their shell isn't in this - file). - -The following is a list of machines that pdksh is reported to work on: - -/PC Linux 1.x,2.x - -/PC NetBSD 0.9a - -/PC BSDI 1.1 - -/PC FreeBSD 2.0, 2.1 - -/PC OpenBSD - -/PC Interactive/Sunsoft 3.0.1 and 4.1 (note that problems have been - reported with isc3.2 - see the BUG-REPORTS file) - -/PC OS/2 - Commadore/Amiga NetBSD 1.0 - Dec/alpha OSF/1 v2.x, v3.x - Dec/alpha NetBSD 1.1B - Dec/pmax Ultrix 4.2 - Dec/vax Ultrix 2.2 (not tested recently :-)) - Dec/vax 4.3BSD+NFS (MtXinu) (not tested recently :-)) - HP/pa HP-UX 9.01 - IBM/RS/6000 AIX 3.2.5 - MIPS/m120 RISC/os 5.0 (bsd43 environ) - NeXT NeXTStep 3.2 - SGI/IRIX 6.2 - Sun/sun4 SunOS 4.1.3, 4.1.4 - Sun/sun4 Solaris 2.x - Sun/sun386i SunOS 4.0.2 - Sun/sun3 SunOS 4.0.3, 4.1.1_U1 - Stardent/TitanOS 4.2 - - -Newer versions of pdksh may be available from - ftp://ftp.cs.mun.ca:/pub/pdksh/ -you may want to check for one if you run into any problems, as the problem may -already be fixed (you can get new release notifications automatically - see -above). - -You can send bug reports, fixes, and enchancements to pdksh@cs.mun.ca (please -don't assume I will see bug reports that are posted to some newsgroup or -mailing list - I probably won't). -If you are reporting a bug (with or without a fix), please include - * the version of pdksh you are using (see version.c, or, if you are - running pdksh, try echo $KSH_VERSION), - * the machine, operating system and compiler you are using, - * and a description of how to repeat the bug (a small shell - script that demonstrates the bug is best). -as well as the following, if relevant (if you aren't sure, include them) - * what options you are using (both configure options and set -o options) - * the output of configure, with the verbose flag - (eg, make distclean; ./configure --verbose) - * the contents of config.log (this is created by the configure script) - * if you are using gcc (the GNU C compiler), which version it is. - -Michael Rendell, michael@cs.mun.ca. diff --git a/bin/pdksh/alloc.c b/bin/pdksh/alloc.c deleted file mode 100644 index bc39b1bc045..00000000000 --- a/bin/pdksh/alloc.c +++ /dev/null @@ -1,288 +0,0 @@ -/* $OpenBSD: alloc.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */ - -/* - * area-based allocation built on malloc/free - */ - -#include "sh.h" -#ifdef MEM_DEBUG -# undef alloc -# undef aresize -# undef afree -#endif /* MEM_DEBUG */ - -#define ICELLS 100 /* number of Cells in small Block */ - -typedef union Cell Cell; -typedef struct Block Block; - -/* - * The Cells in a Block are organized as a set of objects. - * Each object (pointed to by dp) begins with a size in (dp-1)->size, - * followed with "size" data Cells. Free objects are - * linked together via dp->next. - */ - -union Cell { - size_t size; - Cell *next; - struct {int _;} junk; /* alignment */ -}; - -struct Block { - Block *next; /* list of Blocks in Area */ - Cell *freelist; /* object free list */ - Cell *last; /* &b.cell[size] */ - Cell cell [1]; /* [size] Cells for allocation */ -}; - -static Block aempty = {&aempty, aempty.cell, aempty.cell}; - -/* create empty Area */ -Area * -ainit(ap) - register Area *ap; -{ - ap->freelist = &aempty; - return ap; -} - -/* free all object in Area */ -void -afreeall(ap) - register Area *ap; -{ - register Block *bp; - register Block *tmp; - - bp = ap->freelist; - if (bp != NULL && bp != &aempty) { - do { - tmp = bp->next; - free((void*)bp); - bp = tmp; - } while (bp != ap->freelist); - ap->freelist = &aempty; - } -} - -/* allocate object from Area */ -void * -alloc(size, ap) - size_t size; - register Area *ap; -{ - int cells, split; - register Block *bp; - register Cell *dp, *fp, *fpp; - - if (size <= 0) { - aerror(ap, "allocate bad size"); - return NULL; - } - cells = (unsigned)(size - 1) / sizeof(Cell) + 1; - - /* find Cell large enough */ - for (bp = ap->freelist; ; bp = bp->next) { - for (fpp = NULL, fp = bp->freelist; - fp != bp->last; fpp = fp, fp = fpp->next) - if ((fp-1)->size >= cells) - goto Found; - - /* wrapped around Block list, create new Block */ - if (bp->next == ap->freelist) { - bp = (Block*) malloc(offsetof(Block, cell[ICELLS]) - + sizeof(bp->cell[0]) * cells); - if (bp == NULL) { - aerror(ap, "cannot allocate"); - return NULL; - } - if (ap->freelist == &aempty) - bp->next = bp; - else { - bp->next = ap->freelist->next; - ap->freelist->next = bp; - } - bp->last = bp->cell + ICELLS + cells; - fp = bp->freelist = bp->cell + 1; /* initial free list */ - (fp-1)->size = ICELLS + cells - 1; - fp->next = bp->last; - fpp = NULL; - break; - } - } - Found: - ap->freelist = bp; - dp = fp; /* allocated object */ - split = (dp-1)->size - cells; - if (split < 0) - aerror(ap, "allocated object too small"); - if (--split <= 0) { /* allocate all */ - fp = fp->next; - } else { /* allocate head, free tail */ - (fp-1)->size = cells; - fp += cells + 1; - (fp-1)->size = split; - fp->next = dp->next; - } - if (fpp == NULL) - bp->freelist = fp; - else - fpp->next = fp; - return (void*) dp; -} - -/* change size of object -- like realloc */ -void * -aresize(ptr, size, ap) - register void *ptr; - size_t size; - Area *ap; -{ - int cells; - register Cell *dp = (Cell*) ptr; - - if (size <= 0) { - aerror(ap, "allocate bad size"); - return NULL; - } - cells = (unsigned)(size - 1) / sizeof(Cell) + 1; - - if (dp == NULL || (dp-1)->size < cells) { /* enlarge object */ - /* XXX check for available adjacent free block */ - ptr = alloc(size, ap); - if (dp != NULL) { - memcpy(ptr, dp, (dp-1)->size * sizeof(Cell)); - afree((void *) dp, ap); - } - } else { /* shrink object */ - int split; - - split = (dp-1)->size - cells; - if (--split <= 0) /* cannot split */ - ; - else { /* shrink head, free tail */ - (dp-1)->size = cells; - dp += cells + 1; - (dp-1)->size = split; - afree((void*)dp, ap); - } - } - return (void*) ptr; -} - -void -afree(ptr, ap) - void *ptr; - register Area *ap; -{ - register Block *bp; - register Cell *fp, *fpp; - register Cell *dp = (Cell*)ptr; - - /* find Block containing Cell */ - for (bp = ap->freelist; ; bp = bp->next) { - if (bp->cell <= dp && dp < bp->last) - break; - if (bp->next == ap->freelist) { - aerror(ap, "freeing with invalid area"); - return; - } - } - - /* find position in free list */ - for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fpp->next) - ; - - if (fp == dp) { - aerror(ap, "freeing free object"); - return; - } - - /* join object with next */ - if (dp + (dp-1)->size == fp-1) { /* adjacent */ - (dp-1)->size += (fp-1)->size + 1; - dp->next = fp->next; - } else /* non-adjacent */ - dp->next = fp; - - /* join previous with object */ - if (fpp == NULL) - bp->freelist = dp; - else if (fpp + (fpp-1)->size == dp-1) { /* adjacent */ - (fpp-1)->size += (dp-1)->size + 1; - fpp->next = dp->next; - } else /* non-adjacent */ - fpp->next = dp; -} - -#if DEBUG_ALLOC -void -aprint(ap, ptr, size) - register Area *ap; - void *ptr; - size_t size; -{ - Block *bp; - - if (!ap) - shellf("aprint: null area pointer\n"); - else if (!(bp = ap->freelist)) - shellf("aprint: null area freelist\n"); - else if (bp == &aempty) - shellf("aprint: area is empty\n"); - else { - int i; - Cell *fp; - - for (i = 0; !i || bp != ap->freelist; bp = bp->next, i++) { - if (ptr) { - void *eptr = (void *) (((char *) ptr) + size); - /* print block only if it overlaps ptr/size */ - if (!((ptr >= (void *) bp - && ptr <= (void *) bp->last) - || (eptr >= (void *) bp - && eptr <= (void *) bp->last))) - continue; - shellf("aprint: overlap of 0x%p .. 0x%p\n", - ptr, eptr); - } - shellf("aprint: block %2d: 0x%p .. 0x%p (%d)\n", i, - bp->cell, bp->last, - (char *) bp->last - (char *) bp->cell); - for (fp = bp->freelist; fp != bp->last; fp = fp->next) - shellf( - "aprint: 0x%p .. 0x%p (%d) free\n", - (fp-1), (fp-1) + (fp-1)->size, - (fp-1)->size * sizeof(Cell)); - } - } -} -#endif /* DEBUG_ALLOC */ - - -#ifdef TEST_ALLOC - -Area a; - -main(int argc, char **argv) { - int i; - char *p [9]; - - ainit(&a); - for (i = 0; i < 9; i++) { - p[i] = alloc(124, &a); - printf("alloc: %x\n", p[i]); - } - for (i = 1; i < argc; i++) - afree(p[atoi(argv[i])], &a); - afreeall(&a); - return 0; -} - -void aerror(Area *ap, const char *msg) { - abort(); -} - -#endif - diff --git a/bin/pdksh/c_ksh.c b/bin/pdksh/c_ksh.c deleted file mode 100644 index 1435aa9c57d..00000000000 --- a/bin/pdksh/c_ksh.c +++ /dev/null @@ -1,1402 +0,0 @@ -/* $OpenBSD: c_ksh.c,v 1.7 1997/06/19 13:58:37 kstailey Exp $ */ - -/* - * built-in Korn commands: c_* - */ - -#include "sh.h" -#include "ksh_stat.h" -#include <ctype.h> - -int -c_cd(wp) - char **wp; -{ - int optc; - int physical = Flag(FPHYSICAL); - int cdnode; /* was a node from cdpath added in? */ - int printpath = 0; /* print where we cd'd? */ - int rval; - struct tbl *pwd_s, *oldpwd_s; - XString xs; - char *xp; - char *dir, *try, *pwd; - int phys_path; - char *cdpath; - - while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF) - switch (optc) { - case 'L': - physical = 0; - break; - case 'P': - physical = 1; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - if (Flag(FRESTRICTED)) { - bi_errorf("restricted shell - can't cd"); - return 1; - } - - pwd_s = global("PWD"); - oldpwd_s = global("OLDPWD"); - - if (!wp[0]) { - /* No arguments - go home */ - if ((dir = str_val(global("HOME"))) == null) { - bi_errorf("no home directory (HOME not set)"); - return 1; - } - } else if (!wp[1]) { - /* One argument: - or dir */ - dir = wp[0]; - if (strcmp(dir, "-") == 0) { - dir = str_val(oldpwd_s); - if (dir == null) { - bi_errorf("no OLDPWD"); - return 1; - } - printpath++; - } - } else if (!wp[2]) { - /* Two arguments - substitute arg1 in PWD for arg2 */ - int ilen, olen, nlen, elen; - char *cp; - - if (!current_wd[0]) { - bi_errorf("don't know current directory"); - return 1; - } - /* substitue arg1 for arg2 in current path. - * if the first substitution fails because the cd fails - * we could try to find another substitution. For now - * we don't - */ - if ((cp = strstr(current_wd, wp[0])) == (char *) 0) { - bi_errorf("bad substitution"); - return 1; - } - ilen = cp - current_wd; - olen = strlen(wp[0]); - nlen = strlen(wp[1]); - elen = strlen(current_wd + ilen + olen) + 1; - dir = alloc(ilen + nlen + elen, ATEMP); - memcpy(dir, current_wd, ilen); - memcpy(dir + ilen, wp[1], nlen); - memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); - printpath++; - } else { - bi_errorf("too many arguments"); - return 1; - } - - Xinit(xs, xp, PATH, ATEMP); - /* xp will have a bogus value after make_path() - set it to 0 - * so that if it's used, it will cause a dump - */ - xp = (char *) 0; - - cdpath = str_val(global("CDPATH")); - do { - cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path); -#ifdef S_ISLNK - if (physical) - rval = chdir(try = Xstring(xs, xp) + phys_path); - else -#endif /* S_ISLNK */ - { - simplify_path(Xstring(xs, xp)); - rval = chdir(try = Xstring(xs, xp)); - } - } while (rval < 0 && cdpath != (char *) 0); - - if (rval < 0) { - if (cdnode) - bi_errorf("%s: bad directory", dir); - else - bi_errorf("%s - %s", try, strerror(errno)); - return 1; - } - - /* Clear out tracked aliases with relative paths */ - flushcom(0); - - /* Set OLDPWD */ - if (current_wd[0]) - setstr(oldpwd_s, current_wd); - - if (!ISABSPATH(Xstring(xs, xp))) { -#ifdef OS2 - /* simplify_path() doesn't know about os/2's drive contexts, - * so it can't set current_wd when changing to a:foo. - * Handle this by calling getcwd()... - */ - pwd = ksh_get_wd((char *) 0, 0); -#else /* OS2 */ - pwd = (char *) 0; -#endif /* OS2 */ - } else -#ifdef S_ISLNK - if (!physical || !(pwd = get_phys_path(Xstring(xs, xp)))) -#endif /* S_ISLNK */ - pwd = Xstring(xs, xp); - - /* Set PWD */ - if (pwd) { - set_current_wd(pwd); - setstr(pwd_s, pwd); - } else { - set_current_wd(null); - pwd = Xstring(xs, xp); - /* XXX unset $PWD? */ - } - if (printpath || cdnode) - shprintf("%s\n", pwd); - - return 0; -} - -int -c_pwd(wp) - char **wp; -{ - int optc; - int physical = Flag(FPHYSICAL); - char *p; - - while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF) - switch (optc) { - case 'L': - physical = 0; - break; - case 'P': - physical = 1; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - if (wp[0]) { - bi_errorf("too many arguments"); - return 1; - } -#ifdef S_ISLNK - p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) - : (char *) 0; -#else /* S_ISLNK */ - p = current_wd[0] ? current_wd : (char *) 0; -#endif /* S_ISLNK */ - if (p && eaccess(p, R_OK) < 0) - p = (char *) 0; - if (!p) { - p = ksh_get_wd((char *) 0, 0); - if (!p) { - bi_errorf("can't get current directory - %s", - strerror(errno)); - return 1; - } - } - shprintf("%s\n", p); - return 0; -} - -int -c_print(wp) - char **wp; -{ -#define PO_NL BIT(0) /* print newline */ -#define PO_EXPAND BIT(1) /* expand backslash sequences */ -#define PO_PMINUSMINUS BIT(2) /* print a -- argument */ -#define PO_HIST BIT(3) /* print to history instead of stdout */ -#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ -#define PO_FSLASH BIT(5) /* swap slash for backslash (for os2 ) */ - int fd = 1; - int flags = PO_EXPAND|PO_NL; - char *s; - const char *emsg; - XString xs; - char *xp; - - if (wp[0][0] == 'e') { /* echo command */ - int nflags = flags; - - /* A compromise between sysV and BSD echo commands: - * escape sequences are enabled by default, and - * -n, -e and -E are recognized if they appear - * in arguments with no illegal options (ie, echo -nq - * will print -nq). - * Different from sysV echo since options are recognized, - * different from BSD echo since escape sequences are enabled - * by default. - */ - wp += 1; - while ((s = *wp) && *s == '-' && s[1]) { - while (*++s) - if (*s == 'n') - nflags &= ~PO_NL; - else if (*s == 'e') - nflags |= PO_EXPAND; - else if (*s == 'E') - nflags &= ~PO_EXPAND; - else - /* bad option: don't use nflags, print - * argument - */ - break; - if (*s) - break; - wp++; - flags = nflags; - } - } else { - int optc; -#if OS2 - const char *options = "Rnpfrsu,"; /* added f flag */ -#else - const char *options = "Rnprsu,"; -#endif - while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) - switch (optc) { - case 'R': /* fake BSD echo command */ - flags |= PO_PMINUSMINUS; - flags &= ~PO_EXPAND; - options = "ne"; - break; - case 'e': - flags |= PO_EXPAND; - break; -#ifdef OS2 - case 'f': - flags |= PO_FSLASH; - break; -#endif - case 'n': - flags &= ~PO_NL; - break; -#ifdef KSH - case 'p': - if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { - bi_errorf("-p: %s", emsg); - return 1; - } - break; -#endif /* KSH */ - case 'r': - flags &= ~PO_EXPAND; - break; - case 's': - flags |= PO_HIST; - break; - case 'u': - if (!*(s = builtin_opt.optarg)) - fd = 0; - else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { - bi_errorf("-u: %s: %s", s, emsg); - return 1; - } - break; - case '?': - return 1; - } - if (!(builtin_opt.info & GI_MINUSMINUS)) { - /* treat a lone - like -- */ - if (wp[builtin_opt.optind] - && strcmp(wp[builtin_opt.optind], "-") == 0) - builtin_opt.optind++; - } else if (flags & PO_PMINUSMINUS) - builtin_opt.optind--; - wp += builtin_opt.optind; - } - - Xinit(xs, xp, 128, ATEMP); - - while (*wp != NULL) { - register int c; - s = *wp; - while ((c = *s++) != '\0') { - Xcheck(xs, xp); -#ifdef OS2 - if ((flags & PO_FSLASH) && c == '\\') - if (*s == '\\') - *s++; - else - c = '/'; -#endif /* OS2 */ - if ((flags & PO_EXPAND) && c == '\\') { - int i; - - switch ((c = *s++)) { - /* Oddly enough, \007 seems more portable than - * \a (due to HP-UX cc, Ultrix cc, old pcc's, - * etc.). - */ - case 'a': c = '\007'; break; - case 'b': c = '\b'; break; - case 'c': flags &= ~PO_NL; - continue; /* AT&T brain damage */ - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = 0x0B; break; - case '0': - /* Look for an octal number: can have - * three digits (not counting the - * leading 0). Truely burnt. - */ - c = 0; - for (i = 0; i < 3; i++) { - if (*s >= '0' && *s <= '7') - c = c*8 + *s++ - '0'; - else - break; - } - break; - case '\0': s--; c = '\\'; break; - case '\\': break; - default: - Xput(xs, xp, '\\'); - } - } - Xput(xs, xp, c); - } - if (*++wp != NULL) - Xput(xs, xp, ' '); - } - if (flags & PO_NL) - Xput(xs, xp, '\n'); - - if (flags & PO_HIST) { - Xput(xs, xp, '\0'); - source->line++; - histsave(source->line, Xstring(xs, xp), 1); - Xfree(xs, xp); - } else { - int n, len = Xlength(xs, xp); - 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 - * not enough). - */ - if (coproc.write >= 0 && coproc.write == fd) { - flags |= PO_COPROC; - opipe = block_pipe(); - } -#endif /* KSH */ - for (s = Xstring(xs, xp); len > 0; ) { - n = write(fd, s, len); - if (n < 0) { -#ifdef KSH - if (flags & PO_COPROC) - restore_pipe(opipe); -#endif /* KSH */ - if (errno == EINTR) { - /* allow user to ^C out */ - intrcheck(); -#ifdef KSH - if (flags & PO_COPROC) - opipe = block_pipe(); -#endif /* KSH */ - continue; - } -#ifdef KSH - /* 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; -} - -int -c_whence(wp) - char **wp; -{ - struct tbl *tp; - char *id; - int pflag = 0, vflag = 0, Vflag = 0; - int ret = 0; - int optc; - int iam_whence = wp[0][0] == 'w'; - int fcflags; - const char *options = iam_whence ? "pv" : "pvV"; - - while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) - switch (optc) { - case 'p': - pflag = 1; - break; - case 'v': - vflag = 1; - break; - case 'V': - Vflag = 1; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - - fcflags = FC_BI | FC_PATH | FC_FUNC; - if (!iam_whence) { - /* Note that -p on its own is deal with in comexec() */ - if (pflag) - fcflags |= FC_DEFPATH; - /* Convert command options to whence options - note that - * command -pV uses a different path search than whence -v - * or whence -pv. This should be considered a feature. - */ - vflag = Vflag; - } - if (pflag) - fcflags &= ~(FC_BI | FC_FUNC); - - while ((vflag || ret == 0) && (id = *wp++) != NULL) { - tp = NULL; - if ((iam_whence || vflag) && !pflag) - tp = tsearch(&keywords, id, hash(id)); - if (!tp && !pflag) { - tp = tsearch(&aliases, id, hash(id)); - if (tp && !(tp->flag & ISSET)) - tp = NULL; - } - if (!tp) - tp = findcom(id, fcflags); - if (vflag || (tp->type != CALIAS && tp->type != CEXEC - && tp->type != CTALIAS)) - shprintf("%s", id); - switch (tp->type) { - case CKEYWD: - if (vflag) - shprintf(" is a reserved word"); - break; - case CALIAS: - if (vflag) - shprintf(" is an %salias for ", - (tp->flag & EXPORT) ? "exported " - : null); - if (!iam_whence && !vflag) - shprintf("alias %s=", id); - print_value_quoted(tp->val.s); - break; - case CFUNC: - if (vflag) { - shprintf(" is a"); - if (tp->flag & EXPORT) - shprintf("n exported"); - if (tp->flag & TRACE) - shprintf(" traced"); - if (!(tp->flag & ISSET)) { - shprintf(" undefined"); - if (tp->u.fpath) - shprintf(" (autoload from %s)", - tp->u.fpath); - } - shprintf(" function"); - } - break; - case CSHELL: - if (vflag) - shprintf(" is a%s shell builtin", - (tp->flag & SPEC_BI) ? " special" : null); - break; - case CTALIAS: - case CEXEC: - if (tp->flag & ISSET) { - if (vflag) { - shprintf(" is "); - if (tp->type == CTALIAS) - shprintf( - "a tracked %salias for ", - (tp->flag & EXPORT) ? - "exported " - : null); - } - shprintf("%s", tp->val.s); - } else { - if (vflag) - shprintf(" not found"); - ret = 1; - } - break; - default: - shprintf("%s is *GOK*", id); - break; - } - if (vflag || !ret) - shprintf(newline); - } - return ret; -} - -/* Deal with command -vV - command -p dealt with in comexec() */ -int -c_command(wp) - char **wp; -{ - /* Let c_whence do the work. Note that c_command() must be - * a distinct function from c_whence() (tested in comexec()). - */ - return c_whence(wp); -} - -/* typeset, export, and readonly */ -int -c_typeset(wp) - char **wp; -{ - struct block *l = e->loc; - struct tbl *vp, **p; - 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; - Tflag flag; - int pflag = 0; - - switch (**wp) { - case 'e': /* export */ - fset |= EXPORT; - options = "p"; - break; - case 'r': /* readonly */ - fset |= RDONLY; - options = "p"; - break; - case 's': /* set */ - /* called with 'typeset -' */ - break; - case 't': /* typeset */ - local = 1; - break; - } - - fieldstr = basestr = (char *) 0; - builtin_opt.flags |= GF_PLUSOPT; - /* at&t ksh seems to have 0-9 as options, which are multiplied - * to get a number that is used with -L, -R, -Z or -i (eg, -1R2 - * sets right justify in a field of 12). This allows options - * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and - * does not allow the number to be specified as a seperate argument - * Here, the number must follow the RLZi option, but is optional - * (see the # kludge in ksh_getopt()). - */ - while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) { - flag = 0; - switch (optc) { - case 'L': - flag |= LJUST; - fieldstr = builtin_opt.optarg; - break; - case 'R': - flag |= RJUST; - fieldstr = builtin_opt.optarg; - break; - case 'U': - /* at&t ksh uses u, but this conflicts with - * upper/lower case. If this option is changed, - * need to change the -U below as well - */ - flag |= INT_U; - break; - case 'Z': - flag |= ZEROFIL; - fieldstr = builtin_opt.optarg; - break; - case 'f': - func = 1; - break; - case 'i': - flag |= INTEGER; - basestr = builtin_opt.optarg; - break; - case 'l': - flag |= LCASEV; - break; - case 'p': /* posix export/readonly -p flag */ - pflag = 1; - break; - case 'r': - flag |= RDONLY; - break; - case 't': - flag |= TRACE; - break; - case 'u': - flag |= UCASEV_AL; /* upper case / autoload */ - break; - case 'x': - flag |= EXPORT; - break; - case '?': - return 1; - } - if (builtin_opt.info & GI_PLUS) { - fclr |= flag; - fset &= ~flag; - thing = '+'; - } else { - fset |= flag; - fclr &= ~flag; - thing = '-'; - } - } - - field = 0; - if (fieldstr && !bi_getn(fieldstr, &field)) - return 1; - base = 0; - if (basestr && !bi_getn(basestr, &base)) - return 1; - - if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] - && (wp[builtin_opt.optind][0] == '-' - || wp[builtin_opt.optind][0] == '+') - && wp[builtin_opt.optind][1] == '\0') - { - thing = wp[builtin_opt.optind][0]; - builtin_opt.optind++; - } - - if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) { - bi_errorf("only -t, -u and -x options may be used with -f"); - return 1; - } - if (wp[builtin_opt.optind]) { - /* Take care of exclusions */ - /* setting these attributes clears the others, unless they - * are also set in this command - */ - if (fset & (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER - |INT_U|INT_L)) - fclr |= ~fset & - (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER - |INT_U|INT_L); - fclr &= ~fset; /* set wins */ - if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { - fset |= RJUST; - fclr &= ~RJUST; - } - if (fset & LCASEV) /* LCASEV has priority */ - fclr |= UCASEV_AL; - else if (fset & UCASEV_AL) - fclr |= LCASEV; - if (fset & LJUST) /* LJUST has priority */ - fclr |= RJUST; - else if (fset & RJUST) - fclr |= LJUST; - if ((fset | fclr) & INTEGER) { - if (!(fset | fclr) & INT_U) - fclr |= INT_U; - if (!(fset | fclr) & INT_L) - fclr |= INT_L; - } - fset &= ~fclr; /* in case of something like -LR */ - } - - /* set variables and attributes */ - if (wp[builtin_opt.optind]) { - int i; - int rval = 0; - struct tbl *f; - - if (local && !func) - fset |= LOCAL; - for (i = builtin_opt.optind; wp[i]; i++) { - if (func) { - f = findfunc(wp[i], hash(wp[i]), - (fset&UCASEV_AL) ? TRUE : FALSE); - if (!f) { - /* at&t ksh does ++rval: bogus */ - rval = 1; - continue; - } - if (fset | fclr) { - f->flag |= fset; - f->flag &= ~fclr; - } else - fptreef(shl_stdout, 0, - "function %s %T\n", - wp[i], f->val.t); - } else if (!typeset(wp[i], fset, fclr, field, base)) { - bi_errorf("%s: not identifier", wp[i]); - return 1; - } - } - return rval; - } - - /* list variables and attributes */ - flag = fset | fclr; /* no difference at this point.. */ - if (func) { - for (l = e->loc; l; l = l->next) { - for (p = tsort(&l->funs); (vp = *p++); ) { - if (flag && (vp->flag & flag) == 0) - continue; - if (thing == '-') - fptreef(shl_stdout, 0, "function %s %T\n", - vp->name, vp->val.t); - else - shprintf("%s\n", vp->name); - } - } - } else { - for (l = e->loc; l; l = l->next) { - for (p = tsort(&l->vars); (vp = *p++); ) - for (; vp; vp = vp->u.array) { - /* Report an unset param only if the user has - * explicitly given it some attribute (like export); - * otherwise, after "echo $FOO", we would report FOO... - */ - if (!(vp->flag & ISSET) && !(vp->flag & USERATTRIB)) - continue; - if (flag && (vp->flag & flag) == 0) - continue; - /* no arguments */ - if (thing == 0 && flag == 0) { - /* at&t ksh prints things like export, integer, - * leftadj, zerofill, etc., but POSIX says must - * be suitable for re-entry... - */ - shprintf("typeset "); - if ((vp->flag&INTEGER)) - shprintf("-i "); - if ((vp->flag&EXPORT)) - shprintf("-x "); - if ((vp->flag&RDONLY)) - shprintf("-r "); - if ((vp->flag&TRACE)) - shprintf("-t "); - if ((vp->flag&LJUST)) - shprintf("-L%d ", vp->u2.field); - if ((vp->flag&RJUST)) - shprintf("-R%d ", vp->u2.field); - if ((vp->flag&ZEROFIL)) - shprintf("-Z "); - if ((vp->flag&LCASEV)) - shprintf("-l "); - if ((vp->flag&UCASEV_AL)) - shprintf("-u "); - if ((vp->flag&INT_U)) - shprintf("-U "); - if (vp->flag&ARRAY) - shprintf("%s[%d]\n", vp->name,vp->index); - else - shprintf("%s\n", vp->name); - } else { - if (pflag) - shprintf("%s ", - (flag & EXPORT) ? "export" : "readonly"); - if (vp->flag&ARRAY) - shprintf("%s[%d]", vp->name, vp->index); - else - shprintf("%s", vp->name); - if (thing == '-' && (vp->flag&ISSET)) { - char *s = str_val(vp); - - shprintf("="); - /* at&t ksh can't have justified integers.. */ - if ((vp->flag & (INTEGER|LJUST|RJUST)) - == INTEGER) - shprintf("%s", s); - else - print_value_quoted(s); - } - shprintf(newline); - } - } - } - } - return 0; -} - -int -c_alias(wp) - char **wp; -{ - struct table *t = &aliases; - int rv = 0, rflag = 0, tflag, Uflag = 0; - Tflag xflag = 0; - int optc; - - while ((optc = ksh_getopt(wp, &builtin_opt, "drtUx")) != EOF) - switch (optc) { - case 'd': - t = &homedirs; - break; - case 'r': - rflag = 1; - break; - case 't': - t = &taliases; - break; - case 'U': /* kludge for tracked alias initialization - * (don't do a path search, just make an entry) - */ - Uflag = 1; - break; - case 'x': - xflag = EXPORT; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - tflag = t == &taliases; - - /* "hash -r" means reset all the tracked aliases.. */ - if (rflag) { - static const char *const args[] = { - "unalias", "-ta", (const char *) 0 - }; - - if (!tflag || *wp) { - shprintf( - "alias: -r flag can only be used with -t and without arguments\n"); - return 1; - } - ksh_getopt_reset(&builtin_opt, GF_ERROR); - return c_unalias((char **) args); - } - - if (*wp == NULL) { - struct tbl *ap, **p; - - for (p = tsort(t); (ap = *p++) != NULL; ) - if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { - shprintf("%s=", ap->name); - print_value_quoted(ap->val.s); - shprintf(newline); - } - } - - for (; *wp != NULL; wp++) { - char *alias = *wp; - char *val = strchr(alias, '='); - char *newval; - struct tbl *ap; - int h; - - if (val) - alias = str_nsave(alias, val++ - alias, ATEMP); - h = hash(alias); - if (val == NULL && !tflag && !xflag) { - ap = tsearch(t, alias, h); - if (ap != NULL && (ap->flag&ISSET)) { - shprintf("%s=", ap->name); - print_value_quoted(ap->val.s); - shprintf(newline); - } else { - shprintf("%s alias not found\n", alias); - rv = 1; - } - continue; - } - ap = tenter(t, alias, h); - ap->type = tflag ? CTALIAS : CALIAS; - /* Are we setting the value or just some flags? */ - if ((val && !tflag) || (!val && tflag && !Uflag)) { - if (ap->flag&ALLOC) { - ap->flag &= ~(ALLOC|ISSET); - afree((void*)ap->val.s, APERM); - } - /* ignore values for -t (at&t ksh does this) */ - newval = tflag ? search(alias, path, X_OK, (int *) 0) - : val; - if (newval) { - ap->val.s = str_save(newval, APERM); - ap->flag |= ALLOC|ISSET; - } else - ap->flag &= ~ISSET; - } - ap->flag |= DEFINED|xflag; - if (val) - afree(alias, ATEMP); - } - - return rv; -} - -int -c_unalias(wp) - char **wp; -{ - register struct table *t = &aliases; - register struct tbl *ap; - int rv = 0, all = 0; - int optc; - - while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != EOF) - switch (optc) { - case 'a': - all = 1; - break; - case 'd': - t = &homedirs; - break; - case 't': - t = &taliases; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - for (; *wp != NULL; wp++) { - ap = tsearch(t, *wp, hash(*wp)); - if (ap == NULL) { - rv = 1; /* POSIX */ - continue; - } - if (ap->flag&ALLOC) { - ap->flag &= ~(ALLOC|ISSET); - afree((void*)ap->val.s, APERM); - } - ap->flag &= ~(DEFINED|ISSET|EXPORT); - } - - if (all) { - struct tstate ts; - - for (twalk(&ts, t); (ap = tnext(&ts)); ) { - if (ap->flag&ALLOC) { - ap->flag &= ~(ALLOC|ISSET); - afree((void*)ap->val.s, APERM); - } - ap->flag &= ~(DEFINED|ISSET|EXPORT); - } - } - - return rv; -} - -#ifdef KSH -int -c_let(wp) - char **wp; -{ - int rv = 1; - long val; - - if (wp[1] == (char *) 0) /* at&t ksh does this */ - bi_errorf("no arguments"); - else - for (wp++; *wp; wp++) - if (!evaluate(*wp, &val, TRUE)) { - rv = 2; /* distinguish error from zero result */ - break; - } else - rv = val == 0; - return rv; -} -#endif /* KSH */ - -int -c_jobs(wp) - char **wp; -{ - int optc; - int flag = 0; - int nflag = 0; - int rv = 0; - - while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != EOF) - switch (optc) { - case 'l': - flag = 1; - break; - case 'p': - flag = 2; - break; - case 'n': - nflag = 1; - break; - case 'z': /* debugging: print zombies */ - nflag = -1; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - if (!*wp) - if (j_jobs((char *) 0, flag, nflag)) - rv = 1; - else - for (; *wp; wp++) - if (j_jobs(*wp, flag, nflag)) - rv = 1; - return rv; -} - -#ifdef JOBS -int -c_fgbg(wp) - char **wp; -{ - int bg = strcmp(*wp, "bg") == 0; - int UNINITIALIZED(rv); - - if (!Flag(FMONITOR)) { - bi_errorf("job control not enabled"); - return 1; - } - if (ksh_getopt(wp, &builtin_opt, null) == '?') - return 1; - wp += builtin_opt.optind; - if (*wp) - for (; *wp; wp++) - rv = j_resume(*wp, bg); - else - rv = j_resume("%%", bg); - /* POSIX says fg shall return 0 (unless an error occurs). - * at&t ksh returns the exit value of the job... - */ - return (bg || Flag(FPOSIX)) ? 0 : rv; -} -#endif - -struct kill_info { - int num_width; - int name_width; -}; -static char *kill_fmt_entry ARGS((void *arg, int i, char *buf, int buflen)); - -/* format a single kill item */ -static char * -kill_fmt_entry(arg, i, buf, buflen) - void *arg; - int i; - char *buf; - int buflen; -{ - struct kill_info *ki = (struct kill_info *) arg; - - i++; - if (sigtraps[i].name) - shf_snprintf(buf, buflen, "%*d %*s %s", - ki->num_width, i, - ki->name_width, sigtraps[i].name, - sigtraps[i].mess); - else - shf_snprintf(buf, buflen, "%*d %*d %s", - ki->num_width, i, - ki->name_width, sigtraps[i].signal, - sigtraps[i].mess); - return buf; -} - - -int -c_kill(wp) - char **wp; -{ - Trap *t = (Trap *) 0; - char *p; - int lflag = 0; - int i, n, rv, sig; - - /* assume old style options if -digits or -UPPERCASE */ - if ((p = wp[1]) && *p == '-' && (digit(p[1]) || isupper(p[1]))) { - if (!(t = gettrap(p + 1))) { - bi_errorf("bad signal `%s'", p + 1); - return 1; - } - i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; - } else { - int optc; - - while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != EOF) - switch (optc) { - case 'l': - lflag = 1; - break; - case 's': - if (!(t = gettrap(builtin_opt.optarg))) { - bi_errorf("bad signal `%s'", - builtin_opt.optarg); - return 1; - } - case '?': - return 1; - } - i = builtin_opt.optind; - } - if ((lflag && t) || (!wp[i] && !lflag)) { - shf_fprintf(shl_out, -"Usage: kill [ -s signame | -signum | -signame ] {pid|job}...\n\ - kill -l [exit_status]\n" - ); - bi_errorf(null); - return 1; - } - - if (lflag) { - if (wp[i]) { - for (; wp[i]; i++) { - if (!bi_getn(wp[i], &n)) - return 1; - if (n > 128 && n < 128 + SIGNALS) - n -= 128; - if (n > 0 && n < SIGNALS && sigtraps[n].name) - shprintf("%s\n", sigtraps[n].name); - else - shprintf("%d\n", n); - } - } else if (Flag(FPOSIX)) { - p = null; - for (i = 1; i < SIGNALS; i++, p = space) - if (sigtraps[i].name) - shprintf("%s%s", p, sigtraps[i].name); - shprintf(newline); - } else { - int w, i; - int mess_width; - struct kill_info ki; - - for (i = SIGNALS, ki.num_width = 1; i >= 10; i /= 10) - ki.num_width++; - ki.name_width = mess_width = 0; - for (i = 0; i < SIGNALS; i++) { - w = sigtraps[i].name ? strlen(sigtraps[i].name) - : ki.num_width; - if (w > ki.name_width) - ki.name_width = w; - w = strlen(sigtraps[i].mess); - if (w > mess_width) - mess_width = w; - } - - print_columns(shl_stdout, SIGNALS - 1, - kill_fmt_entry, (void *) &ki, - ki.num_width + ki.name_width + mess_width + 3); - } - return 0; - } - rv = 0; - sig = t ? t->signal : SIGTERM; - for (; (p = wp[i]); i++) { - if (*p == '%') { - if (j_kill(p, sig)) - rv = 1; - } else if (!getn(p, &n)) { - bi_errorf("%s: arguments must be jobs or process ids", - p); - rv = 1; - } else { - /* use killpg if < -1 since -1 does special things for - * some non-killpg-endowed kills - */ - if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) < 0) { - bi_errorf("%s: %s", p, strerror(errno)); - rv = 1; - } - } - } - return rv; -} - -static Getopt user_opt; /* parsing state for getopts builtin command */ -static int getopts_noset; /* stop OPTIND assign from resetting state */ - -void -getopts_reset(val) - int val; -{ - if (!getopts_noset && val >= 1) { - ksh_getopt_reset(&user_opt, - GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT)); - user_opt.optind = val; - } -} - -int -c_getopts(wp) - char **wp; -{ - int argc; - const char *options; - const char *var; - int optc; - char buf[3]; - struct tbl *vq; - - if (ksh_getopt(wp, &builtin_opt, null) == '?') - return 1; - wp += builtin_opt.optind; - - options = *wp++; - if (!options) { - bi_errorf("missing options argument"); - return 1; - } - - var = *wp++; - if (!var) { - bi_errorf("missing name argument"); - return 1; - } - if (!*var || *skip_varname(var, TRUE)) { - bi_errorf("%s: is not an identifier", var); - return 1; - } - - if (e->loc->next == (struct block *) 0) { - internal_errorf(0, "c_getopts: no argv"); - return 1; - } - /* Which arguments are we parsing... */ - if (*wp == (char *) 0) - wp = e->loc->next->argv; - else - *--wp = e->loc->next->argv[0]; - - /* Check that our saved state won't cause a core dump... */ - for (argc = 0; wp[argc]; argc++) - ; - if (user_opt.optind > argc - || (user_opt.p != 0 - && user_opt.p > strlen(wp[user_opt.optind - 1]))) - { - bi_errorf("arguments changed since last call"); - return 1; - } - - user_opt.optarg = (char *) 0; - optc = ksh_getopt(wp, &user_opt, options); - - if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { - buf[0] = '+'; - buf[1] = optc; - buf[2] = '\0'; - } else { - /* POSIX says var is set to ? at end-of-options, at&t ksh - * sets it to null - we go with POSIX... - */ - buf[0] = optc < 0 ? '?' : optc; - buf[1] = '\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); - - 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 optc < 0 ? 1 : 0; -} - -#ifdef EMACS -int -c_bind(wp) - char **wp; -{ - int rv = 0, macro = 0, list = 0; - register char *cp; - int optc; - - while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != EOF) - switch (optc) { - case 'l': - list = 1; - break; - case 'm': - macro = 1; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - if (*wp == NULL) /* list all */ - rv = x_bind((char*)NULL, (char*)NULL, 0, list); - - for (; *wp != NULL; wp++) { - cp = strchr(*wp, '='); - if (cp != NULL) - *cp++ = '\0'; - if (x_bind(*wp, cp, macro, 0)) - rv = 1; - } - - return rv; -} -#endif - -/* A leading = means assignments before command are kept; - * a leading * means a POSIX special builtin; - * a leading + means a POSIX regular builtin - * (* and + should not be combined). - */ -const struct builtin kshbuiltins [] = { - {"+alias", c_alias}, /* no =: at&t manual wrong */ - {"+cd", c_cd}, - {"+command", c_command}, - {"echo", c_print}, - {"*=export", c_typeset}, -#ifdef HISTORY - {"+fc", c_fc}, -#endif /* HISTORY */ - {"+getopts", c_getopts}, - {"+jobs", c_jobs}, - {"+kill", c_kill}, -#ifdef KSH - {"let", c_let}, -#endif /* KSH */ - {"print", c_print}, - {"pwd", c_pwd}, - {"*=readonly", c_typeset}, - {"=typeset", c_typeset}, - {"+unalias", c_unalias}, - {"whence", c_whence}, -#ifdef JOBS - {"+bg", c_fgbg}, - {"+fg", c_fgbg}, -#endif -#ifdef EMACS - {"bind", c_bind}, -#endif - {NULL, NULL} -}; diff --git a/bin/pdksh/c_sh.c b/bin/pdksh/c_sh.c deleted file mode 100644 index 0691aa51af5..00000000000 --- a/bin/pdksh/c_sh.c +++ /dev/null @@ -1,787 +0,0 @@ -/* $OpenBSD: c_sh.c,v 1.6 1997/08/05 21:49:54 grr Exp $ */ - -/* - * built-in Bourne commands - */ - -#include "sh.h" -#include "ksh_stat.h" /* umask() */ -#include "ksh_time.h" -#include "ksh_times.h" - -static char *clocktos ARGS((clock_t t)); - -/* :, false and true */ -int -c_label(wp) - char **wp; -{ - return wp[0][0] == 'f' ? 1 : 0; -} - -int -c_shift(wp) - char **wp; -{ - register struct block *l = e->loc; - register int n; - long val; - char *arg; - - 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", arg); - return (1); - } - if (l->argc < n) { - bi_errorf("nothing to shift"); - return (1); - } - l->argv[n] = l->argv[0]; - l->argv += n; - l->argc -= n; - return 0; -} - -int -c_umask(wp) - char **wp; -{ - register int i; - register char *cp; - int symbolic = 0; - int old_umask; - int optc; - - while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF) - switch (optc) { - case 'S': - symbolic = 1; - break; - case '?': - return 1; - } - cp = wp[builtin_opt.optind]; - if (cp == NULL) { - old_umask = umask(0); - umask(old_umask); - if (symbolic) { - char buf[18]; - int j; - - old_umask = ~old_umask; - cp = buf; - for (i = 0; i < 3; i++) { - *cp++ = "ugo"[i]; - *cp++ = '='; - for (j = 0; j < 3; j++) - if (old_umask & (1 << (8 - (3*i + j)))) - *cp++ = "rwx"[j]; - *cp++ = ','; - } - cp[-1] = '\0'; - shprintf("%s\n", buf); - } else - shprintf("%#3.3o\n", old_umask); - } else { - int new_umask; - - if (digit(*cp)) { - for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++) - new_umask = new_umask * 8 + (*cp - '0'); - if (*cp) { - bi_errorf("bad number"); - return 1; - } - } else { - /* symbolic format */ - int positions, new_val; - char op; - - old_umask = umask(0); - umask(old_umask); /* in case of error */ - old_umask = ~old_umask; - new_umask = old_umask; - positions = 0; - while (*cp) { - while (*cp && strchr("augo", *cp)) - switch (*cp++) { - case 'a': positions |= 0111; break; - case 'u': positions |= 0100; break; - case 'g': positions |= 0010; break; - case 'o': positions |= 0001; break; - } - if (!positions) - positions = 0111; /* default is a */ - if (!strchr("=+-", op = *cp)) - break; - cp++; - new_val = 0; - while (*cp && strchr("rwxugoXs", *cp)) - switch (*cp++) { - case 'r': new_val |= 04; break; - case 'w': new_val |= 02; break; - case 'x': new_val |= 01; break; - case 'u': new_val |= old_umask >> 6; - break; - case 'g': new_val |= old_umask >> 3; - break; - case 'o': new_val |= old_umask >> 0; - break; - case 'X': if (old_umask & 0111) - new_val |= 01; - break; - case 's': /* ignored */ - break; - } - new_val = (new_val & 07) * positions; - switch (op) { - case '-': - new_umask &= ~new_val; - break; - case '=': - new_umask = new_val - | (new_umask & ~(positions * 07)); - break; - case '+': - new_umask |= new_val; - } - if (*cp == ',') { - positions = 0; - cp++; - } else if (!strchr("=+-", *cp)) - break; - } - if (*cp) { - bi_errorf("bad mask"); - return 1; - } - new_umask = ~new_umask; - } - umask(new_umask); - } - return 0; -} - -int -c_dot(wp) - char **wp; -{ - char *file, *cp; - char **argv; - int argc; - int i; - - if (ksh_getopt(wp, &builtin_opt, null) == '?') - return 1; - - if ((cp = wp[builtin_opt.optind]) == NULL) - return 0; - file = search(cp, path, R_OK, (int *) 0); - if (file == NULL) { - bi_errorf("%s: not found", cp); - return 1; - } - - /* Set positional parameters? */ - if (wp[builtin_opt.optind + 1]) { - argv = wp + builtin_opt.optind; - argv[0] = e->loc->argv[0]; /* preserve $0 */ - for (argc = 0; argv[argc + 1]; argc++) - ; - } else { - argc = 0; - argv = (char **) 0; - } - i = include(file, argc, argv, 0); - if (i < 0) { /* should not happen */ - bi_errorf("%s: %s", cp, strerror(errno)); - return 1; - } - return i; -} - -int -c_wait(wp) - char **wp; -{ - int UNINITIALIZED(rv); - int sig; - - if (ksh_getopt(wp, &builtin_opt, null) == '?') - return 1; - wp += builtin_opt.optind; - if (*wp == (char *) 0) { - while (waitfor((char *) 0, &sig) >= 0) - ; - rv = sig; - } else { - for (; *wp; wp++) - rv = waitfor(*wp, &sig); - if (rv < 0) - rv = sig ? sig : 127; /* magic exit code: bad job-id */ - } - return rv; -} - -int -c_read(wp) - char **wp; -{ - register int c = 0; - int expand = 1, history = 0; - int expanding; - int ecode = 0; - register char *cp; - int fd = 0; - struct shf *shf; - int optc; - const char *emsg; - XString cs, xs; - struct tbl *vp; - char UNINITIALIZED(*xp); - - while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF) - switch (optc) { -#ifdef KSH - case 'p': - if ((fd = coproc_getfd(R_OK, &emsg)) < 0) { - bi_errorf("-p: %s", emsg); - return 1; - } - break; -#endif /* KSH */ - case 'r': - expand = 0; - break; - case 's': - history = 1; - break; - case 'u': - if (!*(cp = builtin_opt.optarg)) - fd = 0; - else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) { - bi_errorf("-u: %s: %s", cp, emsg); - return 1; - } - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - if (*wp == NULL) - *--wp = "REPLY"; - - /* Since we can't necessarily seek backwards on non-regular files, - * don't buffer them so we can't read too much. - */ - shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare); - - if ((cp = strchr(*wp, '?')) != NULL) { - *cp = 0; - if (isatty(fd)) { - /* at&t ksh says it prints prompt on fd if it's open - * for writing and is a tty, but it doesn't do it - * (it also doesn't check the interactive flag, - * as is indicated in the Kornshell book). - */ - shellf("%s", cp+1); - } - } - -#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. 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); - */ -#endif /* KSH */ - - if (history) - Xinit(xs, xp, 128, ATEMP); - expanding = 0; - Xinit(cs, cp, 128, ATEMP); - for (; *wp != NULL; wp++) { - for (cp = Xstring(cs, cp); ; ) { - if (c == '\n' || c == EOF) - break; - while (1) { - c = shf_getc(shf); - if (c == '\0' -#ifdef OS2 - || c == '\r' -#endif /* OS2 */ - ) - continue; - if (c == EOF && shf_error(shf) - && shf_errno(shf) == EINTR) - { - /* Was the offending signal one that - * would normally kill a process? - * If so, pretend the read was killed. - */ - ecode = fatal_trap_check(); - - /* non fatal (eg, CHLD), carry on */ - if (!ecode) { - shf_clearerr(shf); - continue; - } - } - break; - } - if (history) { - Xcheck(xs, xp); - Xput(xs, xp, c); - } - Xcheck(cs, cp); - if (expanding) { - expanding = 0; - if (c == '\n') { - c = 0; - if (Flag(FTALKING) && isatty(fd)) { - /* set prompt in case this is - * called from .profile or $ENV - */ - set_prompt(PS2, (Source *) 0); - pprompt(prompt, 0); - } - } else if (c != EOF) - Xput(cs, cp, c); - continue; - } - if (expand && c == '\\') { - expanding = 1; - continue; - } - if (c == '\n' || c == EOF) - break; - if (ctype(c, C_IFS)) { - if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS)) - continue; - if (wp[1]) - break; - } - Xput(cs, cp, c); - } - /* strip trailing IFS white space from last variable */ - if (!wp[1]) - while (Xlength(cs, cp) && ctype(cp[-1], C_IFS) - && ctype(cp[-1], C_IFSWS)) - cp--; - Xput(cs, cp, '\0'); - vp = global(*wp); - if (vp->flag & RDONLY) { - shf_flush(shf); - bi_errorf("%s is read only", *wp); - return 1; - } - if (Flag(FEXPORT)) - typeset(*wp, EXPORT, 0, 0, 0); - setstr(vp, Xstring(cs, cp)); - } - - shf_flush(shf); - if (history) { - Xput(xs, xp, '\0'); - source->line++; - histsave(source->line, Xstring(xs, xp), 1); - Xfree(xs, xp); - } -#ifdef KSH - /* 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 */ - - return ecode ? ecode : c == EOF; -} - -int -c_eval(wp) - char **wp; -{ - register struct source *s; - - if (ksh_getopt(wp, &builtin_opt, null) == '?') - return 1; - s = pushs(SWORDS, ATEMP); - s->u.strv = wp + builtin_opt.optind; - return shell(s, FALSE); -} - -int -c_trap(wp) - char **wp; -{ - int i; - char *s; - register Trap *p; - - if (ksh_getopt(wp, &builtin_opt, null) == '?') - return 1; - wp += builtin_opt.optind; - - if (*wp == NULL) { - int anydfl = 0; - - for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) { - if (p->trap == NULL) - anydfl = 1; - else { - shprintf("trap -- "); - print_value_quoted(p->trap); - shprintf(" %s\n", p->name); - } - } -#if 0 /* this is ugly and not clear POSIX needs it */ - /* POSIX may need this so output of trap can be saved and - * used to restore trap conditions - */ - if (anydfl) { - shprintf("trap -- -"); - for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) - if (p->trap == NULL && p->name) - shprintf(" %s", p->name); - shprintf(newline); - } -#endif - return 0; - } - - s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */ - if (s != NULL && s[0] == '-' && s[1] == '\0') - s = NULL; - - /* set/clear traps */ - while (*wp != NULL) { - p = gettrap(*wp++); - if (p == NULL) { - bi_errorf("bad signal %s", wp[-1]); - return 1; - } - settrap(p, s); - } - return 0; -} - -int -c_exitreturn(wp) - char **wp; -{ - int how = LEXIT; - char *arg; - - 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", arg); - } - if (wp[0][0] == 'r') { /* return */ - struct env *ep; - - /* need to tell if this is exit or return so trap exit will - * work right (POSIX) - */ - for (ep = e; ep; ep = ep->oenv) - if (STOP_RETURN(ep->type)) { - how = LRETURN; - break; - } - } - - if (how == LEXIT && !really_exit && j_stopped_running()) { - really_exit = 1; - how = LSHELL; - } - - quitenv(); /* get rid of any i/o redirections */ - unwind(how); - /*NOTREACHED*/ - return 0; -} - -int -c_brkcont(wp) - char **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 (!arg) - n = 1; - 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("%s: bad value", arg); - return 1; - } - - /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ - for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) - if (ep->type == E_LOOP) { - if (--quit == 0) - break; - ep->flags |= EF_BRKCONT_PASS; - last_ep = ep; - } - - if (quit) { - /* at&t ksh doesn't print a message - just does what it - * can. We print a message 'cause it helps in debugging - * scripts, but don't generate an error (ie, keep going). - */ - if (n == quit) { - warningf(TRUE, "%s: cannot %s", wp[0], wp[0]); - return 0; - } - /* POSIX says if n is too big, the last enclosing loop - * shall be used. Doesn't say to print an error but we - * do anyway 'cause the user messed up. - */ - last_ep->flags &= ~EF_BRKCONT_PASS; - warningf(TRUE, "%s: can only %s %d level(s)", - wp[0], wp[0], n - quit); - } - - unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); - /*NOTREACHED*/ -} - -int -c_set(wp) - char **wp; -{ - int argi, setargs; - struct block *l = e->loc; - register char **owp = wp; - - if (wp[1] == NULL) { - static const char *const args [] = { "set", "-", NULL }; - return c_typeset((char **) args); - } - - argi = parse_args(wp, OF_SET, &setargs); - if (argi < 0) - return 1; - /* set $# and $* */ - if (setargs) { - owp = wp += argi - 1; - wp[0] = l->argv[0]; /* save $0 */ - while (*++wp != NULL) - *wp = str_save(*wp, &l->area); - l->argc = wp - owp - 1; - l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area); - for (wp = l->argv; (*wp++ = *owp++) != NULL; ) - ; - } - /* POSIX says set exit status is 0, but old scripts that use - * getopt(1), use the construct: set -- `getopt ab:c "$@"` - * which assumes the exit value set will be that of the `` - * (subst_exstat is cleared in execute() so that it will be 0 - * if there are no command substitutions). - */ - return Flag(FPOSIX) ? 0 : subst_exstat; -} - -int -c_unset(wp) - char **wp; -{ - register char *id; - int optc, unset_var = 1; - int ret = 0; - - while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF) - switch (optc) { - case 'f': - unset_var = 0; - break; - case 'v': - unset_var = 1; - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - for (; (id = *wp) != NULL; 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 */ - if (define(id, (struct op *) NULL)) - ret = 1; - } - return ret; -} - -int -c_times(wp) - char **wp; -{ - struct tms all; - - (void) ksh_times(&all); - shprintf("Shell: %8s user ", clocktos(all.tms_utime)); - shprintf("%8s system\n", clocktos(all.tms_stime)); - shprintf("Kids: %8s user ", clocktos(all.tms_cutime)); - shprintf("%8s system\n", clocktos(all.tms_cstime)); - - return 0; -} - -/* - * time pipeline (really a statement, not a built-in command) - */ -int -timex(t, f) - struct op *t; - int f; -{ - int rv; - struct tms t0, t1; - clock_t t0t, t1t; - extern clock_t j_usrtime, j_systime; /* computed by j_wait */ - - j_usrtime = j_systime = 0; - t0t = ksh_times(&t0); - rv = execute(t->left, f); - t1t = ksh_times(&t1); - - shf_fprintf(shl_out, "%8s real ", clocktos(t1t - t0t)); - shf_fprintf(shl_out, "%8s user ", - clocktos(t1.tms_utime - t0.tms_utime + j_usrtime)); - shf_fprintf(shl_out, "%8s system ", - clocktos(t1.tms_stime - t0.tms_stime + j_systime)); - shf_fprintf(shl_out, newline); - - return rv; -} - -static char * -clocktos(t) - clock_t t; -{ - static char temp[20]; - register int i; - register char *cp = temp + sizeof(temp); - - if (CLK_TCK != 100) /* convert to 1/100'ths */ - t = (t < 1000000000/CLK_TCK) ? - (t * 100) / CLK_TCK : (t / CLK_TCK) * 100; - - *--cp = '\0'; - *--cp = 's'; - for (i = -2; i <= 0 || t > 0; i++) { - if (i == 0) - *--cp = '.'; - *--cp = '0' + (char)(t%10); - t /= 10; - } - return cp; -} - -/* exec with no args - args case is taken care of in comexec() */ -int -c_exec(wp) - char ** wp; -{ - int i; - - /* make sure redirects stay in place */ - if (e->savefd != NULL) { - for (i = 0; i < NUFILE; i++) { - if (e->savefd[i] > 0) - close(e->savefd[i]); - /* keep anything > 2 private */ - if (!Flag(FSH) && i > 2 && e->savefd[i]) - fd_clexec(i); - } - e->savefd = NULL; - } - return 0; -} - -/* dummy function, special case in comexec() */ -int -c_builtin(wp) - char ** wp; -{ - return 0; -} - -extern int c_test ARGS((char **wp)); /* in c_test.c */ -extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */ - -/* A leading = means assignments before command are kept; - * a leading * means a POSIX special builtin; - * a leading + means a POSIX regular builtin - * (* and + should not be combined). - */ -const struct builtin shbuiltins [] = { - {"*=.", c_dot}, - {"*=:", c_label}, - {"[", c_test}, - {"*=break", c_brkcont}, - {"=builtin", c_builtin}, - {"*=continue", c_brkcont}, - {"*=eval", c_eval}, - {"*=exec", c_exec}, - {"*=exit", c_exitreturn}, - {"+false", c_label}, - {"*=return", c_exitreturn}, - {"*=set", c_set}, - {"*=shift", c_shift}, - {"=times", c_times}, - {"*=trap", c_trap}, - {"+=wait", c_wait}, - {"+read", c_read}, - {"test", c_test}, - {"+true", c_label}, - {"ulimit", c_ulimit}, - {"+umask", c_umask}, - {"*=unset", c_unset}, -#ifdef OS2 - /* In OS2, the first line of a file can be "extproc name", which - * tells the command interpreter (cmd.exe) to use name to execute - * the file. For this to be useful, ksh must ignore commands - * starting with extproc and this does the trick... - */ - {"extproc", c_label}, -#endif /* OS2 */ - {NULL, NULL} -}; diff --git a/bin/pdksh/c_test.c b/bin/pdksh/c_test.c deleted file mode 100644 index 16703ff4960..00000000000 --- a/bin/pdksh/c_test.c +++ /dev/null @@ -1,616 +0,0 @@ -/* $OpenBSD: c_test.c,v 1.4 1997/06/19 13:58:38 kstailey Exp $ */ - -/* - * test(1); version 7-like -- author Erik Baalbergen - * modified by Eric Gisin to be used as built-in. - * modified by Arnold Robbins to add SVR3 compatibility - * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). - * modified by Michael Rendell to add Korn's [[ .. ]] expressions. - * modified by J.T. Conklin to add POSIX compatibility. - */ - -#include "sh.h" -#include "ksh_stat.h" -#include "c_test.h" - -/* test(1) accepts the following grammar: - oexpr ::= aexpr | aexpr "-o" oexpr ; - aexpr ::= nexpr | nexpr "-a" aexpr ; - nexpr ::= primary | "!" nexpr ; - primary ::= unary-operator operand - | operand binary-operator operand - | operand - | "(" oexpr ")" - ; - - unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"| - "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"| - "-L"|"-h"|"-S"|"-H"; - - binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| - "-nt"|"-ot"|"-ef"| - "<"|">" # rules used for [[ .. ]] expressions - ; - operand ::= <any thing> -*/ - -#define T_ERR_EXIT 2 /* POSIX says > 1 for errors */ - -struct t_op { - char op_text[4]; - Test_op op_num; -}; -static const struct t_op u_ops [] = { - {"-a", TO_FILAXST }, - {"-b", TO_FILBDEV }, - {"-c", TO_FILCDEV }, - {"-d", TO_FILID }, - {"-e", TO_FILEXST }, - {"-f", TO_FILREG }, - {"-G", TO_FILGID }, - {"-g", TO_FILSETG }, - {"-h", TO_FILSYM }, - {"-H", TO_FILCDF }, - {"-k", TO_FILSTCK }, - {"-L", TO_FILSYM }, - {"-n", TO_STNZE }, - {"-O", TO_FILUID }, - {"-o", TO_OPTION }, - {"-p", TO_FILFIFO }, - {"-r", TO_FILRD }, - {"-s", TO_FILGZ }, - {"-S", TO_FILSOCK }, - {"-t", TO_FILTT }, - {"-u", TO_FILSETU }, - {"-w", TO_FILWR }, - {"-x", TO_FILEX }, - {"-z", TO_STZER }, - {"", TO_NONOP } - }; -static const struct t_op b_ops [] = { - {"=", TO_STEQL }, -#ifdef KSH - {"==", TO_STEQL }, -#endif /* KSH */ - {"!=", TO_STNEQ }, - {"<", TO_STLT }, - {">", TO_STGT }, - {"-eq", TO_INTEQ }, - {"-ne", TO_INTNE }, - {"-gt", TO_INTGT }, - {"-ge", TO_INTGE }, - {"-lt", TO_INTLT }, - {"-le", TO_INTLE }, - {"-ef", TO_FILEQ }, - {"-nt", TO_FILNT }, - {"-ot", TO_FILOT }, - {"", TO_NONOP } - }; - -static int test_stat ARGS((const char *path, struct stat *statb)); -static int test_eaccess ARGS((const char *path, int mode)); -static int test_oexpr ARGS((Test_env *te, int do_eval)); -static int test_aexpr ARGS((Test_env *te, int do_eval)); -static int test_nexpr ARGS((Test_env *te, int do_eval)); -static int test_primary ARGS((Test_env *te, int do_eval)); -static int ptest_isa ARGS((Test_env *te, Test_meta meta)); -static const char *ptest_getopnd ARGS((Test_env *te, Test_op op, int do_eval)); -static int ptest_eval ARGS((Test_env *te, Test_op op, const char *opnd1, - const char *opnd2, int do_eval)); -static void ptest_error ARGS((Test_env *te, int offset, const char *msg)); - -int -c_test(wp) - char **wp; -{ - int argc; - int res; - Test_env te; - - te.flags = 0; - te.isa = ptest_isa; - te.getopnd = ptest_getopnd; - te.eval = ptest_eval; - te.error = ptest_error; - - for (argc = 0; wp[argc]; argc++) - ; - - if (strcmp(wp[0], "[") == 0) { - if (strcmp(wp[--argc], "]") != 0) { - bi_errorf("missing ]"); - return T_ERR_EXIT; - } - } - - te.pos.wp = wp + 1; - te.wp_end = wp + argc; - - /* - * Handle the special cases from POSIX.2, section 4.62.4. - * Implementation of all the rules isn't necessary since - * our parser does the right thing for the ommited steps. - */ - if (argc <= 5) { - char **owp = wp; - int invert = 0; - Test_op op; - const char *opnd1, *opnd2; - - while (--argc >= 0) { - if ((*te.isa)(&te, TM_END)) - return !0; - if (argc == 3) { - opnd1 = (*te.getopnd)(&te, TO_NONOP, 1); - if ((op = (Test_op) (*te.isa)(&te, TM_BINOP))) { - opnd2 = (*te.getopnd)(&te, op, 1); - res = (*te.eval)(&te, op, opnd1, opnd2, - 1); - if (te.flags & TEF_ERROR) - return T_ERR_EXIT; - if (invert & 1) - res = !res; - return !res; - } - /* back up to opnd1 */ - te.pos.wp--; - } - if (argc == 1) { - opnd1 = (*te.getopnd)(&te, TO_NONOP, 1); - res = (*te.eval)(&te, TO_STNZE, opnd1, - (char *) 0, 1); - if (invert & 1) - res = !res; - return !res; - } - if ((*te.isa)(&te, TM_NOT)) { - invert++; - } else - break; - } - te.pos.wp = owp + 1; - } - - return test_parse(&te); -} - -/* - * Generic test routines. - */ - -Test_op -test_isop(te, meta, s) - Test_env *te; - Test_meta meta; - const char *s; -{ - char sc1; - const struct t_op *otab; - - otab = meta == TM_UNOP ? u_ops : b_ops; - if (*s) { - sc1 = s[1]; - for (; otab->op_text[0]; otab++) - if (sc1 == otab->op_text[1] - && strcmp(s, otab->op_text) == 0 - && ((te->flags & TEF_DBRACKET) - || (otab->op_num != TO_STLT - && otab->op_num != TO_STGT))) - return otab->op_num; - } - return TO_NONOP; -} - -int -test_eval(te, op, opnd1, opnd2, do_eval) - Test_env *te; - Test_op op; - const char *opnd1; - const char *opnd2; - int do_eval; -{ - int res; - int not; - struct stat b1, b2; - - if (!do_eval) - return 0; - - switch ((int) op) { - /* - * Unary Operators - */ - case TO_STNZE: /* -n */ - return *opnd1 != '\0'; - case TO_STZER: /* -z */ - return *opnd1 == '\0'; - case TO_OPTION: /* -o */ - if ((not = *opnd1 == '!')) - opnd1++; - if ((res = option(opnd1)) < 0) - res = 0; - else { - res = Flag(res); - if (not) - res = !res; - } - return res; - case TO_FILRD: /* -r */ - return test_eaccess(opnd1, R_OK) == 0; - case TO_FILWR: /* -w */ - return test_eaccess(opnd1, W_OK) == 0; - case TO_FILEX: /* -x */ - return test_eaccess(opnd1, X_OK) == 0; - case TO_FILAXST: /* -a */ - return test_stat(opnd1, &b1) == 0; - case TO_FILEXST: /* -e */ - /* at&t ksh does not appear to do the /dev/fd/ thing for - * this (unless the os itself handles it) - */ - return stat(opnd1, &b1) == 0; - case TO_FILREG: /* -r */ - return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode); - case TO_FILID: /* -d */ - return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode); - case TO_FILCDEV: /* -c */ -#ifdef S_ISCHR - return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode); -#else - return 0; -#endif - case TO_FILBDEV: /* -b */ -#ifdef S_ISBLK - return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode); -#else - return 0; -#endif - case TO_FILFIFO: /* -p */ -#ifdef S_ISFIFO - return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode); -#else - return 0; -#endif - case TO_FILSYM: /* -h -L */ -#ifdef S_ISLNK - return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode); -#else - return 0; -#endif - case TO_FILSOCK: /* -S */ -#ifdef S_ISSOCK - return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode); -#else - return 0; -#endif - case TO_FILCDF:/* -H HP context dependent files (directories) */ -#ifdef S_ISCDF - { - /* Append a + to filename and check to see if result is a - * setuid directory. CDF stuff in general is hookey, since - * it breaks for the following sequence: echo hi > foo+; - * mkdir foo; echo bye > foo/default; chmod u+s foo - * (foo+ refers to the file with hi in it, there is no way - * to get at the file with bye in it - please correct me if - * I'm wrong about this). - */ - int len = strlen(opnd1); - char *p = str_nsave(opnd1, len + 1, ATEMP); - - p[len++] = '+'; - p[len] = '\0'; - return stat(p, &b1) == 0 && S_ISCDF(b1.st_mode); - } -#else - return 0; -#endif - case TO_FILSETU: /* -u */ -#ifdef S_ISUID - return test_stat(opnd1, &b1) == 0 - && (b1.st_mode & S_ISUID) == S_ISUID; -#else - return 0; -#endif - case TO_FILSETG: /* -g */ -#ifdef S_ISGID - return test_stat(opnd1, &b1) == 0 - && (b1.st_mode & S_ISGID) == S_ISGID; -#else - return 0; -#endif - case TO_FILSTCK: /* -k */ - return test_stat(opnd1, &b1) == 0 - && (b1.st_mode & S_ISVTX) == S_ISVTX; - case TO_FILGZ: /* -s */ - return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L; - case TO_FILTT: /* -t */ - if (opnd1 && !bi_getn(opnd1, &res)) { - te->flags |= TEF_ERROR; - res = 0; - } else - res = isatty(opnd1 ? res : 0); - return res; - case TO_FILUID: /* -O */ - return test_stat(opnd1, &b1) == 0 && b1.st_uid == geteuid(); - case TO_FILGID: /* -G */ - return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid(); - /* - * Binary Operators - */ - case TO_STEQL: /* = */ - if (te->flags & TEF_DBRACKET) - return gmatch(opnd1, opnd2, FALSE); - return strcmp(opnd1, opnd2) == 0; - case TO_STNEQ: /* != */ - if (te->flags & TEF_DBRACKET) - return !gmatch(opnd1, opnd2, FALSE); - return strcmp(opnd1, opnd2) != 0; - case TO_STLT: /* < */ - return strcmp(opnd1, opnd2) < 0; - case TO_STGT: /* > */ - return strcmp(opnd1, opnd2) > 0; - case TO_INTEQ: /* -eq */ - case TO_INTNE: /* -ne */ - case TO_INTGE: /* -ge */ - case TO_INTGT: /* -gt */ - case TO_INTLE: /* -le */ - case TO_INTLT: /* -lt */ - { - long v1, v2; - - if (!evaluate(opnd1, &v1, TRUE) - || !evaluate(opnd2, &v2, TRUE)) - { - /* error already printed.. */ - te->flags |= TEF_ERROR; - return 1; - } - switch ((int) op) { - case TO_INTEQ: - return v1 == v2; - case TO_INTNE: - return v1 != v2; - case TO_INTGE: - return v1 >= v2; - case TO_INTGT: - return v1 > v2; - case TO_INTLE: - return v1 <= v2; - case TO_INTLT: - return v1 < v2; - } - } - case TO_FILNT: /* -nt */ - return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 - && b1.st_mtime > b2.st_mtime; - case TO_FILOT: /* -ot */ - return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 - && b1.st_mtime < b2.st_mtime; - case TO_FILEQ: /* -ef */ - return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 - && b1.st_dev == b2.st_dev - && b1.st_ino == b2.st_ino; - } - (*te->error)(te, 0, "internal error: unknown op"); - return 1; -} - -/* Nasty kludge to handle Korn's bizarre /dev/fd hack */ -static int -test_stat(path, statb) - const char *path; - struct stat *statb; -{ -#if !defined(HAVE_DEV_FD) - int fd; - - if (strncmp(path, "/dev/fd/", 8) == 0 && getn(path + 8, &fd)) - return fstat(fd, statb); -#endif /* !HAVE_DEV_FD */ - - return stat(path, statb); -} - -/* Another nasty kludge to handle Korn's bizarre /dev/fd hack */ -static int -test_eaccess(path, mode) - const char *path; - int mode; -{ -#if !defined(HAVE_DEV_FD) - int fd; - - if (strncmp(path, "/dev/fd/", 8) == 0 && getn(path + 8, &fd)) { - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) < 0 - || (mode & X_OK) - || ((mode & W_OK) && (flags & O_ACCMODE) == O_RDONLY) - || ((mode & R_OK) && (flags & O_ACCMODE) == O_WRONLY)) - return -1; - return 0; - } -#endif /* !HAVE_DEV_FD */ - - return eaccess(path, mode); -} - -int -test_parse(te) - Test_env *te; -{ - int res; - - res = test_oexpr(te, 1); - - if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END)) - (*te->error)(te, 0, "unexpected operator/operand"); - - return (te->flags & TEF_ERROR) ? T_ERR_EXIT : !res; -} - -static int -test_oexpr(te, do_eval) - Test_env *te; - int do_eval; -{ - int res; - - res = test_aexpr(te, do_eval); - if (res) - do_eval = 0; - if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR)) - return test_oexpr(te, do_eval) || res; - return res; -} - -static int -test_aexpr(te, do_eval) - Test_env *te; - int do_eval; -{ - int res; - - res = test_nexpr(te, do_eval); - if (!res) - do_eval = 0; - if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND)) - return test_aexpr(te, do_eval) && res; - return res; -} - -static int -test_nexpr(te, do_eval) - Test_env *te; - int do_eval; -{ - if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT)) - return !test_nexpr(te, do_eval); - return test_primary(te, do_eval); -} - -static int -test_primary(te, do_eval) - Test_env *te; - int do_eval; -{ - const char *opnd1, *opnd2; - int res; - Test_op op; - - if (te->flags & TEF_ERROR) - return 0; - if ((*te->isa)(te, TM_OPAREN)) { - res = test_oexpr(te, do_eval); - if (te->flags & TEF_ERROR) - return 0; - if (!(*te->isa)(te, TM_CPAREN)) { - (*te->error)(te, 0, "missing closing paren"); - return 0; - } - return res; - } - if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) { - /* unary expression */ - opnd1 = (*te->getopnd)(te, op, do_eval); - if (!opnd1) { - (*te->error)(te, -1, "missing argument"); - return 0; - } - - return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval); - } - opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval); - if (!opnd1) { - (*te->error)(te, 0, "expression expected"); - return 0; - } - if ((op = (Test_op) (*te->isa)(te, TM_BINOP))) { - /* binary expression */ - opnd2 = (*te->getopnd)(te, op, do_eval); - if (!opnd2) { - (*te->error)(te, -1, "missing second argument"); - return 0; - } - - return (*te->eval)(te, op, opnd1, opnd2, do_eval); - } - if (te->flags & TEF_DBRACKET) { - (*te->error)(te, -1, "missing expression operator"); - return 0; - } - return (*te->eval)(te, TO_STNZE, opnd1, (const char *) 0, do_eval); -} - -/* - * Plain test (test and [ .. ]) specific routines. - */ - -/* Test if the current token is a whatever. Accepts the current token if - * it is. Returns 0 if it is not, non-zero if it is (in the case of - * TM_UNOP and TM_BINOP, the returned value is a Test_op). - */ -static int -ptest_isa(te, meta) - Test_env *te; - Test_meta meta; -{ - /* Order important - indexed by Test_meta values */ - static const char *const tokens[] = { - "-o", "-a", "!", "(", ")" - }; - int ret; - - if (te->pos.wp >= te->wp_end) - return meta == TM_END; - - if (meta == TM_UNOP || meta == TM_BINOP) - ret = (int) test_isop(te, meta, *te->pos.wp); - else if (meta == TM_END) - ret = 0; - else - ret = strcmp(*te->pos.wp, tokens[(int) meta]) == 0; - - /* Accept the token? */ - if (ret) - te->pos.wp++; - - return ret; -} - -static const char * -ptest_getopnd(te, op, do_eval) - Test_env *te; - Test_op op; - int do_eval; -{ - if (te->pos.wp >= te->wp_end) - return op == TO_FILTT ? "1" : (const char *) 0; - return *te->pos.wp++; -} - -static int -ptest_eval(te, op, opnd1, opnd2, do_eval) - Test_env *te; - Test_op op; - const char *opnd1; - const char *opnd2; - int do_eval; -{ - return test_eval(te, op, opnd1, opnd2, do_eval); -} - -static void -ptest_error(te, offset, msg) - Test_env *te; - int offset; - const char *msg; -{ - const char *op = te->pos.wp + offset >= te->wp_end ? - (const char *) 0 : te->pos.wp[offset]; - - te->flags |= TEF_ERROR; - if (op) - bi_errorf("%s: %s", op, msg); - else - bi_errorf("%s", msg); -} diff --git a/bin/pdksh/c_test.h b/bin/pdksh/c_test.h deleted file mode 100644 index 0caf40b3dfc..00000000000 --- a/bin/pdksh/c_test.h +++ /dev/null @@ -1,55 +0,0 @@ -/* $OpenBSD: c_test.h,v 1.1 1996/08/14 06:19:10 downsj Exp $ */ - -/* Various types of operations. Keeping things grouped nicely - * (unary,binary) makes switch() statements more efficeint. - */ -enum Test_op { - TO_NONOP = 0, /* non-operator */ - /* unary operators */ - TO_STNZE, TO_STZER, TO_OPTION, - TO_FILAXST, - TO_FILEXST, - TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK, - TO_FILCDF, TO_FILID, TO_FILGID, TO_FILSETG, TO_FILSTCK, TO_FILUID, - TO_FILRD, TO_FILGZ, TO_FILTT, TO_FILSETU, TO_FILWR, TO_FILEX, - /* binary operators */ - TO_STEQL, TO_STNEQ, TO_STLT, TO_STGT, TO_INTEQ, TO_INTNE, TO_INTGT, - TO_INTGE, TO_INTLT, TO_INTLE, TO_FILEQ, TO_FILNT, TO_FILOT -}; -typedef enum Test_op Test_op; - -/* Used by Test_env.isa() (order important - used to index *_tokens[] arrays) */ -enum Test_meta { - TM_OR, /* -o or || */ - TM_AND, /* -a or && */ - TM_NOT, /* ! */ - TM_OPAREN, /* ( */ - TM_CPAREN, /* ) */ - TM_UNOP, /* unary operator */ - TM_BINOP, /* binary operator */ - TM_END /* end of input */ -}; -typedef enum Test_meta Test_meta; - -#define TEF_ERROR BIT(0) /* set if we've hit an error */ -#define TEF_DBRACKET BIT(1) /* set if [[ .. ]] test */ - -typedef struct test_env Test_env; -struct test_env { - int flags; /* TEF_* */ - union { - char **wp; /* used by ptest_* */ - XPtrV *av; /* used by dbtestp_* */ - } pos; - char **wp_end; /* used by ptest_* */ - int (*isa) ARGS((Test_env *te, Test_meta meta)); - const char *(*getopnd) ARGS((Test_env *te, Test_op op, int do_eval)); - int (*eval) ARGS((Test_env *te, Test_op op, const char *opnd1, - const char *opnd2, int do_eval)); - void (*error) ARGS((Test_env *te, int offset, const char *msg)); -}; - -Test_op test_isop ARGS((Test_env *te, Test_meta meta, const char *s)); -int test_eval ARGS((Test_env *te, Test_op op, const char *opnd1, - const char *opnd2, int do_eval)); -int test_parse ARGS((Test_env *te)); diff --git a/bin/pdksh/c_ulimit.c b/bin/pdksh/c_ulimit.c deleted file mode 100644 index b96c10bf5b8..00000000000 --- a/bin/pdksh/c_ulimit.c +++ /dev/null @@ -1,257 +0,0 @@ -/* $OpenBSD: c_ulimit.c,v 1.3 1997/06/19 13:58:39 kstailey Exp $ */ - -/* - ulimit -- handle "ulimit" builtin - - Reworked to use getrusage() and ulimit() at once (as needed on - some schizophenic systems, eg, HP-UX 9.01), made argument parsing - conform to at&t ksh, added autoconf support. Michael Rendell, May, '94 - - Eric Gisin, September 1988 - Adapted to PD KornShell. Removed AT&T code. - - last edit: 06-Jun-1987 D A Gwyn - - This started out as the BRL UNIX System V system call emulation - for 4.nBSD, and was later extended by Doug Kingston to handle - the extended 4.nBSD resource limits. It now includes the code - that was originally under case SYSULIMIT in source file "xec.c". -*/ - -#include "sh.h" -#include "ksh_time.h" -#ifdef HAVE_SYS_RESOURCE_H -# include <sys/resource.h> -#endif /* HAVE_SYS_RESOURCE_H */ -#ifdef HAVE_ULIMIT_H -# include <ulimit.h> -#else /* HAVE_ULIMIT_H */ -# ifdef HAVE_ULIMIT -extern long ulimit(); -# endif /* HAVE_ULIMIT */ -#endif /* HAVE_ULIMIT_H */ - -#define SOFT 0x1 -#define HARD 0x2 - -int -c_ulimit(wp) - char **wp; -{ - static const struct limits { - const char *name; - enum { RLIMIT, ULIMIT } which; - int gcmd; /* get command */ - int scmd; /* set command (or -1, if no set command) */ - int factor; /* multiply by to get rlim_{cur,max} values */ - char option; - } limits[] = { - /* Do not use options -H, -S or -a */ -#ifdef RLIMIT_CPU - { "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' }, -#endif -#ifdef RLIMIT_FSIZE - { "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' }, -#else /* RLIMIT_FSIZE */ -# ifdef UL_GETFSIZE /* x/open */ - { "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' }, -# else /* UL_GETFSIZE */ -# ifdef UL_GFILLIM /* svr4/xenix */ - { "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' }, -# else /* UL_GFILLIM */ - { "file(blocks)", ULIMIT, 1, 2, 1, 'f' }, -# endif /* UL_GFILLIM */ -# endif /* UL_GETFSIZE */ -#endif /* RLIMIT_FSIZE */ -#ifdef RLIMIT_CORE - { "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' }, -#endif -#ifdef RLIMIT_DATA - { "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' }, -#endif -#ifdef RLIMIT_STACK - { "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' }, -#endif -#ifdef RLIMIT_MEMLOCK - { "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' }, -#endif -#ifdef RLIMIT_RSS - { "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' }, -#endif -#ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' }, -#else /* RLIMIT_NOFILE */ -# ifdef UL_GDESLIM /* svr4/xenix */ - { "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' }, -# endif /* UL_GDESLIM */ -#endif /* RLIMIT_NOFILE */ -#ifdef RLIMIT_NPROC - { "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' }, -#endif -#ifdef RLIMIT_VMEM - { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' }, -#else /* RLIMIT_VMEM */ - /* These are not quite right - really should subtract etext or something */ -# ifdef UL_GMEMLIM /* svr4/xenix */ - { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' }, -# else /* UL_GMEMLIM */ -# ifdef UL_GETBREAK /* osf/1 */ - { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' }, -# else /* UL_GETBREAK */ -# ifdef UL_GETMAXBRK /* hpux */ - { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' }, -# endif /* UL_GETMAXBRK */ -# endif /* UL_GETBREAK */ -# endif /* UL_GMEMLIM */ -#endif /* RLIMIT_VMEM */ -#ifdef RLIMIT_SWAP - { "swap(kbytes)", RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' }, -#endif - { (char *) 0 } - }; - static char options[3 + NELEM(limits)]; - rlim_t UNINITIALIZED(val); - int how = SOFT | HARD; - const struct limits *l; - int set, all = 0; - int optc, what; -#ifdef HAVE_SETRLIMIT - struct rlimit limit; -#endif /* HAVE_SETRLIMIT */ - - if (!options[0]) { - /* build options string on first call - yuck */ - char *p = options; - - *p++ = 'H'; *p++ = 'S'; *p++ = 'a'; - for (l = limits; l->name; l++) - *p++ = l->option; - *p = '\0'; - } - what = 'f'; - while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) - switch (optc) { - case 'H': - how = HARD; - break; - case 'S': - how = SOFT; - break; - case 'a': - all = 1; - break; - case '?': - return 1; - default: - what = optc; - } - - for (l = limits; l->name && l->option != what; l++) - ; - if (!l->name) { - internal_errorf(0, "ulimit: %c", what); - return 1; - } - - wp += builtin_opt.optind; - set = *wp ? 1 : 0; - if (set) { - char *p = *wp; - - if (all || wp[1]) { - bi_errorf("too many arguments"); - return 1; - } -#ifdef RLIM_INFINITY - if (strcmp(p, "unlimited") == 0) - val = RLIM_INFINITY; - else -#endif /* RLIM_INFINITY */ - { - long rval; - - if (!evaluate(p, &rval, TRUE)) - return 1; - val = rval * l->factor; - } - } - if (all) { - for (l = limits; l->name; l++) { -#ifdef HAVE_SETRLIMIT - if (l->which == RLIMIT) { - getrlimit(l->gcmd, &limit); - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - } else -#endif /* HAVE_SETRLIMIT */ -#ifdef HAVE_ULIMIT - { - val = ulimit(l->gcmd, (rlim_t) 0); - } -#else /* HAVE_ULIMIT */ - ; -#endif /* HAVE_ULIMIT */ - shprintf("%-20s ", l->name); -#ifdef RLIM_INFINITY - if (val == RLIM_INFINITY) - shprintf("unlimited\n"); - else -#endif /* RLIM_INFINITY */ - { - val /= l->factor; - shprintf("%ld\n", (long) val); - } - } - return 0; - } -#ifdef HAVE_SETRLIMIT - if (l->which == RLIMIT) { - getrlimit(l->gcmd, &limit); - if (set) { - if (how & SOFT) - limit.rlim_cur = val; - if (how & HARD) - limit.rlim_max = val; - if (setrlimit(l->scmd, &limit) < 0) { - bi_errorf("bad limit: %s", strerror(errno)); - return 1; - } - } else { - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - } - } else -#endif /* HAVE_SETRLIMIT */ -#ifdef HAVE_ULIMIT - { - if (set) { - if (l->scmd == -1) { - bi_errorf("can't change limit"); - return 1; - } else if (ulimit(l->scmd, val) < 0) { - bi_errorf("bad limit: %s", strerror(errno)); - return 1; - } - } else - val = ulimit(l->gcmd, (rlim_t) 0); - } -#else /* HAVE_ULIMIT */ - ; -#endif /* HAVE_ULIMIT */ - if (!set) { -#ifdef RLIM_INFINITY - if (val == RLIM_INFINITY) - shprintf("unlimited\n"); - else -#endif /* RLIM_INFINITY */ - { - val /= l->factor; - shprintf("%ld\n", (long) val); - } - } - return 0; -} diff --git a/bin/pdksh/conf-end.h b/bin/pdksh/conf-end.h deleted file mode 100644 index 8b65cb7d1df..00000000000 --- a/bin/pdksh/conf-end.h +++ /dev/null @@ -1,62 +0,0 @@ -/* $OpenBSD: conf-end.h,v 1.2 1996/08/25 12:37:58 downsj Exp $ */ - -/* - * End of configuration stuff for PD ksh. - */ - -#if defined(EMACS) || defined(VI) -# define EDIT -#else -# undef EDIT -#endif - -/* Super small configuration-- no editing. */ -#if defined(EDIT) && defined(NOEDIT) -# undef EDIT -# undef EMACS -# undef VI -#endif - -/* Editing implies history */ -#if defined(EDIT) && !defined(HISTORY) -# define HISTORY -#endif /* EDIT */ - -/* - * if you don't have mmap() you can't use Peter Collinson's history - * mechanism. If that is the case, then define EASY_HISTORY - */ -#if defined(HISTORY) && (!defined(COMPLEX_HISTORY) || !defined(HAVE_MMAP) || !defined(HAVE_FLOCK)) -# undef COMPLEX_HISTORY -# define EASY_HISTORY /* sjg's trivial history file */ -#endif - -/* Can we safely catch sigchld and wait for processes? */ -#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT3)) \ - && (defined(POSIX_SIGNALS) || defined(BSD42_SIGNALS)) -# define JOB_SIGS -#endif - -#if !defined(JOB_SIGS) || !(defined(POSIX_PGRP) || defined(BSD_PGRP)) -# undef JOBS /* if no JOB_SIGS, no job control support */ -#endif - -/* pdksh assumes system calls return EINTR if a signal happened (this so - * the signal handler doesn't have to longjmp()). I don't know if this - * happens (or can be made to happen) with sigset() et. al. (the bsd41 signal - * routines), so, the autoconf stuff checks what they do and defines - * SIGNALS_DONT_INTERRUPT if signals don't interrupt read(). - * If SIGNALS_DONT_INTERRUPT isn't defined and your compiler chokes on this, - * delete the hash in front of the error (and file a bug report). - */ -#ifdef SIGNALS_DONT_INTERRUPT - # error pdksh needs interruptable system calls. -#endif /* SIGNALS_DONT_INTERRUPT */ - -#ifdef HAVE_GCC_FUNC_ATTR -# define GCC_FUNC_ATTR(x) __attribute__((x)) -# define GCC_FUNC_ATTR2(x,y) __attribute__((x,y)) -#else -# define GCC_FUNC_ATTR(x) -# define GCC_FUNC_ATTR2(x,y) -#endif /* HAVE_GCC_FUNC_ATTR */ diff --git a/bin/pdksh/config.h b/bin/pdksh/config.h deleted file mode 100644 index c949a254ee2..00000000000 --- a/bin/pdksh/config.h +++ /dev/null @@ -1,351 +0,0 @@ -/* $OpenBSD: config.h,v 1.2 1996/08/25 11:56:34 downsj Exp $ */ - -/* config.h. Generated automatically by configure. */ -/* config.h.in. Generated automatically from configure.in by autoheader. */ -/* - * This file, acconfig.h, which is a part of pdksh (the public domain ksh), - * is placed in the public domain. It comes with no licence, warranty - * or guarantee of any kind (i.e., at your own risk). - */ - -#ifndef CONFIG_H -#define CONFIG_H - - -/* Define if on AIX 3. - System headers sometimes define this. - We just want to avoid a redefinition error message. */ -#ifndef _ALL_SOURCE -/* #undef _ALL_SOURCE */ -#endif - -/* Define if the closedir function returns void instead of int. */ -/* #undef CLOSEDIR_VOID */ - -/* Define to empty if the keyword does not work. */ -/* #undef const */ - - -/* Define to `int' if <sys/types.h> doesn't define. */ -/* #undef gid_t */ - -/* Define if you have a working `mmap' system call. */ -#define HAVE_MMAP 1 - -/* Define if your struct stat has st_rdev. */ -#define HAVE_ST_RDEV 1 - -/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define if you have <unistd.h>. */ -#define HAVE_UNISTD_H 1 - -/* Define if on MINIX. */ -/* #undef _MINIX */ - -/* Define to `int' if <sys/types.h> doesn't define. */ -/* #undef mode_t */ - -/* Define to `long' if <sys/types.h> doesn't define. */ -/* #undef off_t */ - -/* Define to `int' if <sys/types.h> doesn't define. */ -/* #undef pid_t */ - -/* Define if the system does not provide POSIX.1 features except - with this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define if you need to in order for stat and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define as the return type of signal handlers (int or void). */ -#define RETSIGTYPE void - -/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ -/* #undef STAT_MACROS_BROKEN */ - -/* Define if `sys_siglist' is declared by <signal.h>. */ -#define SYS_SIGLIST_DECLARED 1 - -/* Define if you can safely include both <sys/time.h> and <time.h>. */ -#define TIME_WITH_SYS_TIME 1 - -/* Define to `int' if <sys/types.h> doesn't define. */ -/* #undef uid_t */ - -/* Define if the closedir function returns void instead of int. */ -/* #undef VOID_CLOSEDIR */ - -/* Define if your kernal doesn't handle scripts starting with #! */ -/* #undef SHARPBANG */ - -/* Define if dup2() preserves the close-on-exec flag (ultrix does this) */ -/* #undef DUP2_BROKEN */ - -/* Define as the return value of signal handlers (0 or ). */ -#define RETSIGVAL - -/* Define if you have posix signal routines (sigaction(), et. al.) */ -#define POSIX_SIGNALS 1 - -/* Define if you have BSD4.2 signal routines (sigsetmask(), et. al.) */ -/* #undef BSD42_SIGNALS */ - -/* Define if you have BSD4.1 signal routines (sigset(), et. al.) */ -/* #undef BSD41_SIGNALS */ - -/* Define if you have v7 signal routines (signal(), signal reset on delivery) */ -/* #undef V7_SIGNALS */ - -/* Define to use the fake posix signal routines (sigact.[ch]) */ -/* #undef USE_FAKE_SIGACT */ - -/* Define if signals don't interrupt read() */ -/* #undef SIGNALS_DONT_INTERRUPT */ - -/* Define if you have bsd versions of the setpgrp() and getpgrp() routines */ -/* #undef BSD_PGRP */ - -/* Define if you have POSIX versions of the setpgid() and getpgrp() routines */ -#define POSIX_PGRP 1 - -/* Define if you have sysV versions of the setpgrp() and getpgrp() routines */ -/* #undef SYSV_PGRP */ - -/* Define if you don't have setpgrp(), setpgid() or getpgrp() routines */ -/* #undef NO_PGRP */ - -/* Define to char if your compiler doesn't like the void keyword */ -/* #undef void */ - -/* Define to nothing if compiler doesn't like the volatile keyword */ -/* #undef volatile */ - -/* Define if C compiler groks function prototypes */ -#define HAVE_PROTOTYPES 1 - -/* Define if C compiler groks __attribute__((...)) (const, noreturn, format) */ -#define HAVE_GCC_FUNC_ATTR 1 - -/* Define to 32-bit signed integer type if <sys/types.h> doesn't define */ -/* #undef clock_t */ - -/* Define to the type of struct rlimit fields if the rlim_t type is missing */ -/* #undef rlim_t */ - -/* Define if time() is declared in <time.h> */ -#define TIME_DECLARED 1 - -/* Define to `unsigned' if <signal.h> doesn't define */ -/* #undef sigset_t */ - -/* Define if sys_errlist[] and sys_nerr are in the C library */ -#define HAVE_SYS_ERRLIST 1 - -/* Define if sys_errlist[] and sys_nerr are defined in <errno.h> */ -#define SYS_ERRLIST_DECLARED 1 - -/* Define if sys_siglist[] is in the C library */ -#define HAVE_SYS_SIGLIST 1 - -/* Define if you have a sane <termios.h> header file */ -#define HAVE_TERMIOS_H 1 - -/* Define if you have a memset() function in your C library */ -#define HAVE_MEMSET 1 - -/* Define if you have a memmove() function in your C library */ -#define HAVE_MEMMOVE 1 - -/* Define if you have a bcopy() function in your C library */ -/* #undef HAVE_BCOPY */ - -/* Define if you have a lstat() function in your C library */ -#define HAVE_LSTAT 1 - -/* Define if you have a sane <termio.h> header file */ -/* #undef HAVE_TERMIO_H */ - -/* Define if you don't have times() or if it always returns 0 */ -/* #undef TIMES_BROKEN */ - -/* Define if opendir() will open non-directory files */ -/* #undef OPENDIR_DOES_NONDIR */ - -/* Define if the pgrp of setpgrp() can't be the pid of a zombie process */ -/* #undef NEED_PGRP_SYNC */ - -/* Define if you arg running SCO unix */ -/* #undef OS_SCO */ - -/* Define if you arg running ISC unix */ -/* #undef OS_ISC */ - -/* Define if you arg running OS2 with the EMX library */ -/* #undef OS2 */ - -/* Define if you have a POSIX.1 compatiable <sys/wait.h> */ -#define POSIX_SYS_WAIT 1 - -/* Define if your OS maps references to /dev/fd/n to file descriptor n */ -#define HAVE_DEV_FD 1 - -/* Default PATH (see comments in configure.in for more details) */ -#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb" - -/* Include ksh features? (see comments in configure.in for more details) */ -/* #define KSH 1 */ - -/* Include emacs editing? (see comments in configure.in for more details) */ -#define EMACS 1 - -/* Include vi editing? (see comments in configure.in for more details) */ -#define VI 1 - -/* Include job control? (see comments in configure.in for more details) */ -#define JOBS 1 - -/* Include brace-expansion? (see comments in configure.in for more details) */ -#define BRACE_EXPAND 1 - -/* Include any history? (see comments in configure.in for more details) */ -#define HISTORY 1 - -/* Include complex history? (see comments in configure.in for more details) */ -/* #undef COMPLEX_HISTORY */ - -/* Strict POSIX behaviour? (see comments in configure.in for more details) */ -/* #undef POSIXLY_CORRECT */ - -/* Specify default $ENV? (see comments in configure.in for more details) */ -/* #undef DEFAULT_ENV */ - -/* Include shl(1) support? (see comments in configure.in for more details) */ -/* #undef SWTCH */ - -/* Include game-of-life? (see comments in configure.in for more details) */ -/* #undef SILLY */ - -/* The number of bytes in a int. */ -#define SIZEOF_INT 4 - -/* The number of bytes in a long. */ -#if defined(alpha) -#define SIZEOF_LONG 8 -#else -#define SIZEOF_LONG 4 -#endif - -/* Define if you have the _setjmp function. */ -/* #undef HAVE__SETJMP */ - -/* Define if you have the confstr function. */ -#define HAVE_CONFSTR 1 - -/* Define if you have the flock function. */ -#define HAVE_FLOCK 1 - -/* Define if you have the getgroups function. */ -/* #undef HAVE_GETGROUPS */ - -/* Define if you have the getrusage function. */ -/* #undef HAVE_GETRUSAGE */ - -/* Define if you have the getwd function. */ -#define HAVE_GETWD 1 - -/* Define if you have the killpg function. */ -#define HAVE_KILLPG 1 - -/* Define if you have the nice function. */ -#define HAVE_NICE 1 - -/* Define if you have the setrlimit function. */ -#define HAVE_SETRLIMIT 1 - -/* Define if you have the sigsetjmp function. */ -#define HAVE_SIGSETJMP 1 - -/* Define if you have the strcasecmp function. */ -#define HAVE_STRCASECMP 1 - -/* Define if you have the strerror function. */ -#define HAVE_STRERROR 1 - -/* Define if you have the strstr function. */ -#define HAVE_STRSTR 1 - -/* Define if you have the sysconf function. */ -#define HAVE_SYSCONF 1 - -/* Define if you have the tcsetpgrp function. */ -#define HAVE_TCSETPGRP 1 - -/* Define if you have the ulimit function. */ -/* #undef HAVE_ULIMIT */ - -/* Define if you have the wait3 function. */ -#define HAVE_WAIT3 1 - -/* Define if you have the waitpid function. */ -#define HAVE_WAITPID 1 - -/* Define if you have the <dirent.h> header file. */ -#define HAVE_DIRENT_H 1 - -/* Define if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the <limits.h> header file. */ -#define HAVE_LIMITS_H 1 - -/* Define if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define if you have the <ndir.h> header file. */ -/* #undef HAVE_NDIR_H */ - -/* Define if you have the <paths.h> header file. */ -#define HAVE_PATHS_H 1 - -/* Define if you have the <stddef.h> header file. */ -#define HAVE_STDDEF_H 1 - -/* Define if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define if you have the <sys/dir.h> header file. */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define if you have the <sys/ndir.h> header file. */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define if you have the <sys/param.h> header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define if you have the <sys/resource.h> header file. */ -#define HAVE_SYS_RESOURCE_H 1 - -/* Define if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define if you have the <sys/wait.h> header file. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define if you have the <ulimit.h> header file. */ -/* #undef HAVE_ULIMIT_H */ - -/* Define if you have the <values.h> header file. */ -/* #undef HAVE_VALUES_H */ - -/* Need to use a separate file to keep the configure script from commenting - * out the undefs.... - */ -#include "conf-end.h" - -#endif /* CONFIG_H */ diff --git a/bin/pdksh/edit.c b/bin/pdksh/edit.c deleted file mode 100644 index 2d4b96b4d0f..00000000000 --- a/bin/pdksh/edit.c +++ /dev/null @@ -1,1013 +0,0 @@ -/* $OpenBSD: edit.c,v 1.6 1997/06/19 13:58:39 kstailey Exp $ */ - -/* - * Command line editing - common code - * - */ - -#include "config.h" -#ifdef EDIT - -#include "sh.h" -#include "tty.h" -#define EXTERN -#include "edit.h" -#undef EXTERN -#ifdef OS_SCO /* SCO Unix 3.2v4.1 */ -# include <sys/stream.h> /* needed for <sys/ptem.h> */ -# include <sys/ptem.h> /* needed for struct winsize */ -#endif /* OS_SCO */ -#include <sys/ioctl.h> -#include <ctype.h> -#include "ksh_stat.h" - - -#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 */ -void -x_init() -{ - /* set to -1 to force initial binding */ - edchars.erase = edchars.kill = edchars.intr = edchars.quit - = edchars.eof = -1; - /* default value for deficient systems */ - edchars.werase = 027; /* ^W */ - -#ifdef TIOCGWINSZ -# ifdef SIGWINCH - if (setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_SHTRAP)) - sigtraps[SIGWINCH].flags |= TF_SHELL_USES; -# endif /* SIGWINCH */ - got_sigwinch = 1; /* force initial check */ - check_sigwinch(); -#endif /* TIOCGWINSZ */ - -#ifdef EMACS - x_init_emacs(); -#endif /* EMACS */ - - /* Bizarreness to figure out how to disable - * a struct termios.c_cc[] char - */ -#ifdef _POSIX_VDISABLE - if (_POSIX_VDISABLE >= 0) - vdisable_c = (char) _POSIX_VDISABLE; - else - /* `feature not available' */ - vdisable_c = (char) 0377; -#else -# if defined(HAVE_PATHCONF) && defined(_PC_VDISABLE) - vdisable_c = fpathconf(tty_fd, _PC_VDISABLE); -# else - vdisable_c = (char) 0377; /* default to old BSD value */ -# endif -#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 - */ -int -x_read(buf, len) - char *buf; - size_t len; -{ - int i; - -#if defined(TIOCGWINSZ) - if (got_sigwinch) - check_sigwinch(); -#endif /* TIOCGWINSZ */ - - x_mode(TRUE); -#ifdef EMACS - if (Flag(FEMACS) || Flag(FGMACS)) - i = x_emacs(buf, len); - else -#endif -#ifdef VI - if (Flag(FVI)) - i = x_vi(buf, len); - else -#endif - i = -1; /* internal error */ - x_mode(FALSE); - return i; -} - -/* tty I/O */ - -int -x_getc() -{ -#ifdef OS2 - unsigned char c = _read_kbd(0, 1, 0); - return c == 0 ? 0xE0 : c; -#else /* OS2 */ - char c; - int n; - - while ((n = blocking_read(0, &c, 1)) < 0 && errno == EINTR) - if (trap) { - x_mode(FALSE); - runtraps(0); - x_mode(TRUE); - } - if (n != 1) - return -1; - return (int) (unsigned char) c; -#endif /* OS2 */ -} - -void -x_flush() -{ - shf_flush(shl_out); -} - -void -x_putc(c) - int c; -{ - shf_putc(c, shl_out); -} - -void -x_puts(s) - const char *s; -{ - while (*s != 0) - shf_putc(*s++, shl_out); -} - -bool_t -x_mode(onoff) - bool_t onoff; -{ - static bool_t x_cur_mode; - bool_t prev; - - if (x_cur_mode == onoff) - return x_cur_mode; - prev = x_cur_mode; - x_cur_mode = onoff; - - if (onoff) { - TTY_state cb; - X_chars oldchars; - - oldchars = edchars; - cb = tty_state; - -#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H) - edchars.erase = cb.c_cc[VERASE]; - edchars.kill = cb.c_cc[VKILL]; - edchars.intr = cb.c_cc[VINTR]; - edchars.quit = cb.c_cc[VQUIT]; - edchars.eof = cb.c_cc[VEOF]; -# ifdef VWERASE - edchars.werase = cb.c_cc[VWERASE]; -# endif -# ifdef _CRAY2 /* brain-damaged terminal handler */ - cb.c_lflag &= ~(ICANON|ECHO); - /* rely on print routine to map '\n' to CR,LF */ -# else - cb.c_iflag &= ~(INLCR|ICRNL); -# ifdef _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */ - cb.c_lflag &= ~(ICANON|ECHO); -# else -# ifdef SWTCH /* need CBREAK to handle swtch char */ - cb.c_lflag &= ~(ICANON|ECHO); - cb.c_lflag |= ISIG; - cb.c_cc[VINTR] = vdisable_c; - cb.c_cc[VQUIT] = vdisable_c; -# else - cb.c_lflag &= ~(ISIG|ICANON|ECHO); -# endif -# endif -# ifdef VLNEXT - /* osf/1 processes lnext when ~icanon */ - cb.c_cc[VLNEXT] = vdisable_c; -# endif /* VLNEXT */ -# ifdef VDISCARD - /* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */ - cb.c_cc[VDISCARD] = vdisable_c; -# endif /* VDISCARD */ - cb.c_cc[VTIME] = 0; - cb.c_cc[VMIN] = 1; -# endif /* _CRAY2 */ -#else - /* Assume BSD tty stuff. */ - edchars.erase = cb.sgttyb.sg_erase; - edchars.kill = cb.sgttyb.sg_kill; - cb.sgttyb.sg_flags &= ~ECHO; - cb.sgttyb.sg_flags |= CBREAK; -# ifdef TIOCGATC - edchars.intr = cb.lchars.tc_intrc; - edchars.quit = cb.lchars.tc_quitc; - edchars.eof = cb.lchars.tc_eofc; - edchars.werase = cb.lchars.tc_werasc; - cb.lchars.tc_suspc = -1; - cb.lchars.tc_dsuspc = -1; - cb.lchars.tc_lnextc = -1; - cb.lchars.tc_statc = -1; - cb.lchars.tc_intrc = -1; - cb.lchars.tc_quitc = -1; - cb.lchars.tc_rprntc = -1; -# else - edchars.intr = cb.tchars.t_intrc; - edchars.quit = cb.tchars.t_quitc; - edchars.eof = cb.tchars.t_eofc; - cb.tchars.t_intrc = -1; - cb.tchars.t_quitc = -1; -# ifdef TIOCGLTC - edchars.werase = cb.ltchars.t_werasc; - cb.ltchars.t_suspc = -1; - cb.ltchars.t_dsuspc = -1; - cb.ltchars.t_lnextc = -1; - cb.ltchars.t_rprntc = -1; -# endif -# endif /* TIOCGATC */ -#endif /* HAVE_TERMIOS_H || HAVE_TERMIO_H */ - - set_tty(tty_fd, &cb, TF_WAIT); - - if (memcmp(&edchars, &oldchars, sizeof(edchars)) != 0) { -#ifdef EMACS - x_emacs_keys(&edchars); -#endif - } - } else - /* TF_WAIT doesn't seem to be necessary when leaving xmode */ - set_tty(tty_fd, &tty_state, TF_NONE); - - return prev; -} - -/* NAME: - * promptlen - calculate the length of PS1 etc. - * - * DESCRIPTION: - * This function is based on a fix from guy@demon.co.uk - * It fixes a bug in that if PS1 contains '!', the length - * given by strlen() is probably wrong. - * - * RETURN VALUE: - * length - */ -int -promptlen(cp, spp) - const char *cp; - const char **spp; -{ - int count = 0; - const char *sp = cp; - char delimiter = 0; - int indelimit = 0; - - /* Undocumented AT&T ksh feature: - * If the second char in the prompt string is \r then the first char - * is taken to be a non-printing delimiter and any chars between two - * instances of the delimiter are not considered to be part of the - * prompt length - */ - if (*cp && cp[1] == '\r') { - delimiter = *cp; - cp += 2; - } - - for (; *cp; cp++) { - if (indelimit && *cp != delimiter) - ; - else if (*cp == '\n' || *cp == '\r') { - count = 0; - sp = cp + 1; - } else if (*cp == '\t') { - count = (count | 7) + 1; - } else if (*cp == '\b') { - if (count > 0) - count--; - } else if (*cp == delimiter) - indelimit = !indelimit; - else - count++; - } - if (spp) - *spp = sp; - return count; -} - -void -set_editmode(ed) - const char *ed; -{ - static const enum sh_flag edit_flags[] = { -#ifdef EMACS - FEMACS, FGMACS, -#endif -#ifdef VI - FVI, -#endif - }; - char *rcp; - int i; - - if ((rcp = ksh_strrchr_dirsep(ed))) - ed = ++rcp; - for (i = 0; i < NELEM(edit_flags); i++) - if (strstr(ed, options[(int) edit_flags[i]].name)) { - change_flag(edit_flags[i], OF_SPECIAL, 1); - return; - } -} - -/* ------------------------------------------------------------------------- */ -/* 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 */ - - -static char *add_glob ARGS((const char *str, int slen)); -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)); - -#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; - int slen; - int is_command; - int *nwordsp; - char **ret; -{ - int nwords; - int prefix_len; - char **words; - - nwords = (is_command ? x_command_glob : x_file_glob)(XCF_FULLPATH, - str, slen, &words); - *nwordsp = nwords; - if (nwords == 0) { - *ret = (char *) 0; - return -1; - } - - prefix_len = x_longest_prefix(nwords, words); - *ret = str_nsave(words[0], prefix_len, ATEMP); - x_free_words(nwords, words); - return prefix_len; -} -#endif /* 0 */ - -void -x_print_expansions(nwords, words, is_command) - int nwords; - char *const *words; - int is_command; -{ - int use_copy = 0; - int prefix_len; - XPtrV l; - - /* Check if all matches are in the same directory (in this - * case, we want to omitt the directory name) - */ - if (!is_command - && (prefix_len = x_longest_prefix(nwords, words)) > 0) - { - int i; - - /* Special case for 1 match (prefix is whole word) */ - if (nwords == 1) - prefix_len = x_basename(words[0], (char *) 0); - /* Any (non-trailing) slashes in non-common word suffixes? */ - for (i = 0; i < nwords; i++) - if (x_basename(words[i] + prefix_len, (char *) 0) - > prefix_len) - break; - /* All in same directory? */ - if (i == nwords) { - while (prefix_len > 0 - && !ISDIRSEP(words[0][prefix_len - 1])) - prefix_len--; - use_copy = 1; - XPinit(l, nwords + 1); - for (i = 0; i < nwords; i++) - XPput(l, words[i] + prefix_len); - XPput(l, (char *) 0); - } - } - - /* - * Enumerate expansions - */ - x_putc('\r'); - x_putc('\n'); - pr_menu(use_copy ? (char **) XPptrv(l) : words); - - if (use_copy) - XPfree(l); /* not x_free_words() */ -} - -/* - * Do file globbing: - * - appends * to (copy of) str if no globbing chars found - * - does expansion, checks for no match, etc. - * - sets *wordsp to array of matching strings - * - returns number of matching strings - */ -static int -x_file_glob(flags, str, slen, wordsp) - int flags; - const char *str; - int slen; - char ***wordsp; -{ - char *toglob; - char **words; - int nwords; - XPtrV w; - struct source *s, *sold; - - if (slen < 0) - return 0; - - toglob = add_glob(str, slen); - - /* - * Convert "foo*" (toglob) to an array of strings (words) - */ - sold = source; - s = pushs(SWSTR, ATEMP); - s->start = s->str = toglob; - source = s; - if (yylex(ONEWORD) != LWORD) { - source = sold; - internal_errorf(0, "fileglob: substitute error"); - return 0; - } - source = sold; - XPinit(w, 32); - expand(yylval.cp, &w, DOGLOB|DOTILDE|DOMARKDIRS); - XPput(w, NULL); - words = (char **) XPclose(w); - - for (nwords = 0; words[nwords]; nwords++) - ; - if (nwords == 1) { - struct stat statb; - - /* Check if globbing failed (returned glob pattern), - * but be careful (E.g. toglob == "ab*" when the file - * "ab*" exists is not an error). - * Also, check for empty result - happens if we tried - * to glob something which evaluated to an empty - * string (e.g., "$FOO" when there is no FOO, etc). - */ - if ((strcmp(words[0], toglob) == 0 - && stat(words[0], &statb) < 0) - || words[0][0] == '\0') - { - x_free_words(nwords, words); - nwords = 0; - } - } - afree(toglob, ATEMP); - - *wordsp = nwords ? words : (char **) 0; - - return nwords; -} - -/* Data structure used in x_command_glob() */ -struct path_order_info { - char *word; - int base; - int path_order; -}; - -/* Compare routine used in x_command_glob() */ -static int -path_order_cmp(aa, bb) - const void *aa; - const void *bb; -{ - const struct path_order_info *a = (const struct path_order_info *) aa; - const struct path_order_info *b = (const struct path_order_info *) bb; - int t; - - t = FILECMP(a->word + a->base, b->word + b->base); - return t ? t : a->path_order - b->path_order; -} - -static int -x_command_glob(flags, str, slen, wordsp) - int flags; - const char *str; - int slen; - char ***wordsp; -{ - char *toglob; - char *pat; - char *fpath; - int nwords; - XPtrV w; - struct block *l; - - if (slen < 0) - return 0; - - toglob = add_glob(str, slen); - - /* Convert "foo*" (toglob) to a pattern for future use */ - pat = evalstr(toglob, DOPAT|DOTILDE); - afree(toglob, ATEMP); - - XPinit(w, 32); - - glob_table(pat, &w, &keywords); - glob_table(pat, &w, &aliases); - glob_table(pat, &w, &builtins); - for (l = e->loc; l; l = l->next) - glob_table(pat, &w, &l->funs); - - glob_path(flags, pat, &w, path); - if ((fpath = str_val(global("FPATH"))) != null) - glob_path(flags, pat, &w, fpath); - - nwords = XPsize(w); - - if (!nwords) { - *wordsp = (char **) 0; - XPfree(w); - return 0; - } - - /* Sort entries */ - if (flags & XCF_FULLPATH) { - /* Sort by basename, then path order */ - struct path_order_info *info; - struct path_order_info *last_info = 0; - char **words = (char **) XPptrv(w); - int path_order = 0; - int i; - - info = (struct path_order_info *) - alloc(sizeof(struct path_order_info) * nwords, ATEMP); - for (i = 0; i < nwords; i++) { - info[i].word = words[i]; - info[i].base = x_basename(words[i], (char *) 0); - if (!last_info || info[i].base != last_info->base - || FILENCMP(words[i], - last_info->word, info[i].base) != 0) - { - last_info = &info[i]; - path_order++; - } - info[i].path_order = path_order; - } - qsort(info, nwords, sizeof(struct path_order_info), - path_order_cmp); - for (i = 0; i < nwords; i++) - words[i] = info[i].word; - afree((void *) info, ATEMP); - } else { - /* Sort and remove duplicate entries */ - char **words = (char **) XPptrv(w); - int i, j; - - qsortp(XPptrv(w), (size_t) nwords, xstrcmp); - - for (i = j = 0; i < nwords - 1; i++) { - if (strcmp(words[i], words[i + 1])) - words[j++] = words[i]; - else - afree(words[i], ATEMP); - } - words[j++] = words[i]; - nwords = j; - w.cur = (void **) &words[j]; - } - - XPput(w, NULL); - *wordsp = (char **) XPclose(w); - - return nwords; -} - -#define IS_WORDC(c) !isspace(c) - -static int -x_locate_word(buf, buflen, pos, startp, is_commandp) - const char *buf; - int buflen; - int pos; - int *startp; - int *is_commandp; -{ - int p; - int start, end; - - /* Bad call? Probably should report error */ - if (pos < 0 || pos > buflen) { - *startp = pos; - *is_commandp = 0; - return 0; - } - - 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++) - ; - - if (is_commandp) { - int iscmd; - - /* Figure out if this is a command */ - for (p = start - 1; p >= 0 && isspace(buf[p]); p--) - ; - iscmd = p < 0 || strchr(";|&()", buf[p]); - if (iscmd) { - /* If command has a /, path, etc. is not searched; - * only current directory is searched, which is just - * like file globbing. - */ - for (p = start; p < end; p++) - if (ISDIRSEP(buf[p])) - break; - iscmd = p == end; - } - *is_commandp = iscmd; - } - - *startp = start; - - return end - start; -} - -int -x_cf_glob(flags, buf, buflen, pos, startp, endp, wordsp, is_commandp) - int flags; - const char *buf; - int buflen; - int pos; - int *startp; - int *endp; - char ***wordsp; - int *is_commandp; -{ - int len; - int nwords; - char **words; - int is_command; - - len = x_locate_word(buf, buflen, pos, startp, &is_command); - 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) { - *wordsp = (char **) 0; - return 0; - } - - if (is_commandp) - *is_commandp = is_command; - *wordsp = words; - *endp = *startp + len; - - return nwords; -} - -/* Given a string, copy it and possibly add a '*' to the end. The - * new string is returned. - */ -static char * -add_glob(str, slen) - const char *str; - int slen; -{ - char *toglob; - char *s; - bool_t saw_slash = FALSE; - - if (slen < 0) - return (char *) 0; - - toglob = str_nsave(str, slen + 1, ATEMP); /* + 1 for "*" */ - toglob[slen] = '\0'; - - /* - * If the pathname contains a wildcard (an unquoted '*', - * '?', or '[') or parameter expansion ('$'), or a ~username - * with no trailing slash, then it is globbed based on that - * value (i.e., without the appended '*'). - */ - for (s = toglob; *s; s++) { - if (*s == '\\' && s[1]) - s++; - else if (*s == '*' || *s == '[' || *s == '?' || *s == '$' - || (s[1] == '(' /*)*/ && strchr("*+?@!", *s))) - break; - else if (ISDIRSEP(*s)) - saw_slash = TRUE; - } - if (!*s && (*toglob != '~' || saw_slash)) { - toglob[slen] = '*'; - toglob[slen + 1] = '\0'; - } - - return toglob; -} - -/* - * Find longest common prefix - */ -int -x_longest_prefix(nwords, words) - int nwords; - char *const *words; -{ - int i, j; - int prefix_len; - char *p; - - if (nwords <= 0) - return 0; - - prefix_len = strlen(words[0]); - for (i = 1; i < nwords; i++) - for (j = 0, p = words[i]; j < prefix_len; j++) - if (FILECHCONV(p[j]) != FILECHCONV(words[0][j])) { - prefix_len = j; - break; - } - return prefix_len; -} - -void -x_free_words(nwords, words) - int nwords; - char **words; -{ - int i; - - for (i = 0; i < nwords; i++) - if (words[i]) - afree(words[i], ATEMP); - afree(words, ATEMP); -} - -/* Return the offset of the basename of string s (which ends at se - need not - * be null terminated). Trailing slashes are ignored. If s is just a slash, - * then the offset is 0 (actually, length - 1). - * s Return - * /etc 1 - * /etc/ 1 - * /etc// 1 - * /etc/fo 5 - * foo 0 - * /// 2 - * 0 - */ -int -x_basename(s, se) - const char *s; - const char *se; -{ - const char *p; - - if (se == (char *) 0) - se = s + strlen(s); - if (s == se) - return 0; - - /* Skip trailing slashes */ - for (p = se - 1; p > s && ISDIRSEP(*p); p--) - ; - for (; p > s && !ISDIRSEP(*p); p--) - ; - if (ISDIRSEP(*p) && p + 1 < se) - p++; - - return p - s; -} - -/* - * Apply pattern matching to a table: all table entries that match a pattern - * are added to wp. - */ -static void -glob_table(pat, wp, tp) - const char *pat; - XPtrV *wp; - struct table *tp; -{ - struct tstate ts; - struct tbl *te; - - for (twalk(&ts, tp); (te = tnext(&ts)); ) { - if (gmatch(te->name, pat, FALSE)) - XPput(*wp, str_save(te->name, ATEMP)); - } -} - -static void -glob_path(flags, pat, wp, path) - int flags; - const char *pat; - XPtrV *wp; - const char *path; -{ - const char *sp, *p; - char *xp; - int pathlen; - int patlen; - int oldsize, newsize, i, j; - char **words; - XString xs; - - patlen = strlen(pat) + 1; - sp = path; - Xinit(xs, xp, patlen + 128, ATEMP); - while (sp) { - xp = Xstring(xs, xp); - if (!(p = strchr(sp, PATHSEP))) - p = sp + strlen(sp); - pathlen = p - sp; - if (pathlen) { - /* Copy sp into xp, stuffing any MAGIC characters - * on the way - */ - const char *s = sp; - - XcheckN(xs, xp, pathlen * 2); - while (s < p) { - if (ISMAGIC(*s)) - *xp++ = MAGIC; - *xp++ = *s++; - } - *xp++ = DIRSEP; - pathlen++; - } - sp = p; - XcheckN(xs, xp, patlen); - memcpy(xp, pat, patlen); - - oldsize = XPsize(*wp); - glob_str(Xstring(xs, xp), wp, 0); - newsize = XPsize(*wp); - - /* Check that each match is executable... */ - words = (char **) XPptrv(*wp); - for (i = j = oldsize; i < newsize; i++) { - if (search_access(words[i], X_OK, (int *) 0) >= 0) { - words[j] = words[i]; - if (!(flags & XCF_FULLPATH)) - memmove(words[j], words[j] + pathlen, - strlen(words[j] + pathlen) + 1); - j++; - } else - afree(words[i], ATEMP); - } - wp->cur = (void **) &words[j]; - - if (!*sp++) - break; - } - Xfree(xs, xp); -} - -#endif /* EDIT */ diff --git a/bin/pdksh/edit.h b/bin/pdksh/edit.h deleted file mode 100644 index fd29701cc06..00000000000 --- a/bin/pdksh/edit.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $OpenBSD: edit.h,v 1.2 1996/08/19 20:08:48 downsj Exp $ */ - -/* NAME: - * edit.h - globals for edit modes - * - * DESCRIPTION: - * This header defines various global edit objects. - * - * SEE ALSO: - * - * - * RCSid: - * $From: edit.h,v 1.2 1994/05/19 18:32:40 michael Exp michael $ - * - */ - -/* some useful #defines */ -#ifdef EXTERN -# define I__(i) = i -#else -# define I__(i) -# define EXTERN extern -# define EXTERN_DEFINED -#endif - -#define BEL 0x07 - -/* tty driver characters we are interested in */ -typedef struct { - int erase; - int kill; - int werase; - int intr; - int quit; - int eof; -} X_chars; - -EXTERN X_chars edchars; - -/* x_fc_glob() flags */ -#define XCF_COMMAND BIT(0) /* Do command completion */ -#define XCF_FILE BIT(1) /* Do file completion */ -#define XCF_FULLPATH BIT(2) /* command completion: store full path */ -#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE) - -/* edit.c */ -int x_getc ARGS((void)); -void x_flush ARGS((void)); -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_do_comment ARGS((char *buf, int bsize, int *lenp)); -void x_print_expansions ARGS((int nwords, char *const *words, 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_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)); -/* emacs.c */ -int x_emacs ARGS((char *buf, size_t len)); -void x_init_emacs ARGS((void)); -void x_emacs_keys ARGS((X_chars *ec)); -/* vi.c */ -int x_vi ARGS((char *buf, size_t len)); - - -#ifdef DEBUG -# define D__(x) x -#else -# define D__(x) -#endif - -/* This lot goes at the END */ -/* be sure not to interfere with anyone else's idea about EXTERN */ -#ifdef EXTERN_DEFINED -# undef EXTERN_DEFINED -# undef EXTERN -#endif -#undef I__ -/* - * Local Variables: - * version-control:t - * comment-column:40 - * End: - */ diff --git a/bin/pdksh/emacs-gen.sh b/bin/pdksh/emacs-gen.sh deleted file mode 100644 index 97449de8fa4..00000000000 --- a/bin/pdksh/emacs-gen.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# $OpenBSD: emacs-gen.sh,v 1.1 1996/08/14 06:19:10 downsj Exp $ - -case $# in -1) file=$1;; -*) - echo "$0: Usage: $0 path-to-emacs.c" 1>&2 - exit 1 -esac; - -if [ ! -r "$file" ] ;then - echo "$0: can't read $file" 1>&2 - exit 1 -fi - -cat << E_O_F || exit 1 -/* - * NOTE: THIS FILE WAS GENERATED AUTOMATICALLY FROM $file - * - * DO NOT BOTHER EDITING THIS FILE - */ -E_O_F - -# Pass 1: print out lines before @START-FUNC-TAB@ -# and generate defines and function declarations, -sed -e '1,/@START-FUNC-TAB@/d' -e '/@END-FUNC-TAB@/,$d' < $file | - awk 'BEGIN { nfunc = 0; } - /^[ ]*#/ { - print $0; - next; - } - { - fname = $2; - c = substr(fname, length(fname), 1); - if (c == ",") - fname = substr(fname, 1, length(fname) - 1); - if (fname != "0") { - printf "#define XFUNC_%s %d\n", substr(fname, 3, length(fname) - 2), nfunc; - printf "static int %s ARGS((int c));\n", fname; - nfunc++; - } - }' || exit 1 - -exit 0 diff --git a/bin/pdksh/emacs.c b/bin/pdksh/emacs.c deleted file mode 100644 index db515363a1d..00000000000 --- a/bin/pdksh/emacs.c +++ /dev/null @@ -1,2182 +0,0 @@ -/* $OpenBSD: emacs.c,v 1.4 1997/06/19 13:58:39 kstailey Exp $ */ - -/* - * Emacs-like command line editing and history - * - * created by Ron Natalie at BRL - * modified by Doug Kingston, Doug Gwyn, and Lou Salkind - * adapted to PD ksh by Eric Gisin - */ - -#include "config.h" -#ifdef EMACS - -#include "sh.h" -#include "ksh_stat.h" -#include "ksh_dir.h" -#include <ctype.h> -#include "edit.h" - -static Area aedit; -#define AEDIT &aedit /* area for kill ring and macro defns */ - -#undef CTRL /* _BSD brain damage */ -#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */ -#define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */ - - -/* values returned by keyboard functions */ -#define KSTD 0 -#define KEOL 1 /* ^M, ^J */ -#define KINTR 2 /* ^G, ^C */ - -struct x_ftab { - int (*xf_func) ARGS((int c)); - const char *xf_name; - short xf_flags; -}; - -/* index into struct x_ftab x_ftab[] - small is good */ -typedef unsigned char Findex; - -struct x_defbindings { - Findex xdb_func; /* XFUNC_* */ - char xdb_tab; - unsigned char xdb_char; -}; - -#define XF_ARG 1 /* command takes number prefix */ -#define XF_NOBIND 2 /* not allowed to bind to function */ -#define XF_PREFIX 4 /* function sets prefix */ - -/* Separator for completion */ -#define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'') -#define is_mfs(c) (!(isalnum(c) || c == '_' || c == '$')) /* Separator for motion */ - -#ifdef OS2 - /* Deal with 8 bit chars & an extra prefix for function key (these two - * changes increase memory usage from 9,216 bytes to 24,416 bytes...) - */ -# define CHARMASK 0xFF /* 8-bit ASCII character mask */ -# define X_TABSZ 256 /* size of keydef tables etc */ -# define X_NTABS 4 /* normal, meta1, meta2, meta3 */ -static int x_prefix3 = 0xE0; -#else /* OS2 */ -# define CHARMASK 0x7F /* 7-bit ASCII character mask */ -# define X_TABSZ 128 /* size of keydef tables etc */ -# define X_NTABS 3 /* normal, meta1, meta2 */ -#endif /* OS2 */ - -/* Arguments for do_complete() - * 0 = enumerate M-= complete as much as possible and then list - * 1 = complete M-Esc - * 2 = list M-? - */ -typedef enum { CT_LIST, /* list the possible completions */ - CT_COMPLETE, /* complete to longest prefix */ - CT_COMPLIST /* complete and then list (if non-exact) */ - } Comp_type; - -/* { from 4.9 edit.h */ -/* - * The following are used for my horizontal scrolling stuff - */ -static char *xbuf; /* beg input buffer */ -static char *xend; /* end input buffer */ -static char *xcp; /* current position */ -static char *xep; /* current end */ -static char *xbp; /* start of visible portion of input buffer */ -static char *xlp; /* last char visible on screen */ -static int x_adj_ok; -/* - * we use x_adj_done so that functions can tell - * whether x_adjust() has been called while they are active. - */ -static int x_adj_done; - -static int xx_cols; -static int x_col; -static int x_displen; -static int x_arg; /* general purpose arg */ -static int x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */ - -static int xlp_valid; -/* end from 4.9 edit.h } */ - -static int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X'); -static char **x_histp; /* history position */ -static int x_nextcmd; /* for newline-and-next */ -static char *xmp; /* mark pointer */ -static Findex x_last_command; -static Findex (*x_tab)[X_TABSZ]; /* key definition */ -static char *(*x_atab)[X_TABSZ]; /* macro definitions */ -#define KILLSIZE 20 -static char *killstack[KILLSIZE]; -static int killsp, killtp; -static int x_curprefix; -static char *macroptr; -static int prompt_skip; - -static int x_ins ARGS((char *cp)); -static void x_delete ARGS((int nc, int force_push)); -static int x_bword ARGS((void)); -static int x_fword ARGS((void)); -static void x_goto ARGS((char *cp)); -static void x_bs ARGS((int c)); -static int x_size_str ARGS((char *cp)); -static int x_size ARGS((int c)); -static void x_zots ARGS((char *str)); -static void x_zotc ARGS((int c)); -static void x_load_hist ARGS((char **hp)); -static int x_search ARGS((char *pat, int sameline, int offset)); -static int x_match ARGS((char *str, char *pat)); -static void x_redraw ARGS((int limit)); -static void x_push ARGS((int nchars)); -static char * x_mapin ARGS((const char *cp)); -static char * x_mapout ARGS((int c)); -static void x_print ARGS((int prefix, int key)); -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)); -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)); - - -/* The lines between START-FUNC-TAB .. END-FUNC-TAB are run through a - * script (emacs-gen.sh) that generates emacs.out which contains: - * - function declarations for x_* functions - * - defines of the form XFUNC_<name> where <name> is function - * name, sans leading x_. - * Note that the script treats #ifdef and { 0, 0, 0} specially - use with - * caution. - */ -#include "emacs.out" -static const struct x_ftab x_ftab[] = { -/* @START-FUNC-TAB@ */ - { x_abort, "abort", 0 }, - { x_beg_hist, "beginning-of-history", 0 }, - { x_comp_comm, "complete-command", 0 }, - { x_comp_file, "complete-file", 0 }, - { x_complete, "complete", 0 }, - { x_del_back, "delete-char-backward", XF_ARG }, - { x_del_bword, "delete-word-backward", XF_ARG }, - { x_del_char, "delete-char-forward", XF_ARG }, - { x_del_fword, "delete-word-forward", XF_ARG }, - { x_del_line, "kill-line", 0 }, - { x_draw_line, "redraw", 0 }, - { x_end_hist, "end-of-history", 0 }, - { x_end_of_text, "eot", 0 }, - { x_enumerate, "list", 0 }, - { x_eot_del, "eot-or-delete", XF_ARG }, - { x_error, "error", 0 }, - { x_goto_hist, "goto-history", XF_ARG }, - { x_ins_string, "macro-string", XF_NOBIND }, - { x_insert, "auto-insert", XF_ARG }, - { x_kill, "kill-to-eol", XF_ARG }, - { x_kill_region, "kill-region", 0 }, - { x_list_comm, "list-command", 0 }, - { x_list_file, "list-file", 0 }, - { x_literal, "quote", 0 }, - { x_meta1, "prefix-1", XF_PREFIX }, - { x_meta2, "prefix-2", XF_PREFIX }, - { x_meta_yank, "yank-pop", 0 }, - { x_mv_back, "backward-char", XF_ARG }, - { x_mv_begin, "beginning-of-line", 0 }, - { x_mv_bword, "backward-word", XF_ARG }, - { x_mv_end, "end-of-line", 0 }, - { x_mv_forw, "forward-char", XF_ARG }, - { x_mv_fword, "forward-word", XF_ARG }, - { x_newline, "newline", 0 }, - { x_next_com, "down-history", XF_ARG }, - { x_nl_next_com, "newline-and-next", 0 }, - { x_noop, "no-op", 0 }, - { x_prev_com, "up-history", XF_ARG }, - { x_prev_histword, "prev-hist-word", XF_ARG }, - { x_search_char_forw, "search-character-forward", XF_ARG }, - { x_search_char_back, "search-character-backward", XF_ARG }, - { x_search_hist, "search-history", 0 }, - { x_set_mark, "set-mark-command", 0 }, - { x_stuff, "stuff", 0 }, - { x_stuffreset, "stuff-reset", 0 }, - { x_transpose, "transpose-chars", 0 }, - { x_version, "version", 0 }, - { x_xchg_point_mark, "exchange-point-and-mark", 0 }, - { x_yank, "yank", 0 }, - { x_comp_list, "complete-list", 0 }, - { x_expand, "expand-file", 0 }, - { x_fold_capitialize, "capitalize-word", XF_ARG }, - { 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 - { 0, 0, 0 }, -#endif -#ifdef DEBUG - { x_debug_info, "debug-info", 0 }, -#else - { 0, 0, 0 }, -#endif -#ifdef OS2 - { x_meta3, "prefix-3", XF_PREFIX }, -#else - { 0, 0, 0 }, -#endif -/* @END-FUNC-TAB@ */ - }; - -static struct x_defbindings const x_defbindings[] = { - { XFUNC_del_back, 0, CTRL('?') }, - { XFUNC_del_bword, 1, CTRL('?') }, - { XFUNC_eot_del, 0, CTRL('D') }, - { XFUNC_del_back, 0, CTRL('H') }, - { XFUNC_del_bword, 1, CTRL('H') }, - { XFUNC_del_bword, 1, 'h' }, - { XFUNC_mv_bword, 1, 'b' }, - { XFUNC_mv_fword, 1, 'f' }, - { XFUNC_del_fword, 1, 'd' }, - { XFUNC_mv_back, 0, CTRL('B') }, - { XFUNC_mv_forw, 0, CTRL('F') }, - { XFUNC_search_char_forw, 0, CTRL(']') }, - { XFUNC_search_char_back, 1, CTRL(']') }, - { XFUNC_newline, 0, CTRL('M') }, - { XFUNC_newline, 0, CTRL('J') }, - { XFUNC_end_of_text, 0, CTRL('_') }, - { XFUNC_abort, 0, CTRL('G') }, - { XFUNC_prev_com, 0, CTRL('P') }, - { XFUNC_next_com, 0, CTRL('N') }, - { XFUNC_nl_next_com, 0, CTRL('O') }, - { XFUNC_search_hist, 0, CTRL('R') }, - { XFUNC_beg_hist, 1, '<' }, - { XFUNC_end_hist, 1, '>' }, - { XFUNC_goto_hist, 1, 'g' }, - { XFUNC_mv_end, 0, CTRL('E') }, - { XFUNC_mv_begin, 0, CTRL('A') }, - { XFUNC_draw_line, 0, CTRL('L') }, - { XFUNC_meta1, 0, CTRL('[') }, - { XFUNC_meta2, 0, CTRL('X') }, - { XFUNC_kill, 0, CTRL('K') }, - { 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 - { XFUNC_transpose, 0, CTRL('T') }, -#endif - { XFUNC_complete, 1, CTRL('[') }, - { XFUNC_comp_list, 1, '=' }, - { XFUNC_enumerate, 1, '?' }, - { XFUNC_expand, 1, '*' }, - { XFUNC_comp_file, 1, CTRL('X') }, - { XFUNC_comp_comm, 2, CTRL('[') }, - { XFUNC_list_comm, 2, '?' }, - { XFUNC_list_file, 2, CTRL('Y') }, - { XFUNC_set_mark, 1, ' ' }, - { XFUNC_kill_region, 0, CTRL('W') }, - { XFUNC_xchg_point_mark, 2, CTRL('X') }, - { XFUNC_version, 0, CTRL('V') }, -#ifdef DEBUG - { XFUNC_debug_info, 1, CTRL('H') }, -#endif - { XFUNC_prev_histword, 1, '.' }, - { XFUNC_prev_histword, 1, '_' }, - { XFUNC_set_arg, 1, '0' }, - { XFUNC_set_arg, 1, '1' }, - { XFUNC_set_arg, 1, '2' }, - { XFUNC_set_arg, 1, '3' }, - { XFUNC_set_arg, 1, '4' }, - { XFUNC_set_arg, 1, '5' }, - { XFUNC_set_arg, 1, '6' }, - { XFUNC_set_arg, 1, '7' }, - { XFUNC_set_arg, 1, '8' }, - { XFUNC_set_arg, 1, '9' }, - { XFUNC_fold_upper, 1, 'U' }, - { XFUNC_fold_upper, 1, 'u' }, - { XFUNC_fold_lower, 1, 'L' }, - { XFUNC_fold_lower, 1, 'l' }, - { XFUNC_fold_capitialize, 1, 'C' }, - { XFUNC_fold_capitialize, 1, 'c' }, -#ifdef OS2 - { XFUNC_meta3, 0, 0xE0 }, - { XFUNC_mv_back, 3, 'K' }, - { XFUNC_mv_forw, 3, 'M' }, - { XFUNC_next_com, 3, 'P' }, - { XFUNC_prev_com, 3, 'H' }, -#else /* OS2 */ - /* These for ansi arrow keys: arguablely shouldn't be here by - * default, but its simpler/faster/smaller than using termcap - * entries. - */ - { XFUNC_meta2, 1, '[' }, - { XFUNC_prev_com, 2, 'A' }, - { XFUNC_next_com, 2, 'B' }, - { XFUNC_mv_forw, 2, 'C' }, - { XFUNC_mv_back, 2, 'D' }, -#endif /* OS2 */ -}; - -int -x_emacs(buf, len) - char *buf; - size_t len; -{ - int c; - const char *p; - int i; - Findex f; - - xbp = xbuf = buf; xend = buf + len; - xlp = xcp = xep = buf; - *xcp = 0; - xlp_valid = TRUE; - xmp = NULL; - x_curprefix = 0; - macroptr = (char *) 0; - 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 = xx_cols - 2 - x_col; - x_adj_done = 0; - - pprompt(prompt, 0); - - if (x_nextcmd >= 0) { - int off = source->line - x_nextcmd; - if (histptr - history >= off) - x_load_hist(histptr - off); - x_nextcmd = -1; - } - - while (1) { - x_flush(); - if ((c = x_e_getc()) < 0) - return 0; - - f = x_curprefix == -1 ? XFUNC_insert - : x_tab[x_curprefix][c&CHARMASK]; - - if (!(x_ftab[f].xf_flags & XF_PREFIX) - && x_last_command != XFUNC_set_arg) - { - x_arg = 1; - x_arg_defaulted = 1; - } - i = c | (x_curprefix << 8); - x_curprefix = 0; - switch (i = (*x_ftab[f].xf_func)(i)) { - case KSTD: - if (!(x_ftab[f].xf_flags & XF_PREFIX)) - x_last_command = f; - break; - case KEOL: - i = xep - xbuf; - return i; - case KINTR: /* special case for interrupt */ - trapsig(SIGINT); - x_mode(FALSE); - unwind(LSHELL); - } - } -} - -static int -x_insert(c) - int c; -{ - char str[2]; - - /* - * Should allow tab and control chars. - */ - if (c == 0) { - x_e_putc(BEL); - return KSTD; - } - str[0] = c; - str[1] = '\0'; - while (x_arg--) - x_ins(str); - return KSTD; -} - -static int -x_ins_string(c) - int c; -{ - if (macroptr) { - x_e_putc(BEL); - return KSTD; - } - macroptr = x_atab[c>>8][c & CHARMASK]; - if (macroptr && !*macroptr) { - /* XXX bell? */ - macroptr = (char *) 0; - } - return KSTD; -} - -static int -x_do_ins(cp, len) - const char *cp; - int len; -{ - if (xep+len >= xend) { - x_e_putc(BEL); - return -1; - } - - memmove(xcp+len, xcp, xep - xcp + 1); - memmove(xcp, cp, len); - xcp += len; - xep += len; - return 0; -} - -static int -x_ins(s) - char *s; -{ - char *cp = xcp; - register int adj = x_adj_done; - - if (x_do_ins(s, strlen(s)) < 0) - return -1; - /* - * x_zots() may result in a call to x_adjust() - * we want xcp to reflect the new position. - */ - xlp_valid = FALSE; - x_lastcp(); - x_adj_ok = (xcp >= xlp); - x_zots(cp); - if (adj == x_adj_done) /* has x_adjust() been called? */ - { - /* no */ - for (cp = xlp; cp > xcp; ) - x_bs(*--cp); - } - - x_adj_ok = 1; - return 0; -} - -static int -x_del_back(c) - int c; -{ - int col = xcp - xbuf; - - if (col == 0) { - x_e_putc(BEL); - return KSTD; - } - if (x_arg > col) - x_arg = col; - x_goto(xcp - x_arg); - x_delete(x_arg, FALSE); - return KSTD; -} - -static int -x_del_char(c) - int c; -{ - int nleft = xep - xcp; - - if (!nleft) { - x_e_putc(BEL); - return KSTD; - } - if (x_arg > nleft) - x_arg = nleft; - x_delete(x_arg, FALSE); - return KSTD; -} - -/* Delete nc chars to the right of the cursor (including cursor position) */ -static void -x_delete(nc, force_push) - int nc; - int force_push; -{ - int i,j; - char *cp; - - if (nc == 0) - return; - if (xmp != NULL && xmp > xcp) { - if (xcp + nc > xmp) - xmp = xcp; - else - xmp -= nc; - } - - /* - * This lets us yank a word we have deleted. - */ - if (nc > 1 || force_push) - x_push(nc); - - xep -= nc; - cp = xcp; - j = 0; - i = nc; - while (i--) { - j += x_size(*cp++); - } - memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */ - x_adj_ok = 0; /* don't redraw */ - x_zots(xcp); - /* - * if we are already filling the line, - * there is no need to ' ','\b'. - * But if we must, make sure we do the minimum. - */ - if ((i = xx_cols - 2 - x_col) > 0) - { - j = (j < i) ? j : i; - i = j; - while (i--) - x_e_putc(' '); - i = j; - while (i--) - x_e_putc('\b'); - } - /*x_goto(xcp);*/ - x_adj_ok = 1; - xlp_valid = FALSE; - for (cp = x_lastcp(); cp > xcp; ) - x_bs(*--cp); - - return; -} - -static int -x_del_bword(c) - int c; -{ - x_delete(x_bword(), FALSE); - return KSTD; -} - -static int -x_mv_bword(c) - int c; -{ - (void)x_bword(); - return KSTD; -} - -static int -x_mv_fword(c) - int c; -{ - x_goto(xcp + x_fword()); - return KSTD; -} - -static int -x_del_fword(c) - int c; -{ - x_delete(x_fword(), FALSE); - return KSTD; -} - -static int -x_bword() -{ - int nc = 0; - register char *cp = xcp; - - if (cp == xbuf) { - x_e_putc(BEL); - return 0; - } - while (x_arg--) - { - while (cp != xbuf && is_mfs(cp[-1])) - { - cp--; - nc++; - } - while (cp != xbuf && !is_mfs(cp[-1])) - { - cp--; - nc++; - } - } - x_goto(cp); - return nc; -} - -static int -x_fword() -{ - int nc = 0; - register char *cp = xcp; - - if (cp == xep) { - x_e_putc(BEL); - return 0; - } - while (x_arg--) - { - while (cp != xep && is_mfs(*cp)) - { - cp++; - nc++; - } - while (cp != xep && !is_mfs(*cp)) - { - cp++; - nc++; - } - } - return nc; -} - -static void -x_goto(cp) - register char *cp; -{ - if (cp < xbp || cp >= (xbp + x_displen)) - { - /* we are heading off screen */ - xcp = cp; - x_adjust(); - } - else - { - if (cp < xcp) /* move back */ - { - while (cp < xcp) - x_bs(*--xcp); - } - else - { - if (cp > xcp) /* move forward */ - { - while (cp > xcp) - x_zotc(*xcp++); - } - } - } -} - -static void -x_bs(c) - int c; -{ - register i; - i = x_size(c); - while (i--) - x_e_putc('\b'); -} - -static int -x_size_str(cp) - register char *cp; -{ - register size = 0; - while (*cp) - size += x_size(*cp++); - return size; -} - -static int -x_size(c) - int c; -{ - if (c=='\t') - return 4; /* Kludge, tabs are always four spaces. */ - if (c < ' ' || c == 0x7F) /* ASCII control char */ - return 2; - return 1; -} - -static void -x_zots(str) - register char *str; -{ - register int adj = x_adj_done; - - x_lastcp(); - while (*str && str < xlp && adj == x_adj_done) - x_zotc(*str++); -} - -static void -x_zotc(c) - int c; -{ - if (c == '\t') { - /* Kludge, tabs are always four spaces. */ - x_e_puts(" "); - } else if (c < ' ' || c == 0x7F) { /* ASCII */ - x_e_putc('^'); - x_e_putc(UNCTRL(c)); - } else - x_e_putc(c); -} - -static int -x_mv_back(c) - int c; -{ - int col = xcp - xbuf; - - if (col == 0) { - x_e_putc(BEL); - return KSTD; - } - if (x_arg > col) - x_arg = col; - x_goto(xcp - x_arg); - return KSTD; -} - -static int -x_mv_forw(c) - int c; -{ - int nleft = xep - xcp; - - if (!nleft) { - x_e_putc(BEL); - return KSTD; - } - if (x_arg > nleft) - x_arg = nleft; - x_goto(xcp + x_arg); - return KSTD; -} - -static int -x_search_char_forw(c) - int c; -{ - char *cp = xcp; - - *xep = '\0'; - c = x_e_getc(); - while (x_arg--) { - if (c < 0 - || ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL - && (cp = strchr(xbuf, c)) == NULL)) - { - x_e_putc(BEL); - return KSTD; - } - } - x_goto(cp); - return KSTD; -} - -static int -x_search_char_back(c) - int c; -{ - char *cp = xcp, *p; - - c = x_e_getc(); - for (; x_arg--; cp = p) - for (p = cp; ; ) { - if (p-- == xbuf) - p = xep; - if (c < 0 || p == cp) { - x_e_putc(BEL); - return KSTD; - } - if (*p == c) - break; - } - x_goto(cp); - return KSTD; -} - -static int -x_newline(c) - int c; -{ - x_e_putc('\r'); - x_e_putc('\n'); - x_flush(); - *xep++ = '\n'; - return KEOL; -} - -static int -x_end_of_text(c) - int c; -{ - return KEOL; -} - -static int x_beg_hist(c) int c; { x_load_hist(history); return KSTD;} - -static int x_end_hist(c) int c; { x_load_hist(histptr); return KSTD;} - -static int x_prev_com(c) int c; { x_load_hist(x_histp - x_arg); return KSTD;} - -static int x_next_com(c) int c; { x_load_hist(x_histp + x_arg); return KSTD;} - -/* Goto a particular history number obtained from argument. - * If no argument is given history 1 is probably not what you - * want so we'll simply go to the oldest one. - */ -static int -x_goto_hist(c) - int c; -{ - if (x_arg_defaulted) - x_load_hist(history); - else - x_load_hist(histptr + x_arg - source->line); - return KSTD; -} - -static void -x_load_hist(hp) - register char **hp; -{ - int oldsize; - - if (hp < history || hp > histptr) { - x_e_putc(BEL); - return; - } - x_histp = hp; - oldsize = x_size_str(xbuf); - (void)strcpy(xbuf, *hp); - xbp = xbuf; - xep = xcp = xbuf + strlen(*hp); - xlp_valid = FALSE; - if (xep > x_lastcp()) - x_goto(xep); - else - x_redraw(oldsize); -} - -static int -x_nl_next_com(c) - int c; -{ - x_nextcmd = source->line - (histptr - x_histp) + 1; - return (x_newline(c)); -} - -static int -x_eot_del(c) - int c; -{ - if (xep == xbuf && x_arg_defaulted) - return (x_end_of_text(c)); - else - return (x_del_char(c)); -} - -/* reverse incremental history search */ -static int -x_search_hist(c) - int c; -{ - int offset = -1; /* offset of match in xbuf, else -1 */ - char pat [256+1]; /* pattern buffer */ - register char *p = pat; - Findex f; - - *p = '\0'; - while (1) { - if (offset < 0) { - x_e_puts("\nI-search: "); - x_e_puts(pat); - } - x_flush(); - if ((c = x_e_getc()) < 0) - return KSTD; - f = x_tab[0][c&CHARMASK]; - if (c == CTRL('[')) - break; - else if (f == XFUNC_search_hist) - offset = x_search(pat, 0, offset); - else if (f == XFUNC_del_back) { - if (p == pat) { - offset = -1; - break; - } - if (p > pat) - *--p = '\0'; - if (p == pat) - offset = -1; - else - offset = x_search(pat, 1, offset); - continue; - } else if (f == XFUNC_insert) { - /* add char to pattern */ - /* overflow check... */ - if (p >= &pat[sizeof(pat) - 1]) { - x_e_putc(BEL); - continue; - } - *p++ = c, *p = '\0'; - if (offset >= 0) { - /* already have partial match */ - offset = x_match(xbuf, pat); - if (offset >= 0) { - x_goto(xbuf + offset + (p - pat) - (*pat == '^')); - continue; - } - } - offset = x_search(pat, 0, offset); - } else { /* other command */ - x_e_ungetc(c); - break; - } - } - if (offset < 0) - x_redraw(-1); - return KSTD; -} - -/* search backward from current line */ -static int -x_search(pat, sameline, offset) - char *pat; - int sameline; - int offset; -{ - register char **hp; - int i; - - for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) { - i = x_match(*hp, pat); - if (i >= 0) { - if (offset < 0) - x_e_putc('\n'); - x_load_hist(hp); - x_goto(xbuf + i + strlen(pat) - (*pat == '^')); - return i; - } - } - x_e_putc(BEL); - x_histp = histptr; - return -1; -} - -/* return position of first match of pattern in string, else -1 */ -static int -x_match(str, pat) - char *str, *pat; -{ - if (*pat == '^') { - return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1; - } else { - char *q = strstr(str, pat); - return (q == NULL) ? -1 : q - str; - } -} - -static int -x_del_line(c) - int c; -{ - int i, j; - - *xep = 0; - i = xep- xbuf; - j = x_size_str(xbuf); - xcp = xbuf; - x_push(i); - xlp = xbp = xep = xbuf; - xlp_valid = TRUE; - *xcp = 0; - xmp = NULL; - x_redraw(j); - return KSTD; -} - -static int -x_mv_end(c) - int c; -{ - x_goto(xep); - return KSTD; -} - -static int -x_mv_begin(c) - int c; -{ - x_goto(xbuf); - return KSTD; -} - -static int -x_draw_line(c) - int c; -{ - x_redraw(-1); - return KSTD; - -} - -/* 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; -{ - int i, j; - char *cp; - - x_adj_ok = 0; - if (limit == -1) - x_e_putc('\n'); - else - x_e_putc('\r'); - x_flush(); - if (xbp == xbuf) - { - pprompt(prompt + prompt_skip, 0); - x_col = promptlen(prompt, (const char **) 0); - } - x_displen = xx_cols - 2 - x_col; - xlp_valid = FALSE; - cp = x_lastcp(); - x_zots(xbp); - if (xbp != xbuf || xep > xlp) - limit = xx_cols; - if (limit >= 0) - { - if (xep > xlp) - i = 0; /* we fill the line */ - else - i = limit - (xlp - xbp); - - for (j = 0; j < i && x_col < (xx_cols - 2); j++) - x_e_putc(' '); - i = ' '; - if (xep > xlp) /* more off screen */ - { - if (xbp > xbuf) - i = '*'; - else - i = '>'; - } - else - if (xbp > xbuf) - i = '<'; - x_e_putc(i); - j++; - while (j--) - x_e_putc('\b'); - } - for (cp = xlp; cp > xcp; ) - x_bs(*--cp); - x_adj_ok = 1; - D__(x_flush();) - return; -} - -static int -x_transpose(c) - int c; -{ - char tmp; - - /* What transpose is meant to do seems to be up for debate. This - * is a general summary of the options; the text is abcd with the - * upper case character or underscore indicating the cursor positiion: - * Who Before After Before After - * at&t ksh in emacs mode: abCd abdC abcd_ (bell) - * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_ - * gnu emacs: abCd acbD abcd_ abdc_ - * Pdksh currently goes with GNU behavior since I believe this is the - * most common version of emacs, unless in gmacs mode, in which case - * it does the at&t ksh gmacs mdoe. - * This should really be broken up into 3 functions so users can bind - * to the one they want. - */ - if (xcp == xbuf) { - x_e_putc(BEL); - return KSTD; - } else if (xcp == xep || Flag(FGMACS)) { - if (xcp - xbuf == 1) { - x_e_putc(BEL); - return KSTD; - } - /* Gosling/Unipress emacs style: Swap two characters before the - * cursor, do not change cursor position - */ - x_bs(xcp[-1]); - x_bs(xcp[-2]); - x_zotc(xcp[-1]); - x_zotc(xcp[-2]); - tmp = xcp[-1]; - xcp[-1] = xcp[-2]; - xcp[-2] = tmp; - } else { - /* GNU emacs style: Swap the characters before and under the - * cursor, move cursor position along one. - */ - x_bs(xcp[-1]); - x_zotc(xcp[0]); - x_zotc(xcp[-1]); - tmp = xcp[-1]; - xcp[-1] = xcp[0]; - xcp[0] = tmp; - x_bs(xcp[0]); - x_goto(xcp + 1); - } - return KSTD; -} - -static int -x_literal(c) - int c; -{ - x_curprefix = -1; - return KSTD; -} - -static int -x_meta1(c) - int c; -{ - x_curprefix = 1; - return KSTD; -} - -static int -x_meta2(c) - int c; -{ - x_curprefix = 2; - return KSTD; -} - -#ifdef OS2 -static int -x_meta3(c) - int c; -{ - x_curprefix = 3; - return KSTD; -} -#endif /* OS2 */ - -static int -x_kill(c) - int c; -{ - int col = xcp - xbuf; - int lastcol = xep - xbuf; - int ndel; - - if (x_arg_defaulted) - x_arg = lastcol; - else if (x_arg > lastcol) - x_arg = lastcol; - ndel = x_arg - col; - if (ndel < 0) { - x_goto(xbuf + x_arg); - ndel = -ndel; - } - x_delete(ndel, TRUE); - return KSTD; -} - -static void -x_push(nchars) - int nchars; -{ - char *cp = str_nsave(xcp, nchars, AEDIT); - if (killstack[killsp]) - afree((void *)killstack[killsp], AEDIT); - killstack[killsp] = cp; - killsp = (killsp + 1) % KILLSIZE; -} - -static int -x_yank(c) - int c; -{ - if (killsp == 0) - killtp = KILLSIZE; - else - killtp = killsp; - killtp --; - if (killstack[killtp] == 0) { - x_e_puts("\nnothing to yank"); - x_redraw(-1); - return KSTD; - } - xmp = xcp; - x_ins(killstack[killtp]); - return KSTD; -} - -static int -x_meta_yank(c) - int c; -{ - int len; - if (x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) { - x_e_puts("\nyank something first"); - x_redraw(-1); - return KSTD; - } - len = strlen(killstack[killtp]); - x_goto(xcp - len); - x_delete(len, FALSE); - do { - if (killtp == 0) - killtp = KILLSIZE - 1; - else - killtp--; - } while (killstack[killtp] == 0); - x_ins(killstack[killtp]); - return KSTD; -} - -static int -x_abort(c) - int c; -{ - /* x_zotc(c); */ - xlp = xep = xcp = xbp = xbuf; - xlp_valid = TRUE; - *xcp = 0; - return KINTR; -} - -static int -x_error(c) - int c; -{ - x_e_putc(BEL); - return KSTD; -} - -static int -x_stuffreset(c) - int c; -{ -#ifdef TIOCSTI - (void)x_stuff(c); - return KINTR; -#else - x_zotc(c); - xlp = xcp = xep = xbp = xbuf; - xlp_valid = TRUE; - *xcp = 0; - x_redraw(-1); - return KSTD; -#endif -} - -static int -x_stuff(c) - int c; -{ -#if 0 || defined TIOCSTI - char ch = c; - bool_t savmode = x_mode(FALSE); - - (void)ioctl(TTY, TIOCSTI, &ch); - (void)x_mode(savmode); - x_redraw(-1); -#endif - return KSTD; -} - -static char * -x_mapin(cp) - const char *cp; -{ - char *new, *op; - - op = new = str_save(cp, ATEMP); - while (*cp) { - /* XXX -- should handle \^ escape? */ - if (*cp == '^') { - cp++; -#ifdef OS2 - if (*cp == '0') /* To define function keys */ - *op++ = 0xE0; - else -#endif /* OS2 */ - if (*cp >= '?') /* includes '?'; ASCII */ - *op++ = CTRL(*cp); - else { - *op++ = '^'; - cp--; - } - } else - *op++ = *cp; - cp++; - } - *op = '\0'; - - return new; -} - -static char * -x_mapout(c) - int c; -{ - static char buf[8]; - register char *p = buf; - - if (c < ' ' || c == 0x7F) { /* ASCII */ - *p++ = '^'; - *p++ = (c == 0x7F) ? '?' : (c | 0x40); -#ifdef OS2 - } else if (c == 0xE0) { - *p++ = '^'; - *p++ = '0'; -#endif /* OS2 */ - } else - *p++ = c; - *p = 0; - return buf; -} - -static void -x_print(prefix, key) - int prefix, key; -{ - if (prefix == 1) - shprintf("%s", x_mapout(x_prefix1)); - if (prefix == 2) - shprintf("%s", x_mapout(x_prefix2)); -#ifdef OS2 - if (prefix == 3) - shprintf("%s", x_mapout(x_prefix3)); -#endif /* OS2 */ - shprintf("%s = ", x_mapout(key)); - if (x_tab[prefix][key] != XFUNC_ins_string) - shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name); - else - shprintf("'%s'\n", x_atab[prefix][key]); -} - -int -x_bind(a1, a2, macro, list) - const char *a1, *a2; - int macro; /* bind -m */ - int list; /* bind -l */ -{ - Findex f; - int prefix, key; - char *sp = NULL; - char *m1, *m2; - - if (x_tab == NULL) { - bi_errorf("cannot bind, not a tty"); - return 1; - } - - /* List function names */ - if (list) { - for (f = 0; f < NELEM(x_ftab); f++) - if (x_ftab[f].xf_name - && !(x_ftab[f].xf_flags & XF_NOBIND)) - shprintf("%s\n", x_ftab[f].xf_name); - return 0; - } - - if (a1 == NULL) { - for (prefix = 0; prefix < X_NTABS; prefix++) - for (key = 0; key < X_TABSZ; key++) { - f = x_tab[prefix][key]; - if (f == XFUNC_insert || f == XFUNC_error - || (macro && f != XFUNC_ins_string)) - continue; - x_print(prefix, key); - } - return 0; - } - - m1 = x_mapin(a1); - prefix = key = 0; - for (;; m1++) { - key = *m1 & CHARMASK; - if (x_tab[prefix][key] == XFUNC_meta1) - prefix = 1; - else if (x_tab[prefix][key] == XFUNC_meta2) - prefix = 2; -#ifdef OS2 - else if (x_tab[prefix][key] == XFUNC_meta3) - prefix = 3; -#endif /* OS2 */ - else - break; - } - - if (a2 == NULL) { - x_print(prefix, key); - return 0; - } - - if (*a2 == 0) - f = XFUNC_insert; - else if (!macro) { - for (f = 0; f < NELEM(x_ftab); f++) - if (x_ftab[f].xf_name - && strcmp(x_ftab[f].xf_name, a2) == 0) - break; - if (f == NELEM(x_ftab) || x_ftab[f].xf_flags & XF_NOBIND) { - bi_errorf("%s: no such function", a2); - return 1; - } -#if 0 /* This breaks the bind commands that map arrow keys */ - if (f == XFUNC_meta1) - x_prefix1 = key; - if (f == XFUNC_meta2) - x_prefix2 = key; -#endif /* 0 */ - } else { - f = XFUNC_ins_string; - m2 = x_mapin(a2); - sp = str_save(m2, AEDIT); - } - - if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key]) - afree((void *)x_atab[prefix][key], AEDIT); - x_tab[prefix][key] = f; - x_atab[prefix][key] = sp; - - return 0; -} - -void -x_init_emacs() -{ - register int i, j; - - ainit(AEDIT); - x_nextcmd = -1; - - x_tab = (Findex (*)[X_TABSZ]) alloc(sizeofN(*x_tab, X_NTABS), AEDIT); - for (j = 0; j < X_TABSZ; j++) - x_tab[0][j] = XFUNC_insert; - for (i = 1; i < X_NTABS; i++) - for (j = 0; j < X_TABSZ; j++) - x_tab[i][j] = XFUNC_error; - for (i = 0; i < NELEM(x_defbindings); i++) - x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char] - = x_defbindings[i].xdb_func; - - x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT); - for (i = 1; i < X_NTABS; i++) - for (j = 0; j < X_TABSZ; j++) - x_atab[i][j] = NULL; -} - -void -x_emacs_keys(ec) - X_chars *ec; -{ - x_tab[0][ec->erase] = XFUNC_del_back; - x_tab[0][ec->kill] = XFUNC_del_line; - x_tab[0][ec->werase] = XFUNC_del_bword; - x_tab[0][ec->intr] = XFUNC_abort; - x_tab[0][ec->quit] = XFUNC_noop; - x_tab[1][ec->erase] = XFUNC_del_bword; -} - -static int -x_set_mark(c) - int c; -{ - xmp = xcp; - return KSTD; -} - -static int -x_kill_region(c) - int c; -{ - int rsize; - char *xr; - - if (xmp == NULL) { - x_e_putc(BEL); - return KSTD; - } - if (xmp > xcp) { - rsize = xmp - xcp; - xr = xcp; - } else { - rsize = xcp - xmp; - xr = xmp; - } - x_goto(xr); - x_delete(rsize, TRUE); - xmp = xr; - return KSTD; -} - -static int -x_xchg_point_mark(c) - int c; -{ - char *tmp; - - if (xmp == NULL) { - x_e_putc(BEL); - return KSTD; - } - tmp = xmp; - xmp = xcp; - x_goto( tmp ); - return KSTD; -} - -static int -x_version(c) - int c; -{ - char *o_xbuf = xbuf, *o_xend = xend; - char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp; - int lim = x_lastcp() - xbp; - - xbuf = xbp = xcp = (char *) ksh_version + 4; - xend = xep = (char *) ksh_version + 4 + strlen(ksh_version + 4); - x_redraw(lim); - x_flush(); - - c = x_e_getc(); - xbuf = o_xbuf; - xend = o_xend; - xbp = o_xbp; - xep = o_xep; - xcp = o_xcp; - x_redraw(strlen(ksh_version)); - - if (c < 0) - return KSTD; - /* This is what at&t ksh seems to do... Very bizarre */ - if (c != ' ') - x_e_ungetc(c); - - return KSTD; -} - -static int -x_noop(c) - int c; -{ - return KSTD; -} - -#ifdef SILLY -static int -x_game_of_life(c) - int c; -{ - char newbuf [256+1]; - register char *ip, *op; - int i, len; - - i = xep - xbuf; - *xep = 0; - len = x_size_str(xbuf); - xcp = xbp = xbuf; - memmove(newbuf+1, xbuf, i); - newbuf[0] = 'A'; - newbuf[i] = 'A'; - for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) { - /* Empty space */ - if (*ip < '@' || *ip == '_' || *ip == 0x7F) { - /* Two adults, make whoopee */ - if (ip[-1] < '_' && ip[1] < '_') { - /* Make kid look like parents. */ - *op = '`' + ((ip[-1] + ip[1])/2)%32; - if (*op == 0x7F) /* Birth defect */ - *op = '`'; - } - else - *op = ' '; /* nothing happens */ - continue; - } - /* Child */ - if (*ip > '`') { - /* All alone, dies */ - if (ip[-1] == ' ' && ip[1] == ' ') - *op = ' '; - else /* Gets older */ - *op = *ip-'`'+'@'; - continue; - } - /* Adult */ - /* Overcrowded, dies */ - if (ip[-1] >= '@' && ip[1] >= '@') { - *op = ' '; - continue; - } - *op = *ip; - } - *op = 0; - x_redraw(len); - return KSTD; -} -#endif - -/* - * File/command name completion routines - */ - - -static int -x_comp_comm(c) - int c; -{ - do_complete(XCF_COMMAND, CT_COMPLETE); - return KSTD; -} -static int -x_list_comm(c) - int c; -{ - do_complete(XCF_COMMAND, CT_LIST); - return KSTD; -} -static int -x_complete(c) - int c; -{ - do_complete(XCF_COMMAND_FILE, CT_COMPLETE); - return KSTD; -} -static int -x_enumerate(c) - int c; -{ - do_complete(XCF_COMMAND_FILE, CT_LIST); - return KSTD; -} -static int -x_comp_file(c) - int c; -{ - do_complete(XCF_FILE, CT_COMPLETE); - return KSTD; -} -static int -x_list_file(c) - int c; -{ - do_complete(XCF_FILE, CT_LIST); - return KSTD; -} -static int -x_comp_list(c) - int c; -{ - do_complete(XCF_COMMAND_FILE, CT_COMPLIST); - return KSTD; -} -static int -x_expand(c) - int c; -{ - char **words; - int nwords = 0; - int start, end; - int is_command; - int i; - - nwords = x_cf_glob(XCF_FILE, - xbuf, xep - xbuf, xcp - xbuf, - &start, &end, &words, &is_command); - - if (nwords == 0) { - x_e_putc(BEL); - return KSTD; - } - - x_goto(xbuf + start); - x_delete(end - start, FALSE); - for (i = 0; i < nwords; i++) - if (x_ins(words[i]) < 0 || (i < nwords - 1 && x_ins(space) < 0)) - { - x_e_putc(BEL); - return KSTD; - } - - return KSTD; -} - -/* type == 0 for list, 1 for complete and 2 for complete-list */ -static void -do_complete(flags, type) - int flags; /* XCF_{COMMAND,FILE,COMMAND_FILE} */ - Comp_type type; -{ - char **words; - int nwords = 0; - int start, end; - int is_command; - int do_glob = 1; - Comp_type t = type; - char *comp_word = (char *) 0; - - if (type == CT_COMPLIST) { - do_glob = 0; - /* decide what we will do */ - nwords = x_cf_glob(flags, - xbuf, xep - xbuf, xcp - xbuf, - &start, &end, &words, &is_command); - if (nwords > 0) { - if (nwords > 1) { - int len = x_longest_prefix(nwords, words); - - t = CT_LIST; - /* Do completion if prefix matches original - * prefix (ie, no globbing chars), otherwise - * don't bother - */ - if (strncmp(words[0], xbuf + start, end - start) - == 0) - comp_word = str_nsave(words[0], len, - ATEMP); - else - type = CT_LIST; - /* Redo globing to show full paths if this - * is a command. - */ - if (is_command) { - do_glob = 1; - x_free_words(nwords, words); - } - } else - type = t = CT_COMPLETE; - } - } - if (do_glob) - nwords = x_cf_glob(flags | (t == CT_LIST ? XCF_FULLPATH : 0), - xbuf, xep - xbuf, xcp - xbuf, - &start, &end, &words, &is_command); - if (nwords == 0) { - x_e_putc(BEL); - return; - } - switch (type) { - case CT_LIST: - x_print_expansions(nwords, words, is_command); - x_redraw(0); - break; - - case CT_COMPLIST: - /* Only get here if nwords > 1 && comp_word is set */ - { - int olen = end - start; - int nlen = strlen(comp_word); - - x_print_expansions(nwords, words, is_command); - xcp = xbuf + end; - x_do_ins(comp_word + olen, nlen - olen); - x_redraw(0); - } - break; - - case CT_COMPLETE: - { - int nlen = x_longest_prefix(nwords, words); - - if (nlen > 0) { - x_goto(xbuf + start); - x_delete(end - start, FALSE); - words[0][nlen] = '\0'; - x_ins(words[0]); - /* If single match is not a directory, add a - * space to the end... - */ - if (nwords == 1 - && !ISDIRSEP(words[0][nlen - 1])) - x_ins(space); - } else - x_e_putc(BEL); - } - break; - } -} - -/* NAME: - * x_adjust - redraw the line adjusting starting point etc. - * - * DESCRIPTION: - * This function is called when we have exceeded the bounds - * of the edit window. It increments x_adj_done so that - * functions like x_ins and x_delete know that we have been - * called and can skip the x_bs() stuff which has already - * been done by x_redraw. - * - * RETURN VALUE: - * None - */ - -static void -x_adjust() -{ - x_adj_done++; /* flag the fact that we were called. */ - /* - * 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(xx_cols); - x_flush(); -} - -static int unget_char = -1; - -static void -x_e_ungetc(c) - int c; -{ - unget_char = c; -} - -static int -x_e_getc() -{ - int c; - - if (unget_char >= 0) { - c = unget_char; - unget_char = -1; - } else { - if (macroptr) { - c = *macroptr++; - if (!*macroptr) - macroptr = (char *) 0; - } else - c = x_getc(); - } - - return c <= CHARMASK ? c : (c & CHARMASK); -} - -static void -x_e_putc(c) - int c; -{ - if (c == '\r' || c == '\n') - x_col = 0; - if (x_col < xx_cols) - { - x_putc(c); - switch(c) - { - case BEL: - break; - case '\r': - case '\n': - break; - case '\b': - x_col--; - break; - default: - x_col++; - break; - } - } - if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2))) - { - x_adjust(); - } -} - -#ifdef DEBUG -static int -x_debug_info(c) - int c; -{ - 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 - -static void -x_e_puts(s) - const char *s; -{ - register int adj = x_adj_done; - - while (*s && adj == x_adj_done) - x_e_putc(*s++); -} - -/* NAME: - * x_set_arg - set an arg value for next function - * - * DESCRIPTION: - * This is a simple implementation of M-[0-9]. - * - * RETURN VALUE: - * KSTD - */ - -static int -x_set_arg(c) - int c; -{ - int n = 0; - int first = 1; - - c &= CHARMASK; /* strip command prefix */ - for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0) - n = n * 10 + (c - '0'); - if (c < 0 || first) { - x_e_putc(BEL); - x_arg = 1; - x_arg_defaulted = 1; - } else { - x_e_ungetc(c); - x_arg = n; - x_arg_defaulted = 0; - } - return KSTD; -} - - -/* 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 - * - * DESCRIPTION: - * This function recovers the last word from the previous - * command and inserts it into the current edit line. If a - * numeric arg is supplied then the n'th word from the - * start of the previous command is used. - * - * Bound to M-. - * - * RETURN VALUE: - * KSTD - */ - -static int -x_prev_histword(c) - int c; -{ - register char *rcp; - char *cp; - char **hp; - - hp = x_histp-1; - if (hp < history || hp > histptr) - { - x_e_putc(BEL); - return KSTD; - } - cp = *hp; - if (x_arg_defaulted) { - rcp = &cp[strlen(cp) - 1]; - /* - * ignore white-space after the last word - */ - while (rcp > cp && is_cfs(*rcp)) - rcp--; - while (rcp > cp && !is_cfs(*rcp)) - rcp--; - if (is_cfs(*rcp)) - rcp++; - x_ins(rcp); - } else { - int c; - - rcp = cp; - /* - * ignore white-space at start of line - */ - while (*rcp && is_cfs(*rcp)) - rcp++; - while (x_arg-- > 1) - { - while (*rcp && !is_cfs(*rcp)) - rcp++; - while (*rcp && is_cfs(*rcp)) - rcp++; - } - cp = rcp; - while (*rcp && !is_cfs(*rcp)) - rcp++; - c = *rcp; - *rcp = '\0'; - x_ins(cp); - *rcp = c; - } - return KSTD; -} - -/* Uppercase N(1) words */ -static int -x_fold_upper(c) - int c; -{ - return x_fold_case('U'); -} - -/* Lowercase N(1) words */ -static int -x_fold_lower(c) - int c; -{ - return x_fold_case('L'); -} - -/* Lowercase N(1) words */ -static int -x_fold_capitialize(c) - int c; -{ - return x_fold_case('C'); -} - -/* NAME: - * x_fold_case - convert word to UPPER/lower/Capitial case - * - * DESCRIPTION: - * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c - * to UPPER case, lower case or Capitalize words. - * - * RETURN VALUE: - * None - */ - -static int -x_fold_case(c) - int c; -{ - char *cp = xcp; - - if (cp == xep) { - x_e_putc(BEL); - return KSTD; - } - while (x_arg--) { - /* - * fisrt skip over any white-space - */ - while (cp != xep && is_mfs(*cp)) - cp++; - /* - * do the first char on its own since it may be - * a different action than for the rest. - */ - if (cp != xep) { - if (c == 'L') { /* lowercase */ - if (isupper(*cp)) - *cp = tolower(*cp); - } else { /* uppercase, capitialize */ - if (islower(*cp)) - *cp = toupper(*cp); - } - cp++; - } - /* - * now for the rest of the word - */ - while (cp != xep && !is_mfs(*cp)) { - if (c == 'U') { /* uppercase */ - if (islower(*cp)) - *cp = toupper(*cp); - } else { /* lowercase, capitialize */ - if (isupper(*cp)) - *cp = tolower(*cp); - } - cp++; - } - } - x_goto(cp); - return KSTD; -} - -/* NAME: - * x_lastcp - last visible char - * - * SYNOPSIS: - * x_lastcp() - * - * DESCRIPTION: - * This function returns a pointer to that char in the - * edit buffer that will be the last displayed on the - * screen. The sequence: - * - * for (cp = x_lastcp(); cp > xcp; cp) - * x_bs(*--cp); - * - * Will position the cursor correctly on the screen. - * - * RETURN VALUE: - * cp or NULL - */ - -static char * -x_lastcp() -{ - register char *rcp; - register int i; - - if (!xlp_valid) - { - for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++) - i += x_size(*rcp); - xlp = rcp; - } - xlp_valid = TRUE; - return (xlp); -} - -#endif /* EDIT */ diff --git a/bin/pdksh/eval.c b/bin/pdksh/eval.c deleted file mode 100644 index 292294d08ee..00000000000 --- a/bin/pdksh/eval.c +++ /dev/null @@ -1,1361 +0,0 @@ -/* $OpenBSD: eval.c,v 1.4 1997/06/19 13:58:40 kstailey Exp $ */ - -/* - * Expansion - quoting, separation, substitution, globbing - */ - -#include "sh.h" -#include <pwd.h> -#include "ksh_dir.h" -#include "ksh_stat.h" - -/* - * string expansion - * - * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution. - * second pass: alternation ({,}), filename expansion (*?[]). - */ - -/* expansion generator state */ -typedef struct Expand { - /* int type; */ /* see expand() */ - const char *str; /* string */ - union { - const char **strv;/* string[] */ - struct shf *shf;/* file */ - } u; /* source */ - struct tbl *var; /* variable in ${var..} */ - short split; /* split "$@" / call waitlast $() */ -} Expand; - -#define XBASE 0 /* scanning original */ -#define XSUB 1 /* expanding ${} string */ -#define XARGSEP 2 /* ifs0 between "$*" */ -#define XARG 3 /* expanding $*, $@ */ -#define XCOM 4 /* expanding $() */ -#define XNULLSUB 5 /* "$@" when $# is 0 (don't generate word) */ - -/* States used for field splitting */ -#define IFS_WORD 0 /* word has chars (or quotes) */ -#define IFS_WS 1 /* have seen IFS white-space */ -#define IFS_NWS 2 /* have seen IFS non-white-space */ - -static int varsub ARGS((Expand *xp, char *sp, char *word, int *stypep)); -static int comsub ARGS((Expand *xp, char *cp)); -static char *trimsub ARGS((char *str, char *pat, int how)); -static void glob ARGS((char *cp, XPtrV *wp, int markdirs)); -static void globit ARGS((XString *xs, char **xpp, char *sp, XPtrV *wp, - int check)); -static char *maybe_expand_tilde ARGS((char *p, XString *dsp, char **dpp, - int isassign)); -static char *tilde ARGS((char *acp)); -static char *homedir ARGS((char *name)); -#ifdef BRACE_EXPAND -static void alt_expand ARGS((XPtrV *wp, char *start, char *exp_start, - char *end, int fdo)); -#endif - -/* compile and expand word */ -char * -substitute(cp, f) - const char *cp; - int f; -{ - struct source *s, *sold; - - sold = source; - s = pushs(SWSTR, ATEMP); - s->start = s->str = cp; - source = s; - if (yylex(ONEWORD) != LWORD) - internal_errorf(1, "substitute"); - source = sold; - afree(s, ATEMP); - return evalstr(yylval.cp, f); -} - -/* - * expand arg-list - */ -char ** -eval(ap, f) - register char **ap; - int f; -{ - XPtrV w; - - if (*ap == NULL) - return ap; - XPinit(w, 32); - XPput(w, NULL); /* space for shell name */ -#ifdef SHARPBANG - XPput(w, NULL); /* and space for one arg */ -#endif - while (*ap != NULL) - expand(*ap++, &w, f); - XPput(w, NULL); -#ifdef SHARPBANG - return (char **) XPclose(w) + 2; -#else - return (char **) XPclose(w) + 1; -#endif -} - -/* - * expand string - */ -char * -evalstr(cp, f) - char *cp; - int f; -{ - XPtrV w; - - XPinit(w, 1); - expand(cp, &w, f); - cp = (XPsize(w) == 0) ? null : (char*) *XPptrv(w); - XPfree(w); - return cp; -} - -/* - * expand string - return only one component - * used from iosetup to expand redirection files - */ -char * -evalonestr(cp, f) - register char *cp; - int f; -{ - XPtrV w; - - XPinit(w, 1); - expand(cp, &w, f); - switch (XPsize(w)) { - case 0: - cp = null; - break; - case 1: - cp = (char*) *XPptrv(w); - break; - default: - cp = evalstr(cp, f&~DOGLOB); - break; - } - XPfree(w); - return cp; -} - -/* for nested substitution: ${var:=$var2} */ -typedef struct SubType { - short stype; /* [=+-?%#] action after expanded word */ - short base; /* begin position of expanded word */ - short f; /* saved value of f (DOPAT, etc) */ - struct tbl *var; /* variable for ${var..} */ - short quote; /* saved value of quote (for ${..[%#]..}) */ - struct SubType *prev; /* old type */ - struct SubType *next; /* poped type (to avoid re-allocating) */ -} SubType; - -void -expand(cp, wp, f) - char *cp; /* input word */ - register XPtrV *wp; /* output words */ - int f; /* DO* flags */ -{ - register int UNINITIALIZED(c); - register int type; /* expansion type */ - register int quote = 0; /* quoted */ - XString ds; /* destination string */ - register char *dp, *sp; /* dest., source */ - int fdo, word; /* second pass flags; have word */ - int doblank; /* field spliting of parameter/command subst */ - Expand x; /* expansion variables */ - SubType st_head, *st; - int UNINITIALIZED(newlines); /* For trailing newlines in COMSUB */ - int saw_eq, tilde_ok; - int make_magic; - - if (cp == NULL) - internal_errorf(1, "expand(NULL)"); - /* for alias, readonly, set, typeset commands */ - if ((f & DOVACHECK) && is_wdvarassign(cp)) { - f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE); - f |= DOASNTILDE; - } - if (Flag(FNOGLOB)) - f &= ~DOGLOB; - if (Flag(FMARKDIRS)) - f |= DOMARKDIRS; -#ifdef BRACE_EXPAND - if (Flag(FBRACEEXPAND) && (f & DOGLOB)) - f |= DOBRACE_; -#endif /* BRACE_EXPAND */ - - Xinit(ds, dp, 128, ATEMP); /* init dest. string */ - type = XBASE; - sp = cp; - fdo = 0; - saw_eq = 0; - tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; /* must be 1/0 */ - doblank = 0; - make_magic = 0; - word = (f&DOBLANK) ? IFS_WS : IFS_WORD; - st_head.next = (SubType *) 0; - st = &st_head; - - while (1) { - Xcheck(ds, dp); - - switch (type) { - case XBASE: /* original prefixed string */ - c = *sp++; - switch (c) { - case EOS: - c = 0; - break; - case CHAR: - c = *sp++; - break; - case QCHAR: - quote |= 2; /* temporary quote */ - c = *sp++; - break; - case OQUOTE: - word = IFS_WORD; - tilde_ok = 0; - quote = 1; - continue; - case CQUOTE: - quote = 0; - continue; - case COMSUB: - tilde_ok = 0; - if (f & DONTRUNCOMMAND) { - word = IFS_WORD; - *dp++ = '$'; *dp++ = '('; - while (*sp != '\0') { - Xcheck(ds, dp); - *dp++ = *sp++; - } - *dp++ = ')'; - } else { - type = comsub(&x, sp); - if (type == XCOM && (f&DOBLANK)) - doblank++; - sp = strchr(sp, 0) + 1; - newlines = 0; - } - continue; - case EXPRSUB: - word = IFS_WORD; - tilde_ok = 0; - if (f & DONTRUNCOMMAND) { - *dp++ = '$'; *dp++ = '('; *dp++ = '('; - while (*sp != '\0') { - Xcheck(ds, dp); - *dp++ = *sp++; - } - *dp++ = ')'; *dp++ = ')'; - } else { - struct tbl v; - char *p; - - v.flag = DEFINED|ISSET|INTEGER; - v.type = 10; /* not default */ - v.name[0] = '\0'; - v_evaluate(&v, substitute(sp, 0), - FALSE); - sp = strchr(sp, 0) + 1; - for (p = str_val(&v); *p; ) { - Xcheck(ds, dp); - *dp++ = *p++; - } - } - continue; - case OSUBST: /* ${{#}var{:}[=+-?#%]word} */ - /* format is: - * OSUBST plain-variable-part \0 - * compiled-word-part CSUBST - * This is were all syntax checking gets done... - */ - { - char *varname = sp; - int stype; - - sp = strchr(sp, '\0') + 1; /* skip variable */ - type = varsub(&x, varname, sp, &stype); - if (type < 0) { - char endc; - char *str, *end; - - end = (char *) wdscan(sp, CSUBST); - endc = *end; - *end = EOS; - str = snptreef((char *) 0, 64, "%S", - varname - 1); - *end = endc; - errorf("%s: bad substitution", str); - } - if (f&DOBLANK) - doblank++; - tilde_ok = 0; - if (type == XBASE) { /* expand? */ - if (!st->next) { - SubType *newst; - - newst = (SubType *) alloc( - sizeof(SubType), ATEMP); - newst->next = (SubType *) 0; - newst->prev = st; - st->next = newst; - } - st = st->next; - st->stype = stype; - st->base = Xsavepos(ds, dp); - st->f = f; - st->var = x.var; - st->quote = quote; - /* skip qualifier(s) */ - if (stype) { - sp += 2; - /* :[-+=?] or double [#%] */ - if (stype & 0x80) - sp += 2; - } - switch (stype & 0x7f) { - case '#': - case '%': - /* ! DOBLANK,DOBRACE_,DOTILDE */ - f = DOPAT | (f&DONTRUNCOMMAND) - | DOTEMP_; - quote = 0; - break; - case '=': - /* Enabling tilde expansion - * after :'s here is - * non-standard ksh, but is - * consistent with rules for - * other assignments. Not - * sure what POSIX thinks of - * this. - * Not doing tilde expansion - * for integer variables is a - * non-POSIX thing - makes - * sense though, since ~ is - * a arithmetic operator. - */ -#if !defined(__hppa) || __GNUC__ != 2 /* gcc 2.3.3 on hp-pa dies on this - ifdef goes away as soon as I get a new version of gcc.. */ - if (!(x.var->flag & INTEGER)) - f |= DOASNTILDE|DOTILDE; - f |= DOTEMP_; -#else - f |= DOTEMP_|DOASNTILDE|DOTILDE; -#endif - /* These will be done after the - * value has been assigned. - */ - f &= ~(DOBLANK|DOGLOB|DOBRACE_); - tilde_ok = 1; - break; - case '?': - f &= ~DOBLANK; - f |= DOTEMP_; - /* fall through */ - default: - /* Enable tilde expansion */ - tilde_ok = 1; - f |= DOTILDE; - } - } else - /* skip word */ - sp = (char *) wdscan(sp, CSUBST); - continue; - } - case CSUBST: /* only get here if expanding word */ - tilde_ok = 0; /* in case of ${unset:-} */ - *dp = '\0'; - quote = st->quote; - f = st->f; - if (f&DOBLANK) - doblank--; - switch (st->stype&0x7f) { - case '#': - case '%': - dp = Xrestpos(ds, dp, st->base); - /* Must use st->var since calling - * global would break things - * like x[i+=1]. - */ - x.str = trimsub(str_val(st->var), - dp, st->stype); - type = XSUB; - if (f&DOBLANK) - doblank++; - st = st->prev; - continue; - case '=': - if (st->var->flag & RDONLY) - /* XXX POSIX says this is only - * fatal for special builtins - */ - errorf("%s: is read only", - st->var->name); - /* Restore our position and substitute - * the value of st->var (may not be - * the assigned value in the presence - * of integer/right-adj/etc attributes). - */ - dp = Xrestpos(ds, dp, st->base); - /* Must use st->var since calling - * global would cause with things - * like x[i+=1] to be evaluated twice. - */ - setstr(st->var, debunk( - (char *) alloc(strlen(dp) + 1, - ATEMP), dp)); - x.str = str_val(st->var); - type = XSUB; - if (f&DOBLANK) - doblank++; - st = st->prev; - continue; - case '?': - { - char *s = Xrestpos(ds, dp, st->base); - - errorf("%s: %s", st->var->name, - dp == s ? - "parameter null or not set" - : (debunk(s, s), s)); - } - } - st = st->prev; - type = XBASE; - continue; - - case OPAT: /* open pattern: *(foo|bar) */ - /* Next char is the type of pattern */ - make_magic = 1; - c = *sp++ + 0x80; - break; - - case SPAT: /* pattern seperator (|) */ - make_magic = 1; - c = '|'; - break; - - case CPAT: /* close pattern */ - make_magic = 1; - c = /*(*/ ')'; - break; - } - break; - - case XNULLSUB: - /* Special case for "$@" (and "${foo[@]}") - no - * word is generated if $# is 0 (unless there is - * other stuff inside the quotes). - */ - type = XBASE; - if (f&DOBLANK) { - doblank--; - /* not really correct: x=; "$x$@" should - * generate a null argument and - * set A; "${@:+}" shouldn't. - */ - if (dp == Xstring(ds, dp)) - word = IFS_WS; - } - continue; - - case XSUB: - if ((c = *x.str++) == 0) { - type = XBASE; - if (f&DOBLANK) - doblank--; - continue; - } - break; - - case XARGSEP: - type = XARG; - quote = 1; - case XARG: - if ((c = *x.str++) == '\0') { - /* force null words to be created so - * set -- '' 2 ''; foo "$@" will do - * the right thing - */ - if (quote && x.split) - word = IFS_WORD; - if ((x.str = *x.u.strv++) == NULL) { - type = XBASE; - if (f&DOBLANK) - doblank--; - continue; - } - c = ifs0; - if (c == 0) { - if (quote && !x.split) - continue; - c = ' '; - } - if (quote && x.split) { - /* terminate word for "$@" */ - type = XARGSEP; - quote = 0; - } - } - break; - - case XCOM: - if (newlines) { /* Spit out saved nl's */ - c = '\n'; - --newlines; - } else { - while ((c = shf_getc(x.u.shf)) == 0 || c == '\n') - if (c == '\n') - newlines++; /* Save newlines */ - if (newlines && c != EOF) { - shf_ungetc(c, x.u.shf); - c = '\n'; - --newlines; - } - } - if (c == EOF) { - newlines = 0; - shf_close(x.u.shf); - if (x.split) - subst_exstat = waitlast(); - type = XBASE; - if (f&DOBLANK) - doblank--; - continue; - } - break; - } - - /* check for end of word or IFS separation */ - if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic - && ctype(c, C_IFS))) - { - /* How words are broken up: - * | value of c - * word | ws nws 0 - * ----------------------------------- - * IFS_WORD w/WS w/NWS w - * IFS_WS -/WS w/NWS - - * IFS_NWS -/NWS w/NWS w - * (w means generate a word) - * Note that IFS_NWS/0 generates a word (at&t ksh - * doesn't do this, but POSIX does). - */ - if (word == IFS_WORD - || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS))) - { - char *p; - - *dp++ = '\0'; - p = Xclose(ds, dp); -#ifdef BRACE_EXPAND - if (fdo & DOBRACE_) - /* also does globbing */ - alt_expand(wp, p, p, - p + Xlength(ds, (dp - 1)), - fdo | (f & DOMARKDIRS)); - else -#endif /* BRACE_EXPAND */ - if (fdo & DOGLOB) - glob(p, wp, f & DOMARKDIRS); - else if ((f & DOPAT) || !(fdo & DOMAGIC_)) - XPput(*wp, p); - else - XPput(*wp, debunk(p, p)); - fdo = 0; - saw_eq = 0; - tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; - if (c != 0) - Xinit(ds, dp, 128, ATEMP); - } - if (c == 0) - return; - if (word != IFS_NWS) - word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS; - } else { - /* age tilde_ok info - ~ code tests second bit */ - tilde_ok <<= 1; - /* mark any special second pass chars */ - if (!quote) - switch (c) { - case '[': - case NOT: - case '-': - case ']': - /* For character classes - doesn't hurt - * to have magic !,-,]'s outside of - * [...] expressions. - */ - if (f & (DOPAT | DOGLOB)) { - fdo |= DOMAGIC_; - if (c == '[') - fdo |= f & DOGLOB; - *dp++ = MAGIC; - } - break; - case '*': - case '?': - if (f & (DOPAT | DOGLOB)) { - fdo |= DOMAGIC_ | (f & DOGLOB); - *dp++ = MAGIC; - } - break; -#ifdef BRACE_EXPAND - case OBRACE: - case ',': - case CBRACE: - if ((f & DOBRACE_) && (c == OBRACE - || (fdo & DOBRACE_))) - { - fdo |= DOBRACE_|DOMAGIC_; - *dp++ = MAGIC; - } - break; -#endif /* BRACE_EXPAND */ - case '=': - /* Note first unquoted = for ~ */ - if (!(f & DOTEMP_) && !saw_eq) { - saw_eq = 1; - tilde_ok = 1; - } - break; - case PATHSEP: /* : */ - /* Note unquoted : for ~ */ - if (!(f & DOTEMP_) && (f & DOASNTILDE)) - tilde_ok = 1; - break; - case '~': - /* tilde_ok is reset whenever - * any of ' " $( $(( ${ } are seen. - * Note that tilde_ok must be preserved - * through the sequence ${A=a=}~ - */ - if (type == XBASE - && (f & (DOTILDE|DOASNTILDE)) - && (tilde_ok & 2)) - { - char *p, *dp_x; - - dp_x = dp; - p = maybe_expand_tilde(sp, - &ds, &dp_x, - f & DOASNTILDE); - if (p) { - if (dp != dp_x) - word = IFS_WORD; - dp = dp_x; - sp = p; - continue; - } - } - break; - } - else - quote &= ~2; /* undo temporary */ - - if (make_magic) { - make_magic = 0; - fdo |= DOMAGIC_ | (f & DOGLOB); - *dp++ = MAGIC; - } else if (ISMAGIC(c)) { - fdo |= DOMAGIC_; - *dp++ = MAGIC; - } - *dp++ = c; /* save output char */ - word = IFS_WORD; - } - } -} - -/* - * Prepare to generate the string returned by ${} substitution. - */ -static int -varsub(xp, sp, word, stypep) - Expand *xp; - char *sp; - char *word; - int *stypep; -{ - int c; - int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */ - int stype; /* substitution type */ - char *p; - struct tbl *vp; - - if (sp[0] == '\0') /* Bad variable name */ - return -1; - - xp->var = (struct tbl *) 0; - - /* ${#var}, string length or array size */ - if (sp[0] == '#' && (c = sp[1]) != '\0') { - int zero_ok = 0; - - /* Can't have any modifiers for ${#...} */ - if (*word != CSUBST) - return -1; - sp++; - /* Check for size of array */ - if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') { - c = 0; - vp = global(arrayname(sp)); - if (vp->flag & (ISSET|ARRAY)) - zero_ok = 1; - for (; vp; vp = vp->u.array) - if (vp->flag&ISSET) - c = vp->index+1; - } else if (c == '*' || c == '@') - c = e->loc->argc; - else { - p = str_val(global(sp)); - zero_ok = p != null; - c = strlen(p); - } - if (Flag(FNOUNSET) && c == 0 && !zero_ok) - errorf("%s: parameter not set", sp); - *stypep = 0; /* unqualified variable/string substitution */ - xp->str = str_save(ulton((unsigned long)c, 10), ATEMP); - return XSUB; - } - - /* Check for qualifiers in word part */ - stype = 0; - c = *word == CHAR ? word[1] : 0; - if (c == ':') { - stype = 0x80; - c = word[2] == CHAR ? word[3] : 0; - } - if (ctype(c, C_SUBOP1)) - stype |= c; - else if (stype) /* :, :# or :% is not ok */ - return -1; - else if (ctype(c, C_SUBOP2)) { - stype = c; - if (word[2] == CHAR && c == word[3]) - stype |= 0x80; - } - if (!stype && *word != CSUBST) - return -1; - *stypep = stype; - - c = sp[0]; - if (c == '*' || c == '@') { - switch (stype & 0x7f) { - case '=': /* can't assign to a vector */ - case '%': /* can't trim a vector */ - case '#': - return -1; - } - if (e->loc->argc == 0) { - xp->str = null; - state = c == '@' ? XNULLSUB : XSUB; - } else { - xp->u.strv = (const char **) e->loc->argv + 1; - xp->str = *xp->u.strv++; - xp->split = c == '@'; /* $@ */ - state = XARG; - } - } else { - if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') { - XPtrV wv; - - switch (stype & 0x7f) { - case '=': /* can't assign to a vector */ - case '%': /* can't trim a vector */ - case '#': - return -1; - } - XPinit(wv, 32); - vp = global(arrayname(sp)); - for (; vp; vp = vp->u.array) { - if (!(vp->flag&ISSET)) - continue; - XPput(wv, str_val(vp)); - } - if (XPsize(wv) == 0) { - xp->str = null; - state = p[1] == '@' ? XNULLSUB : XSUB; - XPfree(wv); - } else { - XPput(wv, 0); - xp->u.strv = (const char **) XPptrv(wv); - xp->str = *xp->u.strv++; - xp->split = p[1] == '@'; /* ${foo[@]} */ - state = XARG; - } - } else { - /* Can't assign things like $! or $1 */ - if ((stype & 0x7f) == '=' - && (ctype(*sp, C_VAR1) || digit(*sp))) - return -1; - xp->var = global(sp); - xp->str = str_val(xp->var); - state = XSUB; - } - } - - c = stype&0x7f; - /* test the compiler's code generator */ - if (ctype(c, C_SUBOP2) || - (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */ - c == '=' || c == '-' || c == '?' : c == '+')) - state = XBASE; /* expand word instead of variable value */ - if (Flag(FNOUNSET) && xp->str == null - && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+'))) - errorf("%s: parameter not set", sp); - return state; -} - -/* - * Run the command in $(...) and read its output. - */ -static int -comsub(xp, cp) - register Expand *xp; - char *cp; -{ - Source *s, *sold; - register struct op *t; - struct shf *shf; - - s = pushs(SSTRING, ATEMP); - s->start = s->str = cp; - sold = source; - t = compile(s); - source = sold; - - if (t == NULL) - return XBASE; - - if (t != NULL && t->type == TCOM && /* $(<file) */ - *t->args == NULL && *t->vars == NULL && t->ioact != NULL) { - register struct ioword *io = *t->ioact; - char *name; - - if ((io->flag&IOTYPE) != IOREAD) - errorf("funny $() command: %s", - snptreef((char *) 0, 32, "%R", io)); - shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0, - SHF_MAPHI|SHF_CLEXEC); - if (shf == NULL) - errorf("%s: cannot open $() input", name); - xp->split = 0; /* no waitlast() */ - } else { - int ofd1, pv[2]; - openpipe(pv); - shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0); - ofd1 = savefd(1, 0); /* fd 1 may be closed... */ - ksh_dup2(pv[1], 1, FALSE); - close(pv[1]); - execute(t, XFORK|XXCOM|XPIPEO); - restfd(1, ofd1); - startlast(); - xp->split = 1; /* waitlast() */ - } - - xp->u.shf = shf; - return XCOM; -} - -/* - * perform #pattern and %pattern substitution in ${} - */ - -static char * -trimsub(str, pat, how) - register char *str; - char *pat; - int how; -{ - register char *end = strchr(str, 0); - register char *p, c; - - switch (how&0xff) { /* UCHAR_MAX maybe? */ - case '#': /* shortest at begining */ - for (p = str; p <= end; p++) { - c = *p; *p = '\0'; - if (gmatch(str, pat, FALSE)) { - *p = c; - return p; - } - *p = c; - } - break; - case '#'|0x80: /* longest match at begining */ - for (p = end; p >= str; p--) { - c = *p; *p = '\0'; - if (gmatch(str, pat, FALSE)) { - *p = c; - return p; - } - *p = c; - } - break; - case '%': /* shortest match at end */ - for (p = end; p >= str; p--) { - if (gmatch(p, pat, FALSE)) - return str_nsave(str, p - str, ATEMP); - } - break; - case '%'|0x80: /* longest match at end */ - for (p = str; p <= end; p++) { - if (gmatch(p, pat, FALSE)) - return str_nsave(str, p - str, ATEMP); - } - break; - } - - return str; /* no match, return string */ -} - -/* - * glob - * Name derived from V6's /etc/glob, the program that expanded filenames. - */ - -/* XXX cp not const 'cause slashes are temporarily replaced with nulls... */ -static void -glob(cp, wp, markdirs) - char *cp; - register XPtrV *wp; - int markdirs; -{ - int oldsize = XPsize(*wp); - - if (glob_str(cp, wp, markdirs) == 0) - XPput(*wp, debunk(cp, cp)); - else - qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize), - xstrcmp); -} - -#define GF_NONE 0 -#define GF_EXCHECK BIT(0) /* do existance check on file */ -#define GF_GLOBBED BIT(1) /* some globbing has been done */ -#define GF_MARKDIR BIT(2) /* add trailing / to directories */ - -/* Apply file globbing to cp and store the matching files in wp. Returns - * the number of matches found. - */ -int -glob_str(cp, wp, markdirs) - char *cp; - XPtrV *wp; - int markdirs; -{ - int oldsize = XPsize(*wp); - XString xs; - char *xp; - - Xinit(xs, xp, 256, ATEMP); - globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE); - Xfree(xs, xp); - - return XPsize(*wp) - oldsize; -} - -static void -globit(xs, xpp, sp, wp, check) - XString *xs; /* dest string */ - char **xpp; /* ptr to dest end */ - char *sp; /* source path */ - register XPtrV *wp; /* output list */ - int check; /* GF_* flags */ -{ - register char *np; /* next source component */ - char *xp = *xpp; - char *se; - char odirsep; - - /* This to allow long expansions to be interrupted */ - intrcheck(); - - if (sp == NULL) { /* end of source path */ - /* We only need to check if the file exists if a pattern - * is followed by a non-pattern (eg, foo*x/bar; no check - * is needed for foo* since the match must exist) or if - * any patterns were expanded and the markdirs option is set. - * Symlinks make things a bit tricky... - */ - if ((check & GF_EXCHECK) - || ((check & GF_MARKDIR) && (check & GF_GLOBBED))) - { -#define stat_check() (stat_done ? stat_done : \ - (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \ - ? -1 : 1)) - struct stat lstatb, statb; - int stat_done = 0; /* -1: failed, 1 ok */ - - if (lstat(Xstring(*xs, xp), &lstatb) < 0) - return; - /* special case for systems which strip trailing - * slashes from regular files (eg, /etc/passwd/). - * SunOS 4.1.3 does this... - */ - if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) - && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode) -#ifdef S_ISLNK - && (!S_ISLNK(lstatb.st_mode) - || stat_check() < 0 - || !S_ISDIR(statb.st_mode)) -#endif /* S_ISLNK */ - ) - return; - /* Possibly tack on a trailing / if there isn't already - * one and if the file is a directory or a symlink to a - * directory - */ - if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) - && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1]) - && (S_ISDIR(lstatb.st_mode) -#ifdef S_ISLNK - || (S_ISLNK(lstatb.st_mode) - && stat_check() > 0 - && S_ISDIR(statb.st_mode)) -#endif /* S_ISLNK */ - )) - { - *xp++ = DIRSEP; - *xp = '\0'; - } - } -#ifdef OS2 /* Done this way to avoid bug in gcc 2.7.2... */ - /* Ugly kludge required for command - * completion - see how search_access() - * is implemented for OS/2... - */ -# define KLUDGE_VAL 4 -#else /* OS2 */ -# define KLUDGE_VAL 0 -#endif /* OS2 */ - XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp) - + KLUDGE_VAL, ATEMP)); - return; - } - - if (xp > Xstring(*xs, xp)) - *xp++ = DIRSEP; - while (ISDIRSEP(*sp)) { - Xcheck(*xs, xp); - *xp++ = *sp++; - } - np = ksh_strchr_dirsep(sp); - if (np != NULL) { - se = np; - odirsep = *np; /* don't assume DIRSEP, can be multiple kinds */ - *np++ = '\0'; - } else { - odirsep = '\0'; /* keep gcc quiet */ - se = sp + strlen(sp); - } - - - /* Check if sp needs globbing - done to avoid pattern checks for strings - * containing MAGIC characters, open ['s without the matching close ], - * etc. (otherwise opendir() will be called which may fail because the - * directory isn't readable - if no globbing is needed, only execute - * permission should be required (as per POSIX)). - */ - if (!has_globbing(sp, se)) { - XcheckN(*xs, xp, se - sp + 1); - debunk(xp, sp); - xp += strlen(xp); - *xpp = xp; - globit(xs, xpp, np, wp, check); - } else { - DIR *dirp; - struct dirent *d; - char *name; - int len; - int prefix_len; - - /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */ - *xp = '\0'; - prefix_len = Xlength(*xs, xp); - dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : "."); - if (dirp == NULL) - goto Nodir; - while ((d = readdir(dirp)) != NULL) { - name = d->d_name; - if (name[0] == '.' && - (name[1] == 0 || (name[1] == '.' && name[2] == 0))) - continue; /* always ignore . and .. */ - if ((*name == '.' && *sp != '.') - || !gmatch(name, sp, TRUE)) - continue; - - len = NLENGTH(d) + 1; - XcheckN(*xs, xp, len); - memcpy(xp, name, len); - *xpp = xp + len - 1; - globit(xs, xpp, np, wp, - (check & GF_MARKDIR) | GF_GLOBBED - | (np ? GF_EXCHECK : GF_NONE)); - xp = Xstring(*xs, xp) + prefix_len; - } - closedir(dirp); - Nodir:; - } - - if (np != NULL) - *--np = odirsep; -} - -#if 0 -/* Check if p contains something that needs globbing; if it does, 0 is - * returned; if not, p is copied into xs/xp after stripping any MAGICs - */ -static int copy_non_glob ARGS((XString *xs, char **xpp, char *p)); -static int -copy_non_glob(xs, xpp, p) - XString *xs; - char **xpp; - char *p; -{ - char *xp; - int len = strlen(p); - - XcheckN(*xs, *xpp, len); - xp = *xpp; - for (; *p; p++) { - if (ISMAGIC(*p)) { - int c = *++p; - - if (c == '*' || c == '?') - return 0; - if (*p == '[') { - char *q = p + 1; - - if (ISMAGIC(*q) && q[1] == NOT) - q += 2; - if (ISMAGIC(*q) && q[1] == ']') - q += 2; - for (; *q; q++) - if (ISMAGIC(*q) && *++q == ']') - return 0; - /* pass a literal [ through */ - } - /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */ - } - *xp++ = *p; - } - *xp = '\0'; - *xpp = xp; - return 1; -} -#endif /* 0 */ - -/* remove MAGIC from string */ -char * -debunk(dp, sp) - char *dp; - const char *sp; -{ - char *d, *s; - - if ((s = strchr(sp, MAGIC))) { - memcpy(dp, sp, s - sp); - for (d = dp + (s - sp); *s; s++) - if (!ISMAGIC(*s) || !(*++s & 0x80) - || !strchr("*+?@!", *s & 0x7f)) - *d++ = *s; - else { - /* extended pattern operators: *+?@! */ - *d++ = *s & 0x7f; - *d++ = '('; - } - *d = '\0'; - } else if (dp != sp) - strcpy(dp, sp); - return dp; -} - -/* Check if p is an unquoted name, possibly followed by a / or :. If so - * puts the expanded version in *dcp,dp and returns a pointer in p just - * past the name, otherwise returns 0. - */ -static char * -maybe_expand_tilde(p, dsp, dpp, isassign) - char *p; - XString *dsp; - char **dpp; - int isassign; -{ - XString ts; - char *dp = *dpp; - char *tp, *r; - - Xinit(ts, tp, 16, ATEMP); - /* : only for DOASNTILDE form */ - while (p[0] == CHAR && !ISDIRSEP(p[1]) - && (!isassign || p[1] != PATHSEP)) - { - Xcheck(ts, tp); - *tp++ = p[1]; - p += 2; - } - *tp = '\0'; - r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0; - Xfree(ts, tp); - if (r) { - while (*r) { - Xcheck(*dsp, dp); - if (ISMAGIC(*r)) - *dp++ = MAGIC; - *dp++ = *r++; - } - *dpp = dp; - r = p; - } - return r; -} - -/* - * tilde expansion - * - * based on a version by Arnold Robbins - */ - -static char * -tilde(cp) - char *cp; -{ - char *dp; - - if (cp[0] == '\0') - dp = str_val(global("HOME")); - else if (cp[0] == '+' && cp[1] == '\0') - dp = str_val(global("PWD")); - else if (cp[0] == '-' && cp[1] == '\0') - dp = str_val(global("OLDPWD")); - else - dp = homedir(cp); - /* If HOME, PWD or OLDPWD are not set, don't expand ~ */ - if (dp == null) - dp = (char *) 0; - return dp; -} - -/* - * map userid to user's home directory. - * note that 4.3's getpw adds more than 6K to the shell, - * and the YP version probably adds much more. - * we might consider our own version of getpwnam() to keep the size down. - */ - -static char * -homedir(name) - char *name; -{ - register struct tbl *ap; - - ap = tenter(&homedirs, name, hash(name)); - if (!(ap->flag & ISSET)) { -#ifdef OS2 - /* No usernames in OS2 - punt */ - return NULL; -#else /* OS2 */ - struct passwd *pw; - - pw = getpwnam(name); - if (pw == NULL) - return NULL; - ap->val.s = str_save(pw->pw_dir, APERM); - ap->flag |= DEFINED|ISSET|ALLOC; -#endif /* OS2 */ - } - return ap->val.s; -} - -#ifdef BRACE_EXPAND -static void -alt_expand(wp, start, exp_start, end, fdo) - XPtrV *wp; - char *start, *exp_start; - char *end; - int fdo; -{ - int UNINITIALIZED(count); - char *brace_start, *brace_end, *UNINITIALIZED(comma); - char *field_start; - char *p; - - /* search for open brace */ - for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2) - ; - brace_start = p; - - /* find matching close brace, if any */ - if (p) { - comma = (char *) 0; - count = 1; - for (p += 2; *p && count; p++) { - if (ISMAGIC(*p)) { - if (*++p == OBRACE) - count++; - else if (*p == CBRACE) - --count; - else if (*p == ',' && count == 1) - comma = p; - } - } - } - /* no valid expansions... */ - if (!p || count != 0) { - /* Note that given a{{b,c} we do not expand anything (this is - * what at&t ksh does. This may be changed to do the {b,c} - * expansion. } - */ - if (fdo & DOGLOB) - glob(start, wp, fdo & DOMARKDIRS); - else - XPput(*wp, debunk(start, start)); - return; - } - brace_end = p; - if (!comma) { - alt_expand(wp, start, brace_end, end, fdo); - return; - } - - /* expand expression */ - field_start = brace_start + 2; - count = 1; - for (p = brace_start + 2; p != brace_end; p++) { - if (ISMAGIC(*p)) { - if (*++p == OBRACE) - count++; - else if ((*p == CBRACE && --count == 0) - || (*p == ',' && count == 1)) - { - char *new; - int l1, l2, l3; - - l1 = brace_start - start; - l2 = (p - 1) - field_start; - l3 = end - brace_end; - new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP); - memcpy(new, start, l1); - memcpy(new + l1, field_start, l2); - memcpy(new + l1 + l2, brace_end, l3); - new[l1 + l2 + l3] = '\0'; - alt_expand(wp, new, new + l1, - new + l1 + l2 + l3, fdo); - field_start = p + 1; - } - } - } - return; -} -#endif /* BRACE_EXPAND */ diff --git a/bin/pdksh/exec.c b/bin/pdksh/exec.c deleted file mode 100644 index 7c98d956239..00000000000 --- a/bin/pdksh/exec.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* $OpenBSD: exec.c,v 1.10 1997/09/12 04:38:05 millert Exp $ */ - -/* - * execute command tree - */ - -#include "sh.h" -#include "c_test.h" -#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, struct tbl *tp)); -static int herein ARGS((char *hname, int sub)); -#ifdef KSH -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)); -static const char *dbteste_getopnd ARGS((Test_env *te, Test_op op, - int do_eval)); -static int dbteste_eval ARGS((Test_env *te, Test_op op, const char *opnd1, - const char *opnd2, int do_eval)); -static void dbteste_error ARGS((Test_env *te, int offset, const char *msg)); -#endif /* KSH */ -#ifdef OS2 -static int search_access1 ARGS((const char *path, int mode, int *errnop)); -#endif /* OS2 */ - - -/* - * handle systems that don't have F_SETFD - */ -#ifndef F_SETFD -# ifndef MAXFD -# define MAXFD 64 -# endif -/* a bit field would be smaller, but this will work */ -static char clexec_tab[MAXFD+1]; -#endif - -/* - * we now use this function always. - */ -int -fd_clexec(fd) - int fd; -{ -#ifndef F_SETFD - if (fd >= 0 && fd < sizeof(clexec_tab)) { - clexec_tab[fd] = 1; - return 0; - } - return -1; -#else - return fcntl(fd, F_SETFD, 1); -#endif -} - - -/* - * execute command tree - */ -int -execute(t, flags) - struct op * volatile t; - volatile int flags; /* if XEXEC don't fork */ -{ - int i; - volatile int rv = 0; - int pv[2]; - char ** volatile ap; - char *s, *cp; - struct ioword **iowp; - struct tbl *tp = NULL; - - 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 */ - - newenv(E_EXEC); - if (trap) - runtraps(0); - - if (t->type == TCOM) { - /* Clear subst_exstat before argument expansion. Used by - * null commands (see comexec()) and by c_set(). - */ - subst_exstat = 0; - - /* POSIX says expand command words first, then redirections, - * and assignments last.. - */ - ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE); - if (Flag(FXTRACE) && ap[0]) { - shf_fprintf(shl_out, "%s", - 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); - shf_flush(shl_out); - } - if (ap[0]) - tp = findcom(ap[0], FC_BI|FC_FUNC); - } - - if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) { - e->savefd = (short *) alloc(sizeofN(short, NUFILE), ATEMP); - /* initialize to not redirected */ - memset(e->savefd, 0, sizeofN(short, NUFILE)); - } - - /* do redirection, to be restored in quitenv() */ - if (t->ioact != NULL) - for (iowp = t->ioact; *iowp != NULL; iowp++) { - if (iosetup(*iowp, tp) < 0) { - exstat = rv = 1; - /* Redirection failures for special commands - * cause (non-interactive) shell to exit. - */ - if (tp && tp->type == CSHELL - && (tp->flag & SPEC_BI)) - errorf(null); - /* Deal with FERREXIT, quitenv(), etc. */ - goto Break; - } - } - - switch(t->type) { - case TCOM: - rv = comexec(t, tp, ap, flags); - break; - - case TPAREN: - rv = execute(t->left, flags|XFORK); - break; - - case TPIPE: - flags |= XFORK; - flags &= ~XEXEC; - e->savefd[0] = savefd(0, 0); - (void) ksh_dup2(e->savefd[0], 0, FALSE); /* stdin of first */ - e->savefd[1] = savefd(1, 0); - while (t->type == TPIPE) { - openpipe(pv); - (void) ksh_dup2(pv[1], 1, FALSE); /* stdout of curr */ - /* Let exchild() close pv[0] in child - * (if this isn't done, commands like - * (: ; cat /etc/termcap) | sleep 1 - * will hang forever). - */ - exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]); - (void) ksh_dup2(pv[0], 0, FALSE); /* stdin of next */ - closepipe(pv); - flags |= XPIPEI; - t = t->right; - } - restfd(1, e->savefd[1]); /* stdout of last */ - e->savefd[1] = 0; /* no need to re-restore this */ - /* Let exchild() close 0 in parent, after fork, before wait */ - i = exchild(t, flags|XPCLOSE, 0); - if (!(flags&XBGND) && !(flags&XXCOM)) - rv = i; - break; - - case TLIST: - while (t->type == TLIST) { - execute(t->left, flags & XERROK); - t = t->right; - } - rv = execute(t, flags & XERROK); - break; - -#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? */ - coproc_cleanup(TRUE); - - /* do this before opening pipes, in case these fail */ - e->savefd[0] = savefd(0, 0); - e->savefd[1] = savefd(1, 0); - - openpipe(pv); - 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); - else { - openpipe(pv); - 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; - } -# 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); - break; - } -#endif /* KSH */ - - case TASYNC: - /* XXX non-optimal, I think - "(foo &)", forks for (), - * forks again for async... parent should optimize - * this to "foo &"... - */ - rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK); - break; - - case TOR: - case TAND: - rv = execute(t->left, XERROK); - if (t->right != NULL && (rv == 0) == (t->type == TAND)) - rv = execute(t->right, flags & XERROK); - else - flags |= XERROK; - break; - - case TBANG: - rv = !execute(t->right, XERROK); - break; - -#ifdef KSH - case TDBRACKET: - { - Test_env te; - - te.flags = TEF_DBRACKET; - te.pos.wp = t->args; - te.isa = dbteste_isa; - te.getopnd = dbteste_getopnd; - te.eval = dbteste_eval; - te.error = dbteste_error; - - rv = test_parse(&te); - break; - } -#endif /* KSH */ - - case TFOR: -#ifdef KSH - case TSELECT: - { - volatile bool_t is_first = TRUE; -#endif /* KSH */ - ap = (t->vars != NULL) ? - eval(t->vars, DOBLANK|DOGLOB|DOTILDE) - : e->loc->argv + 1; - e->type = E_LOOP; - while (1) { - i = ksh_sigsetjmp(e->jbuf, 0); - if (!i) - break; - if ((e->flags&EF_BRKCONT_PASS) - || (i != LBREAK && i != LCONTIN)) - { - quitenv(); - unwind(i); - } else if (i == LBREAK) { - rv = 0; - goto Break; - } - } - rv = 0; /* in case of a continue */ - if (t->type == TFOR) { - struct tbl *vq; - - while (*ap != NULL) { - vq = global(t->str); - if (vq->flag & RDONLY) - errorf("%s is read only", t->str); - setstr(vq, *ap++); - rv = execute(t->left, flags & XERROK); - } - } -#ifdef KSH - else { /* TSELECT */ - struct tbl *vq; - - for (;;) { - if (!(cp = do_selectargs(ap, is_first))) { - rv = 1; - break; - } - is_first = FALSE; - vq = global(t->str); - if (vq->flag & RDONLY) - errorf("%s is read only", t->str); - setstr(vq, cp); - rv = execute(t->left, flags & XERROK); - } - } - } -#endif /* KSH */ - break; - - case TWHILE: - case TUNTIL: - e->type = E_LOOP; - while (1) { - i = ksh_sigsetjmp(e->jbuf, 0); - if (!i) - break; - if ((e->flags&EF_BRKCONT_PASS) - || (i != LBREAK && i != LCONTIN)) - { - quitenv(); - unwind(i); - } else if (i == LBREAK) { - rv = 0; - goto Break; - } - } - rv = 0; /* in case of a continue */ - while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE)) - rv = execute(t->right, flags & XERROK); - break; - - case TIF: - case TELIF: - if (t->right == NULL) - break; /* should be error */ - rv = execute(t->left, XERROK) == 0 ? - execute(t->right->left, flags & XERROK) : - execute(t->right->right, flags & XERROK); - break; - - case TCASE: - cp = evalstr(t->str, DOTILDE); - for (t = t->left; t != NULL && t->type == TPAT; t = t->right) - for (ap = t->vars; *ap; ap++) - if ((s = evalstr(*ap, DOTILDE|DOPAT)) - && gmatch(cp, s, FALSE)) - goto Found; - break; - Found: - rv = execute(t->left, flags & XERROK); - break; - - case TBRACE: - rv = execute(t->left, flags & XERROK); - break; - - case TFUNCT: - rv = define(t->str, t); - break; - - case TTIME: - rv = timex(t, flags); - break; - - case TEXEC: /* an eval'd TCOM */ - s = t->args[0]; - ap = makenv(); -#ifndef F_SETFD - for (i = 0; i < sizeof(clexec_tab); i++) - if (clexec_tab[i]) { - close(i); - clexec_tab[i] = 0; - } -#endif - restoresigs(); - cleanup_proc_env(); - ksh_execve(t->str, t->args, ap); - if (errno == ENOEXEC) - scriptexec(t, ap); - else - errorf("%s: %s", s, strerror(errno)); - } - Break: - exstat = rv; - - quitenv(); /* restores IO */ - if ((flags&XEXEC)) - exit(rv); /* exit child */ - if (rv != 0 && !(flags & XERROK)) { - if (Flag(FERREXIT)) - unwind(LERROR); - trapsig(SIGERR_); - } - return rv; -} - -/* - * execute simple command - */ - -static int -comexec(t, tp, ap, flags) - struct op *t; - struct tbl *volatile tp; - register char **ap; - int volatile flags; -{ - int i; - int rv = 0; - register char *cp; - register char **lastp; - static struct op texec; /* Must be static (XXX but why?) */ - int type_flags; - int keepasn_ok; - int fcflags = FC_BI|FC_FUNC|FC_PATH; - -#ifdef __GNUC__ - (void)&rv; -#endif - - /* snag the last argument for $_ XXX not the same as at&t ksh, - * which only seems to set $_ after a newline (but not in - * functions/dot scripts, but in interactive and scipt) - - * perhaps save last arg here and set it in shell()?. - */ - if (!Flag(FSH) && *(lastp = ap)) { - while (*++lastp) - ; - setstr(typeset("_", LOCAL, 0, 0, 0), *--lastp); - } - - /* Deal with the shell builtins builtin, exec and command since - * they can be followed by other commands. This must be done before - * we know if we should create a local block, which must be done - * before we can do a path search (in case the assignments change - * PATH). - * Odd cases: - * FOO=bar exec > /dev/null FOO is kept but not exported - * FOO=bar exec foobar FOO is exported - * FOO=bar command exec > /dev/null FOO is neither kept nor exported - * FOO=bar command FOO is neither kept nor exported - * PATH=... foobar use new PATH in foobar search - */ - keepasn_ok = 1; - while (tp && tp->type == CSHELL) { - fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */ - if (tp->val.f == c_builtin) { - if ((cp = *++ap) == NULL) { - tp = NULL; - break; - } - tp = findcom(cp, FC_BI); - if (tp == NULL) - errorf("builtin: %s: not a builtin", cp); - continue; - } else if (tp->val.f == c_exec) { - if (ap[1] == NULL) - break; - ap++; - flags |= XEXEC; - } else if (tp->val.f == c_command) { - int optc, saw_p = 0; - - /* Ugly dealing with options in two places (here and - * in c_command(), but such is life) - */ - ksh_getopt_reset(&builtin_opt, 0); - while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) - == 'p') - saw_p = 1; - if (optc != EOF) - break; /* command -vV or something */ - /* don't look for functions */ - fcflags = FC_BI|FC_PATH; - if (saw_p) { - if (Flag(FRESTRICTED)) { - warningf(TRUE, - "command -p: restricted"); - rv = 1; - goto Leave; - } - fcflags |= FC_DEFPATH; - } - ap += builtin_opt.optind; - /* POSIX says special builtins lose their status - * if accessed using command. - */ - keepasn_ok = 0; - if (!ap[0]) { - /* ensure command with no args exits with 0 */ - subst_exstat = 0; - break; - } - } else - break; - tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC)); - } - if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN)))) - type_flags = 0; - else { - /* create new variable/function block */ - newblock(); - /* 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; - for (i = 0; t->vars[i]; i++) { - cp = evalstr(t->vars[i], DOASNTILDE); - if (Flag(FXTRACE)) { - if (i == 0) - shf_fprintf(shl_out, "%s", - PS4_SUBSTITUTE(str_val(global("PS4")))); - shf_fprintf(shl_out, "%s%s", cp, - t->vars[i + 1] ? space : newline); - if (!t->vars[i + 1]) - shf_flush(shl_out); - } - typeset(cp, type_flags, 0, 0, 0); - } - - if ((cp = *ap) == NULL) { - rv = subst_exstat; - goto Leave; - } else if (!tp) { - if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) { - warningf(TRUE, "%s: restricted", cp); - rv = 1; - goto Leave; - } - tp = findcom(cp, fcflags); - } - - switch (tp->type) { - case CSHELL: /* shell built-in */ - rv = call_builtin(tp, ap); - break; - - case CFUNC: /* function call */ - { - volatile int old_xflag; - volatile Tflag old_inuse; - const char *volatile old_kshname; - - if (!(tp->flag & ISSET)) { - struct tbl *ftp; - - if (!tp->u.fpath) { - 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; - } - 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 = 127; - break; - } - if (!(ftp = findfunc(cp, hash(cp), FALSE)) - || !(ftp->flag & ISSET)) - { - warningf(TRUE, - "%s: function not defined by %s", - cp, tp->u.fpath); - rv = 127; - break; - } - tp = ftp; - } - - /* ksh functions set $0 to function name, POSIX functions leave - * $0 unchanged. - */ - old_kshname = kshname; - if (tp->flag & FKSH) - kshname = ap[0]; - e->loc->argv = ap; - for (i = 0; *ap++ != NULL; i++) - ; - e->loc->argc = i - 1; - getopts_reset(1); - - old_xflag = Flag(FXTRACE); - Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE; - - old_inuse = tp->flag & FINUSE; - tp->flag |= FINUSE; - - e->type = E_FUNC; - i = ksh_sigsetjmp(e->jbuf, 0); - if (i == 0) { - /* seems odd to pass XERROK here, but at&t ksh does */ - exstat = execute(tp->val.t, flags & XERROK); - i = LRETURN; - } - kshname = old_kshname; - Flag(FXTRACE) = old_xflag; - tp->flag = (tp->flag & ~FINUSE) | old_inuse; - /* Were we deleted while executing? If so, free the execution - * 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) { - tp->flag &= ~ALLOC; - tfree(tp->val.t, tp->areap); - } - tp->flag = 0; - } - switch (i) { - case LRETURN: - case LERROR: - rv = exstat; - break; - case LINTR: - case LEXIT: - case LLEAVE: - case LSHELL: - quitenv(); - unwind(i); - /*NOTREACHED*/ - default: - quitenv(); - internal_errorf(1, "CFUNC %d", i); - } - break; - } - - case CEXEC: /* executable command */ - case CTALIAS: /* tracked alias */ - if (!(tp->flag&ISSET)) { - /* 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 (tp->u2.errno_) { - warningf(TRUE, "%s: cannot execute - %s", cp, - strerror(tp->u2.errno_)); - rv = 126; /* POSIX */ - } else { - warningf(TRUE, "%s: not found", cp); - rv = 127; - } - break; - } - - if (!Flag(FSH)) { - /* set $_ to program's full path */ - setstr(typeset("_", LOCAL|EXPORT, 0, 0, 0), tp->val.s); - } - - if (flags&XEXEC) { - j_exit(); - if (!(flags&XBGND) || Flag(FMONITOR)) { - setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG); - setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG); - } - } - - /* to fork we set up a TEXEC node and call execute */ - texec.type = TEXEC; - texec.left = t; /* for tprint */ - texec.str = tp->val.s; - texec.args = ap; - rv = exchild(&texec, flags, -1); - break; - } - Leave: - if (flags & XEXEC) { - exstat = rv; - unwind(LLEAVE); - } - return rv; -} - -static void -scriptexec(tp, ap) - register struct op *tp; - register char **ap; -{ - char *shell; - - shell = str_val(global(EXECSHELL_STR)); - if (shell && *shell) - shell = search(shell, path, X_OK, (int *) 0); - if (!shell || !*shell) - shell = EXECSHELL; - - *tp->args-- = tp->str; -#ifdef SHARPBANG - { - char buf[LINE]; - register char *cp; - register int fd, n; - - buf[0] = '\0'; - if ((fd = open(tp->str, O_RDONLY)) >= 0) { - if ((n = read(fd, buf, LINE - 1)) > 0) - buf[n] = '\0'; - (void) close(fd); - } - if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2])) -# ifdef OS2 - || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7]) - && (cp = &buf[7])) -# endif /* OS2 */ - ) - { - while (*cp && (*cp == ' ' || *cp == '\t')) - cp++; - if (*cp && *cp != '\n') { - char *a0 = cp, *a1 = (char *) 0; -# ifdef OS2 - char *a2 = cp; -# endif /* OS2 */ - - while (*cp && *cp != '\n' && *cp != ' ' - && *cp != '\t') - { -# ifdef OS2 - /* Allow shell search without prepended path - * if shell with / in pathname cannot be found. - * Use / explicitly so \ can be used if explicit - * needs to be forced. - */ - if (*cp == '/') - a2 = cp + 1; -# endif /* OS2 */ - cp++; - } - if (*cp && *cp != '\n') { - *cp++ = '\0'; - while (*cp - && (*cp == ' ' || *cp == '\t')) - cp++; - if (*cp && *cp != '\n') { - a1 = cp; - /* all one argument */ - while (*cp && *cp != '\n') - cp++; - } - } - if (*cp == '\n') { - *cp = '\0'; - if (a1) - *tp->args-- = a1; -# ifdef OS2 - if (a0 != a2 && search_access(a0, X_OK, (int *) 0)) - a0 = a2; -# endif /* OS2 */ - shell = a0; - } - } -# ifdef OS2 - } else { - /* Use ksh documented shell default if present - * else use OS2_SHELL which is assumed to need - * the /c option and '\' as dir separater. - */ - char *p = shell; - - shell = str_val(global("EXECSHELL")); - if (shell && *shell) - shell = search(shell, path, X_OK, (int *) 0); - if (!shell || !*shell) { - shell = p; - *tp->args-- = "/c"; - for (p = tp->str; *p; p++) - if (*p == '/') - *p = '\\'; - } -# endif /* OS2 */ - } - } -#endif /* SHARPBANG */ - *tp->args = shell; - - ksh_execve(tp->args[0], tp->args, ap); - - /* report both the program that was run and the bogus shell */ - errorf("%s: %s: %s", tp->str, shell, strerror(errno)); -} - -int -shcomexec(wp) - register char **wp; -{ - register struct tbl *tp; - - tp = tsearch(&builtins, *wp, hash(*wp)); - if (tp == NULL) - internal_errorf(1, "shcomexec: %s", *wp); - return call_builtin(tp, wp); -} - -/* - * Search function tables for a function. If create set, a table entry - * is created if none is found. - */ -struct tbl * -findfunc(name, h, create) - const char *name; - unsigned int h; - int create; -{ - struct block *l; - struct tbl *tp = (struct tbl *) 0; - - for (l = e->loc; l; l = l->next) { - tp = tsearch(&l->funs, name, h); - if (tp) - break; - if (!l->next && create) { - tp = tenter(&l->funs, name, h); - tp->flag = DEFINED; - tp->type = CFUNC; - tp->val.t = (struct op *) 0; - break; - } - } - return tp; -} - -/* - * 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; -{ - struct tbl *tp; - int was_set = 0; - - while (1) { - tp = findfunc(name, hash(name), TRUE); - - 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) { - tp->flag &= ~(ISSET|ALLOC); - tfree(tp->val.t, tp->areap); - } - - if (t == NULL) { /* undefine */ - tdelete(tp); - return was_set ? 0 : 1; - } - - tp->val.t = tcopy(t->left, tp->areap); - tp->flag |= (ISSET|ALLOC); - if (t->u.ksh_func) - tp->flag |= FKSH; - - return 0; -} - -/* - * add builtin - */ -void -builtin(name, func) - const char *name; - int (*func) ARGS((char **)); -{ - register struct tbl *tp; - Tflag flag; - - /* see if any flags should be set for this builtin */ - for (flag = 0; ; name++) { - if (*name == '=') /* command does variable assignment */ - flag |= KEEPASN; - else if (*name == '*') /* POSIX special builtin */ - flag |= SPEC_BI; - else if (*name == '+') /* POSIX regular builtin */ - flag |= REG_BI; - else - break; - } - - tp = tenter(&builtins, name, hash(name)); - tp->flag = DEFINED | flag; - tp->type = CSHELL; - tp->val.f = func; -} - -/* - * find command - * either function, hashed command, or built-in (in that order) - */ -struct tbl * -findcom(name, flags) - const char *name; - int flags; /* FC_* */ -{ - static struct tbl temp; - unsigned int h = hash(name); - struct tbl *tp = NULL, *tbi; - int insert = Flag(FTRACKALL); /* insert if not found */ - char *fpath; /* for function autoloading */ - char *npath; - - if (ksh_strchr_dirsep(name) != NULL) { - insert = 0; - /* prevent FPATH search below */ - flags &= ~FC_FUNC; - goto Search; - } - tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL; - /* POSIX says special builtins first, then functions, then - * POSIX regular builtins, then search path... - */ - if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI)) - tp = tbi; - if (!tp && (flags & FC_FUNC)) { - tp = findfunc(name, h, FALSE); - if (tp && !(tp->flag & ISSET)) { - if ((fpath = str_val(global("FPATH"))) == null) { - tp->u.fpath = (char *) 0; - 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)) - tp = tbi; - /* todo: posix says non-special/non-regular builtins must - * be triggered by some user-controllable means like a - * special directory in PATH. Requires modifications to - * the search() function. Tracked aliases should be - * modified to allow tracking of builtin commands. - * This should be under control of the FPOSIX flag. - * If this is changed, also change c_whence... - */ - if (!tp && (flags & FC_UNREGBI) && tbi) - tp = tbi; - if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) { - tp = tsearch(&taliases, name, h); - if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) { - if (tp->flag & ALLOC) { - tp->flag &= ~ALLOC; - afree(tp->val.s, APERM); - } - tp->flag &= ~ISSET; - } - } - - Search: - if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) - && (flags & FC_PATH)) - { - if (!tp) { - if (insert && !(flags & FC_DEFPATH)) { - tp = tenter(&taliases, name, h); - tp->type = CTALIAS; - } else { - tp = &temp; - tp->type = CEXEC; - } - tp->flag = DEFINED; /* make ~ISSET */ - } - npath = search(name, flags & FC_DEFPATH ? def_path : path, - 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, - &tp->u2.errno_)) != (char *) 0) - { - /* An undocumented feature of at&t ksh is that it - * searches FPATH if a command is not found, even - * if the command hasn't been set up as an autoloaded - * function (ie, no typeset -uf). - */ - tp = &temp; - tp->type = CFUNC; - tp->flag = DEFINED; /* make ~ISSET */ - tp->u.fpath = npath; - } - } - return tp; -} - -/* - * flush executable commands with relative paths - */ -void -flushcom(all) - int all; /* just relative or all */ -{ - struct tbl *tp; - struct tstate ts; - - for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; ) - if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) { - if (tp->flag&ALLOC) { - tp->flag &= ~(ALLOC|ISSET); - afree(tp->val.s, APERM); - } - tp->flag = ~ISSET; - } -} - -/* Check if path is something we want to find. Returns -1 for failure. */ -int -search_access(path, mode, errnop) - const char *path; - int mode; - int *errnop; /* set if candidate found, but not suitable */ -{ -#ifndef OS2 - int ret, err = 0; - struct stat statb; - - 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 */ - /* - * NOTE: ASSUMES path can be modified and has enough room at the - * end of the string for a suffix (ie, 4 extra characters). - * Certain code knows this (eg, eval.c(globit()), - * exec.c(search())). - */ - static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd", - ".com", ".bat", (char *) 0 - }; - static char *rsuffixes[] = { ".ksh", ".", ".sh", ".cmd", ".bat", - (char *) 0 - }; - int i; - char *mpath = (char *) path; - char *tp = mpath + strlen(mpath); - char *p; - char **sfx; - - /* If a suffix has been specified, check if it is one of the - * suffixes that indicate the file is executable - if so, change - * the access test to R_OK... - * This code assumes OS/2 files can have only one suffix... - */ - if ((p = strrchr((p = ksh_strrchr_dirsep(mpath)) ? p : mpath, '.'))) { - if (mode == X_OK) - mode = R_OK; - 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... - */ - sfx = mode == R_OK ? rsuffixes : xsuffixes; - for (i = 0; sfx[i]; i++) { - strcpy(tp, p = sfx[i]); - if (search_access1(mpath, R_OK, errnop) == 0) - return 0; - *tp = '\0'; - } - return -1; -#endif /* !OS2 */ -} - -#ifdef OS2 -static int -search_access1(path, mode, errnop) - const char *path; - int mode; - int *errnop; /* set if candidate found, but not suitable */ -{ - int ret, err = 0; - struct stat statb; - - 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 */ - -/* - * search for command with PATH - */ -char * -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. - */ - namelen = strlen(name) + 1; - Xinit(xs, xp, namelen, ATEMP); - memcpy(Xstring(xs, xp), name, namelen); - - if (ksh_strchr_dirsep(name)) { - 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, errnop) == 0) - return Xstring(xs, xp); /* not Xclose() - xp may be wrong */ -#else /* OS2 */ - if (ksh_strchr_dirsep(name)) { - if (search_access(name, mode, errnop) == 0) - return (char *) name; - return NULL; - } - - namelen = strlen(name) + 1; - Xinit(xs, xp, 128, ATEMP); -#endif /* OS2 */ - - sp = path; - while (sp != NULL) { - xp = Xstring(xs, xp); - if (!(p = strchr(sp, PATHSEP))) - p = sp + strlen(sp); - if (p != sp) { - XcheckN(xs, xp, p - sp); - memcpy(xp, sp, p - sp); - xp += p - sp; - *xp++ = DIRSEP; - } - sp = p; - XcheckN(xs, xp, namelen); - memcpy(xp, name, namelen); - if (search_access(Xstring(xs, xp), mode, errnop) == 0) -#ifdef OS2 - return Xstring(xs, xp); /* Not Xclose() - see above */ -#else /* OS2 */ - return Xclose(xs, xp + namelen); -#endif /* OS2 */ - if (*sp++ == '\0') - sp = NULL; - } - Xfree(xs, xp); - return NULL; -} - -static int -call_builtin(tp, wp) - struct tbl *tp; - char **wp; -{ - int rv; - - builtin_argv0 = wp[0]; - builtin_flag = tp->flag; - shf_reopen(1, SHF_WR, shl_stdout); - shl_stdout_ok = 1; - ksh_getopt_reset(&builtin_opt, GF_ERROR); - rv = (*tp->val.f)(wp); - shf_flush(shl_stdout); - shl_stdout_ok = 0; - builtin_flag = 0; - builtin_argv0 = (char *) 0; - return rv; -} - -/* - * set up redirection, saving old fd's in e->savefd - */ -static int -iosetup(iop, tp) - register struct ioword *iop; - struct tbl *tp; -{ - register int u = -1; - char *cp = iop->name; - int iotype = iop->flag & IOTYPE; - int do_open = 1, do_close = 0, UNINITIALIZED(flags); - struct ioword iotmp; - struct stat statb; - - if (iotype != IOHERE) - cp = evalonestr(cp, DOTILDE|(Flag(FTALKING) ? DOGLOB : 0)); - - /* Used for tracing and error messages to print expanded cp */ - iotmp = *iop; - iotmp.name = (iotype == IOHERE) ? (char *) 0 : cp; - iotmp.flag |= IONAMEXP; - - if (Flag(FXTRACE)) - shellf("%s%s\n", - PS4_SUBSTITUTE(str_val(global("PS4"))), - snptreef((char *) 0, 32, "%R", &iotmp)); - - switch (iotype) { - case IOREAD: - flags = O_RDONLY; - break; - - case IOCAT: - flags = O_WRONLY | O_APPEND | O_CREAT; - break; - - case IOWRITE: - flags = O_WRONLY | O_CREAT | O_TRUNC; - if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) - && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode))) - flags |= O_EXCL; - break; - - case IORDWR: - flags = O_RDWR | O_CREAT; - break; - - case IOHERE: - do_open = 0; - /* herein() returns -2 if error has been printed */ - u = herein(cp, iop->flag & IOEVAL); - /* cp may have wrong name */ - break; - - case IODUP: - { - const char *emsg; - - do_open = 0; - if (*cp == '-' && !cp[1]) { - u = 1009; /* prevent error return below */ - do_close = 1; - } else if ((u = check_fd(cp, - X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK), - &emsg)) < 0) - { - warningf(TRUE, "%s: %s", - snptreef((char *) 0, 32, "%R", &iotmp), emsg); - return -1; - } - break; - } - } - if (do_open) { - if (Flag(FRESTRICTED) && (flags & O_CREAT)) { - warningf(TRUE, "%s: restricted", cp); - return -1; - } - u = open(cp, flags, 0666); -#ifdef OS2 - if (u < 0 && strcmp(cp, "/dev/null") == 0) - u = open("nul", flags, 0666); -#endif /* OS2 */ - } - if (u < 0) { - /* herein() may already have printed message */ - if (u == -1) - warningf(TRUE, "cannot %s %s: %s", - iotype == IODUP ? "dup" - : (iotype == IOREAD || iotype == IOHERE) ? - "open" : "create", cp, strerror(errno)); - return -1; - } - /* Do not save if it has already been redirected (i.e. "cat >x >y"). */ - if (e->savefd[iop->unit] == 0) - /* c_exec() assumes e->savefd[fd] set for any redirections. - * Ask savefd() not to close iop->unit - allows error messages - * to be seen if iop->unit is 2; also means we can't lose - * the fd (eg, both dup2 below and dup2 in restfd() failing). - */ - e->savefd[iop->unit] = savefd(iop->unit, 1); - - if (do_close) - close(iop->unit); - else if (u != iop->unit) { - if (ksh_dup2(u, iop->unit, TRUE) < 0) { - warningf(TRUE, - "could not finish (dup) redirection %s: %s", - snptreef((char *) 0, 32, "%R", &iotmp), - strerror(errno)); - if (iotype != IODUP) - close(u); - return -1; - } - if (iotype != IODUP) - close(u); -#ifdef KSH - /* 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); - } -#endif /* KSH */ - } - if (u == 2) /* Clear any write errors */ - shf_reopen(2, SHF_WR, shl_out); - return 0; -} - -/* - * open here document temp file. - * if unquoted here, expand here temp file into second temp file. - */ -static int -herein(hname, sub) - char *hname; - int sub; -{ - int fd; - - /* ksh -c 'cat << EOF' can cause this... */ - if (hname == (char *) 0) { - warningf(TRUE, "here document missing"); - return -2; /* special to iosetup(): don't print error */ - } - if (sub) { - char *cp; - struct source *s, *volatile osource = source; - struct temp *h; - struct shf *volatile shf; - int i; - - /* must be before newenv() 'cause shf uses ATEMP */ - shf = shf_open(hname, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); - if (shf == NULL) - return -1; - newenv(E_ERRH); - i = ksh_sigsetjmp(e->jbuf, 0); - if (i) { - if (shf) - shf_close(shf); - source = osource; - quitenv(); /* after shf_close() due to alloc */ - return -2; /* special to iosetup(): don't print error */ - } - /* set up yylex input from here file */ - s = pushs(SFILE, ATEMP); - s->u.shf = shf; - source = s; - if (yylex(ONEWORD) != LWORD) - internal_errorf(1, "herein: yylex"); - shf_close(shf); - shf = (struct shf *) 0; - cp = evalstr(yylval.cp, 0); - - /* write expanded input to another temp file */ - h = maketemp(ATEMP); - h->next = e->temps; e->temps = h; - if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) - /* shf closeed by error handler */ - errorf("%s: %s", h->name, strerror(errno)); - shf_puts(cp, shf); - if (shf_close(shf) == EOF) { - close(fd); - shf = (struct shf *) 0; - errorf("error writing %s: %s", h->name, - strerror(errno)); - } - shf = (struct shf *) 0; - - quitenv(); - } else { - fd = open(hname, O_RDONLY, 0); - if (fd < 0) - return -1; - } - - return fd; -} - -#if defined(KSH) || defined(EDIT) -/* - * ksh special - the select command processing section - * print the args in column form - assuming that we can - */ -static char * -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, argct; - - for (argct = 0; ap[argct]; argct++) - ; - while (1) { - /* 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")); - if (*s) { - i = atoi(s); - return (i >= 1 && i <= argct) ? ap[i - 1] : null; - } - print_menu = 1; - } -} - -struct select_menu_info { - char *const *args; - int arg_width; - int num_width; -} info; - -static char *select_fmt_entry ARGS((void *arg, int i, char *buf, int buflen)); - -/* format a single select menu item */ -static char * -select_fmt_entry(arg, i, buf, buflen) - void *arg; - int i; - char *buf; - int buflen; -{ - struct select_menu_info *smi = (struct select_menu_info *) arg; - - shf_snprintf(buf, buflen, "%*d) %s", - smi->num_width, i + 1, smi->args[i]); - return buf; -} - -/* - * print a select style menu - */ -int -pr_menu(ap) - char *const *ap; -{ - struct select_menu_info smi; - char *const *pp; - int nwidth, dwidth; - int i, n; - - /* Width/column calculations were done once and saved, but this - * means select can't be used recursively so we re-calculate each - * time (could save in a structure that is returned, but its probably - * not worth the bother). - */ - - /* - * get dimensions of the list - */ - for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) { - i = strlen(*pp); - nwidth = (i > nwidth) ? i : nwidth; - } - /* - * we will print an index of the form - * %d) - * in front of each entry - * get the max width of this - */ - for (i = n, dwidth = 1; i >= 10; i /= 10) - dwidth++; - - smi.args = ap; - smi.arg_width = nwidth; - smi.num_width = dwidth; - print_columns(shl_out, n, select_fmt_entry, (void *) &smi, - dwidth + nwidth + 2); - - return n; -} -#endif /* KSH || EDIT */ -#ifdef KSH - -/* - * [[ ... ]] evaluation routines - */ - -extern const char *const dbtest_tokens[]; -extern const char db_close[]; - -/* Test if the current token is a whatever. Accepts the current token if - * it is. Returns 0 if it is not, non-zero if it is (in the case of - * TM_UNOP and TM_BINOP, the returned value is a Test_op). - */ -static int -dbteste_isa(te, meta) - Test_env *te; - Test_meta meta; -{ - int ret = 0; - int uqword; - char *p; - - if (!*te->pos.wp) - return meta == TM_END; - - /* unquoted word? */ - for (p = *te->pos.wp; *p == CHAR; p += 2) - ; - uqword = *p == EOS; - - if (meta == TM_UNOP || meta == TM_BINOP) { - if (uqword) { - char buf[8]; /* longer than the longest operator */ - char *q = buf; - for (p = *te->pos.wp; *p == CHAR - && q < &buf[sizeof(buf) - 1]; - p += 2) - *q++ = p[1]; - *q = '\0'; - ret = (int) test_isop(te, meta, buf); - } - } else if (meta == TM_END) - ret = 0; - else - ret = uqword - && strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0; - - /* Accept the token? */ - if (ret) - te->pos.wp++; - - return ret; -} - -static const char * -dbteste_getopnd(te, op, do_eval) - Test_env *te; - Test_op op; - int do_eval; -{ - char *s = *te->pos.wp; - - if (!s) - return (char *) 0; - - te->pos.wp++; - - if (!do_eval) - return null; - - if (op == TO_STEQL || op == TO_STNEQ) - s = evalstr(s, DOTILDE | DOPAT); - else - s = evalstr(s, DOTILDE); - - return s; -} - -static int -dbteste_eval(te, op, opnd1, opnd2, do_eval) - Test_env *te; - Test_op op; - const char *opnd1; - const char *opnd2; - int do_eval; -{ - return test_eval(te, op, opnd1, opnd2, do_eval); -} - -static void -dbteste_error(te, offset, msg) - Test_env *te; - int offset; - const char *msg; -{ - te->flags |= TEF_ERROR; - internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset); -} -#endif /* KSH */ diff --git a/bin/pdksh/expand.h b/bin/pdksh/expand.h deleted file mode 100644 index d0ab5937c1d..00000000000 --- a/bin/pdksh/expand.h +++ /dev/null @@ -1,106 +0,0 @@ -/* $OpenBSD: expand.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */ - -/* - * Expanding strings - */ - - -#if 0 /* Usage */ - XString xs; - char *xp; - - Xinit(xs, xp, 128, ATEMP); /* allocate initial string */ - while ((c = generate()) { - Xcheck(xs, xp); /* expand string if neccessary */ - Xput(xs, xp, c); /* add character */ - } - return Xclose(xs, xp); /* resize string */ -/* - * NOTE: - * The Xcheck and Xinit macros have a magic + 8 in the lengths. This is - * so that you can put up to 4 characters in a XString before calling - * Xcheck. (See yylex in lex.c) - */ -#endif /* 0 */ - -typedef struct XString { - char *end, *beg; /* end, begin of string */ - size_t len; /* length */ - Area *areap; /* area to allocate/free from */ -} XString; - -typedef char * XStringP; - -/* initialize expandable string */ -#define Xinit(xs, xp, length, area) do { \ - (xs).len = length; \ - (xs).areap = (area); \ - (xs).beg = alloc((xs).len + 8, (xs).areap); \ - (xs).end = (xs).beg + (xs).len; \ - xp = (xs).beg; \ - } while (0) - -/* stuff char into string */ -#define Xput(xs, xp, c) (*xp++ = (c)) - -/* check if there are at least n bytes left */ -#define XcheckN(xs, xp, n) do { \ - int more = ((xp) + (n)) - (xs).end; \ - if (more > 0) \ - xp = Xcheck_grow_(&xs, xp, more); \ - } while (0) - -/* check for overflow, expand string */ -#define Xcheck(xs, xp) XcheckN(xs, xp, 1) - -/* free string */ -#define Xfree(xs, xp) afree((void*) (xs).beg, (xs).areap) - -/* close, return string */ -#define Xclose(xs, xp) (char*) aresize((void*)(xs).beg, \ - (size_t)((xp) - (xs).beg), (xs).areap) -/* begin of string */ -#define Xstring(xs, xp) ((xs).beg) - -#define Xnleft(xs, xp) ((xs).end - (xp)) /* may be less than 0 */ -#define Xlength(xs, xp) ((xp) - (xs).beg) -#define Xsize(xs, xp) ((xs).end - (xs).beg) -#define Xsavepos(xs, xp) ((xp) - (xs).beg) -#define Xrestpos(xs, xp, n) ((xs).beg + (n)) - -char * Xcheck_grow_ ARGS((XString *xsp, char *xp, int more)); - -/* - * expandable vector of generic pointers - */ - -typedef struct XPtrV { - void **cur; /* next avail pointer */ - void **beg, **end; /* begin, end of vector */ -} XPtrV; - -#define XPinit(x, n) do { \ - register void **vp__; \ - vp__ = (void**) alloc(sizeofN(void*, n), ATEMP); \ - (x).cur = (x).beg = vp__; \ - (x).end = vp__ + n; \ - } while (0) - -#define XPput(x, p) do { \ - if ((x).cur >= (x).end) { \ - int n = XPsize(x); \ - (x).beg = (void**) aresize((void*) (x).beg, \ - sizeofN(void*, n*2), ATEMP); \ - (x).cur = (x).beg + n; \ - (x).end = (x).cur + n; \ - } \ - *(x).cur++ = (p); \ - } while (0) - -#define XPptrv(x) ((x).beg) -#define XPsize(x) ((x).cur - (x).beg) - -#define XPclose(x) (void**) aresize((void*)(x).beg, \ - sizeofN(void*, XPsize(x)), ATEMP) - -#define XPfree(x) afree((void*) (x).beg, ATEMP) diff --git a/bin/pdksh/expr.c b/bin/pdksh/expr.c deleted file mode 100644 index 775d7ee44dd..00000000000 --- a/bin/pdksh/expr.c +++ /dev/null @@ -1,596 +0,0 @@ -/* $OpenBSD: expr.c,v 1.4 1997/06/19 13:58:41 kstailey Exp $ */ - -/* - * Korn expression evaluation - */ -/* - * todo: better error handling: if in builtin, should be builtin error, etc. - */ - -#include "sh.h" -#include <ctype.h> - - -/* 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, 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, - O_LSHIFT, O_RSHIFT, - O_LE, O_GE, O_LT, O_GT, - O_LAND, - O_LOR, - O_TIMES, O_DIV, O_MOD, - O_PLUS, O_MINUS, - O_BAND, - 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, - /* misc */ - OPEN_PAREN, CLOSE_PAREN, CTERN, - /* things that don't appear in the opinfo[] table */ - VAR, LIT, END, BAD - }; -#define IS_BINOP(op) (((int)op) >= O_EQ && ((int)op) <= O_COMMA) -#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN) - -enum prec { - P_PRIMARY = 0, /* VAR, LIT, (), ~ ! - + */ - P_MULT, /* * / % */ - P_ADD, /* + - */ - P_SHIFT, /* << >> */ - P_RELATION, /* < <= > >= */ - P_EQUALITY, /* == != */ - P_BAND, /* & */ - P_BXOR, /* ^ */ - P_BOR, /* | */ - P_LAND, /* && */ - P_LOR, /* || */ - P_TERN, /* ?: */ - P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */ - P_COMMA /* , */ - }; -#define MAX_PREC P_COMMA - -struct opinfo { - char name[4]; - int len; /* name length */ - enum prec prec; /* precidence: lower is higher */ -}; - -/* Tokens in this table must be ordered so the longest are first - * (eg, += before +). If you change something, change the order - * 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 */ - { "*=", 2, P_ASSIGN }, - { "/=", 2, P_ASSIGN }, - { "%=", 2, P_ASSIGN }, - { "+=", 2, P_ASSIGN }, - { "-=", 2, P_ASSIGN }, - { "<<=", 3, P_ASSIGN }, - { ">>=", 3, P_ASSIGN }, - { "&=", 2, P_ASSIGN }, - { "^=", 2, P_ASSIGN }, - { "|=", 2, P_ASSIGN }, - { "<<", 2, P_SHIFT }, - { ">>", 2, P_SHIFT }, - { "<=", 2, P_RELATION }, - { ">=", 2, P_RELATION }, - { "<", 1, P_RELATION }, - { ">", 1, P_RELATION }, - { "&&", 2, P_LAND }, - { "||", 2, P_LOR }, - { "*", 1, P_MULT }, - { "/", 1, P_MULT }, - { "%", 1, P_MULT }, - { "+", 1, P_ADD }, - { "-", 1, P_ADD }, - { "&", 1, P_BAND }, - { "^", 1, P_BXOR }, - { "|", 1, P_BOR }, - { "?", 1, P_TERN }, - { ",", 1, P_COMMA }, - { "~", 1, P_PRIMARY }, - { "!", 1, P_PRIMARY }, - { "(", 1, P_PRIMARY }, - { ")", 1, P_PRIMARY }, - { ":", 1, P_PRIMARY }, - { "", 0, P_PRIMARY } /* end of table */ - }; - - -typedef struct expr_state Expr_state; -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 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_RECURSIVE, - ET_LVALUE, ET_RDONLY, ET_STR }; - -static Expr_state *es; - -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)); - -/* - * parse and evalute expression - */ -int -evaluate(expr, rval, error_ok) - const char *expr; - long *rval; - int error_ok; -{ - struct tbl v; - int ret; - - v.flag = DEFINED|INTEGER; - v.type = 0; - ret = v_evaluate(&v, expr, error_ok); - *rval = v.val.i; - return ret; -} - -/* - * parse and evalute expression, storing result in vp. - */ -int -v_evaluate(vp, expr, error_ok) - struct tbl *vp; - const char *expr; - volatile int error_ok; -{ - struct tbl *v; - Expr_state curstate; - int i; - - /* save state to allow recursive calls */ - 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) { - if (error_ok) - return 0; - errorf(null); - } - unwind(i); - /*NOTREACHED*/ - } - - token(); -#if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */ - if (es->tok == END) { - es->tok = LIT; - es->val = tempvar(); - } -#endif /* 0 */ - v = intvar(evalexpr(MAX_PREC)); - - if (es->tok != END) - evalerr(ET_UNEXPECTED, (char *) 0); - - if (vp->flag & INTEGER) - setint_v(vp, v); - else - setstr(vp, str_val(v)); - - es = curstate.prev; - quitenv(); - - return 1; -} - -static void -evalerr(type, str) - enum error_type type; - const char *str; -{ - char tbuf[2]; - const char *s; - - switch (type) { - case ET_UNEXPECTED: - switch (es->tok) { - case VAR: - s = es->val->name; - break; - case LIT: - s = str_val(es->val); - break; - case END: - s = "end of expression"; - break; - case BAD: - tbuf[0] = *es->tokp; - tbuf[1] = '\0'; - s = tbuf; - break; - default: - s = opinfo[(int)es->tok].name; - } - warningf(TRUE, "%s: unexpected `%s'", es->expression, s); - break; - - case ET_BADLIT: - warningf(TRUE, "%s: bad number `%s'", es->expression, str); - break; - - 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; - - default: /* keep gcc happy */ - case ET_STR: - warningf(TRUE, "%s: %s", es->expression, str); - break; - } - unwind(LAEXPR); -} - -static struct tbl * -evalexpr(prec) - enum prec prec; -{ - register struct tbl *vl, UNINITIALIZED(*vr), *vasn; - register enum token op; - long UNINITIALIZED(res); - - if (prec == P_PRIMARY) { - op = es->tok; - if (op == O_BNOT || op == O_LNOT || op == O_MINUS - || op == O_PLUS) - { - token(); - vl = intvar(evalexpr(P_PRIMARY)); - if (op == O_BNOT) - vl->val.i = ~vl->val.i; - else if (op == O_LNOT) - vl->val.i = !vl->val.i; - else if (op == O_MINUS) - vl->val.i = -vl->val.i; - /* op == O_PLUS is a no-op */ - } else if (op == OPEN_PAREN) { - token(); - vl = evalexpr(MAX_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(); - } else { - 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); - 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)) { - 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)); - if ((op == O_DIV || op == O_MOD || op == O_DIVASN - || op == O_MODASN) && vr->val.i == 0) - { - if (es->noassign) - vr->val.i = 1; - else - evalerr(ET_STR, "zero divisor"); - } - switch ((int) op) { - case O_TIMES: - case O_TIMESASN: - res = vl->val.i * vr->val.i; - break; - case O_DIV: - case O_DIVASN: - res = vl->val.i / vr->val.i; - break; - case O_MOD: - case O_MODASN: - res = vl->val.i % vr->val.i; - break; - case O_PLUS: - case O_PLUSASN: - res = vl->val.i + vr->val.i; - break; - case O_MINUS: - case O_MINUSASN: - res = vl->val.i - vr->val.i; - break; - case O_LSHIFT: - case O_LSHIFTASN: - res = vl->val.i << vr->val.i; - break; - case O_RSHIFT: - case O_RSHIFTASN: - res = vl->val.i >> vr->val.i; - break; - case O_LT: - res = vl->val.i < vr->val.i; - break; - case O_LE: - res = vl->val.i <= vr->val.i; - break; - case O_GT: - res = vl->val.i > vr->val.i; - break; - case O_GE: - res = vl->val.i >= vr->val.i; - break; - case O_EQ: - res = vl->val.i == vr->val.i; - break; - case O_NE: - res = vl->val.i != vr->val.i; - break; - case O_BAND: - case O_BANDASN: - res = vl->val.i & vr->val.i; - break; - case O_BXOR: - case O_BXORASN: - res = vl->val.i ^ vr->val.i; - break; - case O_BOR: - case O_BORASN: - res = vl->val.i | vr->val.i; - break; - case O_LAND: - if (!vl->val.i) - es->noassign++; - vr = intvar(evalexpr(((int) prec) - 1)); - res = vl->val.i && vr->val.i; - if (!vl->val.i) - es->noassign--; - break; - case O_LOR: - if (vl->val.i) - es->noassign++; - vr = intvar(evalexpr(((int) prec) - 1)); - res = vl->val.i || vr->val.i; - if (vl->val.i) - es->noassign--; - break; - case O_TERN: - { - int e = vl->val.i != 0; - if (!e) - es->noassign++; - vl = evalexpr(MAX_PREC); - if (!e) - es->noassign--; - if (es->tok != CTERN) - evalerr(ET_STR, "missing :"); - token(); - if (e) - es->noassign++; - vr = evalexpr(P_TERN); - if (e) - es->noassign--; - vl = e ? vl : vr; - } - break; - case O_ASN: - res = vr->val.i; - break; - case O_COMMA: - res = vr->val.i; - break; - } - if (IS_ASSIGNOP(op)) { - vr->val.i = res; - if (vasn->flag & INTEGER) - setint_v(vasn, vr); - else - setint(vasn, res); - vl = vr; - } else if (op != O_TERN) - vl->val.i = res; - } - return vl; -} - -static void -token() -{ - register const char *cp; - register int c; - char *tvar; - - /* skip white space */ - for (cp = es->tokp; (c = *cp), isspace(c); cp++) - ; - es->tokp = cp; - - if (c == '\0') - es->tok = END; - else if (letter(c)) { - for (; letnum(c); c = *cp) - cp++; - if (c == '[') { - int len; - - len = array_ref_len(cp); - if (len == 0) - evalerr(ET_STR, "missing ]"); - cp += len; - } - if (es->noassign) { - es->val = tempvar(); - es->val->flag |= EXPRLVALUE; - } else { - tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP); - es->val = global(tvar); - afree(tvar, ATEMP); - } - es->tok = VAR; - } else if (digit(c)) { - for (; c != '_' && (letnum(c) || c == '#'); c = *cp++) - ; - tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP); - es->val = tempvar(); - es->val->flag &= ~INTEGER; - es->val->type = 0; - es->val->val.s = tvar; - if (setint_v(es->val, es->val) == NULL) - evalerr(ET_BADLIT, tvar); - afree(tvar, ATEMP); - es->tok = LIT; - } else { - int i, n0; - - for (i = 0; (n0 = opinfo[i].name[0]); i++) - if (c == n0 - && strncmp(cp, opinfo[i].name, opinfo[i].len) == 0) - { - es->tok = (enum token) i; - cp += opinfo[i].len; - break; - } - if (!n0) - es->tok = BAD; - } - 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() -{ - register struct tbl *vp; - - vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP); - vp->flag = ISSET|INTEGER; - vp->type = 0; - vp->areap = ATEMP; - vp->val.i = 0; - vp->name[0] = '\0'; - return vp; -} - -/* cast (string) variable to temporary integer variable */ -static struct tbl * -intvar(vp) - register struct tbl *vp; -{ - register struct tbl *vq; - - /* try to avoid replacing a temp var with another temp var */ - if (vp->name[0] == '\0' - && (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER)) - return vp; - - vq = tempvar(); - if (setint_v(vq, vp) == NULL) { - 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/pdksh/history.c b/bin/pdksh/history.c deleted file mode 100644 index f9c4b28e2e7..00000000000 --- a/bin/pdksh/history.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* $OpenBSD: history.c,v 1.7 1997/06/19 13:58:42 kstailey Exp $ */ - -/* - * command history - * - * only implements in-memory history. - */ - -/* - * This file contains - * a) the original in-memory history mechanism - * b) a simple file saving history mechanism done by sjg@zen - * define EASY_HISTORY to get this - * c) a more complicated mechanism done by pc@hillside.co.uk - * that more closely follows the real ksh way of doing - * things. You need to have the mmap system call for this - * to work on your system - */ - -#include "sh.h" -#include "ksh_stat.h" - -#ifdef HISTORY -# ifdef EASY_HISTORY - -# ifndef HISTFILE -# ifdef OS2 -# define HISTFILE "history.ksh" -# else /* OS2 */ -# define HISTFILE ".pdksh_hist" -# endif /* OS2 */ -# endif - -# else -/* Defines and includes for the complicated case */ - -# include <sys/file.h> -# include <sys/mman.h> - -/* - * variables for handling the data file - */ -static int histfd; -static int hsize; - -static int hist_count_lines ARGS((unsigned char *, int)); -static int hist_shrink ARGS((unsigned char *, int)); -static unsigned char *hist_skip_back ARGS((unsigned char *,int *,int)); -static void histload ARGS((Source *, unsigned char *, int)); -static void histinsert ARGS((Source *, int, unsigned char *)); -static void writehistfile ARGS((int, char *)); -static int sprinkle ARGS((int)); - -# ifdef MAP_FILE -# define MAP_FLAGS (MAP_FILE|MAP_PRIVATE) -# else -# define MAP_FLAGS MAP_PRIVATE -# endif - -# endif /* of EASY_HISTORY */ - -static int hist_execute ARGS((char *cmd)); -static int hist_replace ARGS((char **hp, const char *pat, const char *rep, - int global)); -static char **hist_get ARGS((const char *str, int approx, int allow_cur)); -static char **hist_get_newest ARGS((int allow_cur)); -static char **hist_get_oldest ARGS(()); -static void histbackup ARGS((void)); - -static char **current; /* current postition in history[] */ -static int curpos; /* current index in history[] */ -static char *hname; /* current name of history file */ -static int hstarted; /* set after hist_init() called */ -static Source *hist_source; - - -int -c_fc(wp) - char **wp; -{ - struct shf *shf; - struct temp UNINITIALIZED(*tf); - char *p, *editor = (char *) 0; - int gflag = 0, lflag = 0, nflag = 0, sflag = 0, rflag = 0; - int optc; - char *first = (char *) 0, *last = (char *) 0; - char **hfirst, **hlast, **hp; - - while ((optc = ksh_getopt(wp, &builtin_opt, "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != EOF) - switch (optc) { - case 'e': - p = builtin_opt.optarg; - if (strcmp(p, "-") == 0) - sflag++; - else { - editor = str_nsave(p, strlen(p) + 4, ATEMP); - strcat(editor, " $_"); - } - break; - case 'g': /* non-at&t ksh */ - gflag++; - break; - case 'l': - lflag++; - break; - case 'n': - nflag++; - break; - case 'r': - rflag++; - break; - case 's': /* posix version of -e - */ - sflag++; - break; - /* kludge city - accept -num as -- -num (kind of) */ - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - p = shf_smprintf("-%c%s", - optc, builtin_opt.optarg); - if (!first) - first = p; - else if (!last) - last = p; - else { - bi_errorf("too many arguments"); - return 1; - } - break; - case '?': - return 1; - } - wp += builtin_opt.optind; - - /* Substitute and execute command */ - if (sflag) { - char *pat = (char *) 0, *rep = (char *) 0; - - if (editor || lflag || nflag || rflag) { - bi_errorf("can't use -e, -l, -n, -r with -s (-e -)"); - return 1; - } - - /* Check for pattern replacement argument */ - if (*wp && **wp && (p = strchr(*wp + 1, '='))) { - pat = str_save(*wp, ATEMP); - p = pat + (p - *wp); - *p++ = '\0'; - rep = p; - wp++; - } - /* Check for search prefix */ - if (!first && (first = *wp)) - wp++; - if (last || *wp) { - bi_errorf("too many arguments"); - return 1; - } - - hp = first ? hist_get(first, FALSE, FALSE) - : hist_get_newest(FALSE); - if (!hp) - return 1; - return hist_replace(hp, pat, rep, gflag); - } - - if (editor && (lflag || nflag)) { - bi_errorf("can't use -l, -n with -e"); - return 1; - } - - if (!first && (first = *wp)) - wp++; - if (!last && (last = *wp)) - wp++; - if (*wp) { - bi_errorf("too many arguments"); - return 1; - } - if (!first) { - hfirst = lflag ? hist_get("-16", TRUE, TRUE) - : hist_get_newest(FALSE); - if (!hfirst) - return 1; - /* can't fail if hfirst didn't fail */ - hlast = hist_get_newest(FALSE); - } else { - /* POSIX says not an error if first/last out of bounds - * when range is specified; at&t ksh and pdksh allow out of - * bounds for -l as well. - */ - hfirst = hist_get(first, (lflag || last) ? TRUE : FALSE, - lflag ? TRUE : FALSE); - if (!hfirst) - return 1; - hlast = last ? hist_get(last, TRUE, lflag ? TRUE : FALSE) - : (lflag ? hist_get_newest(FALSE) : hfirst); - if (!hlast) - return 1; - } - if (hfirst > hlast) { - char **temp; - - temp = hfirst; hfirst = hlast; hlast = temp; - rflag = !rflag; /* POSIX */ - } - - /* List history */ - if (lflag) { - char *s, *t; - const char *nfmt = nflag ? "\t" : "%d\t"; - - for (hp = rflag ? hlast : hfirst; - hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) - { - shf_fprintf(shl_stdout, nfmt, - hist_source->line - (int) (histptr - hp)); - /* print multi-line commands correctly */ - for (s = *hp; (t = strchr(s, '\n')); s = t) - shf_fprintf(shl_stdout, "%.*s\t", ++t - s, s); - shf_fprintf(shl_stdout, "%s\n", s); - } - shf_flush(shl_stdout); - return 0; - } - - /* Run editor on selected lines, then run resulting commands */ - - tf = maketemp(ATEMP); - tf->next = e->temps; e->temps = tf; - if (!(shf = tf->shf)) { - bi_errorf("cannot create temp file %s - %s", - tf->name, strerror(errno)); - return 1; - } - for (hp = rflag ? hlast : hfirst; - hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) - shf_fprintf(shf, "%s\n", *hp); - if (shf_close(shf) == EOF) { - bi_errorf("error writing temporary file - %s", strerror(errno)); - return 1; - } - - if (!Flag(FSH)) - setstr(local("_", FALSE), tf->name); - - /* XXX: source should not get trashed by this.. */ - { - Source *sold = source; - int ret; - - ret = command(editor ? editor : "${FCEDIT:-/bin/ed} $_"); - source = sold; - if (ret) - return ret; - } - - { - struct stat statb; - XString xs; - char *xp; - int n; - - if (!(shf = shf_open(tf->name, O_RDONLY, 0, 0))) { - bi_errorf("cannot open temp file %s", tf->name); - return 1; - } - - n = fstat(shf_fileno(shf), &statb) < 0 ? 128 - : statb.st_size + 1; - Xinit(xs, xp, n, hist_source->areap); - while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) { - xp += n; - if (Xnleft(xs, xp) <= 0) - XcheckN(xs, xp, Xlength(xs, xp)); - } - if (n < 0) { - bi_errorf("error reading temp file %s - %s", - tf->name, strerror(shf_errno(shf))); - shf_close(shf); - return 1; - } - shf_close(shf); - *xp = '\0'; - strip_nuls(Xstring(xs, xp), Xlength(xs, xp)); - return hist_execute(Xstring(xs, xp)); - } -} - -/* Save cmd in history, execute cmd (cmd gets trashed) */ -static int -hist_execute(cmd) - char *cmd; -{ - Source *sold; - int ret; - char *p, *q; - - histbackup(); - - for (p = cmd; p; p = q) { - if ((q = strchr(p, '\n'))) { - *q++ = '\0'; /* kill the newline */ - if (!*q) /* ignore trailing newline */ - q = (char *) 0; - } -#ifdef EASY_HISTORY - if (p != cmd) - histappend(p, TRUE); - else -#endif /* EASY_HISTORY */ - histsave(++(hist_source->line), p, 1); - - shellf("%s\n", p); /* POSIX doesn't say this is done... */ - if ((p = q)) /* restore \n (trailing \n not restored) */ - q[-1] = '\n'; - } - - /* Commands are executed here instead of pushing them onto the - * input 'cause posix says the redirection and variable assignments - * in - * X=y fc -e - 42 2> /dev/null - * are to effect the repeated commands environment. - */ - /* XXX: source should not get trashed by this.. */ - sold = source; - ret = command(cmd); - source = sold; - return ret; -} - -static int -hist_replace(hp, pat, rep, global) - char **hp; - const char *pat; - const char *rep; - int global; -{ - char *line; - - if (!pat) - line = str_save(*hp, ATEMP); - else { - char *s, *s1; - int pat_len = strlen(pat); - int rep_len = strlen(rep); - int len; - XString xs; - char *xp; - int any_subst = 0; - - Xinit(xs, xp, 128, ATEMP); - for (s = *hp; (s1 = strstr(s, pat)) - && (!any_subst || global) ; s = s1 + pat_len) - { - any_subst = 1; - len = s1 - s; - XcheckN(xs, xp, len + rep_len); - memcpy(xp, s, len); /* first part */ - xp += len; - memcpy(xp, rep, rep_len); /* replacement */ - xp += rep_len; - } - if (!any_subst) { - bi_errorf("substitution failed"); - return 1; - } - len = strlen(s) + 1; - XcheckN(xs, xp, len); - memcpy(xp, s, len); - xp += len; - line = Xclose(xs, xp); - } - return hist_execute(line); -} - -/* - * get pointer to history given pattern - * pattern is a number or string - */ -static char ** -hist_get(str, approx, allow_cur) - const char *str; - int approx; - int allow_cur; -{ - char **hp = (char **) 0; - int n; - - if (getn(str, &n)) { - hp = histptr + (n < 0 ? n : (n - hist_source->line)); - if (hp < history) { - if (approx) - hp = hist_get_oldest(); - else { - bi_errorf("%s: not in history", str); - hp = (char **) 0; - } - } else if (hp > histptr) { - if (approx) - hp = hist_get_newest(allow_cur); - else { - bi_errorf("%s: not in history", str); - hp = (char **) 0; - } - } else if (!allow_cur && hp == histptr) { - bi_errorf("%s: invalid range", str); - hp = (char **) 0; - } - } else { - int anchored = *str == '?' ? (++str, 0) : 1; - - /* the -1 is to avoid the current fc command */ - n = findhist(histptr - history - 1, 0, str, anchored); - if (n < 0) { - bi_errorf("%s: not in history", str); - hp = (char **) 0; - } else - hp = &history[n]; - } - return hp; -} - -/* Return a pointer to the newest command in the history */ -static char ** -hist_get_newest(allow_cur) - int allow_cur; -{ - if (histptr < history || (!allow_cur && histptr == history)) { - bi_errorf("no history (yet)"); - return (char **) 0; - } - if (allow_cur) - return histptr; - return histptr - 1; -} - -/* Return a pointer to the newest command in the history */ -static char ** -hist_get_oldest() -{ - if (histptr <= history) { - bi_errorf("no history (yet)"); - return (char **) 0; - } - return history; -} - -/******************************/ -/* Back up over last histsave */ -/******************************/ -static void -histbackup() -{ - static int last_line = -1; - - if (histptr >= history && last_line != hist_source->line) { - hist_source->line--; - afree((void*)*histptr, APERM); - histptr--; - last_line = hist_source->line; - } -} - -/* - * Return the current position. - */ -char ** -histpos() -{ - return current; -} - -int -histN() -{ - return curpos; -} - -int -histnum(n) - int n; -{ - int last = histptr - history; - - if (n < 0 || n >= last) { - current = histptr; - curpos = last; - return last; - } else { - current = &history[n]; - curpos = n; - return n; - } -} - -/* - * This will become unecessary if hist_get is modified to allow - * searching from positions other than the end, and in either - * direction. - */ -int -findhist(start, fwd, str, anchored) - int start; - int fwd; - const char *str; - int anchored; -{ - char **hp; - int maxhist = histptr - history; - int incr = fwd ? 1 : -1; - int len = strlen(str); - - if (start < 0 || start >= maxhist) - start = maxhist; - - hp = &history[start]; - for (; hp >= history && hp <= histptr; hp += incr) - if ((anchored && strncmp(*hp, str, len) == 0) - || (!anchored && strstr(*hp, str))) - return hp - history; - - return -1; -} - -/* - * set history - * this means reallocating the dataspace - */ -void -sethistsize(n) - int n; -{ - if (n > 0 && n != histsize) { - int cursize = histptr - history; - - /* save most recent history */ - if (n < cursize) { - memmove(history, histptr - n, n * sizeof(char *)); - cursize = n; - } - - history = (char **)aresize(history, n*sizeof(char *), APERM); - - histsize = n; - histptr = history + cursize; - } -} - -/* - * set history file - * This can mean reloading/resetting/starting history file - * maintenance - */ -void -sethistfile(name) - const char *name; -{ - /* if not started then nothing to do */ - if (hstarted == 0) - return; - - /* if the name is the same as the name we have */ - if (hname && strcmp(hname, name) == 0) - return; - - /* - * its a new name - possibly - */ -# ifdef EASY_HISTORY - if (hname) { - afree(hname, APERM); - hname = NULL; - } -# else - if (histfd) { - /* yes the file is open */ - (void) close(histfd); - histfd = 0; - hsize = 0; - afree(hname, APERM); - hname = NULL; - /* let's reset the history */ - histptr = history - 1; - hist_source->line = 0; - } -# endif - - hist_init(hist_source); -} - -/* - * initialise the history vector - */ -void -init_histvec() -{ - if (history == (char **)NULL) { - histsize = HISTORYSIZE; - history = (char **)alloc(histsize*sizeof (char *), APERM); - histptr = history - 1; - } -} - -# ifdef EASY_HISTORY -/* - * save command in history - */ -void -histsave(lno, cmd, dowrite) - int lno; /* ignored (compatibility with COMPLEX_HISTORY) */ - const char *cmd; - int dowrite; /* ignored (compatibility with COMPLEX_HISTORY) */ -{ - register char **hp = histptr; - char *cp; - - if (++hp >= history + histsize) { /* remove oldest command */ - afree((void*)history[0], APERM); - memmove(history, history + 1, - sizeof(history[0]) * (histsize - 1)); - hp = &history[histsize - 1]; - } - *hp = str_save(cmd, APERM); - /* trash trailing newline but allow imbedded newlines */ - cp = *hp + strlen(*hp); - if (cp > *hp && cp[-1] == '\n') - cp[-1] = '\0'; - histptr = hp; -} - -/* - * Append an entry to the last saved command. Used for multiline - * commands - */ -void -histappend(cmd, nl_seperate) - const char *cmd; - int nl_seperate; -{ - int hlen, clen; - char *p; - - hlen = strlen(*histptr); - clen = strlen(cmd); - if (clen > 0 && cmd[clen-1] == '\n') - clen--; - p = *histptr = (char *) aresize(*histptr, hlen + clen + 2, APERM); - p += hlen; - if (nl_seperate) - *p++ = '\n'; - memcpy(p, cmd, clen); - p[clen] = '\0'; -} - -/* - * 92-04-25 <sjg@zen> - * A simple history file implementation. - * At present we only save the history when we exit. - * This can cause problems when there are multiple shells are - * running under the same user-id. The last shell to exit gets - * to save its history. - */ -void -hist_init(s) - Source *s; -{ - char *f; - FILE *fh; - - if (Flag(FTALKING) == 0) - return; - - hstarted = 1; - - hist_source = s; - - if ((f = str_val(global("HISTFILE"))) == NULL || *f == '\0') { -# if 1 /* Don't use history file unless the user asks for it */ - hname = NULL; - return; -# else - char *home = str_val(global("HOME")); - int len; - - if (home == NULL) - home = null; - f = HISTFILE; - hname = alloc(len = strlen(home) + strlen(f) + 2, APERM); - shf_snprintf(hname, len, "%s/%s", home, f); -# endif - } else - hname = str_save(f, APERM); - - if ((fh = fopen(hname, "r"))) { - int pos = 0, nread = 0; - int contin = 0; /* continuation of previous command */ - char *end; - char hline[LINE + 1]; - - while (1) { - if (pos >= nread) { - pos = 0; - nread = fread(hline, 1, LINE, fh); - if (nread <= 0) - break; - hline[nread] = '\0'; - } - end = strchr(hline + pos, 0); /* will always succeed */ - if (contin) - histappend(hline + pos, 0); - else { - hist_source->line++; - histsave(0, hline + pos, 0); - } - pos = end - hline + 1; - contin = end == &hline[nread]; - } - fclose(fh); - } -} - -/* - * save our history. - * We check that we do not have more than we are allowed. - * If the history file is read-only we do nothing. - * Handy for having all shells start with a useful history set. - */ - -void -hist_finish() -{ - static int once; - FILE *fh; - register int i; - register char **hp; - - if (once++) - return; - /* check how many we have */ - i = histptr - history; - if (i >= histsize) - hp = &histptr[-histsize]; - else - hp = history; - if (hname && (fh = fopen(hname, "w"))) - { - for (i = 0; hp + i <= histptr && hp[i]; i++) - fprintf(fh, "%s%c", hp[i], '\0'); - fclose(fh); - } -} - -# else /* EASY_HISTORY */ - -/* - * Routines added by Peter Collinson BSDI(Europe)/Hillside Systems to - * a) permit HISTSIZE to control number of lines of history stored - * b) maintain a physical history file - * - * It turns out that there is a lot of ghastly hackery here - */ - - -/* - * save command in history - */ -void -histsave(lno, cmd, dowrite) - int lno; - const char *cmd; - int dowrite; -{ - register char **hp; - char *c, *cp; - - c = str_save(cmd, APERM); - if ((cp = strchr(c, '\n')) != NULL) - *cp = '\0'; - - if (histfd && dowrite) - writehistfile(lno, c); - - hp = histptr; - - if (++hp >= history + histsize) { /* remove oldest command */ - afree((void*)*history, APERM); - for (hp = history; hp < history + histsize - 1; hp++) - hp[0] = hp[1]; - } - *hp = c; - histptr = hp; -} - -/* - * Write history data to a file nominated by HISTFILE - * if HISTFILE is unset then history still happens, but - * the data is not written to a file - * All copies of ksh looking at the file will maintain the - * same history. This is ksh behaviour. - * - * This stuff uses mmap() - * if your system ain't got it - then you'll have to undef HISTORYFILE - */ - -/* - * Open a history file - * Format is: - * Bytes 1, 2: HMAGIC - just to check that we are dealing with - * the correct object - * Then follows a number of stored commands - * Each command is - * <command byte><command number(4 bytes)><bytes><null> - */ -# define HMAGIC1 0xab -# define HMAGIC2 0xcd -# define COMMAND 0xff - -void -hist_init(s) - Source *s; -{ - unsigned char *base; - int lines; - int fd; - - if (Flag(FTALKING) == 0) - return; - - hstarted = 1; - - hist_source = s; - - hname = str_val(global("HISTFILE")); - if (hname == NULL) - return; - hname = str_save(hname, APERM); - - retry: - /* we have a file and are interactive */ - if ((fd = open(hname, O_RDWR|O_CREAT|O_APPEND, 0600)) < 0) - return; - - histfd = savefd(fd, 0); - - (void) flock(histfd, LOCK_EX); - - hsize = lseek(histfd, 0L, SEEK_END); - - if (hsize == 0) { - /* add magic */ - if (sprinkle(histfd)) { - hist_finish(); - return; - } - } - else if (hsize > 0) { - /* - * we have some data - */ - base = (unsigned char *)mmap(0, hsize, PROT_READ, MAP_FLAGS, histfd, 0); - /* - * check on its validity - */ - if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) { - if ((int)base != -1) - munmap((caddr_t)base, hsize); - hist_finish(); - unlink(hname); - goto retry; - } - if (hsize > 2) { - lines = hist_count_lines(base+2, hsize-2); - if (lines > histsize) { - /* we need to make the file smaller */ - if (hist_shrink(base, hsize)) - unlink(hname); - munmap((caddr_t)base, hsize); - hist_finish(); - goto retry; - } - } - histload(hist_source, base+2, hsize-2); - munmap((caddr_t)base, hsize); - } - (void) flock(histfd, LOCK_UN); - hsize = lseek(histfd, 0L, SEEK_END); -} - -typedef enum state { - shdr, /* expecting a header */ - sline, /* looking for a null byte to end the line */ - sn1, /* bytes 1 to 4 of a line no */ - sn2, sn3, sn4, -} State; - -static int -hist_count_lines(base, bytes) - register unsigned char *base; - register int bytes; -{ - State state = shdr; - register lines = 0; - - while (bytes--) { - switch (state) - { - case shdr: - if (*base == COMMAND) - state = sn1; - break; - case sn1: - state = sn2; break; - case sn2: - state = sn3; break; - case sn3: - state = sn4; break; - case sn4: - state = sline; break; - case sline: - if (*base == '\0') - lines++, state = shdr; - } - base++; - } - return lines; -} - -/* - * Shrink the history file to histsize lines - */ -static int -hist_shrink(oldbase, oldbytes) - unsigned char *oldbase; - int oldbytes; -{ - int fd; - char nfile[1024]; - struct stat statb; - unsigned char *nbase = oldbase; - int nbytes = oldbytes; - - nbase = hist_skip_back(nbase, &nbytes, histsize); - if (nbase == NULL) - return 1; - if (nbase == oldbase) - return 0; - - /* - * create temp file - */ - (void) shf_snprintf(nfile, sizeof(nfile), "%s.%d", hname, procpid); - if ((fd = creat(nfile, 0600)) < 0) - return 1; - - if (sprinkle(fd)) { - close(fd); - unlink(nfile); - return 1; - } - if (write(fd, nbase, nbytes) != nbytes) { - close(fd); - unlink(nfile); - return 1; - } - /* - * worry about who owns this file - */ - if (fstat(histfd, &statb) >= 0) - fchown(fd, statb.st_uid, statb.st_gid); - close(fd); - - /* - * rename - */ - if (rename(nfile, hname) < 0) - return 1; - return 0; -} - - -/* - * find a pointer to the data `no' back from the end of the file - * return the pointer and the number of bytes left - */ -static unsigned char * -hist_skip_back(base, bytes, no) - unsigned char *base; - int *bytes; - int no; -{ - register int lines = 0; - register unsigned char *ep; - - for (ep = base + *bytes; --ep > base; ) { - /* this doesn't really work: the 4 byte line number that is - * encoded after the COMMAND byte can itself contain the - * COMMAND byte.... - */ - for (; ep > base && *ep != COMMAND; ep--) - ; - if (ep == base) - break; - if (++lines == no) { - *bytes = *bytes - ((char *)ep - (char *)base); - return ep; - } - } - return NULL; -} - -/* - * load the history structure from the stored data - */ -static void -histload(s, base, bytes) - Source *s; - register unsigned char *base; - register int bytes; -{ - State state; - int lno; - unsigned char *line; - - for (state = shdr; bytes-- > 0; base++) { - switch (state) { - case shdr: - if (*base == COMMAND) - state = sn1; - break; - case sn1: - lno = (((*base)&0xff)<<24); - state = sn2; - break; - case sn2: - lno |= (((*base)&0xff)<<16); - state = sn3; - break; - case sn3: - lno |= (((*base)&0xff)<<8); - state = sn4; - break; - case sn4: - lno |= (*base)&0xff; - line = base+1; - state = sline; - break; - case sline: - if (*base == '\0') { - /* worry about line numbers */ - if (histptr >= history && lno-1 != s->line) { - /* a replacement ? */ - histinsert(s, lno, line); - } - else { - s->line = lno; - histsave(lno, (char *)line, 0); - } - state = shdr; - } - } - } -} - -/* - * Insert a line into the history at a specified number - */ -static void -histinsert(s, lno, line) - Source *s; - int lno; - unsigned char *line; -{ - register char **hp; - - if (lno >= s->line-(histptr-history) && lno <= s->line) { - hp = &histptr[lno-s->line]; - if (*hp) - afree((void*)*hp, APERM); - *hp = str_save((char *)line, APERM); - } -} - -/* - * write a command to the end of the history file - * This *MAY* seem easy but it's also necessary to check - * that the history file has not changed in size. - * If it has - then some other shell has written to it - * and we should read those commands to update our history - */ -static void -writehistfile(lno, cmd) - int lno; - char *cmd; -{ - int sizenow; - unsigned char *base; - unsigned char *new; - int bytes; - char hdr[5]; - - (void) flock(histfd, LOCK_EX); - sizenow = lseek(histfd, 0L, SEEK_END); - if (sizenow != hsize) { - /* - * Things have changed - */ - if (sizenow > hsize) { - /* someone has added some lines */ - bytes = sizenow - hsize; - base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0); - if ((int)base == -1) - goto bad; - new = base + hsize; - if (*new != COMMAND) { - munmap((caddr_t)base, sizenow); - goto bad; - } - hist_source->line--; - histload(hist_source, new, bytes); - hist_source->line++; - lno = hist_source->line; - munmap((caddr_t)base, sizenow); - hsize = sizenow; - } else { - /* it has shrunk */ - /* but to what? */ - /* we'll give up for now */ - goto bad; - } - } - /* - * we can write our bit now - */ - hdr[0] = COMMAND; - hdr[1] = (lno>>24)&0xff; - hdr[2] = (lno>>16)&0xff; - hdr[3] = (lno>>8)&0xff; - hdr[4] = lno&0xff; - (void) write(histfd, hdr, 5); - (void) write(histfd, cmd, strlen(cmd)+1); - hsize = lseek(histfd, 0L, SEEK_END); - (void) flock(histfd, LOCK_UN); - return; -bad: - hist_finish(); -} - -void -hist_finish() -{ - (void) flock(histfd, LOCK_UN); - (void) close(histfd); - histfd = 0; -} - -/* - * add magic to the history file - */ -static int -sprinkle(fd) - int fd; -{ - static char mag[] = { HMAGIC1, HMAGIC2 }; - - return(write(fd, mag, 2) != 2); -} - -# endif -#else /* HISTORY */ - -/* No history to be compiled in: dummy routines to avoid lots more ifdefs */ -void -init_histvec() -{ -} -void -hist_init(s) - Source *s; -{ -} -void -hist_finish() -{ -} -void -histsave(lno, cmd, dowrite) - int lno; - const char *cmd; - int dowrite; -{ - errorf("history not enabled"); -} -#endif /* HISTORY */ diff --git a/bin/pdksh/io.c b/bin/pdksh/io.c deleted file mode 100644 index 4a2f1cc88e2..00000000000 --- a/bin/pdksh/io.c +++ /dev/null @@ -1,473 +0,0 @@ -/* $OpenBSD: io.c,v 1.4 1997/06/19 13:58:42 kstailey Exp $ */ - -/* - * shell buffered IO and formatted output - */ - -#include <ctype.h> -#include "sh.h" -#include "ksh_stat.h" - -/* - * formatted output functions - */ - - -/* A shell error occured (eg, syntax error, etc.) */ -void -#ifdef HAVE_PROTOTYPES -errorf(const char *fmt, ...) -#else -errorf(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list va; - - shl_stdout_ok = 0; /* debugging: note that stdout not valid */ - exstat = 1; - if (*fmt) { - error_prefix(TRUE); - SH_VA_START(va, fmt); - shf_vfprintf(shl_out, fmt, va); - va_end(va); - shf_putchar('\n', shl_out); - } - shf_flush(shl_out); - unwind(LERROR); -} - -/* like errorf(), but no unwind is done */ -void -#ifdef HAVE_PROTOTYPES -warningf(int fileline, const char *fmt, ...) -#else -warningf(fileline, fmt, va_alist) - int fileline; - const char *fmt; - va_dcl -#endif -{ - va_list va; - - error_prefix(fileline); - SH_VA_START(va, fmt); - shf_vfprintf(shl_out, fmt, va); - va_end(va); - shf_putchar('\n', shl_out); - shf_flush(shl_out); -} - -/* Used by built-in utilities to prefix shell and utility name to message - * (also unwinds environments for special builtins). - */ -void -#ifdef HAVE_PROTOTYPES -bi_errorf(const char *fmt, ...) -#else -bi_errorf(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list va; - - shl_stdout_ok = 0; /* debugging: note that stdout not valid */ - exstat = 1; - if (*fmt) { - error_prefix(TRUE); - /* not set when main() calls parse_args() */ - if (builtin_argv0) - shf_fprintf(shl_out, "%s: ", builtin_argv0); - SH_VA_START(va, fmt); - shf_vfprintf(shl_out, fmt, va); - va_end(va); - shf_putchar('\n', shl_out); - } - shf_flush(shl_out); - /* POSIX special builtins and ksh special builtins cause - * non-interactive shells to exit. - * XXX odd use of KEEPASN; also may not want LERROR here - */ - if ((builtin_flag & SPEC_BI) - || (Flag(FPOSIX) && (builtin_flag & KEEPASN))) - { - builtin_argv0 = (char *) 0; - unwind(LERROR); - } -} - -/* Called when something that shouldn't happen does */ -void -#ifdef HAVE_PROTOTYPES -internal_errorf(int jump, const char *fmt, ...) -#else -internal_errorf(jump, fmt, va_alist) - int jump; - const char *fmt; - va_dcl -#endif -{ - va_list va; - - error_prefix(TRUE); - shf_fprintf(shl_out, "internal error: "); - SH_VA_START(va, fmt); - shf_vfprintf(shl_out, fmt, va); - va_end(va); - shf_putchar('\n', shl_out); - shf_flush(shl_out); - if (jump) - unwind(LERROR); -} - -/* used by error reporting functions to print "ksh: .kshrc[25]: " */ -void -error_prefix(fileline) - int fileline; -{ - shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-')); - if (fileline && source && source->file != NULL) { - shf_fprintf(shl_out, "%s[%d]: ", source->file, - source->errline > 0 ? source->errline : source->line); - source->errline = 0; - } -} - -/* printf to shl_out (stderr) with flush */ -void -#ifdef HAVE_PROTOTYPES -shellf(const char *fmt, ...) -#else -shellf(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list va; - - SH_VA_START(va, fmt); - shf_vfprintf(shl_out, fmt, va); - va_end(va); - shf_flush(shl_out); -} - -/* printf to shl_stdout (stdout) */ -void -#ifdef HAVE_PROTOTYPES -shprintf(const char *fmt, ...) -#else -shprintf(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list va; - - if (!shl_stdout_ok) - internal_errorf(1, "shl_stdout not valid"); - SH_VA_START(va, fmt); - shf_vfprintf(shl_stdout, fmt, va); - va_end(va); -} - -/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */ -int -can_seek(fd) - int fd; -{ - struct stat statb; - - return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ? - SHF_UNBUF : 0; -} - -struct shf shf_iob[3]; - -void -initio() -{ - shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */ - shf_fdopen(2, SHF_WR, shl_out); - shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */ -} - -/* A dup2() with error checking */ -int -ksh_dup2(ofd, nfd, errok) - int ofd; - int nfd; - int errok; -{ - int ret = dup2(ofd, nfd); - - if (ret < 0 && errno != EBADF && !errok) - errorf("too many files open in shell"); - -#ifdef DUP2_BROKEN - /* Ultrix systems like to preserve the close-on-exec flag */ - if (ret >= 0) - (void) fcntl(nfd, F_SETFD, 0); -#endif /* DUP2_BROKEN */ - - return ret; -} - -/* - * move fd from user space (0<=fd<10) to shell space (fd>=10), - * set close-on-exec flag. - */ -int -savefd(fd, noclose) - int fd; - int noclose; -{ - int nfd; - - if (fd < FDBASE) { - nfd = ksh_dupbase(fd, FDBASE); - if (nfd < 0) - if (errno == EBADF) - return -1; - else - errorf("too many files open in shell"); - if (!noclose) - close(fd); - } else - nfd = fd; - fd_clexec(nfd); - return nfd; -} - -void -restfd(fd, ofd) - int fd, ofd; -{ - if (fd == 2) - shf_flush(&shf_iob[fd]); - if (ofd < 0) /* original fd closed */ - close(fd); - else { - ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */ - close(ofd); - } -} - -void -openpipe(pv) - register int *pv; -{ - if (pipe(pv) < 0) - errorf("can't create pipe - try again"); - pv[0] = savefd(pv[0], 0); - pv[1] = savefd(pv[1], 0); -} - -void -closepipe(pv) - register int *pv; -{ - close(pv[0]); - close(pv[1]); -} - -/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn - * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. - */ -int -check_fd(name, mode, emsgp) - char *name; - int mode; - const char **emsgp; -{ - int fd, fl; - - if (isdigit(name[0]) && !name[1]) { - fd = name[0] - '0'; - if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) { - if (emsgp) - *emsgp = "bad file descriptor"; - return -1; - } - fl &= O_ACCMODE; -#ifdef OS2 - if (mode == W_OK ) { - if (setmode(fd, O_TEXT) == -1) { - if (emsgp) - *emsgp = "couldn't set write mode"; - return -1; - } - } else if (mode == R_OK) - if (setmode(fd, O_BINARY) == -1) { - if (emsgp) - *emsgp = "couldn't set read mode"; - return -1; - } -#else /* OS2 */ - /* X_OK is a kludge to disable this check for dups (x<&1): - * historical shells never did this check (XXX don't know what - * posix has to say). - */ - if (!(mode & X_OK) && fl != O_RDWR - && (((mode & R_OK) && fl != O_RDONLY) - || ((mode & W_OK) && fl != O_WRONLY))) - { - if (emsgp) - *emsgp = (fl == O_WRONLY) ? - "fd not open for reading" - : "fd not open for writing"; - return -1; - } -#endif /* OS2 */ - return fd; - } -#ifdef KSH - else if (name[0] == 'p' && !name[1]) - return coproc_getfd(mode, emsgp); -#endif /* KSH */ - if (emsgp) - *emsgp = "illegal file descriptor name"; - return -1; -} - -#ifdef KSH -/* Called once from main */ -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 */ -void -coproc_read_close(fd) - int fd; -{ - if (coproc.read >= 0 && fd == coproc.read) { - coproc_readw_close(fd); - close(coproc.read); - coproc.read = -1; - } -} - -/* Called by c_read() and by iosetup() to close the other side of the - * read pipe, so reads will actually terminate. - */ -void -coproc_readw_close(fd) - int fd; -{ - if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) { - close(coproc.readw); - coproc.readw = -1; - } -} - -/* Called by c_print when a write to a fd fails with EPIPE and by iosetup - * when co-process input is dup'd - */ -void -coproc_write_close(fd) - int fd; -{ - if (coproc.write >= 0 && fd == coproc.write) { - close(coproc.write); - coproc.write = -1; - } -} - -/* Called to check for existance of/value of the co-process file descriptor. - * (Used by check_fd() and by c_read/c_print to deal with -p option). - */ -int -coproc_getfd(mode, emsgp) - int mode; - const char **emsgp; -{ - int fd = (mode & R_OK) ? coproc.read : coproc.write; - - if (fd >= 0) - return fd; - if (emsgp) - *emsgp = "no coprocess"; - return -1; -} - -/* called to close file descriptors related to the coprocess (if any) - * Should be called with SIGCHLD blocked. - */ -void -coproc_cleanup(reuse) - int reuse; -{ - /* This to allow co-processes to share output pipe */ - if (!reuse || coproc.readw < 0 || coproc.read < 0) { - if (coproc.read >= 0) { - close(coproc.read); - coproc.read = -1; - } - if (coproc.readw >= 0) { - close(coproc.readw); - coproc.readw = -1; - } - } - if (coproc.write >= 0) { - close(coproc.write); - coproc.write = -1; - } -} -#endif /* KSH */ - -/* - * temporary files - */ - -struct temp * -maketemp(ap) - Area *ap; -{ - static unsigned int inc; - struct temp *tp; - int len; - int fd; - char *path; - const char *tmp; - - tmp = tmpdir ? tmpdir : "/tmp"; - /* The 20 + 20 is a paranoid worst case for pid/inc */ - len = strlen(tmp) + 3 + 20 + 20 + 1; - tp = (struct temp *) alloc(sizeof(struct temp) + len, ap); - tp->name = path = (char *) &tp[1]; - tp->shf = (struct shf *) 0; - while (1) { - /* Note that temp files need to fit 8.3 DOS limits */ - shf_snprintf(path, len, "%s/sh%05u.%03x", - tmp, (unsigned) procpid, inc++); - /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't - * really there. - */ - fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600); - if (fd >= 0) { - tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0); - break; - } - if (errno != EINTR -#ifdef EEXIST - && errno != EEXIST -#endif /* EEXIST */ -#ifdef EISDIR - && errno != EISDIR -#endif /* EISDIR */ - ) - /* Error must be printed by called: don't know here if - * errorf() or bi_errorf() should be used. - */ - break; - } - tp->next = NULL; - tp->pid = procpid; - return tp; -} diff --git a/bin/pdksh/jobs.c b/bin/pdksh/jobs.c deleted file mode 100644 index e79f2ac731c..00000000000 --- a/bin/pdksh/jobs.c +++ /dev/null @@ -1,1844 +0,0 @@ -/* $OpenBSD: jobs.c,v 1.6 1997/06/19 13:58:43 kstailey Exp $ */ - -/* - * Process and job control - */ - -/* - * Reworked/Rewritten version of Eric Gisin's/Ron Natalie's code by - * Larry Bouzane (larry@cs.mun.ca) and hacked again by - * Michael Rendell (michael@cs.mun.ca) - * - * The interface to the rest of the shell should probably be changed - * to allow use of vfork() when available but that would be way too much - * work :) - * - * Notes regarding the copious ifdefs: - * - JOB_SIGS is independent of JOBS - it is defined if there are modern - * signal and wait routines available. This is prefered, even when - * JOBS is not defined, since the shell will not otherwise notice when - * background jobs die until the shell waits for a foreground process - * to die. - * - TTY_PGRP defined iff JOBS is defined - defined if there are tty - * process groups - * - NEED_PGRP_SYNC defined iff JOBS is defined - see comment below - */ - -#include "sh.h" -#include "ksh_stat.h" -#include "ksh_wait.h" -#include "ksh_times.h" -#include "tty.h" - -/* Start of system configuration stuff */ - -/* We keep CHILD_MAX zombie processes around (exact value isn't critical) */ -#ifndef CHILD_MAX -# if defined(HAVE_SYSCONF) && defined(_SC_CHILD_MAX) -# define CHILD_MAX sysconf(_SC_CHILD_MAX) -# else /* _SC_CHILD_MAX */ -# ifdef _POSIX_CHILD_MAX -# define CHILD_MAX ((_POSIX_CHILD_MAX) * 2) -# else /* _POSIX_CHILD_MAX */ -# define CHILD_MAX 20 -# endif /* _POSIX_CHILD_MAX */ -# endif /* _SC_CHILD_MAX */ -#endif /* !CHILD_MAX */ - -#ifdef JOBS -# if defined(HAVE_TCSETPGRP) || defined(TIOCSPGRP) -# define TTY_PGRP -# endif -# ifdef BSD_PGRP -# define setpgid setpgrp -# define getpgID() getpgrp(0) -# else -# define getpgID() getpgrp() -# endif -# if defined(TTY_PGRP) && !defined(HAVE_TCSETPGRP) -int tcsetpgrp ARGS((int fd, pid_t grp)); -int tcgetpgrp ARGS((int fd)); - -int -tcsetpgrp(fd, grp) - int fd; - pid_t grp; -{ - return ioctl(fd, TIOCSPGRP, &grp); -} - -int -tcgetpgrp(fd) - int fd; -{ - int r, grp; - - if ((r = ioctl(fd, TIOCGPGRP, &grp)) < 0) - return r; - return grp; -} -# endif /* !HAVE_TCSETPGRP && TIOCSPGRP */ -#else /* JOBS */ -/* These so we can use ifdef xxx instead of if defined(JOBS) && defined(xxx) */ -# undef TTY_PGRP -# undef NEED_PGRP_SYNC -#endif /* JOBS */ - -/* End of system configuration stuff */ - - -/* Order important! */ -#define PRUNNING 0 -#define PEXITED 1 -#define PSIGNALLED 2 -#define PSTOPPED 3 - -typedef struct proc Proc; -struct proc { - Proc *next; /* next process in pipeline (if any) */ - int state; - WAIT_T status; /* wait status */ - pid_t pid; /* process id */ - char command[48]; /* process command string */ -}; - -/* Notify/print flag - j_print() argument */ -#define JP_NONE 0 /* don't print anything */ -#define JP_SHORT 1 /* print signals processes were killed by */ -#define JP_MEDIUM 2 /* print [job-num] -/+ command */ -#define JP_LONG 3 /* print [job-num] -/+ pid command */ -#define JP_PGRP 4 /* print pgrp */ - -/* put_job() flags */ -#define PJ_ON_FRONT 0 /* at very front */ -#define PJ_PAST_STOPPED 1 /* just past any stopped jobs */ - -/* Job.flags values */ -#define JF_STARTED 0x001 /* set when all processes in job are started */ -#define JF_WAITING 0x002 /* set if j_waitj() is waiting on job */ -#define JF_W_ASYNCNOTIFY 0x004 /* set if waiting and async notification ok */ -#define JF_XXCOM 0x008 /* set for `command` jobs */ -#define JF_FG 0x010 /* running in foreground (also has tty pgrp) */ -#define JF_SAVEDTTY 0x020 /* j->ttystate is valid */ -#define JF_CHANGED 0x040 /* process has changed state */ -#define JF_KNOWN 0x080 /* $! referenced */ -#define JF_ZOMBIE 0x100 /* known, unwaited process */ -#define JF_REMOVE 0x200 /* flaged for removal (j_jobs()/j_noityf()) */ -#define JF_USETTYMODE 0x400 /* tty mode saved if process exits normally */ - -typedef struct job Job; -struct job { - Job *next; /* next job in list */ - int job; /* job number: %n */ - int flags; /* see JF_* */ - int state; /* job state */ - int status; /* exit status of last process */ - pid_t pgrp; /* process group of job */ - pid_t ppid; /* pid of process that forked job */ - INT32 age; /* number of jobs started */ - clock_t systime; /* system time used by job */ - clock_t usrtime; /* user time used by job */ - Proc *proc_list; /* process list */ - Proc *last_proc; /* last process in list */ -#ifdef KSH - Coproc_id coproc_id; /* 0 or id of coprocess output pipe */ -#endif /* KSH */ -#ifdef TTY_PGRP - TTY_state ttystate; /* saved tty state for stopped jobs */ -#endif /* TTY_PGRP */ -}; - -/* Flags for j_waitj() */ -#define JW_NONE 0x00 -#define JW_INTERRUPT 0x01 /* ^C will stop the wait */ -#define JW_ASYNCNOTIFY 0x02 /* asynchronous notification during wait ok */ -#define JW_STOPPEDWAIT 0x04 /* wait even if job stopped */ - -/* Error codes for j_lookup() */ -#define JL_OK 0 -#define JL_NOSUCH 1 /* no such job */ -#define JL_AMBIG 2 /* %foo or %?foo is ambiguous */ -#define JL_INVALID 3 /* non-pid, non-% job id */ - -static const char *const lookup_msgs[] = { - null, - "no such job", - "ambiguous", - "argument must be %job or process id", - (char *) 0 - }; -clock_t j_systime, j_usrtime; /* user and system time of last j_waitjed job */ - -static Job *job_list; /* job list */ -static Job *last_job; -static Job *async_job; -static pid_t async_pid; - -static int nzombie; /* # of zombies owned by this process */ -static INT32 njobs; /* # of jobs started */ -static int child_max; /* CHILD_MAX */ - - -#ifdef JOB_SIGS -/* held_sigchld is set if sigchld occurs before a job is completely started */ -static int held_sigchld; -#endif /* JOB_SIGS */ - -#ifdef JOBS -static struct shf *shl_j; -#endif /* JOBS */ - -#ifdef NEED_PGRP_SYNC -/* On some systems, the kernel doesn't count zombie processes when checking - * if a process group is valid, which can cause problems in creating the - * pipeline "cmd1 | cmd2": if cmd1 can die (and go into the zombie state) - * before cmd2 is started, the kernel doesn't allow the setpgid() for cmd2 - * to succeed. Solution is to create a pipe between the parent and the first - * process; the first process doesn't do anything until the pipe is closed - * and the parent doesn't close the pipe until all the processes are started. - */ -static int j_sync_pipe[2]; -static int j_sync_open; -#endif /* NEED_PGRP_SYNC */ - -#ifdef TTY_PGRP -static int ttypgrp_ok; /* set if can use tty pgrps */ -static pid_t restore_ttypgrp = -1; -static pid_t our_pgrp; -static int const tt_sigs[] = { SIGTSTP, SIGTTIN, SIGTTOU }; -#endif /* TTY_PGRP */ - -static void j_set_async ARGS((Job *j)); -static void j_startjob ARGS((Job *j)); -static int j_waitj ARGS((Job *j, int flags, const char *where)); -static RETSIGTYPE j_sigchld ARGS((int sig)); -static void j_print ARGS((Job *j, int how, struct shf *shf)); -static Job *j_lookup ARGS((const char *cp, int *ecodep)); -static Job *new_job ARGS((void)); -static Proc *new_proc ARGS((void)); -static void check_job ARGS((Job *j)); -static void put_job ARGS((Job *j, int where)); -static void remove_job ARGS((Job *j, const char *where)); -static void kill_job ARGS((Job *j)); -static void fill_command ARGS((char *c, int len, struct op *t)); - -/* initialize job control */ -void -j_init(mflagset) - int mflagset; -{ - child_max = CHILD_MAX; /* so syscon() isn't always being called */ - -#ifdef JOB_SIGS - sigemptyset(&sm_default); - sigprocmask(SIG_SETMASK, &sm_default, (sigset_t *) 0); - - sigemptyset(&sm_sigchld); - sigaddset(&sm_sigchld, SIGCHLD); - - 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); -#endif /* JOB_SIGS */ - -#ifdef JOBS - if (!mflagset && Flag(FTALKING)) - Flag(FMONITOR) = 1; - - /* shl_j is used to do asynchronous notification (used in - * an interrupt handler, so need a distinct shf) - */ - shl_j = shf_fdopen(2, SHF_WR, (struct shf *) 0); - -# ifdef TTY_PGRP - if (Flag(FMONITOR) || Flag(FTALKING)) { - int i; - - /* 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); - } - } -# endif /* TTY_PGRP */ - - /* j_change() calls tty_init() */ - if (Flag(FMONITOR)) - j_change(); - else -#endif /* JOBS */ - if (Flag(FTALKING)) - tty_init(TRUE); -} - -/* job cleanup before shell exit */ -void -j_exit() -{ - /* kill stopped, and possibly running, jobs */ - Job *j; - int killed = 0; - - for (j = job_list; j != (Job *) 0; j = j->next) { - if (j->ppid == procpid - && (j->state == PSTOPPED - || (j->state == PRUNNING - && ((j->flags & JF_FG) - || (Flag(FLOGIN) && !Flag(FNOHUP) - && procpid == kshpid))))) - { - killed = 1; - killpg(j->pgrp, SIGHUP); -#ifdef JOBS - if (j->state == PSTOPPED) - killpg(j->pgrp, SIGCONT); -#endif /* JOBS */ - } - } - if (killed) - sleep(1); - j_notify(); - -#ifdef JOBS -# ifdef TTY_PGRP - if (kshpid == procpid && restore_ttypgrp >= 0) { - /* Need to restore the tty pgrp to what it was when the - * shell started up, so that the process that started us - * will be able to access the tty when we are done. - * Also need to restore our process group in case we are - * about to do an exec so that both our parent and the - * process we are to become will be able to access the tty. - */ - tcsetpgrp(tty_fd, restore_ttypgrp); - setpgid(0, restore_ttypgrp); - } -# endif /* TTY_PGRP */ - if (Flag(FMONITOR)) { - Flag(FMONITOR) = 0; - j_change(); - } -#endif /* JOBS */ -} - -#ifdef JOBS -/* turn job control on or off according to Flag(FMONITOR) */ -void -j_change() -{ - int i; - - if (Flag(FMONITOR)) { - /* Don't call get_tty() 'til we own the tty process group */ - tty_init(FALSE); - -# ifdef TTY_PGRP - /* no controlling tty, no SIGT* */ - ttypgrp_ok = tty_fd >= 0 && tty_devtty; - - if (ttypgrp_ok && (our_pgrp = getpgID()) < 0) { - warningf(FALSE, "j_init: getpgrp() failed: %s", - strerror(errno)); - ttypgrp_ok = 0; - } - if (ttypgrp_ok) { - setsig(&sigtraps[SIGTTIN], SIG_DFL, - SS_RESTORE_ORIG|SS_FORCE); - /* wait to be given tty (POSIX.1, B.2, job control) */ - while (1) { - pid_t ttypgrp; - - if ((ttypgrp = tcgetpgrp(tty_fd)) < 0) { - warningf(FALSE, - "j_init: tcgetpgrp() failed: %s", - strerror(errno)); - ttypgrp_ok = 0; - break; - } - if (ttypgrp == our_pgrp) - break; - kill(0, SIGTTIN); - } - } - for (i = NELEM(tt_sigs); --i >= 0; ) - setsig(&sigtraps[tt_sigs[i]], SIG_IGN, - SS_RESTORE_DFL|SS_FORCE); - if (ttypgrp_ok && our_pgrp != kshpid) { - if (setpgid(0, kshpid) < 0) { - warningf(FALSE, - "j_init: setpgid() failed: %s", - strerror(errno)); - ttypgrp_ok = 0; - } else { - if (tcsetpgrp(tty_fd, kshpid) < 0) { - warningf(FALSE, - "j_init: tcsetpgrp() failed: %s", - strerror(errno)); - ttypgrp_ok = 0; - } else - restore_ttypgrp = our_pgrp; - our_pgrp = kshpid; - } - } -# if defined(NTTYDISC) && defined(TIOCSETD) && !defined(HAVE_TERMIOS_H) && !defined(HAVE_TERMIO_H) - if (ttypgrp_ok) { - int ldisc = NTTYDISC; - - if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0) - warningf(FALSE, - "j_init: can't set new line discipline: %s", - strerror(errno)); - } -# endif /* NTTYDISC && TIOCSETD */ - if (!ttypgrp_ok) - warningf(FALSE, "warning: won't have full job control"); -# endif /* TTY_PGRP */ - if (tty_fd >= 0) - get_tty(tty_fd, &tty_state); - } else { -# ifdef TTY_PGRP - ttypgrp_ok = 0; - if (Flag(FTALKING)) - for (i = NELEM(tt_sigs); --i >= 0; ) - setsig(&sigtraps[tt_sigs[i]], SIG_IGN, - SS_RESTORE_IGN|SS_FORCE); - else - for (i = NELEM(tt_sigs); --i >= 0; ) { - if (sigtraps[tt_sigs[i]].flags & (TF_ORIG_IGN - |TF_ORIG_DFL)) - setsig(&sigtraps[tt_sigs[i]], - (sigtraps[tt_sigs[i]].flags & TF_ORIG_IGN) ? SIG_IGN : SIG_DFL, - SS_RESTORE_ORIG|SS_FORCE); - } -# endif /* TTY_PGRP */ - if (!Flag(FTALKING)) - tty_close(); - } -} -#endif /* JOBS */ - -/* execute tree in child subprocess */ -int -exchild(t, flags, close_fd) - struct op *t; - int flags; - int close_fd; /* used if XPCLOSE or XCCLOSE */ -{ - static Proc *last_proc; /* for pipelines */ - - int i; -#ifdef JOB_SIGS - sigset_t omask; -#endif /* JOB_SIGS */ - Proc *p; - Job *j; - int rv = 0; - int forksleep; - int orig_flags = flags; - int ischild; - - flags &= ~(XFORK|XPCLOSE|XCCLOSE|XCOPROC); - if (flags & XEXEC) - return execute(t, flags); - -#ifdef JOB_SIGS - /* no SIGCHLD's while messing with job and process lists */ - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - p = new_proc(); - p->next = (Proc *) 0; - p->state = PRUNNING; - WSTATUS(p->status) = 0; - p->pid = 0; - - /* link process into jobs list */ - if (flags&XPIPEI) { /* continuing with a pipe */ - j = last_job; - last_proc->next = p; - last_proc = p; - } else { -#ifdef NEED_PGRP_SYNC - if (j_sync_open) { /* should never happen */ - j_sync_open = 0; - closepipe(j_sync_pipe); - } - /* don't do the sync pipe business if there is no pipeline */ - if (flags & XPIPEO) { - openpipe(j_sync_pipe); - j_sync_open = 1; - } -#endif /* NEED_PGRP_SYNC */ - j = new_job(); /* fills in j->job */ - /* we don't consider XXCOM's foreground since they don't get - * tty process group and we don't save or restore tty modes. - */ - j->flags = (flags & XXCOM) ? JF_XXCOM - : ((flags & XBGND) ? 0 : (JF_FG|JF_USETTYMODE)); - j->usrtime = j->systime = 0; - j->state = PRUNNING; - j->pgrp = 0; - j->ppid = procpid; - j->age = ++njobs; - j->proc_list = p; -#ifdef KSH - j->coproc_id = 0; -#endif /* KSH */ - last_job = j; - last_proc = p; - put_job(j, PJ_PAST_STOPPED); - } - - fill_command(p->command, sizeof(p->command), t); - - /* create child process */ - forksleep = 1; - while ((i = fork()) < 0 && errno == EAGAIN && forksleep < 32) { - if (intrsig) /* allow user to ^C out... */ - break; - sleep(forksleep); - forksleep <<= 1; - } - if (i < 0) { - kill_job(j); - remove_job(j, "fork failed"); -#ifdef NEED_PGRP_SYNC - if (j_sync_open) { - closepipe(j_sync_pipe); - j_sync_open = 0; - } -#endif /* NEED_PGRP_SYNC */ -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - errorf("cannot fork - try again"); - } - ischild = i == 0; - if (ischild) - p->pid = procpid = getpid(); - else - p->pid = i; - -#ifdef JOBS - /* job control set up */ - if (Flag(FMONITOR) && !(flags&XXCOM)) { - int dotty = 0; -# ifdef NEED_PGRP_SYNC - int first_child_sync = 0; -# endif /* NEED_PGRP_SYNC */ - -# ifdef NEED_PGRP_SYNC - if (j_sync_open) { - /* - * The Parent closes 0, keeps 1 open 'til the whole - * pipeline is started. The First child closes 1, - * keeps 0 open (reads from it). The remaining - * children just have to close 1 (parent has already - * closeed 0). - */ - if (j->pgrp == 0) { /* First process */ - close(j_sync_pipe[ischild]); - j_sync_pipe[ischild] = -1; - first_child_sync = ischild; - } else if (ischild) { - j_sync_open = 0; - closepipe(j_sync_pipe); - } - } -# endif /* NEED_PGRP_SYNC */ - if (j->pgrp == 0) { /* First process */ - j->pgrp = p->pid; - dotty = 1; - } - - /* set pgrp in both parent and child to deal with race - * condition - */ - setpgid(p->pid, j->pgrp); -# ifdef TTY_PGRP - /* YYY: should this be - if (ttypgrp_ok && ischild && !(flags&XBGND)) - tcsetpgrp(tty_fd, j->pgrp); - instead? (see also YYY below) - */ - if (ttypgrp_ok && dotty && !(flags & XBGND)) - tcsetpgrp(tty_fd, j->pgrp); -# endif /* TTY_PGRP */ -# ifdef NEED_PGRP_SYNC - if (first_child_sync) { - char c; - while (read(j_sync_pipe[0], &c, 1) == -1 - && errno == EINTR) - ; - close(j_sync_pipe[0]); - j_sync_open = 0; - } -# endif /* NEED_PGRP_SYNC */ - } -#endif /* JOBS */ - - /* used to close pipe input fd */ - if (close_fd >= 0 && (((orig_flags & XPCLOSE) && !ischild) - || ((orig_flags & XCCLOSE) && ischild))) - close(close_fd); - 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 TTY_PGRP - /* If FMONITOR or FTALKING is set, these signals are ignored, - * if neither FMONITOR nor FTALKING are set, the signals have - * their inherited values. - */ - if (Flag(FMONITOR) && !(flags & XXCOM)) { - for (i = NELEM(tt_sigs); --i >= 0; ) - setsig(&sigtraps[tt_sigs[i]], SIG_DFL, - SS_RESTORE_DFL|SS_FORCE); - } -#endif /* TTY_PGRP */ -#ifdef HAVE_NICE - if (Flag(FBGNICE) && (flags & XBGND)) - nice(4); -#endif /* HAVE_NICE */ - if ((flags & XBGND) && !Flag(FMONITOR)) { - setsig(&sigtraps[SIGINT], SIG_IGN, - SS_RESTORE_IGN|SS_FORCE); - setsig(&sigtraps[SIGQUIT], SIG_IGN, - SS_RESTORE_IGN|SS_FORCE); - if (!(orig_flags & (XPIPEI | XCOPROC))) { - int fd = open("/dev/null", 0); - (void) ksh_dup2(fd, 0, TRUE); - close(fd); - } - } - remove_job(j, "child"); /* in case of `jobs` command */ - nzombie = 0; -#ifdef JOBS - ttypgrp_ok = 0; - Flag(FMONITOR) = 0; -#endif /* JOBS */ - Flag(FTALKING) = 0; - tty_close(); - cleartraps(); - execute(t, flags|XEXEC); /* no return */ - internal_errorf(0, "exchild: execute() returned"); - unwind(LLEAVE); - /* NOTREACHED */ - } - - /* shell (parent) stuff */ - if (!(flags & XPIPEO)) { /* last process in a job */ -#ifdef TTY_PGRP - /* YYY: Is this needed? (see also YYY above) - if (Flag(FMONITOR) && !(flags&(XXCOM|XBGND))) - tcsetpgrp(tty_fd, j->pgrp); - */ -#endif /* TTY_PGRP */ - j_startjob(j); -#ifdef KSH - 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); - if (Flag(FTALKING)) { - shf_fprintf(shl_out, "[%d]", j->job); - for (p = j->proc_list; p; p = p->next) - shf_fprintf(shl_out, " %d", p->pid); - shf_putchar('\n', shl_out); - shf_flush(shl_out); - } - } else - rv = j_waitj(j, JW_NONE, "jw:last proc"); - } - -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - - return rv; -} - -/* start the last job: only used for `command` jobs */ -void -startlast() -{ -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - if (last_job) { /* no need to report error - waitlast() will do it */ - /* ensure it isn't removed by check_job() */ - last_job->flags |= JF_WAITING; - j_startjob(last_job); - } -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ -} - -/* wait for last job: only used for `command` jobs */ -int -waitlast() -{ - int rv; - Job *j; -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - j = last_job; - if (!j || !(j->flags & JF_STARTED)) { - if (!j) - warningf(TRUE, "waitlast: no last job"); - else - internal_errorf(0, "waitlast: not started"); -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - return 125; /* not so arbitrary, non-zero value */ - } - - rv = j_waitj(j, JW_NONE, "jw:waitlast"); - -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - - return rv; -} - -/* wait for child, interruptable. */ -int -waitfor(cp, sigp) - const char *cp; - int *sigp; -{ - int rv; - Job *j; - int ecode; - int flags = JW_INTERRUPT|JW_ASYNCNOTIFY; -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - *sigp = 0; - - if (cp == (char *) 0) { - /* wait for an unspecified job - always returns 0, so - * don't have to worry about exited/signaled jobs - */ - for (j = job_list; j; j = j->next) - /* at&t ksh will wait for stopped jobs - we don't */ - if (j->ppid == procpid && j->state == PRUNNING) - break; - if (!j) { -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - return -1; - } - } else if ((j = j_lookup(cp, &ecode))) { - /* don't report normal job completion */ - flags &= ~JW_ASYNCNOTIFY; - if (j->ppid != procpid) { -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - return -1; - } - } else { -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - if (ecode == JL_NOSUCH) - return -1; - bi_errorf("%s: %s", cp, lookup_msgs[ecode]); - } - - /* at&t ksh will wait for stopped jobs - we don't */ - rv = j_waitj(j, flags, "jw:waitfor"); - -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - - if (rv < 0) /* we were interrupted */ - *sigp = 128 + -rv; - - return rv; -} - -/* kill (built-in) a job */ -int -j_kill(cp, sig) - const char *cp; - int sig; -{ - Job *j; - Proc *p; - int rv = 0; - int ecode; -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - if ((j = j_lookup(cp, &ecode)) == (Job *) 0) { -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - bi_errorf("%s: %s", cp, lookup_msgs[ecode]); - return 1; - } - - if (j->pgrp == 0) { /* started when !Flag(FMONITOR) */ - for (p=j->proc_list; p != (Proc *) 0; p = p->next) - if (kill(p->pid, sig) < 0) { - bi_errorf("%s: %s", cp, strerror(errno)); - rv = 1; - } - } else { -#ifdef JOBS - if (j->state == PSTOPPED && (sig == SIGTERM || sig == SIGHUP)) - (void) killpg(j->pgrp, SIGCONT); -#endif /* JOBS */ - if (killpg(j->pgrp, sig) < 0) { - bi_errorf("%s: %s", cp, strerror(errno)); - rv = 1; - } - } - -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - - return rv; -} - -#ifdef JOBS -/* fg and bg built-ins: called only if Flag(FMONITOR) set */ -int -j_resume(cp, bg) - const char *cp; - int bg; -{ - Job *j; - Proc *p; - int ecode; - int running; - int rv = 0; - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); - - if ((j = j_lookup(cp, &ecode)) == (Job *) 0) { - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); - bi_errorf("%s: %s", cp, lookup_msgs[ecode]); - return 1; - } - - if (j->pgrp == 0) { - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); - bi_errorf("job not job-controlled"); - return 1; - } - - if (bg) - shprintf("[%d] ", j->job); - - running = 0; - for (p = j->proc_list; p != (Proc *) 0; p = p->next) { - if (p->state == PSTOPPED) { - p->state = PRUNNING; - WSTATUS(p->status) = 0; - running = 1; - } - shprintf("%s%s", p->command, p->next ? "| " : null); - } - shprintf(newline); - shf_flush(shl_stdout); - if (running) - j->state = PRUNNING; - - put_job(j, PJ_PAST_STOPPED); - if (bg) - j_set_async(j); - else { -# ifdef TTY_PGRP - /* attach tty to job */ - if (j->state == PRUNNING) { - if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) { - set_tty(tty_fd, &j->ttystate, TF_NONE); - } - if (ttypgrp_ok && tcsetpgrp(tty_fd, j->pgrp) < 0) { - if (j->flags & JF_SAVEDTTY) - set_tty(tty_fd, &tty_state, TF_NONE); - sigprocmask(SIG_SETMASK, &omask, - (sigset_t *) 0); - bi_errorf("1st tcsetpgrp(%d, %d) failed: %s", - tty_fd, (int) j->pgrp, strerror(errno)); - return 1; - } - } -# endif /* TTY_PGRP */ - j->flags |= JF_FG; - j->flags &= ~JF_KNOWN; - if (j == async_job) - async_job = (Job *) 0; - } - - if (j->state == PRUNNING && killpg(j->pgrp, SIGCONT) < 0) { - int err = errno; - - if (!bg) { - j->flags &= ~JF_FG; -# ifdef TTY_PGRP - if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) - set_tty(tty_fd, &tty_state, TF_NONE); - if (ttypgrp_ok && tcsetpgrp(tty_fd, our_pgrp) < 0) { - warningf(TRUE, - "fg: 2nd tcsetpgrp(%d, %d) failed: %s", - tty_fd, (int) our_pgrp, - strerror(errno)); - } -# endif /* TTY_PGRP */ - } - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); - bi_errorf("cannot continue job %s: %s", - cp, strerror(err)); - return 1; - } - if (!bg) { -# ifdef TTY_PGRP - if (ttypgrp_ok) { - j->flags &= ~JF_SAVEDTTY; - } -# endif /* TTY_PGRP */ - rv = j_waitj(j, JW_NONE, "jw:resume"); - } - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); - return rv; -} -#endif /* JOBS */ - -/* are there any running or stopped jobs ? */ -int -j_stopped_running() -{ - Job *j; - int which = 0; - - for (j = job_list; j != (Job *) 0; j = j->next) { -#ifdef JOBS - if (j->ppid == procpid && j->state == PSTOPPED) - which |= 1; -#endif /* JOBS */ - if (Flag(FLOGIN) && !Flag(FNOHUP) && procpid == kshpid - && j->ppid == procpid && j->state == PRUNNING) - which |= 2; - } - if (which) { - shellf("You have %s%s%s jobs\n", - which & 1 ? "stopped" : "", - which == 3 ? " and " : "", - which & 2 ? "running" : ""); - return 1; - } - - return 0; -} - -/* list jobs for jobs built-in */ -int -j_jobs(cp, slp, nflag) - const char *cp; - int slp; /* 0: short, 1: long, 2: pgrp */ - int nflag; -{ - Job *j, *tmp; - int how; - int zflag = 0; -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - if (nflag < 0) { /* kludge: print zombies */ - nflag = 0; - zflag = 1; - } - if (cp) { - int ecode; - - if ((j = j_lookup(cp, &ecode)) == (Job *) 0) { -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - bi_errorf("%s: %s", cp, lookup_msgs[ecode]); - return 1; - } - } else - j = job_list; - how = slp == 0 ? JP_MEDIUM : (slp == 1 ? JP_LONG : JP_PGRP); - for (; j; j = j->next) { - if ((!(j->flags & JF_ZOMBIE) || zflag) - && (!nflag || (j->flags & JF_CHANGED))) - { - j_print(j, how, shl_stdout); - if (j->state == PEXITED || j->state == PSIGNALLED) - j->flags |= JF_REMOVE; - } - if (cp) - break; - } - /* Remove jobs after printing so there won't be multiple + or - jobs */ - for (j = job_list; j; j = tmp) { - tmp = j->next; - if (j->flags & JF_REMOVE) - remove_job(j, "jobs"); - } -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - return 0; -} - -/* list jobs for top-level notification */ -void -j_notify() -{ - Job *j, *tmp; -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - for (j = job_list; j; j = j->next) { -#ifdef JOBS - if (Flag(FMONITOR) && (j->flags & JF_CHANGED)) - j_print(j, JP_MEDIUM, shl_out); -#endif /* JOBS */ - /* Remove job after doing reports so there aren't - * multiple +/- jobs. - */ - if (j->state == PEXITED || j->state == PSIGNALLED) - j->flags |= JF_REMOVE; - } - for (j = job_list; j; j = tmp) { - tmp = j->next; - if (j->flags & JF_REMOVE) - remove_job(j, "notify"); - } - shf_flush(shl_out); -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ -} - -/* Return pid of last process in last asynchornous job */ -pid_t -j_async() -{ -#ifdef JOB_SIGS - sigset_t omask; - - sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); -#endif /* JOB_SIGS */ - - if (async_job) - async_job->flags |= JF_KNOWN; - -#ifdef JOB_SIGS - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); -#endif /* JOB_SIGS */ - - return async_pid; -} - -/* Make j the last async process - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -j_set_async(j) - Job *j; -{ - Job *jl, *oldest; - - if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE) - remove_job(async_job, "async"); - if (!(j->flags & JF_STARTED)) { - internal_errorf(0, "j_async: job not started"); - return; - } - async_job = j; - async_pid = j->last_proc->pid; - while (nzombie > child_max) { - oldest = (Job *) 0; - for (jl = job_list; jl; jl = jl->next) - if (jl != async_job && (jl->flags & JF_ZOMBIE) - && (!oldest || jl->age < oldest->age)) - oldest = jl; - if (!oldest) { - /* XXX debugging */ - if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) { - internal_errorf(0, "j_async: bad nzombie (%d)", nzombie); - nzombie = 0; - } - break; - } - remove_job(oldest, "zombie"); - } -} - -/* Start a job: set STARTED, check for held signals and set j->last_proc - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -j_startjob(j) - Job *j; -{ - Proc *p; - - j->flags |= JF_STARTED; - for (p = j->proc_list; p->next; p = p->next) - ; - j->last_proc = p; - -#ifdef NEED_PGRP_SYNC - if (j_sync_open) { - j_sync_open = 0; - closepipe(j_sync_pipe); - } -#endif /* NEED_PGRP_SYNC */ -#ifdef JOB_SIGS - if (held_sigchld) { - held_sigchld = 0; - /* Don't call j_sigchld() as it may remove job... */ - kill(procpid, SIGCHLD); - } -#endif /* JOB_SIGS */ -} - -/* - * wait for job to complete or change state - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static int -j_waitj(j, flags, where) - Job *j; - int flags; /* see JW_* */ - const char *where; -{ - int rv; - - /* - * No auto-notify on the job we are waiting on. - */ - j->flags |= JF_WAITING; - if (flags & JW_ASYNCNOTIFY) - j->flags |= JF_W_ASYNCNOTIFY; - - if (!Flag(FMONITOR)) - flags |= JW_STOPPEDWAIT; - - while ((volatile int) j->state == PRUNNING - || ((flags & JW_STOPPEDWAIT) - && (volatile int) j->state == PSTOPPED)) - { -#ifdef JOB_SIGS - sigsuspend(&sm_default); -#else /* JOB_SIGS */ - j_sigchld(SIGCHLD); -#endif /* JOB_SIGS */ - if (fatal_trap) { - int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY); - j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); - runtraps(TF_FATAL); - j->flags |= oldf; /* not reached... */ - } - if ((flags & JW_INTERRUPT) && (rv = trap_pending())) { - j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); - return -rv; - } - } - j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); - - if (j->flags & JF_FG) { - WAIT_T status; - - j->flags &= ~JF_FG; -#ifdef TTY_PGRP - if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) { - if (tcsetpgrp(tty_fd, our_pgrp) < 0) { - warningf(TRUE, - "j_waitj: tcsetpgrp(%d, %d) failed: %s", - tty_fd, (int) our_pgrp, - strerror(errno)); - } - if (j->state == PSTOPPED) { - j->flags |= JF_SAVEDTTY; - get_tty(tty_fd, &j->ttystate); - } - } -#endif /* TTY_PGRP */ - if (tty_fd >= 0) { - /* Only restore tty settings if job was originally - * started in the foreground. Problems can be - * caused by things like `more foobar &' which will - * typically get and save the shell's vi/emacs tty - * settings before setting up the tty for itself; - * when more exits, it restores the `original' - * settings, and things go down hill from there... - */ - if (j->state == PEXITED && j->status == 0 - && (j->flags & JF_USETTYMODE)) - { - get_tty(tty_fd, &tty_state); - } else { - set_tty(tty_fd, &tty_state, - (j->state == PEXITED) ? 0 : TF_MIPSKLUDGE); - /* Don't use tty mode if job is stopped and - * later restarted and exits. Consider - * the sequence: - * vi foo (stopped) - * ... - * stty something - * ... - * fg (vi; ZZ) - * mode should be that of the stty, not what - * was before the vi started. - */ - if (j->state == PSTOPPED) - j->flags &= ~JF_USETTYMODE; - } - } -#ifdef JOBS - /* If it looks like user hit ^C to kill a job, pretend we got - * one too to break out of for loops, etc. (at&t ksh does this - * even when not monitoring, but this doesn't make sense since - * a tty generated ^C goes to the whole process group) - */ - status = j->last_proc->status; - if (Flag(FMONITOR) && j->state == PSIGNALLED - && WIFSIGNALED(status) - && (sigtraps[WTERMSIG(status)].flags & TF_TTY_INTR)) - trapsig(WTERMSIG(status)); -#endif /* JOBS */ - } - - j_usrtime = j->usrtime; - j_systime = j->systime; - rv = j->status; - - if (!(flags & JW_ASYNCNOTIFY) - && (!Flag(FMONITOR) || j->state != PSTOPPED)) - { - j_print(j, JP_SHORT, shl_out); - shf_flush(shl_out); - } - if (j->state != PSTOPPED - && (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY))) - remove_job(j, where); - - return rv; -} - -/* SIGCHLD handler to reap children and update job states - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static RETSIGTYPE -j_sigchld(sig) - int sig; -{ - int errno_ = errno; - Job *j; - Proc UNINITIALIZED(*p); - int pid; - WAIT_T status; - struct tms t0, t1; - -#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 - * before all the processes in a pipe line are started (so the - * setpgid() won't fail) - */ - for (j = job_list; j; j = j->next) - if (j->ppid == procpid && !(j->flags & JF_STARTED)) { - held_sigchld = 1; - return RETSIGVAL; - } -#endif /* JOB_SIGS */ - - ksh_times(&t0); - do { -#ifdef JOB_SIGS - pid = ksh_waitpid(-1, &status, (WNOHANG|WUNTRACED)); -#else /* JOB_SIGS */ - pid = wait(&status); -#endif /* JOB_SIGS */ - - if (pid <= 0) /* return if would block (0) ... */ - break; /* ... or no children or interrupted (-1) */ - - ksh_times(&t1); - - /* find job and process structures for this pid */ - for (j = job_list; j != (Job *) 0; j = j->next) - for (p = j->proc_list; p != (Proc *) 0; p = p->next) - if (p->pid == pid) - goto found; -found: - if (j == (Job *) 0) { - /* Can occur if process has kids, then execs shell - warningf(TRUE, "bad process waited for (pid = %d)", - pid); - */ - t0 = t1; - continue; - } - - j->usrtime += t1.tms_cutime - t0.tms_cutime; - j->systime += t1.tms_cstime - t0.tms_cstime; - t0 = t1; - p->status = status; -#ifdef JOBS - if (WIFSTOPPED(status)) - p->state = PSTOPPED; - else -#endif /* JOBS */ - if (WIFSIGNALED(status)) - p->state = PSIGNALLED; - else - p->state = PEXITED; - - check_job(j); /* check to see if entire job is done */ - } -#ifdef JOB_SIGS - while (1); -#else /* JOB_SIGS */ - while (0); -#endif /* JOB_SIGS */ - - errno = errno_; - - return RETSIGVAL; -} - -/* - * Called only when a process in j has exited/stopped (ie, called only - * from j_sigchld()). If no processes are running, the job status - * and state are updated, asynchronous job notification is done and, - * if unneeded, the job is removed. - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -check_job(j) - Job *j; -{ - int jstate; - Proc *p; - - /* XXX debugging (nasty - interrupt routine using shl_out) */ - if (!(j->flags & JF_STARTED)) { - internal_errorf(0, "check_job: job started (flags 0x%x)", - j->flags); - return; - } - - jstate = PRUNNING; - for (p=j->proc_list; p != (Proc *) 0; p = p->next) { - if (p->state == PRUNNING) - return; /* some processes still running */ - if (p->state > jstate) - jstate = p->state; - } - j->state = jstate; - - switch (j->last_proc->state) { - case PEXITED: - j->status = WEXITSTATUS(j->last_proc->status); - break; - case PSIGNALLED: - j->status = 128 + WTERMSIG(j->last_proc->status); - break; - default: - j->status = 0; - break; - } - -#ifdef KSH - /* Note when co-process dies: can't be done in j_wait() nor - * remove_job() since neither may be called for non-interactive - * shells. - */ - 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; -#ifdef JOBS - if (Flag(FMONITOR) && !(j->flags & JF_XXCOM)) { - /* Only put stopped jobs at the front to avoid confusing - * the user (don't want finished jobs effecting %+ or %-) - */ - if (j->state == PSTOPPED) - put_job(j, PJ_ON_FRONT); - if (Flag(FNOTIFY) - && (j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY)) != JF_WAITING) - { - /* Look for the real file descriptor 2 */ - { - struct env *ep; - int fd = 2; - - for (ep = e; ep; ep = ep->oenv) - if (ep->savefd && ep->savefd[2]) - fd = ep->savefd[2]; - shf_reopen(fd, SHF_WR, shl_j); - } - /* Can't call j_notify() as it removes jobs. The job - * must stay in the job list as j_waitj() may be - * running with this job. - */ - j_print(j, JP_MEDIUM, shl_j); - shf_flush(shl_j); - if (!(j->flags & JF_WAITING) && j->state != PSTOPPED) - remove_job(j, "notify"); - } - } -#endif /* JOBS */ - if (!Flag(FMONITOR) && !(j->flags & (JF_WAITING|JF_FG)) - && j->state != PSTOPPED) - { - if (j == async_job || (j->flags & JF_KNOWN)) { - j->flags |= JF_ZOMBIE; - j->job = -1; - nzombie++; - } else - remove_job(j, "checkjob"); - } -} - -/* - * Print job status in either short, medium or long format. - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -j_print(j, how, shf) - Job *j; - int how; - struct shf *shf; -{ - Proc *p; - int state; - WAIT_T status; - int coredumped; - char jobchar = ' '; - char buf[64]; - const char *filler; - int output = 0; - - if (how == JP_PGRP) { - /* POSIX doesn't say what to do it there is no process - * group leader (ie, !FMONITOR). We arbitrarily return - * last pid (which is what $! returns). - */ - shf_fprintf(shf, "%d\n", j->pgrp ? j->pgrp - : (j->last_proc ? j->last_proc->pid : 0)); - return; - } - j->flags &= ~JF_CHANGED; - filler = j->job > 10 ? "\n " : "\n "; - if (j == job_list) - jobchar = '+'; - else if (j == job_list->next) - jobchar = '-'; - - for (p = j->proc_list; p != (Proc *) 0;) { - coredumped = 0; - switch (p->state) { - case PRUNNING: - strcpy(buf, "Running"); - break; - case PSTOPPED: - strcpy(buf, sigtraps[WSTOPSIG(p->status)].mess); - break; - case PEXITED: - if (how == JP_SHORT) - buf[0] = '\0'; - else if (WEXITSTATUS(p->status) == 0) - strcpy(buf, "Done"); - else - shf_snprintf(buf, sizeof(buf), "Done (%d)", - WEXITSTATUS(p->status)); - break; - case PSIGNALLED: - if (WIFCORED(p->status)) - coredumped = 1; - /* kludge for not reporting `normal termination signals' - * (ie, SIGINT, SIGPIPE) - */ - if (how == JP_SHORT && !coredumped - && (WTERMSIG(p->status) == SIGINT - || WTERMSIG(p->status) == SIGPIPE)) { - buf[0] = '\0'; - } else - strcpy(buf, sigtraps[WTERMSIG(p->status)].mess); - break; - } - - if (how != JP_SHORT) - if (p == j->proc_list) - shf_fprintf(shf, "[%d] %c ", j->job, jobchar); - else - shf_fprintf(shf, "%s", filler); - - if (how == JP_LONG) - shf_fprintf(shf, "%5d ", p->pid); - - if (how == JP_SHORT) { - if (buf[0]) { - output = 1; - shf_fprintf(shf, "%s%s ", - buf, coredumped ? " (core dumped)" : null); - } - } else { - output = 1; - shf_fprintf(shf, "%-20s %s%s%s", buf, p->command, - p->next ? "|" : null, - coredumped ? " (core dumped)" : null); - } - - state = p->state; - status = p->status; - p = p->next; - while (p && p->state == state - && WSTATUS(p->status) == WSTATUS(status)) - { - if (how == JP_LONG) - shf_fprintf(shf, "%s%5d %-20s %s%s", filler, p->pid, - space, p->command, p->next ? "|" : null); - else if (how == JP_MEDIUM) - shf_fprintf(shf, " %s%s", p->command, - p->next ? "|" : null); - p = p->next; - } - } - if (output) - shf_fprintf(shf, newline); -} - -/* Convert % sequence to job - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static Job * -j_lookup(cp, ecodep) - const char *cp; - int *ecodep; -{ - Job *j, *last_match; - Proc *p; - int len, job = 0; - - if (digit(*cp)) { - job = atoi(cp); - /* Look for last_proc->pid (what $! returns) first... */ - for (j = job_list; j != (Job *) 0; j = j->next) - if (j->last_proc && j->last_proc->pid == job) - return j; - /* ...then look for process group (this is non-POSIX), - * but should not break anything (so FPOSIX isn't used). - */ - for (j = job_list; j != (Job *) 0; j = j->next) - if (j->pgrp && j->pgrp == job) - return j; - if (ecodep) - *ecodep = JL_NOSUCH; - return (Job *) 0; - } - if (*cp != '%') { - if (ecodep) - *ecodep = JL_INVALID; - return (Job *) 0; - } - switch (*++cp) { - case '\0': /* non-standard */ - case '+': - case '%': - if (job_list != (Job *) 0) - return job_list; - break; - - case '-': - if (job_list != (Job *) 0 && job_list->next) - return job_list->next; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - job = atoi(cp); - for (j = job_list; j != (Job *) 0; j = j->next) - if (j->job == job) - return j; - break; - - case '?': /* %?string */ - last_match = (Job *) 0; - for (j = job_list; j != (Job *) 0; j = j->next) - for (p = j->proc_list; p != (Proc *) 0; p = p->next) - if (strstr(p->command, cp+1) != (char *) 0) { - if (last_match) { - if (ecodep) - *ecodep = JL_AMBIG; - return (Job *) 0; - } - last_match = j; - } - if (last_match) - return last_match; - break; - - default: /* %string */ - len = strlen(cp); - last_match = (Job *) 0; - for (j = job_list; j != (Job *) 0; j = j->next) - if (strncmp(cp, j->proc_list->command, len) == 0) { - if (last_match) { - if (ecodep) - *ecodep = JL_AMBIG; - return (Job *) 0; - } - last_match = j; - } - if (last_match) - return last_match; - break; - } - if (ecodep) - *ecodep = JL_NOSUCH; - return (Job *) 0; -} - -static Job *free_jobs; -static Proc *free_procs; - -/* allocate a new job and fill in the job number. - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static Job * -new_job() -{ - int i; - Job *newj, *j; - - if (free_jobs != (Job *) 0) { - newj = free_jobs; - free_jobs = free_jobs->next; - } else - newj = (Job *) alloc(sizeof(Job), APERM); - - /* brute force method */ - for (i = 1; ; i++) { - for (j = job_list; j && j->job != i; j = j->next) - ; - if (j == (Job *) 0) - break; - } - newj->job = i; - - return newj; -} - -/* Allocate new process strut - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static Proc * -new_proc() -{ - Proc *p; - - if (free_procs != (Proc *) 0) { - p = free_procs; - free_procs = free_procs->next; - } else - p = (Proc *) alloc(sizeof(Proc), APERM); - - return p; -} - -/* Take job out of job_list and put old structures into free list. - * Keeps nzombies, last_job and async_job up to date. - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -remove_job(j, where) - Job *j; - const char *where; -{ - Proc *p, *tmp; - Job **prev, *curr; - - prev = &job_list; - curr = *prev; - for (; curr != (Job *) 0 && curr != j; prev = &curr->next, curr = *prev) - ; - if (curr != j) { - internal_errorf(0, "remove_job: job not found (%s)", where); - return; - } - *prev = curr->next; - - /* free up proc structures */ - for (p = j->proc_list; p != (Proc *) 0; ) { - tmp = p; - p = p->next; - tmp->next = free_procs; - free_procs = tmp; - } - - if ((j->flags & JF_ZOMBIE) && j->ppid == procpid) - --nzombie; - j->next = free_jobs; - free_jobs = j; - - if (j == last_job) - last_job = (Job *) 0; - if (j == async_job) - async_job = (Job *) 0; -} - -/* put j in a particular location (taking it out job_list if it is there - * already) - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -put_job(j, where) - Job *j; - int where; -{ - Job **prev, *curr; - - /* Remove job from list (if there) */ - prev = &job_list; - curr = job_list; - for (; curr && curr != j; prev = &curr->next, curr = *prev) - ; - if (curr == j) - *prev = curr->next; - - switch (where) { - case PJ_ON_FRONT: - j->next = job_list; - job_list = j; - break; - - case PJ_PAST_STOPPED: - prev = &job_list; - curr = job_list; - for (; curr && curr->state == PSTOPPED; prev = &curr->next, - curr = *prev) - ; - j->next = curr; - *prev = j; - break; - } -} - -/* nuke a job (called when unable to start full job). - * - * If jobs are compiled in then this routine expects sigchld to be blocked. - */ -static void -kill_job(j) - Job *j; -{ - Proc *p; - - for (p = j->proc_list; p != (Proc *) 0; p = p->next) - if (p->pid != 0) - (void) kill(p->pid, SIGKILL); -} - -/* put a more useful name on a process than snptreef does (in certain cases) */ -static void -fill_command(c, len, t) - char *c; - int len; - struct op *t; -{ - int alen; - char **ap; - - if (t->type == TEXEC || t->type == TCOM) { - if (t->type == TCOM) - ap = eval(t->args, DOBLANK|DONTRUNCOMMAND); - else - ap = t->args; - --len; /* save room for the null */ - while (len > 0 && *ap != (char *) 0) { - alen = strlen(*ap); - if (alen > len) - alen = len; - memcpy(c, *ap, alen); - c += alen; - len -= alen; - if (len > 0) { - *c++ = ' '; len--; - } - ap++; - } - *c = '\0'; - } else - snptreef(c, len, "%T", t); -} diff --git a/bin/pdksh/ksh.1tbl b/bin/pdksh/ksh.1tbl deleted file mode 100644 index 651f25fd765..00000000000 --- a/bin/pdksh/ksh.1tbl +++ /dev/null @@ -1,3298 +0,0 @@ -'\" t -.\" $OpenBSD: ksh.1tbl,v 1.3 1996/11/21 08:18:19 downsj Exp $ -.\"{{{}}} -.\"{{{ Notes about man page -.\" - use the pseudo-macros .sh( and .sh) to begin and end sh-specific -.\" text and .ksh( and .ksh) for ksh specific text. -.\" - put i.e., e.g. and etc. in italics -.\"}}} -.\"{{{ To do -.\" todo: Things not covered that should be: -.\" - distinguish (POSIX) special built-in's, (POSIX) regular built-in's, -.\" and sh/ksh weirdo built-in's (put S,R,X superscripts after command -.\" name in built-in commands section?) -.\" - need to be consistent about notation for `See section-name', ` -.\" See description of foobar command', `See section section-name', etc. -.\" - need to use the term `external command' meaning `a command that is -.\" executed using execve(2)' (as opposed to a built-in command or -.\" function) for more clear description. -.\"}}} -.\"{{{ Title -.TH KSH 1 "August 19, 1996" "" "User commands" -.\"}}} -.\"{{{ Name -.SH NAME -ksh \- Public domain Korn shell -.\"}}} -.\"{{{ Synopsis -.SH SYNOPSIS -.ad l -\fBksh\fP -[\fB\(+-abCefhikmnprsuvxX\fP] [\fB\(+-o\fP \fIoption\fP] [ [ \fB\-c\fP \fIcommand-string\fP [\fIcommand-name\fP] | \fB\-s\fP | \fIfile\fP ] [\fIargument\fP ...] ] -.ad b -.\"}}} -.\"{{{ Description -.SH DESCRIPTION -\fBksh\fP is a command interpreter that is intended for both -interactive and shell script use. Its command language is a superset -of the \fIsh\fP(1) shell language. -.\"{{{ Shell Startup -.SS "Shell Startup" -The following options can be specified only on the command line: -.IP "\fB\-c\fP \fIcommand-string\fP" -the shell executes the command(s) contained in \fIcommand-string\fP -.IP \fB\-i\fP -interactive mode \(em see below -.IP \fB\-l\fP -login shell \(em see below -interactive mode \(em see below -.IP \fB\-s\fP -the shell reads commands from standard input; all non-option arguments -are positional parameters -.IP \fB\-r\fP -restricted mode \(em see below -.PP -In addition to the above, the options described in the \fBset\fP built-in -command can also be used on the command line. -.PP -If neither the \fB\-c\fP nor the \fB\-s\fP options are specified, the -first non-option argument specifies the name of a file the shell reads -commands from; if there are no non-option arguments, the shell reads -commands from standard input. -The name of the shell (\fIi.e.\fP, the contents of the \fB$0\fP) parameter -is determined as follows: if the \fB\-c\fP option is used and there is -a non-option argument, it is used as the name; if commands are being -read from a file, the file is used as the name; otherwise the name -the shell was called with (\fIi.e.\fP, argv[0]) is used. -.PP -A shell is \fBinteractive\fP if the \fB\-i\fP option is used or -if both standard input and standard error are attached to a tty. -An interactive shell has job control enabled (if available), -ignores the INT, QUIT and TERM signals, and prints prompts before -reading input (see \fBPS1\fP and \fBPS2\fP parameters). -For non-interactive shells, the \fBtrackall\fP option is on by default -(see \fBset\fP command below). -.PP -A shell is \fBrestricted\fP if the \fB\-r\fP option is used or if either -the basename of the name the shell is invoked with or the \fBSHELL\fP -parameter match the pattern *r*sh (\fIe.g.\fP, rsh, rksh, rpdksh, \fIetc.\fP). -The following restrictions come into effect after the shell processes -any profile and \fB$ENV\fP files: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -the \fBcd\fP command is disabled -.IP \ \ \(bu -the \fBSHELL\fP, \fBENV\fP and \fBPATH\fP parameters can't be changed -.IP \ \ \(bu -command names can't be specified with absolute or relative paths -.IP \ \ \(bu -the \fB\-p\fP option of the \fBcommand\fP built-in can't be used -.IP \ \ \(bu -redirections that create files can't be used (\fIi.e.\fP, \fB>\fP, -\fB>|\fP, \fB>>\fP, \fB<>\fP) -.nr PD \n(P2 -.PP -A shell is \fBprivileged\fP if the \fB\-p\fP option is used or if -the real user-id or group-id does not match the effective user-id -or group-id (see \fIgetuid\fP(2), \fIgetgid\fP(2)). -A privileged shell does not process $HOME/.profile nor the \fBENV\fP -parameter (see below), instead the file /etc/suid_profile is processed. -Clearing the privileged option causes the shell to set its effective -user-id (group-id) to its real user-id (group-id). -.PP -If the basename of the name the shell is called with (\fIi.e.\fP, argv[0]) -starts with \fB\-\fP or if the \fB\-l\fP option is used, the shell is assumed -to be a login shell and the shell reads and executes the contents of -\fB/etc/profile\fP and \fB$HOME/.profile\fP if they exist and are readable. -.PP -If the \fBENV\fP parameter is set when the shell starts (or, in the -case of login shells, after any profiles are processed), its value -is subjected to parameter, command, arithmetic and tilde substitution and -the resulting file (if any) is read and executed. -If \fBENV\fP parameter is not set (and not null) and pdksh was compiled -with the \fBDEFAULT_ENV\fP macro defined, the file named in that macro -is included (after the above mentioned substitutions have been performed). -.PP -The exit status of the shell is 127 if the command file specified -on the command line could not be opened, or non-zero if a fatal syntax -error occurred during the execution of a script. -In the absence of fatal errors, the exit status is that of the last -command executed, or zero, if no command is executed. -.\"}}} -.\"{{{ Command Syntax -.SS "Command Syntax" -.\"{{{ words and tokens -The shell begins parsing its input by breaking it into \fIword\fPs. -Words, which are sequences of characters, are delimited by unquoted -\fIwhite-space\fP characters (space, tab and newline) or \fImeta-characters\fP -(\fB<\fP, \fB>\fP, \fB|\fP, \fB;\fP, \fB&\fP, \fB(\fP and \fB)\fP). -Aside from delimiting words, spaces and tabs are ignored, while -newlines usually delimit commands. -The meta-characters are used in building the following tokens: -\fB<\fP, \fB<&\fP, \fB<<\fP, \fB>\fP, \fB>&\fP, \fB>>\fP, \fIetc.\fP are -used to specify redirections (see Input/Output Redirection below); -\fB|\fP is used to create pipelines; -\fB|&\fP is used to create co-processes (see Co-Processes below); -\fB;\fP is used to separate commands; -\fB&\fP is used to create asynchronous pipelines; -\fB&&\fP and \fB||\fP are used to specify conditional execution; -\fB;;\fP is used in \fBcase\fP statements; -\fB((\fP .. \fB))\fP are used in arithmetic expressions; -and lastly, -\fB(\fP .. \fB)\fP are used to create subshells. -.PP -White-space and meta-characters can be quoted individually using -backslash (\fB\e\fP), or in groups using double (\fB"\fP) or single (\fB'\fP) -quotes. -Note that the following characters are also treated specially by the shell and -must be quoted if they are to represent themselves: -\fB\e\fP, \fB"\fP, \fB'\fP, \fB#\fP, \fB$\fP, \fB`\fP, \fB~\fP, \fB{\fP, -\fB}\fP, \fB*\fP, \fB?\fP and \fB[\fP. -The first three of these are the above mentioned quoting characters -(see Quoting below); -\fB#\fP, if used at the beginning of a word, introduces a comment \(em everything -after the \fB#\fP up to the nearest newline is ignored; -\fB$\fP is used to introduce parameter, command and arithmetic substitutions -(see Substitution below); -\fB`\fP introduces an old-style command substitution -(see Substitution below); -\fB~\fP begins a directory expansion (see Tilde Expansion below); -\fB{\fP and \fB}\fP delimit \fIcsh\fP(1) style alternations -(see Brace Expansion below); -and, finally, \fB*\fP, \fB?\fP and \fB[\fP are used in file name generation -(see File Name Patterns below). -.\"}}} -.\"{{{ simple-command -.PP -As words and tokens are parsed, the shell builds commands, of which -there are two basic types: \fIsimple-commands\fP, typically programs -that are executed, and \fIcompound-commands\fP, such as \fBfor\fP and -\fBif\fP statements, grouping constructs and function definitions. -.PP -A simple-command consists of some combination of parameter assignments (see -Parameters below), input/output redirections (see Input/Output Redirections -below), and command words; the only restriction is that parameter assignments -come before any command words. -The command words, if any, define the command that is to be executed and its -arguments. -The command may be a shell built-in command, a function or an \fIexternal -command\fP, \fIi.e.\fP, a separate executable file that is located using the -\fBPATH\fP parameter (see Command Execution below). -Note that all command constructs have an \fIexit status\fP: for external -commands, this is related to the status returned by \fIwait\fP(2) (if the -command could not be found, the exit status is 127, if it could not be -executed, the exit status is 126); -the exit status of other command constructs (built-in commands, functions, -compound-commands, pipelines, lists, \fIetc.\fP) are all well defined and are -described where the construct is described. -The exit status of a command consisting only of parameter assignments is that -of the last command substitution performed during the parameter assignment -or zero if there were no command substitutions. -.\"}}} -.\"{{{ pipeline -.PP -Commands can be chained together using the \fB|\fP token to -form \fIpipelines\fP, in which the standard output of each command but -the last is piped (see \fIpipe\fP(2)) to the standard input of the following -command. -The exit status of a pipeline is that of its last command. -A pipeline may be prefixed by the \fB!\fP reserved word which -causes the exit status of the pipeline to be logically -complemented: if the original status was 0 the complemented status will -be 1, and if the original status was not 0, then the complemented -status will be 0. -.\"}}} -.\"{{{ lists -.PP -\fILists\fP of commands can be created by separating pipelines by -any of the following tokens: \fB&&\fP, \fB||\fP, \fB&\fP, \fB|&\fP and \fB;\fP. -The first two are for conditional execution: \fIcmd1\fP \fB&&\fP \fIcmd2\fP -executes \fIcmd2\fP only if the exit status of \fIcmd1\fP is zero; -\fB||\fP is the opposite \(em \fIcmd2\fP is executed only if the exit status -of \fIcmd1\fP is non-zero. -\fB&&\fP and \fB||\fP have equal precedence which is higher than that of -\fB&\fP, \fB|&\fP and \fB;\fP, which also have equal precedence. -The \fB&\fP token causes the preceding command to be executed asynchronously, -that is, the shell starts the command, but does not wait for it to complete -(the shell does keep track of the status of asynchronous commands \(em see -Job Control below). -When an asynchronous command is started when job control is disabled -(\fIi.e.\fP, in most scripts), the command is started with signals INT -and QUIT ignored and with input redirected from /dev/null -(however, redirections specified in the asynchronous command have precedence). -The \fB|&\fP operator starts a \fIco-process\fP which is special kind of -asynchronous process (see Co-Processes below). -Note that a command must follow the \fB&&\fP and \fB||\fP operators, while -a command need not follow \fB&\fP, \fB|&\fP and \fB;\fP. -The exit status of a list is that of the last command executed, with the -exception of asynchronous lists, for which the exit status is 0. -.\"}}} -.\"{{{ compound-commands -.PP -Compound commands are created using the following reserved words \(em these -words are only recognized if they are unquoted and if they are used as -the first word of a command (\fIi.e.\fP, they can't be preceded by parameter -assignments or redirections): -.TS -center; -lfB lfB lfB lfB lfB . -case else function then ! -do esac if time [[ -done fi in until { -elif for select while } -.TE -\fBNote:\fP Some shells (but not this one) execute control structure commands -in a subshell when one or more of their file descriptors are redirected, so -any environment changes inside them may fail. -To be portable, the \fBexec\fP statement should be used instead to redirect -file descriptors before the control structure. -.PP -In the following compound command descriptions, command lists (denoted as -\fIlist\fP) that are followed by reserved words must end with a -semi-colon, a newline or a (syntactically correct) reserved word. -For example, -.RS -\fB{ echo foo; echo bar; }\fP -.br -\fB{ echo foo; echo bar<newline>}\fP -.br -\fB{ { echo foo; echo bar; } }\fP -.RE -are all valid, but -.RS -\fB{ echo foo; echo bar }\fP -.RE -is not. -.\"{{{ ( list ) -.IP "\fB(\fP \fIlist\fP \fB)\fP" -Execute \fIlist\fP in a subshell. There is no implicit way to pass -environment changes from a subshell back to its parent. -.\"}}} -.\"{{{ { list } -.IP "\fB{\fP \fIlist\fP \fB}\fP" -Compound construct; \fIlist\fP is executed, but not in a subshell. -Note that \fB{\fP and \fB}\fP are reserved words, not meta-characters. -.\"}}} -.\"{{{ case word in [ [ ( ] pattern [ | pattern ] ... ) list ;; ] ... esac -.IP "\fBcase\fP \fIword\fP \fBin\fP [ [\fB(\fP] \fIpattern\fP [\fB|\fP \fIpattern\fP] ... \fB)\fP \fIlist\fP \fB;;\fP ] ... \fBesac\fP" -The \fBcase\fP statement attempts to match \fIword\fP against the specified -\fIpattern\fPs; the \fIlist\fP associated with the first successfully matched -pattern is executed. Patterns used in \fBcase\fP statements are the same as -those used for file name patterns except that the restrictions regarding -\fB\&.\fP and \fB/\fP are dropped. Note that any unquoted space before and -after a pattern is stripped; any space with a pattern must be quoted. Both the -word and the patterns are subject to parameter, command, and arithmetic -substitution as well as tilde substitution. -For historical reasons, open and close braces may be used instead -of \fBin\fP and \fBesac\fP (\fIe.g.\fP, \fBcase $foo { *) echo bar; }\fP). -The exit status of a \fBcase\fP statement is that of the executed \fIlist\fP; -if no \fIlist\fP is executed, the exit status is zero. -.\"}}} -.\"{{{ for name [ in word ... term ] do list done -.IP "\fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP ... \fIterm\fP ] \fBdo\fP \fIlist\fP \fBdone\fP" -where \fIterm\fP is either a newline or a \fB;\fP. -For each \fIword\fP in the specified word list, the parameter \fIname\fP is -set to the word and \fIlist\fP is executed. If \fBin\fP is not used to -specify a word list, the positional parameters (\fB"$1"\fP, \fB"$2"\fP, -\fIetc.\fP) are used instead. -For historical reasons, open and close braces may be used instead -of \fBdo\fP and \fBdone\fP (\fIe.g.\fP, \fBfor i; { echo $i; }\fP). -The exit status of a \fBfor\fP statement is the last exit status -of \fIlist\fP; if \fIlist\fP is never executed, the exit status is zero. -.\"}}} -.\"{{{ if list then list [ elif list then list ] ... [ else list ] fi -.IP "\fBif\fP \fIlist\fP \fBthen\fP \fIlist\fP [\fBelif\fP \fIlist\fP \fBthen\fP \fIlist\fP] ... [\fBelse\fP \fIlist\fP] \fBfi\fP" -If the exit status of the first \fIlist\fP is zero, the second \fIlist\fP -is executed; otherwise the \fIlist\fP following the \fBelif\fP, if any, is -executed with similar consequences. If all the lists following the \fBif\fP -and \fBelif\fPs fail (\fIi.e.\fP, exit with non-zero status), the \fIlist\fP -following the \fBelse\fP is executed. -The exit status of an \fBif\fP statement is that -of non-conditional \fIlist\fP that is executed; if no non-conditional -\fIlist\fP is executed, the exit status is zero. -.\"}}} -.\"{{{ select name [ in word ... ] do list done -.IP "\fBselect\fP \fIname\fP [ \fBin\fP \fIword\fP ... \fIterm\fP ] \fBdo\fP \fIlist\fP \fBdone\fP" -where \fIterm\fP is either a newline or a \fB;\fP. -The \fBselect\fP statement provides an automatic method of presenting -the user with a menu and selecting from it. -An enumerated list of the specified \fIwords\fP is printed on standard -error, followed by a prompt (\fBPS3\fP, normally `\fB#? \fP'). -A number corresponding to one of the enumerated words is then read -from standard input, \fIname\fP is set to the selected word (or is -unset if the selection is not valid), \fBREPLY\fP -is set to what was read (leading/trailing space is stripped), -and \fIlist\fP is executed. -If a blank line (\fIi.e.\fP, zero or more \fBIFS\fP characters) is entered, -the menu is re-printed without executing \fIlist\fP. -When \fIlist\fP completes, the enumerated list is printed if \fBREPLY\fP -is null, the prompt is printed and so on. -This process is continues until an end-of-file is read, an interrupt is -received or a break statement is executed inside the loop. -If \fBin\fP \fIword\fP \fB\&...\fP is omitted, the positional parameters -are used (\fIi.e.\fP, \fB"$1"\fP, \fB"$2"\fP, \fIetc.\fP). -For historical reasons, open and close braces may be used instead -of \fBdo\fP and \fBdone\fP (\fIe.g.\fP, \fBselect i; { echo $i; }\fP). -The exit status of a \fBselect\fP statement is zero if a break statement -is used to exit the loop, non-zero otherwise. -.\"}}} -.\"{{{ until list do list done -.IP "\fBuntil\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP" -This works like \fBwhile\fP, except that the body is executed only while the -exit status of the first \fIlist\fP is non-zero. -.\"}}} -.\"{{{ while list do list done -.IP "\fBwhile\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP" -A \fBwhile\fP is a prechecked loop. Its body is executed as often -as the exit status of the first \fIlist\fP is zero. -The exit status of a \fBwhile\fP statement is the last exit status -of the \fIlist\fP in the body of the loop; if the body is not executed, -the exit status is zero. -.\"}}} -.\"{{{ function name { list } -.IP "\fBfunction\fP \fIname\fP \fB{\fP \fIlist\fP \fB}\fP" -Defines the function \fIname\fP. -See Functions below. -Note that redirections specified after a function definition are -performed whenever the function is executed, not when the function -definition is executed. -.\"}}} -.\"{{{ name () command -.IP "\fIname\fP \fB()\fP \fIcommand\fP" -Mostly the same as \fBfunction\fP. -See Functions below. -.\"}}} -.\"{{{ (( expression )) -.IP "\fB((\fP \fIexpression\fP \fB))\fP" -The arithmetic expression \fIexpression\fP is evaluated; -equivalent to \fBlet "\fP\fIexpression\fP\fB"\fP. -See Arithmetic Expressions and the \fBlet\fP command below. -.\"}}} -.\"{{{ [[ expression ]] -.IP "\fB[[\fP \fIexpression\fP \fB]]\fP" -Similar to the \fBtest\fP and \fB[\fP \&... \fB]\fP commands (described later), -with the following exceptions: -.RS -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -Field splitting and file name generation are not performed on -arguments. -.IP \ \ \(bu -The \fB\-a\fP (and) and \fB\-o\fP (or) operators are replaced with -\fB&&\fP and \fB||\fP, respectively. -.IP \ \ \(bu -Operators (\fIe.g.\fP, \fB\-f\fP, \fB=\fP, \fB!\fP, \fIetc.\fP) must be unquoted. -.IP \ \ \(bu -The second operand of \fB!=\fP and \fB=\fP -expressions are patterns (\fIe.g.\fP, the comparison in -.ce -\fB[[ foobar = f*r ]]\fP -succeeds). -.IP \ \ \(bu -There are two additional binary operators: \fB<\fP and \fB>\fP -which return true if their first string operand is less than, -or greater than, their second string operand, respectively. -.IP \ \ \(bu -The single argument form -of \fBtest\fP, which tests if the argument has non-zero length, is not valid -- explicit operators must be always be used, \fIe.g.\fP, instead of -.ce -\fB[\fP \fIstr\fP \fB]\fP -use -.ce -\fB[[ \-n \fP\fIstr\fP\fB ]]\fP -.IP \ \ \(bu -Parameter, command and arithmetic substitutions are performed as -expressions are evaluated and lazy expression evaluation is used for -the \fB&&\fP and \fB||\fP operators. -This means that in the statement -.ce -\fB[[ -r foo && $(< foo) = b*r ]]\fP -the \fB$(< foo)\fP is evaluated if and only if the file \fBfoo\fP exists -and is readable. -.nr PD \n(P2 -.RE -.\"}}} -.\"}}} -.\"}}} -.\"{{{ Quoting -.SS Quoting -Quoting is used to prevent the shell from treating characters or words -specially. -There are three methods of quoting: First, \fB\e\fP quotes -the following character, unless it is at the end of a line, in which -case both the \fB\e\fP and the newline are stripped. -Second, a single quote (\fB'\fP) quotes everything up to the next single -quote (this may span lines). -Third, a double quote (\fB"\fP) quotes all characters, -except \fB$\fP, \fB`\fP and \fB\e\fP, up to the next unquoted double quote. -\fB$\fP and \fB`\fP inside double quotes have their usual meaning (\fIi.e.\fP, -parameter, command or arithmetic substitution) except no field splitting -is carried out on the results of double-quoted substitutions. -If a \fB\e\fP inside a double-quoted string is followed by \fB\e\fP, \fB$\fP, -\fB`\fP or \fB"\fP, it is replaced by the second character; if it is -followed by a newline, both the \fB\e\fP and the newline are stripped; -otherwise, both the \fB\e\fP and the character following are unchanged. -.PP -Note: see POSIX Mode below for a special rule regarding sequences -of the form \fB"\fP...\fB`\fP...\fB\e"\fP...\fB`\fP..\fB"\fP. -.\"}}} -.\"{{{ Aliases -.SS "Aliases" -There are two types of aliases: normal command aliases and tracked -aliases. Command aliases are normally used as a short hand for a long -or often used command. The shell expands command aliases (\fIi.e.\fP, -substitutes the alias name for its value) when it reads the first word -of a command. An expanded alias is re-processed to check for more -aliases. If a command alias ends in a space or tab, the following word -is also checked for alias expansion. The alias expansion process stops -when a word that is not an alias is found, when a quoted word is found -or when an alias word that is currently being expanded is found. -.PP -The following command aliases are defined automatically by the shell: -.ft B -.RS -autoload='typeset \-fu' -.br -functions='typeset \-f' -.br -hash='alias \-t' -.br -history='fc \-l' -.br -integer='typeset \-i' -.br -local='typeset' -.br -login='exec login' -.br -newgrp='exec newgrp' -.br -nohup='nohup ' -.br -r='fc \-e \-' -.br -stop='kill \-STOP' -.br -suspend='kill \-STOP $$' -.br -type='whence \-v' -.RE -.ft P -.PP -Tracked aliases allow the shell to remember where it found a particular -command. The first time the shell does a path search for a command that -is marked as a tracked alias, it saves the full path of the command. -The next time the command is executed, the shell checks the saved path -to see that it is still valid, and if so, avoids repeating the path -search. Tracked aliases can be listed and created using \fBalias -\-t\fP. Note that changing the \fBPATH\fP parameter clears the saved -paths for all tracked aliases. If the \fBtrackall\fP option is set (\fIi.e.\fP, -\fBset \-o trackall\fP or \fBset \-h\fP), the shell tracks all -commands. This option is set automatically for non-interactive shells. -For interactive shells, only the following commands are automatically -tracked: \fBcat\fP, \fBcc\fP, \fBchmod\fP, \fBcp\fP, \fBdate\fP, \fBed\fP, -\fBemacs\fP, \fBgrep\fP, \fBls\fP, \fBmail\fP, \fBmake\fP, \fBmv\fP, -\fBpr\fP, \fBrm\fP, \fBsed\fP, \fBsh\fP, \fBvi\fP and \fBwho\fP. -.\"}}} -.\"{{{ Substitution -.SS "Substitution" -The first step the shell takes in executing a simple-command is to -perform substitutions on the words of the command. -There are three kinds of substitution: parameter, command and arithmetic. -Parameter substitutions, which are described in detail in the next section, -take the form \fB$name\fP or \fB${\fP...\fB}\fP; command substitutions take -the form \fB$(\fP\fIcommand\fP\fB)\fP or \fB`\fP\fIcommand\fP\fB`\fP; -and arithmetic substitutions take the form \fB$((\fP\fIexpression\fP\fB))\fP. -.PP -If a substitution appears outside of double quotes, the results of the -substitution are generally subject to word or field splitting according to -the current value of the \fBIFS\fP parameter. -The \fBIFS\fP parameter specifies a list of characters which -are used to break a string up into several words; -any characters from the set space, tab and newline that appear in the -IFS characters are called \fIIFS white space\fP. -Sequences of one or more IFS white space characters, in combination with -zero or one non-IFS white space characters delimit a field. -As a special case, leading and trailing IFS white space is stripped (\fIi.e.\fP, -no leading or trailing empty field is created by it); leading or trailing -non-IFS white space does create an empty field. -Example: if \fBIFS\fP is set to `<space>:', the sequence of characters -`<space>A<space>:<space><space>B::D' contains four fields: `A', `B', `' and `D'. -Note that if the \fBIFS\fP parameter is set to the null string, no -field splitting is done; if the parameter is unset, the default value -of space, tab and newline is used. -.PP -The results of substitution are, unless otherwise specified, also subject -to brace expansion and file name expansion (see the relevant sections -below). -.PP -A command substitution is replaced by the output generated by the specified -command, which is run in a subshell. -For \fB$(\fP\fIcommand\fP\fB)\fP substitutions, normal quoting rules -are used when \fIcommand\fP is parsed, however, for the -\fB`\fP\fIcommand\fP\fB`\fP form, a \fB\e\fP followed by any of -\fB$\fP, \fB`\fP or \fB\e\fP is stripped (a \fB\e\fP followed by any other -character is unchanged). -As a special case in command substitutions, a command of the form -\fB<\fP \fIfile\fP is interpreted to mean substitute the contents -of \fIfile\fP ($(< foo) has the same effect as $(cat foo), but it -is carried out more efficiently because no process is started). -.br -.\"todo: fix this( $(..) parenthesis counting). -NOTE: \fB$(\fP\fIcommand\fP\fB)\fP expressions are currently parsed by -finding the matching parenthesis, regardless of quoting. This will hopefully -be fixed soon. -.PP -Arithmetic substitutions are replaced by the value of the specified -expression. -For example, the command \fBecho $((2+3*4))\fP prints 14. -See Arithmetic Expressions for a description of an \fIexpression\fP. -.\"}}} -.\"{{{ Parameters -.SS "Parameters" -Parameters are shell variables; they can be assigned values and -their values can be accessed using a parameter substitution. -A parameter name is either one of the special single punctuation or digit -character parameters described below, or a letter followed by zero or more -letters or digits (`_' counts as a letter). -Parameter substitutions take the form \fB$\fP\fIname\fP or -\fB${\fP\fIname\fP\fB}\fP, where \fIname\fP is a parameter name. -If substitution is performed on a parameter that is not set, a null -string is substituted unless the \fBnounset\fP option (\fBset \-o nounset\fP -or \fBset \-u\fP) is set, in which case an error occurs. -.PP -.\"{{{ parameter assignment -Parameters can be assigned values in a number of ways. -First, the shell implicitly sets some parameters like \fB#\fP, \fBPWD\fP, -etc.; this is the only way the special single character parameters are -set. -Second, parameters are imported from the shell's environment at startup. -Third, parameters can be assigned values on the command line, for example, -`\fBFOO=bar\fP' sets the parameter FOO to bar; multiple parameter -assignments can be given on a single command line and they can -be followed by a simple-command, in which case the assignments are -in effect only for the duration of the command (such assignments are -also exported, see below for implications of this). -Note that both the parameter name and the \fB=\fP must be unquoted for -the shell to recognize a parameter assignment. -The fourth way of setting a parameter is with the \fBexport\fP, \fBreadonly\fP -and \fBtypeset\fP commands; see their descriptions in the Command Execution -section. -Fifth, \fBfor\fP and \fBselect\fP loops set parameters as well as -the \fBgetopts\fP, \fBread\fP and \fBset \-A\fP commands. -Lastly, parameters can be assigned values using assignment operators -inside arithmetic expressions (see Arithmetic Expressions below) or -using the \fB${\fP\fIname\fP\fB=\fP\fIvalue\fP\fB}\fP form -of parameter substitution (see below). -.\"}}} -.PP -.\"{{{ environment -Parameters with the export attribute (set using the \fBexport\fP or -\fBtypeset \-x\fP commands, or by parameter assignments followed by simple -commands) are put in the environment (see \fIenviron\fP(5)) of commands -run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs. -The order in which parameters appear in the environment of a command -is unspecified. -When the shell starts up, it extracts parameters and their values from its -environment and automatically sets the export attribute for those parameters. -.\"}}} -.\"{{{ ${name[:][-+=?]word} -.PP -Modifiers can be applied to the \fB${\fP\fIname\fP\fB}\fP form of parameter -substitution: -.IP \fB${\fP\fIname\fP\fB:-\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP is -substituted. -.IP \fB${\fP\fIname\fP\fB:+\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, \fIword\fP is substituted, otherwise nothing is substituted. -.IP \fB${\fP\fIname\fP\fB:=\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, it is substituted, otherwise it is -assigned \fIword\fP and the resulting value of \fIname\fP is substituted. -.IP \fB${\fP\fIname\fP\fB:?\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP -is printed on standard error (preceded by \fIname\fP:) and an error occurs -(normally causing termination of a shell script, function or \&.-script). -If word is omitted the string `parameter null or not set' is used instead. -.PP -In the above modifiers, the \fB:\fP can be omitted, in which case the -conditions only depend on \fIname\fP being set (as opposed to set and -not null). -If \fIword\fP is needed, parameter, command, arithmetic and tilde substitution -are performed on it; if \fIword\fP is not needed, it is not evaluated. -.\"}}} -.PP -The following forms of parameter substitution can also be used: -.\"{{{ ${#name} -.IP \fB${#\fP\fIname\fP\fB}\fP -The number of positional parameters if \fIname\fP is \fB*\fP, \fB@\fP or -is not specified, -or the length of the string value of parameter \fIname\fP. -.\"}}} -.\"{{{ ${#name[*]}, ${#name[@]} -.IP "\fB${#\fP\fIname\fP\fB[*]}\fP, \fB${#\fP\fIname\fP\fB[@]}\fP" -The number of elements in the array \fIname\fP. -.\"}}} -.\"{{{ ${name#pattern}, ${name##pattern} -.IP "\fB${\fP\fIname\fP\fB#\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB##\fP\fIpattern\fP\fB}\fP" -If \fIpattern\fP matches the beginning of the value of parameter \fIname\fP, -the matched text is deleted from the result of substitution. A single -\fB#\fP results in the shortest match, two \fB#\fP's results in the -longest match. -.\"}}} -.\"{{{ ${name%pattern}, ${name%%pattern} -.IP "\fB${\fP\fIname\fP\fB%\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB%%\fP\fIpattern\fP\fB}\fP" -Like \fB${\fP..\fB#\fP..\fB}\fP substitution, but it deletes from the end of the -value. -.\"}}} -.\"{{{ special shell parameters -.PP -The following special parameters are implicitly set by the shell and cannot be -set directly using assignments: -.\"{{{ ! -.IP \fB!\fP -Process id of the last background process started. If no background -processes have been started, the parameter is not set. -.\"}}} -.\"{{{ # -.IP \fB#\fP -The number of positional parameters (\fIi.e.\fP, \fB$1\fP, \fB$2\fP, -\fIetc.\fP). -.\"}}} -.\"{{{ $ -.IP \fB$\fP -The process ID of the shell, or the PID of the original shell if -it is a subshell. -.\"}}} -.\"{{{ - -.IP \fB\-\fP -The concatenation of the current single letter options -(see \fBset\fP command below for list of options). -.\"}}} -.\"{{{ ? -.IP \fB?\fP -The exit status of the last non-asynchronous command executed. -If the last command was killed by a signal, \fB$?\fP is set to 128 plus -the signal number. -.\"}}} -.\"{{{ 0 -.IP "\fB0\fP" -The name the shell was invoked with (\fIi.e.\fP, \fBargv[0]\fP), or the -\fBcommand-name\fP if it was invoked with the \fB\-c\fP option and the -\fBcommand-name\fP was supplied, or the \fIfile\fP argument, if it was -supplied. -If the \fBposix\fP option is not set, \fB$0\fP is the name of the current -function or script. -.\"}}} -.\"{{{ 1-9 -.IP "\fB1\fP ... \fB9\fP" -The first nine positional parameters that were supplied to the shell, -function or \fB.\fP-script. -Further positional parameters may be accessed using -\fB${\fP\fInumber\fP\fB}\fP. -.\"}}} -.\"{{{ * -.IP \fB*\fP -All positional parameters (except parameter 0), -\fIi.e.\fP, \fB$1 $2 $3\fP.... -If used outside of double quotes, parameters are separate words -(which are subjected to word splitting); if used within double quotes, -parameters are separated by the first character of the \fBIFS\fP parameter -(or the empty string if \fBIFS\fP is null). -.\"}}} -.\"{{{ @ -.IP \fB@\fP -Same as \fB$*\fP, unless it is used inside double quotes, in which case -a separate word is generated for each positional parameter \- if there -are no positional parameters, no word is generated ("$@" can be used -to access arguments, verbatim, without loosing null arguments or -splitting arguments with spaces). -.\"}}} -.\"}}} -.\"{{{ general shell parameters -.PP -The following parameters are set and/or used by the shell: -.\"{{{ _ -.IP "\fB_\fP \fI(underscore)\fP" -In interactive use, this parameter is set to the last word of the -previous command. When a command is executed, this parameter is set to -the full path of the command and is placed in the command's environment. -When \fBMAILPATH\fP messages are evaluated, this parameter contains -the name of the file that changed (see \fBMAILPATH\fP parameter below). -.\"}}} -.\"{{{ CDPATH -.IP \fBCDPATH\fP -Search path for the \fBcd\fP built-in command. Works the same way as -\fBPATH\fP for those directories not beginning with \fB/\fP in \fBcd\fP -commands. -Note that if CDPATH is set and does not contain \fB.\fP nor an empty path, -the current directory is not searched. -.\"}}} -.\"{{{ COLUMNS -.IP \fBCOLUMNS\fP -Set to the number of columns on the terminal or window. -Currently set to the \fBcols\fP value as reported by \fIstty\fP(1) if that -value is non-zero. -This parameter is used by the interactive line editing modes, and by -\fBselect\fP, \fBset \-o\fP and \fBkill \-l\fP commands -to format information in columns. -.\"}}} -.\"{{{ EDITOR -.IP \fBEDITOR\fP -If the \fBVISUAL\fP parameter is not set, this parameter controls the -command line editing mode for interactive shells. -See \fBVISUAL\fP parameter below for how this works. -.\"}}} -.\"{{{ ENV -.IP \fBENV\fP -If this parameter is found to be set after any profile files are -executed, the expanded value is used as a shell start-up file. It -typically contains function and alias definitions. -.\"}}} -.\"{{{ ERRNO -.IP \fBERRNO\fP -Integer value of the shell's errno variable \(em indicates the reason -the last system call failed. -.\" todo: ERRNO variable -.sp -Not implemented yet. -.\"}}} -.\"{{{ EXECSHELL -.IP \fBEXECSHELL\fP -If set, this parameter is assumed to contain the shell that is to be -used to execute commands that \fIexecve\fP(2) fails to execute and -which do not start with a `\fB#!\fP \fIshell\fP' sequence. -.\"}}} -.\"{{{ FCEDIT -.IP \fBFCEDIT\fP -The editor used by the \fBfc\fP command (see below). -.\"}}} -.\"{{{ FPATH -.IP \fBFPATH\fP -Like \fBPATH\fP, but used when an undefined function is executed to locate -the file defining the function. -It is also searched when a command can't be found using \fBPATH\fP. -See Functions below for more information. -.\"}}} -.\"{{{ HISTFILE -.IP \fBHISTFILE\fP -The name of the file used to store history. -When assigned to, history is loaded from the specified file. -Also, several invocations of the -shell running on the same machine will share history if their -\fBHISTFILE\fP parameters all point at the same file. -.br -NOTE: if HISTFILE isn't set, no history file is used. This is -different from the original Korn shell, which uses \fB$HOME/.sh_history\fP; -in future, pdksh may also use a default history file. -.\"}}} -.\"{{{ HISTSIZE -.IP \fBHISTSIZE\fP -The number of commands normally stored for history, default 128. -.\"}}} -.\"{{{ HOME -.IP \fBHOME\fP -The default directory for the \fBcd\fP command and the value -substituted for an unqualified \fB~\fP (see Tilde Expansion below). -.\"}}} -.\"{{{ IFS -.IP \fBIFS\fP -Internal field separator, used during substitution and by the \fBread\fP -command, to split values into distinct arguments; normally set to -space, tab and newline. See Substitution above for details. -.br -\fBNote:\fP this parameter is not imported from the environment -when the shell is started. -.\"}}} -.\"{{{ KSH_VERSION -.IP \fBKSH_VERSION\fP -The version of shell and the date the version was created (readonly). -See also the version commands in Emacs Interactive Input Line Editing -and Vi Interactive Input Line Editing, below. -.\"}}} -.\"{{{ SH_VERSION -.\"}}} -.\"{{{ LINENO -.IP \fBLINENO\fP -The line number of the function or shell script that is currently being -executed. -.\" todo: LINENO variable -.sp -Not implemented yet. -.\"}}} -.\"{{{ LINES -.IP \fBLINES\fP -Set to the number of lines on the terminal or window. -.\"Currently set to the \fBrows\fP value as reported by \fIstty\fP(1) if that -.\"value is non-zero. -.\" todo: LINES variable -.sp -Not implemented yet. -.\"}}} -.\"{{{ MAIL -.IP \fBMAIL\fP -If set, the user will be informed of the arrival of mail in the named -file. This parameter is ignored if the \fBMAILPATH\fP parameter is set. -.\"}}} -.\"{{{ MAILCHECK -.IP \fBMAILCHECK\fP -How often, in seconds, the shell will check for mail in the file(s) -specified by \fBMAIL\fP or \fBMAILPATH\fP. If 0, the shell checks -before each prompt. The default is 600 (10 minutes). -.\"}}} -.\"{{{ MAILPATH -.IP \fBMAILPATH\fP -A list of files to be checked for mail. The list is colon separated, -and each file may be followed by a \fB?\fP and a message to be printed -if new mail has arrived. Command, parameter and arithmetic substitution is -performed on the message, and, during substitution, the parameter \fB$_\fP -contains the name of the file. -The default message is \fByou have mail in $_\fP. -.\"}}} -.\"{{{ OLDPWD -.IP \fBOLDPWD\fP -The previous working directory. -Unset if \fBcd\fP has not successfully changed directories since the -shell started, or if the shell doesn't know where it is. -.\"}}} -.\"{{{ OPTARG -.IP \fBOPTARG\fP -When using \fBgetopts\fP, it contains the argument for a parsed option, -if it requires one. -.\"}}} -.\"{{{ OPTIND -.IP \fBOPTIND\fP -The index of the last argument processed when using \fBgetopts\fP. -Assigning 1 to this parameter causes \fBgetopts\fP to -process arguments from the beginning the next time it is invoked. -.\"}}} -.\"{{{ PATH -.IP \fBPATH\fP -A colon separated list of directories that are searched when looking -for commands and \fB.\fP'd files. -An empty string resulting from a leading or trailing colon, or two adjacent -colons is treated as a `.', the current directory. -.\"}}} -.\"{{{ POSIXLY_CORRECT -.IP \fBPOSIXLY_CORRECT\fP -If set, this parameter causes the \fBposix\fP option to be enabled. -See POSIX Mode below. -.\"}}} -.\"{{{ PPID -.IP \fBPPID\fP -The process ID of the shell's parent (readonly). -.\"}}} -.\"{{{ PS1 -.IP \fBPS1\fP -\fBPS1\fP is the primary prompt for interactive shells. -Parameter, command and arithmetic substitutions are performed, and -\fB!\fP is replaced with the current command number (see \fBfc\fP -command below). A literal ! can be put in the prompt by placing !! in PS1. -Note that since the command line editors try to figure out how long the -prompt is (so they know how far it is to edge of the screen), -escape codes in the prompt tend to mess things up. -You can tell the shell not to count certain sequences (such as escape codes) -by prefixing your prompt with a non-printing character (such as control-A) -followed by a carriage return and then delimiting the escape codes with -this non-printing character. -If you don't have any non-printing characters, you're out of luck... -BTW, don't blame me for this hack; it's in the original ksh. -Default is `\fB$\ \fP' for non-root users, `\fB#\ \fP' for root.. -.\"}}} -.\"{{{ PS2 -.IP \fBPS2\fP -Secondary prompt string, by default `\fB>\fP ', used when more input is -needed to complete a command. -.\"}}} -.\"{{{ PS3 -.IP \fBPS3\fP -Prompt used by \fBselect\fP statement when reading a menu selection. -Default is `\fB#?\ \fP'. -.\"}}} -.\"{{{ PS4 -.IP \fBPS4\fP -Used to prefix commands that are printed during execution tracing -(see \fBset \-x\fP command below). -Parameter, command and arithmetic substitutions are performed -before it is printed. -Default is `\fB+\ \fP'. -.\"}}} -.\"{{{ PWD -.IP \fBPWD\fP -The current working directory. Maybe unset or null if shell doesn't -know where it is. -.\"}}} -.\"{{{ RANDOM -.IP \fBRANDOM\fP -A simple random number generator. Every time \fBRANDOM\fP is -referenced, it is assigned the next number in a random number series. -The point in the series can be set by assigning a number to -\fBRANDOM\fP (see \fIrand\fP(3)). -.\"}}} -.\"{{{ REPLY -.IP \fBREPLY\fP -Default parameter for the \fBread\fP command if no names are given. -Also used in \fBselect\fP loops to store the value that is read from -standard input. -.\"}}} -.\"{{{ SECONDS -.IP \fBSECONDS\fP -The number of seconds since the shell started or, if the parameter has been -assigned an integer value, the number of seconds since the assignment plus -the value that was assigned. -.\"}}} -.\"{{{ TMOUT -.IP \fBTMOUT\fP -If set to a positive integer in an interactive shell, it specifies -the maximum number of seconds the shell will wait for input after -printing the primary prompt (\fBPS1\fP). If the time is exceeded, the -shell exits. -.\"}}} -.\"{{{ TMPDIR -.IP \fBTMPDIR\fP -The directory shell temporary files are created in. If this parameter -is not set, or does not contain the absolute path of a writable -directory, temporary files are created in \fB/tmp\fP. -.\"}}} -.\"{{{ VISUAL -.IP \fBVISUAL\fP -If set, this parameter controls the command line editing mode for -interactive shells. If the last component of the path specified in this -parameter contains the string \fBvi\fP, \fBemacs\fP or \fBgmacs\fP, the -vi, emacs or gmacs (Gosling emacs) editing mode is enabled, respectively. -.\"}}} -.\"}}} -.\"}}} -.\"{{{ Tilde Expansion -.SS "Tilde Expansion" -Tilde expansion, which is done in parallel with parameter substitution, -is done on words starting with an unquoted \fB~\fP. The characters -following the tilde, up to the first \fB/\fP, if any, are assumed to be -a login name. If the login name is empty, \fB+\fP or \fB\-\fP, the -value of the \fBHOME\fP, \fBPWD\fP, or \fBOLDPWD\fP parameter is -substituted, respectively. Otherwise, the password file is searched for -the login name, and the tilde expression is substituted with the -user's home directory. If the login name is not found in the password -file or if any quoting or parameter substitution occurs in the login name, -no substitution is performed. -.PP -In parameter assignments (those preceding a simple-command or those -occurring in the arguments of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, -and \fBtypeset\fP), tilde expansion is done after any unquoted colon -(\fB:\fP), and login names are also delimited by colons. -.PP -The home directory of previously expanded login names are cached and -re-used. The \fBalias \-d\fP command may be used to list, change and -add to this cache (\fIe.g.\fP, `alias \-d fac=/usr/local/facilities; cd -~fac/bin'). -.\"}}} -.\"{{{ Brace Expansion -.SS "Brace Expansion (alternation)" -Brace expressions, which take the form -.RS -\fIprefix\fP\fB{\fP\fIstr\fP1\fB,\fP...\fB,\fP\fIstr\fPN\fB}\fP\fIsuffix\fP -.RE -are expanded to N words, each of which is the concatenation of -\fIprefix\fP, \fIstr\fPi and \fIsuffix\fP -(\fIe.g.\fP, `a{c,b{X,Y},d}e' expands to four word: ace, abXe, abYe, and ade). -As noted in the example, brace expressions can be nested and the resulting -words are not sorted. -Brace expressions must contain an unquoted comma (\fB,\fP) for expansion -to occur (\fIi.e.\fP, \fB{}\fP and \fB{foo}\fP are not expanded). -Brace expansion is carried out after parameter substitution and before -file name generation. -.\"}}} -.\"{{{ File Name Patterns -.SS "File Name Patterns" -.PP -A file name pattern is a word containing one or more unquoted \fB?\fP or -\fB*\fP characters or \fB[\fP..\fB]\fP sequences. Once brace expansion has -been performed, the shell replaces file name patterns with the sorted names -of all the files that match the pattern (if no files match, the word is -left unchanged). The pattern elements have the following meaning: -.IP \fB?\fP -matches any single character. -.IP \fB*\fP -matches any sequence of characters. -.IP \fB[\fP..\fB]\fP -matches any of the characters inside the brackets. Ranges of characters -can be specified by separating two characters by a \fB\-\fP, \fIe.g.\fP, -\fB[a0\-9]\fP matches the letter \fBa\fP or any digit. -In order to represent itself, a -\fB\-\fP must either be quoted or the first or last character in the character -list. Similarly, a \fB]\fP must be quoted or the first character in the list -if it is represent itself instead of the end of the list. Also, a \fB!\fP -appearing at the start of the list has special meaning (see below), so to -represent itself it must be quoted or appear later in the list. -.IP \fB[!\fP..\fB]\fP -like \fB[\fP..\fB]\fP, except it matches any character not inside the brackets. -.IP "\fB*(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP" -matches any string of characters that matches zero or more occurances -of the specified patterns. -Example: the pattern \fB*(foo|bar)\fP matches the strings -`', `foo', `bar', `foobarfoo', \fIetc.\fP. -.IP "\fB+(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP" -matches any string of characters that matches one or more occurances -of the specified patterns. -Example: the pattern \fB+(foo|bar)\fP matches the strings -`foo', `bar', `foobarfoo', \fIetc.\fP. -.IP "\fB?(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP" -matches the empty string or a string that matches one of the -specified patterns. -Example: the pattern \fB?(foo|bar)\fP only matches the strings -`', `foo' and `bar'. -.IP "\fB@(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP" -matches a string that matches one of the -specified patterns. -Example: the pattern \fB@(foo|bar)\fP only matches the strings -`foo' and `bar'. -.IP "\fB!(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP" -matches any string that does not match one of the specified -patterns. -Examples: the pattern \fB!(foo|bar)\fP matches all strings except -`foo' and `bar'; the pattern \fB!(*)\fP matches no strings; -the pattern \fB!(?)*\fP matches all strings (think about it). -.PP -Note that pdksh currently never matches \fB.\fP and \fB..\fP, but the original -ksh, Bourne sh and bash do, so this may have to change (too bad). -.PP -Note that none of the above pattern elements match either a period (\fB.\fP) -at the start of a file name or a slash (\fB/\fP), even if they are explicitly -used in a \fB[\fP..\fB]\fP sequence; also, the names \fB.\fP and \fB..\fP -are never matched, even by the pattern \fB.*\fP. -.PP -If the \fBmarkdirs\fP option is set, any directories that result from -file name generation are marked with a trailing \fB/\fP. -.PP -.\" todo: implement this ([[:alpha:]], \fIetc.\fP) -The POSIX character classes (\fIi.e.\fP, -\fB[:\fP\fIclass-name\fP\fB:]\fP inside a \fB[\fP..\fB]\fP expression) -are not yet implemented. -.\"}}} -.\"{{{ Input/Output Redirection -.SS "Input/Output Redirection" -When a command is executed, its standard input, standard output and -standard error (file descriptors 0, 1 and 2, respectively) are normally -inherited from the shell. -Three exceptions to this are commands in pipelines, for which standard input -and/or standard output are those set up by the pipeline, asynchronous commands -created when job control is disabled, for which standard input is initially -set to be from \fB/dev/null\fP, and commands for which any of the following -redirections have been specified: -.IP "\fB>\fP \fIfile\fP" -standard output is redirected to \fIfile\fP. If \fIfile\fP does not exist, -it is created; if it does exist, is a regular file and the \fBnoclobber\fP -option is set, an error occurs, otherwise the file is truncated. -Note that this means the command \fIcmd < foo > foo\fP will open -\fIfoo\fP for reading and then truncate it when it opens it for writing, -before \fIcmd\fP gets a chance to actually read \fIfoo\fP. -.IP "\fB>|\fP \fIfile\fP" -same as \fB>\fP, except the file is truncated, even if the \fBnoclobber\fP -option is set. -.IP "\fB>>\fP \fIfile\fP" -same as \fB>\fP, except the file an existing file is appended to instead -of being truncated. Also, the file is opened in append mode, so writes -always go to the end of the file (see \fIopen\fP(2)). -.IP "\fB<\fP \fIfile\fP" -standard input is redirected from \fIfile\fP, which is opened for reading. -.IP "\fB<>\fP \fIfile\fP" -same as \fB<\fP, except the file is opened for reading and writing. -.IP "\fB<<\fP \fImarker\fP" -after reading the command line containing this kind of redirection (called a -here document), the shell copies lines from the command source into a temporary -file until a line matching \fImarker\fP is read. -When the command is executed, standard input is redirected from the temporary -file. -If \fImarker\fP contains no quoted characters, the contents of the -temporary file are processed as if enclosed in double quotes each time -the command is executed, so parameter, command and arithmetic substitutions -are performed, along with backslash (\fB\e\fP) escapes for -\fB$\fP, \fB`\fP, \fB\e\fP and \fB\enewline\fP. -If multiple here documents are used on the same command line, they are -saved in order. -.IP "\fB<<-\fP \fImarker\fP" -same as \fB<<\fP, except leading tabs are stripped from lines in the -here document. -.IP "\fB<&\fP \fIfd\fP" -standard input is duplicated from file descriptor \fIfd\fP. -\fIfd\fP can be a single digit, indicating the number of an existing -file descriptor, the letter \fBp\fP, indicating the file descriptor -associated with the output of the current co-process, or -the character \fB\-\fP, indicating standard input is to be closed. -.IP "\fB>&\fP \fIfd\fP" -same as \fB<&\fP, except the operation is done on standard output. -.PP -In any of the above redirections, the file descriptor that is redirected -(\fIi.e.\fP, standard input or standard output) can be explicitly given by -preceding the redirection with a single digit. -Parameter, command and arithmetic substitutions, tilde substitutions and -file name generation are all performed on the \fIfile\fP, \fImarker\fP and -\fIfd\fP arguments of redirections. -Note however, that the results of any file name generation are only used -if a single file is matched; if multiple files match, the word with the -unexpanded file name generation characters is used. -Note that in restricted shells, redirections which can create files cannot -be used. -.PP -For simple-commands, redirections may appear anywhere in the command, for -compound-commands (\fBif\fP statements, \fIetc.\fP), any redirections must -appear at the end. -Redirections are processed after pipelines are created and in the order they -are given, so -.RS -\fBcat /foo/bar 2>&1 > /dev/null | cat \-n\fP -.RE -will print an error with a line number prepended to it. -.\"}}} -.\"{{{ Arithmetic Expressions -.SS "Arithmetic Expressions" -Integer arithmetic expressions can be used -with the \fBlet\fP command, -inside \fB$((\fP..\fB))\fP expressions, -inside array references (\fIe.g.\fP, \fIname\fP\fB[\fP\fIexpr\fP\fB]\fP), -as numeric arguments to the \fBtest\fP command, -and as the value of an assignment to an integer parameter. -.PP -Expression may contain alpha-numeric parameter identifiers, array -references, and integer constants and may be combined with the -following C operators (listed and grouped in increasing order of precedence). -.TP -Unary operators: -\fB+ \- ! ~ ++ --\fP -.TP -Binary operators: -\fB,\fP -.br -\fB= *= /= %= += \-= <<= >>= &= ^= |=\fP -.br -\fB||\fP -.br -\fB&&\fP -.br -\fB|\fP -.br -\fB^\fP -.br -\fB&\fP -.br -\fB== !=\fP -.br -\fB< <= >= >\fP -.br -\fB<< >>\fP -.br -\fB+ \-\fP -.br -\fB* / %\fP -.TP -Ternary operator: -\fB?:\fP (precedence is immediately higher than assignment) -.TP -Grouping operators: -\fB( )\fP -.PP -Integer constants may be specified with arbitrary bases using the notation -\fIbase\fP\fB#\fP\fInumber\fP, where \fIbase\fP is a decimal integer specifying -the base, and \fInumber\fP is a number in the specified base. -.LP -The operators are evaluated as follows: -.RS -.IP "unary \fB+\fP" -result is the argument (included for completeness). -.IP "unary \fB\-\fP" -negation. -.IP "\fB!\fP" -logical not; the result is 1 if argument is zero, 0 if not. -.IP "\fB~\fP" -arithmetic (bit-wise) not. -.IP "\fB++\fP" -increment; must be applied to a parameter (not a literal or other -expression) - the parameter is incremented by 1. -When used as a prefix operator, the result is the incremented value of -the parameter, when used as a postfix operator, the result is the -original value of the parameter. -.IP "\fB++\fP" -similar to \fB++\fP, except the paramter is decremented by 1. -.IP "\fB,\fP" -seperates two arithmetic expressions; the left hand side is evaluated first, -then the right. The result is value of the expression on the right hand side. -.IP "\fB=\fP" -assignment; variable on the left is set to the value on the right. -.IP "\fB*= /= %= += \-= <<= >>= &= ^= |=\fP" -assignment operators; \fI<var> <op>\fP\fB=\fP \fI<expr>\fP is the same as -\fI<var>\fP \fB=\fP \fI<var> <op>\fP \fB(\fP \fI<expr>\fP \fB)\fP. -.IP "\fB||\fP" -logical or; the result is 1 if either argument is non-zero, 0 if not. -The right argument is evaluated only if the left argument is zero. -.IP "\fB&&\fP" -logical and; the result is 1 if both arguments are non-zero, 0 if not. -The right argument is evaluated only if the left argument is non-zero. -.IP "\fB|\fP" -arithmetic (bit-wise) or. -.IP "\fB^\fP" -arithmetic (bit-wise) exclusive-or. -.IP "\fB&\fP" -arithmetic (bit-wise) and. -.IP "\fB==\fP" -equal; the result is 1 if both arguments are equal, 0 if not. -.IP "\fB!=\fP" -not equal; the result is 0 if both arguments are equal, 1 if not. -.IP "\fB<\fP" -less than; the result is 1 if the left argument is less than the right, -0 if not. -.IP "\fB<= >= >\fP" -less than or equal, greater than or equal, greater than. See <. -.IP "\fB<< >>\fP" -shift left (right); the result is the left argument with its bits shifted -left (right) by the amount given in the right argument. -.IP "\fB+ - * /\fP" -addition, subtraction, multiplication, and division. -.IP "\fB%\fP" -remainder; the result is the remainder of the division of the left argument -by the right. The sign of the result is unspecified if either argument -is negative. -.IP "\fI<arg1>\fP \fB?\fP \fI<arg2>\fP \fB:\fP \fI<arg3>\fP" -if \fI<arg1>\fP is non-zero, the result is \fI<arg2>\fP, -otherwise \fI<arg3>\fP. -.RE -.\"}}} -.\"{{{ Co-Processes -.SS "Co-Processes" -A co-process, which is a pipeline created with the \fB|&\fP operator, -is an asynchronous process that the shell can both write to -(using \fBprint \-p\fP) and read from (using \fBread \-p\fP). -The input and output of the co-process can also be manipulated -using \fB>&p\fP and \fB<&p\fP redirections, respectively. -Once a co-process has been started, another can't be started until -the co-process exits, or until the co-process input has been redirected using -an \fBexec \fP\fIn\fP\fB>&p\fP redirection. -If a co-process's input is redirected in this way, the next -co-process to be started will share the output with the first co-process, -unless the output of the initial co-process has been redirected using an -\fBexec \fP\fIn\fP\fB<&p\fP redirection. -.PP -Some notes concerning co-processes: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -the only way to close the co-process input (so the co-process reads -an end-of-file) is to redirect the input to a numbered file descriptor -and then close that file descriptor (\fIe.g.\fP, \fBexec 3>&p;exec 3>&-\fP). -.IP \ \ \(bu -in order for co-processes to share a common output, the shell must keep -the write portion of the output pipe open. -This means that end of file will not be detected until all co-processes -sharing the co-process output have exited (when they all exit, the shell -closes its copy of the pipe). -This can be avoided by redirecting the output to a numbered -file descriptor (as this also causes the shell to close its copy). -Note that this behaviour is slightly different from the original Korn shell -which closes its copy of the write portion of the co-processs output when the -most recently started co-process (instead of when all sharing co-processes) -exits. -.IP \ \ \(bu -\fBprint \-p\fP will ignore SIGPIPE signals during writes -if the signal is not being trapped or ignored; the same is not true if -the co-process input has been duplicated to another file descriptor and -\fBprint \-u\fP\fIn\fP is used. -.nr PD \n(P2 -.\"}}} -.\"{{{ Functions -.SS "Functions" -Functions are defined using either Korn shell \fBfunction\fP \fIname\fP -syntax or the Bourne/POSIX shell \fIname\fP\fB()\fP syntax -(see below for the difference between the two forms). -Functions are like \fB.\fP-scripts in that they are executed in -the current environment, however, unlike \fB.\fP-scripts, shell arguments -(\fIi.e.\fP, positional parameters, \fB$1\fP, \fIetc.\fP) are never visible -inside them. -When the shell is determining the location of a command, functions are -searched after special built-in commands, and before regular and non-regular -built-ins, and before the \fBPATH\fP is searched. -.PP -An existing function may be deleted using \fBunset \-f\fP \fIfunction-name\fP. -A list of functions can be obtained using \fBtypeset +f\fP and the -function definitions can be listed using \fBtypeset \-f\fP. -\fBautoload\fP (which is an alias for \fBtypeset \-fu\fP) may be used to -create undefined functions; when an undefined function is executed, the -shell searches the path specified in the \fBFPATH\fP parameter for a file -with the same name as the function, which, if found is read and executed. -If after executing the file, the named function is found to be defined, the -function is executed, otherwise, the normal command search is continued -(\fIi.e.\fP, the shell searches the regular built-in command table -and \fBPATH\fP). -Note that if a command is not found using \fBPATH\fP, an attempt is -made to autoload a function using \fBFPATH\fP (this is an undocumented -feature of the original Korn shell). -.PP -Functions can have two attributes, trace and export, which can be set -with \fBtypeset \-ft\fP and \fBtypeset \-fx\fP, respectively. -When a traced function is executed, the shell's \fBxtrace\fP option is turned -on for the functions duration, otherwise the \fBxtrace\fP option is turned off. -The export attribute of functions is currently not used. In the original -Korn shell, exported functions are visible to shell scripts that are executed. -.PP -Since functions are executed in the current shell environment, parameter -assignments made inside functions are visible after the function completes. -If this is not the desired effect, the \fBtypeset\fP command can be used -inside a function to create a local parameter. -Note that special parameters (\fIe.g.\fP, \fB$$\fP, \fB$!\fP) can't be -scoped in this way. -.PP -The exit status of a function is that of the last command executed in -the function. -A function can be made to finish immediately using the \fBreturn\fP command; -this may also be used to explicitly specify the exit status. -.PP -Functions defined with the \fBfunction\fP reserved word are -treated differently in the following ways from functions defined with -the \fB()\fP notation: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -the \fB$0\fP parameter is set to the name of the function -(Bourne-style functions leave \fB$0\fP untouched). -.IP \ \ \(bu -parameter assignments preceeding function calls are not kept in -the shell environment -(executing Bourne-style functions will keep assignments). -.nr PD \n(P2 -In the future, the following differences will also be added: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -A separate trap/signal environment will be used during the execution of -functions. -This will mean that traps set inside a function will not affect the shell's -traps and signals that are not ignored in the shell (but may be trapped) will -have their default effect in a function. -.IP \ \ \(bu -The EXIT trap, if set in a function, will be executed after the function -returns. -.nr PD \n(P2 -.\"}}} -.\"{{{ POSIX mode -.SS "POSIX Mode" -The shell is intended to be POSIX compliant, however, in some cases, POSIX -behaviour is contrary either to the original Korn shell behaviour or to -user convenience. -How the shell behaves in these cases is determined by the state of -the posix option (\fBset \-o posix\fP) \(em if it is on, the POSIX behaviour -is followed, otherwise it is not. -The \fBposix\fP option is set automatically when the shell starts up -if the environment contains the \fBPOSIXLY_CORRECT\fP parameter. -(The shell can also be compiled so that it is in POSIX mode by default, -however this is usually not desirable). -.PP -The following is a list of things that are affected by the state of -the \fBposix\fP option: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -\fB\e"\fP inside double quoted \fB`\fP..\fB`\fP command substitutions: -in posix mode, the \fB\e"\fP is interpreted when the command is interpreted; -in non-posix mode, the backslash is stripped before the command substitution -is interpreted. For example, \fBecho "`echo \e"hi\e"`"\fP produces `"hi"' in -posix mode, `hi' in non-posix mode. To avoid problems, use the \fB$(...\fP) -form of command substitution. -.IP \ \ \(bu -\fBkill \-l\fP output: in posix mode, signal names are listed one a single line; -in non-posix mode, signal numbers, names and descriptions are printed in -columns. -In future, a new option (\fB\-v\fP perhaps) will be added to distinguish -the two behaviours. -.IP \ \ \(bu -\fBfg\fP exit status: in posix mode, the exit status is 0 if no errors occur; -in non-posix mode, the exit status is that of the last foregrounded job. -.IP \ \ \(bu -\fBgetopts\fP: in posix mode, options must start with a \fB\-\fP; in non-posix -mode, options can start with either \fB\-\fP or \fB+\fP. -.IP \ \ \(bu -brace expansion (also known as alternation): in posix mode, brace expansion -is disabled; in non-posix mode, brace expansion enabled. -Note that \fBset \-o posix\fP (or setting the \fBPOSIXLY_CORRECT\fP parameter) -automatically turns the \fBbraceexpand\fP option off, however it can be -explicitly turned on later. -.IP \ \ \(bu -\fBset \-\fP: in posix mode, this does not clear the \fBverbose\fP or -\fBxtrace\fP options; in non-posix mode, it does. -.IP \ \ \(bu -\fBset\fP exit status: in posix mode, the exit status of set is 0 -if there are no errors; in non-posix mode, the exit status is that of -any command substitutions performed in generating the set command. -For example, `\fBset \-\- `false`; echo $?\fP' prints 0 in posix mode, -1 in non-posix mode. This construct is used in most shell scripts that -use the old \fIgetopt\fP(1) command. -.IP \ \ \(bu -argument expansion of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, and -\fBtypeset\fP commands: in posix mode, normal argument expansion done; -in non-posix mode, field splitting, file globing, brace expansion and -(normal) tilde expansion are turned off, and assignment tilde expansion -is turned on. -.IP \ \ \(bu -signal specification: in posix mode, signals can be specified as digits only -if signal numbers match POSIX values (\fIi.e.\fP, HUP=1, INT=2, QUIT=3, ABRT=6, -KILL=9, ALRM=14, and TERM=15); in non-posix mode, signals can be always digits. -.IP \ \ \(bu -alias expansion: in posix mode, alias expansion is only carried out when -reading command words; in non-posix mode, alias expansion is carried out -on any word following an alias that ended in a space. -For example, the following for loop -.RS -.ft B -alias a='for ' i='j' -.br -a i in 1 2; do echo i=$i j=$j; done -.ft P -.RE -uses parameter \fBi\fP in posix mode, \fBj\fP in non-posix mode. -.nr PD \n(P2 -.\"}}} -.\"{{{ Command Execution (built-in commands) -.SS "Command Execution" -After evaluation of command line arguments, redirections and parameter -assignments, the type of command is determined: a special built-in, -a function, a regular built-in or the name of a file to execute found -using the \fBPATH\fP parameter. -The checks are made in the above order. -Special built-in commands differ from other commands in that -the \fBPATH\fP parameter is not used to find them, an error -during their execution can cause a non-interactive shell to exit and -parameter assignments that are specified before the command are -kept after the command completes. -Just to confuse things, if the posix option is turned off (see \fBset\fP -command below) some special commands are very special in that -no field splitting, file globing, brace expansion nor tilde expansion -is preformed on arguments that look like assignments. -Regular built-in commands are different only in that the \fBPATH\fP -parameter is not used to find them. -.PP -The original ksh and POSIX differ somewhat in which commands are considered -special or regular: -.IP "POSIX special commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -\&. continue exit return trap -: eval export set unset -break exec readonly shift -.TE -.IP "Additional ksh special commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -builtin times typeset -.TE -.IP "Very special commands (non-posix mode)" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -alias readonly set typeset -.TE -.IP "POSIX regular commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -alias command fg kill umask -bg false getopts read unalias -cd fc jobs true wait -.TE -.IP "Additional ksh regular commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -[ let pwd ulimit -echo print test whence -.TE -.PP -In the future, the additional ksh special and regular commands may -be treated differently from the POSIX special and regular commands. -.PP -Once the type of the command has been determined, any command line parameter -assignments are performed and exported for the duration of the command. -.PP -The following describes the special and regular built-in commands: -.\"{{{ . file [ arg1 ... ] -.IP "\fB\&.\fP \fIfile\fP [\fIarg1\fP ...]" -Execute the commands in \fIfile\fP in the current environment. -The file is searched for in the directories of \fBPATH\fP. -If arguments are given, the positional parameters may be used to -access them while \fIfile\fP is being executed. -If no arguments are given, the positional parameters are those of the -environment the command is used in. -.\"}}} -.\"{{{ : [ ... ] -.IP "\fB:\fP [ ... ]" -The null command. -Exit status is set to zero. -.\"}}} -.\"{{{ alias [ -d | -t [ -r ] ] [-x] [name1[=value1] ...] -.IP "\fBalias\fP [ \fB\-d\fP | \fB\-t\fP [\fB\-r\fP] ] [\fB\-x\fP] [\fIname1\fP[\fB=\fP\fIvalue1\fP] ...]" -Without arguments, \fBalias\fP lists all aliases and their values. For -any name without a value, its value is listed. Any name with a value -defines an alias (see Aliases above). -.sp -The \fB\-x\fP option sets the export attribute of an alias, or, if no -names are given, lists the aliases with the export attribute -(exporting an alias currently has no affect). -.sp -The \fB\-t\fP option indicates that tracked aliases are to be listed/set -(values specified on the command line are ignored for tracked aliases). -The \fB\-r\fP option indicates that all tracked aliases are to be reset. -.sp -The \fB\-d\fP causes directory aliases, which are used in tilde expansion, -to be listed or set (see Tilde Expansion above). -.\"}}} -.\"{{{ bg [job ...] -.IP "\fBbg\fP [\fIjob\fP ...]" -Resume the specified stopped job(s) in the background. -If no jobs are specified, \fB%+\fP is assumed. -This command is only available on systems which support job control. -See Job Control below for more information. -.\"}}} -.\"{{{ bind [-l] [-m] [key[=editing-command] ...] -.IP "\fBbind\fP [\fB\-m\fP] [\fIkey\fP[\fB=\fP\fIediting-command\fP] ...]" -Set or view the current emacs command editing key bindings/macros. -See Emacs Interactive Input Line Editing below for a complete description. -.\"}}} -.\"{{{ break [level] -.IP "\fBbreak\fP [\fIlevel\fP]" -\fBbreak\fP exits the \fIlevel\fPth inner most for, select, until, or while -loop. -\fIlevel\fP defaults to 1. -.\"}}} -.\"{{{ builtin command [arg1 ...] -.IP "\fBbuiltin\fP \fIcommand\fP [\fIarg1\fP ...]" -Execute the built-in command \fIcommand\fP. -.\"}}} -.\"{{{ cd [-LP] [dir] -.IP "\fBcd\fP [\fB\-LP\fP] [\fIdir\fP]" -Set the working directory to \fIdir\fP. If the parameter \fBCDPATH\fP -is set, it lists the search path for the directory containing -\fIdir\fP. A null path means the current directory. If \fIdir\fP is -missing, the home directory \fB$HOME\fP is used. If \fIdir\fP is -\fB\-\fP, the previous working directory is used (see OLDPWD parameter). -If \fB\-L\fP option (logical path) is used or if the \fBphysical\fP option -(see \fBset\fP command below) isn't set, references to \fB..\fP in \fIdir\fP -are relative to the path used get to the directory. -If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option -is set, \fB..\fP is relative to the filesystem directory tree. -The \fBPWD\fP and \fBOLDPWD\fP parameters are updated to reflect the -current and old wording directory, respectively. -.\"}}} -.\"{{{ cd [-LP] old new -.IP "\fBcd\fP [\fB\-LP\fP] \fIold new\fP" -The string \fInew\fP is substituted for \fIold\fP in the current -directory, and the shell attempts to change to the new directory. -.\"}}} -.\"{{{ command [ -pvV ] cmd [arg1 ...] -.IP "\fBcommand\fP [\fB\-pvV\fP] \fIcmd\fP [\fIarg1\fP ...]" -If neither the \fB\-v\fP nor \fB\-V\fP options are given, -\fIcmd\fP -is executed exactly as if the \fBcommand\fP had not been specified, -with two exceptions: first, \fIcmd\fP cannot be a shell function, and -second, special built-in commands lose their specialness (\fIi.e.\fP, -redirection and utility errors do not cause the shell to exit, and command -assignments are not permanent). -If the \fB\-p\fP option is given, a default search path is used instead of -the current value of \fBPATH\fP (the actual value of the default path is -system dependent: on POSIXish systems, it is the value returned by -.ce -\fBgetconf CS_PATH\fP -). -.sp -If the \fB\-v\fP option is given, instead of executing \fIcmd\fP, information -about what would be executed is given (and the same is done for -\fIarg1\fP ...): -for special and regular built-in commands and functions, -their names are simply printed, -for aliases, a command that defines them is printed, -and for commands found by searching the \fBPATH\fP parameter, -the full path of the command is printed. -If no command is be found, (\fIi.e.\fP, the path search fails), nothing -is printed and \fBcommand\fP exits with a non-zero status. -The \fB\-V\fP option is like the \fB\-v\fP option, except it is more verbose. -.\"}}} -.\"{{{ continue [levels] -.IP "\fBcontinue\fP [\fIlevels\fP]" -\fBcontinue\fP jumps to the beginning of the \fIlevel\fPth inner most for, -select, until, or while loop. -\fIlevel\fP defaults to 1. -.\"}}} -.\"{{{ echo [-neE] [arg ...] -.IP "\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...]" -Prints its arguments (separated by spaces) followed by a newline, to -standard out. -The newline is suppressed if any of the arguments contain the backslash -sequence \fB\ec\fP. -See \fBprint\fP command below for a list of other backslash sequences -that are recognized. -.sp -The options are provided for compatibility with BSD shell scripts: -\fB\-n\fP suppresses the trailing newline, \fB\-e\fP enables backslash -interpretation (a no-op, since this is normally done), and \fB\-E\fP which -suppresses backslash interpretation. -.\"}}} -.\"{{{ eval command ... -.IP "\fBeval\fP \fIcommand ...\fP" -The arguments are concatenated (with spaces between them) to form -a single string which the shell then parses and executes -in the current environment. -.\"}}} -.\"{{{ exec [command [arg ...]] -.IP "\fBexec\fP [\fIcommand\fP [\fIarg\fP ...]]" -The command is executed without forking, replacing the shell process. -.sp -If no arguments are given, any IO redirection is permanent and the shell -is not replaced. -Any file descriptors greater than 2 which are opened or \fIdup\fP(2)-ed -in this way are not made available to other executed commands (\fIi.e.\fP, -commands that are not built-in to the shell). -.\"}}} -.\"{{{ exit [status] -.IP "\fBexit\fP [\fIstatus\fP]" -The shell exits with the specified exit status. -If \fIstatus\fP is not specified, the exit status is the current -value of the \fB?\fP parameter. -.\"}}} -.\"{{{ export [-p] [parameter[=value] ...] -.IP "\fBexport\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..." -Sets the export attribute of the named parameters. -Exported parameters are passed in the environment to executed commands. -If values are specified, the named parameters also assigned. -.sp -If no parameters are specified, the names of all parameters with the export -attribute are printed one per line, unless the \fB\-p\fP option is used, -in which case \fBexport\fP commands defining all exported -parameters, including their values, are printed. -.\"}}} -.\"{{{ false -.IP "\fBfalse\fP" -A command that exits with a non-zero status. -.\"}}} -.\"{{{ fc [-e editor | -l [-n]] [-r] [first [ last ]] -.IP "\fBfc\fP [\fB\-e\fP \fIeditor\fP | \fB\-l\fP [\fB\-n\fP]] [\fB\-r\fP] [\fIfirst\fP [\fIlast\fP]]" -\fIfirst\fP and \fIlast\fP select commands from the history. -Commands can be selected by -history number, or a string specifying the most recent command starting -with that string. The \fB\-l\fP option lists the command on stdout, -and \fB\-n\fP inhibits the default command numbers. The \fB\-r\fP -option reverses the order of the list. Without \fB\-l\fP, the selected -commands are edited by the editor specified with the \fB\-e\fP -option, or if no \fB\-e\fP is specified, the editor specified by the -\fBFCEDIT\fP parameter (if this parameter is not set, \fB/bin/ed\fP is used), -and then executed by the shell. -.\"}}} -.\"{{{ fc [-e - | -s] [-g] [old=new] [prefix] -.IP "\fBfc\fP [\fB\-e \-\fP | \fB\-s\fP] [\fB\-g\fP] [\fIold\fP\fB=\fP\fInew\fP] [\fIprefix\fP]" -Re-execute the selected command (the previous command by default) after -performing the optional substitution of \fIold\fP with \fInew\fP. If -\fB\-g\fP is specified, all occurrences of \fIold\fP are replaced with -\fInew\fP. This command is usually accessed with the predefined alias -\fBr='fc \-e \-'\fP. -.\"}}} -.\"{{{ fg [job ...] -.IP "\fBfg\fP [\fIjob\fP ...]" -Resume the specified job(s) in the foreground. -If no jobs are specified, \fB%+\fP is assumed. -This command is only available on systems which support job control. -See Job Control below for more information. -.\"}}} -.\"{{{ getopts optstring name [arg ...] -.IP "\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIarg\fP ...]" -\fBgetopts\fP is used by shell procedures to parse the specified arguments -(or positional parameters, if no arguments are given) and to check for legal -options. -\fIoptstring\fP contains the option letters that -\fBgetopts\fP is to recognize. If a letter is followed by a colon, the -option is expected to have an argument. -Arguments containing options must all start with either a \fB\-\fP or -a \fB+\fP, options that do not take arguments may be grouped in a single -argument. -If an option takes an argument and the option character is not the last -character of the argument it is found in, the remainder of the argument -is taken to be the option's argument, otherwise, the next argument is -the option's argument. -.sp -Each time \fBgetopts\fP is invoked, it places the next option in -the shell parameter \fIname\fP and the index of the next argument to be -processed in the shell parameter \fBOPTIND\fP. -If the option was introduced with a \fB+\fP, the option placed in -\fIname\fP is prefixed with a \fB+\fP. -When an option requires an argument, \fBgetopts\fP places it in the -shell parameter \fBOPTARG\fP. -When an illegal option or a missing option argument is -encountered a question mark or a colon is placed in \fIname\fP -(indicating an illegal option or missing argument, respectively) -and \fBOPTARG\fP is set to the option character that caused the problem. -An error message is also printed to standard error if \fIoptstring\fP -does not begin with a colon. -.sp -When the end of the options is encountered, \fBgetopts\fP exits with a -non-zero exit status. -Options end at the first (non-option argument) argument that does not -start with a \-, or when a \fB\-\-\fP argument is encountered. -.sp -Option parsing can be reset by setting \fBOPTIND\fP to 1 (this is done -automatically whenever the shell or a shell procedure is invoked). -.sp -Warning: Changing the value of the shell parameter \fBOPTIND\fP to -a value other than 1, or parsing different sets of arguments without -resetting \fBOPTIND\fP may lead to unexpected results. -.\"}}} -.\"{{{ hash [-r] [name ...] -.IP "\fBhash\fP [\fB\-r\fP] [\fIname ...\fP]" -Without arguments, any hashed executable command pathnames are listed. -The \fB\-r\fP option causes all hashed commands to be removed -from the hash table. -Each \fIname\fP is searched as if it where a command name and added to the -hash table if it is an executable command. -.\"}}} -.\"{{{ jobs [-lpn] [job ...] -.IP "\fBjobs\fP [\fB\-lpn\fP] [\fIjob\fP ...]" -Display information about the specified jobs; if no jobs are specified, -all jobs are displayed. -The \fB\-n\fP option causes information to be displayed only for jobs -that have changed state since the last notification. -If the \fB\-l\fP option is used, the process-id of each process in a job -is also listed. -The \fB\-p\fP option causes only the process group of each job to be printed. -See Job Control below for the format of \fIjob\fP and the displayed job. -.\"}}} -.\"{{{ kill [-s signame | -signum | -signame] { job | pid | -pgrp } ... -.IP "\fBkill\fP [\fB\-s\fP \fIsigname\fP | \fB\-signum\fP | \fB\-signame\fP ] { \fIjob\fP | \fIpid\fP | \fB\-\fP\fIpgrp\fP } ..." -Send the specified signal to the specified jobs, process ids, or process groups. -If no signal is specified, the signal TERM is sent. -If a job is specified, the signal is sent to the job's process group. -See Job Control below for the format of \fIjob\fP. -.\"}}} -.\"{{{ kill -l [exit-status ...] -.IP "\fBkill \-l\fP [\fIexit-status\fP ...]" -Print the name of the signal that killed a process which exited with -the specified \fIexit-status\fPes. -If no arguments are specified, a list of all the signals, their numbers and -a short description of them are printed. -.\"}}} -.\"{{{ let [expression ...] -.IP "\fBlet\fP [\fIexpression\fP ...]" -Each expression is evaluated, see Arithmetic Expressions above. -If all expressions are successfully evaluated, the exit status -is 0 (1) if the last expression evaluated to non-zero (zero). -If an error occurs during the parsing or evaluation of an expression, -the exit status is greater than 1. -Since expressions may need to be -quoted, \fB((\fP \fIexpr\fP \fB))\fP is syntactic sugar for \fBlet -"\fP\fIexpr\fP\fB"\fP. -.\"}}} -.\"{{{ print [-nprsun | -R [-en]] [argument ...] -.IP "\fBprint\fP [\fB\-nprsu\fP\fIn\fP | \fB\-R\fP [\fB\-en\fP]] [\fIargument ...\fP]" -\fBPrint\fP prints its arguments on the standard output, separated by -spaces, and terminated with a newline. The \fB\-n\fP option suppresses -the newline. By default, certain C escapes are translated. These -include \eb, \ef, \en, \er, \et, \ev, and \e0### (# is an octal digit, of -which there may be 0 to 3). -\ec is equivalent to using the \fB\-n\fP option. \e expansion may be -inhibited with the \fB\-r\fP option. -The \fB\-s\fP option prints to the history file instead of standard output, -the \fB\-u\fP option prints to file descriptor \fIn\fP (\fIn\fP -defaults to 1 if omitted), and the \fB\-p\fP option prints to the co-process -(see Co-Processes above). -.sp -The \fB\-R\fP option is used to emulate, to some degree, the BSD echo -command, which does not process \e sequences unless the \fB\-e\fP option -is given. -As above, the \fB\-n\fP option suppresses the trailing newline. -.\"}}} -.\"{{{ pwd [-LP] -.IP "\fBpwd\fP [\fB\-LP\fP]" -Print the present working directory. -If \fB\-L\fP option is used or if the \fBphysical\fP option -(see \fBset\fP command below) isn't set, the logical path is printed -(\fIi.e.\fP, the path used to \fBcd\fP to the current directory). -If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option -is set, the path determined from the filesystem (by following \fB..\fP -directories to the root directory) is printed. -.\"}}} -.\"{{{ read [-prsun] [parameter ...] -.IP "\fBread\fP [\fB\-prsu\fP\fIn\fP] [\fIparameter ...\fP]" -Reads a line of input from standard input, separate the line into fields using -the \fBIFS\fP parameter (see Substitution above), and assign each field to the -specified parameters. -If there are more parameters than fields, the extra parameters are set to null, -or alternatively, if there are more fields than parameters, the last parameter -is assigned the remaining fields (inclusive of any separating spaces). -If no parameters are specified, the \fBREPLY\fP parameter is used. -If the input line ends in a backslash and the \fB\-r\fP option was not used, the -backslash and newline are stripped and more input is read. -If no input is read, \fBread\fP exits with a non-zero status. -.sp -The first parameter may have a question mark and a string appended to it, in -which case the string is used as a prompt (printed to standard error before -any input is read) if the input is a tty -(\fIe.g.\fP, \fBread nfoo?'number of foos: '\fP). -.sp -The \fB\-u\fP\fIn\fP and \fB\-p\fP options cause input to be read -from file descriptor \fIn\fP or the current co-process (see Co-Processes above -for comments on this), respectively. -If the \fB\-s\fP option is used, input is saved to the history file. -.\"}}} -.\"{{{ readonly [-p] [parameter[=value] ...] -.IP "\fBreadonly\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..." -Sets the readonly attribute of the named parameters. If values are given, -parameters are set to them before setting the attribute. -Once a parameter is made readonly, it cannot be unset and its value cannot -be changed. -.sp -If no parameters are specified, the names of all parameters with the readonly -attribute are printed one per line, unless the \fB\-p\fP option is used, -in which case \fBreadonly\fP commands defining all readonly -parameters, including their values, are printed. -.\"}}} -.\"{{{ return [status] -.IP "\fBreturn\fP [\fIstatus\fP]" -Returns from a function or \fB.\fP script, with exit status \fIstatus\fP. -If no \fIstatus\fP is given, the exit status of the last executed command -is used. -If used outside of a function or \fB.\fP script, it has the same effect -as \fBexit\fP. -Note that pdksh treats both profile and \fB$ENV\fP files as \fB.\fP scripts, -while the original Korn shell only treats profiles as \fB.\fP scripts. -.\"}}} -.\"{{{ set [+-abCefhkmnpsuvxX] [+-o [option]] [+-A name] [--] [arg ...] -.IP "\fBset\fP [\fB\(+-abCefhkmnpsuvxX\fP] [\fB\(+-o\fP [\fIoption\fP]] [\fB\(+-A\fP \fIname\fP] [\fB\-\-\fP] [\fIarg\fP ...]" -The set command can be used to set (\fB\-\fP) or clear (\fB+\fP) shell options, -set the positional parameters, or set an array parameter. -Options can be changed using the \fB\(+-o\fP \fIoption\fP syntax, -where \fIoption\fP is the long name of an option, or using -the \fB\(+-\fP\fIletter\fP syntax, where \fIletter\fP is the -option's single letter name (not all options have a single letter name). -The following table lists both option letters (if they exist) and long names -along with a description of what the option does. -.sp -.TS -expand; -afB lfB lw(3i). -\-A T{ -Sets the elements of the array parameter \fIname\fP to \fIarg\fP ...; -If \fB\-A\fP is used, the array is reset (\fIi.e.\fP, emptied) first; -if \fB+A\fP is used, the first N elements are set (where N is the number -of \fIarg\fPs), the rest are left untouched. -T} -\-a allexport T{ -all new parameters are created with the export attribute -T} -\-b notify T{ -Print job notification messages asynchronously, instead of just before the -prompt. -Only used if job control is enabled (\fB\-m\fP). -T} -\-C noclobber T{ -Prevent \fB>\fP redirection from overwriting existing files (\fB>|\fP must -be used to force an overwrite). -T} -\-e errexit T{ -Exit (after executing the \fBERR\fP trap) as soon as an error occurs or -a command fails (\fIi.e.\fP, exits with a non-zero status). -This does not apply to commands whose exit status is explicitly tested by a -shell construct such as \fBif\fP, \fBuntil\fP, \fBwhile\fP, \fB&&\fP or -\fB||\fP statements. -T} -\-f noglob T{ -Do not expand file name patterns. -T} -\-h trackall T{ -Create tracked aliases for all executed commands (see Aliases above). -On by default for non-interactive shells. -T} -\-i interactive T{ -Enable interactive mode \- this can only be set/unset when the shell is -invoked. -T} -\-k keyword T{ -Parameter assignments are recognized anywhere in a command. -T} -\-l login T{ -The shell is a login shell \- this can only be set/unset when the shell is -invoked (see Shell Startup above). -T} -\-m monitor T{ -Enable job control (default for interactive shells). -T} -\-n noexec T{ -Do not execute any commands \- useful for checking the syntax of scripts -(ignored if interactive). -T} -\-p privileged T{ -Set automatically if, when the shell starts, the read uid or gid does not -match the effective uid or gid, respectively. -See Shell Startup above for a description of what this -means. -T} --r restricted T{ -Enable restricted mode \(em this option can only be used when the shell is -invoked. See Shell Startup above for a description of what this -means. -T} -\-s stdin T{ -If used when the shell is invoked, commands are read from standard input. -Set automatically if the shell is invoked with no arguments. -.sp -When \fB\-s\fP is used in the \fBset\fP command, it causes the specified -arguments to be sorted before assigning them to the positional parameters -(or to array \fIname\fP, if \fB\-A\fP is used). -T} -\-u nounset T{ -Referencing of an unset parameter is treated as an error, unless -one of the \fB\-\fP, \fB+\fP or \fB=\fP modifiers is used. -T} -\-v verbose T{ -Write shell input to standard error as it is read. -T} -\-x xtrace T{ -Print commands and parameter assignments when they are executed, -preceded by the value of \fBPS4\fP. -T} -\-X markdirs T{ -Mark directories with a trailing \fB/\fP during file name generation. -T} - bgnice T{ -Background jobs are run with lower priority. -T} - braceexpand T{ -Enable brace expansion (aka, alternation). -T} - emacs T{ -Enable BRL emacs-like command line editing (interactive shells only); -see Emacs Interactive Input Line Editing. -T} - gmacs T{ -Enable gmacs-like (Gosling emacs) command line editing (interactive shells -only); -currently identical to emacs editing except that transpose (^T) acts -slightly differently. -T} - ignoreeof T{ -The shell will not exit on when end-of-file is read, \fBexit\fP must be used. -T} - nohup T{ -Do not kill running jobs with a \fBHUP\fP signal when a login shell exists. -Currently set by default, but this will change in the future to be compatible -with the original Korn shell (which doesn't have this option, but does -send the \fBHUP\fP signal). -T} - nolog T{ -No effect \- in the original Korn shell, this prevents function definitions -from being stored in the history file. -T} - physical T{ -Causes the \fBcd\fP and \fBpwd\fP commands to use `physical' -(\fIi.e.\fP, the filesystem's) \fB..\fP directories instead of `logical' -directories (\fIi.e.\fP, the shell handles \fB..\fP, which allows the user -to be obliveous of symlink links to directories). -Clear by default. Note that setting -this option does not effect the current value of the \fBPWD\fP parameter; -only the \fBcd\fP command changes \fBPWD\fP. -See the \fBcd\fP and \fBpwd\fP commands above for more details. -T} - posix T{ -Enable posix mode. See POSIX Mode above. -T} - vi T{ -Enable vi-like command line editing (interactive shells only). -T} - viraw T{ -No effect \- in the original Korn shell, unless viraw was set, the vi command -line mode would let the tty driver do the work until ESC (^[) was entered. -pdksh is always in viraw mode. -T} - vi-esccomplete T{ -In vi command line editing, do command / file name completion when -escape (^[) is entered in command mode. -T} - vi-show8 T{ -Prefix characters with the eighth bit set with `M-'. -If this option is not set, characters in the range -128-160 are printed as is, which may cause problems. -T} - vi-tabcomplete T{ -In vi command line editing, do command / file name completion when -tab (^I) is entered in insert mode. -T} -.TE -.sp -These options can also be used upon invocation of the shell. The current -set of options (with single letter names) can be found in the -parameter \fB\-\fP. -\fBset -o\fP with no option name will list all the options and whether each -is on or off; \fBset +o\fP will print the long names of all options that -are currently on. -.sp -Remaining arguments, if any, are positional parameters and are assigned, -in order, to the -positional parameters (\fIi.e.\fP, \fB1\fP, \fB2\fP, \fIetc.\fP). -If options are ended with \fB\-\-\fP and there are no remaining arguments, -all positional parameters are cleared. -If no options or arguments are given, then the values of all names are printed. -For unknown historical reasons, a lone \fB\-\fP option is treated specially: -it clears both the \fB\-x\fP and \fB\-v\fP options. -.\"}}} -.\"{{{ shift [number] -.IP "\fBshift\fP [\fInumber\fP]" -The positional parameters \fInumber\fP+1, \fInumber\fP+2 \fIetc.\fP\& are -renamed to \fB1\fP, \fB2\fP, \fIetc.\fP -\fInumber\fP defaults to 1. -.\"}}} -.\"{{{ test expression, [ expression ] -.IP "\fBtest\fP \fIexpression\fP" -.IP "\fB[\fP \fIexpression\fP \fB]\fP" -\fBtest\fP evaluates the \fIexpression\fP and returns zero status if -true, and 1 status if false and greater than 1 if there was an error. -It is normally used as the -condition command of \fBif\fP and \fBwhile\fP statements. -The following basic expressions are available: -.sp -.TS -afB ltw(2.8i). -\fIstr\fP T{ -\fIstr\fP has non-zero length. Note that there is the potential -for problems if \fIstr\fP turns out to be an operator (\fIe.g.\fP, \fB-r\fP) -- it is generally better to use a test like -.RS -\fB[ X"\fP\fIstr\fP\fB" != X ]\fP -.RE -instead (double quotes are used in case \fIstr\fP contains spaces or file -globing characters). -T} -\-r \fIfile\fP T{ -\fIfile\fP exists and is readable -T} -\-w \fIfile\fP T{ -\fIfile\fP exists and is writable -T} -\-x \fIfile\fP T{ -\fIfile\fP exists and is executable -T} -\-a \fIfile\fP T{ -\fIfile\fP exists -T} -\-e \fIfile\fP T{ -\fIfile\fP exists -T} -\-f \fIfile\fP T{ -\fIfile\fP is a regular file -T} -\-d \fIfile\fP T{ -\fIfile\fP is a directory -T} -\-c \fIfile\fP T{ -\fIfile\fP is a character special device -T} -\-b \fIfile\fP T{ -\fIfile\fP is a block special device -T} -\-p \fIfile\fP T{ -\fIfile\fP is a named pipe -T} -\-u \fIfile\fP T{ -\fIfile\fP's mode has setuid bit set -T} -\-g \fIfile\fP T{ -\fIfile\fP's mode has setgid bit set -T} -\-k \fIfile\fP T{ -\fIfile\fP's mode has sticky bit set -T} -\-s \fIfile\fP T{ -\fIfile\fP is not empty -T} -\-O \fIfile\fP T{ -\fIfile\fP's owner is the shell's effective user-ID -T} -\-G \fIfile\fP T{ -\fIfile\fP's group is the shell's effective group-ID -T} -\-h \fIfile\fP T{ -\fIfile\fP is a symbolic link -T} -\-H \fIfile\fP T{ -\fIfile\fP is a context dependent directory (only useful on HP-UX) -T} -\-L \fIfile\fP T{ -\fIfile\fP is a symbolic link -T} -\-S \fIfile\fP T{ -\fIfile\fP is a socket -T} -\-o \fIoption\fP T{ -shell \fIoption\fP is set (see \fBset\fP command above for list of options). -As a non-standard extension, if the option starts with a \fB!\fP, the test -is negated; the test always fails if option doesn't exist (thus -.RS -\fB[ -o \fP\fIfoo\fP \fB-o -o !\fP\fIfoo\fP \fB]\fP -.RE -returns true if and only if option \fIfoo\fP exists). -T} -\fIfile\fP \-nt \fIfile\fP T{ -first \fIfile\fP is newer than second \fIfile\fP -T} -\fIfile\fP \-ot \fIfile\fP T{ -first \fIfile\fP is older than second \fIfile\fP -T} -\fIfile\fP \-ef \fIfile\fP T{ -first \fIfile\fP is the same file as second \fIfile\fP -T} -\-t [\fIfd\fP] T{ -file descriptor is a tty device. -Default value of \fIfd\fP is 1. -T} -\fIstring\fP T{ -\fIstring\fP is not empty -T} -\-z \fIstring\fP T{ -\fIstring\fP is empty -T} -\-n \fIstring\fP T{ -\fIstring\fP is not empty -T} -\fIstring\fP = \fIstring\fP T{ -strings are equal -T} -\fIstring\fP == \fIstring\fP T{ -strings are equal -T} -\fIstring\fP != \fIstring\fP T{ -strings are not equal -T} -\fInumber\fP \-eq \fInumber\fP T{ -numbers compare equal -T} -\fInumber\fP \-ne \fInumber\fP T{ -numbers compare not equal -T} -\fInumber\fP \-ge \fInumber\fP T{ -numbers compare greater than or equal -T} -\fInumber\fP \-gt \fInumber\fP T{ -numbers compare greater than -T} -\fInumber\fP \-le \fInumber\fP T{ -numbers compare less than or equal -T} -\fInumber\fP \-lt \fInumber\fP T{ -numbers compare less than -T} -.TE -.sp -The above basic expressions, in which unary operators have precedence over -binary operators, may be combined with the following operators -(listed in increasing order of precedence): -.sp -.TS -afB l. -\fIexpr\fP \-o \fIexpr\fP logical or -\fIexpr\fP \-a \fIexpr\fP logical and -! \fIexpr\fP logical not -( \fIexpr\fP ) grouping -.TE -.sp -On operating systems not supporting \fB/dev/fd/\fP\fIn\fP devices -(where \fIn\fP is a file descriptor number), -the \fBtest\fP command will attempt to fake it for all tests that -operate on files (except the \fB-e\fP test). -I.e., \fB[ -w /dev/fd/2 ]\fP tests if file descriptor 2 is writable. -.sp -Note that some special rules are applied (courtesy of POSIX) if the -number of arguments to \fBtest\fP or \fB[\fP \&... \fB]\fP is less than -five: if leading \fB!\fP arguments can be stripped such that only one -argument remains then a string length test is performed (again, even if -the argument is a unary operator); -if leading \fB!\fP arguments can be stripped such that three -arguments remain and the second argument is a binary operator, then the -binary operation is performed (even if first argument is a unary -operator, including an unstripped \fB!\fP). -.sp -\fBNote:\fP A common mistake is to use \fBif [ $foo = bar ]\fP which -fails if parameter \fBfoo\fP is null or unset, if it has embedded spaces -(\fIi.e.\fP, \fBIFS\fP characters), or if it is a unary operator like \fB!\fP or -\fB\-n\fP. Use tests like \fBif [ "X$foo" = Xbar ]\fP instead. -.\"}}} -.\"{{{ times -.IP \fBtimes\fP -Print the accumulated user and system times used by the shell and by -processes which have exited that the shell started. -.\"}}} -.\"{{{ trap [handler signal ...] -.IP "\fBtrap\fP [\fIhandler\fP \fIsignal ...\fP]" -Sets trap handler that is to be executed when any of the specified signals -are received. -\fBHandler\fP is either a null string, indicating the signals are to -be ignored, a minus (\fB\-\fP), indicating that the default action is to -be taken for the signals (see signal(2 or 3)), or a string containing shell -commands to be evaluated and executed at the first opportunity (\fIi.e.\fP, -when the current command completes, or before printing the next \fBPS1\fP -prompt) after receipt of one of the signals. -\fBSignal\fP is the name of a signal (\fIe.g.\fP, PIPE or ALRM) or the number -of the signal (see \fBkill \-l\fP command above). -There are two special signals: \fBEXIT\fP (also known as \fB0\fP), which -is executed when the shell is about to exit, and \fBERR\fP which is -executed after an error occurs (an error is something that would cause -the shell to exit if the \fB\-e\fP or \fBerrexit\fP option were set \(em -see \fBset\fP command above). -\fBEXIT\fP handlers are executed in the environment of the last executed -command. -Note that for non-interactive shells, the trap handler cannot be changed for -signals that were ignored when the shell started. -.sp -With no arguments, \fBtrap\fP lists, as a series of \fBtrap\fP commands, -the current state of the traps that have been set since the shell started. -.sp -.\" todo: add these features (trap DEBUG, trap ERR/EXIT in function) -The original Korn shell's \fBDEBUG\fP trap and the handling of \fBERR\fP and -\fBEXIT\fP traps in functions are not yet implemented. -.\"}}} -.\"{{{ true -.IP \fBtrue\fP -A command that exits with a zero value. -.\"}}} -.\"{{{ typeset [[+-Ulrtux] [-L[n]] [-R[n]] [-Z[n]] [-i[n]] | -f [-tux]] [name[=value] ...] -.IP "\fBtypeset\fP [[\(+-Ulrtux] [\fB\-L\fP[\fIn\fP]] [\fB\-R\fP[\fIn\fP]] [\fB\-Z\fP[\fIn\fP]] [\fB\-i\fP[\fIn\fP]] | \fB\-f\fP [\fB\-tux\fP]] [\fIname\fP[\fB=\fP\fIvalue\fP] ...]" -Display or set parameter attributes. -With no \fIname\fP arguments, parameter attributes are displayed: if no options -arg used, the current attributes of all parameters are printed as typeset -commands; if an option is given (or \fB\-\fP with no option letter) -all parameters and their values with the specified attributes are printed; -if options are introduced with \fB+\fP, parameter values are not printed. -.sp -If \fIname\fP arguments are given, the attributes of the named parameters -are set (\fB\-\fP) or cleared (\fB+\fP). -Values for parameters may optionally be specified. -If typeset is used inside a function, any newly created parameters are local -to the function. -.sp -When \fB\-f\fP is used, typeset operates on the attributes of functions. -As with parameters, if no \fIname\fPs are given, functions are listed -with their values (\fIi.e.\fP, definitions) unless options are introduced with -\fB+\fP, in which case only the function names are reported. -.sp -.TS -expand; -afB lw(4.5i). -\-L\fIn\fP T{ -Left justify attribute: \fIn\fP specifies the field width. -If \fIn\fP is not specified, the current width of a parameter (or the -width of its first assigned value) is used. -Leading white space (and zeros, if used with the \fB\-Z\fP option) is stripped. -If necessary, values are either truncated or space padded to fit the -field width. -T} -\-R\fIn\fP T{ -Right justify attribute: \fIn\fP specifies the field width. -If \fIn\fP is not specified, the current width of a parameter (or the -width of its first assigned value) is used. -Trailing white space are stripped. -If necessary, values are either stripped of leading characters -or space padded to make them fit the field width. -T} -\-Z\fIn\fP T{ -Zero fill attribute: if not combined with \fB\-L\fP, this is the -same as \fB\-R\fP, except zero padding is used instead of space padding. -T} -\-i\fIn\fP T{ -integer attribute: -\fIn\fP specifies the base to use when displaying the integer -(if not specified, the base given in the first assignment is used). -Parameters with this attribute may be assigned values containing -arithmetic expressions. -T} -\-U T{ -unsigned integer attribute: integers are printed as unsigned values -(only useful when combined with the \fB\-i\fP option). -This option is not in the original Korn shell. -T} -\-f T{ -Function mode: display or set functions and their attributes, instead of -parameters. -T} -\-l T{ -Lower case attribute: all upper case characters in values are converted to -lower case. -(In the original Korn shell, this parameter meant `long integer' when used -with the \fB\-i\fP option). -T} -\-r T{ -Readonly attribute: parameters with the this attribute may not be assigned to -or unset. -Once this attribute is set, it can not be turned off. -T} -\-t T{ -Tag attribute: has no meaning to the shell; provided for application use. -.sp -For functions, \fB\-t\fP is the trace attribute. -When functions with the trace attribute are executed, the \fBxtrace\fP (\fB\-x\fP) shell option is temporarily turned on. -T} -\-u T{ -Upper case attribute: all lower case characters in values are converted to -upper case. -(In the original Korn shell, this parameter meant `unsigned integer' when used -with the \fB\-i\fP option, which meant upper case letters would never be used -for bases greater than 10. See the \fB\-U\fP option). -.sp -For functions, \fB\-u\fP is the undefined attribute. See Functions above -for the implications of this. -T} -\-x T{ -Export attribute: parameters (or functions) are placed in the environment of -any executed commands. Exported functions are not implemented yet. -T} -.TE -.\"}}} -.\"{{{ ulimit [-acdfHlmnpsStvw] [value] -.IP "\fBulimit\fP [\fB\-acdfHlmnpsStvw\fP] [\fIvalue\fP]" -Display or set process limits. -If no options are used, the file size limit (\fB\-f\fP) is assumed. -\fBvalue\fP, if specified, may be either be an arithmetic expression or the -word \fBunlimited\fP. -The limits affect the shell and any processes created by the shell after -a limit is imposed. -Note that some systems may not allow limits to be increased once they -are set. -Also note that the types of limits available are system dependent \- some -systems have only the \fB\-f\fP limit. -.RS -.IP \fB\-a\fP -Displays all limits; unless \fB\-H\fP is used, soft limits are displayed. -.IP \fB\-H\fP -Set the hard limit only (default is to set both hard and soft limits). -.IP \fB\-S\fP -Set the soft limit only (default is to set both hard and soft limits). -.IP \fB\-c\fP -Impose a size limit of \fIn\fP blocks on the size of core dumps. -.IP \fB\-d\fP -Impose a size limit of \fIn\fP kbytes on the size of the data area. -.IP \fB\-f\fP -Impose a size limit of \fIn\fP blocks on files written by the shell and -its child processes (files of any size may be read). -.IP \fB\-l\fP -Impose a limit of \fIn\fP kbytes on the amount of locked (wired) physical -memory. -.IP \fB\-m\fP -Impose a limit of \fIn\fP kbytes on the amount of physical memory used. -.IP \fB\-n\fP -Impose a limit of \fIn\fP file descriptors that can be open at once. -.IP \fB\-p\fP -Impose a limit of \fIn\fP processes that can be run by the user at any one -time. -.IP \fB\-s\fP -Impose a size limit of \fIn\fP kbytes on the size of the stack area. -.IP \fB\-t\fP -Impose a time limit of \fIn\fP cpu seconds to be used by each process. -.IP \fB\-v\fP -Impose a limit of \fIn\fP kbytes on the amount of virtual memory used; -on some systems this is the maximum allowable virtual address (in bytes, -not kbytes). -.IP \fB\-w\fP -Impose a limit of \fIn\fP kbytes on the amount of swap space used. -.PP -As far as \fBulimit\fP is concerned, a block is 512 bytes. -.RE -.\"}}} -.\"{{{ umask [-S] [mask] -.IP "\fBumask\fP [\fB\-S\fP] [\fImask\fP]" -.RS -Display or set the file permission creation mask, or umask (see \fIumask\fP(2)). -If the \fB\-S\fP option is used, the mask displayed or set is symbolic, -otherwise it is an octal number. -.sp -Symbolic masks are like those used by \fIchmod\fP(1): -.RS -[\fBugoa\fP]{{\fB=+-\fP}{\fBrwx\fP}*}+[\fB,\fP...] -.RE -in which the first group of characters is the \fIwho\fP part, the second -group is the \fIop\fP part, and the last group is the \fIperm\fP part. -The \fIwho\fP part specifies which part of the umask is to be modified. -The letters mean: -.RS -.IP \fBu\fP -the user permissions -.IP \fBg\fP -the group permissions -.IP \fBo\fP -the other permissions (non-user, non-group) -.IP \fBa\fP -all permissions (user, group and other) -.RE -.sp -The \fIop\fP part indicates how the \fIwho\fP permissions are to be modified: -.RS -.IP \fB=\fP -set -.IP \fB+\fP -added to -.IP \fB\-\fP -removed from -.RE -.sp -The \fIperm\fP part specifies which permissions are to be set, added or removed: -.RS -.IP \fBr\fP -read permission -.IP \fBw\fP -write permission -.IP \fBx\fP -execute permission -.RE -.sp -When symbolic masks are used, they describe what permissions may -be made available (as opposed to octal masks in which a set bit means -the corresponding bit is to be cleared). -Example: `ug=rwx,o=' sets the mask so files will not be readable, writable -or executable by `others', and is equivalent (on most systems) to the octal -mask `07'. -.RE -.\"}}} -.\"{{{ unalias [-adt] name ... -.IP "\fBunalias\fP [\fB\-adt\fP] [\fIname1\fP ...]" -The aliases for the given names are removed. -If the \fB\-a\fP option is used, all aliases are removed. -If the \fB\-t\fP or \fB\-d\fP options are used, the indicated operations -are carried out on tracked or directory aliases, respectively. -.\"}}} -.\"{{{ unset [-fv] parameter ... -.IP "\fBunset\fP [\fB\-fv\fP] \fIparameter\fP ..." -Unset the named parameters (\fB\-v\fP, the default) or functions (\fB\-f\fP). -The exit status is non-zero if any of the parameters were already unset, -zero otherwise. -.\"}}} -.\"{{{ wait [job] -.IP "\fBwait\fP [\fIjob\fP]" -Wait for the specified job(s) to finish. -The exit status of wait is that of the last specified job: -if the last job is killed by a signal, the exit status is 128 + the -number of the signal (see \fBkill \-l\fP \fIexit-status\fP above); if the last -specified job can't be found (because it never existed, or had already -finished), the exit status of wait is 127. -See Job Control below for the format of \fIjob\fP. -\fBWait\fP will return if a signal for which a trap has been set is received, -or if a HUP, INT or QUIT signal is received. -.sp -If no jobs are specified, \fBwait\fP waits for all currently running jobs -(if any) to finish and exits with a zero status. -If job monitoring is enabled, the completion status of jobs is -printed (this is not the case when jobs are explicitly specified). -.\"}}} -.\"{{{ whence [-pv] [name ...] -.IP "\fBwhence\fP [\fB\-pv\fP] [name ...]" -For each name, the type of command is listed (reserved word, built-in, alias, -function, tracked alias or executable). -If the \fB\-p\fP option is used, a path search done even if \fIname\fP -is a reserved word, alias, \fIetc.\fP -Without the \fB\-v\fP option, \fBwhence\fP is similar to \fBcommand \-v\fP -except that \fBwhence\fP will find reserved words and won't print aliases -as alias commands; -with the \fB\-v\fP option, \fBwhence\fP is the same as \fBcommand \-V\fP. -Note that for \fBwhence\fP, the \fB\-p\fP option does not affect the search -path used, as it does for \fBcommand\fP. -If the type of one or more of the names could not be determined, the -exit status is non-zero. -.\"}}} -.\"}}} -.\"{{{ job control (and its built-in commands) -.SS "Job Control" -Job control refers to the shell's ability to monitor and control \fBjobs\fP, -which are processes or groups of processes created for commands or pipelines. -At a minimum, the shell keeps track of the status of the background -(\fIi.e.\fP, asynchronous) jobs that currently exist; this information can be -displayed using the \fBjobs\fP command. -If job control is fully enabled (using \fBset \-m\fP or -\fBset \-o monitor\fP), as it is for interactive shells, -the processes of a job are placed in their own process group, -foreground jobs can be stopped by typing the suspend character from the -terminal (normally ^Z), -jobs can be restarted in either the foreground -or background, using the \fBfg\fP and \fBbg\fP commands, respectively, -and the state of the terminal is saved or restored when a foreground -job is stopped or restarted, respectively. -.sp -Note that only commands that create processes (\fIe.g.\fP, -asynchronous commands, subshell commands, and non-built-in, -non-function commands) can be stopped; commands like \fBread\fP cannot be. -.sp -When a job is created, it is assigned a job-number. -For interactive shells, this number is printed inside \fB[\fP..\fB]\fP, -followed by the process-ids of the processes in the job when an asynchronous -command is run. -A job may be referred to in \fBbg\fP, \fBfg\fP, \fBjobs\fP, \fBkill\fP and -\fBwait\fP commands either by the process id of the last process in the -command pipeline (as stored in the \fB$!\fP parameter) or by prefixing the -job-number with a percent sign (\fB%\fP). -Other percent sequences can also be used to refer to jobs: -.sp -.TS -expand; -afB lw(4.5i). -%+ T{ -The most recently stopped job, or, if there are no stopped jobs, the oldest -running job. -T} -%%\fR, \fP% T{ -Same as \fB%+\fP. -T} -%\- T{ -The job that would be the \fB%+\fP job, if the later did not exist. -T} -%\fIn\fP T{ -The job with job-number \fIn\fP. -T} -%?\fIstring\fP T{ -The job containing the string \fIstring\fP (an error occurs if multiple jobs -are matched). -T} -%\fIstring\fP T{ -The job starting with string \fIstring\fP (an error occurs if multiple jobs -are matched). -T} -.TE -.sp -When a job changes state (\fIe.g.\fP, a background job finishes or foreground -job is stopped), the shell prints the following status information: -.RS -\fB[\fP\fInumber\fP\fB]\fP \fIflag status command\fP -.RE -where -.IP "\ \fInumber\fP" -is the job-number of the job. -.IP "\ \fIflag\fP" -is \fB+\fP or \fB-\fP if the job is the \fB%+\fP or \fB%-\fP job, -respectively, or space if it is neither. -.IP "\ \fIstatus\fP" -indicates the current state of the job and can be -.RS -.IP "\fBRunning\fP" -the job has neither stopped or exited (note that running does not -necessarily mean consuming CPU time \(em the process could be blocked waiting -for some event). -.IP "\fBDone\fP [\fB(\fP\fInumber\fP\fB)\fP]" -the job exited. \fInumber\fP is the exit status of the job, which is -omitted if the status is zero. -.IP "\fBStopped\fP [\fB(\fP\fIsignal\fP\fB)\fP]" -the job was stopped by the indicated \fIsignal\fP (if no signal is given, -the job was stopped by SIGTSTP). -.IP "\fIsignal-description\fP [\fB(core dumped)\fP]" -the job was killed by a signal (\fIe.g.\fP, Memory\ fault, -Hangup, \fIetc.\fP \(em use -\fBkill \-l\fP for a list of signal descriptions). -The \fB(core\ dumped)\fP message indicates the process created a core file. -.RE -.IP "\ \fIcommand\fP" -is the command that created the process. -If there are multiple processes in the job, then each process will -have a line showing its \fIcommand\fP and possibly its \fIstatus\fP, -if it is different from the status of the previous process. -.PP -When an attempt is made to exit the shell while there are jobs in -the stopped state, the shell warns the user that there are stopped jobs -and does not exit. -If another attempt is immediately made to exit the shell, the stopped -jobs are sent a \fBHUP\fP signal and the shell exits. -Similarly, if the \fBnohup\fP option is not set and there are running -jobs when an attempt is made to exit a login shell, the shell warns the -user and does not exit. -If another attempt is immediately made to exit the shell, the running -jobs are sent a \fBHUP\fP signal and the shell exits. -.\"}}} -.\"{{{ Emacs Interactive Input Line Editing -.SS "Emacs Interactive Input Line Editing" -When the \fBemacs\fP option is set, interactive input line editing is -enabled. \fBWarning\fP: This mode is slightly different from the emacs -mode in the original Korn shell and the 8th bit is stripped in emacs mode. -In this mode various editing commands (typically bound to one or more -control characters) cause immediate actions without waiting for a -new-line. Several editing commands are bound to particular control -characters when the shell is invoked; these bindings can be changed -using the following commands: -.\"{{{ bind -.IP \fBbind\fP -The current bindings are listed. -.\"}}} -.\"{{{ bind string=[editing-command] -.IP "\fBbind\fP \fIstring\fP\fB=\fP[\fIediting-command\fP]" -The specified editing command is bound to the given \fBstring\fP, which -should consist of a control character (which may be written using caret -notation \fB^\fP\fIX\fP), optionally preceded by one of the two prefix -characters. Future input of the \fIstring\fP will cause the editing -command to be immediately invoked. Note that although only two prefix -characters (usually ESC and ^X) are supported, some multi-character -sequences can be supported. The following binds the arrow keys on -an ANSI terminal, or xterm (these are in the default bindings). Of course -some escape sequences won't work out quite this nicely: -.sp -.RS -\fBbind '^[['=prefix\-2 -.br -bind '^XA'=up\-history -.br -bind '^XB'=down\-history -.br -bind '^XC'=forward\-char -.br -bind '^XD'=backward\-char\fP -.RE -.\"}}} -.\"{{{ bind -l -.IP "\fBbind \-l\fP" -Lists the names of the functions to which keys may be bound. -.\"}}} -.\"{{{ bind -m string=[substitute] -.IP "\fBbind \-m\fP \fIstring\fP\fB=\fP[\fIsubstitute\fP]" -The specified input \fIstring\fP will afterwards be immediately -replaced by the given \fIsubstitute\fP string, which may contain -editing commands. -.\"}}} -.PP -The following is a list of editing commands available. -Each description starts with the name of the command, -a \fIn\fP, if the command can be prefixed with a count, -and any keys the command is bound to by default (written using -caret notation, \fIe.g.\fP, ASCII ESC character is written as ^[). -A count prefix for a command is entered using the sequence -\fB^[\fP\fIn\fP, where \fIn\fP is a sequence of 1 or more digits; -unless otherwise specified, if a count is omitted, it defaults to 1. -Note that editing command names are -used only with the \fBbind\fP command. Furthermore, many editing -commands are useful only on terminals with a visible cursor. The -default bindings were chosen to resemble corresponding EMACS key -bindings. The users tty characters (\fIe.g.\fP, ERASE) are bound to -reasonable substitutes and override the default bindings. -.\"{{{ abort ^G -.IP "\fBabort ^G\fP" -Useful as a response to a request for a \fBsearch-history\fP pattern in -order to abort the search. -.\"}}} -.\"{{{ auto-insert n -.IP "\fBauto-insert\fP \fIn\fP" -Simply causes the character to appear as literal input. Most ordinary -characters are bound to this. -.\"}}} -.\"{{{ backward-char n ^B -.IP "\fBbackward-char\fP \fIn\fP \fB^B\fP" -Moves the cursor backward \fIn\fP characters. -.\"}}} -.\"{{{ backward-word n ^[B -.IP "\fBbackward-word\fP \fIn\fP \fB^[B\fP" -Moves the cursor backward to the beginning of a word; words consist -of alphanumerics, underscore (_) and dollar ($). -.\"}}} -.\"{{{ beginning-of-history ^[< -.IP "\fBbeginning-of-history ^[<\fP" -Moves to the beginning of the history. -.\"}}} -.\"{{{ beginning-of-line ^A -.IP "\fBbeginning-of-line ^A\fP" -Moves the cursor to the beginning of the edited input line. -.\"}}} -.\"{{{ capitalize-word n ^[c, ^[C -.IP "\fBcapitalize-word\fP \fIn\fP \fB^[c\fP, \fB^[C\fP" -Uppercase the first character in the next \fIn\fP words, -leaving the cursor past the end of the last word. -.\"}}} -.\"{{{ comment ^[# -If the current line does not begin with a comment character, one -is added at the beginning of the line and the line is entered (as if -return had been pressed), otherwise the existing comment characters -are removed and the cursor is placed at the beginning of the line. -.\"}}} -.\"{{{ complete ^[^[ -.IP "\fBcomplete ^[^[\fP" -Automatically completes as much as is unique of the command name -or the file name containing the cursor. If the entire remaining command -or file name is unique a space is printed after its completion, unless -it is a directory name in which case \fB/\fP is appended. If there is -no command or file name with the current partial word as its -prefix, a bell character is output (usually causing a audio beep). -.\"}}} -.\"{{{ complete-command ^X^[ -.IP "\fBcomplete-command ^X^[\fP" -Automatically completes as much as is unique of the command name -having the partial word up to the cursor as its prefix, as in the -\fBcomplete\fP command described above. -.\"}}} -.\"{{{ complete-file ^[^X -.IP "\fBcomplete-file ^[^X\fP" -Automatically completes as much as is unique of the file name having -the partial word up to the cursor as its prefix, as in the -\fBcomplete\fP command described above. -.\"}}} -.\"{{{ complete-list ^[= -.IP "\fBcomplete-list ^[=\fP" -List the possible completions for the current word. -.\"}}} -.\"{{{ delete-char-backward n ERASE, ^?, ^H -.IP "\fBdelete-char-backward\fP \fIn\fP \fBERASE\fP, \fB^?\fP, \fB^H\fP" -Deletes \fIn\fP characters before the cursor. -.\"}}} -.\"{{{ delete-char-forward n -.IP "\fBdelete-char-forward\fP \fIn\fP" -Deletes \fIn\fP characters after the cursor. -.\"}}} -.\"{{{ delete-word-backward n ^[ERASE, ^[^?, ^[^H, ^[h -.IP "\fBdelete-word-backward\fP \fIn\fP \fB^[ERASE\fP, \fB^[^?\fP, \fB^[^H\fP, \fB^[h\fP" -Deletes \fIn\fP words before the cursor. -.\"}}} -.\"{{{ delete-word-forward n ^[d -.IP "\fBdelete-word-forward\fP \fIn\fP \fB^[d\fP" -Deletes characters after the cursor up to the end of \fIn\fP words. -.\"}}} -.\"{{{ down-history n ^N -.IP "\fBdown-history\fP \fIn\fP \fB^N\fP" -Scrolls the history buffer forward \fIn\fP lines (later). Each input line -originally starts just after the last entry in the history buffer, so -\fBdown-history\fP is not useful until either \fBsearch-history\fP or -\fBup-history\fP has been performed. -.\"}}} -.\"{{{ downcase-word n ^[L, ^[l -.IP "\fBdowncase-word\fP \fIn\fP \fB^[L\fP, \fB^[l\fP" -Lowercases the next \fIn\fP words. -.\"}}} -.\"{{{ end-of-history ^[> -.IP "\fBend-of-history ^[>\fP" -Moves to the end of the history. -.\"}}} -.\"{{{ end-of-line ^E -.IP "\fBend-of-line ^E\fP" -Moves the cursor to the end of the input line. -.\"}}} -.\"{{{ eot ^_ -.IP "\fBeot ^_\fP" -Acts as an end-of-file; this is useful because edit-mode input disables -normal terminal input canonicalization. -.\"}}} -.\"{{{ eot-or-delete n ^D -.IP "\fBeot-or-delete\fP \fIn\fP \fB^D\fP" -Acts as eot if alone on a line; otherwise acts as delete-char-forward. -.\"}}} -.\"{{{ error -.IP "\fBerror\fP" -Error (ring the bell). -.\"}}} -.\"{{{ exchange-point-and-mark ^X^X -.IP "\fBexchange-point-and-mark ^X^X\fP" -Places the cursor where the mark is, and sets the mark to where the -cursor was. -.\"}}} -.\"{{{ expand-file ^[* -.IP "\fBexpand-file ^[*\fP" -Appends a * to the current word and replaces the word with -the result of performing file globbing on the word. -If no files match the pattern, the bell is rung. -.\"}}} -.\"{{{ forward-char n ^F -.IP "\fBforward-char\fP \fIn\fP \fB^F\fP" -Moves the cursor forward \fIn\fP characters. -.\"}}} -.\"{{{ forward-word n ^[f -.IP "\fBforward-word\fP \fIn\fP \fB^[f\fP" -Moves the cursor forward to the end of the \fIn\fPth word. -.\"}}} -.\"{{{ goto-history n ^[g -.IP "\fBgoto-history\fP \fIn\fP \fB^[g\fP" -Goes to history number \fIn\fP. -.\"}}} -.\"{{{ kill-line KILL -.IP "\fBkill-line KILL\fP" -Deletes the entire input line. -.\"}}} -.\"{{{ kill-region ^W -.IP "\fBkill-region ^W\fP" -Deletes the input between the cursor and the mark. -.\"}}} -.\"{{{ kill-to-eol n ^K -.IP "\fBkill-to-eol\fP \fIn\fP \fB^K\fP" -Deletes the input from the cursor to the end of the line if \fIn\fP is -not specified, otherwise deletes characters between the cursor and -column \fIn\fP. -.\"}}} -.\"{{{ list ^[? -.IP "\fBlist ^[?\fP" -Prints a sorted, columnated list of command names or file names -(if any) that can complete the partial word containing the cursor. -Directory names have \fB/\fP appended to them. -.\"}}} -.\"{{{ list-command ^X? -.IP "\fBlist-command ^X?\fP" -Prints a sorted, columnated list of command names (if any) that -can complete the partial word containing the cursor. -.\"}}} -.\"{{{ list-file ^X^Y -.IP "\fBlist-file ^X^Y\fP" -Prints a sorted, columnated list of file names (if any) that can -complete the partial word containing the cursor. File type indicators -are appended as described under \fBlist\fP above. -.\"}}} -.\"{{{ newline ^J and ^M -.IP "\fBnewline ^J\fP, \fB^M\fP" -Causes the current input line to be processed by the shell. The -current cursor position may be anywhere on the line. -.\"}}} -.\"{{{ newline-and-next ^O -.IP "\fBnewline-and-next ^O\fP" -Causes the current input line to be processed by the shell, and -the next line from history becomes the current line. This is -only useful after an up-history or search-history. -.\"}}} -.\"{{{ no-op QUIT -.IP "\fBno-op QUIT\fP" -This does nothing. -.\"}}} -.\"{{{ prefix-1 ^[ -.IP "\fBprefix-1 ^[\fP" -Introduces a 2-character command sequence. -.\"}}} -.\"{{{ prefix-2 ^X and ^[[ -.IP "\fBprefix-2 ^X\fP" -.IP "\fBprefix-2 ^[[\fP" -Introduces a 2-character command sequence. -.\"}}} -.\"{{{ prev-hist-word ^[. ^[_ -.IP "\fBprev-hist-word\fP \fIn\fP \fB^[.\fP, \fB^[_\fP" -The last (\fIn\fPth) word of the previous command is inserted at the cursor. -.\"}}} -.\"{{{ quote ^^ -.IP "\fBquote ^^\fP" -The following character is taken literally rather than as an editing -command. -.\"}}} -.\"{{{ redraw ^L -.IP "\fBredraw ^L\fP" -Reprints the prompt string and the current input line. -.\"}}} -.\"{{{ search-character-backward n ^[^] -.IP "\fBsearch-character-backward\fP \fIn\fP \fB^[^]\fP" -Search backward in the current line for the \fIn\fPth occurance of the -next character typed. -.\"}}} -.\"{{{ search-character-forward n ^] -.IP "\fBsearch-character-forward\fP \fIn\fP \fB^]\fP" -Search forward in the current line for the \fIn\fPth occurance of the -next character typed. -.\"}}} -.\"{{{ search-history ^R -.IP "\fBsearch-history ^R\fP" -Enter incremental search mode. The internal history list is searched -backwards for commands matching the input. An initial \fB^\fP in the -search string anchors the search. The abort key will leave search mode. -Other commands will be executed after leaving search mode. Successive -\fBsearch-history\fP commands continue searching backward to the next -previous occurrence of the pattern. The history buffer retains only a -finite number of lines; the oldest are discarded as necessary. -.\"}}} -.\"{{{ set-mark-command ^[<space> -.IP "\fBset-mark-command ^[\fP<space>" -Set the mark at the cursor position. -.\"}}} -.\"{{{ stuff -.IP "\fBstuff\fP" -On systems supporting it, pushes the bound character back onto the -terminal input where it may receive special processing by the terminal -handler. This is useful for the BRL \fB^T\fP mini-systat feature, for -example. -.\"}}} -.\"{{{ stuff-reset -.IP "\fBstuff-reset\fP" -Acts like \fBstuff\fP, then aborts input the same as an interrupt. -.\"}}} -.\"{{{ transport-chars ^T -.IP "\fBtranspose-chars ^T\fP" -If at the end of line, or if the \fBgmacs\fP option is set, -this exchanges the two previous characters; otherwise, it -exchanges the previous and current characters and moves the cursor -one character to the right. -.\"}}} -.\"{{{ up-history n ^P -.IP "\fBup-history\fP \fIn\fP \fB^P\fP" -Scrolls the history buffer backward \fIn\fP lines (earlier). -.\"}}} -.\"{{{ upcase-word n ^[U, ^[u -.IP "\fBupcase-word\fP \fIn\fP \fB^[U\fP, \fB^[u\fP" -Uppercases the next \fIn\fP words. -.\"}}} -.\"{{{ version ^V -.IP "\fBversion ^V\fP" -Display the version of ksh. The current edit buffer is restored as soon -as any key is pressed (the key is then processed, unless it is a space). -.\"}}} -.\"{{{ yank ^Y -.IP "\fByank ^Y\fP" -Inserts the most recently killed text string at the current cursor position. -.\"}}} -.\"{{{ yank-pop ^[y -.IP "\fByank-pop ^[y\fP" -Immediately after a \fByank\fP, replaces the inserted text string with -the next previous killed text string. -.\"}}} -.\"}}} -.\"{{{ Vi Interactive Input Line Editing -.\"{{{ introduction -.SS "Vi Interactive Input Line Editing" -The vi command line editor in ksh has basically the same commands as the -vi editor (see \fIvi\fP(1)), with the following exceptions: -.nr P2 \n(PD -.IP \ \ \(bu -you start out in insert mode, -.IP \ \ \(bu -there are file name and command completion commands -(\fB=\fP, \fB\e\fP, \fB*\fP, \fB^X\fP, \fB^E\fP, \fB^F\fP and, -optionally, \fB<tab>\fP), -.IP \ \ \(bu -the \fB_\fP command is different (in ksh it is the last argument command, -in vi it goes to the start of the current line), -.IP \ \ \(bu -the \fB/\fP and \fBG\fP commands move in the opposite direction as the \fBj\fP -command -.IP \ \ \(bu -and commands which don't make sense in a single line editor are not available -(\fIe.g.\fP, screen movement commands, ex \fB:\fP commands, \fIetc.\fP). -.nr PD \n(P2 -.LP -Note that the \fB^X\fP stands for control-X; also \fB<esc>\fP, \fB<space>\fP -and \fB<tab>\fP are used for escape, space and tab, respectively (no kidding). -.\"}}} -.\"{{{ modes -.PP -Like vi, there are two modes: insert mode and command mode. -In insert mode, most characters are simply put in the buffer at the -current cursor position as they are typed, however, some characters -are treated specially. -In particular, the following characters are taken from current tty settings -(see \fIstty\fP(1)) and have their usual meaning (normal values are in -parentheses): -kill (\fB^U\fP), erase (\fB^?\fP), werase (\fB^W\fP), eof (\fB^D\fP), -intr (\fB^C\fP) and quit (\fB^\e\fP). -In addition to the above, the following characters are also treated -specially in insert mode: -.TS -expand; -afB lw(4.5i). -^H T{ -erases previous character -T} -^V T{ -literal next: the next character typed is not treated specially (can be -used to insert the characters being described here) -T} -^J ^M T{ -end of line: the current line is read, parsed and executed by the shell -T} -<esc> T{ -puts the editor in command mode (see below) -T} -^E T{ -command and file name enumeration (see below) -T} -^F T{ -command and file name completion (see below). -If used twice in a row, the list of possible completions is displayed; -if used a third time, the completion is undone. -T} -^X T{ -command and file name expansion (see below) -T} -<tab> T{ -optional file name and command completion (see \fB^F\fP above), enabled with -\fBset \-o vi-tabcomplete\fP -T} -.TE -.\"}}} -.\"{{{ display -.PP -If a line is longer that the screen width (see \fBCOLUMNS\fP parameter), -a \fB>\fP, \fB+\fP or \fB<\fP character is displayed in the last column -indicating that there are more characters after, before and after, or -before the current position, respectively. -The line is scrolled horizontally as necessary. -.\"}}} -.\"{{{ command mode -.PP -In command mode, each character is interpreted as a command. -Characters that don't correspond to commands, are illegal combinations of -commands or are commands that can't be carried out all cause beeps. -In the following command descriptions, a \fIn\fP indicates the -command may be prefixed by a number (\fIe.g.\fP, \fB10l\fP moves right 10 -characters); if no number prefix is used, \fIn\fP is assumed to be 1 -unless otherwise specified. -The term `current position' refers to the position between the cursor -and the character preceding the cursor. -A `word' is a sequence of letters, digits and underscore characters or a -sequence of non-letter, non-digit, non-underscore, non-white-space characters -(\fIe.g.\fP, ab2*&^ contains two words) and a `big-word' is a sequence of -non-white-space characters. -.\"{{{ Special ksh vi commands -.IP "Special ksh vi commands" -The following commands are not in, or are different from, the normal vi file -editor: -.RS -.IP "\fIn\fP\fB_\fP" -insert a space followed by the \fIn\fPth big-word from the last command in the -history at the current position and enter insert mode; if \fIn\fP is not -specified, the last word is inserted. -.IP "\fB#\fP" -insert the comment character (\fB#\fP) at the start of the current line and -return the line to the shell (equivalent to \fBI#^J\fP). -.IP "\fIn\fP\fBg\fP" -like \fBG\fP, except if \fIn\fP is not specified, it goes to the most recent -remembered line. -.IP "\fIn\fP\fBv\fP" -edit line \fIn\fP using the vi editor; -if \fIn\fP is not specified, the current line is edited. -The actual command executed is -`\fBfc \-e ${VISUAL:-${EDITOR:-vi}}\fP \fIn\fP'. -.IP "\fB*\fP and \fB^X\fP" -command or file name expansion is applied to the current big-word -(with an appended *, if the word contains no file globing characters) - the -big-word is replaced with the resulting words. -If the current big-word is the first on the line (or follows one -of the following characters: \fB;\fP, \fB|\fP, \fB&\fP, \fB(\fP, \fB)\fP) -and does not contain a slash (\fB/\fP) then command expansion is done, -otherwise file name expansion is done. -Command expansion will match the big-word against all aliases, functions -and built-in commands as well as any executable files found by searching -the directories in the \fBPATH\fP parameter. -File name expansion matches the big-word against the files in the -current directory. -After expansion, the cursor is placed just past the last word and the editor -is in insert mode. -.IP "\fIn\fP\fB\e\fP, \fIn\fP\fB^F\fP, \fIn\fP\fB<tab>\fP and \fIn\fP\fB<esc>\fP" -command/file name completion: -replace the current big-word with the longest unique -match obtained after performing command/file name expansion. -\fB<tab>\fP is only recognized if the \fBvi-tabcomplete\fP option is set, -while \fB<esc>\fP is only recognized if the \fBvi-esccomplete\fP option -is set (see \fBset \-o\fP). -If \fIn\fP is specified, the \fIn\fPth possible -completion is selected (as reported by the command/file name enumeration -command). -.IP "\fB=\fP and \fB^E\fP" -command/file name enumeration: list all the commands or files that match -the current big-word. -.IP "\fB^V\fP" -display the version of pdksh; it is displayed until another key is pressed -(this key is ignored). -.IP "\fB@\fP\fIc\fP" -macro expansion: execute the commands found in the alias _\fIc\fP. -.RE -.\"}}} -.\"{{{ Intra-line movement commands -.IP "Intra-line movement commands" -.RS -.IP "\fIn\fP\fBh\fP and \fIn\fP\fB^H\fP" -move left \fIn\fP characters. -.IP "\fIn\fP\fBl\fP and \fIn\fP\fB<space>\fP" -move right \fIn\fP characters. -.IP "\fB0\fP" -move to column 0. -.IP "\fB^\fP" -move to the first non white-space character. -.IP "\fIn\fP\fB|\fP" -move to column \fIn\fP. -.IP "\fB$\fP" -move to the last character. -.IP "\fIn\fP\fBb\fP" -move back \fIn\fP words. -.IP "\fIn\fP\fBB\fP" -move back \fIn\fP big-words. -.IP "\fIn\fP\fBe\fP" -move forward to the end the word, \fIn\fP times. -.IP "\fIn\fP\fBE\fP" -move forward to the end the big-word, \fIn\fP times. -.IP "\fIn\fP\fBw\fP" -move forward \fIn\fP words. -.IP "\fIn\fP\fBW\fP" -move forward \fIn\fP big-words. -.IP "\fB%\fP" -find match: the editor looks forward for the nearest parenthesis, -bracket or brace and then moves the to the matching parenthesis, bracket or -brace. -.IP "\fIn\fP\fBf\fP\fIc\fP" -move forward to the \fIn\fPth occurrence of the character \fIc\fP. -.IP "\fIn\fP\fBF\fP\fIc\fP" -move backward to the \fIn\fPth occurrence of the character \fIc\fP. -.IP "\fIn\fP\fBt\fP\fIc\fP" -move forward to just before the \fIn\fPth occurrence of the character \fIc\fP. -.IP "\fIn\fP\fBT\fP\fIc\fP" -move backward to just before the \fIn\fPth occurrence of the character \fIc\fP. -.IP "\fIn\fP\fB;\fP" -repeats the last \fBf\fP, \fBF\fP, \fBt\fP or \fBT\fP command. -.IP "\fIn\fP\fB,\fP" -repeats the last \fBf\fP, \fBF\fP, \fBt\fP or \fBT\fP command, but moves -in the opposite direction. -.RE -.\"}}} -.\"{{{ Inter-line movement commands -.IP "Inter-line movement commands" -.RS -.IP "\fIn\fP\fBj\fP and \fIn\fP\fB+\fP and \fIn\fP\fB^N\fP" -move to the \fIn\fPth next line in the history. -.IP "\fIn\fP\fBk\fP and \fIn\fP\fB-\fP and \fIn\fP\fB^P\fP" -move to the \fIn\fPth previous line in the history. -.IP "\fIn\fP\fBG\fP" -move to line \fIn\fP in the history; if \fIn\fP is not specified, the -number first remembered line is used. -.IP "\fIn\fP\fBg\fP" -like \fBG\fP, except if \fIn\fP is not specified, it goes to the most recent -remembered line. -.IP "\fIn\fP\fB/\fP\fIstring\fP" -search backward through the history for the \fIn\fPth line containing -\fIstring\fP; if \fIstring\fP starts with \fB^\fP, the remainder of the -string must appear at the start of the history line for it to match. -.IP "\fIn\fP\fB?\fP\fIstring\fP" -same as \fB/\fP, except it searches forward through the history. -.IP "\fIn\fP\fBn\fP" -search for the \fIn\fPth occurrence of the last search string; the -direction of the search is the same as the last search. -.IP "\fIn\fP\fBN\fP" -search for the \fIn\fPth occurrence of the last search string; the -direction of the search is the opposite of the last search. -.RE -.\"}}} -.\"{{{ Edit commands -.IP "Edit commands" -.RS -.IP "\fIn\fP\fBa\fP" -append text \fIn\fP times: goes into insert mode just after the current -position. -The append is only replicated if command mode is re-entered (\fIi.e.\fP, -<esc> is used). -.IP "\fIn\fP\fBA\fP" -same as \fBa\fP, except it appends at the end of the line. -.IP "\fIn\fP\fBi\fP" -insert text \fIn\fP times: goes into insert mode at the current -position. -The insertion is only replicated if command mode is re-entered (\fIi.e.\fP, -<esc> is used). -.IP "\fIn\fP\fBI\fP" -same as \fBi\fP, except the insertion is done just before the first non-blank -character. -.IP "\fIn\fP\fBs\fP" -substitute the next \fIn\fP characters (\fIi.e.\fP, delete the characters -and go into insert mode). -.IP "\fBS\fP" -substitute whole line: all characters from the first non-blank character -to the end of line are deleted and insert mode is entered. -.IP "\fIn\fP\fBc\fP\fImove-cmd\fP" -change from the current position to the position resulting from \fIn\fP -\fImove-cmd\fPs (\fIi.e.\fP, delete the indicated region and go into insert -mode); -if \fImove-cmd\fP is \fBc\fP, the line starting from the first non-blank -character is changed. -.IP "\fBC\fP" -change from the current position to the end of the line (\fIi.e.\fP, delete to -the end of the line and go into insert mode). -.IP "\fIn\fP\fBx\fP" -delete the next \fIn\fP characters. -.IP "\fIn\fP\fBX\fP" -delete the previous \fIn\fP characters. -.IP "\fBD\fP" -delete to the end of the line. -.IP "\fIn\fP\fBd\fP\fImove-cmd\fP" -delete from the current position to the position resulting from -\fIn\fP \fImove-cmd\fPs; -\fImove-cmd\fP is a movement command (see above) or \fBd\fP, in which case -the current line is deleted. -.IP "\fIn\fP\fBr\fP\fIc\fP" -replace the next \fIn\fP characters with the character \fIc\fP. -.IP "\fIn\fP\fBR\fP" -replace: enter insert mode but overwrite existing characters instead of -inserting before existing characters. The replacement is repeated \fIn\fP -times. -.IP "\fIn\fP\fB~\fP" -change the case of the next \fIn\fP characters. -.IP "\fIn\fP\fBy\fP\fImove-cmd\fP" -yank from the current position to the position resulting from \fIn\fP -\fImove-cmd\fPs into the yank buffer; if \fImove-cmd\fP is \fBy\fP, the -whole line is yanked. -.IP "\fBY\fP" -yank from the current position to the end of the line. -.IP "\fIn\fP\fBp\fP" -paste the contents of the yank buffer just after the current position, -\fIn\fP times. -.IP "\fIn\fP\fBP\fP" -same as \fBp\fP, except the buffer is pasted at the current position. -.RE -.\"}}} -.\"{{{ Miscellaneous vi commands -.IP "Miscellaneous vi commands" -.RS -.IP "\fB^J\fP and \fB^M\fP" -the current line is read, parsed and executed by the shell. -.IP "\fB^L\fP and \fB^R\fP" -redraw the current line. -.IP "\fIn\fP\fB.\fP" -redo the last edit command \fIn\fP times. -.IP "\fBu\fP" -undo the last edit command. -.IP "\fBU\fP" -undo all changes that have been made to the current line. -.IP "\fIintr\fP and \fIquit\fP" -the interrupt and quit terminal characters cause the current line to -be deleted and a new prompt to be printed. -.RE -.\"Has all vi commands except: -.\" movement: { } [[ ]] ^E ^Y ^U ^D ^F ^B H L M () -.\" tag commands: ^T ^] -.\" mark commands: m ` ' -.\" named-buffer commands: " @ -.\" file/shell/ex-commands: Q ZZ ^^ : ! & -.\" multi-line change commands: o O J -.\" shift commands: << >> -.\" status command: ^G -.\"}}} -.\"}}} -.\"}}} -.\"}}} -.\"{{{ Files -.SH FILES -~/.profile -.br -/etc/profile -.br -/etc/suid_profile -.\"}}} -.\"{{{ Bugs -.SH BUGS -Any bugs in pdksh should be reported to pdksh@cs.mun.ca. Please -include the version of pdksh (echo $KSH_VERSION shows it), the machine, -operating system and compiler you are using and a description of how to -repeat the bug (a small shell script that demonstrates the bug is -best). The following, if relevant (if you are not sure, include them), -can also helpful: options you are using (both options.h options and set -\-o options) and a copy of your config.h (the file generated by the -configure script). New versions of pdksh can be obtained from -ftp.cs.mun.ca:pub/pdksh/. -.\"}}} -.\"{{{ Authors -.SH AUTHORS -This shell is based on the public domain 7th edition Bourne shell clone by -Charles Forsyth and parts of the BRL shell by Doug A.\& Gwyn, Doug Kingston, -Ron Natalie, Arnold Robbins, Lou Salkind and others. The first release -was created by Eric Gisin, and it was subsequently maintained by -John R.\& MacMillan (chance!john@sq.sq.com), and -Simon J.\& Gerraty (sjg@zen.void.oz.au). The current maintainer is -Michael Rendell (michael@cs.mun.ca). -The CONTRIBUTORS file in the source distribution contains a more complete -list of people and their part in the shell's development. -.\"}}} -.\"{{{ See also -.SH "SEE ALSO" -awk(1), -sh(1), -csh(1), ed(1), getconf(1), getopt(1), sed(1), stty(1), vi(1), -dup(2), execve(2), getgid(2), getuid(2), open(2), pipe(2), wait(2), -getopt(3), rand(3), signal(3), system(3), -environ(5) -.PP -.IR "The KornShell Command and Programming Language" , -Morris Bolsky and David Korn, 1989, ISBN 0-13-516972-0. -.PP -.\" XXX ISBN missing -.IR "UNIX Shell Programming" , -Stephen G.\& Kochan, Patrick H.\& Wood, Hayden. -.PP -.IR "IEEE Standard for information Technology \- Portable Operating System Interface (POSIX) \- Part 2: Shell and Utilities" , -IEEE Inc, 1993, ISBN 1-55937-255-9. -.\"}}} diff --git a/bin/pdksh/ksh_dir.h b/bin/pdksh/ksh_dir.h deleted file mode 100644 index 34c981fedc1..00000000000 --- a/bin/pdksh/ksh_dir.h +++ /dev/null @@ -1,26 +0,0 @@ -/* $OpenBSD: ksh_dir.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */ - -/* Wrapper around the ugly dir includes/ifdefs */ - -#if defined(HAVE_DIRENT_H) -# include <dirent.h> -# define NLENGTH(dirent) (strlen(dirent->d_name)) -#else -# define dirent direct -# define NLENGTH(dirent) (dirent->d_namlen) -# ifdef HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif /* HAVE_SYS_NDIR_H */ -# ifdef HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif /* HAVE_SYSDIR_H */ -# ifdef HAVE_NDIR_H -# include <ndir.h> -# endif /* HAVE_NDIR_H */ -#endif /* HAVE_DIRENT_H */ - -#ifdef OPENDIR_DOES_NONDIR -extern DIR *ksh_opendir ARGS((const char *d)); -#else /* OPENDIR_DOES_NONDIR */ -# define ksh_opendir(d) opendir(d) -#endif /* OPENDIR_DOES_NONDIR */ diff --git a/bin/pdksh/ksh_limval.h b/bin/pdksh/ksh_limval.h deleted file mode 100644 index 828c0f82577..00000000000 --- a/bin/pdksh/ksh_limval.h +++ /dev/null @@ -1,24 +0,0 @@ -/* $OpenBSD: ksh_limval.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */ - -/* Wrapper around the values.h/limits.h includes/ifdefs */ - -#ifdef HAVE_VALUES_H -# include <values.h> -#endif /* HAVE_VALUES_H */ -/* limits.h is included in sh.h */ - -#ifndef DMAXEXP -# define DMAXEXP 128 /* should be big enough */ -#endif - -#ifndef BITSPERBYTE -# ifdef CHAR_BIT -# define BITSPERBYTE CHAR_BIT -# else -# define BITSPERBYTE 8 /* probably true.. */ -# endif -#endif - -#ifndef BITS -# define BITS(t) (BITSPERBYTE * sizeof(t)) -#endif diff --git a/bin/pdksh/ksh_stat.h b/bin/pdksh/ksh_stat.h deleted file mode 100644 index 1abcc7cb1fc..00000000000 --- a/bin/pdksh/ksh_stat.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $OpenBSD: ksh_stat.h,v 1.3 1996/10/01 02:05:39 downsj Exp $ */ - -/* Wrapper around the ugly sys/stat includes/ifdefs */ - -/* assumes <sys/types.h> already included */ -#include <sys/stat.h> - -#ifndef HAVE_LSTAT -# define lstat(path, buf) stat(path, buf) -#endif /* HAVE_LSTAT */ - -#ifdef STAT_MACROS_BROKEN -# undef S_ISREG -# undef S_ISDIR -# undef S_ISCHR -# undef S_ISBLK -# undef S_ISFIFO -# undef S_ISSOCK -# undef S_ISLNK -#endif /* STAT_MACROS_BROKEN */ - -#if !defined(S_ISREG) && defined(S_IFREG) -# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif /* S_ISREG */ -#if !defined(S_ISDIR) && defined(S_IFDIR) -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif /* S_ISDIR */ -#if !defined(S_ISCHR) && defined(S_IFCHR) -# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#endif /* S_ISCHR */ -#if !defined(S_ISBLK) && defined(S_IFBLK) -# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#endif /* S_ISBLK */ -#if !defined(S_ISFIFO) && defined(S_IFIFO) -# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#endif /* S_ISFIFO */ -#if !defined(S_ISLNK) && defined(S_IFLNK) -# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif /* S_ISLNK */ -#if !defined(S_ISSOCK) && defined(S_IFSOCK) -# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -#endif /* S_ISSOCK */ -#if !defined(S_ISCDF) && defined(S_CDF) -# define S_ISCDF(m) (S_ISDIR(m) && ((m) & S_CDF)) -#endif /* S_ISSOCK */ - -#ifndef S_ISVTX -# define S_ISVTX 01000 /* sticky bit */ -#endif /* S_ISVTX */ - -#ifndef S_IXUSR -# define S_IXUSR 00100 /* user execute bit */ -#endif /* S_IXUSR */ -#ifndef S_IXGRP -# define S_IXGRP 00010 /* user execute bit */ -#endif /* S_IXGRP */ -#ifndef S_IXOTH -# define S_IXOTH 00001 /* user execute bit */ -#endif /* S_IXOTH */ diff --git a/bin/pdksh/ksh_time.h b/bin/pdksh/ksh_time.h deleted file mode 100644 index ee8dc9b9128..00000000000 --- a/bin/pdksh/ksh_time.h +++ /dev/null @@ -1,26 +0,0 @@ -/* $OpenBSD: ksh_time.h,v 1.2 1996/10/01 02:05:40 downsj Exp $ */ - -#ifndef KSH_TIME_H -# define KSH_TIME_H - -/* Wrapper around the ugly time.h,sys/time.h includes/ifdefs */ - -#ifdef TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else /* TIME_WITH_SYS_TIME */ -# ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif /* TIME_WITH_SYS_TIME */ - -#ifndef TIME_DECLARED -extern time_t time ARGS((time_t *)); -#endif - -#ifndef CLK_TCK -# define CLK_TCK 60 /* 60HZ */ -#endif -#endif /* KSH_TIME_H */ diff --git a/bin/pdksh/ksh_times.h b/bin/pdksh/ksh_times.h deleted file mode 100644 index ec7b97eedf5..00000000000 --- a/bin/pdksh/ksh_times.h +++ /dev/null @@ -1,20 +0,0 @@ -/* $OpenBSD: ksh_times.h,v 1.2 1996/10/01 02:05:41 downsj Exp $ */ - -#ifndef KSH_TIMES_H -# define KSH_TIMES_H - -/* Needed for clock_t on some systems (ie, NeXT in non-posix mode) */ -#include "ksh_time.h" - -#include <sys/times.h> - -#ifdef TIMES_BROKEN -extern clock_t ksh_times ARGS((struct tms *)); -#else /* TIMES_BROKEN */ -# define ksh_times times -#endif /* TIMES_BROKEN */ - -#ifdef HAVE_TIMES -extern clock_t times ARGS((struct tms *)); -#endif /* HAVE_TIMES */ -#endif /* KSH_TIMES_H */ diff --git a/bin/pdksh/ksh_wait.h b/bin/pdksh/ksh_wait.h deleted file mode 100644 index a077b90f16b..00000000000 --- a/bin/pdksh/ksh_wait.h +++ /dev/null @@ -1,51 +0,0 @@ -/* $OpenBSD: ksh_wait.h,v 1.3 1997/06/19 13:58:43 kstailey Exp $ */ - -/* Wrapper around the ugly sys/wait includes/ifdefs */ - -#ifdef HAVE_SYS_WAIT_H -# include <sys/wait.h> -#endif - -#ifndef POSIX_SYS_WAIT -/* Get rid of system macros (which probably use union wait) */ -# undef WIFCORED -# undef WIFEXITED -# undef WEXITSTATUS -# undef WIFSIGNALED -# undef WTERMSIG -# undef WIFSTOPPED -# undef WSTOPSIG -#endif /* POSIX_SYS_WAIT */ - -typedef int WAIT_T; - -#ifndef WIFCORED -# define WIFCORED(s) ((s) & 0x80) -#endif -#define WSTATUS(s) (s) - -#ifndef WIFEXITED -# define WIFEXITED(s) (((s) & 0xff) == 0) -#endif -#ifndef WEXITSTATUS -# define WEXITSTATUS(s) (((s) >> 8) & 0xff) -#endif -#ifndef WIFSIGNALED -# define WIFSIGNALED(s) (((s) & 0xff) != 0 && ((s) & 0xff) != 0x7f) -#endif -#ifndef WTERMSIG -# define WTERMSIG(s) ((s) & 0x7f) -#endif -#ifndef WIFSTOPPED -# define WIFSTOPPED(s) (((s) & 0xff) == 0x7f) -#endif -#ifndef WSTOPSIG -# define WSTOPSIG(s) (((s) >> 8) & 0xff) -#endif - -#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT3) - /* always used with p == -1 */ -# define ksh_waitpid(p, s, o) wait3((s), (o), (struct rusage *) 0) -#else /* !HAVE_WAITPID && HAVE_WAIT3 */ -# define ksh_waitpid(p, s, o) waitpid((p), (s), (o)) -#endif /* !HAVE_WAITPID && HAVE_WAIT3 */ diff --git a/bin/pdksh/lex.c b/bin/pdksh/lex.c deleted file mode 100644 index 5db0c81accd..00000000000 --- a/bin/pdksh/lex.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* $OpenBSD: lex.c,v 1.10 1997/09/12 04:39:32 millert Exp $ */ - -/* - * lexical analysis and source input - */ - -#include "sh.h" -#include <ctype.h> - -static void readhere ARGS((struct ioword *iop)); -static int getsc__ ARGS((void)); -static void getsc_line ARGS((Source *s)); -static char *get_brace_var ARGS((XString *wsp, char *wp)); -static int arraysub ARGS((char **strp)); -static const char *ungetsc ARGS((int c)); -static int getsc_bn ARGS((void)); -static void gethere ARGS((void)); - -static int backslash_skip; -static int ignore_backslash_newline; - -/* optimized getsc_bn() */ -#define getsc() (*source->str != '\0' && *source->str != '\\' \ - && !backslash_skip ? *source->str++ : getsc_bn()) -/* optimized getsc__() */ -#define getsc_() ((*source->str != '\0') ? *source->str++ : getsc__()) - - -/* - * Lexical analyzer - * - * tokens are not regular expressions, they are LL(1). - * for example, "${var:-${PWD}}", and "$(size $(whence ksh))". - * hence the state stack. - */ - -int -yylex(cf) - int cf; -{ - register int c, state; - char states [64], *statep = states; /* XXX overflow check */ - XString ws; /* expandable output word */ - register char *wp; /* output word pointer */ - register char *sp, *dp; - char UNINITIALIZED(*ddparen_start); - int istate; - int UNINITIALIZED(c2); - int UNINITIALIZED(nparen), UNINITIALIZED(csstate); - int UNINITIALIZED(ndparen); - int UNINITIALIZED(indquotes); - - - Again: - Xinit(ws, wp, 64, ATEMP); - - backslash_skip = 0; - ignore_backslash_newline = 0; - - if (cf&ONEWORD) - istate = SWORD; -#ifdef KSH - else if (cf&LETEXPR) { - *wp++ = OQUOTE; /* enclose arguments in (double) quotes */ - istate = SDPAREN; - ndparen = 0; - } -#endif /* KSH */ - else { /* normal lexing */ - istate = (cf & HEREDELIM) ? SHEREDELIM : SBASE; - while ((c = getsc()) == ' ' || c == '\t') - ; - if (c == '#') { - ignore_backslash_newline++; - while ((c = getsc()) != '\0' && c != '\n') - ; - ignore_backslash_newline--; - } - ungetsc(c); - } - if (source->flags & SF_ALIAS) { /* trailing ' ' in alias definition */ - source->flags &= ~SF_ALIAS; - /* In POSIX mode, a trailing space only counts if we are - * parsing a simple command - */ - if (!Flag(FPOSIX) || (cf & CMDWORD)) - cf |= ALIAS; - } - - /* collect non-special or quoted characters to form word */ - for (*statep = state = istate; - !((c = getsc()) == 0 || ((state == SBASE || state == SHEREDELIM) - && ctype(c, C_LEX1))); ) - { - Xcheck(ws, wp); - switch (state) { - case SBASE: - if (c == '[' && (cf & (VARASN|ARRAYVAR))) { - *wp = EOS; /* temporary */ - if (is_wdvarname(Xstring(ws, wp), FALSE)) - { - char *p, *tmp; - - if (arraysub(&tmp)) { - *wp++ = CHAR; - *wp++ = c; - for (p = tmp; *p; ) { - Xcheck(ws, wp); - *wp++ = CHAR; - *wp++ = *p++; - } - afree(tmp, ATEMP); - break; - } else { - Source *s; - - s = pushs(SREREAD, - source->areap); - s->start = s->str - = s->u.freeme = tmp; - s->next = source; - source = s; - } - } - *wp++ = CHAR; - *wp++ = c; - break; - } - /* fall through.. */ - Sbase1: /* includes *(...|...) pattern (*+?@!) */ -#ifdef KSH - if (c == '*' || c == '@' || c == '+' || c == '?' - || c == '!') - { - c2 = getsc(); - if (c2 == '(' /*)*/ ) { - *wp++ = OPAT; - *wp++ = c; - *++statep = state = SPATTERN; - break; - } - ungetsc(c2); - } -#endif /* KSH */ - /* fall through.. */ - Sbase2: /* doesn't include *(...|...) pattern (*+?@!) */ - switch (c) { - case '\\': - c = getsc(); -#ifdef OS2 - if (isalnum(c)) { - *wp++ = CHAR, *wp++ = '\\'; - *wp++ = CHAR, *wp++ = c; - } else -#endif - if (c) /* trailing \ is lost */ - *wp++ = QCHAR, *wp++ = c; - break; - case '\'': - *++statep = state = SSQUOTE; - *wp++ = OQUOTE; - ignore_backslash_newline++; - break; - case '"': - *++statep = state = SDQUOTE; - *wp++ = OQUOTE; - break; - default: - goto Subst; - } - break; - - Subst: - switch (c) { - case '\\': - c = getsc(); - switch (c) { - case '"': case '\\': - case '$': case '`': - *wp++ = QCHAR, *wp++ = c; - break; - default: - Xcheck(ws, wp); - if (c) { /* trailing \ is lost */ - *wp++ = CHAR, *wp++ = '\\'; - *wp++ = CHAR, *wp++ = c; - } - break; - } - break; - case '$': - c = getsc(); - if (c == '(') /*)*/ { - c = getsc(); - if (c == '(') /*)*/ { - *++statep = state = SDDPAREN; - nparen = 2; - ddparen_start = wp; - *wp++ = EXPRSUB; - } else { - ungetsc(c); - *++statep = state = SPAREN; - nparen = 1; - csstate = 0; - *wp++ = COMSUB; - } - } else if (c == '{') /*}*/ { - *wp++ = OSUBST; - wp = get_brace_var(&ws, wp); - /* If this is a trim operation, - * wrap @(...) around the pattern - * (allows easy handling of ${a#b|c}) - */ - c = getsc(); - if (c == '#' || c == '%') { - *wp++ = CHAR, *wp++ = c; - if ((c2 = getsc()) == c) - *wp++ = CHAR, *wp++ = c; - else - ungetsc(c2); - *wp++ = OPAT, *wp++ = '@'; - *++statep = state = STBRACE; - } else { - ungetsc(c); - *++statep = state = SBRACE; - } - } else if (ctype(c, C_ALPHA)) { - *wp++ = OSUBST; - do { - Xcheck(ws, wp); - *wp++ = c; - c = getsc(); - } while (ctype(c, C_ALPHA|C_DIGIT)); - *wp++ = '\0'; - *wp++ = CSUBST; - ungetsc(c); - } else if (ctype(c, C_DIGIT|C_VAR1)) { - Xcheck(ws, wp); - *wp++ = OSUBST; - *wp++ = c; - *wp++ = '\0'; - *wp++ = CSUBST; - } else { - *wp++ = CHAR, *wp++ = '$'; - ungetsc(c); - } - break; - case '`': - *++statep = state = SBQUOTE; - *wp++ = COMSUB; - /* Need to know if we are inside double quotes - * since sh/at&t-ksh translate the \" to " in - * "`..\"..`". - */ - indquotes = 0; - if (!Flag(FPOSIX)) - for (sp = statep; sp > states; --sp) - if (*sp == SDQUOTE) - indquotes = 1; - break; - default: - *wp++ = CHAR, *wp++ = c; - } - break; - - case SSQUOTE: - if (c == '\'') { - state = *--statep; - *wp++ = CQUOTE; - ignore_backslash_newline--; - } else - *wp++ = QCHAR, *wp++ = c; - break; - - case SDQUOTE: - if (c == '"') { - state = *--statep; - *wp++ = CQUOTE; - } else - goto Subst; - break; - - case SPAREN: /* $( .. ) */ - /* todo: deal with $(...) quoting properly - * kludge to partly fake quoting inside $(..): doesn't - * really work because nested $(..) or ${..} inside - * double quotes aren't dealt with. - */ - switch (csstate) { - case 0: /* normal */ - switch (c) { - case '(': - nparen++; - break; - case ')': - nparen--; - break; - case '\\': - csstate = 1; - break; - case '"': - csstate = 2; - break; - case '\'': - csstate = 4; - ignore_backslash_newline++; - break; - } - break; - - case 1: /* backslash in normal mode */ - case 3: /* backslash in double quotes */ - --csstate; - break; - - case 2: /* double quotes */ - if (c == '"') - csstate = 0; - else if (c == '\\') - csstate = 3; - break; - - case 4: /* single quotes */ - if (c == '\'') { - csstate = 0; - ignore_backslash_newline--; - } - break; - } - if (nparen == 0) { - state = *--statep; - *wp++ = 0; /* end of COMSUB */ - } else - *wp++ = c; - break; - - case SDDPAREN: /* $(( .. )) */ - /* todo: deal with $((...); (...)) properly */ - /* XXX should nest using existing state machine - * (embed "..", $(...), etc.) */ - if (c == '(') - nparen++; - else if (c == ')') { - nparen--; - if (nparen == 1) { - /*(*/ - if ((c2 = getsc()) == ')') { - state = *--statep; - *wp++ = 0; /* end of EXPRSUB */ - break; - } else { - ungetsc(c2); - /* mismatched parenthesis - - * assume we were really - * parsing a $(..) expression - */ - memmove(ddparen_start + 1, - ddparen_start, - wp - ddparen_start); - *ddparen_start++ = COMSUB; - *ddparen_start = '('; /*)*/ - wp++; - csstate = 0; - *statep = state = SPAREN; - } - } - } - *wp++ = c; - break; - - case SBRACE: - /*{*/ - if (c == '}') { - state = *--statep; - *wp++ = CSUBST; - } else - goto Sbase1; - break; - - case STBRACE: - /* same as SBRACE, except | is saved as SPAT and - * CPAT is added at the end. - */ - /*{*/ - if (c == '}') { - state = *--statep; - *wp++ = CPAT; - *wp++ = CSUBST; - } else if (c == '|') { - *wp++ = SPAT; - } else - goto Sbase1; - break; - - case SBQUOTE: - if (c == '`') { - *wp++ = 0; - state = *--statep; - } else if (c == '\\') { - switch (c = getsc()) { - case '\\': - case '$': case '`': - *wp++ = c; - break; - case '"': - if (indquotes) { - *wp++ = c; - break; - } - /* fall through.. */ - default: - if (c) { /* trailing \ is lost */ - *wp++ = '\\'; - *wp++ = c; - } - break; - } - } else - *wp++ = c; - break; - - case SWORD: /* ONEWORD */ - goto Subst; - -#ifdef KSH - case SDPAREN: /* LETEXPR: (( ... )) */ - /*(*/ - if (c == ')') { - if (ndparen > 0) - --ndparen; - /*(*/ - else if ((c2 = getsc()) == ')') { - c = 0; - *wp++ = CQUOTE; - goto Done; - } else - ungetsc(c2); - } else if (c == '(') - /* parenthesis inside quotes and backslashes - * are lost, but at&t ksh doesn't count them - * either - */ - ++ndparen; - goto Sbase2; -#endif /* KSH */ - - case SHEREDELIM: /* <<,<<- delimiter */ - /* XXX chuck this state (and the next) - use - * the existing states ($ and \`..` should be - * stripped of their specialness after the - * fact). - */ - /* here delimiters need a special case since - * $ and `..` are not to be treated specially - */ - if (c == '\\') { - c = getsc(); - if (c) { /* trailing \ is lost */ - *wp++ = QCHAR; - *wp++ = c; - } - } else if (c == '\'') { - *++statep = state = SSQUOTE; - *wp++ = OQUOTE; - ignore_backslash_newline++; - } else if (c == '"') { - state = SHEREDQUOTE; - *wp++ = OQUOTE; - } else { - *wp++ = CHAR; - *wp++ = c; - } - break; - - case SHEREDQUOTE: /* " in <<,<<- delimiter */ - if (c == '"') { - *wp++ = CQUOTE; - state = SHEREDELIM; - } else { - if (c == '\\') { - switch (c = getsc()) { - case '\\': case '"': - case '$': case '`': - break; - default: - if (c) { /* trailing \ lost */ - *wp++ = CHAR; - *wp++ = '\\'; - } - break; - } - } - *wp++ = CHAR; - *wp++ = c; - } - break; - - case SPATTERN: /* in *(...|...) pattern (*+?@!) */ - if ( /*(*/ c == ')') { - *wp++ = CPAT; - state = *--statep; - } else if (c == '|') - *wp++ = SPAT; - else - goto Sbase1; - break; - } - } -Done: - Xcheck(ws, wp); - if (state != istate) - yyerror("no closing quote\n"); - - /* This done to avoid tests for SHEREDELIM wherever SBASE tested */ - if (state == SHEREDELIM) - state = SBASE; - - if ((c == '<' || c == '>') && state == SBASE) { - char *cp = Xstring(ws, wp); - if (Xlength(ws, wp) == 2 && cp[0] == CHAR && digit(cp[1])) { - wp = cp; /* throw away word */ - c2/*unit*/ = cp[1] - '0'; - } else - c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */ - } - - if (wp == Xstring(ws, wp) && state == SBASE) { - Xfree(ws, wp); /* free word */ - /* no word, process LEX1 character */ - switch (c) { - default: - return c; - - case '|': - case '&': - case ';': - if ((c2 = getsc()) == c) - c = (c == ';') ? BREAK : - (c == '|') ? LOGOR : - (c == '&') ? LOGAND : - YYERRCODE; -#ifdef KSH - else if (c == '|' && c2 == '&') - c = COPROC; -#endif /* KSH */ - else - ungetsc(c2); - return c; - - case '>': - case '<': { - register struct ioword *iop; - - iop = (struct ioword *) alloc(sizeof(*iop), ATEMP); - iop->unit = c2/*unit*/; - - c2 = getsc(); - /* <<, >>, <> are ok, >< is not */ - if (c == c2 || (c == '<' && c2 == '>')) { - iop->flag = c == c2 ? - (c == '>' ? IOCAT : IOHERE) : IORDWR; - if (iop->flag == IOHERE) - if ((c2 = getsc()) == '-') - iop->flag |= IOSKIP; - else - ungetsc(c2); - } else if (c2 == '&') - iop->flag = IODUP | (c == '<' ? IORDUP : 0); - else { - iop->flag = c == '>' ? IOWRITE : IOREAD; - if (c == '>' && c2 == '|') - iop->flag |= IOCLOB; - else - ungetsc(c2); - } - - iop->name = (char *) 0; - iop->delim = (char *) 0; - yylval.iop = iop; - return REDIR; - } - case '\n': - gethere(); - if (cf & CONTIN) - goto Again; - return c; - - case '(': /*)*/ -#ifdef KSH - if (!Flag(FSH)) { - if ((c2 = getsc()) == '(') /*)*/ - c = MDPAREN; - else - ungetsc(c2); - } -#endif /* KSH */ - return c; - /*(*/ - case ')': - return c; - } - } - - *wp++ = EOS; /* terminate word */ - yylval.cp = Xclose(ws, wp); - if (state == SWORD -#ifdef KSH - || state == SDPAREN -#endif /* KSH */ - ) /* ONEWORD? */ - return LWORD; - ungetsc(c); /* unget terminator */ - - /* copy word to unprefixed string ident */ - for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; ) - *dp++ = *sp++; - /* Make sure the ident array stays '\0' paded */ - memset(dp, 0, (ident+IDENT) - dp + 1); - if (c != EOS) - *ident = '\0'; /* word is not unquoted */ - - if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) { - struct tbl *p; - int h = hash(ident); - - /* { */ - if ((cf & KEYWORD) && (p = tsearch(&keywords, ident, h)) - && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}')) - { - afree(yylval.cp, ATEMP); - return p->val.i; - } - if ((cf & ALIAS) && (p = tsearch(&aliases, ident, h)) - && (p->flag & ISSET)) - { - register Source *s; - - for (s = source; s->type == SALIAS; s = s->next) - if (s->u.tblp == p) - return LWORD; - /* push alias expansion */ - s = pushs(SALIAS, source->areap); - s->start = s->str = p->val.s; - s->u.tblp = p; - s->next = source; - source = s; - afree(yylval.cp, ATEMP); - goto Again; - } - } - - return LWORD; -} - -static void -gethere() -{ - register struct ioword **p; - - for (p = heres; p < herep; p++) - readhere(*p); - herep = heres; -} - -/* - * read "<<word" text into temp file - */ - -static void -readhere(iop) - register struct ioword *iop; -{ - struct shf *volatile shf; - struct temp *h; - register int c; - char *volatile eof; - char *eofp; - int skiptabs; - int i; - - eof = evalstr(iop->delim, 0); - - if (e->flags & EF_FUNC_PARSE) { - h = maketemp(APERM); - h->next = func_heredocs; - func_heredocs = h; - } else { - h = maketemp(ATEMP); - h->next = e->temps; - e->temps = h; - } - iop->name = h->name; - if (!(shf = h->shf)) - yyerror("cannot create temporary file %s - %s\n", - h->name, strerror(errno)); - - newenv(E_ERRH); - i = ksh_sigsetjmp(e->jbuf, 0); - if (i) { - quitenv(); - shf_close(shf); - unwind(i); - } - - if (!(iop->flag & IOEVAL)) - ignore_backslash_newline++; - - for (;;) { - eofp = eof; - skiptabs = iop->flag & IOSKIP; - while ((c = getsc()) != 0) { - if (skiptabs) { - if (c == '\t') - continue; - skiptabs = 0; - } - if (c != *eofp) - break; - eofp++; - } - /* Allow EOF here so commands with out trailing newlines - * will work (eg, ksh -c '...', $(...), etc). - */ - if (*eofp == '\0' && (c == 0 || c == '\n')) - break; - ungetsc(c); - shf_write(eof, eofp - eof, shf); - while ((c = getsc()) != '\n') { - if (c == 0) - yyerror("here document `%s' unclosed\n", eof); - shf_putc(c, shf); - } - shf_putc(c, shf); - } - shf_flush(shf); - if (shf_error(shf)) - yyerror("error saving here document `%s': %s\n", - eof, strerror(shf_errno(shf))); - /*XXX add similar checks for write errors everywhere */ - quitenv(); - shf_close(shf); - if (!(iop->flag & IOEVAL)) - ignore_backslash_newline--; -} - -void -#ifdef HAVE_PROTOTYPES -yyerror(const char *fmt, ...) -#else -yyerror(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list va; - - yynerrs++; - /* pop aliases and re-reads */ - while (source->type == SALIAS || source->type == SREREAD) - source = source->next; - source->str = null; /* zap pending input */ - - error_prefix(TRUE); - SH_VA_START(va, fmt); - shf_vfprintf(shl_out, fmt, va); - va_end(va); - errorf(null); -} - -/* - * input for yylex with alias expansion - */ - -Source * -pushs(type, areap) - int type; - Area *areap; -{ - register Source *s; - - s = (Source *) alloc(sizeof(Source), areap); - s->type = type; - s->str = null; - s->start = NULL; - s->line = 0; - s->errline = 0; - s->file = NULL; - s->flags = 0; - s->next = NULL; - s->areap = areap; - if (type == SFILE || type == SSTDIN) { - char *dummy; - Xinit(s->xs, dummy, 256, s->areap); - } else - memset(&s->xs, 0, sizeof(s->xs)); - return s; -} - -static int -getsc__() -{ - register Source *s = source; - register int c; - - while ((c = *s->str++) == 0) { - s->str = NULL; /* return 0 for EOF by default */ - switch (s->type) { - case SEOF: - s->str = null; - return 0; - - case SSTDIN: - case SFILE: - getsc_line(s); - break; - - case SWSTR: - break; - - case SSTRING: - break; - - case SWORDS: - s->start = s->str = *s->u.strv++; - s->type = SWORDSEP; - break; - - case SWORDSEP: - if (*s->u.strv == NULL) { - s->start = s->str = newline; - s->type = SEOF; - } else { - s->start = s->str = space; - s->type = SWORDS; - } - break; - - case SALIAS: - if (s->flags & SF_ALIASEND) { - /* pass on an unused SF_ALIAS flag */ - source = s->next; - source->flags |= s->flags & SF_ALIAS; - s = source; - } else if (*s->u.tblp->val.s - && isspace(strchr(s->u.tblp->val.s, 0)[-1])) - { - source = s = s->next; /* pop source stack */ - /* Note that this alias ended with a space, - * enabling alias expansion on the following - * word. - */ - s->flags |= SF_ALIAS; - } else { - /* At this point, we need to keep the current - * alias in the source list so recursive - * aliases can be detected and we also need - * to return the next character. Do this - * by temporarily popping the alias to get - * the next character and then put it back - * in the source list with the SF_ALIASEND - * flag set. - */ - source = s->next; /* pop source stack */ - source->flags |= s->flags & SF_ALIAS; - c = getsc__(); - if (c) { - s->flags |= SF_ALIASEND; - s->ugbuf[0] = c; s->ugbuf[1] = '\0'; - s->start = s->str = s->ugbuf; - s->next = source; - source = s; - } else { - s = source; - /* avoid reading eof twice */ - s->str = NULL; - break; - } - } - continue; - - case SREREAD: - if (s->start != s->ugbuf) /* yuck */ - afree(s->u.freeme, ATEMP); - source = s = s->next; - continue; - } - if (s->str == NULL) { - s->type = SEOF; - s->start = s->str = null; - return '\0'; - } - if (s->flags & SF_ECHO) { - shf_puts(s->str, shl_out); - shf_flush(shl_out); - } - } - return c; -} - -static void -getsc_line(s) - Source *s; -{ - char *xp = Xstring(s->xs, xp); - int interactive = Flag(FTALKING) && s->type == SSTDIN; - int have_tty = interactive && (s->flags & SF_TTY); - - /* Done here to ensure nothing odd happens when a timeout occurs */ - XcheckN(s->xs, xp, LINE); - *xp = '\0'; - s->start = s->str = xp; - -#ifdef KSH - if (have_tty && ksh_tmout) { - ksh_tmout_state = TMOUT_READING; - alarm(ksh_tmout); - } -#endif /* KSH */ -#ifdef EDIT - if (have_tty && (0 -# ifdef VI - || Flag(FVI) -# endif /* VI */ -# ifdef EMACS - || Flag(FEMACS) || Flag(FGMACS) -# endif /* EMACS */ - )) - { - int nread; - - nread = x_read(xp, LINE); - if (nread < 0) /* read error */ - nread = 0; - xp[nread] = '\0'; - xp += nread; - } - else -#endif /* EDIT */ - { - if (interactive) { - pprompt(prompt, 0); -#ifdef OS2 - setmode (0, O_TEXT); -#endif /* OS2 */ - } else - s->line++; - - while (1) { - char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf); - - if (!p && shf_error(s->u.shf) - && shf_errno(s->u.shf) == EINTR) - { - shf_clearerr(s->u.shf); - if (trap) - runtraps(0); - continue; - } - if (!p || (xp = p, xp[-1] == '\n')) - break; - /* double buffer size */ - xp++; /* move past null so doubling works... */ - XcheckN(s->xs, xp, Xlength(s->xs, xp)); - xp--; /* ...and move back again */ - } -#ifdef OS2 - setmode(0, O_BINARY); -#endif /* OS2 */ - /* flush any unwanted input so other programs/builtins - * can read it. Not very optimal, but less error prone - * than flushing else where, dealing with redirections, - * etc.. - * todo: reduce size of shf buffer (~128?) if SSTDIN - */ - if (s->type == SSTDIN) - shf_flush(s->u.shf); - } - /* XXX: temporary kludge to restore source after a - * trap may have been executed. - */ - source = s; -#ifdef KSH - if (have_tty && ksh_tmout) - { - ksh_tmout_state = TMOUT_EXECUTING; - alarm(0); - } -#endif /* KSH */ - s->start = s->str = Xstring(s->xs, xp); - strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp)); - /* Note: if input is all nulls, this is not eof */ - if (Xlength(s->xs, xp) == 0) { /* EOF */ - if (s->type == SFILE) - shf_fdclose(s->u.shf); - s->str = NULL; - } else if (interactive) { -#ifdef HISTORY - char *p = Xstring(s->xs, xp); - if (cur_prompt == PS1) - while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS)) - p++; - if (*p) { -# ifdef EASY_HISTORY - if (cur_prompt == PS2) - histappend(Xstring(s->xs, xp), 1); - else -# endif /* EASY_HISTORY */ - { - s->line++; - histsave(s->line, s->str, 1); - } - } -#endif /* HISTORY */ - } - if (interactive) - set_prompt(PS2, (Source *) 0); -} - -void -set_prompt(to, s) - int to; - Source *s; -{ - cur_prompt = to; - - 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 - * substitutions, POSIX doesn't say which is to be done. - */ - { - struct shf *shf; - char *ps1; - Area *saved_atemp; -#ifdef __GNUC__ - (void)&ps1; -#endif - ps1 = str_val(global("PS1")); - shf = shf_sopen((char *) 0, strlen(ps1) * 2, - SHF_WR | SHF_DYNAMIC, (struct shf *) 0); - while (*ps1) { - if (*ps1 != '!' || *++ps1 == '!') - shf_putchar(*ps1++, shf); - else - shf_fprintf(shf, "%d", - s ? s->line + 1 : 0); - } - ps1 = shf_sclose(shf); - saved_atemp = ATEMP; - newenv(E_ERRH); - if (ksh_sigsetjmp(e->jbuf, 0)) { - prompt = safe_prompt; - /* 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 */ - prompt = str_val(global("PS2")); - break; - } -} - -/* See also related routine, promptlen() in edit.c */ -void -pprompt(cp, ntruncate) - const char *cp; - int ntruncate; -{ -#if 0 - char nbuf[32]; - int c; - - while (*cp != 0) { - if (*cp != '!') - c = *cp++; - else if (*++cp == '!') - c = *cp++; - else { - int len; - char *p; - - shf_snprintf(p = nbuf, sizeof(nbuf), "%d", - source->line + 1); - len = strlen(nbuf); - if (ntruncate) { - if (ntruncate >= len) { - ntruncate -= len; - continue; - } - p += ntruncate; - len -= ntruncate; - ntruncate = 0; - } - shf_write(p, len, shl_out); - continue; - } - if (ntruncate) - --ntruncate; - else - shf_putc(c, shl_out); - } -#endif /* 0 */ - shf_puts(cp + ntruncate, shl_out); - shf_flush(shl_out); -} - -/* Read the variable part of a ${...} expression (ie, up to but not including - * the :[-+?=#%] or close-brace. - */ -static char * -get_brace_var(wsp, wp) - XString *wsp; - char *wp; -{ - enum parse_state { - PS_INITIAL, PS_SAW_HASH, PS_IDENT, - PS_NUMBER, PS_VAR1, PS_END - } - state; - char c; - - state = PS_INITIAL; - while (1) { - c = getsc(); - /* State machine to figure out where the variable part ends. */ - switch (state) { - case PS_INITIAL: - if (c == '#') { - state = PS_SAW_HASH; - break; - } - /* fall through.. */ - case PS_SAW_HASH: - if (letter(c)) - state = PS_IDENT; - else if (digit(c)) - state = PS_NUMBER; - else if (ctype(c, C_VAR1)) - state = PS_VAR1; - else - state = PS_END; - break; - case PS_IDENT: - if (!letnum(c)) { - state = PS_END; - if (c == '[') { - char *tmp, *p; - - if (!arraysub(&tmp)) - yyerror("missing ]\n"); - *wp++ = c; - for (p = tmp; *p; ) { - Xcheck(*wsp, wp); - *wp++ = *p++; - } - afree(tmp, ATEMP); - c = getsc(); /* the ] */ - } - } - break; - case PS_NUMBER: - if (!digit(c)) - state = PS_END; - break; - case PS_VAR1: - state = PS_END; - break; - case PS_END: /* keep gcc happy */ - break; - } - if (state == PS_END) { - *wp++ = '\0'; /* end of variable part */ - ungetsc(c); - break; - } - Xcheck(*wsp, wp); - *wp++ = c; - } - return wp; -} - -/* - * Save an array subscript - returns true if matching bracket found, false - * if eof or newline was found. - * (Returned string double null terminated) - */ -static int -arraysub(strp) - char **strp; -{ - XString ws; - char *wp; - char c; - int depth = 1; /* we are just past the initial [ */ - - Xinit(ws, wp, 32, ATEMP); - - do { - c = getsc(); - Xcheck(ws, wp); - *wp++ = c; - if (c == '[') - depth++; - else if (c == ']') - depth--; - } while (depth > 0 && c && c != '\n'); - - *wp++ = '\0'; - *strp = Xclose(ws, wp); - - return depth == 0 ? 1 : 0; -} - -/* Unget a char: handles case when we are already at the start of the buffer */ -static const char * -ungetsc(c) - int c; -{ - if (backslash_skip) - backslash_skip--; - /* Don't unget eof... */ - if (source->str == null && c == '\0') - return source->str; - if (source->str > source->start) - source->str--; - else { - Source *s; - - s = pushs(SREREAD, source->areap); - s->ugbuf[0] = c; s->ugbuf[1] = '\0'; - s->start = s->str = s->ugbuf; - s->next = source; - source = s; - } - return source->str; -} - - -/* Called to get a char that isn't a \newline sequence. */ -static int -getsc_bn ARGS((void)) -{ - int c, c2; - - if (ignore_backslash_newline) - return getsc_(); - - if (backslash_skip == 1) { - backslash_skip = 2; - return getsc_(); - } - - backslash_skip = 0; - - while (1) { - c = getsc_(); - if (c == '\\') { - if ((c2 = getsc_()) == '\n') - /* ignore the \newline; get the next char... */ - continue; - ungetsc(c2); - backslash_skip = 1; - } - return c; - } -} diff --git a/bin/pdksh/lex.h b/bin/pdksh/lex.h deleted file mode 100644 index bca6446d268..00000000000 --- a/bin/pdksh/lex.h +++ /dev/null @@ -1,133 +0,0 @@ -/* $OpenBSD: lex.h,v 1.3 1996/10/13 21:32:20 downsj Exp $ */ - -/* - * Source input, lexer and parser - */ - -/* $From: lex.h,v 1.4 1994/05/31 13:34:34 michael Exp $ */ - -#define IDENT 64 - -typedef struct source Source; -struct source { - const char *str; /* input pointer */ - int type; /* input type */ - char const *start; /* start of current buffer */ - union { - char **strv; /* string [] */ - struct shf *shf; /* shell file */ - struct tbl *tblp; /* alias (SALIAS) */ - char *freeme; /* also for SREREAD */ - } u; - char ugbuf[2]; /* buffer for ungetsc() (SREREAD) and - * alias (SALIAS) */ - int line; /* line number */ - int errline; /* line the error occured on (0 if not set) */ - const char *file; /* input file name */ - int flags; /* SF_* */ - Area *areap; - XString xs; /* input buffer */ - Source *next; /* stacked source */ -}; - -/* Source.type values */ -#define SEOF 0 /* input EOF */ -#define SFILE 1 /* file input */ -#define SSTDIN 2 /* read stdin */ -#define SSTRING 3 /* string */ -#define SWSTR 4 /* string without \n */ -#define SWORDS 5 /* string[] */ -#define SWORDSEP 6 /* string[] seperator */ -#define SALIAS 7 /* alias expansion */ -#define SREREAD 8 /* read ahead to be re-scanned */ - -/* Source.flags values */ -#define SF_ECHO BIT(0) /* echo input to shlout */ -#define SF_ALIAS BIT(1) /* faking space at end of alias */ -#define SF_ALIASEND BIT(2) /* faking space at end of alias */ -#define SF_TTY BIT(3) /* type == SSTDIN & it is a tty */ - -/* - * states while lexing word - */ -#define SBASE 0 /* outside any lexical constructs */ -#define SWORD 1 /* implicit quoting for substitute() */ -#ifdef KSH -#define SDPAREN 2 /* inside (( )), implicit quoting */ -#endif /* KSH */ -#define SSQUOTE 3 /* inside '' */ -#define SDQUOTE 4 /* inside "" */ -#define SBRACE 5 /* inside ${} */ -#define SPAREN 6 /* inside $() */ -#define SBQUOTE 7 /* inside `` */ -#define SDDPAREN 8 /* inside $(( )) */ -#define SHEREDELIM 9 /* parsing <<,<<- delimiter */ -#define SHEREDQUOTE 10 /* parsing " in <<,<<- delimiter */ -#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */ -#define STBRACE 12 /* parsing ${..[#%]..} */ - -typedef union { - int i; - char *cp; - char **wp; - struct op *o; - struct ioword *iop; -} YYSTYPE; - -/* If something is added here, add it to tokentab[] in syn.c as well */ -#define LWORD 256 -#define LOGAND 257 /* && */ -#define LOGOR 258 /* || */ -#define BREAK 259 /* ;; */ -#define IF 260 -#define THEN 261 -#define ELSE 262 -#define ELIF 263 -#define FI 264 -#define CASE 265 -#define ESAC 266 -#define FOR 267 -#define SELECT 268 -#define WHILE 269 -#define UNTIL 270 -#define DO 271 -#define DONE 272 -#define IN 273 -#define FUNCTION 274 -#define TIME 275 -#define REDIR 276 -#ifdef KSH -#define MDPAREN 277 /* (( )) */ -#endif /* KSH */ -#define BANG 278 /* ! */ -#define DBRACKET 279 /* [[ .. ]] */ -#define COPROC 280 /* |& */ -#define YYERRCODE 300 - -/* flags to yylex */ -#define CONTIN BIT(0) /* skip new lines to complete command */ -#define ONEWORD BIT(1) /* single word for substitute() */ -#define ALIAS BIT(2) /* recognize alias */ -#define KEYWORD BIT(3) /* recognize keywords */ -#define LETEXPR BIT(4) /* get expression inside (( )) */ -#define VARASN BIT(5) /* check for var=word */ -#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */ -#define ESACONLY BIT(7) /* only accept esac keyword */ -#define CMDWORD BIT(8) /* parsing simple command (alias related) */ -#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */ - -#define HERES 10 /* max << in line */ - -EXTERN Source *source; /* yyparse/yylex source */ -EXTERN YYSTYPE yylval; /* result from yylex */ -EXTERN int yynerrs; -EXTERN struct ioword *heres [HERES], **herep; -EXTERN char ident [IDENT+1]; - -#ifdef HISTORY -# define HISTORYSIZE 128 /* size of saved history */ - -EXTERN char **history; /* saved commands */ -EXTERN char **histptr; /* last history item */ -EXTERN int histsize; /* history size */ -#endif /* HISTORY */ diff --git a/bin/pdksh/mail.c b/bin/pdksh/mail.c deleted file mode 100644 index 79ff7aee0f6..00000000000 --- a/bin/pdksh/mail.c +++ /dev/null @@ -1,198 +0,0 @@ -/* $OpenBSD: mail.c,v 1.6 1997/11/16 12:07:28 niklas 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" - -#define MBMESSAGE "you have mail in $_" - -typedef struct mbox { - struct mbox *mb_next; /* next mbox in list */ - char *mb_path; /* path to mail file */ - char *mb_msg; /* to announce arrival of new mail */ - time_t mb_mtime; /* mtime of mail file */ -} mbox_t; - -/* - * $MAILPATH is a linked list of mboxes. $MAIL is a treated as a - * special case of $MAILPATH, where the list has only one node. The - * same list is used for both since they are exclusive. - */ - -static mbox_t *mplist; -static mbox_t mbox; -static time_t mlastchkd; /* when mail was last checked */ - -static void munset ARGS((mbox_t *mlist)); /* free mlist and mval */ -static mbox_t * mballoc ARGS((char *p, char *m)); /* allocate a new mbox */ -static void mprintit ARGS((mbox_t *mbp)); - -void -mcheck() -{ - register mbox_t *mbp; - time_t now; - long mailcheck; - struct tbl *vp; - struct stat stbuf; - - if (getint(global("MAILCHECK"), &mailcheck) < 0) - return; - - now = time((time_t *) 0); - if (mlastchkd == 0) - mlastchkd = now; - if (now - mlastchkd >= mailcheck) { - mlastchkd = now; - - vp = global("MAILPATH"); - if (vp && (vp->flag & ISSET)) - mbp = mplist; - else if ((vp = global("MAIL")) && (vp->flag & ISSET)) - mbp = &mbox; - else - mbp = NULL; - - while (mbp) { - if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0 - && S_ISREG(stbuf.st_mode)) - { - if (stbuf.st_size - && mbp->mb_mtime != stbuf.st_mtime - && stbuf.st_atime <= stbuf.st_mtime) - mprintit(mbp); - mbp->mb_mtime = stbuf.st_mtime; - } else { - /* - * Some mail readers remove the mail - * file if all mail is read. If file - * does not exist, assume this is the - * case and set mtime to zero. - */ - mbp->mb_mtime = 0; - } - mbp = mbp->mb_next; - } - } -} - -void -mbset(p) - register char *p; -{ - struct stat stbuf; - - if (mbox.mb_msg) - afree((void *)mbox.mb_msg, APERM); - mbox.mb_path = p; - mbox.mb_msg = NULL; - if (p && stat(p,&stbuf) == 0 && S_ISREG(stbuf.st_mode)) - mbox.mb_mtime = stbuf.st_mtime; - else - mbox.mb_mtime = 0; -} - -void -mpset(mptoparse) - register char *mptoparse; -{ - register mbox_t *mbp; - register char *mpath, *mmsg, *mval; - char *p; - - munset( mplist ); - mplist = NULL; - mval = str_save(mptoparse, APERM); - while (mval) { - mpath = mval; - if ((mval = strchr(mval, PATHSEP)) != NULL) { - *mval = '\0', mval++; - } - /* POSIX/bourne-shell say file%message */ - for (p = mpath; (mmsg = strchr(p, '%')); ) { - /* a literal percent? (POSIXism) */ - if (mmsg[-1] == '\\') { - /* use memmove() to avoid overlap problems */ - memmove(mmsg - 1, mmsg, strlen(mmsg) + 1); - p = mmsg + 1; - continue; - } - break; - } - /* at&t ksh says file?message */ - if (!mmsg && !Flag(FPOSIX)) - mmsg = strchr(mpath, '?'); - if (mmsg) { - *mmsg = '\0'; - mmsg++; - } - mbp = mballoc(mpath, mmsg); - mbp->mb_next = mplist; - mplist = mbp; - } -} - -static void -munset(mlist) -register mbox_t *mlist; -{ - register mbox_t *mbp; - - while (mlist != NULL) { - mbp = mlist; - mlist = mbp->mb_next; - if (!mlist) - afree((void *)mbp->mb_path, APERM); - afree((void *)mbp, APERM); - } -} - -static mbox_t * -mballoc(p, m) - char *p; - char *m; -{ - struct stat stbuf; - register mbox_t *mbp; - - mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM); - mbp->mb_next = NULL; - mbp->mb_path = p; - mbp->mb_msg = m; - if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode)) - mbp->mb_mtime = stbuf.st_mtime; - else - mbp->mb_mtime = 0; - return(mbp); -} - -static void -mprintit( mbp ) -mbox_t *mbp; -{ - struct tbl *vp; - -#if 0 - /* - * I doubt this $_ overloading is bad in /bin/sh mode. Anyhow, we - * crash as the code looks now if we do not set vp. Now, this is - * easy to fix too, but I'd like to see what POSIX says before doing - * a change like that. - */ - if (!Flag(FSH)) -#endif - setstr((vp = local("_", FALSE)), mbp->mb_path); - - shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0)); - - unset(vp, 0); -} -#endif /* KSH */ diff --git a/bin/pdksh/main.c b/bin/pdksh/main.c deleted file mode 100644 index d161fb9b3d0..00000000000 --- a/bin/pdksh/main.c +++ /dev/null @@ -1,820 +0,0 @@ -/* $OpenBSD: main.c,v 1.9 1997/09/12 00:32:53 deraadt Exp $ */ - -/* - * startup, main loop, enviroments and error handling - */ - -#define EXTERN /* define EXTERNs in sh.h */ - -#include "sh.h" -#include "ksh_stat.h" -#include "ksh_time.h" - -extern char **environ; - -/* - * global data - */ - -static void reclaim ARGS((void)); -static void remove_temps ARGS((struct temp *tp)); -static int is_restricted ARGS((char *name)); - -/* - * shell initialization - */ - -static const char initifs [] = "IFS= \t\n"; /* must be R/W */ - -static const char initsubs [] = - "${PS2=> } ${PS3=#? } ${PS4=+ }"; - -static const char version_param[] = -#ifdef KSH - "KSH_VERSION" -#else /* KSH */ - "SH_VERSION" -#endif /* KSH */ - ; - -static const char *const initcoms [] = { - "typeset", "-x", "SHELL", "PATH", "HOME", NULL, - "typeset", "-r", version_param, NULL, - "typeset", "-ri", "PPID", NULL, - "typeset", "-i", "OPTIND=1", -#ifdef KSH - "MAILCHECK=600", "RANDOM", "SECONDS=0", "TMOUT=0", -#endif /* KSH */ - NULL, - "alias", - /* Standard ksh aliases */ - "hash=alias -t", /* not "alias -t --": hash -r needs to work */ - "type=whence -v", -#ifdef JOBS - "stop=kill -STOP", - "suspend=kill -STOP $$", -#endif -#ifdef KSH - "autoload=typeset -fu", - "functions=typeset -f", -# ifdef HISTORY - "history=fc -l", -# endif /* HISTORY */ - "integer=typeset -i", - "nohup=nohup ", - "local=typeset", - "r=fc -e -", -#endif /* KSH */ -#ifdef KSH - /* Aliases that are builtin commands in at&t */ - "login=exec login", - "newgrp=exec newgrp", -#endif /* KSH */ - NULL, - /* this is what at&t ksh seems to track, with the addition of emacs */ - "alias", "-tU", - "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls", - "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", - NULL, -#ifdef EXTRA_INITCOMS - EXTRA_INITCOMS, NULL, -#endif /* EXTRA_INITCOMS */ - NULL -}; - -int -main(argc, argv) - int argc; - register char **argv; -{ - register int i; - int argi; - Source *s; - struct block *l; - int restricted; - char **wp; - struct env env; - int euid; - -#ifdef MEM_DEBUG - chmem_push("+c", 1); - /*chmem_push("+cd", 1);*/ -#endif - -#ifdef OS2 - setmode (0, O_BINARY); - setmode (1, O_TEXT); -#endif - - /* make sure argv[] is sane */ - if (!*argv) { - static const char *empty_argv[] = { - "pdksh", (char *) 0 - }; - - argv = (char **) empty_argv; - argc = 1; - } - kshname = *argv; - - ainit(&aperm); /* initialize permanent Area */ - - /* set up base enviroment */ - memset(&env, 0, sizeof(env)); - env.type = E_NONE; - ainit(&env.area); - e = &env; - newblock(); /* set up global l->vars and l->funs */ - - /* Do this first so output routines (eg, errorf, shellf) can work */ - initio(); - - initvar(); - - initctypes(); - - inittraps(); - -#ifdef KSH - coproc_init(); -#endif /* KSH */ - - /* set up variable and command dictionaries */ - tinit(&taliases, APERM, 0); - tinit(&aliases, APERM, 0); - tinit(&homedirs, APERM, 0); - - /* define shell keywords */ - initkeywords(); - - /* define built-in commands */ - tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */ - for (i = 0; shbuiltins[i].name != NULL; i++) - builtin(shbuiltins[i].name, shbuiltins[i].func); - for (i = 0; kshbuiltins[i].name != NULL; i++) - builtin(kshbuiltins[i].name, kshbuiltins[i].func); - - init_histvec(); - - def_path = DEFAULT__PATH; -#if defined(HAVE_CONFSTR) && defined(_CS_PATH) - { - size_t len = confstr(_CS_PATH, (char *) 0, 0); - char *new; - - if (len > 0) { - confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1); - def_path = new; - } - } -#endif /* HAVE_CONFSTR && _CS_PATH */ - path = def_path; - - - /* Turn on nohup by default for how - will change to off - * by default once people are aware of its existance - * (at&t ksh does not have a nohup option - it always sends - * the hup). - */ - Flag(FNOHUP) = 1; - - /* Turn on brace expansion by default. At&t ksh's that have - * alternation always have it on. BUT, posix doesn't have - * brace expansion, so set this before setting up FPOSIX - * (change_flag() clears FBRACEEXPAND when FPOSIX is set). - */ -#ifdef BRACE_EXPAND - Flag(FBRACEEXPAND) = 1; -#endif /* BRACE_EXPAND */ - - /* set posix flag just before environment so that it will have - * exactly the same effect as the POSIXLY_CORRECT environment - * variable. If this needs to be done sooner to ensure correct posix - * operation, an initial scan of the environment will also have - * done sooner. - */ -#ifdef POSIXLY_CORRECT - change_flag(FPOSIX, OF_SPECIAL, 1); -#endif /* POSIXLY_CORRECT */ - - /* Check to see if we're /bin/sh. */ - if (!strcmp(&kshname[strlen(kshname) - 3], "/sh") - || !strcmp(kshname, "sh") || !strcmp(kshname, "-sh")) - Flag(FSH) = 1; - - /* import enviroment */ - if (environ != NULL) - for (wp = environ; *wp != NULL; wp++) - typeset(*wp, IMPORT|EXPORT, 0, 0, 0); - - kshpid = procpid = getpid(); - typeset(initifs, 0, 0, 0, 0); /* for security */ - - /* assign default shell variable values */ - substitute(initsubs, 0); - - /* Figure out the current working directory and set $PWD */ - { - struct stat s_pwd, s_dot; - struct tbl *pwd_v = global("PWD"); - char *pwd = str_val(pwd_v); - char *pwdx = pwd; - - /* Try to use existing $PWD if it is valid */ - if (!ISABSPATH(pwd) - || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0 - || s_pwd.st_dev != s_dot.st_dev - || s_pwd.st_ino != s_dot.st_ino) - pwdx = (char *) 0; - set_current_wd(pwdx); - if (current_wd[0]) - simplify_path(current_wd); - /* Only set pwd if we know where we are or if it had a - * bogus value - */ - if (current_wd[0] || pwd != null) - setstr(pwd_v, current_wd); - } - setint(global("PPID"), (long) getppid()); -#ifdef KSH - setint(global("RANDOM"), (long) time((time_t *)0)); -#endif /* KSH */ - setstr(global(version_param), ksh_version); - - /* execute initialization statements */ - for (wp = (char**) initcoms; *wp != NULL; wp++) { - shcomexec(wp); - for (; *wp != NULL; wp++) - ; - } - - euid = geteuid(); - safe_prompt = euid ? "$ " : "# "; - { - struct tbl *vp = global("PS1"); - - /* Set PS1 if it isn't set, or we are root and prompt doesn't - * contain a #. - */ - if (!(vp->flag & ISSET) || (!euid && !strchr(str_val(vp), '#'))) - setstr(vp, safe_prompt); - } - - /* Set this before parsing arguments */ - Flag(FPRIVILEGED) = getuid() != euid || getgid() != getegid(); - - /* this to note if monitor is set on command line (see below) */ - Flag(FMONITOR) = 127; - argi = parse_args(argv, OF_CMDLINE, (int *) 0); - if (argi < 0) - exit(1); - - if (Flag(FCOMMAND)) { - s = pushs(SSTRING, ATEMP); - if (!(s->start = s->str = argv[argi++])) - errorf("-c requires an argument"); - if (argv[argi]) - kshname = argv[argi++]; - } else if (argi < argc && !Flag(FSTDIN)) { - s = pushs(SFILE, ATEMP); -#ifdef OS2 - /* a bug in os2 extproc shell processing doesn't - * pass full pathnames so we have to search for it. - * 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, (int *) 0); - if (!s->file || !*s->file) - s->file = argv[argi - 1]; -#else - s->file = argv[argi++]; -#endif /* OS2 */ - s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); - if (s->u.shf == NULL) { - exstat = 127; /* POSIX */ - errorf("%s: %s", s->file, strerror(errno)); - } - kshname = s->file; - } else { - Flag(FSTDIN) = 1; - s = pushs(SSTDIN, ATEMP); - s->file = "<stdin>"; - s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), - (struct shf *) 0); - if (isatty(0) && isatty(2)) { - Flag(FTALKING) = 1; - /* The following only if isatty(0) */ - s->flags |= SF_TTY; - s->u.shf->flags |= SHF_INTERRUPT; - s->file = (char *) 0; - } - } - - /* This bizarreness is mandated by POSIX */ - { - struct stat s_stdin; - - if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode)) - reset_nonblock(0); - } - - /* initialize job control */ - i = Flag(FMONITOR) != 127; - Flag(FMONITOR) = 0; - j_init(i); -#ifdef EDIT - /* Do this after j_init(), as tty_fd is not initialized 'til then */ - if (Flag(FTALKING)) - x_init(); -#endif - - l = e->loc; - l->argv = &argv[argi - 1]; - l->argc = argc - argi; - l->argv[0] = (char *) kshname; - getopts_reset(1); - - /* Disable during .profile/ENV reading */ - restricted = Flag(FRESTRICTED); - Flag(FRESTRICTED) = 0; - - /* Do this before profile/$ENV so that if it causes problems in them, - * user will know why things broke. - */ - if (!current_wd[0] && Flag(FTALKING)) - warningf(FALSE, "Cannot determine current working directory"); - - if (Flag(FLOGIN)) { -#ifdef OS2 - char *profile; - - /* Try to find a profile - first see if $INIT has a value, - * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh. - */ - if (!Flag(FPRIVILEGED) - && strcmp(profile = substitute("$INIT/profile.ksh", 0), - "/profile.ksh")) - include(profile, 0, (char **) 0, 1); - else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0) - include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1); - if (!Flag(FPRIVILEGED)) - include(substitute("$HOME/profile.ksh", 0), 0, - (char **) 0, 1); -#else /* OS2 */ - include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1); - if (!Flag(FPRIVILEGED)) - include(substitute("$HOME/.profile", 0), 0, - (char **) 0, 1); -#endif /* OS2 */ - } - - if (Flag(FPRIVILEGED)) - include("/etc/suid_profile", 0, (char **) 0, 1); - else { - char *env_file; - -#ifndef KSH - if (!Flag(FPOSIX)) - env_file = null; - else -#endif /* !KSH */ - /* include $ENV */ - env_file = str_val(global("ENV")); - -#ifdef DEFAULT_ENV - /* If env isn't set, include default environment */ - if (env_file == null) - env_file = DEFAULT_ENV; -#endif /* DEFAULT_ENV */ - env_file = substitute(env_file, DOTILDE); - if (*env_file != '\0') - include(env_file, 0, (char **) 0, 1); -#ifdef OS2 - else if (Flag(FTALKING)) - include(substitute("$HOME/kshrc.ksh", 0), 0, - (char **) 0, 1); -#endif /* OS2 */ - } - - if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL")))) - restricted = 1; - if (restricted) { - static const char *const restr_com[] = { - "typeset", "-r", "PATH", - "ENV", "SHELL", - (char *) 0 - }; - shcomexec((char **) restr_com); - /* After typeset command... */ - Flag(FRESTRICTED) = 1; - } - - if (Flag(FTALKING)) { - hist_init(s); -#ifdef KSH - alarm_init(); -#endif /* KSH */ - } else - Flag(FTRACKALL) = 1; /* set after ENV */ - - shell(s, TRUE); /* doesn't return */ - return 0; -} - -int -include(name, argc, argv, intr_ok) - const char *name; - int argc; - char **argv; - int intr_ok; -{ - register Source *volatile s = NULL; - Source *volatile sold; - struct shf *shf; - char **volatile old_argv; - volatile int old_argc; - int i; - - shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); - if (shf == NULL) - return -1; - - if (argv) { - old_argv = e->loc->argv; - old_argc = e->loc->argc; - } else { - old_argv = (char **) 0; - old_argc = 0; - } - sold = source; - newenv(E_INCL); - i = ksh_sigsetjmp(e->jbuf, 0); - if (i) { - quitenv(); - source = sold; - if (s) - shf_close(s->u.shf); - if (old_argv) { - e->loc->argv = old_argv; - e->loc->argc = old_argc; - } - switch (i) { - case LRETURN: - case LERROR: - return exstat & 0xff; /* see below */ - case LINTR: - /* intr_ok is set if we are including .profile or $ENV. - * If user ^C's out, we don't want to kill the shell... - */ - if (intr_ok && (exstat - 128) != SIGTERM) - return 1; - /* fall through... */ - case LEXIT: - case LLEAVE: - case LSHELL: - unwind(i); - /*NOREACHED*/ - default: - internal_errorf(1, "include: %d", i); - /*NOREACHED*/ - } - } - if (argv) { - e->loc->argv = argv; - e->loc->argc = argc; - } - s = pushs(SFILE, ATEMP); - s->u.shf = shf; - s->file = str_save(name, ATEMP); - i = shell(s, FALSE); - source = sold; - shf_close(s->u.shf); - quitenv(); - if (old_argv) { - e->loc->argv = old_argv; - e->loc->argc = old_argc; - } - return i & 0xff; /* & 0xff to ensure value not -1 */ -} - -int -command(comm) - const char *comm; -{ - register Source *s; - - s = pushs(SSTRING, ATEMP); - s->start = s->str = comm; - return shell(s, FALSE); -} - -/* - * run the commands from the input source, returning status. - */ -int -shell(s, toplevel) - Source *volatile s; /* input source */ - int volatile toplevel; -{ - struct op *t; - volatile int wastty = s->flags & SF_TTY; - volatile int attempts = 13; - volatile int interactive = Flag(FTALKING) && toplevel; - int i; - - newenv(E_PARSE); - if (interactive) - really_exit = 0; - i = ksh_sigsetjmp(e->jbuf, 0); - if (i) { - s->start = s->str = null; - switch (i) { - case LINTR: /* we get here if SIGINT not caught or ignored */ - case LERROR: - case LSHELL: - if (interactive) { - if (i == LINTR) - shellf(newline); - /* Reset any eof that was read as part of a - * multiline command. - */ - if (Flag(FIGNOREEOF) && s->type == SEOF - && wastty) - s->type = SSTDIN; - /* Used by exit command to get back to - * top level shell. Kind of strange since - * interactive is set if we are reading from - * a tty, but to have stopped jobs, one only - * needs FMONITOR set (not FTALKING/SF_TTY)... - */ - break; - } - /* fall through... */ - case LEXIT: - case LLEAVE: - case LRETURN: - quitenv(); - unwind(i); /* keep on going */ - /*NOREACHED*/ - default: - quitenv(); - internal_errorf(1, "shell: %d", i); - /*NOREACHED*/ - } - } - - while (1) { - if (trap) - runtraps(0); - - if (s->next == NULL) - if (Flag(FVERBOSE)) - s->flags |= SF_ECHO; - else - s->flags &= ~SF_ECHO; - - if (interactive) { - j_notify(); -#ifdef KSH - mcheck(); -#endif /* KSH */ - set_prompt(PS1, s); - } - - t = compile(s); - if (t != NULL && t->type == TEOF) { - if (wastty && Flag(FIGNOREEOF) && --attempts > 0) { - shellf("Use `exit' to leave ksh\n"); - s->type = SSTDIN; - } else if (wastty && !really_exit - && j_stopped_running()) - { - really_exit = 1; - s->type = SSTDIN; - } else { - /* this for POSIX, which says EXIT traps - * shall be taken in the environment - * immediately after the last command - * executed. - */ - if (toplevel) - unwind(LEXIT); - break; - } - } - - if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY))) - exstat = execute(t, 0); - - if (t != NULL && t->type != TEOF && interactive && really_exit) - really_exit = 0; - - reclaim(); - } - quitenv(); - return exstat; -} - -/* return to closest error handler or shell(), exit if none found */ -void -unwind(i) - int i; -{ - /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */ - if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) - && sigtraps[SIGEXIT_].trap)) - { - runtrap(&sigtraps[SIGEXIT_]); - i = LLEAVE; - } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) { - runtrap(&sigtraps[SIGERR_]); - i = LLEAVE; - } - while (1) { - switch (e->type) { - case E_PARSE: - case E_FUNC: - case E_INCL: - case E_LOOP: - case E_ERRH: - ksh_siglongjmp(e->jbuf, i); - /*NOTREACHED*/ - - case E_NONE: /* bottom of the stack */ - { - if (Flag(FTALKING)) - hist_finish(); - j_exit(); - remove_temps(func_heredocs); - if (i == LINTR) { - int sig = exstat - 128; - - /* ham up our death a bit (at&t ksh - * only seems to do this for SIGTERM) - * Don't do it for SIGQUIT, since we'd - * dump a core.. - */ - if (sig == SIGINT || sig == SIGTERM) { - setsig(&sigtraps[sig], SIG_DFL, - SS_RESTORE_CURR|SS_FORCE); - kill(0, sig); - } - } - exit(exstat); - /* NOTREACHED */ - } - - default: - quitenv(); - } - } -} - -void -newenv(type) - int type; -{ - register struct env *ep; - - ep = (struct env *) alloc(sizeof(*ep), ATEMP); - ep->type = type; - ep->flags = 0; - ainit(&ep->area); - ep->loc = e->loc; - ep->savefd = NULL; - ep->oenv = e; - ep->temps = NULL; - e = ep; -} - -void -quitenv() -{ - register struct env *ep = e; - register int fd; - - if (ep->oenv == NULL) /* cleanup_parents_env() was called */ - exit(exstat); /* exit child */ - if (ep->oenv->loc != ep->loc) - popblock(); - if (ep->savefd != NULL) { - for (fd = 0; fd < NUFILE; fd++) - /* if ep->savefd[fd] < 0, means fd was closed */ - if (ep->savefd[fd]) - restfd(fd, ep->savefd[fd]); - if (ep->savefd[2]) /* Clear any write errors */ - shf_reopen(2, SHF_WR, shl_out); - } - reclaim(); - e = e->oenv; - afree(ep, ATEMP); -} - -/* Called after a fork to cleanup stuff left over from parents environment */ -void -cleanup_parents_env() -{ - struct env *ep; - int fd; - - /* Don't clean up temporary files - parent will probably need them. - * Also, can't easily reclaim memory since variables, etc. could be - * anywyere. - */ - - /* close all file descriptors hiding in savefd */ - for (ep = e; ep; ep = ep->oenv) { - if (ep->savefd) - for (fd = 0; fd < NUFILE; fd++) - if (ep->savefd[fd] > 0) - close(ep->savefd[fd]); - } - e->oenv = (struct env *) 0; -} - -/* Called just before an execve cleanup stuff temporary files */ -void -cleanup_proc_env() -{ - struct env *ep; - - for (ep = e; ep; ep = ep->oenv) - remove_temps(ep->temps); - remove_temps(func_heredocs); -} - -/* remove temp files and free ATEMP Area */ -static void -reclaim() -{ - remove_temps(e->temps); - e->temps = NULL; - afreeall(&e->area); -} - -static void -remove_temps(tp) - struct temp *tp; -{ -#ifdef OS2 - static struct temp *delayed_remove; - struct temp *t, **tprev; - - if (delayed_remove) { - for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev) - /* No need to check t->pid here... */ - if (unlink(t->name) >= 0 || errno == ENOENT) { - *tprev = t->next; - afree(t, APERM); - } else - tprev = &t->next; - } -#endif /* OS2 */ - - for (; tp != NULL; tp = tp->next) - if (tp->pid == procpid) { -#ifdef OS2 - /* OS/2 (and dos) do not allow files that are currently - * open to be removed, so we cache it away for future - * removal. - * XXX should only do this if errno - * is Efile-still-open-can't-remove - * (but I don't know what that is...) - */ - if (unlink(tp->name) < 0 && errno != ENOENT) { - t = (struct temp *) alloc( - sizeof(struct temp) + strlen(tp->name) + 1, - APERM); - memset(t, 0, sizeof(struct temp)); - strcpy(t->name, tp->name); - t->next = delayed_remove; - delayed_remove = t; - } -#else /* OS2 */ - unlink(tp->name); -#endif /* OS2 */ - } -} - -/* Returns true if name refers to a restricted shell */ -static int -is_restricted(name) - char *name; -{ - char *p; - - if ((p = ksh_strrchr_dirsep(name))) - name = p; - /* accepts rsh, rksh, rpdksh, pdrksh, etc. */ - return (p = strchr(name, 'r')) && strstr(p, "sh"); -} - -void -aerror(ap, msg) - Area *ap; - const char *msg; -{ - internal_errorf(1, "alloc: %s", msg); - errorf(null); /* this is never executed - keeps gcc quiet */ - /*NOTREACHED*/ -} diff --git a/bin/pdksh/misc.c b/bin/pdksh/misc.c deleted file mode 100644 index 5287f4e9dfa..00000000000 --- a/bin/pdksh/misc.c +++ /dev/null @@ -1,1318 +0,0 @@ -/* $OpenBSD: misc.c,v 1.6 1997/06/19 13:58:45 kstailey Exp $ */ - -/* - * Miscellaneous functions - */ - -#include "sh.h" -#include <ctype.h> /* for FILECHCONV */ -#ifdef HAVE_LIMITS_H -# include <limits.h> -#endif - -#ifndef UCHAR_MAX -# define UCHAR_MAX 0xFF -#endif - -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, - int isfile)); -static const unsigned char *cclass ARGS((const unsigned char *p, int sub)); - -/* - * Fast character classes - */ -void -setctypes(s, t) - register const char *s; - register int t; -{ - register int i; - - 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 */ - } - while (*s != 0) - ctypes[(unsigned char) *s++] |= t; -} - -void -initctypes() -{ - register int c; - - for (c = 'a'; c <= 'z'; c++) - ctypes[c] |= C_ALPHA; - for (c = 'A'; c <= 'Z'; c++) - ctypes[c] |= C_ALPHA; - ctypes['_'] |= C_ALPHA; - setctypes("0123456789", C_DIGIT); - setctypes(" \t\n|&;<>()", C_LEX1); /* \0 added automatically */ - setctypes("*@#!$-?", C_VAR1); - setctypes(" \t\n", C_IFSWS); - setctypes("=-+?", C_SUBOP1); - setctypes("#%", C_SUBOP2); - setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE); -} - -/* convert unsigned long to base N string */ - -char * -ulton(n, base) - register unsigned long n; - int base; -{ - register char *p; - static char buf [20]; - - p = &buf[sizeof(buf)]; - *--p = '\0'; - do { - *--p = "0123456789ABCDEF"[n%base]; - n /= base; - } while (n != 0); - return p; -} - -char * -str_save(s, ap) - register const char *s; - Area *ap; -{ - return s ? strcpy((char*) alloc((size_t)strlen(s)+1, ap), s) : NULL; -} - -/* Allocate a string of size n+1 and copy upto n characters from the possibly - * null terminated string s into it. Always returns a null terminated string - * (unless n < 0). - */ -char * -str_nsave(s, n, ap) - register const char *s; - int n; - Area *ap; -{ - char *ns; - - if (n < 0) - return 0; - ns = alloc(n + 1, ap); - ns[0] = '\0'; - return strncat(ns, s, n); -} - -/* called from expand.h:XcheckN() to grow buffer */ -char * -Xcheck_grow_(xsp, xp, more) - XString *xsp; - char *xp; - int more; -{ - char *old_beg = xsp->beg; - - xsp->len += more > xsp->len ? more : xsp->len; - xsp->beg = aresize(xsp->beg, xsp->len + 8, xsp->areap); - xsp->end = xsp->beg + xsp->len; - return xsp->beg + (xp - old_beg); -} - -const struct option options[] = { - /* Special cases (see parse_args()): -A, -o, -s. - * Options are sorted by their longnames - the order of these - * entries MUST match the order of sh_flag F* enumerations in sh.h. - */ - { "allexport", 'a', OF_ANY }, -#ifdef BRACE_EXPAND - { "braceexpand", 0, OF_ANY }, /* non-standard */ -#endif - { "bgnice", 0, OF_ANY }, - { null, 'c', OF_CMDLINE }, -#ifdef EMACS - { "emacs", 0, OF_ANY }, -#endif - { "errexit", 'e', OF_ANY }, -#ifdef EMACS - { "gmacs", 0, OF_ANY }, -#endif - { "ignoreeof", 0, OF_ANY }, - { "interactive",'i', OF_CMDLINE }, - { "keyword", 'k', OF_ANY }, - { "login", 'l', OF_CMDLINE }, - { "markdirs", 'X', OF_ANY }, -#ifdef JOBS - { "monitor", 'm', OF_ANY }, -#else /* JOBS */ - { null, 'm', 0 }, /* so FMONITOR not ifdef'd */ -#endif /* JOBS */ - { "noclobber", 'C', OF_ANY }, - { "noexec", 'n', OF_ANY }, - { "noglob", 'f', OF_ANY }, - { "nohup", 0, OF_ANY }, - { "nolog", 0, OF_ANY }, /* no effect */ -#ifdef JOBS - { "notify", 'b', OF_ANY }, -#endif /* JOBS */ - { "nounset", 'u', OF_ANY }, - { "physical", 0, OF_ANY }, /* non-standard */ - { "posix", 0, OF_ANY }, /* non-standard */ - { "privileged", 'p', OF_ANY }, - { "restricted", 'r', OF_CMDLINE }, - { "sh", 0, OF_ANY }, /* non-standard */ - { "stdin", 's', OF_CMDLINE }, /* pseudo non-standard */ - { "trackall", 'h', OF_ANY }, - { "verbose", 'v', OF_ANY }, -#ifdef VI - { "vi", 0, OF_ANY }, - { "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 } -}; - -/* - * translate -o option into F* constant (also used for test -o option) - */ -int -option(n) - const char *n; -{ - int i; - - for (i = 0; options[i].name; i++) - if (strcmp(options[i].name, n) == 0) - return i; - - return -1; -} - -struct options_info { - int opt_width; - struct { - const char *name; - int flag; - } opts[NELEM(options)]; -}; - -static char *options_fmt_entry ARGS((void *arg, int i, char *buf, int buflen)); -static void printoptions ARGS((int verbose)); - -/* format a single select menu item */ -static char * -options_fmt_entry(arg, i, buf, buflen) - void *arg; - int i; - char *buf; - int buflen; -{ - struct options_info *oi = (struct options_info *) arg; - - shf_snprintf(buf, buflen, "%-*s %s", - oi->opt_width, oi->opts[i].name, - Flag(oi->opts[i].flag) ? "on" : "off"); - return buf; -} - -static void -printoptions(verbose) - int verbose; -{ - int i; - - if (verbose) { - struct options_info oi; - int n, len; - - /* verbose version */ - shprintf("Current option settings\n"); - - for (i = n = oi.opt_width = 0; options[i].name; i++) - if (options[i].name[0]) { - len = strlen(options[i].name); - oi.opts[n].name = options[i].name; - oi.opts[n++].flag = i; - if (len > oi.opt_width) - oi.opt_width = len; - } - print_columns(shl_stdout, n, options_fmt_entry, &oi, - oi.opt_width + 5); - } else { - /* short version ala ksh93 */ - shprintf("set"); - for (i = 0; options[i].name; i++) - if (Flag(i) && options[i].name[0]) - shprintf(" -o %s", options[i].name); - shprintf(newline); - } -} - -char * -getoptions() -{ - int i; - char m[FNFLAGS + 1]; - register char *cp = m; - - for (i = 0; options[i].name; i++) - if (options[i].c && Flag(i)) - *cp++ = options[i].c; - *cp = 0; - return str_save(m, ATEMP); -} - -/* change a Flag(*) value; takes care of special actions */ -void -change_flag(f, what, newval) - enum sh_flag f; /* flag to change */ - int what; /* what is changing the flag (command line vs set) */ - int newval; -{ - int oldval; - - oldval = Flag(f); - Flag(f) = newval; -#ifdef JOBS - if (f == FMONITOR) { - if (what != OF_CMDLINE && newval != oldval) - j_change(); - } else -#endif /* JOBS */ -#ifdef EDIT - if (0 -# ifdef VI - || f == FVI -# endif /* VI */ -# ifdef EMACS - || f == FEMACS || f == FGMACS -# endif /* EMACS */ - ) - { - if (newval) { -# ifdef VI - Flag(FVI) = 0; -# endif /* VI */ -# ifdef EMACS - Flag(FEMACS) = Flag(FGMACS) = 0; -# endif /* EMACS */ - Flag(f) = newval; - } - } else -#endif /* EDIT */ - /* Turning off -p? */ - if (f == FPRIVILEGED && oldval && !newval) { -#ifdef OS2 - ; -#else /* OS2 */ - seteuid(getuid()); - setuid(getuid()); - setegid(getgid()); - setgid(getgid()); -#endif /* OS2 */ - } else if (f == FPOSIX && newval) { -#ifdef BRACE_EXPAND - Flag(FBRACEEXPAND) = 0 -#endif /* BRACE_EXPAND */ - ; - } -} - -/* parse command line & set command arguments. returns the index of - * non-option arguments, -1 if there is an error. - */ -int -parse_args(argv, what, setargsp) - char **argv; - int what; /* OF_CMDLINE or OF_SET */ - int *setargsp; -{ - static char cmd_opts[NELEM(options) + 3]; /* o:\0 */ - static char set_opts[NELEM(options) + 5]; /* Ao;s\0 */ - char *opts; - char *array; - Getopt go; - int i, optc, set, sortargs = 0, arrayset = 0; - - /* First call? Build option strings... */ - if (cmd_opts[0] == '\0') { - char *p; - - /* c is also in options[], but it needs a trailing : */ - strcpy(cmd_opts, "o:"); /* see cmd_opts[] declaration */ - p = cmd_opts + strlen(cmd_opts); - for (i = 0; options[i].name; i++) - if (options[i].c && (options[i].flags & OF_CMDLINE)) - *p++ = options[i].c; - *p = '\0'; - - strcpy(set_opts, "Ao;s"); /* see set_opts[] declaration */ - p = set_opts + strlen(set_opts); - for (i = 0; options[i].name; i++) - if (options[i].c && (options[i].flags & OF_SET)) - *p++ = options[i].c; - *p = '\0'; - } - - if (what == OF_CMDLINE) { - char *p; - /* Set FLOGIN before parsing options so user can clear - * flag using +l. - */ - Flag(FLOGIN) = (argv[0][0] == '-' - || ((p = ksh_strrchr_dirsep(argv[0])) - && *++p == '-')); - opts = cmd_opts; - } else - opts = set_opts; - ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT); - while ((optc = ksh_getopt(argv, &go, opts)) != EOF) { - set = (go.info & GI_PLUS) ? 0 : 1; - switch (optc) { - case 'A': - arrayset = set ? 1 : -1; - break; - - case 'o': - if (go.optarg == (char *) 0) { - /* lone -o: print options - * - * Note that on the command line, -o requires - * an option (ie, can't get here if what is - * OF_CMDLINE). - */ - printoptions(set); - break; - } - i = option(go.optarg); - if (i >= 0 && set == Flag(i)) - /* Don't check the context if the flag - * isn't changing - makes "set -o interactive" - * work if you're already interactive. Needed - * if the output of "set +o" is to be used. - */ - ; - else if (i >= 0 && (options[i].flags & what)) - change_flag((enum sh_flag) i, what, set); - else { - bi_errorf("%s: bad option", go.optarg); - return -1; - } - break; - - case '?': - return -1; - - default: - /* -s: sort positional params (at&t ksh stupidity) */ - if (what == OF_SET && optc == 's') { - sortargs = 1; - break; - } - for (i = 0; options[i].name; i++) - if (optc == options[i].c - && (what & options[i].flags)) - { - change_flag((enum sh_flag) i, what, - set); - break; - } - if (!options[i].name) { - internal_errorf(1, "parse_args: `%c'", optc); - return -1; /* not reached */ - } - } - } - if (!(go.info & GI_MINUSMINUS) && argv[go.optind] - && (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') - && argv[go.optind][1] == '\0') - { - /* lone - clears -v and -x flags */ - if (argv[go.optind][0] == '-' && !Flag(FPOSIX)) - Flag(FVERBOSE) = Flag(FXTRACE) = 0; - /* set skips lone - or + option */ - go.optind++; - } - if (setargsp) - /* -- means set $#/$* even if there are no arguments */ - *setargsp = !arrayset && ((go.info & GI_MINUSMINUS) - || argv[go.optind]); - - if (arrayset) { - array = argv[go.optind++]; - if (!array) { - bi_errorf("-A: missing array name"); - return -1; - } - if (!*array || *skip_varname(array, FALSE)) { - bi_errorf("%s: is not an identifier", array); - return -1; - } - } else - array = (char *) 0; /* keep gcc happy */ - if (sortargs) { - for (i = go.optind; argv[i]; i++) - ; - qsortp((void **) &argv[go.optind], (size_t) (i - go.optind), - xstrcmp); - } - if (arrayset) { - set_array(array, arrayset, argv + go.optind); - for (; argv[go.optind]; go.optind++) - ; - } - - return go.optind; -} - -/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */ -int -getn(as, ai) - const char *as; - int *ai; -{ - const char *s; - register int n; - int sawdigit = 0; - - s = as; - if (*s == '-' || *s == '+') - s++; - for (n = 0; digit(*s); s++, sawdigit = 1) - n = n * 10 + (*s - '0'); - *ai = (*as == '-') ? -n : n; - if (*s || !sawdigit) - return 0; - return 1; -} - -/* getn() that prints error */ -int -bi_getn(as, ai) - const char *as; - int *ai; -{ - int rv = getn(as, ai); - - if (!rv) - bi_errorf("%s: bad number", as); - return rv; -} - -/* -------- gmatch.c -------- */ - -/* - * int gmatch(string, pattern) - * char *string, *pattern; - * - * Match a pattern as in sh(1). - * pattern character are prefixed with MAGIC by expand. - */ - -int -gmatch(s, p, isfile) - const char *s, *p; - int isfile; -{ - const char *se, *pe; - - if (s == NULL || p == NULL) - return 0; - se = s + strlen(s); - pe = p + strlen(p); - /* isfile is false iff no syntax check has been done on - * the pattern. If check fails, just to a strcmp(). - */ - if (!isfile && !has_globbing(p, pe)) { - int len = pe - p + 1; - char tbuf[64]; - char *t = len <= sizeof(tbuf) ? tbuf - : (char *) alloc(len, ATEMP); - debunk(t, p); - return !strcmp(t, s); - } - return do_gmatch((const unsigned char *) s, (const unsigned char *) se, - (const unsigned char *) p, (const unsigned char *) pe, - isfile); -} - -/* Returns if p is a syntacticly correct globbing pattern, false - * if it contains no pattern characters or if there is a syntax error. - * Syntax errors are: - * - [ with no closing ] - * - imballenced $(...) expression - * - [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d)) - */ -/*XXX -- if no magic, - if dest given, copy to dst - return ? -- if magic && (no globbing || syntax error) - debunk to dst - return ? -- return ? -*/ -int -has_globbing(xp, xpe) - const char *xp, *xpe; -{ - const unsigned char *p = (const unsigned char *) xp; - const unsigned char *pe = (const unsigned char *) xpe; - int c; - int nest = 0, bnest = 0; - int saw_glob = 0; - int in_bracket = 0; /* inside [...] */ - - for (; p < pe; p++) { - if (!ISMAGIC(*p)) - continue; - if ((c = *++p) == '*' || c == '?') - saw_glob = 1; - else if (c == '[') { - if (!in_bracket) { - saw_glob = 1; - in_bracket = 1; - if (ISMAGIC(p[1]) && p[2] == NOT) - p += 2; - if (ISMAGIC(p[1]) && p[2] == ']') - p += 2; - } - /* XXX Do we need to check ranges here? POSIX Q */ - } else if (c == ']') { - if (in_bracket) { - if (bnest) /* [a*(b]) */ - return 0; - in_bracket = 0; - } - } else if ((c & 0x80) && strchr("*+?@!", c & 0x7f)) { - saw_glob = 1; - if (in_bracket) - bnest++; - else - nest++; - } else if (c == '|') { - if (in_bracket && !bnest) /* *(a[foo|bar]) */ - return 0; - } else if (c == /*(*/ ')') { - if (in_bracket) { - if (!bnest--) /* *(a[b)c] */ - return 0; - } else if (nest) - nest--; - } - /* else must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, MAGIC-] - MAGIC-{, MAGIC-,, MAGIC-} */ - } - return saw_glob && !in_bracket && !nest; -} - -/* Function must return either 0 or 1 (assumed by code for 0x80|'!') */ -static int -do_gmatch(s, se, p, pe, isfile) - const unsigned char *s, *p; - const unsigned char *se, *pe; - int isfile; -{ - register int sc, pc; - const unsigned char *prest, *psub, *pnext; - const unsigned char *srest; - - if (s == NULL || p == NULL) - return 0; - while (p < pe) { - pc = *p++; - sc = s < se ? *s : '\0'; - s++; - if (isfile) { - sc = FILECHCONV(sc); - pc = FILECHCONV(pc); - } - if (!ISMAGIC(pc)) { - if (sc != pc) - return 0; - continue; - } - switch (*p++) { - case '[': - if (sc == 0 || (p = cclass(p, sc)) == NULL) - return 0; - break; - - case '?': - if (sc == 0) - return 0; - break; - - case '*': - if (p == pe) - return 1; - s--; - do { - if (do_gmatch(s, se, p, pe, isfile)) - return 1; - } while (s++ < se); - return 0; - -#ifdef KSH - /* [*+?@!](pattern|pattern|..) */ - case 0x80|'+': /* matches one or more times */ - case 0x80|'*': /* matches zero or more times */ - if (!(prest = pat_scan(p, pe, 0))) - return 0; - s--; - /* take care of zero matches */ - if (p[-1] == (0x80 | '*') - && do_gmatch(s, se, prest, pe, isfile)) - return 1; - for (psub = p; ; psub = pnext) { - pnext = pat_scan(psub, pe, 1); - for (srest = s; srest <= se; srest++) { - if (do_gmatch(s, srest, - psub, pnext - 2, isfile) - && (do_gmatch(srest, se, - prest, pe, isfile) - || (s != srest - && do_gmatch(srest, se, - p - 2, pe, isfile)))) - return 1; - } - if (pnext == prest) - break; - } - return 0; - - case 0x80|'?': /* matches zero or once */ - case 0x80|'@': /* matches one of the patterns */ - if (!(prest = pat_scan(p, pe, 0))) - return 0; - s--; - /* Take care of zero matches */ - if (p[-1] == (0x80 | '?') - && do_gmatch(s, se, prest, pe, isfile)) - return 1; - for (psub = p; ; psub = pnext) { - pnext = pat_scan(psub, pe, 1); - srest = prest == pe ? se : s; - for (; srest <= se; srest++) { - if (do_gmatch(s, srest, - psub, pnext - 2, isfile) - && do_gmatch(srest, se, - prest, pe, isfile)) - return 1; - } - if (pnext == prest) - break; - } - return 0; - - case 0x80|'!': /* matches none of the patterns */ - if (!(prest = pat_scan(p, pe, 0))) - return 0; - s--; - for (srest = s; srest <= se; srest++) { - int matched = 0; - - for (psub = p; ; psub = pnext) { - pnext = pat_scan(psub, pe, 1); - if (do_gmatch(s, srest, - psub, pnext - 2, isfile)) - { - matched = 1; - break; - } - if (pnext == prest) - break; - } - if (!matched && do_gmatch(srest, se, - prest, pe, isfile)) - return 1; - } - return 0; -#endif /* KSH */ - - default: - if (sc != p[-1]) - return 0; - break; - } - } - return s == se; -} - -static const unsigned char * -cclass(p, sub) - const unsigned char *p; - register int sub; -{ - register int c, d, not, found = 0; - const unsigned char *orig_p = p; - - if ((not = (ISMAGIC(*p) && *++p == NOT))) - p++; - do { - c = *p++; - if (ISMAGIC(c)) { - c = *p++; - if ((c & 0x80) && !ISMAGIC(c)) - c &= 0x7f;/* extended pattern matching: *+?@! */ - } - if (c == '\0') - /* No closing ] - act as if the opening [ was quoted */ - return sub == '[' ? orig_p : NULL; - if (ISMAGIC(p[0]) && p[1] == '-' - && (!ISMAGIC(p[2]) || p[3] != ']')) - { - p += 2; /* MAGIC- */ - d = *p++; - if (ISMAGIC(d)) { - d = *p++; - if ((d & 0x80) && !ISMAGIC(d)) - d &= 0x7f; - } - /* POSIX says this is an invalid expression */ - if (c > d) - return NULL; - } else - d = c; - if (c == sub || (c <= sub && sub <= d)) - found = 1; - } while (!(ISMAGIC(p[0]) && p[1] == ']')); - - return (found != not) ? p+2 : NULL; -} - -/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */ -const unsigned char * -pat_scan(p, pe, match_sep) - const unsigned char *p; - const unsigned char *pe; - int match_sep; -{ - int nest = 0; - - for (; p < pe; p++) { - if (!ISMAGIC(*p)) - continue; - if ((*++p == /*(*/ ')' && nest-- == 0) - || (*p == '|' && match_sep && nest == 0)) - return ++p; - if ((*p & 0x80) && strchr("*+?@!", *p & 0x7f)) - nest++; - } - return (const unsigned char *) 0; -} - - -/* -------- qsort.c -------- */ - -/* - * quick sort of array of generic pointers to objects. - */ -static void qsort1 ARGS((void **base, void **lim, int (*f)(void *, void *))); - -void -qsortp(base, n, f) - void **base; /* base address */ - size_t n; /* elements */ - int (*f) ARGS((void *, void *)); /* compare function */ -{ - qsort1(base, base + n, f); -} - -#define swap2(a, b) {\ - register void *t; t = *(a); *(a) = *(b); *(b) = t;\ -} -#define swap3(a, b, c) {\ - register void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\ -} - -static void -qsort1(base, lim, f) - void **base, **lim; - int (*f) ARGS((void *, void *)); -{ - register void **i, **j; - register void **lptr, **hptr; - size_t n; - int c; - - top: - n = (lim - base) / 2; - if (n == 0) - return; - hptr = lptr = base+n; - i = base; - j = lim - 1; - - for (;;) { - if (i < lptr) { - if ((c = (*f)(*i, *lptr)) == 0) { - lptr --; - swap2(i, lptr); - continue; - } - if (c < 0) { - i += 1; - continue; - } - } - - begin: - if (j > hptr) { - if ((c = (*f)(*hptr, *j)) == 0) { - hptr ++; - swap2(hptr, j); - goto begin; - } - if (c > 0) { - if (i == lptr) { - hptr ++; - swap3(i, hptr, j); - i = lptr += 1; - goto begin; - } - swap2(i, j); - j -= 1; - i += 1; - continue; - } - j -= 1; - goto begin; - } - - if (i == lptr) { - if (lptr-base >= lim-hptr) { - qsort1(hptr+1, lim, f); - lim = lptr; - } else { - qsort1(base, lptr, f); - base = hptr+1; - } - goto top; - } - - lptr -= 1; - swap3(j, lptr, i); - j = hptr -= 1; - } -} - -int -xstrcmp(p1, p2) - void *p1, *p2; -{ - return (strcmp((char *)p1, (char *)p2)); -} - -/* Initialize a Getopt structure */ -void -ksh_getopt_reset(go, flags) - Getopt *go; - int flags; -{ - go->optind = 1; - go->optarg = (char *) 0; - go->p = 0; - go->flags = flags; - go->info = 0; - go->buf[1] = '\0'; -} - - -/* getopt() used for shell built-in commands, the getopts command, and - * command line options. - * A leading ':' in options means don't print errors, instead return '?' - * or ':' and set go->optarg to the offending option character. - * If GF_ERROR is set (and option doesn't start with :), errors result in - * a call to bi_errorf(). - * - * Non-standard features: - * - ';' is like ':' in options, except the argument is optional - * (if it isn't present, optarg is set to 0). - * Used for 'set -o'. - * - ',' is like ':' in options, except the argument always immediately - * follows the option character (optarg is set to the null string if - * the option is missing). - * Used for 'read -u2', 'print -u2' and fc -40. - * - '#' is like ':' in options, expect that the argument is optional - * and must start with a digit. If the argument doesn't start with a - * digit, it is assumed to be missing and normal option processing - * continues (optarg is set to 0 if the option is missing). - * Used for 'typeset -LZ4'. - * - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an - * option starting with + is accepted, the GI_PLUS flag will be set - * in go->info. Once a - or + has been seen, all other options must - * start with the same character. - */ -int -ksh_getopt(argv, go, options) - char **argv; - Getopt *go; - const char *options; -{ - char c; - char *o; - - if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') { - char *arg = argv[go->optind], flag = arg ? *arg : '\0'; - - go->p = 1; - if (flag == '-' && arg[1] == '-' && arg[2] == '\0') { - go->optind++; - go->p = 0; - go->info |= GI_MINUSMINUS; - return EOF; - } - if (arg == (char *) 0 - || ((flag != '-' || (go->info & GI_PLUS)) - && (!(go->flags & GF_PLUSOPT) || (go->info & GI_MINUS) - || flag != '+')) - || (c = arg[1]) == '\0') - { - go->p = 0; - return EOF; - } - go->optind++; - go->info |= flag == '-' ? GI_MINUS : GI_PLUS; - } - go->p++; - if (c == '?' || c == ':' || c == ';' || c == ',' || c == '#' - || !(o = strchr(options, c))) - { - if (options[0] == ':') { - go->buf[0] = c; - go->optarg = go->buf; - } else { - warningf(TRUE, "%s%s-%c: unknown option", - (go->flags & GF_NONAME) ? "" : argv[0], - (go->flags & GF_NONAME) ? "" : ": ", c); - if (go->flags & GF_ERROR) - bi_errorf(null); - } - return '?'; - } - /* : means argument must be present, may be part of option argument - * or the next argument - * ; same as : but argument may be missing - * , means argument is part of option argument, and may be null. - */ - if (*++o == ':' || *o == ';') { - if (argv[go->optind - 1][go->p]) - go->optarg = argv[go->optind - 1] + go->p; - else if (argv[go->optind]) - go->optarg = argv[go->optind++]; - else if (*o == ';') - go->optarg = (char *) 0; - else { - if (options[0] == ':') { - go->buf[0] = c; - go->optarg = go->buf; - return ':'; - } - warningf(TRUE, "%s%s-`%c' requires argument", - (go->flags & GF_NONAME) ? "" : argv[0], - (go->flags & GF_NONAME) ? "" : ": ", c); - if (go->flags & GF_ERROR) - bi_errorf(null); - return '?'; - } - go->p = 0; - } else if (*o == ',') { - /* argument is attatched to option character, even if null */ - go->optarg = argv[go->optind - 1] + go->p; - go->p = 0; - } else if (*o == '#') { - /* argument is optional and may be attatched or unattatched - * but must start with a digit. optarg is set to 0 if the - * argument is missing. - */ - if (argv[go->optind - 1][go->p]) { - if (digit(argv[go->optind - 1][go->p])) { - go->optarg = argv[go->optind - 1] + go->p; - go->p = 0; - } else - go->optarg = (char *) 0;; - } else { - if (argv[go->optind] && digit(argv[go->optind][0])) { - go->optarg = argv[go->optind++]; - go->p = 0; - } else - go->optarg = (char *) 0;; - } - } - return c; -} - -/* print variable/alias value using necessary quotes - * (POSIX says they should be suitable for re-entry...) - * No trailing newline is printed. - */ -void -print_value_quoted(s) - const char *s; -{ - const char *p; - int inquote = 0; - - /* Test if any quotes are needed */ - for (p = s; *p; p++) - if (ctype(*p, C_QUOTE)) - break; - if (!*p) { - shprintf("%s", s); - return; - } - for (p = s; *p; p++) { - if (*p == '\'') { - shprintf("'\\'" + 1 - inquote); - inquote = 0; - } else { - if (!inquote) { - shprintf("'"); - inquote = 1; - } - shf_putc(*p, shl_stdout); - } - } - if (inquote) - shprintf("'"); -} - -/* Print things in columns and rows - func() is called to format the ith - * element - */ -void -print_columns(shf, n, func, arg, max_width) - struct shf *shf; - int n; - char *(*func) ARGS((void *, int, char *, int)); - void *arg; - int max_width; -{ - char *str = (char *) alloc(max_width + 1, ATEMP); - int i; - int r, c; - int rows, cols; - int nspace; - - /* max_width + 1 for the space. Note that no space - * is printed after the last column to avoid problems - * with terminals that have auto-wrap. - */ - cols = x_cols / (max_width + 1); - if (!cols) - cols = 1; - rows = (n + cols - 1) / cols; - if (n && cols > rows) { - int tmp = rows; - - rows = cols; - cols = tmp; - if (rows > n) - rows = n; - } - - nspace = (x_cols - max_width * cols) / cols; - if (nspace <= 0) - nspace = 1; - for (r = 0; r < rows; r++) { - for (c = 0; c < cols; c++) { - i = c * rows + r; - if (i < n) { - shf_fprintf(shf, "%-*s", - max_width, - (*func)(arg, i, str, max_width + 1)); - if (c + 1 < cols) - shf_fprintf(shf, "%*s", nspace, null); - } - } - shf_putchar('\n', shf); - } - afree(str, ATEMP); -} - -/* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */ -int -strip_nuls(buf, nbytes) - char *buf; - int nbytes; -{ - char *dst; - - /* nbytes check because some systems (older freebsd's) have a buggy - * memchr() - */ - if (nbytes && (dst = memchr(buf, '\0', nbytes))) { - char *end = buf + nbytes; - char *p, *q; - - for (p = dst; p < end; p = q) { - /* skip a block of nulls */ - while (++p < end && *p == '\0') - ; - /* find end of non-null block */ - if (!(q = memchr(p, '\0', end - p))) - q = end; - memmove(dst, p, q - p); - dst += q - p; - } - *dst = '\0'; - return dst - buf; - } - return nbytes; -} - -/* Copy at most dsize-1 bytes from src to dst, ensuring dst is null terminated. - * Returns dst. - */ -char * -str_zcpy(dst, src, dsize) - char *dst; - const char *src; - int dsize; -{ - if (dsize > 0) { - int len = strlen(src); - - if (len >= dsize) - len = dsize - 1; - memcpy(dst, src, len); - dst[len] = '\0'; - } - return dst; -} - -/* Like read(2), but if read fails due to non-blocking flag, resets flag - * and restarts read. - */ -int -blocking_read(fd, buf, nbytes) - int fd; - char *buf; - int nbytes; -{ - int ret; - int tried_reset = 0; - - while ((ret = read(fd, buf, nbytes)) < 0) { - if (!tried_reset && (errno == EAGAIN -#ifdef EWOULDBLOCK - || errno == EWOULDBLOCK -#endif /* EWOULDBLOCK */ - )) - { - int oerrno = errno; - if (reset_nonblock(fd) > 0) { - tried_reset = 1; - continue; - } - errno = oerrno; - } - break; - } - return ret; -} - -/* Reset the non-blocking flag on the specified file descriptor. - * Returns -1 if there was an error, 0 if non-blocking wasn't set, - * 1 if it was. - */ -int -reset_nonblock(fd) - int fd; -{ - int flags; - int blocking_flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) < 0) - return -1; - /* With luck, the C compiler will reduce this to a constant */ - blocking_flags = 0; -#ifdef O_NONBLOCK - blocking_flags |= O_NONBLOCK; -#endif /* O_NONBLOCK */ -#ifdef O_NDELAY - blocking_flags |= O_NDELAY; -#else /* O_NDELAY */ -# ifndef O_NONBLOCK - blocking_flags |= FNDELAY; /* hope this exists... */ -# endif /* O_NONBLOCK */ -#endif /* O_NDELAY */ - if (!(flags & blocking_flags)) - return 0; - flags &= ~blocking_flags; - if (fcntl(fd, F_SETFL, flags) < 0) - return -1; - return 1; -} - - -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif /* HAVE_SYS_PARAM_H */ -#ifndef MAXPATHLEN -# define MAXPATHLEN PATH -#endif /* MAXPATHLEN */ - -/* Like getcwd(), except bsize is ignored if buf is 0 (MAXPATHLEN is used) */ -char * -ksh_get_wd(buf, bsize) - char *buf; - int bsize; -{ -#ifdef HAVE_GETWD - extern char *getwd ARGS((char *)); - char *b; - int len; - - if (buf && bsize > MAXPATHLEN) - b = buf; - else - b = alloc(MAXPATHLEN + 1, ATEMP); - if (!getwd(b)) { - errno = EACCES; - if (b != buf) - afree(b, ATEMP); - return (char *) 0; - } - len = strlen(b) + 1; - if (!buf) - b = aresize(b, len, ATEMP); - else if (buf != b) { - if (len > bsize) { - errno = ERANGE; - return (char *) 0; - } - memcpy(buf, b, len); - afree(b, ATEMP); - b = buf; - } - - return b; -#else /* HAVE_GETWD */ - char *b; - char *ret; - - /* Assume getcwd() available */ - if (!buf) { - bsize = MAXPATHLEN; - b = alloc(MAXPATHLEN + 1, ATEMP); - } else - b = buf; - - ret = getcwd(b, bsize); - - if (!buf) { - if (ret) - ret = aresize(b, strlen(b) + 1, ATEMP); - else - afree(b, ATEMP); - } - - return ret; -#endif /* HAVE_GETWD */ -} diff --git a/bin/pdksh/missing.c b/bin/pdksh/missing.c deleted file mode 100644 index 7f507fe66b9..00000000000 --- a/bin/pdksh/missing.c +++ /dev/null @@ -1,271 +0,0 @@ -/* $OpenBSD: missing.c,v 1.3 1997/06/19 13:58:45 kstailey Exp $ */ - -/* - * Routines which may be missing on some machines - */ - -#include "sh.h" -#include "ksh_stat.h" -#include "ksh_dir.h" - - -#ifndef HAVE_MEMSET -void * -memset(d, c, n) - void *d; - int c; - size_t n; -{ - unsigned char *p = (unsigned char *) d; - - /* Not amazingly fast.. */ - for (; n > 0; --n) - *p++ = c; - return d; -} -#endif /* !HAVE_MEMSET */ - -#if !defined(HAVE_MEMMOVE) && !defined(HAVE_BCOPY) -void * -memmove(d, s, n) - void *d; - const void *s; - size_t n; -{ - char *dp = (char *) d, *sp = (char *) s; - - if (n <= 0) - ; - else if (dp < sp) - do - *dp++ = *sp++; - while (--n > 0); - else if (dp > sp) { - dp += n; - sp += n; - do - *--dp = *--sp; - while (--n > 0); - } - return d; -} -#endif /* !HAVE_MEMMOVE && !HAVE_BCOPY */ - - -#ifndef HAVE_STRCASECMP -/* - * Case insensitive string compare routines, same semantics as str[n]cmp() - * (assumes ASCII..). - */ -static const char ichars[256] = { - 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, - 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff - }; - -int -strcasecmp(s1, s2) - const char *s1; - const char *s2; -{ - const unsigned char *us1 = (const unsigned char *) s1; - const unsigned char *us2 = (const unsigned char *) s2; - - while (ichars[*us1] == ichars[*us2++]) - if (!*us1++) - return 0; - - return ichars[*us1] - ichars[*--us2]; -} - -int -strncasecmp(s1, s2, n) - const char *s1; - const char *s2; - int n; -{ - const unsigned char *us1 = (const unsigned char *) s1; - const unsigned char *us2 = (const unsigned char *) s2; - - while (--n >= 0 && ichars[*us1] == ichars[*us2++]) - if (!*us1++) - return 0; - - return n < 0 ? 0 : ichars[*us1] - ichars[*--us2]; -} -#endif /* HAVE_STRCASECMP */ - - -#ifndef HAVE_STRSTR -char * -strstr(s, p) - const char *s; - const char *p; -{ - int len; - - if (s && p) - for (len = strlen(p); *s; s++) - if (*s == *p && strncmp(s, p, len) == 0) - return (char *) s; - - return 0; -} -#endif /* HAVE_STRSTR */ - - -#ifndef HAVE_STRERROR -char * -strerror(err) - int err; -{ - static char buf[64]; -# ifdef HAVE_SYS_ERRLIST -# ifndef SYS_ERRLIST_DECLARED - extern int sys_nerr; - extern char *sys_errlist[]; -# endif - char *p; - - if (err < 0 || err >= sys_nerr) - shf_snprintf(p = buf, sizeof(buf), "Unknown system error %d", - err); - else - p = sys_errlist[err]; - return p; -# else /* HAVE_SYS_ERRLIST */ - switch (err) { - case EINVAL: - return "Invalid argument"; - case EACCES: - return "Permission denied"; - case ESRCH: - return "No such process"; - case EPERM: - return "Not owner"; - case ENOENT: - return "No such file or directory"; - case ENOTDIR: - return "Not a directory"; - case ENOEXEC: - return "Exec format error"; - case ENOMEM: - return "Not enough memory"; - case E2BIG: - return "Argument list too long"; - default: - shf_snprintf(buf, sizeof(buf), "Unknown system error %d", err); - return buf; - } -# endif /* HAVE_SYS_ERRLIST */ -} -#endif /* !HAVE_STRERROR */ - - -#ifdef TIMES_BROKEN -# include "ksh_time.h" -# include "ksh_times.h" -# ifdef HAVE_GETRUSAGE -# include <sys/resource.h> -# else /* HAVE_GETRUSAGE */ -# include <sys/timeb.h> -# endif /* HAVE_GETRUSAGE */ - -clock_t -ksh_times(tms) - struct tms *tms; -{ - static clock_t base_sec; - clock_t rv; - -# ifdef HAVE_GETRUSAGE - { - struct timeval tv; - struct rusage ru; - - getrusage(RUSAGE_SELF, &ru); - tms->tms_utime = ru.ru_utime.tv_sec * CLK_TCK - + ru.ru_utime.tv_usec * CLK_TCK / 1000000; - tms->tms_stime = ru.ru_stime.tv_sec * CLK_TCK - + ru.ru_stime.tv_usec * CLK_TCK / 1000000; - - getrusage(RUSAGE_CHILDREN, &ru); - tms->tms_cutime = ru.ru_utime.tv_sec * CLK_TCK - + ru.ru_utime.tv_usec * CLK_TCK / 1000000; - tms->tms_cstime = ru.ru_stime.tv_sec * CLK_TCK - + ru.ru_stime.tv_usec * CLK_TCK / 1000000; - - gettimeofday(&tv, (struct timezone *) 0); - if (base_sec == 0) - base_sec = tv.tv_sec; - rv = (tv.tv_sec - base_sec) * CLK_TCK; - rv += tv.tv_usec * CLK_TCK / 1000000; - } -# else /* HAVE_GETRUSAGE */ - /* Assume times() available, but always returns 0 - * (also assumes ftime() available) - */ - { - struct timeb tb; - - if (times(tms) == (clock_t) -1) - return (clock_t) -1; - ftime(&tb); - if (base_sec == 0) - base_sec = tb.time; - rv = (tb.time - base_sec) * CLK_TCK; - rv += tb.millitm * CLK_TCK / 1000; - } -# endif /* HAVE_GETRUSAGE */ - return rv; -} -#endif /* TIMES_BROKEN */ - -#ifdef OPENDIR_DOES_NONDIR -/* Prevent opendir() from attempting to open non-directories. Such - * behavior can cause problems if it attempts to open special devices... - */ -DIR * -ksh_opendir(d) - const char *d; -{ - struct stat statb; - - if (stat(d, &statb) != 0) - return (DIR *) 0; - if (!S_ISDIR(statb.st_mode)) { - errno = ENOTDIR; - return (DIR *) 0; - } - return opendir(d); -} -#endif /* OPENDIR_DOES_NONDIR */ diff --git a/bin/pdksh/path.c b/bin/pdksh/path.c deleted file mode 100644 index d0a08761d9a..00000000000 --- a/bin/pdksh/path.c +++ /dev/null @@ -1,346 +0,0 @@ -/* $OpenBSD: path.c,v 1.3 1997/06/19 13:58:46 kstailey Exp $ */ - -#include "sh.h" -#include "ksh_stat.h" - -/* - * Contains a routine to search a : seperated list of - * paths (a la CDPATH) and make appropiate file names. - * Also contains a routine to simplify .'s and ..'s out of - * a path name. - * - * Larry Bouzane (larry@cs.mun.ca) - */ - -/* - * $Log: path.c,v $ - * Revision 1.3 1997/06/19 13:58:46 kstailey - * back out - * - * Revision 1.1.1.1 1996/08/14 06:19:11 downsj - * Import pdksh 5.2.7. - * - * Revision 1.2 1994/05/19 18:32:40 michael - * Merge complete, stdio replaced, various fixes. (pre autoconf) - * - * Revision 1.1 1994/04/06 13:14:03 michael - * Initial revision - * - * Revision 4.2 1990/12/06 18:05:24 larry - * Updated test code to reflect parameter change. - * Fixed problem with /a/./.dir being simplified to /a and not /a/.dir due - * to *(cur+2) == *f test instead of the correct cur+2 == f - * - * Revision 4.1 90/10/29 14:42:19 larry - * base MUN version - * - * Revision 3.1.0.4 89/02/16 20:28:36 larry - * Forgot to set *pathlist to NULL when last changed make_path(). - * - * Revision 3.1.0.3 89/02/13 20:29:55 larry - * Fixed up cd so that it knew when a node from CDPATH was used and would - * print a message only when really necessary. - * - * Revision 3.1.0.2 89/02/13 17:51:22 larry - * Merged with Eric Gisin's version. - * - * Revision 3.1.0.1 89/02/13 17:50:58 larry - * *** empty log message *** - * - * Revision 3.1 89/02/13 17:49:28 larry - * *** empty log message *** - * - */ - -#ifdef S_ISLNK -static char *do_phys_path ARGS((XString *xsp, char *xp, const char *path)); -#endif /* S_ISLNK */ - -/* - * Makes a filename into result using the following algorithm. - * - make result NULL - * - if file starts with '/', append file to result & set cdpathp to NULL - * - if file starts with ./ or ../ append cwd and file to result - * and set cdpathp to NULL - * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx - * then cwd is appended to result. - * - the first element of cdpathp is appended to result - * - file is appended to result - * - cdpathp is set to the start of the next element in cdpathp (or NULL - * if there are no more elements. - * The return value indicates whether a non-null element from cdpathp - * was appened to result. - */ -int -make_path(cwd, file, cdpathp, xsp, phys_pathp) - const char *cwd; - const char *file; - char **cdpathp; /* & of : seperated list */ - XString *xsp; - int *phys_pathp; -{ - int rval = 0; - int use_cdpath = 1; - char *plist; - int len; - int plen = 0; - char *xp = Xstring(*xsp, xp); - - if (!file) - file = null; - - if (!ISRELPATH(file)) { - *phys_pathp = 0; - use_cdpath = 0; - } else { - if (file[0] == '.') { - char c = file[1]; - - if (c == '.') - c = file[2]; - if (ISDIRSEP(c) || c == '\0') - use_cdpath = 0; - } - - plist = *cdpathp; - if (!plist) - use_cdpath = 0; - else if (use_cdpath) { - char *pend; - - for (pend = plist; *pend && *pend != PATHSEP; pend++) - ; - plen = pend - plist; - *cdpathp = *pend ? ++pend : (char *) 0; - } - - if ((use_cdpath == 0 || !plen || ISRELPATH(plist)) - && (cwd && *cwd)) - { - len = strlen(cwd); - XcheckN(*xsp, xp, len); - memcpy(xp, cwd, len); - xp += len; - if (!ISDIRSEP(cwd[len - 1])) - Xput(*xsp, xp, DIRSEP); - } - *phys_pathp = Xlength(*xsp, xp); - if (use_cdpath && plen) { - XcheckN(*xsp, xp, plen); - memcpy(xp, plist, plen); - xp += plen; - if (!ISDIRSEP(plist[plen - 1])) - Xput(*xsp, xp, DIRSEP); - rval = 1; - } - } - - len = strlen(file) + 1; - XcheckN(*xsp, xp, len); - memcpy(xp, file, len); - - if (!use_cdpath) - *cdpathp = (char *) 0; - - return rval; -} - -/* - * Simplify pathnames containing "." and ".." entries. - * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b" - */ -void -simplify_path(path) - char *path; -{ - char *cur; - char *t; - int isrooted; - char *very_start = path; - char *start; - - if (!*path) - return; - - if ((isrooted = ISROOTEDPATH(path))) - very_start++; -#ifdef OS2 - if (path[0] && path[1] == ':') /* skip a: */ - very_start += 2; -#endif /* OS2 */ - - /* Before After - * /foo/ /foo - * /foo/../../bar /bar - * /foo/./blah/.. /foo - * . . - * .. .. - * ./foo foo - * foo/../../../bar ../../bar - * OS2: - * a:/foo/../.. a:/ - * a:. a: - * a:.. a:.. - * a:foo/../../blah a:../blah - */ - - for (cur = t = start = very_start; ; ) { - /* treat multiple '/'s as one '/' */ - while (ISDIRSEP(*t)) - t++; - - if (*t == '\0') { - if (cur == path) - /* convert empty path to dot */ - *cur++ = '.'; - *cur = '\0'; - break; - } - - if (t[0] == '.') { - if (!t[1] || ISDIRSEP(t[1])) { - t += 1; - continue; - } else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) { - if (!isrooted && cur == start) { - if (cur != very_start) - *cur++ = DIRSEP; - *cur++ = '.'; - *cur++ = '.'; - start = cur; - } else if (cur != start) - while (--cur > start && !ISDIRSEP(*cur)) - ; - t += 2; - continue; - } - } - - if (cur != very_start) - *cur++ = DIRSEP; - - /* find/copy next component of pathname */ - while (*t && !ISDIRSEP(*t)) - *cur++ = *t++; - } -} - - -void -set_current_wd(path) - char *path; -{ - int len; - char *p = path; - - if (!p && !(p = ksh_get_wd((char *) 0, 0))) - p = null; - - len = strlen(p) + 1; - - if (len > current_wd_size) - current_wd = aresize(current_wd, current_wd_size = len, APERM); - memcpy(current_wd, p, len); - if (p != path && p != null) - afree(p, ATEMP); -} - -#ifdef S_ISLNK -char * -get_phys_path(path) - const char *path; -{ - XString xs; - char *xp; - - Xinit(xs, xp, strlen(path) + 1, ATEMP); - - xp = do_phys_path(&xs, xp, path); - - if (!xp) - return (char *) 0; - - if (Xlength(xs, xp) == 0) - Xput(xs, xp, DIRSEP); - Xput(xs, xp, '\0'); - - return Xclose(xs, xp); -} - -static char * -do_phys_path(xsp, xp, path) - XString *xsp; - char *xp; - const char *path; -{ - const char *p, *q; - int len, llen; - int savepos; - char lbuf[PATH]; - - Xcheck(*xsp, xp); - for (p = path; p; p = q) { - while (ISDIRSEP(*p)) - p++; - if (!*p) - break; - len = (q = ksh_strchr_dirsep(p)) ? q - p : strlen(p); - if (len == 1 && p[0] == '.') - continue; - if (len == 2 && p[0] == '.' && p[1] == '.') { - while (xp > Xstring(*xsp, xp)) { - xp--; - if (ISDIRSEP(*xp)) - break; - } - continue; - } - - savepos = Xsavepos(*xsp, xp); - Xput(*xsp, xp, DIRSEP); - XcheckN(*xsp, xp, len + 1); - memcpy(xp, p, len); - xp += len; - *xp = '\0'; - - llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1); - if (llen < 0) { - /* EINVAL means it wasn't a symlink... */ - if (errno != EINVAL) - return (char *) 0; - continue; - } - lbuf[llen] = '\0'; - - /* If absolute path, start from scratch.. */ - xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp) - : Xrestpos(*xsp, xp, savepos); - if (!(xp = do_phys_path(xsp, xp, lbuf))) - return (char *) 0; - } - return xp; -} -#endif /* S_ISLNK */ - -#ifdef TEST - -main(argc, argv) -{ - int rv; - char *cp, cdpath[256], pwd[256], file[256], result[256]; - - printf("enter CDPATH: "); gets(cdpath); - printf("enter PWD: "); gets(pwd); - while (1) { - if (printf("Enter file: "), gets(file) == 0) - return 0; - cp = cdpath; - do { - rv = make_path(pwd, file, &cp, result, sizeof(result)); - printf("make_path returns (%d), \"%s\" ", rv, result); - simplify_path(result); - printf("(simpifies to \"%s\")\n", result); - } while (cp); - } -} -#endif /* TEST */ diff --git a/bin/pdksh/proto.h b/bin/pdksh/proto.h deleted file mode 100644 index 608b451f593..00000000000 --- a/bin/pdksh/proto.h +++ /dev/null @@ -1,292 +0,0 @@ -/* $OpenBSD: proto.h,v 1.3 1996/11/21 07:59:34 downsj Exp $ */ - -/* - * prototypes for PD-KSH - * originally generated using "cproto.c 3.5 92/04/11 19:28:01 cthuang " - * $From: proto.h,v 1.3 1994/05/19 18:32:40 michael Exp michael $ - */ - -/* alloc.c */ -Area * ainit ARGS((Area *ap)); -void afreeall ARGS((Area *ap)); -void * alloc ARGS((size_t size, Area *ap)); -void * aresize ARGS((void *ptr, size_t size, Area *ap)); -void afree ARGS((void *ptr, Area *ap)); -/* c_ksh.c */ -int c_hash ARGS((char **wp)); -int c_cd ARGS((char **wp)); -int c_pwd ARGS((char **wp)); -int c_print ARGS((char **wp)); -int c_whence ARGS((char **wp)); -int c_command ARGS((char **wp)); -int c_typeset ARGS((char **wp)); -int c_alias ARGS((char **wp)); -int c_unalias ARGS((char **wp)); -int c_let ARGS((char **wp)); -int c_jobs ARGS((char **wp)); -int c_fgbg ARGS((char **wp)); -int c_kill ARGS((char **wp)); -void getopts_reset ARGS((int val)); -int c_getopts ARGS((char **wp)); -int c_bind ARGS((char **wp)); -/* c_sh.c */ -int c_label ARGS((char **wp)); -int c_shift ARGS((char **wp)); -int c_umask ARGS((char **wp)); -int c_dot ARGS((char **wp)); -int c_wait ARGS((char **wp)); -int c_read ARGS((char **wp)); -int c_eval ARGS((char **wp)); -int c_trap ARGS((char **wp)); -int c_brkcont ARGS((char **wp)); -int c_exitreturn ARGS((char **wp)); -int c_set ARGS((char **wp)); -int c_unset ARGS((char **wp)); -int c_ulimit ARGS((char **wp)); -int c_times ARGS((char **wp)); -int timex ARGS((struct op *t, int f)); -int c_exec ARGS((char **wp)); -int c_builtin ARGS((char **wp)); -/* c_test.c */ -int c_test ARGS((char **wp)); -/* edit.c: most prototypes in edit.h */ -void x_init ARGS((void)); -int x_read ARGS((char *buf, size_t len)); -void set_editmode ARGS((const char *ed)); -/* emacs.c: most prototypes in edit.h */ -int x_bind ARGS((const char *a1, const char *a2, int macro, - int list)); -/* eval.c */ -char * substitute ARGS((const char *cp, int f)); -char ** eval ARGS((char **ap, int f)); -char * evalstr ARGS((char *cp, int f)); -char * evalonestr ARGS((char *cp, int f)); -char *debunk ARGS((char *dp, const char *sp)); -void expand ARGS((char *cp, XPtrV *wp, int f)); -int glob_str ARGS((char *cp, XPtrV *wp, int markdirs)); -/* exec.c */ -int fd_clexec ARGS((int fd)); -int execute ARGS((struct op * volatile t, volatile int flags)); -int shcomexec ARGS((char **wp)); -struct tbl * findfunc ARGS((const char *name, unsigned int h, int create)); -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 *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)); -int v_evaluate ARGS((struct tbl *vp, const char *expr, volatile int error_ok)); -/* history.c */ -void init_histvec ARGS((void)); -void hist_init ARGS((Source *s)); -void hist_finish ARGS((void)); -void histsave ARGS((int lno, const char *cmd, int dowrite)); -#ifdef HISTORY -int c_fc ARGS((register char **wp)); -void sethistsize ARGS((int n)); -void sethistfile ARGS((const char *name)); -# ifdef EASY_HISTORY -void histappend ARGS((const char *cmd, int nl_seperate)); -# endif -char ** histpos ARGS((void)); -int histN ARGS((void)); -int histnum ARGS((int n)); -int findhist ARGS((int start, int fwd, const char *str, - int anchored)); -#endif /* HISTORY */ -/* io.c */ -void errorf ARGS((const char *fmt, ...)) - GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2)); -void warningf ARGS((int fileline, const char *fmt, ...)) - GCC_FUNC_ATTR(format(printf, 2, 3)); -void bi_errorf ARGS((const char *fmt, ...)) - GCC_FUNC_ATTR(format(printf, 1, 2)); -void internal_errorf ARGS((int jump, const char *fmt, ...)) - GCC_FUNC_ATTR(format(printf, 2, 3)); -void error_prefix ARGS((int fileline)); -void shellf ARGS((const char *fmt, ...)) - GCC_FUNC_ATTR(format(printf, 1, 2)); -void shprintf ARGS((const char *fmt, ...)) - GCC_FUNC_ATTR(format(printf, 1, 2)); -int can_seek ARGS((int fd)); -void initio ARGS((void)); -int ksh_dup2 ARGS((int ofd, int nfd, int errok)); -int savefd ARGS((int fd, int noclose)); -void restfd ARGS((int fd, int ofd)); -void openpipe ARGS((int *pv)); -void closepipe ARGS((int *pv)); -int check_fd ARGS((char *name, int mode, const char **emsgp)); -#ifdef KSH -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 coproc_getfd ARGS((int mode, const char **emsgp)); -void coproc_cleanup ARGS((int reuse)); -#endif /* KSH */ -struct temp *maketemp ARGS((Area *ap)); -/* jobs.c */ -void j_init ARGS((int mflagset)); -void j_exit ARGS((void)); -void j_change ARGS((void)); -int exchild ARGS((struct op *t, int flags, int close_fd)); -void startlast ARGS((void)); -int waitlast ARGS((void)); -int waitfor ARGS((const char *cp, int *sigp)); -int j_kill ARGS((const char *cp, int sig)); -int j_resume ARGS((const char *cp, int bg)); -int j_jobs ARGS((const char *cp, int slp, int nflag)); -void j_notify ARGS((void)); -pid_t j_async ARGS((void)); -int j_stopped_running ARGS((void)); -/* lex.c */ -int yylex ARGS((int cf)); -void yyerror ARGS((const char *fmt, ...)) - GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2)); -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)); -int command ARGS((const char *comm)); -int shell ARGS((Source *volatile s, int volatile toplevel)); -void unwind ARGS((int i)) GCC_FUNC_ATTR(noreturn); -void newenv ARGS((int type)); -void quitenv ARGS((void)); -void cleanup_parents_env ARGS((void)); -void cleanup_proc_env ARGS((void)); -void aerror ARGS((Area *ap, const char *msg)) - GCC_FUNC_ATTR(noreturn); -/* misc.c */ -void setctypes ARGS((const char *s, int t)); -void initctypes ARGS((void)); -char * ulton ARGS((unsigned long n, int base)); -char * str_save ARGS((const char *s, Area *ap)); -char * str_nsave ARGS((const char *s, int n, Area *ap)); -int option ARGS((const char *n)); -char * getoptions ARGS((void)); -void change_flag ARGS((enum sh_flag f, int what, int newval)); -int parse_args ARGS((char **argv, int what, int *setargsp)); -int getn ARGS((const char *as, int *ai)); -int bi_getn ARGS((const char *as, int *ai)); -char * strerror ARGS((int i)); -int gmatch ARGS((const char *s, const char *p, int isfile)); -int has_globbing ARGS((const char *xp, const char *xpe)); -const unsigned char *pat_scan ARGS((const unsigned char *p, - const unsigned char *pe, int match_sep)); -void qsortp ARGS((void **base, size_t n, int (*f)(void *, void *))); -int xstrcmp ARGS((void *p1, void *p2)); -void ksh_getopt_reset ARGS((Getopt *go, int)); -int ksh_getopt ARGS((char **argv, Getopt *go, const char *options)); -void print_value_quoted ARGS((const char *s)); -void print_columns ARGS((struct shf *shf, int n, - char *(*func)(void *, int, char *, int), - void *arg, int max_width)); -int strip_nuls ARGS((char *buf, int nbytes)); -char *str_zcpy ARGS((char *dst, const char *src, int dsize)); -int blocking_read ARGS((int fd, char *buf, int nbytes)); -int reset_nonblock ARGS((int fd)); -char *ksh_get_wd ARGS((char *buf, int bsize)); -/* path.c */ -int make_path ARGS((const char *cwd, const char *file, - char **pathlist, XString *xsp, int *phys_pathp)); -void simplify_path ARGS((char *path)); -char *get_phys_path ARGS((const char *path)); -void set_current_wd ARGS((char *path)); -/* syn.c */ -void initkeywords ARGS((void)); -struct op * compile ARGS((Source *s)); -/* table.c */ -unsigned int hash ARGS((const char *n)); -void tinit ARGS((struct table *tp, Area *ap, int tsize)); -struct tbl * tsearch ARGS((struct table *tp, const char *n, unsigned int h)); -struct tbl * tenter ARGS((struct table *tp, const char *n, unsigned int h)); -void tdelete ARGS((struct tbl *p)); -void twalk ARGS((struct tstate *ts, struct table *tp)); -struct tbl * tnext ARGS((struct tstate *ts)); -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)); -int fatal_trap_check ARGS((void)); -int trap_pending ARGS((void)); -void runtraps ARGS((int intr)); -void runtrap ARGS((Trap *p)); -void cleartraps ARGS((void)); -void restoresigs ARGS((void)); -void settrap ARGS((Trap *p, char *s)); -int block_pipe ARGS((void)); -void restore_pipe ARGS((int restore_dfl)); -int setsig ARGS((Trap *p, handler_t f, int flags)); -void setexecsig ARGS((Trap *p, int restore)); -/* tree.c */ -int fptreef ARGS((struct shf *f, int indent, const char *fmt, ...)); -char * snptreef ARGS((char *s, int n, const char *fmt, ...)); -struct op * tcopy ARGS((struct op *t, Area *ap)); -char * wdcopy ARGS((const char *wp, Area *ap)); -char * wdscan ARGS((const char *wp, int c)); -void tfree ARGS((struct op *t, Area *ap)); -/* var.c */ -void newblock ARGS((void)); -void popblock ARGS((void)); -void initvar ARGS((void)); -struct tbl * global ARGS((const char *n)); -struct tbl * local ARGS((const char *n, bool_t copy)); -char * str_val ARGS((struct tbl *vp)); -long intval ARGS((struct tbl *vp)); -void setstr ARGS((struct tbl *vq, const char *s)); -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, 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)); -int is_wdvarname ARGS((const char *s, int aok)); -int is_wdvarassign ARGS((const char *s)); -char ** makenv ARGS((void)); -int array_ref_len ARGS((const char *cp)); -char * arrayname ARGS((const char *str)); -void set_array ARGS((const char *var, int reset, char **vals)); -/* version.c */ -/* vi.c: see edit.h */ - - -/* Hack to avoid billions of compile warnings on SunOS 4.1.x */ -#if defined(MUN) && defined(sun) && !defined(__svr4__) -extern void bcopy ARGS((const void *src, void *dst, size_t size)); -extern int fclose ARGS((FILE *fp)); -extern int fprintf ARGS((FILE *fp, const char *fmt, ...)); -extern int fread ARGS((void *buf, int size, int num, FILE *fp)); -extern int ioctl ARGS((int fd, int request, void *arg)); -extern int killpg ARGS((int pgrp, int sig)); -extern int nice ARGS((int n)); -extern int readlink ARGS((const char *path, char *buf, int bufsize)); -extern int setpgrp ARGS((int pid, int pgrp)); -extern int strcasecmp ARGS((const char *s1, const char *s2)); -extern int tolower ARGS((int)); -extern int toupper ARGS((int)); -/* Include files aren't included yet */ -extern int getrlimit ARGS(( /* int resource, struct rlimit *rpl */ )); -extern int getrusage ARGS(( /* int who, struct rusage *rusage */ )); -extern int gettimeofday ARGS(( /* struct timeval *tv, struct timezone *tz */ )); -extern int setrlimit ARGS(( /* int resource, struct rlimit *rlp */ )); -extern int lstat ARGS(( /* const char *path, struct stat *buf */ )); -#endif diff --git a/bin/pdksh/sh.1tbl b/bin/pdksh/sh.1tbl deleted file mode 100644 index 7d0eeacbc9e..00000000000 --- a/bin/pdksh/sh.1tbl +++ /dev/null @@ -1,2372 +0,0 @@ -'\" t -.\" $OpenBSD: sh.1tbl,v 1.3 1997/08/05 21:49:56 grr Exp $ -.\"{{{}}} -.\"{{{ Notes about man page -.\" - use the pseudo-macros .sh( and .sh) to begin and end sh-specific -.\" text and .ksh( and .ksh) for ksh specific text. -.\" - put i.e., e.g. and etc. in italics -.\"}}} -.\"{{{ To do -.\" todo: Things not covered that should be: -.\" - distinguish (POSIX) special built-in's, (POSIX) regular built-in's, -.\" and sh/ksh weirdo built-in's (put S,R,X superscripts after command -.\" name in built-in commands section?) -.\" - need to be consistent about notation for `See section-name', ` -.\" See description of foobar command', `See section section-name', etc. -.\" - need to use the term `external command' meaning `a command that is -.\" executed using execve(2)' (as opposed to a built-in command or -.\" function) for more clear description. -.\"}}} -.\"{{{ Title -.TH SH 1 "August 19, 1996" "" "User commands" -.\"}}} -.\"{{{ Name -.SH NAME -sh \- Public domain Bourne shell -.\"}}} -.\"{{{ Synopsis -.SH SYNOPSIS -.ad l -\fBsh\fP -[\fB\(+-abCefhikmnprsuvxX\fP] [\fB\(+-o\fP \fIoption\fP] [ [ \fB\-c\fP \fIcommand-string\fP [\fIcommand-name\fP] | \fB\-s\fP | \fIfile\fP ] [\fIargument\fP ...] ] -.ad b -.\"}}} -.\"{{{ Description -.SH DESCRIPTION -\fBsh\fP is a reimplementation of the Bourne shell, a command -interpreter for both interactive and script use. -.\"{{{ Shell Startup -.SS "Shell Startup" -The following options can be specified only on the command line: -.IP "\fB\-c\fP \fIcommand-string\fP" -the shell executes the command(s) contained in \fIcommand-string\fP -.IP \fB\-i\fP -interactive mode \(em see below -.IP \fB\-l\fP -login shell \(em see below -interactive mode \(em see below -.IP \fB\-s\fP -the shell reads commands from standard input; all non-option arguments -are positional parameters -.IP \fB\-r\fP -restricted mode \(em see below -.PP -In addition to the above, the options described in the \fBset\fP built-in -command can also be used on the command line. -.PP -If neither the \fB\-c\fP nor the \fB\-s\fP options are specified, the -first non-option argument specifies the name of a file the shell reads -commands from; if there are no non-option arguments, the shell reads -commands from standard input. -The name of the shell (\fIi.e.\fP, the contents of the \fB$0\fP) parameter -is determined as follows: if the \fB\-c\fP option is used and there is -a non-option argument, it is used as the name; if commands are being -read from a file, the file is used as the name; otherwise the name -the shell was called with (\fIi.e.\fP, argv[0]) is used. -.PP -A shell is \fBinteractive\fP if the \fB\-i\fP option is used or -if both standard input and standard error are attached to a tty. -An interactive shell has job control enabled (if available), -ignores the INT, QUIT and TERM signals, and prints prompts before -reading input (see \fBPS1\fP and \fBPS2\fP parameters). -For non-interactive shells, the \fBtrackall\fP option is on by default -(see \fBset\fP command below). -.PP -A shell is \fBrestricted\fP if the \fB\-r\fP option is used or if either -the basename of the name the shell is invoked with or the \fBSHELL\fP -parameter match the pattern *r*sh (\fIe.g.\fP, rsh, rksh, rpdksh, \fIetc.\fP). -The following restrictions come into effect after the shell processes -any profile and \fB$ENV\fP files: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -the \fBcd\fP command is disabled -.IP \ \ \(bu -the \fBSHELL\fP, \fBENV\fP and \fBPATH\fP parameters can't be changed -.IP \ \ \(bu -command names can't be specified with absolute or relative paths -.IP \ \ \(bu -the \fB\-p\fP option of the \fBcommand\fP built-in can't be used -.IP \ \ \(bu -redirections that create files can't be used (\fIi.e.\fP, \fB>\fP, -\fB>|\fP, \fB>>\fP, \fB<>\fP) -.nr PD \n(P2 -.PP -A shell is \fBprivileged\fP if the \fB\-p\fP option is used or if -the real user-id or group-id does not match the effective user-id -or group-id (see \fIgetuid\fP(2), \fIgetgid\fP(2)). -A privileged shell does not process $HOME/.profile nor the \fBENV\fP -parameter (see below), instead the file /etc/suid_profile is processed. -Clearing the privileged option causes the shell to set its effective -user-id (group-id) to its real user-id (group-id). -.PP -If the basename of the name the shell is called with (\fIi.e.\fP, argv[0]) -starts with \fB\-\fP or if the \fB\-l\fP option is used, the shell is assumed -to be a login shell and the shell reads and executes the contents of -\fB/etc/profile\fP and \fB$HOME/.profile\fP if they exist and are readable. -.PP -If the \fBENV\fP parameter is set when the shell starts (or, in the -case of login shells, after any profiles are processed), its value -is subjected to parameter, command, arithmetic and tilde substitution and -the resulting file (if any) is read and executed. -If \fBENV\fP parameter is not set (and not null) and pdksh was compiled -with the \fBDEFAULT_ENV\fP macro defined, the file named in that macro -is included (after the above mentioned substitutions have been performed). -.PP -The exit status of the shell is 127 if the command file specified -on the command line could not be opened, or non-zero if a fatal syntax -error occurred during the execution of a script. -In the absence of fatal errors, the exit status is that of the last -command executed, or zero, if no command is executed. -.\"}}} -.\"{{{ Command Syntax -.SS "Command Syntax" -.\"{{{ words and tokens -The shell begins parsing its input by breaking it into \fIword\fPs. -Words, which are sequences of characters, are delimited by unquoted -\fIwhite-space\fP characters (space, tab and newline) or \fImeta-characters\fP -(\fB<\fP, \fB>\fP, \fB|\fP, \fB;\fP, \fB&\fP, \fB(\fP and \fB)\fP). -Aside from delimiting words, spaces and tabs are ignored, while -newlines usually delimit commands. -The meta-characters are used in building the following tokens: -\fB<\fP, \fB<&\fP, \fB<<\fP, \fB>\fP, \fB>&\fP, \fB>>\fP, \fIetc.\fP are -used to specify redirections (see Input/Output Redirection below); -\fB|\fP is used to create pipelines; -\fB;\fP is used to separate commands; -\fB&\fP is used to create asynchronous pipelines; -\fB&&\fP and \fB||\fP are used to specify conditional execution; -\fB;;\fP is used in \fBcase\fP statements; -and lastly, -\fB(\fP .. \fB)\fP are used to create subshells. -.PP -White-space and meta-characters can be quoted individually using -backslash (\fB\e\fP), or in groups using double (\fB"\fP) or single (\fB'\fP) -quotes. -Note that the following characters are also treated specially by the shell and -must be quoted if they are to represent themselves: -\fB\e\fP, \fB"\fP, \fB'\fP, \fB#\fP, \fB$\fP, \fB`\fP, \fB~\fP, \fB{\fP, -\fB}\fP, \fB*\fP, \fB?\fP and \fB[\fP. -The first three of these are the above mentioned quoting characters -(see Quoting below); -\fB#\fP, if used at the beginning of a word, introduces a comment \(em everything -after the \fB#\fP up to the nearest newline is ignored; -\fB$\fP is used to introduce parameter, command and arithmetic substitutions -(see Substitution below); -\fB`\fP introduces an old-style command substitution -(see Substitution below); -\fB~\fP begins a directory expansion (see Tilde Expansion below); -\fB{\fP and \fB}\fP delimit \fIcsh\fP(1) style alternations -(see Brace Expansion below); -and, finally, \fB*\fP, \fB?\fP and \fB[\fP are used in file name generation -(see File Name Patterns below). -.\"}}} -.\"{{{ simple-command -.PP -As words and tokens are parsed, the shell builds commands, of which -there are two basic types: \fIsimple-commands\fP, typically programs -that are executed, and \fIcompound-commands\fP, such as \fBfor\fP and -\fBif\fP statements, grouping constructs and function definitions. -.PP -A simple-command consists of some combination of parameter assignments (see -Parameters below), input/output redirections (see Input/Output Redirections -below), and command words; the only restriction is that parameter assignments -come before any command words. -The command words, if any, define the command that is to be executed and its -arguments. -The command may be a shell built-in command, a function or an \fIexternal -command\fP, \fIi.e.\fP, a separate executable file that is located using the -\fBPATH\fP parameter (see Command Execution below). -Note that all command constructs have an \fIexit status\fP: for external -commands, this is related to the status returned by \fIwait\fP(2) (if the -command could not be found, the exit status is 127, if it could not be -executed, the exit status is 126); -the exit status of other command constructs (built-in commands, functions, -compound-commands, pipelines, lists, \fIetc.\fP) are all well defined and are -described where the construct is described. -The exit status of a command consisting only of parameter assignments is that -of the last command substitution performed during the parameter assignment -or zero if there were no command substitutions. -.\"}}} -.\"{{{ pipeline -.PP -Commands can be chained together using the \fB|\fP token to -form \fIpipelines\fP, in which the standard output of each command but -the last is piped (see \fIpipe\fP(2)) to the standard input of the following -command. -The exit status of a pipeline is that of its last command. -A pipeline may be prefixed by the \fB!\fP reserved word which -causes the exit status of the pipeline to be logically -complemented: if the original status was 0 the complemented status will -be 1, and if the original status was not 0, then the complemented -status will be 0. -.\"}}} -.\"{{{ lists -.PP -\fILists\fP of commands can be created by separating pipelines by -any of the following tokens: \fB&&\fP, \fB||\fP, \fB&\fP, \fB|&\fP and \fB;\fP. -The first two are for conditional execution: \fIcmd1\fP \fB&&\fP \fIcmd2\fP -executes \fIcmd2\fP only if the exit status of \fIcmd1\fP is zero; -\fB||\fP is the opposite \(em \fIcmd2\fP is executed only if the exit status -of \fIcmd1\fP is non-zero. -\fB&&\fP and \fB||\fP have equal precedence which is higher than that of -\fB&\fP, \fB|&\fP and \fB;\fP, which also have equal precedence. -The \fB&\fP token causes the preceding command to be executed asynchronously, -that is, the shell starts the command, but does not wait for it to complete -(the shell does keep track of the status of asynchronous commands \(em see -Job Control below). -When an asynchronous command is started when job control is disabled -(\fIi.e.\fP, in most scripts), the command is started with signals INT -and QUIT ignored and with input redirected from /dev/null -(however, redirections specified in the asynchronous command have precedence). -Note that a command must follow the \fB&&\fP and \fB||\fP operators, while -a command need not follow \fB&\fP, \fB|&\fP and \fB;\fP. -The exit status of a list is that of the last command executed, with the -exception of asynchronous lists, for which the exit status is 0. -.\"}}} -.\"{{{ compound-commands -.PP -Compound commands are created using the following reserved words \(em these -words are only recognized if they are unquoted and if they are used as -the first word of a command (\fIi.e.\fP, they can't be preceded by parameter -assignments or redirections): -.TS -center; -lfB lfB lfB lfB lfB . -case else function then ! -do esac if time [[ -done fi in until { -elif for select while } -.TE -\fBNote:\fP Some shells (but not this one) execute control structure commands -in a subshell when one or more of their file descriptors are redirected, so -any environment changes inside them may fail. -To be portable, the \fBexec\fP statement should be used instead to redirect -file descriptors before the control structure. -.PP -In the following compound command descriptions, command lists (denoted as -\fIlist\fP) that are followed by reserved words must end with a -semi-colon, a newline or a (syntactically correct) reserved word. -For example, -.RS -\fB{ echo foo; echo bar; }\fP -.br -\fB{ echo foo; echo bar<newline>}\fP -.br -\fB{ { echo foo; echo bar; } }\fP -.RE -are all valid, but -.RS -\fB{ echo foo; echo bar }\fP -.RE -is not. -.\"{{{ ( list ) -.IP "\fB(\fP \fIlist\fP \fB)\fP" -Execute \fIlist\fP in a subshell. There is no implicit way to pass -environment changes from a subshell back to its parent. -.\"}}} -.\"{{{ { list } -.IP "\fB{\fP \fIlist\fP \fB}\fP" -Compound construct; \fIlist\fP is executed, but not in a subshell. -Note that \fB{\fP and \fB}\fP are reserved words, not meta-characters. -.\"}}} -.\"{{{ case word in [ [ ( ] pattern [ | pattern ] ... ) list ;; ] ... esac -.IP "\fBcase\fP \fIword\fP \fBin\fP [ [\fB(\fP] \fIpattern\fP [\fB|\fP \fIpattern\fP] ... \fB)\fP \fIlist\fP \fB;;\fP ] ... \fBesac\fP" -The \fBcase\fP statement attempts to match \fIword\fP against the specified -\fIpattern\fPs; the \fIlist\fP associated with the first successfully matched -pattern is executed. Patterns used in \fBcase\fP statements are the same as -those used for file name patterns except that the restrictions regarding -\fB\&.\fP and \fB/\fP are dropped. Note that any unquoted space before and -after a pattern is stripped; any space with a pattern must be quoted. Both the -word and the patterns are subject to parameter, command, and arithmetic -substitution as well as tilde substitution. -For historical reasons, open and close braces may be used instead -of \fBin\fP and \fBesac\fP (\fIe.g.\fP, \fBcase $foo { *) echo bar; }\fP). -The exit status of a \fBcase\fP statement is that of the executed \fIlist\fP; -if no \fIlist\fP is executed, the exit status is zero. -.\"}}} -.\"{{{ for name [ in word ... term ] do list done -.IP "\fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP ... \fIterm\fP ] \fBdo\fP \fIlist\fP \fBdone\fP" -where \fIterm\fP is either a newline or a \fB;\fP. -For each \fIword\fP in the specified word list, the parameter \fIname\fP is -set to the word and \fIlist\fP is executed. If \fBin\fP is not used to -specify a word list, the positional parameters (\fB"$1"\fP, \fB"$2"\fP, -\fIetc.\fP) are used instead. -For historical reasons, open and close braces may be used instead -of \fBdo\fP and \fBdone\fP (\fIe.g.\fP, \fBfor i; { echo $i; }\fP). -The exit status of a \fBfor\fP statement is the last exit status -of \fIlist\fP; if \fIlist\fP is never executed, the exit status is zero. -.\"}}} -.\"{{{ if list then list [ elif list then list ] ... [ else list ] fi -.IP "\fBif\fP \fIlist\fP \fBthen\fP \fIlist\fP [\fBelif\fP \fIlist\fP \fBthen\fP \fIlist\fP] ... [\fBelse\fP \fIlist\fP] \fBfi\fP" -If the exit status of the first \fIlist\fP is zero, the second \fIlist\fP -is executed; otherwise the \fIlist\fP following the \fBelif\fP, if any, is -executed with similar consequences. If all the lists following the \fBif\fP -and \fBelif\fPs fail (\fIi.e.\fP, exit with non-zero status), the \fIlist\fP -following the \fBelse\fP is executed. -The exit status of an \fBif\fP statement is that -of non-conditional \fIlist\fP that is executed; if no non-conditional -\fIlist\fP is executed, the exit status is zero. -.\"}}} -.\"{{{ select name [ in word ... ] do list done -.\"}}} -.\"{{{ until list do list done -.IP "\fBuntil\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP" -This works like \fBwhile\fP, except that the body is executed only while the -exit status of the first \fIlist\fP is non-zero. -.\"}}} -.\"{{{ while list do list done -.IP "\fBwhile\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP" -A \fBwhile\fP is a prechecked loop. Its body is executed as often -as the exit status of the first \fIlist\fP is zero. -The exit status of a \fBwhile\fP statement is the last exit status -of the \fIlist\fP in the body of the loop; if the body is not executed, -the exit status is zero. -.\"}}} -.\"{{{ function name { list } -.IP "\fBfunction\fP \fIname\fP \fB{\fP \fIlist\fP \fB}\fP" -Defines the function \fIname\fP. -See Functions below. -Note that redirections specified after a function definition are -performed whenever the function is executed, not when the function -definition is executed. -.\"}}} -.\"{{{ name () command -.IP "\fIname\fP \fB()\fP \fIcommand\fP" -Mostly the same as \fBfunction\fP. -See Functions below. -.\"}}} -.\"{{{ (( expression )) -.\"}}} -.\"{{{ [[ expression ]] -.\"}}} -.\"}}} -.\"}}} -.\"{{{ Quoting -.SS Quoting -Quoting is used to prevent the shell from treating characters or words -specially. -There are three methods of quoting: First, \fB\e\fP quotes -the following character, unless it is at the end of a line, in which -case both the \fB\e\fP and the newline are stripped. -Second, a single quote (\fB'\fP) quotes everything up to the next single -quote (this may span lines). -Third, a double quote (\fB"\fP) quotes all characters, -except \fB$\fP, \fB`\fP and \fB\e\fP, up to the next unquoted double quote. -\fB$\fP and \fB`\fP inside double quotes have their usual meaning (\fIi.e.\fP, -parameter, command or arithmetic substitution) except no field splitting -is carried out on the results of double-quoted substitutions. -If a \fB\e\fP inside a double-quoted string is followed by \fB\e\fP, \fB$\fP, -\fB`\fP or \fB"\fP, it is replaced by the second character; if it is -followed by a newline, both the \fB\e\fP and the newline are stripped; -otherwise, both the \fB\e\fP and the character following are unchanged. -.PP -Note: see POSIX Mode below for a special rule regarding sequences -of the form \fB"\fP...\fB`\fP...\fB\e"\fP...\fB`\fP..\fB"\fP. -.\"}}} -.\"{{{ Aliases -.SS "Aliases" -There are two types of aliases: normal command aliases and tracked -aliases. Command aliases are normally used as a short hand for a long -or often used command. The shell expands command aliases (\fIi.e.\fP, -substitutes the alias name for its value) when it reads the first word -of a command. An expanded alias is re-processed to check for more -aliases. If a command alias ends in a space or tab, the following word -is also checked for alias expansion. The alias expansion process stops -when a word that is not an alias is found, when a quoted word is found -or when an alias word that is currently being expanded is found. -.PP -The following command aliases are defined automatically by the shell: -.ft B -.RS -hash='alias \-t' -.br -type='whence \-v' -.RE -.ft P -.PP -Tracked aliases allow the shell to remember where it found a particular -command. The first time the shell does a path search for a command that -is marked as a tracked alias, it saves the full path of the command. -The next time the command is executed, the shell checks the saved path -to see that it is still valid, and if so, avoids repeating the path -search. Tracked aliases can be listed and created using \fBalias -\-t\fP. Note that changing the \fBPATH\fP parameter clears the saved -paths for all tracked aliases. If the \fBtrackall\fP option is set (\fIi.e.\fP, -\fBset \-o trackall\fP or \fBset \-h\fP), the shell tracks all -commands. This option is set automatically for non-interactive shells. -For interactive shells, only the following commands are automatically -tracked: \fBcat\fP, \fBcc\fP, \fBchmod\fP, \fBcp\fP, \fBdate\fP, \fBed\fP, -\fBemacs\fP, \fBgrep\fP, \fBls\fP, \fBmail\fP, \fBmake\fP, \fBmv\fP, -\fBpr\fP, \fBrm\fP, \fBsed\fP, \fBsh\fP, \fBvi\fP and \fBwho\fP. -.\"}}} -.\"{{{ Substitution -.SS "Substitution" -The first step the shell takes in executing a simple-command is to -perform substitutions on the words of the command. -There are three kinds of substitution: parameter, command and arithmetic. -Parameter substitutions, which are described in detail in the next section, -take the form \fB$name\fP or \fB${\fP...\fB}\fP; command substitutions take -the form \fB$(\fP\fIcommand\fP\fB)\fP or \fB`\fP\fIcommand\fP\fB`\fP; -and arithmetic substitutions take the form \fB$((\fP\fIexpression\fP\fB))\fP. -.PP -If a substitution appears outside of double quotes, the results of the -substitution are generally subject to word or field splitting according to -the current value of the \fBIFS\fP parameter. -The \fBIFS\fP parameter specifies a list of characters which -are used to break a string up into several words; -any characters from the set space, tab and newline that appear in the -IFS characters are called \fIIFS white space\fP. -Sequences of one or more IFS white space characters, in combination with -zero or one non-IFS white space characters delimit a field. -As a special case, leading and trailing IFS white space is stripped (\fIi.e.\fP, -no leading or trailing empty field is created by it); leading or trailing -non-IFS white space does create an empty field. -.PP -Example: if \fBIFS\fP is set to `<space>:', and VAR is set to -`<space>A<space>:<space><space>B::D', the substitution for $VAR results -in four fields: `A', `B', `' and `D'. -Note that if the \fBIFS\fP parameter is set to the null string, no -field splitting is done; if the parameter is unset, the default value -of space, tab and newline is used. -.PP -Also, note that the field splitting applies only to immediate result of -the substitution. Using the previous example, the substitution for $VAR:E -results in the fields: `A', `B', `' and `D:E', not `A', `B', `', `D' and `E'. -This behavior is POSIX compliant, but incompatible with some other shell -implementations which do field splitting on the word which contained the -substitution or use \fBIFS\fP\ as a general whitespace delimiter. -.PP -The results of substitution are, unless otherwise specified, also subject -to brace expansion and file name expansion (see the relevant sections -below). -.PP -A command substitution is replaced by the output generated by the specified -command, which is run in a subshell. -For \fB$(\fP\fIcommand\fP\fB)\fP substitutions, normal quoting rules -are used when \fIcommand\fP is parsed, however, for the -\fB`\fP\fIcommand\fP\fB`\fP form, a \fB\e\fP followed by any of -\fB$\fP, \fB`\fP or \fB\e\fP is stripped (a \fB\e\fP followed by any other -character is unchanged). -As a special case in command substitutions, a command of the form -\fB<\fP \fIfile\fP is interpreted to mean substitute the contents -of \fIfile\fP ($(< foo) has the same effect as $(cat foo), but it -is carried out more efficiently because no process is started). -.br -.\"todo: fix this( $(..) parenthesis counting). -NOTE: \fB$(\fP\fIcommand\fP\fB)\fP expressions are currently parsed by -finding the matching parenthesis, regardless of quoting. This will hopefully -be fixed soon. -.PP -Arithmetic substitutions are replaced by the value of the specified -expression. -For example, the command \fBecho $((2+3*4))\fP prints 14. -See Arithmetic Expressions for a description of an \fIexpression\fP. -.\"}}} -.\"{{{ Parameters -.SS "Parameters" -Parameters are shell variables; they can be assigned values and -their values can be accessed using a parameter substitution. -A parameter name is either one of the special single punctuation or digit -character parameters described below, or a letter followed by zero or more -letters or digits (`_' counts as a letter). -Parameter substitutions take the form \fB$\fP\fIname\fP or -\fB${\fP\fIname\fP\fB}\fP, where \fIname\fP is a parameter name. -If substitution is performed on a parameter that is not set, a null -string is substituted unless the \fBnounset\fP option (\fBset \-o nounset\fP -or \fBset \-u\fP) is set, in which case an error occurs. -.PP -.\"{{{ parameter assignment -Parameters can be assigned values in a number of ways. -First, the shell implicitly sets some parameters like \fB#\fP, \fBPWD\fP, -etc.; this is the only way the special single character parameters are -set. -Second, parameters are imported from the shell's environment at startup. -Third, parameters can be assigned values on the command line, for example, -`\fBFOO=bar\fP' sets the parameter FOO to bar; multiple parameter -assignments can be given on a single command line and they can -be followed by a simple-command, in which case the assignments are -in effect only for the duration of the command (such assignments are -also exported, see below for implications of this). -Note that both the parameter name and the \fB=\fP must be unquoted for -the shell to recognize a parameter assignment. -The fourth way of setting a parameter is with the \fBexport\fP, \fBreadonly\fP -and \fBtypeset\fP commands; see their descriptions in the Command Execution -section. -Fifth, \fBfor\fP and \fBselect\fP loops set parameters as well as -the \fBgetopts\fP, \fBread\fP and \fBset \-A\fP commands. -Lastly, parameters can be assigned values using assignment operators -inside arithmetic expressions (see Arithmetic Expressions below) or -using the \fB${\fP\fIname\fP\fB=\fP\fIvalue\fP\fB}\fP form -of parameter substitution (see below). -.\"}}} -.PP -.\"{{{ environment -Parameters with the export attribute (set using the \fBexport\fP or -\fBtypeset \-x\fP commands, or by parameter assignments followed by simple -commands) are put in the environment (see \fIenviron\fP(5)) of commands -run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs. -The order in which parameters appear in the environment of a command -is unspecified. -When the shell starts up, it extracts parameters and their values from its -environment and automatically sets the export attribute for those parameters. -.\"}}} -.\"{{{ ${name[:][-+=?]word} -.PP -Modifiers can be applied to the \fB${\fP\fIname\fP\fB}\fP form of parameter -substitution: -.IP \fB${\fP\fIname\fP\fB:-\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP is -substituted. -.IP \fB${\fP\fIname\fP\fB:+\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, \fIword\fP is substituted, otherwise nothing is substituted. -.IP \fB${\fP\fIname\fP\fB:=\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, it is substituted, otherwise it is -assigned \fIword\fP and the resulting value of \fIname\fP is substituted. -.IP \fB${\fP\fIname\fP\fB:?\fP\fIword\fP\fB}\fP -if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP -is printed on standard error (preceded by \fIname\fP:) and an error occurs -(normally causing termination of a shell script, function or \&.-script). -If word is omitted the string `parameter null or not set' is used instead. -.PP -In the above modifiers, the \fB:\fP can be omitted, in which case the -conditions only depend on \fIname\fP being set (as opposed to set and -not null). -If \fIword\fP is needed, parameter, command, arithmetic and tilde substitution -are performed on it; if \fIword\fP is not needed, it is not evaluated. -.\"}}} -.PP -The following forms of parameter substitution can also be used: -.\"{{{ ${#name} -.IP \fB${#\fP\fIname\fP\fB}\fP -The number of positional parameters if \fIname\fP is \fB*\fP, \fB@\fP or -is not specified, -or the length of the string value of parameter \fIname\fP. -.\"}}} -.\"{{{ ${#name[*]}, ${#name[@]} -.IP "\fB${#\fP\fIname\fP\fB[*]}\fP, \fB${#\fP\fIname\fP\fB[@]}\fP" -The number of elements in the array \fIname\fP. -.\"}}} -.\"{{{ ${name#pattern}, ${name##pattern} -.IP "\fB${\fP\fIname\fP\fB#\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB##\fP\fIpattern\fP\fB}\fP" -If \fIpattern\fP matches the beginning of the value of parameter \fIname\fP, -the matched text is deleted from the result of substitution. A single -\fB#\fP results in the shortest match, two \fB#\fP's results in the -longest match. -.\"}}} -.\"{{{ ${name%pattern}, ${name%%pattern} -.IP "\fB${\fP\fIname\fP\fB%\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB%%\fP\fIpattern\fP\fB}\fP" -Like \fB${\fP..\fB#\fP..\fB}\fP substitution, but it deletes from the end of the -value. -.\"}}} -.\"{{{ special shell parameters -.PP -The following special parameters are implicitly set by the shell and cannot be -set directly using assignments: -.\"{{{ ! -.IP \fB!\fP -Process id of the last background process started. If no background -processes have been started, the parameter is not set. -.\"}}} -.\"{{{ # -.IP \fB#\fP -The number of positional parameters (\fIi.e.\fP, \fB$1\fP, \fB$2\fP, -\fIetc.\fP). -.\"}}} -.\"{{{ $ -.IP \fB$\fP -The process ID of the shell, or the PID of the original shell if -it is a subshell. -.\"}}} -.\"{{{ - -.IP \fB\-\fP -The concatenation of the current single letter options -(see \fBset\fP command below for list of options). -.\"}}} -.\"{{{ ? -.IP \fB?\fP -The exit status of the last non-asynchronous command executed. -If the last command was killed by a signal, \fB$?\fP is set to 128 plus -the signal number. -.\"}}} -.\"{{{ 0 -.IP "\fB0\fP" -The name the shell was invoked with (\fIi.e.\fP, \fBargv[0]\fP), or the -\fBcommand-name\fP if it was invoked with the \fB\-c\fP option and the -\fBcommand-name\fP was supplied, or the \fIfile\fP argument, if it was -supplied. -If the \fBposix\fP option is not set, \fB$0\fP is the name of the current -function or script. -.\"}}} -.\"{{{ 1-9 -.IP "\fB1\fP ... \fB9\fP" -The first nine positional parameters that were supplied to the shell, -function or \fB.\fP-script. -Further positional parameters may be accessed using -\fB${\fP\fInumber\fP\fB}\fP. -.\"}}} -.\"{{{ * -.IP \fB*\fP -All positional parameters (except parameter 0), -\fIi.e.\fP, \fB$1 $2 $3\fP.... -If used outside of double quotes, parameters are separate words -(which are subjected to word splitting); if used within double quotes, -parameters are separated by the first character of the \fBIFS\fP parameter -(or the empty string if \fBIFS\fP is null). -.\"}}} -.\"{{{ @ -.IP \fB@\fP -Same as \fB$*\fP, unless it is used inside double quotes, in which case -a separate word is generated for each positional parameter \- if there -are no positional parameters, no word is generated ("$@" can be used -to access arguments, verbatim, without loosing null arguments or -splitting arguments with spaces). -.\"}}} -.\"}}} -.\"{{{ general shell parameters -.PP -The following parameters are set and/or used by the shell: -.\"{{{ CDPATH -.IP \fBCDPATH\fP -Search path for the \fBcd\fP built-in command. Works the same way as -\fBPATH\fP for those directories not beginning with \fB/\fP in \fBcd\fP -commands. -Note that if CDPATH is set and does not contain \fB.\fP nor an empty path, -the current directory is not searched. -.\"}}} -.\"{{{ COLUMNS -.IP \fBCOLUMNS\fP -Set to the number of columns on the terminal or window. -Currently set to the \fBcols\fP value as reported by \fIstty\fP(1) if that -value is non-zero. -This parameter is used by the interactive line editing modes, and by -\fBselect\fP, \fBset \-o\fP and \fBkill \-l\fP commands -to format information in columns. -.\"}}} -.\"{{{ EDITOR -.\"}}} -.\"{{{ ENV -.IP \fBENV\fP -If this parameter is found to be set after any profile files are -executed, the expanded value is used as a shell start-up file. It -typically contains function and alias definitions. -.\"}}} -.\"{{{ ERRNO -.IP \fBERRNO\fP -Integer value of the shell's errno variable \(em indicates the reason -the last system call failed. -.\" todo: ERRNO variable -.sp -Not implemented yet. -.\"}}} -.\"{{{ EXECSHELL -.IP \fBEXECSHELL\fP -If set, this parameter is assumed to contain the shell that is to be -used to execute commands that \fIexecve\fP(2) fails to execute and -which do not start with a `\fB#!\fP \fIshell\fP' sequence. -.\"}}} -.\"{{{ FCEDIT -.IP \fBFCEDIT\fP -The editor used by the \fBfc\fP command (see below). -.\"}}} -.\"{{{ FPATH -.IP \fBFPATH\fP -Like \fBPATH\fP, but used when an undefined function is executed to locate -the file defining the function. -It is also searched when a command can't be found using \fBPATH\fP. -See Functions below for more information. -.\"}}} -.\"{{{ HISTFILE -.\"}}} -.\"{{{ HISTSIZE -.\"}}} -.\"{{{ HOME -.IP \fBHOME\fP -The default directory for the \fBcd\fP command and the value -substituted for an unqualified \fB~\fP (see Tilde Expansion below). -.\"}}} -.\"{{{ IFS -.IP \fBIFS\fP -Internal field separator, used during substitution and by the \fBread\fP -command, to split values into distinct arguments; normally set to -space, tab and newline. See Substitution above for details. -.br -\fBNote:\fP this parameter is not imported from the environment -when the shell is started. -.\"}}} -.\"{{{ KSH_VERSION -.\"}}} -.\"{{{ SH_VERSION -.IP \fBSH_VERSION\fP -The version of shell and the date the version was created (readonly). -.\"}}} -.\"{{{ LINENO -.IP \fBLINENO\fP -The line number of the function or shell script that is currently being -executed. -.\" todo: LINENO variable -.sp -Not implemented yet. -.\"}}} -.\"{{{ LINES -.IP \fBLINES\fP -Set to the number of lines on the terminal or window. -.\"Currently set to the \fBrows\fP value as reported by \fIstty\fP(1) if that -.\"value is non-zero. -.\" todo: LINES variable -.sp -Not implemented yet. -.\"}}} -.\"{{{ MAIL -.\"}}} -.\"{{{ MAILCHECK -.\"}}} -.\"{{{ MAILPATH -.\"}}} -.\"{{{ OLDPWD -.IP \fBOLDPWD\fP -The previous working directory. -Unset if \fBcd\fP has not successfully changed directories since the -shell started, or if the shell doesn't know where it is. -.\"}}} -.\"{{{ OPTARG -.IP \fBOPTARG\fP -When using \fBgetopts\fP, it contains the argument for a parsed option, -if it requires one. -.\"}}} -.\"{{{ OPTIND -.IP \fBOPTIND\fP -The index of the last argument processed when using \fBgetopts\fP. -Assigning 1 to this parameter causes \fBgetopts\fP to -process arguments from the beginning the next time it is invoked. -.\"}}} -.\"{{{ PATH -.IP \fBPATH\fP -A colon separated list of directories that are searched when looking -for commands and \fB.\fP'd files. -An empty string resulting from a leading or trailing colon, or two adjacent -colons is treated as a `.', the current directory. -.\"}}} -.\"{{{ POSIXLY_CORRECT -.IP \fBPOSIXLY_CORRECT\fP -If set, this parameter causes the \fBposix\fP option to be enabled. -See POSIX Mode below. -.\"}}} -.\"{{{ PPID -.IP \fBPPID\fP -The process ID of the shell's parent (readonly). -.\"}}} -.\"{{{ PS1 -.IP \fBPS1\fP -\fBPS1\fP is the primary prompt for interactive shells. -The prompt is printed verbatim (\fIi.e.\fP, no substitutions are done). -Default is `\fB$\ \fP' for non-root users, `\fB#\ \fP' for root.. -.\"}}} -.\"{{{ PS2 -.IP \fBPS2\fP -Secondary prompt string, by default `\fB>\fP ', used when more input is -needed to complete a command. -.\"}}} -.\"{{{ PS3 -.\"}}} -.\"{{{ PS4 -.IP \fBPS4\fP -Used to prefix commands that are printed during execution tracing -(see \fBset \-x\fP command below). -The prompt is printed verbatim (\fIi.e.\fP, no substitutions are done). -Default is `\fB+\ \fP'. -.\"}}} -.\"{{{ PWD -.IP \fBPWD\fP -The current working directory. Maybe unset or null if shell doesn't -know where it is. -.\"}}} -.\"{{{ RANDOM -.\"}}} -.\"{{{ REPLY -.IP \fBREPLY\fP -Default parameter for the \fBread\fP command if no names are given. -Also used in \fBselect\fP loops to store the value that is read from -standard input. -.\"}}} -.\"{{{ SECONDS -.\"}}} -.\"{{{ TMOUT -.\"}}} -.\"{{{ TMPDIR -.IP \fBTMPDIR\fP -The directory shell temporary files are created in. If this parameter -is not set, or does not contain the absolute path of a writable -directory, temporary files are created in \fB/tmp\fP. -.\"}}} -.\"{{{ VISUAL -.\"}}} -.\"}}} -.\"}}} -.\"{{{ Tilde Expansion -.SS "Tilde Expansion" -Tilde expansion, which is done in parallel with parameter substitution, -is done on words starting with an unquoted \fB~\fP. The characters -following the tilde, up to the first \fB/\fP, if any, are assumed to be -a login name. If the login name is empty, \fB+\fP or \fB\-\fP, the -value of the \fBHOME\fP, \fBPWD\fP, or \fBOLDPWD\fP parameter is -substituted, respectively. Otherwise, the password file is searched for -the login name, and the tilde expression is substituted with the -user's home directory. If the login name is not found in the password -file or if any quoting or parameter substitution occurs in the login name, -no substitution is performed. -.PP -In parameter assignments (those preceding a simple-command or those -occurring in the arguments of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, -and \fBtypeset\fP), tilde expansion is done after any unquoted colon -(\fB:\fP), and login names are also delimited by colons. -.PP -The home directory of previously expanded login names are cached and -re-used. The \fBalias \-d\fP command may be used to list, change and -add to this cache (\fIe.g.\fP, `alias \-d fac=/usr/local/facilities; cd -~fac/bin'). -.\"}}} -.\"{{{ Brace Expansion -.\"}}} -.\"{{{ File Name Patterns -.SS "File Name Patterns" -.PP -A file name pattern is a word containing one or more unquoted \fB?\fP or -\fB*\fP characters or \fB[\fP..\fB]\fP sequences. Once brace expansion has -been performed, the shell replaces file name patterns with the sorted names -of all the files that match the pattern (if no files match, the word is -left unchanged). The pattern elements have the following meaning: -.IP \fB?\fP -matches any single character. -.IP \fB*\fP -matches any sequence of characters. -.IP \fB[\fP..\fB]\fP -matches any of the characters inside the brackets. Ranges of characters -can be specified by separating two characters by a \fB\-\fP, \fIe.g.\fP, -\fB[a0\-9]\fP matches the letter \fBa\fP or any digit. -In order to represent itself, a -\fB\-\fP must either be quoted or the first or last character in the character -list. Similarly, a \fB]\fP must be quoted or the first character in the list -if it is represent itself instead of the end of the list. Also, a \fB!\fP -appearing at the start of the list has special meaning (see below), so to -represent itself it must be quoted or appear later in the list. -.IP \fB[!\fP..\fB]\fP -like \fB[\fP..\fB]\fP, except it matches any character not inside the brackets. -.PP -Note that pdksh currently never matches \fB.\fP and \fB..\fP, but the original -ksh, Bourne sh and bash do, so this may have to change (too bad). -.PP -Note that none of the above pattern elements match either a period (\fB.\fP) -at the start of a file name or a slash (\fB/\fP), even if they are explicitly -used in a \fB[\fP..\fB]\fP sequence; also, the names \fB.\fP and \fB..\fP -are never matched, even by the pattern \fB.*\fP. -.PP -If the \fBmarkdirs\fP option is set, any directories that result from -file name generation are marked with a trailing \fB/\fP. -.PP -.\" todo: implement this ([[:alpha:]], \fIetc.\fP) -The POSIX character classes (\fIi.e.\fP, -\fB[:\fP\fIclass-name\fP\fB:]\fP inside a \fB[\fP..\fB]\fP expression) -are not yet implemented. -.\"}}} -.\"{{{ Input/Output Redirection -.SS "Input/Output Redirection" -When a command is executed, its standard input, standard output and -standard error (file descriptors 0, 1 and 2, respectively) are normally -inherited from the shell. -Three exceptions to this are commands in pipelines, for which standard input -and/or standard output are those set up by the pipeline, asynchronous commands -created when job control is disabled, for which standard input is initially -set to be from \fB/dev/null\fP, and commands for which any of the following -redirections have been specified: -.IP "\fB>\fP \fIfile\fP" -standard output is redirected to \fIfile\fP. If \fIfile\fP does not exist, -it is created; if it does exist, is a regular file and the \fBnoclobber\fP -option is set, an error occurs, otherwise the file is truncated. -Note that this means the command \fIcmd < foo > foo\fP will open -\fIfoo\fP for reading and then truncate it when it opens it for writing, -before \fIcmd\fP gets a chance to actually read \fIfoo\fP. -.IP "\fB>|\fP \fIfile\fP" -same as \fB>\fP, except the file is truncated, even if the \fBnoclobber\fP -option is set. -.IP "\fB>>\fP \fIfile\fP" -same as \fB>\fP, except the file an existing file is appended to instead -of being truncated. Also, the file is opened in append mode, so writes -always go to the end of the file (see \fIopen\fP(2)). -.IP "\fB<\fP \fIfile\fP" -standard input is redirected from \fIfile\fP, which is opened for reading. -.IP "\fB<>\fP \fIfile\fP" -same as \fB<\fP, except the file is opened for reading and writing. -.IP "\fB<<\fP \fImarker\fP" -after reading the command line containing this kind of redirection (called a -here document), the shell copies lines from the command source into a temporary -file until a line matching \fImarker\fP is read. -When the command is executed, standard input is redirected from the temporary -file. -If \fImarker\fP contains no quoted characters, the contents of the -temporary file are processed as if enclosed in double quotes each time -the command is executed, so parameter, command and arithmetic substitutions -are performed, along with backslash (\fB\e\fP) escapes for -\fB$\fP, \fB`\fP, \fB\e\fP and \fB\enewline\fP. -If multiple here documents are used on the same command line, they are -saved in order. -.IP "\fB<<-\fP \fImarker\fP" -same as \fB<<\fP, except leading tabs are stripped from lines in the -here document. -.IP "\fB<&\fP \fIfd\fP" -standard input is duplicated from file descriptor \fIfd\fP. -\fIfd\fP can be a single digit, indicating the number of an existing -file descriptor, the letter \fBp\fP, indicating the file descriptor -associated with the output of the current co-process, or -the character \fB\-\fP, indicating standard input is to be closed. -.IP "\fB>&\fP \fIfd\fP" -same as \fB<&\fP, except the operation is done on standard output. -.PP -In any of the above redirections, the file descriptor that is redirected -(\fIi.e.\fP, standard input or standard output) can be explicitly given by -preceding the redirection with a single digit. -Parameter, command and arithmetic substitutions, tilde substitutions and -file name generation are all performed on the \fIfile\fP, \fImarker\fP and -\fIfd\fP arguments of redirections. -Note however, that the results of any file name generation are only used -if a single file is matched; if multiple files match, the word with the -unexpanded file name generation characters is used. -Note that in restricted shells, redirections which can create files cannot -be used. -.PP -For simple-commands, redirections may appear anywhere in the command, for -compound-commands (\fBif\fP statements, \fIetc.\fP), any redirections must -appear at the end. -Redirections are processed after pipelines are created and in the order they -are given, so -.RS -\fBcat /foo/bar 2>&1 > /dev/null | cat \-n\fP -.RE -will print an error with a line number prepended to it. -.\"}}} -.\"{{{ Arithmetic Expressions -.SS "Arithmetic Expressions" -Integer arithmetic expressions can be used -inside \fB$((\fP..\fB))\fP expressions, -inside array references (\fIe.g.\fP, \fIname\fP\fB[\fP\fIexpr\fP\fB]\fP), -as numeric arguments to the \fBtest\fP command, -and as the value of an assignment to an integer parameter. -.PP -Expression may contain alpha-numeric parameter identifiers, array -references, and integer constants and may be combined with the -following C operators (listed and grouped in increasing order of precedence). -.TP -Unary operators: -\fB+ \- ! ~ ++ --\fP -.TP -Binary operators: -\fB,\fP -.br -\fB= *= /= %= += \-= <<= >>= &= ^= |=\fP -.br -\fB||\fP -.br -\fB&&\fP -.br -\fB|\fP -.br -\fB^\fP -.br -\fB&\fP -.br -\fB== !=\fP -.br -\fB< <= >= >\fP -.br -\fB<< >>\fP -.br -\fB+ \-\fP -.br -\fB* / %\fP -.TP -Ternary operator: -\fB?:\fP (precedence is immediately higher than assignment) -.TP -Grouping operators: -\fB( )\fP -.PP -Integer constants may be specified with arbitrary bases using the notation -\fIbase\fP\fB#\fP\fInumber\fP, where \fIbase\fP is a decimal integer specifying -the base, and \fInumber\fP is a number in the specified base. -.LP -The operators are evaluated as follows: -.RS -.IP "unary \fB+\fP" -result is the argument (included for completeness). -.IP "unary \fB\-\fP" -negation. -.IP "\fB!\fP" -logical not; the result is 1 if argument is zero, 0 if not. -.IP "\fB~\fP" -arithmetic (bit-wise) not. -.IP "\fB++\fP" -increment; must be applied to a parameter (not a literal or other -expression) - the parameter is incremented by 1. -When used as a prefix operator, the result is the incremented value of -the parameter, when used as a postfix operator, the result is the -original value of the parameter. -.IP "\fB++\fP" -similar to \fB++\fP, except the paramter is decremented by 1. -.IP "\fB,\fP" -seperates two arithmetic expressions; the left hand side is evaluated first, -then the right. The result is value of the expression on the right hand side. -.IP "\fB=\fP" -assignment; variable on the left is set to the value on the right. -.IP "\fB*= /= %= += \-= <<= >>= &= ^= |=\fP" -assignment operators; \fI<var> <op>\fP\fB=\fP \fI<expr>\fP is the same as -\fI<var>\fP \fB=\fP \fI<var> <op>\fP \fB(\fP \fI<expr>\fP \fB)\fP. -.IP "\fB||\fP" -logical or; the result is 1 if either argument is non-zero, 0 if not. -The right argument is evaluated only if the left argument is zero. -.IP "\fB&&\fP" -logical and; the result is 1 if both arguments are non-zero, 0 if not. -The right argument is evaluated only if the left argument is non-zero. -.IP "\fB|\fP" -arithmetic (bit-wise) or. -.IP "\fB^\fP" -arithmetic (bit-wise) exclusive-or. -.IP "\fB&\fP" -arithmetic (bit-wise) and. -.IP "\fB==\fP" -equal; the result is 1 if both arguments are equal, 0 if not. -.IP "\fB!=\fP" -not equal; the result is 0 if both arguments are equal, 1 if not. -.IP "\fB<\fP" -less than; the result is 1 if the left argument is less than the right, -0 if not. -.IP "\fB<= >= >\fP" -less than or equal, greater than or equal, greater than. See <. -.IP "\fB<< >>\fP" -shift left (right); the result is the left argument with its bits shifted -left (right) by the amount given in the right argument. -.IP "\fB+ - * /\fP" -addition, subtraction, multiplication, and division. -.IP "\fB%\fP" -remainder; the result is the remainder of the division of the left argument -by the right. The sign of the result is unspecified if either argument -is negative. -.IP "\fI<arg1>\fP \fB?\fP \fI<arg2>\fP \fB:\fP \fI<arg3>\fP" -if \fI<arg1>\fP is non-zero, the result is \fI<arg2>\fP, -otherwise \fI<arg3>\fP. -.RE -.\"}}} -.\"{{{ Co-Processes -.\"}}} -.\"{{{ Functions -.SS "Functions" -Functions are defined using either Korn shell \fBfunction\fP \fIname\fP -syntax or the Bourne/POSIX shell \fIname\fP\fB()\fP syntax -(see below for the difference between the two forms). -Functions are like \fB.\fP-scripts in that they are executed in -the current environment, however, unlike \fB.\fP-scripts, shell arguments -(\fIi.e.\fP, positional parameters, \fB$1\fP, \fIetc.\fP) are never visible -inside them. -When the shell is determining the location of a command, functions are -searched after special built-in commands, and before regular and non-regular -built-ins, and before the \fBPATH\fP is searched. -.PP -An existing function may be deleted using \fBunset \-f\fP \fIfunction-name\fP. -A list of functions can be obtained using \fBtypeset +f\fP and the -function definitions can be listed using \fBtypeset \-f\fP. -\fBautoload\fP (which is an alias for \fBtypeset \-fu\fP) may be used to -create undefined functions; when an undefined function is executed, the -shell searches the path specified in the \fBFPATH\fP parameter for a file -with the same name as the function, which, if found is read and executed. -If after executing the file, the named function is found to be defined, the -function is executed, otherwise, the normal command search is continued -(\fIi.e.\fP, the shell searches the regular built-in command table -and \fBPATH\fP). -Note that if a command is not found using \fBPATH\fP, an attempt is -made to autoload a function using \fBFPATH\fP (this is an undocumented -feature of the original Korn shell). -.PP -Functions can have two attributes, trace and export, which can be set -with \fBtypeset \-ft\fP and \fBtypeset \-fx\fP, respectively. -When a traced function is executed, the shell's \fBxtrace\fP option is turned -on for the functions duration, otherwise the \fBxtrace\fP option is turned off. -The export attribute of functions is currently not used. In the original -Korn shell, exported functions are visible to shell scripts that are executed. -.PP -Since functions are executed in the current shell environment, parameter -assignments made inside functions are visible after the function completes. -If this is not the desired effect, the \fBtypeset\fP command can be used -inside a function to create a local parameter. -Note that special parameters (\fIe.g.\fP, \fB$$\fP, \fB$!\fP) can't be -scoped in this way. -.PP -The exit status of a function is that of the last command executed in -the function. -A function can be made to finish immediately using the \fBreturn\fP command; -this may also be used to explicitly specify the exit status. -.PP -Functions defined with the \fBfunction\fP reserved word are -treated differently in the following ways from functions defined with -the \fB()\fP notation: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -the \fB$0\fP parameter is set to the name of the function -(Bourne-style functions leave \fB$0\fP untouched). -.IP \ \ \(bu -parameter assignments preceeding function calls are not kept in -the shell environment -(executing Bourne-style functions will keep assignments). -.nr PD \n(P2 -In the future, the following differences will also be added: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -A separate trap/signal environment will be used during the execution of -functions. -This will mean that traps set inside a function will not affect the shell's -traps and signals that are not ignored in the shell (but may be trapped) will -have their default effect in a function. -.IP \ \ \(bu -The EXIT trap, if set in a function, will be executed after the function -returns. -.nr PD \n(P2 -.\"}}} -.\"{{{ POSIX mode -.SS "POSIX Mode" -The shell is intended to be POSIX compliant, however, in some cases, POSIX -behaviour is contrary either to the original Korn shell behaviour or to -user convenience. -How the shell behaves in these cases is determined by the state of -the posix option (\fBset \-o posix\fP) \(em if it is on, the POSIX behaviour -is followed, otherwise it is not. -The \fBposix\fP option is set automatically when the shell starts up -if the environment contains the \fBPOSIXLY_CORRECT\fP parameter. -(The shell can also be compiled so that it is in POSIX mode by default, -however this is usually not desirable). -.PP -The following is a list of things that are affected by the state of -the \fBposix\fP option: -.nr P2 \n(PD -.nr PD 0 -.IP \ \ \(bu -reading of \fB$ENV\fP: if not in posix mode, the \fBENV\fP parameter -is not expanded and included when the shell starts. -.IP \ \ \(bu -\fB\e"\fP inside double quoted \fB`\fP..\fB`\fP command substitutions: -in posix mode, the \fB\e"\fP is interpreted when the command is interpreted; -in non-posix mode, the backslash is stripped before the command substitution -is interpreted. For example, \fBecho "`echo \e"hi\e"`"\fP produces `"hi"' in -posix mode, `hi' in non-posix mode. To avoid problems, use the \fB$(...\fP) -form of command substitution. -.IP \ \ \(bu -\fBkill \-l\fP output: in posix mode, signal names are listed one a single line; -in non-posix mode, signal numbers, names and descriptions are printed in -columns. -In future, a new option (\fB\-v\fP perhaps) will be added to distinguish -the two behaviours. -.IP \ \ \(bu -\fBfg\fP exit status: in posix mode, the exit status is 0 if no errors occur; -in non-posix mode, the exit status is that of the last foregrounded job. -.IP \ \ \(bu -\fBgetopts\fP: in posix mode, options must start with a \fB\-\fP; in non-posix -mode, options can start with either \fB\-\fP or \fB+\fP. -.IP \ \ \(bu -brace expansion (also known as alternation): in posix mode, brace expansion -is disabled; in non-posix mode, brace expansion enabled. -Note that \fBset \-o posix\fP (or setting the \fBPOSIXLY_CORRECT\fP parameter) -automatically turns the \fBbraceexpand\fP option off, however it can be -explicitly turned on later. -.IP \ \ \(bu -\fBset \-\fP: in posix mode, this does not clear the \fBverbose\fP or -\fBxtrace\fP options; in non-posix mode, it does. -.IP \ \ \(bu -\fBset\fP exit status: in posix mode, the exit status of set is 0 -if there are no errors; in non-posix mode, the exit status is that of -any command substitutions performed in generating the set command. -For example, `\fBset \-\- `false`; echo $?\fP' prints 0 in posix mode, -1 in non-posix mode. This construct is used in most shell scripts that -use the old \fIgetopt\fP(1) command. -.IP \ \ \(bu -argument expansion of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, and -\fBtypeset\fP commands: in posix mode, normal argument expansion done; -in non-posix mode, field splitting, file globing, brace expansion and -(normal) tilde expansion are turned off, and assignment tilde expansion -is turned on. -.IP \ \ \(bu -signal specification: in posix mode, signals can be specified as digits only -if signal numbers match POSIX values (\fIi.e.\fP, HUP=1, INT=2, QUIT=3, ABRT=6, -KILL=9, ALRM=14, and TERM=15); in non-posix mode, signals can be always digits. -.IP \ \ \(bu -alias expansion: in posix mode, alias expansion is only carried out when -reading command words; in non-posix mode, alias expansion is carried out -on any word following an alias that ended in a space. -For example, the following for loop -.RS -.ft B -alias a='for ' i='j' -.br -a i in 1 2; do echo i=$i j=$j; done -.ft P -.RE -uses parameter \fBi\fP in posix mode, \fBj\fP in non-posix mode. -.nr PD \n(P2 -.\"}}} -.\"{{{ Command Execution (built-in commands) -.SS "Command Execution" -After evaluation of command line arguments, redirections and parameter -assignments, the type of command is determined: a special built-in, -a function, a regular built-in or the name of a file to execute found -using the \fBPATH\fP parameter. -The checks are made in the above order. -Special built-in commands differ from other commands in that -the \fBPATH\fP parameter is not used to find them, an error -during their execution can cause a non-interactive shell to exit and -parameter assignments that are specified before the command are -kept after the command completes. -Just to confuse things, if the posix option is turned off (see \fBset\fP -command below) some special commands are very special in that -no field splitting, file globing, brace expansion nor tilde expansion -is preformed on arguments that look like assignments. -Regular built-in commands are different only in that the \fBPATH\fP -parameter is not used to find them. -.PP -The original ksh and POSIX differ somewhat in which commands are considered -special or regular: -.IP "POSIX special commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -\&. continue exit return trap -: eval export set unset -break exec readonly shift -.TE -.IP "Additional ksh special commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -builtin times typeset -.TE -.IP "Very special commands (non-posix mode)" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -alias readonly set typeset -.TE -.IP "POSIX regular commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -alias command fg kill umask -bg false getopts read unalias -cd fc jobs true wait -.TE -.IP "Additional ksh regular commands" -.TS -lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB . -[ let pwd ulimit -echo print test whence -.TE -.PP -In the future, the additional ksh special and regular commands may -be treated differently from the POSIX special and regular commands. -.PP -Once the type of the command has been determined, any command line parameter -assignments are performed and exported for the duration of the command. -.PP -The following describes the special and regular built-in commands: -.\"{{{ . file [ arg1 ... ] -.IP "\fB\&.\fP \fIfile\fP [\fIarg1\fP ...]" -Execute the commands in \fIfile\fP in the current environment. -The file is searched for in the directories of \fBPATH\fP. -If arguments are given, the positional parameters may be used to -access them while \fIfile\fP is being executed. -If no arguments are given, the positional parameters are those of the -environment the command is used in. -.\"}}} -.\"{{{ : [ ... ] -.IP "\fB:\fP [ ... ]" -The null command. -Exit status is set to zero. -.\"}}} -.\"{{{ alias [ -d | -t [ -r ] ] [-x] [name1[=value1] ...] -.IP "\fBalias\fP [ \fB\-d\fP | \fB\-t\fP [\fB\-r\fP] ] [\fB\-x\fP] [\fIname1\fP[\fB=\fP\fIvalue1\fP] ...]" -Without arguments, \fBalias\fP lists all aliases and their values. For -any name without a value, its value is listed. Any name with a value -defines an alias (see Aliases above). -.sp -The \fB\-x\fP option sets the export attribute of an alias, or, if no -names are given, lists the aliases with the export attribute -(exporting an alias currently has no affect). -.sp -The \fB\-t\fP option indicates that tracked aliases are to be listed/set -(values specified on the command line are ignored for tracked aliases). -The \fB\-r\fP option indicates that all tracked aliases are to be reset. -.sp -The \fB\-d\fP causes directory aliases, which are used in tilde expansion, -to be listed or set (see Tilde Expansion above). -.\"}}} -.\"{{{ bg [job ...] -.IP "\fBbg\fP [\fIjob\fP ...]" -Resume the specified stopped job(s) in the background. -If no jobs are specified, \fB%+\fP is assumed. -This command is only available on systems which support job control. -See Job Control below for more information. -.\"}}} -.\"{{{ bind [-l] [-m] [key[=editing-command] ...] -.IP "\fBbind\fP [\fB\-m\fP] [\fIkey\fP[\fB=\fP\fIediting-command\fP] ...]" -Set or view the current emacs command editing key bindings/macros. -See Emacs Interactive Input Line Editing below for a complete description. -.\"}}} -.\"{{{ break [level] -.IP "\fBbreak\fP [\fIlevel\fP]" -\fBbreak\fP exits the \fIlevel\fPth inner most for, select, until, or while -loop. -\fIlevel\fP defaults to 1. -.\"}}} -.\"{{{ builtin command [arg1 ...] -.IP "\fBbuiltin\fP \fIcommand\fP [\fIarg1\fP ...]" -Execute the built-in command \fIcommand\fP. -.\"}}} -.\"{{{ cd [-LP] [dir] -.IP "\fBcd\fP [\fB\-LP\fP] [\fIdir\fP]" -Set the working directory to \fIdir\fP. If the parameter \fBCDPATH\fP -is set, it lists the search path for the directory containing -\fIdir\fP. A null path means the current directory. If \fIdir\fP is -missing, the home directory \fB$HOME\fP is used. If \fIdir\fP is -\fB\-\fP, the previous working directory is used (see OLDPWD parameter). -If \fB\-L\fP option (logical path) is used or if the \fBphysical\fP option -(see \fBset\fP command below) isn't set, references to \fB..\fP in \fIdir\fP -are relative to the path used get to the directory. -If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option -is set, \fB..\fP is relative to the filesystem directory tree. -The \fBPWD\fP and \fBOLDPWD\fP parameters are updated to reflect the -current and old wording directory, respectively. -.\"}}} -.\"{{{ cd [-LP] old new -.IP "\fBcd\fP [\fB\-LP\fP] \fIold new\fP" -The string \fInew\fP is substituted for \fIold\fP in the current -directory, and the shell attempts to change to the new directory. -.\"}}} -.\"{{{ command [ -pvV ] cmd [arg1 ...] -.IP "\fBcommand\fP [\fB\-p\fP] \fIcmd\fP [\fIarg1\fP ...]" -\fIcmd\fP -is executed exactly as if the \fBcommand\fP had not been specified, -with two exceptions: first, \fIcmd\fP cannot be a shell function, and -second, special built-in commands lose their specialness (\fIi.e.\fP, -redirection and utility errors do not cause the shell to exit, and command -assignments are not permanent). -If the \fB\-p\fP option is given, a default search path is used instead of -the current value of \fBPATH\fP (the actual value of the default path is -system dependent: on POSIXish systems, it is the value returned by -.ce -\fBgetconf CS_PATH\fP -). -.sp -.\"}}} -.\"{{{ continue [levels] -.IP "\fBcontinue\fP [\fIlevels\fP]" -\fBcontinue\fP jumps to the beginning of the \fIlevel\fPth inner most for, -select, until, or while loop. -\fIlevel\fP defaults to 1. -.\"}}} -.\"{{{ echo [-neE] [arg ...] -.IP "\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...]" -Prints its arguments (separated by spaces) followed by a newline, to -standard out. -The newline is suppressed if any of the arguments contain the backslash -sequence \fB\ec\fP. -See \fBprint\fP command below for a list of other backslash sequences -that are recognized. -.sp -The options are provided for compatibility with BSD shell scripts: -\fB\-n\fP suppresses the trailing newline, \fB\-e\fP enables backslash -interpretation (a no-op, since this is normally done), and \fB\-E\fP which -suppresses backslash interpretation. -.\"}}} -.\"{{{ eval command ... -.IP "\fBeval\fP \fIcommand ...\fP" -The arguments are concatenated (with spaces between them) to form -a single string which the shell then parses and executes -in the current environment. -.\"}}} -.\"{{{ exec [command [arg ...]] -.IP "\fBexec\fP [\fIcommand\fP [\fIarg\fP ...]]" -The command is executed without forking, replacing the shell process. -.sp -If no arguments are given, any IO redirection is permanent and the shell -is not replaced. -.\"}}} -.\"{{{ exit [status] -.IP "\fBexit\fP [\fIstatus\fP]" -The shell exits with the specified exit status. -If \fIstatus\fP is not specified, the exit status is the current -value of the \fB?\fP parameter. -.\"}}} -.\"{{{ export [-p] [parameter[=value] ...] -.IP "\fBexport\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..." -Sets the export attribute of the named parameters. -Exported parameters are passed in the environment to executed commands. -If values are specified, the named parameters also assigned. -.sp -If no parameters are specified, the names of all parameters with the export -attribute are printed one per line, unless the \fB\-p\fP option is used, -in which case \fBexport\fP commands defining all exported -parameters, including their values, are printed. -.\"}}} -.\"{{{ false -.IP "\fBfalse\fP" -A command that exits with a non-zero status. -.\"}}} -.\"{{{ fc [-e editor | -l [-n]] [-r] [first [ last ]] -.\"}}} -.\"{{{ fc [-e - | -s] [-g] [old=new] [prefix] -.IP "\fBfc\fP [\fB\-e \-\fP | \fB\-s\fP] [\fB\-g\fP] [\fIold\fP\fB=\fP\fInew\fP] [\fIprefix\fP]" -Re-execute the selected command (the previous command by default) after -performing the optional substitution of \fIold\fP with \fInew\fP. If -\fB\-g\fP is specified, all occurrences of \fIold\fP are replaced with -\fInew\fP. This command is usually accessed with the predefined alias -\fBr='fc \-e \-'\fP. -.\"}}} -.\"{{{ fg [job ...] -.IP "\fBfg\fP [\fIjob\fP ...]" -Resume the specified job(s) in the foreground. -If no jobs are specified, \fB%+\fP is assumed. -This command is only available on systems which support job control. -See Job Control below for more information. -.\"}}} -.\"{{{ getopts optstring name [arg ...] -.IP "\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIarg\fP ...]" -\fBgetopts\fP is used by shell procedures to parse the specified arguments -(or positional parameters, if no arguments are given) and to check for legal -options. -\fIoptstring\fP contains the option letters that -\fBgetopts\fP is to recognize. If a letter is followed by a colon, the -option is expected to have an argument. -Arguments containing options must all start with either a \fB\-\fP or -a \fB+\fP, options that do not take arguments may be grouped in a single -argument. -If an option takes an argument and the option character is not the last -character of the argument it is found in, the remainder of the argument -is taken to be the option's argument, otherwise, the next argument is -the option's argument. -.sp -Each time \fBgetopts\fP is invoked, it places the next option in -the shell parameter \fIname\fP and the index of the next argument to be -processed in the shell parameter \fBOPTIND\fP. -If the option was introduced with a \fB+\fP, the option placed in -\fIname\fP is prefixed with a \fB+\fP. -When an option requires an argument, \fBgetopts\fP places it in the -shell parameter \fBOPTARG\fP. -When an illegal option or a missing option argument is -encountered a question mark or a colon is placed in \fIname\fP -(indicating an illegal option or missing argument, respectively) -and \fBOPTARG\fP is set to the option character that caused the problem. -An error message is also printed to standard error if \fIoptstring\fP -does not begin with a colon. -.sp -When the end of the options is encountered, \fBgetopts\fP exits with a -non-zero exit status. -Options end at the first (non-option argument) argument that does not -start with a \-, or when a \fB\-\-\fP argument is encountered. -.sp -Option parsing can be reset by setting \fBOPTIND\fP to 1 (this is done -automatically whenever the shell or a shell procedure is invoked). -.sp -Warning: Changing the value of the shell parameter \fBOPTIND\fP to -a value other than 1, or parsing different sets of arguments without -resetting \fBOPTIND\fP may lead to unexpected results. -.\"}}} -.\"{{{ hash [-r] [name ...] -.IP "\fBhash\fP [\fB\-r\fP] [\fIname ...\fP]" -Without arguments, any hashed executable command pathnames are listed. -The \fB\-r\fP option causes all hashed commands to be removed -from the hash table. -Each \fIname\fP is searched as if it where a command name and added to the -hash table if it is an executable command. -.\"}}} -.\"{{{ jobs [-lpn] [job ...] -.IP "\fBjobs\fP [\fB\-lpn\fP] [\fIjob\fP ...]" -Display information about the specified jobs; if no jobs are specified, -all jobs are displayed. -The \fB\-n\fP option causes information to be displayed only for jobs -that have changed state since the last notification. -If the \fB\-l\fP option is used, the process-id of each process in a job -is also listed. -The \fB\-p\fP option causes only the process group of each job to be printed. -See Job Control below for the format of \fIjob\fP and the displayed job. -.\"}}} -.\"{{{ kill [-s signame | -signum | -signame] { job | pid | -pgrp } ... -.IP "\fBkill\fP [\fB\-s\fP \fIsigname\fP | \fB\-signum\fP | \fB\-signame\fP ] { \fIjob\fP | \fIpid\fP | \fB\-\fP\fIpgrp\fP } ..." -Send the specified signal to the specified jobs, process ids, or process groups. -If no signal is specified, the signal TERM is sent. -If a job is specified, the signal is sent to the job's process group. -See Job Control below for the format of \fIjob\fP. -.\"}}} -.\"{{{ kill -l [exit-status ...] -.IP "\fBkill \-l\fP [\fIexit-status\fP ...]" -Print the name of the signal that killed a process which exited with -the specified \fIexit-status\fPes. -If no arguments are specified, a list of all the signals, their numbers and -a short description of them are printed. -.\"}}} -.\"{{{ let [expression ...] -.\"}}} -.\"{{{ print [-nprsun | -R [-en]] [argument ...] -.IP "\fBprint\fP [\fB\-nprsu\fP\fIn\fP | \fB\-R\fP [\fB\-en\fP]] [\fIargument ...\fP]" -\fBPrint\fP prints its arguments on the standard output, separated by -spaces, and terminated with a newline. The \fB\-n\fP option suppresses -the newline. By default, certain C escapes are translated. These -include \eb, \ef, \en, \er, \et, \ev, and \e0### (# is an octal digit, of -which there may be 0 to 3). -\ec is equivalent to using the \fB\-n\fP option. \e expansion may be -inhibited with the \fB\-r\fP option. -The \fB\-s\fP option prints to the history file instead of standard output, -the \fB\-u\fP option prints to file descriptor \fIn\fP (\fIn\fP -defaults to 1 if omitted), and the \fB\-p\fP option prints to the co-process -(see Co-Processes above). -.sp -The \fB\-R\fP option is used to emulate, to some degree, the BSD echo -command, which does not process \e sequences unless the \fB\-e\fP option -is given. -As above, the \fB\-n\fP option suppresses the trailing newline. -.\"}}} -.\"{{{ pwd [-LP] -.IP "\fBpwd\fP [\fB\-LP\fP]" -Print the present working directory. -If \fB\-L\fP option is used or if the \fBphysical\fP option -(see \fBset\fP command below) isn't set, the logical path is printed -(\fIi.e.\fP, the path used to \fBcd\fP to the current directory). -If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option -is set, the path determined from the filesystem (by following \fB..\fP -directories to the root directory) is printed. -.\"}}} -.\"{{{ read [-prsun] [parameter ...] -.IP "\fBread\fP [\fB\-prsu\fP\fIn\fP] [\fIparameter ...\fP]" -Reads a line of input from standard input, separate the line into fields using -the \fBIFS\fP parameter (see Substitution above), and assign each field to the -specified parameters. -If there are more parameters than fields, the extra parameters are set to null, -or alternatively, if there are more fields than parameters, the last parameter -is assigned the remaining fields (inclusive of any separating spaces). -If no parameters are specified, the \fBREPLY\fP parameter is used. -If the input line ends in a backslash and the \fB\-r\fP option was not used, the -backslash and newline are stripped and more input is read. -If no input is read, \fBread\fP exits with a non-zero status. -.sp -The first parameter may have a question mark and a string appended to it, in -which case the string is used as a prompt (printed to standard error before -any input is read) if the input is a tty -(\fIe.g.\fP, \fBread nfoo?'number of foos: '\fP). -.sp -The \fB\-u\fP\fIn\fP and \fB\-p\fP options cause input to be read -from file descriptor \fIn\fP or the current co-process (see Co-Processes above -for comments on this), respectively. -If the \fB\-s\fP option is used, input is saved to the history file. -.\"}}} -.\"{{{ readonly [-p] [parameter[=value] ...] -.IP "\fBreadonly\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..." -Sets the readonly attribute of the named parameters. If values are given, -parameters are set to them before setting the attribute. -Once a parameter is made readonly, it cannot be unset and its value cannot -be changed. -.sp -If no parameters are specified, the names of all parameters with the readonly -attribute are printed one per line, unless the \fB\-p\fP option is used, -in which case \fBreadonly\fP commands defining all readonly -parameters, including their values, are printed. -.\"}}} -.\"{{{ return [status] -.IP "\fBreturn\fP [\fIstatus\fP]" -Returns from a function or \fB.\fP script, with exit status \fIstatus\fP. -If no \fIstatus\fP is given, the exit status of the last executed command -is used. -If used outside of a function or \fB.\fP script, it has the same effect -as \fBexit\fP. -Note that pdksh treats both profile and \fB$ENV\fP files as \fB.\fP scripts, -while the original Korn shell only treats profiles as \fB.\fP scripts. -.\"}}} -.\"{{{ set [+-abCefhkmnpsuvxX] [+-o [option]] [+-A name] [--] [arg ...] -.IP "\fBset\fP [\fB\(+-abCefhkmnpsuvxX\fP] [\fB\(+-o\fP [\fIoption\fP]] [\fB\(+-A\fP \fIname\fP] [\fB\-\-\fP] [\fIarg\fP ...]" -The set command can be used to set (\fB\-\fP) or clear (\fB+\fP) shell options, -set the positional parameters, or set an array parameter. -Options can be changed using the \fB\(+-o\fP \fIoption\fP syntax, -where \fIoption\fP is the long name of an option, or using -the \fB\(+-\fP\fIletter\fP syntax, where \fIletter\fP is the -option's single letter name (not all options have a single letter name). -The following table lists both option letters (if they exist) and long names -along with a description of what the option does. -.sp -.TS -expand; -afB lfB lw(3i). -\-A T{ -Sets the elements of the array parameter \fIname\fP to \fIarg\fP ...; -If \fB\-A\fP is used, the array is reset (\fIi.e.\fP, emptied) first; -if \fB+A\fP is used, the first N elements are set (where N is the number -of \fIarg\fPs), the rest are left untouched. -T} -\-a allexport T{ -all new parameters are created with the export attribute -T} -\-b notify T{ -Print job notification messages asynchronously, instead of just before the -prompt. -Only used if job control is enabled (\fB\-m\fP). -T} -\-C noclobber T{ -Prevent \fB>\fP redirection from overwriting existing files (\fB>|\fP must -be used to force an overwrite). -T} -\-e errexit T{ -Exit (after executing the \fBERR\fP trap) as soon as an error occurs or -a command fails (\fIi.e.\fP, exits with a non-zero status). -This does not apply to commands whose exit status is explicitly tested by a -shell construct such as \fBif\fP, \fBuntil\fP, \fBwhile\fP, \fB&&\fP or -\fB||\fP statements. -T} -\-f noglob T{ -Do not expand file name patterns. -T} -\-h trackall T{ -Create tracked aliases for all executed commands (see Aliases above). -On by default for non-interactive shells. -T} -\-i interactive T{ -Enable interactive mode \- this can only be set/unset when the shell is -invoked. -T} -\-k keyword T{ -Parameter assignments are recognized anywhere in a command. -T} -\-l login T{ -The shell is a login shell \- this can only be set/unset when the shell is -invoked (see Shell Startup above). -T} -\-m monitor T{ -Enable job control (default for interactive shells). -T} -\-n noexec T{ -Do not execute any commands \- useful for checking the syntax of scripts -(ignored if interactive). -T} -\-p privileged T{ -Set automatically if, when the shell starts, the read uid or gid does not -match the effective uid or gid, respectively. -See Shell Startup above for a description of what this -means. -T} --r restricted T{ -Enable restricted mode \(em this option can only be used when the shell is -invoked. See Shell Startup above for a description of what this -means. -T} -\-s stdin T{ -If used when the shell is invoked, commands are read from standard input. -Set automatically if the shell is invoked with no arguments. -.sp -When \fB\-s\fP is used in the \fBset\fP command, it causes the specified -arguments to be sorted before assigning them to the positional parameters -(or to array \fIname\fP, if \fB\-A\fP is used). -T} -\-u nounset T{ -Referencing of an unset parameter is treated as an error, unless -one of the \fB\-\fP, \fB+\fP or \fB=\fP modifiers is used. -T} -\-v verbose T{ -Write shell input to standard error as it is read. -T} -\-x xtrace T{ -Print commands and parameter assignments when they are executed, -preceded by the value of \fBPS4\fP. -T} -\-X markdirs T{ -Mark directories with a trailing \fB/\fP during file name generation. -T} - bgnice T{ -Background jobs are run with lower priority. -T} - ignoreeof T{ -The shell will not exit on when end-of-file is read, \fBexit\fP must be used. -T} - nohup T{ -Do not kill running jobs with a \fBHUP\fP signal when a login shell exists. -Currently set by default, but this will change in the future to be compatible -with the original Korn shell (which doesn't have this option, but does -send the \fBHUP\fP signal). -T} - nolog T{ -No effect \- in the original Korn shell, this prevents function definitions -from being stored in the history file. -T} - physical T{ -Causes the \fBcd\fP and \fBpwd\fP commands to use `physical' -(\fIi.e.\fP, the filesystem's) \fB..\fP directories instead of `logical' -directories (\fIi.e.\fP, the shell handles \fB..\fP, which allows the user -to be obliveous of symlink links to directories). -Clear by default. Note that setting -this option does not effect the current value of the \fBPWD\fP parameter; -only the \fBcd\fP command changes \fBPWD\fP. -See the \fBcd\fP and \fBpwd\fP commands above for more details. -T} - posix T{ -Enable posix mode. See POSIX Mode above. -T} - vi T{ -Enable vi-like command line editing (interactive shells only). -T} - viraw T{ -No effect \- in the original Korn shell, unless viraw was set, the vi command -line mode would let the tty driver do the work until ESC (^[) was entered. -pdksh is always in viraw mode. -T} - vi-esccomplete T{ -In vi command line editing, do command / file name completion when -escape (^[) is entered in command mode. -T} - vi-show8 T{ -Prefix characters with the eighth bit set with `M-'. -If this option is not set, characters in the range -128-160 are printed as is, which may cause problems. -T} - vi-tabcomplete T{ -In vi command line editing, do command / file name completion when -tab (^I) is entered in insert mode. -T} -.TE -.sp -These options can also be used upon invocation of the shell. The current -set of options (with single letter names) can be found in the -parameter \fB\-\fP. -\fBset -o\fP with no option name will list all the options and whether each -is on or off; \fBset +o\fP will print the long names of all options that -are currently on. -.sp -Remaining arguments, if any, are positional parameters and are assigned, -in order, to the -positional parameters (\fIi.e.\fP, \fB1\fP, \fB2\fP, \fIetc.\fP). -If options are ended with \fB\-\-\fP and there are no remaining arguments, -all positional parameters are cleared. -If no options or arguments are given, then the values of all names are printed. -For unknown historical reasons, a lone \fB\-\fP option is treated specially: -it clears both the \fB\-x\fP and \fB\-v\fP options. -.\"}}} -.\"{{{ shift [number] -.IP "\fBshift\fP [\fInumber\fP]" -The positional parameters \fInumber\fP+1, \fInumber\fP+2 \fIetc.\fP\& are -renamed to \fB1\fP, \fB2\fP, \fIetc.\fP -\fInumber\fP defaults to 1. -.\"}}} -.\"{{{ test expression, [ expression ] -.IP "\fBtest\fP \fIexpression\fP" -.IP "\fB[\fP \fIexpression\fP \fB]\fP" -\fBtest\fP evaluates the \fIexpression\fP and returns zero status if -true, and 1 status if false and greater than 1 if there was an error. -It is normally used as the -condition command of \fBif\fP and \fBwhile\fP statements. -The following basic expressions are available: -.sp -.TS -afB ltw(2.8i). -\fIstr\fP T{ -\fIstr\fP has non-zero length. Note that there is the potential -for problems if \fIstr\fP turns out to be an operator (\fIe.g.\fP, \fB-r\fP) -- it is generally better to use a test like -.RS -\fB[ X"\fP\fIstr\fP\fB" != X ]\fP -.RE -instead (double quotes are used in case \fIstr\fP contains spaces or file -globing characters). -T} -\-r \fIfile\fP T{ -\fIfile\fP exists and is readable -T} -\-w \fIfile\fP T{ -\fIfile\fP exists and is writable -T} -\-x \fIfile\fP T{ -\fIfile\fP exists and is executable -T} -\-a \fIfile\fP T{ -\fIfile\fP exists -T} -\-e \fIfile\fP T{ -\fIfile\fP exists -T} -\-f \fIfile\fP T{ -\fIfile\fP is a regular file -T} -\-d \fIfile\fP T{ -\fIfile\fP is a directory -T} -\-c \fIfile\fP T{ -\fIfile\fP is a character special device -T} -\-b \fIfile\fP T{ -\fIfile\fP is a block special device -T} -\-p \fIfile\fP T{ -\fIfile\fP is a named pipe -T} -\-u \fIfile\fP T{ -\fIfile\fP's mode has setuid bit set -T} -\-g \fIfile\fP T{ -\fIfile\fP's mode has setgid bit set -T} -\-k \fIfile\fP T{ -\fIfile\fP's mode has sticky bit set -T} -\-s \fIfile\fP T{ -\fIfile\fP is not empty -T} -\-O \fIfile\fP T{ -\fIfile\fP's owner is the shell's effective user-ID -T} -\-G \fIfile\fP T{ -\fIfile\fP's group is the shell's effective group-ID -T} -\-h \fIfile\fP T{ -\fIfile\fP is a symbolic link -T} -\-H \fIfile\fP T{ -\fIfile\fP is a context dependent directory (only useful on HP-UX) -T} -\-L \fIfile\fP T{ -\fIfile\fP is a symbolic link -T} -\-S \fIfile\fP T{ -\fIfile\fP is a socket -T} -\-o \fIoption\fP T{ -shell \fIoption\fP is set (see \fBset\fP command above for list of options). -As a non-standard extension, if the option starts with a \fB!\fP, the test -is negated; the test always fails if option doesn't exist (thus -.RS -\fB[ -o \fP\fIfoo\fP \fB-o -o !\fP\fIfoo\fP \fB]\fP -.RE -returns true if and only if option \fIfoo\fP exists). -T} -\fIfile\fP \-nt \fIfile\fP T{ -first \fIfile\fP is newer than second \fIfile\fP -T} -\fIfile\fP \-ot \fIfile\fP T{ -first \fIfile\fP is older than second \fIfile\fP -T} -\fIfile\fP \-ef \fIfile\fP T{ -first \fIfile\fP is the same file as second \fIfile\fP -T} -\-t [\fIfd\fP] T{ -file descriptor is a tty device. -Default value of \fIfd\fP is 1. -T} -\fIstring\fP T{ -\fIstring\fP is not empty -T} -\-z \fIstring\fP T{ -\fIstring\fP is empty -T} -\-n \fIstring\fP T{ -\fIstring\fP is not empty -T} -\fIstring\fP = \fIstring\fP T{ -strings are equal -T} -\fIstring\fP != \fIstring\fP T{ -strings are not equal -T} -\fInumber\fP \-eq \fInumber\fP T{ -numbers compare equal -T} -\fInumber\fP \-ne \fInumber\fP T{ -numbers compare not equal -T} -\fInumber\fP \-ge \fInumber\fP T{ -numbers compare greater than or equal -T} -\fInumber\fP \-gt \fInumber\fP T{ -numbers compare greater than -T} -\fInumber\fP \-le \fInumber\fP T{ -numbers compare less than or equal -T} -\fInumber\fP \-lt \fInumber\fP T{ -numbers compare less than -T} -.TE -.sp -The above basic expressions, in which unary operators have precedence over -binary operators, may be combined with the following operators -(listed in increasing order of precedence): -.sp -.TS -afB l. -\fIexpr\fP \-o \fIexpr\fP logical or -\fIexpr\fP \-a \fIexpr\fP logical and -! \fIexpr\fP logical not -( \fIexpr\fP ) grouping -.TE -.sp -On operating systems not supporting \fB/dev/fd/\fP\fIn\fP devices -(where \fIn\fP is a file descriptor number), -the \fBtest\fP command will attempt to fake it for all tests that -operate on files (except the \fB-e\fP test). -I.e., \fB[ -w /dev/fd/2 ]\fP tests if file descriptor 2 is writable. -.sp -Note that some special rules are applied (courtesy of POSIX) if the -number of arguments to \fBtest\fP or \fB[\fP \&... \fB]\fP is less than -five: if leading \fB!\fP arguments can be stripped such that only one -argument remains then a string length test is performed (again, even if -the argument is a unary operator); -if leading \fB!\fP arguments can be stripped such that three -arguments remain and the second argument is a binary operator, then the -binary operation is performed (even if first argument is a unary -operator, including an unstripped \fB!\fP). -.sp -\fBNote:\fP A common mistake is to use \fBif [ $foo = bar ]\fP which -fails if parameter \fBfoo\fP is null or unset, if it has embedded spaces -(\fIi.e.\fP, \fBIFS\fP characters), or if it is a unary operator like \fB!\fP or -\fB\-n\fP. Use tests like \fBif [ "X$foo" = Xbar ]\fP instead. -.\"}}} -.\"{{{ times -.IP \fBtimes\fP -Print the accumulated user and system times used by the shell and by -processes which have exited that the shell started. -.\"}}} -.\"{{{ trap [handler signal ...] -.IP "\fBtrap\fP [\fIhandler\fP \fIsignal ...\fP]" -Sets trap handler that is to be executed when any of the specified signals -are received. -\fBHandler\fP is either a null string, indicating the signals are to -be ignored, a minus (\fB\-\fP), indicating that the default action is to -be taken for the signals (see signal(2 or 3)), or a string containing shell -commands to be evaluated and executed at the first opportunity (\fIi.e.\fP, -when the current command completes, or before printing the next \fBPS1\fP -prompt) after receipt of one of the signals. -\fBSignal\fP is the name of a signal (\fIe.g.\fP, PIPE or ALRM) or the number -of the signal (see \fBkill \-l\fP command above). -There are two special signals: \fBEXIT\fP (also known as \fB0\fP), which -is executed when the shell is about to exit, and \fBERR\fP which is -executed after an error occurs (an error is something that would cause -the shell to exit if the \fB\-e\fP or \fBerrexit\fP option were set \(em -see \fBset\fP command above). -\fBEXIT\fP handlers are executed in the environment of the last executed -command. -Note that for non-interactive shells, the trap handler cannot be changed for -signals that were ignored when the shell started. -.sp -With no arguments, \fBtrap\fP lists, as a series of \fBtrap\fP commands, -the current state of the traps that have been set since the shell started. -.sp -.\" todo: add these features (trap DEBUG, trap ERR/EXIT in function) -The original Korn shell's \fBDEBUG\fP trap and the handling of \fBERR\fP and -\fBEXIT\fP traps in functions are not yet implemented. -.\"}}} -.\"{{{ true -.IP \fBtrue\fP -A command that exits with a zero value. -.\"}}} -.\"{{{ typeset [[+-Ulrtux] [-L[n]] [-R[n]] [-Z[n]] [-i[n]] | -f [-tux]] [name[=value] ...] -.IP "\fBtypeset\fP [[\(+-Ulrtux] [\fB\-L\fP[\fIn\fP]] [\fB\-R\fP[\fIn\fP]] [\fB\-Z\fP[\fIn\fP]] [\fB\-i\fP[\fIn\fP]] | \fB\-f\fP [\fB\-tux\fP]] [\fIname\fP[\fB=\fP\fIvalue\fP] ...]" -Display or set parameter attributes. -With no \fIname\fP arguments, parameter attributes are displayed: if no options -arg used, the current attributes of all parameters are printed as typeset -commands; if an option is given (or \fB\-\fP with no option letter) -all parameters and their values with the specified attributes are printed; -if options are introduced with \fB+\fP, parameter values are not printed. -.sp -If \fIname\fP arguments are given, the attributes of the named parameters -are set (\fB\-\fP) or cleared (\fB+\fP). -Values for parameters may optionally be specified. -If typeset is used inside a function, any newly created parameters are local -to the function. -.sp -When \fB\-f\fP is used, typeset operates on the attributes of functions. -As with parameters, if no \fIname\fPs are given, functions are listed -with their values (\fIi.e.\fP, definitions) unless options are introduced with -\fB+\fP, in which case only the function names are reported. -.sp -.TS -expand; -afB lw(4.5i). -\-L\fIn\fP T{ -Left justify attribute: \fIn\fP specifies the field width. -If \fIn\fP is not specified, the current width of a parameter (or the -width of its first assigned value) is used. -Leading white space (and zeros, if used with the \fB\-Z\fP option) is stripped. -If necessary, values are either truncated or space padded to fit the -field width. -T} -\-R\fIn\fP T{ -Right justify attribute: \fIn\fP specifies the field width. -If \fIn\fP is not specified, the current width of a parameter (or the -width of its first assigned value) is used. -Trailing white space are stripped. -If necessary, values are either stripped of leading characters -or space padded to make them fit the field width. -T} -\-Z\fIn\fP T{ -Zero fill attribute: if not combined with \fB\-L\fP, this is the -same as \fB\-R\fP, except zero padding is used instead of space padding. -T} -\-i\fIn\fP T{ -integer attribute: -\fIn\fP specifies the base to use when displaying the integer -(if not specified, the base given in the first assignment is used). -Parameters with this attribute may be assigned values containing -arithmetic expressions. -T} -\-U T{ -unsigned integer attribute: integers are printed as unsigned values -(only useful when combined with the \fB\-i\fP option). -This option is not in the original Korn shell. -T} -\-f T{ -Function mode: display or set functions and their attributes, instead of -parameters. -T} -\-l T{ -Lower case attribute: all upper case characters in values are converted to -lower case. -(In the original Korn shell, this parameter meant `long integer' when used -with the \fB\-i\fP option). -T} -\-r T{ -Readonly attribute: parameters with the this attribute may not be assigned to -or unset. -Once this attribute is set, it can not be turned off. -T} -\-t T{ -Tag attribute: has no meaning to the shell; provided for application use. -.sp -For functions, \fB\-t\fP is the trace attribute. -When functions with the trace attribute are executed, the \fBxtrace\fP (\fB\-x\fP) shell option is temporarily turned on. -T} -\-u T{ -Upper case attribute: all lower case characters in values are converted to -upper case. -(In the original Korn shell, this parameter meant `unsigned integer' when used -with the \fB\-i\fP option, which meant upper case letters would never be used -for bases greater than 10. See the \fB\-U\fP option). -.sp -For functions, \fB\-u\fP is the undefined attribute. See Functions above -for the implications of this. -T} -\-x T{ -Export attribute: parameters (or functions) are placed in the environment of -any executed commands. Exported functions are not implemented yet. -T} -.TE -.\"}}} -.\"{{{ ulimit [-acdfHlmnpsStvw] [value] -.IP "\fBulimit\fP [\fB\-acdfHlmnpsStvw\fP] [\fIvalue\fP]" -Display or set process limits. -If no options are used, the file size limit (\fB\-f\fP) is assumed. -\fBvalue\fP, if specified, may be either be an arithmetic expression or the -word \fBunlimited\fP. -The limits affect the shell and any processes created by the shell after -a limit is imposed. -Note that some systems may not allow limits to be increased once they -are set. -Also note that the types of limits available are system dependent \- some -systems have only the \fB\-f\fP limit. -.RS -.IP \fB\-a\fP -Displays all limits; unless \fB\-H\fP is used, soft limits are displayed. -.IP \fB\-H\fP -Set the hard limit only (default is to set both hard and soft limits). -.IP \fB\-S\fP -Set the soft limit only (default is to set both hard and soft limits). -.IP \fB\-c\fP -Impose a size limit of \fIn\fP blocks on the size of core dumps. -.IP \fB\-d\fP -Impose a size limit of \fIn\fP kbytes on the size of the data area. -.IP \fB\-f\fP -Impose a size limit of \fIn\fP blocks on files written by the shell and -its child processes (files of any size may be read). -.IP \fB\-l\fP -Impose a limit of \fIn\fP kbytes on the amount of locked (wired) physical -memory. -.IP \fB\-m\fP -Impose a limit of \fIn\fP kbytes on the amount of physical memory used. -.IP \fB\-n\fP -Impose a limit of \fIn\fP file descriptors that can be open at once. -.IP \fB\-p\fP -Impose a limit of \fIn\fP processes that can be run by the user at any one -time. -.IP \fB\-s\fP -Impose a size limit of \fIn\fP kbytes on the size of the stack area. -.IP \fB\-t\fP -Impose a time limit of \fIn\fP cpu seconds to be used by each process. -.IP \fB\-v\fP -Impose a limit of \fIn\fP kbytes on the amount of virtual memory used; -on some systems this is the maximum allowable virtual address (in bytes, -not kbytes). -.IP \fB\-w\fP -Impose a limit of \fIn\fP kbytes on the amount of swap space used. -.PP -As far as \fBulimit\fP is concerned, a block is 512 bytes. -.RE -.\"}}} -.\"{{{ umask [-S] [mask] -.IP "\fBumask\fP [\fB\-S\fP] [\fImask\fP]" -.RS -Display or set the file permission creation mask, or umask (see \fIumask\fP(2)). -If the \fB\-S\fP option is used, the mask displayed or set is symbolic, -otherwise it is an octal number. -.sp -Symbolic masks are like those used by \fIchmod\fP(1): -.RS -[\fBugoa\fP]{{\fB=+-\fP}{\fBrwx\fP}*}+[\fB,\fP...] -.RE -in which the first group of characters is the \fIwho\fP part, the second -group is the \fIop\fP part, and the last group is the \fIperm\fP part. -The \fIwho\fP part specifies which part of the umask is to be modified. -The letters mean: -.RS -.IP \fBu\fP -the user permissions -.IP \fBg\fP -the group permissions -.IP \fBo\fP -the other permissions (non-user, non-group) -.IP \fBa\fP -all permissions (user, group and other) -.RE -.sp -The \fIop\fP part indicates how the \fIwho\fP permissions are to be modified: -.RS -.IP \fB=\fP -set -.IP \fB+\fP -added to -.IP \fB\-\fP -removed from -.RE -.sp -The \fIperm\fP part specifies which permissions are to be set, added or removed: -.RS -.IP \fBr\fP -read permission -.IP \fBw\fP -write permission -.IP \fBx\fP -execute permission -.RE -.sp -When symbolic masks are used, they describe what permissions may -be made available (as opposed to octal masks in which a set bit means -the corresponding bit is to be cleared). -Example: `ug=rwx,o=' sets the mask so files will not be readable, writable -or executable by `others', and is equivalent (on most systems) to the octal -mask `07'. -.RE -.\"}}} -.\"{{{ unalias [-adt] name ... -.IP "\fBunalias\fP [\fB\-adt\fP] [\fIname1\fP ...]" -The aliases for the given names are removed. -If the \fB\-a\fP option is used, all aliases are removed. -If the \fB\-t\fP or \fB\-d\fP options are used, the indicated operations -are carried out on tracked or directory aliases, respectively. -.\"}}} -.\"{{{ unset [-fv] parameter ... -.IP "\fBunset\fP [\fB\-fv\fP] \fIparameter\fP ..." -Unset the named parameters (\fB\-v\fP, the default) or functions (\fB\-f\fP). -The exit status is non-zero if any of the parameters were already unset, -zero otherwise. -.\"}}} -.\"{{{ wait [job] -.IP "\fBwait\fP [\fIjob\fP]" -Wait for the specified job(s) to finish. -The exit status of wait is that of the last specified job: -if the last job is killed by a signal, the exit status is 128 + the -number of the signal (see \fBkill \-l\fP \fIexit-status\fP above); if the last -specified job can't be found (because it never existed, or had already -finished), the exit status of wait is 127. -See Job Control below for the format of \fIjob\fP. -\fBWait\fP will return if a signal for which a trap has been set is received, -or if a HUP, INT or QUIT signal is received. -.sp -If no jobs are specified, \fBwait\fP waits for all currently running jobs -(if any) to finish and exits with a zero status. -If job monitoring is enabled, the completion status of jobs is -printed (this is not the case when jobs are explicitly specified). -.\"}}} -.\"{{{ whence [-pv] [name ...] -.IP "\fBwhence\fP [\fB\-pv\fP] [name ...]" -For each name, the type of command is listed (reserved word, built-in, alias, -function, tracked alias or executable). -If the \fB\-p\fP option is used, a path search done even if \fIname\fP -is a reserved word, alias, \fIetc.\fP -Without the \fB\-v\fP option, \fBwhence\fP is similar to \fBcommand \-v\fP -except that \fBwhence\fP will find reserved words and won't print aliases -as alias commands; -with the \fB\-v\fP option, \fBwhence\fP is the same as \fBcommand \-V\fP. -Note that for \fBwhence\fP, the \fB\-p\fP option does not affect the search -path used, as it does for \fBcommand\fP. -If the type of one or more of the names could not be determined, the -exit status is non-zero. -.\"}}} -.\"}}} -.\"{{{ job control (and its built-in commands) -.SS "Job Control" -Job control refers to the shell's ability to monitor and control \fBjobs\fP, -which are processes or groups of processes created for commands or pipelines. -At a minimum, the shell keeps track of the status of the background -(\fIi.e.\fP, asynchronous) jobs that currently exist; this information can be -displayed using the \fBjobs\fP command. -If job control is fully enabled (using \fBset \-m\fP or -\fBset \-o monitor\fP), as it is for interactive shells, -the processes of a job are placed in their own process group, -foreground jobs can be stopped by typing the suspend character from the -terminal (normally ^Z), -jobs can be restarted in either the foreground -or background, using the \fBfg\fP and \fBbg\fP commands, respectively, -and the state of the terminal is saved or restored when a foreground -job is stopped or restarted, respectively. -.sp -Note that only commands that create processes (\fIe.g.\fP, -asynchronous commands, subshell commands, and non-built-in, -non-function commands) can be stopped; commands like \fBread\fP cannot be. -.sp -When a job is created, it is assigned a job-number. -For interactive shells, this number is printed inside \fB[\fP..\fB]\fP, -followed by the process-ids of the processes in the job when an asynchronous -command is run. -A job may be referred to in \fBbg\fP, \fBfg\fP, \fBjobs\fP, \fBkill\fP and -\fBwait\fP commands either by the process id of the last process in the -command pipeline (as stored in the \fB$!\fP parameter) or by prefixing the -job-number with a percent sign (\fB%\fP). -Other percent sequences can also be used to refer to jobs: -.sp -.TS -expand; -afB lw(4.5i). -%+ T{ -The most recently stopped job, or, if there are no stopped jobs, the oldest -running job. -T} -%%\fR, \fP% T{ -Same as \fB%+\fP. -T} -%\- T{ -The job that would be the \fB%+\fP job, if the later did not exist. -T} -%\fIn\fP T{ -The job with job-number \fIn\fP. -T} -%?\fIstring\fP T{ -The job containing the string \fIstring\fP (an error occurs if multiple jobs -are matched). -T} -%\fIstring\fP T{ -The job starting with string \fIstring\fP (an error occurs if multiple jobs -are matched). -T} -.TE -.sp -When a job changes state (\fIe.g.\fP, a background job finishes or foreground -job is stopped), the shell prints the following status information: -.RS -\fB[\fP\fInumber\fP\fB]\fP \fIflag status command\fP -.RE -where -.IP "\ \fInumber\fP" -is the job-number of the job. -.IP "\ \fIflag\fP" -is \fB+\fP or \fB-\fP if the job is the \fB%+\fP or \fB%-\fP job, -respectively, or space if it is neither. -.IP "\ \fIstatus\fP" -indicates the current state of the job and can be -.RS -.IP "\fBRunning\fP" -the job has neither stopped or exited (note that running does not -necessarily mean consuming CPU time \(em the process could be blocked waiting -for some event). -.IP "\fBDone\fP [\fB(\fP\fInumber\fP\fB)\fP]" -the job exited. \fInumber\fP is the exit status of the job, which is -omitted if the status is zero. -.IP "\fBStopped\fP [\fB(\fP\fIsignal\fP\fB)\fP]" -the job was stopped by the indicated \fIsignal\fP (if no signal is given, -the job was stopped by SIGTSTP). -.IP "\fIsignal-description\fP [\fB(core dumped)\fP]" -the job was killed by a signal (\fIe.g.\fP, Memory\ fault, -Hangup, \fIetc.\fP \(em use -\fBkill \-l\fP for a list of signal descriptions). -The \fB(core\ dumped)\fP message indicates the process created a core file. -.RE -.IP "\ \fIcommand\fP" -is the command that created the process. -If there are multiple processes in the job, then each process will -have a line showing its \fIcommand\fP and possibly its \fIstatus\fP, -if it is different from the status of the previous process. -.PP -When an attempt is made to exit the shell while there are jobs in -the stopped state, the shell warns the user that there are stopped jobs -and does not exit. -If another attempt is immediately made to exit the shell, the stopped -jobs are sent a \fBHUP\fP signal and the shell exits. -Similarly, if the \fBnohup\fP option is not set and there are running -jobs when an attempt is made to exit a login shell, the shell warns the -user and does not exit. -If another attempt is immediately made to exit the shell, the running -jobs are sent a \fBHUP\fP signal and the shell exits. -.\"}}} -.\"{{{ Emacs Interactive Input Line Editing -.\"}}} -.\"{{{ Vi Interactive Input Line Editing -.\"}}} -.\"}}} -.\"{{{ Files -.SH FILES -~/.profile -.br -/etc/profile -.br -/etc/suid_profile -.\"}}} -.\"{{{ Notes -.SH NOTES -Sh is implemented as a runtime option of pdksh, with only those ksh features -whose syntax or semantics are incompatible with a traditional Bourne -shell disabled. Since this leaves some ksh extensions exposed, caution -should be used where backwards compatibility with traditional Bourne or -POSIX compliant shells is an issue. -.\"}}} -.\"{{{ Bugs -.SH BUGS -Any bugs in pdksh should be reported to pdksh@cs.mun.ca. Please -include the version of pdksh (echo $KSH_VERSION shows it), the machine, -operating system and compiler you are using and a description of how to -repeat the bug (a small shell script that demonstrates the bug is -best). The following, if relevant (if you are not sure, include them), -can also helpful: options you are using (both options.h options and set -\-o options) and a copy of your config.h (the file generated by the -configure script). New versions of pdksh can be obtained from -ftp.cs.mun.ca:pub/pdksh/. -.\"}}} -.\"{{{ Authors -.SH AUTHORS -This shell is based on the public domain 7th edition Bourne shell clone by -Charles Forsyth and parts of the BRL shell by Doug A.\& Gwyn, Doug Kingston, -Ron Natalie, Arnold Robbins, Lou Salkind and others. The first release -was created by Eric Gisin, and it was subsequently maintained by -John R.\& MacMillan (chance!john@sq.sq.com), and -Simon J.\& Gerraty (sjg@zen.void.oz.au). The current maintainer is -Michael Rendell (michael@cs.mun.ca). -The CONTRIBUTORS file in the source distribution contains a more complete -list of people and their part in the shell's development. -.\"}}} -.\"{{{ See also -.SH "SEE ALSO" -awk(1), -ksh(1), -csh(1), ed(1), getconf(1), getopt(1), sed(1), stty(1), vi(1), -dup(2), execve(2), getgid(2), getuid(2), open(2), pipe(2), wait(2), -getopt(3), rand(3), signal(3), system(3), -environ(5) -.PP -.IR "The KornShell Command and Programming Language" , -Morris Bolsky and David Korn, 1989, ISBN 0-13-516972-0. -.PP -.\" XXX ISBN missing -.IR "UNIX Shell Programming" , -Stephen G.\& Kochan, Patrick H.\& Wood, Hayden. -.PP -.IR "IEEE Standard for information Technology \- Portable Operating System Interface (POSIX) \- Part 2: Shell and Utilities" , -IEEE Inc, 1993, ISBN 1-55937-255-9. -.\"}}} diff --git a/bin/pdksh/sh.h b/bin/pdksh/sh.h deleted file mode 100644 index 588abd2c18e..00000000000 --- a/bin/pdksh/sh.h +++ /dev/null @@ -1,707 +0,0 @@ -/* $OpenBSD: sh.h,v 1.5 1997/01/02 09:34:10 downsj Exp $ */ - -/* - * Public Domain Bourne/Korn shell - */ - -/* $From: sh.h,v 1.2 1994/05/19 18:32:40 michael Exp michael $ */ - -#include "config.h" /* system and option configuration info */ - -#ifdef HAVE_PROTOTYPES -# define ARGS(args) args /* prototype declaration */ -#else -# define ARGS(args) () /* K&R declaration */ -#endif - - -/* Start of common headers */ - -#include <stdio.h> -#include <sys/types.h> -#include <setjmp.h> -#ifdef HAVE_STDDEF_H -# include <stddef.h> -#endif - -#ifdef HAVE_STDLIB_H -# include <stdlib.h> -#else -/* just a useful subset of what stdlib.h would have */ -extern char * getenv ARGS((const char *)); -extern void * malloc ARGS((size_t)); -extern int free ARGS((void *)); -extern int exit ARGS((int)); -extern int rand ARGS((void)); -extern void srand ARGS((unsigned int)); -extern int atoi ARGS((const char *)); -#endif /* HAVE_STDLIB_H */ - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#else -/* just a useful subset of what unistd.h would have */ -extern int access ARGS((const char *, int)); -extern int open ARGS((const char *, int, ...)); -extern int creat ARGS((const char *, mode_t)); -extern int read ARGS((int, char *, unsigned)); -extern int write ARGS((int, const char *, unsigned)); -extern off_t lseek ARGS((int, off_t, int)); -extern int close ARGS((int)); -extern int pipe ARGS((int [])); -extern int dup2 ARGS((int, int)); -extern int unlink ARGS((const char *)); -extern int fork ARGS((void)); -extern int execve ARGS((const char *, char * const[], char * const[])); -extern int chdir ARGS((const char *)); -extern int kill ARGS((pid_t, int)); -extern char *getcwd(); /* no ARGS here - differs on different machines */ -extern int geteuid ARGS((void)); -extern int readlink ARGS((const char *, char *, int)); -extern int getegid ARGS((void)); -extern int getpid ARGS((void)); -extern int getppid ARGS((void)); -extern unsigned int sleep ARGS((unsigned int)); -extern int isatty ARGS((int)); -# ifdef POSIX_PGRP -extern int getpgrp ARGS((void)); -extern int setpgid ARGS((pid_t, pid_t)); -# endif /* POSIX_PGRP */ -# ifdef BSD_PGRP -extern int getpgrp ARGS((pid_t)); -extern int setpgrp ARGS((pid_t, pid_t)); -# endif /* BSD_PGRP */ -# ifdef SYSV_PGRP -extern int getpgrp ARGS((void)); -extern int setpgrp ARGS((void)); -# endif /* SYSV_PGRP */ -#endif /* HAVE_UNISTD_H */ - -#ifdef HAVE_STRING_H -# include <string.h> -#else -# include <strings.h> -# define strchr index -# define strrchr rindex -#endif /* HAVE_STRING_H */ -#ifndef HAVE_STRSTR -char *strstr ARGS((const char *s, const char *p)); -#endif /* HAVE_STRSTR */ -#ifndef HAVE_STRCASECMP -int strcasecmp ARGS((const char *s1, const char *s2)); -int strncasecmp ARGS((const char *s1, const char *s2, int n)); -#endif /* HAVE_STRCASECMP */ - -#ifdef HAVE_MEMORY_H -# include <memory.h> -#endif -#ifndef HAVE_MEMSET -# define memcpy(d, s, n) bcopy(s, d, n) -# define memcmp(s1, s2, n) bcmp(s1, s2, n) -void *memset ARGS((void *d, int c, size_t n)); -#endif /* HAVE_MEMSET */ -#ifndef HAVE_MEMMOVE -# ifdef HAVE_BCOPY -# define memmove(d, s, n) bcopy(s, d, n) -# else -void *memmove ARGS((void *d, const void *s, size_t n)); -# endif -#endif /* HAVE_MEMMOVE */ - -#ifdef HAVE_PROTOTYPES -# include <stdarg.h> -# define SH_VA_START(va, argn) va_start(va, argn) -#else -# include <varargs.h> -# define SH_VA_START(va, argn) va_start(va) -#endif /* HAVE_PROTOTYPES */ - -#include <errno.h> -extern int errno; - -#ifdef HAVE_FCNTL_H -# include <fcntl.h> -#else -# include <sys/file.h> -#endif /* HAVE_FCNTL_H */ -#ifndef O_ACCMODE -# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) -#endif /* !O_ACCMODE */ - -#ifndef F_OK /* access() arguments */ -# define F_OK 0 -# define X_OK 1 -# define W_OK 2 -# define R_OK 4 -#endif /* !F_OK */ - -#ifndef SEEK_SET -# ifdef L_SET -# define SEEK_SET L_SET -# define SEEK_CUR L_INCR -# define SEEK_END L_XTND -# else /* L_SET */ -# define SEEK_SET 0 -# define SEEK_CUR 1 -# define SEEK_END 2 -# endif /* L_SET */ -#endif /* !SEEK_SET */ - -/* Some machines (eg, FreeBSD 1.1.5) define CLK_TCK in limits.h - * (ksh_limval.h assumes limits has been included, if available) - */ -#ifdef HAVE_LIMITS_H -# include <limits.h> -#endif /* HAVE_LIMITS_H */ - -#include <signal.h> -#ifdef NSIG -# define SIGNALS NSIG -#else -# ifdef _MINIX -# define SIGNALS (_NSIG+1) /* _NSIG is # of signals used, excluding 0. */ -# else -# ifdef _SIGMAX /* QNX */ -# define SIGNALS _SIGMAX -# else /* _SIGMAX */ -# define SIGNALS 32 -# endif /* _SIGMAX */ -# endif /* _MINIX */ -#endif /* NSIG */ -#ifndef SIGCHLD -# define SIGCHLD SIGCLD -#endif -/* struct sigaction.sa_flags is set to KSH_SA_FLAGS. Used to ensure - * system calls are interrupted - */ -#ifdef SA_INTERRUPT -# define KSH_SA_FLAGS SA_INTERRUPT -#else /* SA_INTERRUPT */ -# define KSH_SA_FLAGS 0 -#endif /* SA_INTERRUPT */ - -typedef RETSIGTYPE (*handler_t) ARGS((int)); /* signal handler */ - -#ifdef USE_FAKE_SIGACT -# include "sigact.h" /* use sjg's fake sigaction() */ -#endif - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif /* HAVE_PATHS_H */ -#ifdef _PATH_DEFPATH -# define DEFAULT__PATH _PATH_DEFPATH -#else /* _PATH_DEFPATH */ -# define DEFAULT__PATH DEFAULT_PATH -#endif /* _PATH_DEFPATH */ - -#ifndef offsetof -# define offsetof(type,id) ((size_t)&((type*)NULL)->id) -#endif - -#ifndef HAVE_KILLPG -# define killpg(p, s) kill(-(p), (s)) -#endif /* !HAVE_KILLPG */ - -/* Special cases for execve(2) */ -#ifdef OS2 -extern int ksh_execve(char *cmd, char **args, char **env); -#else /* OS2 */ -# if defined(OS_ISC) && defined(_POSIX_SOURCE) -/* Kludge for ISC 3.2 (and other versions?) so programs will run correctly. */ -# define ksh_execve(p, av, ev) do { \ - __setostype(0); \ - execve(p, av, ev); \ - __setostype(1); \ - } while (0) -# else /* OS_ISC && _POSIX */ -# define ksh_execve(p, av, ev) execve(p, av, ev) -# endif /* OS_ISC && _POSIX */ -#endif /* OS2 */ - -/* this is a hang-over from older versions of the os2 port */ -#define ksh_dupbase(fd, base) fcntl(fd, F_DUPFD, base) - -#ifdef HAVE_SIGSETJMP -# define ksh_sigsetjmp(env,sm) sigsetjmp((env), (sm)) -# define ksh_siglongjmp(env,v) siglongjmp((env), (v)) -# define ksh_jmp_buf sigjmp_buf -#else /* HAVE_SIGSETJMP */ -# ifdef HAVE__SETJMP -# define ksh_sigsetjmp(env,sm) _setjmp(env) -# define ksh_siglongjmp(env,v) _longjmp((env), (v)) -# else /* HAVE__SETJMP */ -# define ksh_sigsetjmp(env,sm) setjmp(env) -# define ksh_siglongjmp(env,v) longjmp((env), (v)) -# endif /* HAVE__SETJMP */ -# define ksh_jmp_buf jmp_buf -#endif /* HAVE_SIGSETJMP */ - -/* Find a integer type that is at least 32 bits (or die) - SIZEOF_* defined - * by autoconf (assumes an 8 bit byte, but I'm not concerned) - */ -#if SIZEOF_INT >= 4 -# define INT32 int -#else /* SIZEOF_INT */ -# if SIZEOF_LONG >= 4 -# define INT32 long -# else /* SIZEOF_LONG */ - #error cannot find 32 bit type... -# endif /* SIZEOF_LONG */ -#endif /* SIZEOF_INT */ - -/* end of common headers */ - -/* Stop gcc and lint from complaining about possibly uninitialized variables */ -#if defined(__GNUC__) || defined(lint) -# define UNINITIALIZED(var) var = 0 -#else -# define UNINITIALIZED(var) var -#endif /* GNUC || lint */ - -/* some useful #defines */ -#ifdef EXTERN -# define I__(i) = i -#else -# define I__(i) -# define EXTERN extern -# define EXTERN_DEFINED -#endif - -#ifndef EXECSHELL -/* shell to exec scripts (see also $SHELL initialization in main.c) */ -# ifdef OS2 -# define EXECSHELL "c:\\os2\\cmd.exe" -# define EXECSHELL_STR "OS2_SHELL" -# else /* OS2 */ -# define EXECSHELL "/bin/sh" -# define EXECSHELL_STR "EXECSHELL" -# endif /* OS2 */ -#endif - -/* ISABSPATH() means path is fully and completely specified, - * ISROOTEDPATH() means a .. as the first component is a no-op, - * ISRELPATH() means $PWD can be tacked on to get an absolute path. - * - * OS Path ISABSPATH ISROOTEDPATH ISRELPATH - * unix /foo yes yes no - * unix foo no no yes - * unix ../foo no no yes - * os2 a:/foo yes yes no - * os2 a:foo no no no - * os2 /foo no yes no - * os2 foo no no yes - * os2 ../foo no no yes - */ -#ifdef OS2 -# define PATHSEP ';' -# define DIRSEP '/' /* even though \ is native */ -# define DIRSEPSTR "\\" -# define ISDIRSEP(c) ((c) == '\\' || (c) == '/') -# define ISABSPATH(s) (((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2]))) -# define ISROOTEDPATH(s) (ISDIRSEP((s)[0]) || ISABSPATH(s)) -# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0]))) -# define FILECHCONV(c) (isascii(c) && isupper(c) ? tolower(c) : c) -# define FILECMP(s1, s2) stricmp(s1, s2) -# define FILENCMP(s1, s2, n) strnicmp(s1, s2, n) -extern char *ksh_strchr_dirsep(const char *path); -extern char *ksh_strrchr_dirsep(const char *path); -# define chdir _chdir2 -# define getcwd _getcwd2 -#else -# define PATHSEP ':' -# define DIRSEP '/' -# define DIRSEPSTR "/" -# define ISDIRSEP(c) ((c) == '/') -# define ISABSPATH(s) ISDIRSEP((s)[0]) -# define ISROOTEDPATH(s) ISABSPATH(s) -# define ISRELPATH(s) (!ISABSPATH(s)) -# define FILECHCONV(c) c -# define FILECMP(s1, s2) strcmp(s1, s2) -# define FILENCMP(s1, s2, n) strncmp(s1, s2, n) -# define ksh_strchr_dirsep(p) strchr(p, DIRSEP) -# define ksh_strrchr_dirsep(p) strrchr(p, DIRSEP) -#endif - -typedef int bool_t; -#define FALSE 0 -#define TRUE 1 - -#define NELEM(a) (sizeof(a) / sizeof((a)[0])) -#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 32 /* Number of user-accessible files */ -#define FDBASE 10 /* First file usable by Shell */ - -/* you're not going to run setuid shell scripts, are you? */ -#define eaccess(path, mode) access(path, mode) - -/* Make MAGIC a char that might be printed to make bugs more obvious, but - * not a char that is used often. Also, can't use the high bit as it causes - * portability problems (calling strchr(x, 0x80|'x') is error prone). - */ -#define MAGIC (7)/* prefix for *?[!{,} during expand */ -#define ISMAGIC(c) ((unsigned char)(c) == MAGIC) -#define NOT '!' /* might use ^ (ie, [!...] vs [^..]) */ - -#define LINE 1024 /* input line size */ -#define PATH 1024 /* pathname size (todo: PATH_MAX/pathconf()) */ -#define ARRAYMAX 1023 /* max array index */ - -EXTERN const char *kshname; /* $0 */ -EXTERN pid_t kshpid; /* $$, shell pid */ -EXTERN pid_t procpid; /* pid of executing process */ -EXTERN int exstat; /* exit status */ -EXTERN int subst_exstat; /* exit status of last $(..)/`..` */ -EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */ - - -/* - * Area-based allocation built on malloc/free - */ - -typedef struct Area { - struct Block *freelist; /* free list */ -} Area; - -EXTERN Area aperm; /* permanent object space */ -#define APERM &aperm -#define ATEMP &e->area - -#ifdef MEM_DEBUG -# include "chmem.h" /* a debugging front end for malloc et. al. */ -#endif /* MEM_DEBUG */ - - -/* - * parsing & execution environment - */ -EXTERN struct env { - short type; /* enviroment type - see below */ - short flags; /* EF_* */ - Area area; /* temporary allocation area */ - struct block *loc; /* local variables and functions */ - short *savefd; /* original redirected fd's */ - struct env *oenv; /* link to previous enviroment */ - ksh_jmp_buf jbuf; /* long jump back to env creator */ - struct temp *temps; /* temp files */ -} *e; - -/* struct env.type values */ -#define E_NONE 0 /* dummy enviroment */ -#define E_PARSE 1 /* parsing command # */ -#define E_FUNC 2 /* executing function # */ -#define E_INCL 3 /* including a file via . # */ -#define E_EXEC 4 /* executing command tree */ -#define E_LOOP 5 /* executing for/while # */ -#define E_ERRH 6 /* general error handler # */ -/* # indicates env has valid jbuf (see unwind()) */ - -/* struct env.flag values */ -#define EF_FUNC_PARSE BIT(0) /* function being parsed */ -#define EF_BRKCONT_PASS BIT(1) /* set if E_LOOP must pass break/continue on */ - -/* Do breaks/continues stop at env type e? */ -#define STOP_BRKCONT(t) ((t) == E_NONE || (t) == E_PARSE \ - || (t) == E_FUNC || (t) == E_INCL) -/* Do returns stop at env type e? */ -#define STOP_RETURN(t) ((t) == E_FUNC || (t) == E_INCL) - -/* values for ksh_siglongjmp(e->jbuf, 0) */ -#define LRETURN 1 /* return statement */ -#define LEXIT 2 /* exit statement */ -#define LERROR 3 /* errorf() called */ -#define LLEAVE 4 /* untrappable exit/error */ -#define LINTR 5 /* ^C noticed */ -#define LBREAK 6 /* break statement */ -#define LCONTIN 7 /* continue statement */ -#define LSHELL 8 /* return to interactive shell() */ -#define LAEXPR 9 /* error in arithmetic expression */ - - -/* option processing */ -#define OF_CMDLINE 0x01 /* command line */ -#define OF_SET 0x02 /* set builtin */ -#define OF_SPECIAL 0x04 /* a special variable changing */ -#define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL) - -struct option { - const char *name; /* long name of option */ - char c; /* character flag (if any) */ - short flags; /* OF_* */ -}; -extern const struct option options[]; - -/* - * flags (the order of these enums MUST match the order in misc.c(options[])) - */ -enum sh_flag { - FEXPORT = 0, /* -a: export all */ -#ifdef BRACE_EXPAND - FBRACEEXPAND, /* enable {} globbing */ -#endif - FBGNICE, /* bgnice */ - FCOMMAND, /* -c: (invocation) execute specified command */ -#ifdef EMACS - FEMACS, /* emacs command editing */ -#endif - FERREXIT, /* -e: quit on error */ -#ifdef EMACS - FGMACS, /* gmacs command editing */ -#endif - FIGNOREEOF, /* eof does not exit */ - FTALKING, /* -i: interactive */ - FKEYWORD, /* -k: name=value anywere */ - FLOGIN, /* -l: a login shell */ - FMARKDIRS, /* mark dirs with / in file name completion */ - FMONITOR, /* -m: job control monitoring */ - FNOCLOBBER, /* -C: don't overwrite existing files */ - FNOEXEC, /* -n: don't execute any commands */ - FNOGLOB, /* -f: don't do file globbing */ - FNOHUP, /* -H: don't kill running jobs when login shell exits */ - FNOLOG, /* don't save functions in history (ignored) */ -#ifdef JOBS - FNOTIFY, /* -b: asynchronous job completion notification */ -#endif - FNOUNSET, /* -u: using an unset var is an error */ - FPHYSICAL, /* -o physical: don't do logical cd's/pwd's */ - FPOSIX, /* -o posix: be posixly correct */ - FPRIVILEGED, /* -p: use suid_profile */ - FRESTRICTED, /* -r: restricted shell */ - FSH, /* -o sh: favor sh behavour */ - FSTDIN, /* -s: (invocation) parse stdin */ - FTRACKALL, /* -h: create tracked aliases for all commands */ - FVERBOSE, /* -v: echo input */ -#ifdef VI - FVI, /* vi command editing */ - 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) */ -}; - -#define Flag(f) (shell_flags[(int) (f)]) - -EXTERN char shell_flags [FNFLAGS]; - -EXTERN char null [] I__(""); /* null value for variable */ -EXTERN char space [] I__(" "); -EXTERN char newline [] I__("\n"); -EXTERN char slash [] I__("/"); - -/* temp/here files. the file is removed when the struct is freed */ -struct temp { - struct temp *next; - struct shf *shf; - int pid; /* pid of process parsed here-doc */ - char *name; -}; - -/* here documents in functions are treated specially (the get removed when - * shell exis) */ -EXTERN struct temp *func_heredocs; - -/* - * stdio and our IO routines - */ - -#define shl_spare (&shf_iob[0]) /* for c_read()/c_print() */ -#define shl_stdout (&shf_iob[1]) -#define shl_out (&shf_iob[2]) -EXTERN int shl_stdout_ok; - -/* - * trap handlers - */ -typedef struct trap { - int signal; /* signal number */ - const char *name; /* short name */ - const char *mess; /* descriptive name */ - char *trap; /* trap command */ - 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 */ -#define TF_SHELL_USES BIT(0) /* shell uses signal, user can't change */ -#define TF_USER_SET BIT(1) /* user has (tried to) set trap */ -#define TF_ORIG_IGN BIT(2) /* original action was SIG_IGN */ -#define TF_ORIG_DFL BIT(3) /* original action was SIG_DFL */ -#define TF_EXEC_IGN BIT(4) /* restore SIG_IGN just before exec */ -#define TF_EXEC_DFL BIT(5) /* restore SIG_DFL just before exec */ -#define TF_DFL_INTR BIT(6) /* when received, default action is LINTR */ -#define TF_TTY_INTR BIT(7) /* tty generated signal (see j_waitj) */ -#define TF_CHANGED BIT(8) /* used by runtrap() to detect trap changes */ -#define TF_FATAL BIT(9) /* causes termination if not trapped */ - -/* values for setsig()/setexecsig() flags argument */ -#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 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 */ - -EXTERN int volatile trap; /* traps pending? */ -EXTERN int volatile intrsig; /* pending trap interrupts executing command */ -EXTERN int volatile fatal_trap;/* received a fatal signal */ -#ifndef FROM_TRAP_C -/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */ -extern Trap sigtraps[SIGNALS+1]; -#endif /* !FROM_TRAP_C */ - - -#ifdef KSH -/* - * TMOUT support - */ -/* values for ksh_tmout_state */ -enum tmout_enum { - TMOUT_EXECUTING = 0, /* executing commands */ - TMOUT_READING, /* waiting for input */ - TMOUT_LEAVING /* have timed out */ - }; -EXTERN unsigned int ksh_tmout; -EXTERN enum tmout_enum ksh_tmout_state I__(TMOUT_EXECUTING); -#endif /* KSH */ - - -/* For "You have stopped jobs" message */ -EXTERN int really_exit; - - -/* - * fast character classes - */ -#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) -#define digit(c) ctype(c, C_DIGIT) -#define letnum(c) ctype(c, C_ALPHA|C_DIGIT) - -EXTERN int ifs0 I__(' '); /* for "$*" */ - - -/* Argument parsing for built-in commands and getopts command */ - -/* Values for Getopt.flags */ -#define GF_ERROR BIT(0) /* call errorf() if there is an error */ -#define GF_PLUSOPT BIT(1) /* allow +c as an option */ -#define GF_NONAME BIT(2) /* don't print argv[0] in errors */ - -/* Values for Getopt.info */ -#define GI_MINUS BIT(0) /* an option started with -... */ -#define GI_PLUS BIT(1) /* an option started with +... */ -#define GI_MINUSMINUS BIT(2) /* arguments were ended with -- */ - -typedef struct { - int optind; - char *optarg; - int flags; /* see GF_* */ - int info; /* see GI_* */ - unsigned int p; /* 0 or index into argv[optind - 1] */ - char buf[2]; /* for bad option OPTARG value */ -} Getopt; - -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 */ - 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 Tflag builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */ - -/* current working directory, and size of memory allocated for same */ -EXTERN char *current_wd; -EXTERN int current_wd_size; - -#ifdef EDIT -/* Minimium required space to work with on a line - if the prompt leaves less - * space than this on a line, the prompt is truncated. - */ -# define MIN_EDIT_SPACE 7 -/* Minimium allowed value for x_cols: 2 for prompt, 3 for " < " at end of line - */ -# define MIN_COLS (2 + MIN_EDIT_SPACE + 3) -EXTERN int x_cols I__(80); /* tty columns */ -#else -# define x_cols 80 /* for pr_menu(exec.c) */ -#endif - - -/* These to avoid bracket matching problems */ -#define OPAREN '(' -#define CPAREN ')' -#define OBRACK '[' -#define CBRACK ']' -#define OBRACE '{' -#define CBRACE '}' - -/* Determine the location of the system (common) profile */ -#ifndef KSH_SYSTEM_PROFILE -# ifdef __NeXT -# define KSH_SYSTEM_PROFILE "/etc/profile.std" -# else /* __NeXT */ -# define KSH_SYSTEM_PROFILE "/etc/profile" -# endif /* __NeXT */ -#endif /* KSH_SYSTEM_PROFILE */ - -#include "shf.h" -#include "table.h" -#include "tree.h" -#include "expand.h" -#include "lex.h" -#include "proto.h" - -/* be sure not to interfere with anyone else's idea about EXTERN */ -#ifdef EXTERN_DEFINED -# undef EXTERN_DEFINED -# undef EXTERN -#endif -#undef I__ diff --git a/bin/pdksh/shf.c b/bin/pdksh/shf.c deleted file mode 100644 index 78266aa9b26..00000000000 --- a/bin/pdksh/shf.c +++ /dev/null @@ -1,1271 +0,0 @@ -/* $OpenBSD: shf.c,v 1.3 1997/06/19 13:58:46 kstailey Exp $ */ - -/* - * Shell file I/O routines - */ - -#include "sh.h" -#include "ksh_stat.h" -#include "ksh_limval.h" - - -/* flags to shf_emptybuf() */ -#define EB_READSW 0x01 /* about to switch to reading */ -#define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ - -/* - * Replacement stdio routines. Stdio is too flakey on too many machines - * to be useful when you have multiple processes using the same underlying - * file descriptors. - */ - -static int shf_fillbuf ARGS((struct shf *shf)); -static int shf_emptybuf ARGS((struct shf *shf, int flags)); - -/* Open a file. First three args are for open(), last arg is flags for - * this package. Returns NULL if file could not be opened, or if a dup - * fails. - */ -struct shf * -shf_open(name, oflags, mode, sflags) - const char *name; - int oflags; - int mode; - int sflags; -{ - int fd; - - fd = open(name, oflags, mode); - if (fd < 0) - return NULL; - if ((sflags & SHF_MAPHI) && fd < FDBASE) { - int nfd; - - nfd = ksh_dupbase(fd, FDBASE); - close(fd); - if (nfd < 0) - return NULL; - fd = nfd; - } - sflags &= ~SHF_ACCMODE; - sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD - : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR - : SHF_RDWR); - - return shf_fdopen(fd, sflags, (struct shf *) 0); -} - -/* Set up the shf structure for a file descriptor. Doesn't fail. */ -struct shf * -shf_fdopen(fd, sflags, shf) - int fd; - int sflags; - struct shf *shf; -{ - int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; - - /* use fcntl() to figure out correct read/write flags */ - if (sflags & SHF_GETFL) { - int flags = fcntl(fd, F_GETFL, 0); - - if (flags < 0) - /* will get an error on first read/write */ - sflags |= SHF_RDWR; - else - switch (flags & O_ACCMODE) { - case O_RDONLY: sflags |= SHF_RD; break; - case O_WRONLY: sflags |= SHF_WR; break; - case O_RDWR: sflags |= SHF_RDWR; break; - } - } - - if (!(sflags & (SHF_RD | SHF_WR))) - internal_errorf(1, "shf_fdopen: missing read/write"); - - if (shf) { - if (bsize) { - shf->buf = (unsigned char *) alloc(bsize, ATEMP); - sflags |= SHF_ALLOCB; - } else - shf->buf = (unsigned char *) 0; - } else { - shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); - shf->buf = (unsigned char *) &shf[1]; - sflags |= SHF_ALLOCS; - } - shf->areap = ATEMP; - shf->fd = fd; - shf->rp = shf->wp = shf->buf; - shf->rnleft = 0; - shf->rbsize = bsize; - shf->wnleft = 0; /* force call to shf_emptybuf() */ - shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; - shf->flags = sflags; - shf->errno_ = 0; - shf->bsize = bsize; - if (sflags & SHF_CLEXEC) - fd_clexec(fd); - return shf; -} - -/* Set up an existing shf (and buffer) to use the given fd */ -struct shf * -shf_reopen(fd, sflags, shf) - int fd; - int sflags; - struct shf *shf; -{ - int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; - - /* use fcntl() to figure out correct read/write flags */ - if (sflags & SHF_GETFL) { - int flags = fcntl(fd, F_GETFL, 0); - - if (flags < 0) - /* will get an error on first read/write */ - sflags |= SHF_RDWR; - else - switch (flags & O_ACCMODE) { - case O_RDONLY: sflags |= SHF_RD; break; - case O_WRONLY: sflags |= SHF_WR; break; - case O_RDWR: sflags |= SHF_RDWR; break; - } - } - - if (!(sflags & (SHF_RD | SHF_WR))) - internal_errorf(1, "shf_reopen: missing read/write"); - if (!shf || !shf->buf || shf->bsize < bsize) - internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); - - /* assumes shf->buf and shf->bsize already set up */ - shf->fd = fd; - shf->rp = shf->wp = shf->buf; - shf->rnleft = 0; - shf->rbsize = bsize; - shf->wnleft = 0; /* force call to shf_emptybuf() */ - shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; - shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; - shf->errno_ = 0; - if (sflags & SHF_CLEXEC) - fd_clexec(fd); - return shf; -} - -/* Open a string for reading or writing. If reading, bsize is the number - * of bytes that can be read. If writing, bsize is the maximum number of - * bytes that can be written. If shf is not null, it is filled in and - * returned, if it is null, shf is allocated. If writing and buf is null - * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is - * used for the initial size). Doesn't fail. - * When writing, a byte is reserved for a trailing null - see shf_sclose(). - */ -struct shf * -shf_sopen(buf, bsize, sflags, shf) - char *buf; - int bsize; - int sflags; - struct shf *shf; -{ - /* can't have a read+write string */ - if (!(sflags & (SHF_RD | SHF_WR)) - || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR)) - internal_errorf(1, "shf_sopen: flags 0x%x", sflags); - - if (!shf) { - shf = (struct shf *) alloc(sizeof(struct shf), ATEMP); - sflags |= SHF_ALLOCS; - } - shf->areap = ATEMP; - if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { - if (bsize <= 0) - bsize = 64; - sflags |= SHF_ALLOCB; - buf = alloc(bsize, shf->areap); - } - shf->fd = -1; - shf->buf = shf->rp = shf->wp = (unsigned char *) buf; - shf->rnleft = bsize; - shf->rbsize = bsize; - shf->wnleft = bsize - 1; /* space for a '\0' */ - shf->wbsize = bsize; - shf->flags = sflags | SHF_STRING; - shf->errno_ = 0; - shf->bsize = bsize; - - return shf; -} - -/* Flush and close file descriptor, free the shf structure */ -int -shf_close(shf) - struct shf *shf; -{ - int ret = 0; - - if (shf->fd >= 0) { - ret = shf_flush(shf); - if (close(shf->fd) < 0) - ret = EOF; - } - if (shf->flags & SHF_ALLOCS) - afree(shf, shf->areap); - else if (shf->flags & SHF_ALLOCB) - afree(shf->buf, shf->areap); - - return ret; -} - -/* Flush and close file descriptor, don't free file structure */ -int -shf_fdclose(shf) - struct shf *shf; -{ - int ret = 0; - - if (shf->fd >= 0) { - ret = shf_flush(shf); - if (close(shf->fd) < 0) - ret = EOF; - shf->rnleft = 0; - shf->rp = shf->buf; - shf->wnleft = 0; - shf->fd = -1; - } - - return ret; -} - -/* Close a string - if it was opened for writing, it is null terminated; - * returns a pointer to the string and frees shf if it was allocated - * (does not free string if it was allocated). - */ -char * -shf_sclose(shf) - struct shf *shf; -{ - unsigned char *s = shf->buf; - - /* null terminate */ - if (shf->flags & SHF_WR) { - shf->wnleft++; - shf_putc('\0', shf); - } - if (shf->flags & SHF_ALLOCS) - afree(shf, shf->areap); - return (char *) s; -} - -/* Flush and free file structure, don't close file descriptor */ -int -shf_finish(shf) - struct shf *shf; -{ - int ret = 0; - - if (shf->fd >= 0) - ret = shf_flush(shf); - if (shf->flags & SHF_ALLOCS) - afree(shf, shf->areap); - else if (shf->flags & SHF_ALLOCB) - afree(shf->buf, shf->areap); - - return ret; -} - -/* Un-read what has been read but not examined, or write what has been - * buffered. Returns 0 for success, EOF for (write) error. - */ -int -shf_flush(shf) - struct shf *shf; -{ - if (shf->flags & SHF_STRING) - return (shf->flags & SHF_WR) ? EOF : 0; - - if (shf->fd < 0) - internal_errorf(1, "shf_flush: no fd"); - - if (shf->flags & SHF_ERROR) { - errno = shf->errno_; - return EOF; - } - - if (shf->flags & SHF_READING) { - shf->flags &= ~(SHF_EOF | SHF_READING); - if (shf->rnleft > 0) { - lseek(shf->fd, (off_t) -shf->rnleft, 1); - shf->rnleft = 0; - shf->rp = shf->buf; - } - return 0; - } else if (shf->flags & SHF_WRITING) - return shf_emptybuf(shf, 0); - - return 0; -} - -/* Write out any buffered data. If currently reading, flushes the read - * buffer. Returns 0 for success, EOF for (write) error. - */ -static int -shf_emptybuf(shf, flags) - struct shf *shf; - int flags; -{ - int ret = 0; - - if (!(shf->flags & SHF_STRING) && shf->fd < 0) - internal_errorf(1, "shf_emptybuf: no fd"); - - if (shf->flags & SHF_ERROR) { - errno = shf->errno_; - return EOF; - } - - if (shf->flags & SHF_READING) { - if (flags & EB_READSW) /* doesn't happen */ - return 0; - ret = shf_flush(shf); - shf->flags &= ~SHF_READING; - } - if (shf->flags & SHF_STRING) { - unsigned char *nbuf; - - /* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB - * is set... (changing the shf pointer could cause problems) - */ - if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) - || !(shf->flags & SHF_ALLOCB)) - return EOF; - /* allocate more space for buffer */ - nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2, - shf->areap); - shf->rp = nbuf + (shf->rp - shf->buf); - shf->wp = nbuf + (shf->wp - shf->buf); - shf->rbsize += shf->wbsize; - shf->wbsize += shf->wbsize; - shf->wnleft += shf->wbsize; - shf->wbsize *= 2; - shf->buf = nbuf; - } else { - if (shf->flags & SHF_WRITING) { - int ntowrite = shf->wp - shf->buf; - unsigned char *buf = shf->buf; - int n; - - while (ntowrite > 0) { - n = write(shf->fd, buf, ntowrite); - if (n < 0) { - if (errno == EINTR - && !(shf->flags & SHF_INTERRUPT)) - continue; - shf->flags |= SHF_ERROR; - shf->errno_ = errno; - shf->wnleft = 0; - if (buf != shf->buf) { - /* allow a second flush - * to work */ - memmove(shf->buf, buf, - ntowrite); - shf->wp = shf->buf + ntowrite; - } - return EOF; - } - buf += n; - ntowrite -= n; - } - if (flags & EB_READSW) { - shf->wp = shf->buf; - shf->wnleft = 0; - shf->flags &= ~SHF_WRITING; - return 0; - } - } - shf->wp = shf->buf; - shf->wnleft = shf->wbsize; - } - shf->flags |= SHF_WRITING; - - return ret; -} - -/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ -static int -shf_fillbuf(shf) - struct shf *shf; -{ - if (shf->flags & SHF_STRING) - return 0; - - if (shf->fd < 0) - internal_errorf(1, "shf_fillbuf: no fd"); - - if (shf->flags & (SHF_EOF | SHF_ERROR)) { - if (shf->flags & SHF_ERROR) - errno = shf->errno_; - return EOF; - } - - if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) - return EOF; - - shf->flags |= SHF_READING; - - shf->rp = shf->buf; - while (1) { - shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, - shf->rbsize); - if (shf->rnleft < 0 && errno == EINTR - && !(shf->flags & SHF_INTERRUPT)) - continue; - break; - } - if (shf->rnleft <= 0) { - if (shf->rnleft < 0) { - shf->flags |= SHF_ERROR; - shf->errno_ = errno; - shf->rnleft = 0; - shf->rp = shf->buf; - return EOF; - } - shf->flags |= SHF_EOF; - } - return 0; -} - -/* Seek to a new position in the file. If writing, flushes the buffer - * first. If reading, optimizes small relative seeks that stay inside the - * buffer. Returns 0 for success, EOF otherwise. - */ -int -shf_seek(shf, where, from) - struct shf *shf; - off_t where; - int from; -{ - if (shf->fd < 0) { - errno = EINVAL; - return EOF; - } - - if (shf->flags & SHF_ERROR) { - errno = shf->errno_; - return EOF; - } - - if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) - return EOF; - - if (shf->flags & SHF_READING) { - if (from == SEEK_CUR && - (where < 0 ? - -where >= shf->rbsize - shf->rnleft : - where < shf->rnleft)) { - shf->rnleft -= where; - shf->rp += where; - return 0; - } - shf->rnleft = 0; - shf->rp = shf->buf; - } - - shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING); - - if (lseek(shf->fd, where, from) < 0) { - shf->errno_ = errno; - shf->flags |= SHF_ERROR; - return EOF; - } - - return 0; -} - - -/* Read a buffer from shf. Returns the number of bytes read into buf, - * if no bytes were read, returns 0 if end of file was seen, EOF if - * a read error occurred. - */ -int -shf_read(buf, bsize, shf) - char *buf; - int bsize; - struct shf *shf; -{ - int orig_bsize = bsize; - int ncopy; - - if (!(shf->flags & SHF_RD)) - internal_errorf(1, "shf_read: flags %x", shf->flags); - - if (bsize <= 0) - internal_errorf(1, "shf_read: bsize %d", bsize); - - while (bsize > 0) { - if (shf->rnleft == 0 - && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) - break; - ncopy = shf->rnleft; - if (ncopy > bsize) - ncopy = bsize; - memcpy(buf, shf->rp, ncopy); - buf += ncopy; - bsize -= ncopy; - shf->rp += ncopy; - shf->rnleft -= ncopy; - } - /* Note: fread(3S) returns 0 for errors - this doesn't */ - return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) - : orig_bsize - bsize; -} - -/* Read up to a newline or EOF. The newline is put in buf; buf is always - * null terminated. Returns NULL on read error or if nothing was read before - * end of file, returns a pointer to the null byte in buf otherwise. - */ -char * -shf_getse(buf, bsize, shf) - char *buf; - int bsize; - struct shf *shf; -{ - unsigned char *end; - int ncopy; - char *orig_buf = buf; - - if (!(shf->flags & SHF_RD)) - internal_errorf(1, "shf_getse: flags %x", shf->flags); - - if (bsize <= 0) - return (char *) 0; - - --bsize; /* save room for null */ - do { - if (shf->rnleft == 0) { - if (shf_fillbuf(shf) == EOF) - return NULL; - if (shf->rnleft == 0) { - *buf = '\0'; - return buf == orig_buf ? NULL : buf; - } - } - end = (unsigned char *) memchr((char *) shf->rp, '\n', - shf->rnleft); - ncopy = end ? end - shf->rp + 1 : shf->rnleft; - if (ncopy > bsize) - ncopy = bsize; - memcpy(buf, (char *) shf->rp, ncopy); - shf->rp += ncopy; - shf->rnleft -= ncopy; - buf += ncopy; - bsize -= ncopy; - } while (!end && bsize); - *buf = '\0'; - return buf; -} - -/* Returns the char read. Returns EOF for error and end of file. */ -int -shf_getchar(shf) - struct shf *shf; -{ - if (!(shf->flags & SHF_RD)) - internal_errorf(1, "shf_getchar: flags %x", shf->flags); - - if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) - return EOF; - --shf->rnleft; - return *shf->rp++; -} - -/* Put a character back in the input stream. Returns the character if - * successful, EOF if there is no room. - */ -int -shf_ungetc(c, shf) - int c; - struct shf *shf; -{ - if (!(shf->flags & SHF_RD)) - internal_errorf(1, "shf_ungetc: flags %x", shf->flags); - - if ((shf->flags & SHF_ERROR) || c == EOF - || (shf->rp == shf->buf && shf->rnleft)) - return EOF; - - if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) - return EOF; - - if (shf->rp == shf->buf) - shf->rp = shf->buf + shf->rbsize; - if (shf->flags & SHF_STRING) { - /* Can unget what was read, but not something different - we - * don't want to modify a string. - */ - if (shf->rp[-1] != c) - return EOF; - shf->flags &= ~SHF_EOF; - shf->rp--; - shf->rnleft++; - return c; - } - shf->flags &= ~SHF_EOF; - *--(shf->rp) = c; - shf->rnleft++; - return c; -} - -/* Write a character. Returns the character if successful, EOF if - * the char could not be written. - */ -int -shf_putchar(c, shf) - int c; - struct shf *shf; -{ - if (!(shf->flags & SHF_WR)) - internal_errorf(1, "shf_putchar: flags %x", shf->flags); - - if (c == EOF) - return EOF; - - if (shf->flags & SHF_UNBUF) { - char cc = c; - int n; - - if (shf->fd < 0) - internal_errorf(1, "shf_putchar: no fd"); - if (shf->flags & SHF_ERROR) { - errno = shf->errno_; - return EOF; - } - while ((n = write(shf->fd, &cc, 1)) != 1) - if (n < 0) { - if (errno == EINTR - && !(shf->flags & SHF_INTERRUPT)) - continue; - shf->flags |= SHF_ERROR; - shf->errno_ = errno; - return EOF; - } - } else { - /* Flush deals with strings and sticky errors */ - if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) - return EOF; - shf->wnleft--; - *shf->wp++ = c; - } - - return c; -} - -/* Write a string. Returns the length of the string if successful, EOF if - * the string could not be written. - */ -int -shf_puts(s, shf) - const char *s; - struct shf *shf; -{ - if (!s) - return EOF; - - return shf_write(s, strlen(s), shf); -} - -/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ -int -shf_write(buf, nbytes, shf) - const char *buf; - int nbytes; - struct shf *shf; -{ - int orig_nbytes = nbytes; - int n; - int ncopy; - - if (!(shf->flags & SHF_WR)) - internal_errorf(1, "shf_write: flags %x", shf->flags); - - if (nbytes < 0) - internal_errorf(1, "shf_write: nbytes %d", nbytes); - - if ((ncopy = shf->wnleft)) { - if (ncopy > nbytes) - ncopy = nbytes; - memcpy(shf->wp, buf, ncopy); - nbytes -= ncopy; - buf += ncopy; - shf->wp += ncopy; - shf->wnleft -= ncopy; - } - if (nbytes > 0) { - /* Flush deals with strings and sticky errors */ - if (shf_emptybuf(shf, EB_GROW) == EOF) - return EOF; - if (nbytes > shf->wbsize) { - ncopy = nbytes; - if (shf->wbsize) - ncopy -= nbytes % shf->wbsize; - nbytes -= ncopy; - while (ncopy > 0) { - n = write(shf->fd, buf, ncopy); - if (n < 0) { - if (errno == EINTR - && !(shf->flags & SHF_INTERRUPT)) - continue; - shf->flags |= SHF_ERROR; - shf->errno_ = errno; - shf->wnleft = 0; - /* Note: fwrite(3S) returns 0 for - * errors - this doesn't */ - return EOF; - } - buf += n; - ncopy -= n; - } - } - if (nbytes > 0) { - memcpy(shf->wp, buf, nbytes); - shf->wp += nbytes; - shf->wnleft -= nbytes; - } - } - - return orig_nbytes; -} - -int -#ifdef HAVE_PROTOTYPES -shf_fprintf(struct shf *shf, const char *fmt, ...) -#else -shf_fprintf(shf, fmt, va_alist) - struct shf *shf; - const char *fmt; - va_dcl -#endif -{ - va_list args; - int n; - - SH_VA_START(args, fmt); - n = shf_vfprintf(shf, fmt, args); - va_end(args); - - return n; -} - -int -#ifdef HAVE_PROTOTYPES -shf_snprintf(char *buf, int bsize, const char *fmt, ...) -#else -shf_snprintf(buf, bsize, fmt, va_alist) - char *buf; - int bsize; - const char *fmt; - va_dcl -#endif -{ - struct shf shf; - va_list args; - int n; - - if (!buf || bsize <= 0) - internal_errorf(1, "shf_snprintf: buf %lx, bsize %d", - (long) buf, bsize); - - shf_sopen(buf, bsize, SHF_WR, &shf); - SH_VA_START(args, fmt); - n = shf_vfprintf(&shf, fmt, args); - va_end(args); - shf_sclose(&shf); /* null terminates */ - return n; -} - -char * -#ifdef HAVE_PROTOTYPES -shf_smprintf(const char *fmt, ...) -#else -shf_smprintf(fmt, va_alist) - char *fmt; - va_dcl -#endif -{ - struct shf shf; - va_list args; - - shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf); - SH_VA_START(args, fmt); - shf_vfprintf(&shf, fmt, args); - va_end(args); - return shf_sclose(&shf); /* null terminates */ -} - -#undef FP /* if you want floating point stuff */ - -#define BUF_SIZE 128 -#define FPBUF_SIZE (DMAXEXP+16)/* this must be > - * MAX(DMAXEXP, log10(pow(2, DSIGNIF))) - * + ceil(log10(DMAXEXP)) + 8 (I think). - * Since this is hard to express as a - * constant, just use a large buffer. - */ - -/* - * What kinda of machine we on? Hopefully the C compiler will optimize - * this out... - * - * For shorts, we want sign extend for %d but not for %[oxu] - on 16 bit - * machines it don't matter. Assmumes C compiler has converted shorts to - * ints before pushing them. - */ -#define POP_INT(f, s, a) (((f) & FL_LONG) ? \ - va_arg((a), unsigned long) \ - : \ - (sizeof(int) < sizeof(long) ? \ - ((s) ? \ - (long) va_arg((a), int) \ - : \ - va_arg((a), unsigned)) \ - : \ - va_arg((a), unsigned))) - -#define ABIGNUM 32000 /* big numer that will fit in a short */ -#define LOG2_10 3.321928094887362347870319429 /* log base 2 of 10 */ - -#define FL_HASH 0x001 /* `#' seen */ -#define FL_PLUS 0x002 /* `+' seen */ -#define FL_RIGHT 0x004 /* `-' seen */ -#define FL_BLANK 0x008 /* ` ' seen */ -#define FL_SHORT 0x010 /* `h' seen */ -#define FL_LONG 0x020 /* `l' seen */ -#define FL_ZERO 0x040 /* `0' seen */ -#define FL_DOT 0x080 /* '.' seen */ -#define FL_UPPER 0x100 /* format character was uppercase */ -#define FL_NUMBER 0x200 /* a number was formated %[douxefg] */ - - -#ifdef FP -#include <math.h> - -static double -my_ceil(d) - double d; -{ - double i; - - return d - modf(d, &i) + (d < 0 ? -1 : 1); -} -#endif /* FP */ - -int -shf_vfprintf(shf, fmt, args) - struct shf *shf; - const char *fmt; - va_list args; -{ - char c, *s; - int UNINITIALIZED(tmp); - int field, precision; - int len; - int flags; - unsigned long lnum; - /* %#o produces the longest output */ - char numbuf[(BITS(long) + 2) / 3 + 1]; - /* this stuff for dealing with the buffer */ - int nwritten = 0; -#ifdef FP - /* should be in <math.h> - * extern double frexp(); - */ - extern char *ecvt(); - - double fpnum; - int expo, decpt; - char style; - char fpbuf[FPBUF_SIZE]; -#endif /* FP */ - - if (!fmt) - return 0; - - while ((c = *fmt++)) { - if (c != '%') { - shf_putc(c, shf); - nwritten++; - continue; - } - /* - * This will accept flags/fields in any order - not - * just the order specified in printf(3), but this is - * the way _doprnt() seems to work (on bsd and sysV). - * The only resriction is that the format character must - * come last :-). - */ - flags = field = precision = 0; - for ( ; (c = *fmt++) ; ) { - switch (c) { - case '#': - flags |= FL_HASH; - continue; - - case '+': - flags |= FL_PLUS; - continue; - - case '-': - flags |= FL_RIGHT; - continue; - - case ' ': - flags |= FL_BLANK; - continue; - - case '0': - if (!(flags & FL_DOT)) - flags |= FL_ZERO; - continue; - - case '.': - flags |= FL_DOT; - precision = 0; - continue; - - case '*': - tmp = va_arg(args, int); - if (flags & FL_DOT) - precision = tmp; - else if ((field = tmp) < 0) { - field = -field; - flags |= FL_RIGHT; - } - continue; - - case 'l': - flags |= FL_LONG; - continue; - - case 'h': - flags |= FL_SHORT; - continue; - } - if (digit(c)) { - tmp = c - '0'; - while (c = *fmt++, digit(c)) - tmp = tmp * 10 + c - '0'; - --fmt; - if (tmp < 0) /* overflow? */ - tmp = 0; - if (flags & FL_DOT) - precision = tmp; - else - field = tmp; - continue; - } - break; - } - - if (precision < 0) - precision = 0; - - if (!c) /* nasty format */ - break; - - if (c >= 'A' && c <= 'Z') { - flags |= FL_UPPER; - c = c - 'A' + 'a'; - } - - switch (c) { - case 'p': /* pointer */ - flags &= ~(FL_LONG | FL_SHORT); - if (sizeof(char *) > sizeof(int)) - flags |= FL_LONG; /* hope it fits.. */ - /* aaahhh... */ - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - flags |= FL_NUMBER; - s = &numbuf[sizeof(numbuf)]; - lnum = POP_INT(flags, c == 'd', args); - switch (c) { - case 'd': - case 'i': - if (0 > (long) lnum) - lnum = - (long) lnum, tmp = 1; - else - tmp = 0; - /* aaahhhh..... */ - - case 'u': - do { - *--s = lnum % 10 + '0'; - lnum /= 10; - } while (lnum); - - if (c != 'u') { - if (tmp) - *--s = '-'; - else if (flags & FL_PLUS) - *--s = '+'; - else if (flags & FL_BLANK) - *--s = ' '; - } - break; - - case 'o': - do { - *--s = (lnum & 0x7) + '0'; - lnum >>= 3; - } while (lnum); - - if ((flags & FL_HASH) && *s != '0') - *--s = '0'; - break; - - case 'p': - case 'x': - { - const char *digits = (flags & FL_UPPER) ? - "0123456789ABCDEF" - : "0123456789abcdef"; - do { - *--s = digits[lnum & 0xf]; - lnum >>= 4; - } while (lnum); - - if (flags & FL_HASH) { - *--s = (flags & FL_UPPER) ? 'X' : 'x'; - *--s = '0'; - } - } - } - len = &numbuf[sizeof(numbuf)] - s; - if (flags & FL_DOT) { - if (precision > len) { - field = precision; - flags |= FL_ZERO; - } else - precision = len; /* no loss */ - } - break; - -#ifdef FP - case 'e': - case 'g': - case 'f': - { - char *p; - - /* - * This could proabably be done better, - * but it seems to work. Note that gcvt() - * is not used, as you cannot tell it to - * not strip the zeros. - */ - flags |= FL_NUMBER; - if (!(flags & FL_DOT)) - precision = 6; /* default */ - /* - * Assumes doubles are pushed on - * the stack. If this is not so, then - * FL_LONG/FL_SHORT should be checked. - */ - fpnum = va_arg(args, double); - s = fpbuf; - style = c; - /* - * This is the same as - * expo = ceil(log10(fpnum)) - * but doesn't need -lm. This is an - * aproximation as expo is rounded up. - */ - (void) frexp(fpnum, &expo); - expo = my_ceil(expo / LOG2_10); - - if (expo < 0) - expo = 0; - - p = ecvt(fpnum, precision + 1 + expo, - &decpt, &tmp); - if (c == 'g') { - if (decpt < -4 || decpt > precision) - style = 'e'; - else - style = 'f'; - if (decpt > 0 && (precision -= decpt) < 0) - precision = 0; - } - if (tmp) - *--s = '-'; - else if (flags & FL_PLUS) - *--s = '+'; - else if (flags & FL_BLANK) - *--s = ' '; - - if (style == 'e') - *s++ = *p++; - else { - if (decpt > 0) { - /* Overflow check - should - * never have this problem. - */ - if (decpt > - &fpbuf[sizeof(fpbuf)] - - s - 8) - decpt = - &fpbuf[sizeof(fpbuf)] - - s - 8; - (void) memcpy(s, p, decpt); - s += decpt; - p += decpt; - } else - *s++ = '0'; - } - - /* print the fraction? */ - if (precision > 0) { - *s++ = '.'; - /* Overflow check - should - * never have this problem. - */ - if (precision > &fpbuf[sizeof(fpbuf)] - - s - 7) - precision = - &fpbuf[sizeof(fpbuf)] - - s - 7; - for (tmp = decpt; tmp++ < 0 && - precision > 0 ; precision--) - *s++ = '0'; - tmp = strlen(p); - if (precision > tmp) - precision = tmp; - /* Overflow check - should - * never have this problem. - */ - if (precision > &fpbuf[sizeof(fpbuf)] - - s - 7) - precision = - &fpbuf[sizeof(fpbuf)] - - s - 7; - (void) memcpy(s, p, precision); - s += precision; - /* - * `g' format strips trailing - * zeros after the decimal. - */ - if (c == 'g' && !(flags & FL_HASH)) { - while (*--s == '0') - ; - if (*s != '.') - s++; - } - } else if (flags & FL_HASH) - *s++ = '.'; - - if (style == 'e') { - *s++ = (flags & FL_UPPER) ? 'E' : 'e'; - if (--decpt >= 0) - *s++ = '+'; - else { - *s++ = '-'; - decpt = -decpt; - } - p = &numbuf[sizeof(numbuf)]; - for (tmp = 0; tmp < 2 || decpt ; tmp++) { - *--p = '0' + decpt % 10; - decpt /= 10; - } - tmp = &numbuf[sizeof(numbuf)] - p; - (void) memcpy(s, p, tmp); - s += tmp; - } - - len = s - fpbuf; - s = fpbuf; - precision = len; - break; - } -#endif /* FP */ - - case 's': - if (!(s = va_arg(args, char *))) - s = "(null %s)"; - len = strlen(s); - break; - - case 'c': - flags &= ~FL_DOT; - numbuf[0] = va_arg(args, int); - s = numbuf; - len = 1; - break; - - case '%': - default: - numbuf[0] = c; - s = numbuf; - len = 1; - break; - } - - /* - * At this point s should point to a string that is - * to be formatted, and len should be the length of the - * string. - */ - if (!(flags & FL_DOT) || len < precision) - precision = len; - if (field > precision) { - field -= precision; - if (!(flags & FL_RIGHT)) { - field = -field; - /* skip past sign or 0x when padding with 0 */ - if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { - if (*s == '+' || *s == '-' || *s ==' ') - { - shf_putc(*s, shf); - s++; - precision--; - nwritten++; - } else if (*s == '0') { - shf_putc(*s, shf); - s++; - nwritten++; - if (--precision > 0 && - (*s | 0x20) == 'x') - { - shf_putc(*s, shf); - s++; - precision--; - nwritten++; - } - } - c = '0'; - } else - c = flags & FL_ZERO ? '0' : ' '; - if (field < 0) { - nwritten += -field; - for ( ; field < 0 ; field++) - shf_putc(c, shf); - } - } else - c = ' '; - } else - field = 0; - - if (precision > 0) { - nwritten += precision; - for ( ; precision-- > 0 ; s++) - shf_putc(*s, shf); - } - if (field > 0) { - nwritten += field; - for ( ; field > 0 ; --field) - shf_putc(c, shf); - } - } - - return shf_error(shf) ? EOF : nwritten; -} diff --git a/bin/pdksh/shf.h b/bin/pdksh/shf.h deleted file mode 100644 index 2069d3248b8..00000000000 --- a/bin/pdksh/shf.h +++ /dev/null @@ -1,81 +0,0 @@ -/* $OpenBSD: shf.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */ - -/* - * Shell file I/O routines - */ - -#define SHF_BSIZE 512 - -#define shf_fileno(shf) ((shf)->fd) -#define shf_setfileno(shf,nfd) ((shf)->fd = (nfd)) -#define shf_getc(shf) ((shf)->rnleft > 0 ? (shf)->rnleft--, *(shf)->rp++ : \ - shf_getchar(shf)) -#define shf_putc(c, shf) ((shf)->wnleft == 0 ? shf_putchar((c), (shf)) \ - : ((shf)->wnleft--, *(shf)->wp++ = (c))) -#define shf_eof(shf) ((shf)->flags & SHF_EOF) -#define shf_error(shf) ((shf)->flags & SHF_ERROR) -#define shf_errno(shf) ((shf)->errno_) -#define shf_clearerr(shf) ((shf)->flags &= ~(SHF_EOF | SHF_ERROR)) - -/* Flags passed to shf_*open() */ -#define SHF_RD 0x0001 -#define SHF_WR 0x0002 -#define SHF_RDWR (SHF_RD|SHF_WR) -#define SHF_ACCMODE 0x0003 /* mask */ -#define SHF_GETFL 0x0004 /* use fcntl() to figure RD/WR flags */ -#define SHF_UNBUF 0x0008 /* unbuffered I/O */ -#define SHF_CLEXEC 0x0010 /* set close on exec flag */ -#define SHF_MAPHI 0x0020 /* make fd > FDBASE (and close orig) - * (shf_open() only) */ -#define SHF_DYNAMIC 0x0040 /* string: increase buffer as needed */ -#define SHF_INTERRUPT 0x0080 /* EINTR in read/write causes error */ -/* Flags used internally */ -#define SHF_STRING 0x0100 /* a string, not a file */ -#define SHF_ALLOCS 0x0200 /* shf and shf->buf were alloc()ed */ -#define SHF_ALLOCB 0x0400 /* shf->buf was alloc()ed */ -#define SHF_ERROR 0x0800 /* read()/write() error */ -#define SHF_EOF 0x1000 /* read eof (sticky) */ -#define SHF_READING 0x2000 /* currently reading: rnleft,rp valid */ -#define SHF_WRITING 0x4000 /* currently writing: wnleft,wp valid */ - - -struct shf { - int flags; /* see SHF_* */ - unsigned char *rp; /* read: current position in buffer */ - int rbsize; /* size of buffer (1 if SHF_UNBUF) */ - int rnleft; /* read: how much data left in buffer */ - unsigned char *wp; /* write: current position in buffer */ - int wbsize; /* size of buffer (0 if SHF_UNBUF) */ - int wnleft; /* write: how much space left in buffer */ - unsigned char *buf; /* buffer */ - int fd; /* file descriptor */ - int errno_; /* saved value of errno after error */ - int bsize; /* actual size of buf */ - Area *areap; /* area shf/buf were allocated in */ -}; - -extern struct shf shf_iob[]; - -struct shf *shf_open ARGS((const char *name, int oflags, int mode, - int sflags)); -struct shf *shf_fdopen ARGS((int fd, int sflags, struct shf *shf)); -struct shf *shf_reopen ARGS((int fd, int sflags, struct shf *shf)); -struct shf *shf_sopen ARGS((char *buf, int bsize, int sflags, - struct shf *shf)); -int shf_close ARGS((struct shf *shf)); -int shf_fdclose ARGS((struct shf *shf)); -char *shf_sclose ARGS((struct shf *shf)); -int shf_finish ARGS((struct shf *shf)); -int shf_flush ARGS((struct shf *shf)); -int shf_seek ARGS((struct shf *shf, off_t where, int from)); -int shf_read ARGS((char *buf, int bsize, struct shf *shf)); -char *shf_getse ARGS((char *buf, int bsize, struct shf *shf)); -int shf_getchar ARGS((struct shf *shf)); -int shf_ungetc ARGS((int c, struct shf *shf)); -int shf_putchar ARGS((int c, struct shf *shf)); -int shf_puts ARGS((const char *s, struct shf *shf)); -int shf_write ARGS((const char *buf, int nbytes, struct shf *shf)); -int shf_fprintf ARGS((struct shf *shf, const char *fmt, ...)); -int shf_snprintf ARGS((char *buf, int bsize, const char *fmt, ...)); -char *shf_smprintf ARGS((const char *fmt, ...)); -int shf_vfprintf ARGS((struct shf *, const char *fmt, va_list args)); diff --git a/bin/pdksh/siglist.in b/bin/pdksh/siglist.in deleted file mode 100644 index de6f1dd849f..00000000000 --- a/bin/pdksh/siglist.in +++ /dev/null @@ -1,56 +0,0 @@ -# $OpenBSD: siglist.in,v 1.1 1996/08/14 06:19:11 downsj Exp $ -# -# List of signals used to initialize ksh's signal table (see trap.c -# and siglist.sh). -# -# Note that if a system has multiple defines for the same signal -# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one -# will be seen, so the order in this list is important. -# - HUP Hangup - INT Interrupt - QUIT Quit - ILL Illegal instruction - TRAP Trace trap -# before IOT (ABRT is posix and ABRT is sometimes the same as IOT) - ABRT Abort - IOT IOT instruction - EMT EMT trap - FPE Floating point exception - KILL Killed -# before BUS (linux doesn't really have a BUS, but defines it to UNUSED) - UNUSED Unused - BUS Bus error - SEGV Memory fault - SYS Bad system call - PIPE Broken pipe - ALRM Alarm clock - TERM Terminated - STKFLT Stack fault - IO I/O possible - XCPU CPU time limit exceeded - XFSZ File size limit exceeded - VTALRM Virtual timer expired - PROF Profiling timer expired - WINCH Window size change - LOST File lock lost - USR1 User defined signal 1 - USR2 User defined signal 2 - PWR Power-fail/Restart - POLL Pollable event occurred - STOP Stopped (signal) - TSTP Stopped - CONT Continued -# before CLD (CHLD is posix and CHLD is sometimes the same as CLD) - CHLD Child exited - CLD Child exited - TTIN Stopped (tty input) - TTOU Stopped (tty output) - INFO Information request - URG Urgent I/O condition -# Solaris (svr4?) signals - WAITING No runnable LWPs - LWP Inter-LWP signal - FREEZE Checkpoint freeze - THAW Checkpoint thaw - CANCEL Thread cancellation diff --git a/bin/pdksh/siglist.sh b/bin/pdksh/siglist.sh deleted file mode 100644 index 123b190140c..00000000000 --- a/bin/pdksh/siglist.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# $OpenBSD: siglist.sh,v 1.4 1997/06/19 13:58:47 kstailey Exp $ - -# -# Script to generate a sorted, complete list of signals, suitable -# for inclusion in trap.c as array initializer. -# - -set -e - -in=tmpi$$.c -out=tmpo$$.c -ecode=1 -trapsigs='0 1 2 13 15' -trap 'rm -f $in $out; trap 0; exit $ecode' $trapsigs - -CPP="${1-cc -E}" - -# The trap here to make up for a bug in bash (1.14.3(1)) that calls the trap -(trap $trapsigs; - echo '#include "sh.h"'; - echo ' { QwErTy SIGNALS , "DUMMY" , "hook for number of signals" },'; - sed -e '/^[ ]*#/d' -e 's/^[ ]*\([^ ][^ ]*\)[ ][ ]*\(.*[^ ]\)[ ]*$/#ifdef SIG\1\ - { QwErTy SIG\1 , "\1", "\2" },\ -#endif/') > $in -$CPP $in > $out -sed -n 's/{ QwErTy/{/p' < $out | awk '{print NR, $0}' | sort +2n +0n | - sed 's/^[0-9]* //' | - awk 'BEGIN { last=0; nsigs=0; } - { - if ($2 ~ /^[0-9][0-9]*$/ && $3 == ",") { - n = $2; - if (n > 0 && n != last) { - while (++last < n) { - printf "\t{ %d , (char *) 0, `Signal %d` } ,\n", last, last; - } - print; - } - } - }' | - tr '`' '"' | grep -v '"DUMMY"' -ecode=0 diff --git a/bin/pdksh/syn.c b/bin/pdksh/syn.c deleted file mode 100644 index 4b37baa819d..00000000000 --- a/bin/pdksh/syn.c +++ /dev/null @@ -1,948 +0,0 @@ -/* $OpenBSD: syn.c,v 1.8 1997/09/01 18:30:12 deraadt Exp $ */ - -/* - * shell parser (C version) - */ - -#include "sh.h" -#include "c_test.h" - -struct multiline_state { - int on; /* set in multiline commands (\n becomes ;) */ - int start_token; /* token multiline is for (eg, FOR, {, etc.) */ - int start_line; /* line multiline command started on */ -}; - -static void yyparse ARGS((void)); -static struct op *pipeline ARGS((int cf)); -static struct op *andor ARGS((void)); -static struct op *c_list ARGS((void)); -static struct ioword *synio ARGS((int cf)); -static void musthave ARGS((int c, int cf)); -static struct op *nested ARGS((int type, int smark, int emark)); -static struct op *get_command ARGS((int cf)); -static struct op *dogroup ARGS((void)); -static struct op *thenpart ARGS((void)); -static struct op *elsepart ARGS((void)); -static struct op *caselist ARGS((void)); -static struct op *casepart ARGS((int endtok)); -static struct op *function_body ARGS((char *name, int ksh_func)); -static char ** wordlist ARGS((void)); -static struct op *block ARGS((int type, struct op *t1, struct op *t2, - char **wp)); -static struct op *newtp ARGS((int type)); -static void syntaxerr ARGS((const char *what)) - GCC_FUNC_ATTR(noreturn); -static void multiline_push ARGS((struct multiline_state *save, int tok)); -static void multiline_pop ARGS((struct multiline_state *saved)); -static int assign_command ARGS((char *s)); -static int inalias ARGS((struct source *s)); -#ifdef KSH -static int dbtestp_isa ARGS((Test_env *te, Test_meta meta)); -static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op, - int do_eval)); -static int dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1, - const char *opnd2, int do_eval)); -static void dbtestp_error ARGS((Test_env *te, int offset, const char *msg)); -#endif /* KSH */ - -static struct op *outtree; /* yyparse output */ - -static struct multiline_state multiline; /* \n changed to ; */ - -static int reject; /* token(cf) gets symbol again */ -static int symbol; /* yylex value */ - -#define REJECT (reject = 1) -#define ACCEPT (reject = 0) -#define token(cf) \ - ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf))) -#define tpeek(cf) \ - ((reject) ? (symbol) : (REJECT, symbol = yylex(cf))) - -static void -yyparse() -{ - int c; - - ACCEPT; - yynerrs = 0; - - outtree = c_list(); - c = tpeek(0); - if (c == 0 && !outtree) - outtree = newtp(TEOF); - else if (c != '\n' && c != 0) - syntaxerr((char *) 0); -} - -static struct op * -pipeline(cf) - int cf; -{ - register struct op *t, *p, *tl = NULL; - - t = get_command(cf); - if (t != NULL) { - while (token(0) == '|') { - if ((p = get_command(CONTIN)) == NULL) - syntaxerr((char *) 0); - if (tl == NULL) - t = tl = block(TPIPE, t, p, NOWORDS); - else - tl = tl->right = block(TPIPE, tl->right, p, NOWORDS); - } - REJECT; - } - return (t); -} - -static struct op * -andor() -{ - register struct op *t, *p; - register int c; - - t = pipeline(0); - if (t != NULL) { - while ((c = token(0)) == LOGAND || c == LOGOR) { - if ((p = pipeline(CONTIN)) == NULL) - syntaxerr((char *) 0); - t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); - } - REJECT; - } - return (t); -} - -static struct op * -c_list() -{ - register struct op *t, *p, *tl = NULL; - register int c; - - t = andor(); - if (t != NULL) { - /* Token has always been read/rejected at this point, so - * we don't worray about what flags to pass token() - */ - while ((c = token(0)) == ';' || c == '&' || c == COPROC || - (c == '\n' && (multiline.on || inalias(source)))) - { - if (c == '&' || c == COPROC) { - int type = c == '&' ? TASYNC : TCOPROC; - if (tl) - tl->right = block(type, tl->right, - NOBLOCK, NOWORDS); - else - t = block(type, t, NOBLOCK, NOWORDS); - } - if ((p = andor()) == NULL) - return (t); - if (tl == NULL) - t = tl = block(TLIST, t, p, NOWORDS); - else - tl = tl->right = block(TLIST, tl->right, p, NOWORDS); - } - REJECT; - } - return (t); -} - -static struct ioword * -synio(cf) - int cf; -{ - register struct ioword *iop; - int ishere; - - if (tpeek(cf) != REDIR) - return NULL; - ACCEPT; - iop = yylval.iop; - ishere = (iop->flag&IOTYPE) == IOHERE; - musthave(LWORD, ishere ? HEREDELIM : 0); - if (ishere) { - iop->delim = yylval.cp; - if (*ident != 0) /* unquoted */ - iop->flag |= IOEVAL; - if (herep >= &heres[HERES]) - yyerror("too many <<'s\n"); - *herep++ = iop; - } else - iop->name = yylval.cp; - return iop; -} - -static void -musthave(c, cf) - int c, cf; -{ - if ((token(cf)) != c) - syntaxerr((char *) 0); -} - -static struct op * -nested(type, smark, emark) - int type, smark, emark; -{ - register struct op *t; - struct multiline_state old_multiline; - - multiline_push(&old_multiline, smark); - t = c_list(); - musthave(emark, KEYWORD|ALIAS); - multiline_pop(&old_multiline); - return (block(type, t, NOBLOCK, NOWORDS)); -} - -static struct op * -get_command(cf) - int cf; -{ - register struct op *t; - register int c, iopn = 0, syniocf; - struct ioword *iop, **iops; - XPtrV args, vars; - struct multiline_state old_multiline; - - iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1), - ATEMP); - XPinit(args, 16); - XPinit(vars, 16); - - /* Don't want to pass CONTIN if reading interactively as just hitting - * return would print PS2 instead of PS1. - */ - if (multiline.on || inalias(source)) - cf = CONTIN; - syniocf = KEYWORD|ALIAS; - switch (c = token(cf|KEYWORD|ALIAS|VARASN)) { - default: - REJECT; - afree((void*) iops, ATEMP); - XPfree(args); - XPfree(vars); - return NULL; /* empty line */ - - case LWORD: - case REDIR: - REJECT; - syniocf &= ~(KEYWORD|ALIAS); - t = newtp(TCOM); - while (1) { - cf = (t->u.evalflags ? ARRAYVAR : 0) - | (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); - switch (tpeek(cf)) { - case REDIR: - if (iopn >= NUFILE) - yyerror("too many redirections\n"); - iops[iopn++] = synio(cf); - break; - - case LWORD: - ACCEPT; - /* the iopn == 0 and XPsize(vars) == 0 are - * dubious but at&t ksh acts this way - */ - if (iopn == 0 && XPsize(vars) == 0 - && XPsize(args) == 0 - && assign_command(ident)) - t->u.evalflags = DOVACHECK; - if ((XPsize(args) == 0 || Flag(FKEYWORD)) - && is_wdvarassign(yylval.cp)) - XPput(vars, yylval.cp); - else - XPput(args, yylval.cp); - break; - - case '(': - /* Check for "> foo (echo hi)", which at&t ksh - * allows (not POSIX, but not disallowed) - */ - afree(t, ATEMP); - if (XPsize(args) == 0 && XPsize(vars) == 0) { - ACCEPT; - goto Subshell; - } - /* Must be a function */ - if (iopn != 0 || XPsize(args) != 1 - || XPsize(vars) != 0) - syntaxerr((char *) 0); - ACCEPT; - /*(*/ - musthave(')', 0); - t = function_body(XPptrv(args)[0], FALSE); - goto Leave; - - default: - goto Leave; - } - } - Leave: - break; - - Subshell: - case '(': - t = nested(TPAREN, '(', ')'); - break; - - case '{': /*}*/ - t = nested(TBRACE, '{', '}'); - break; - -#ifdef KSH - case MDPAREN: - { - static const char let_cmd[] = { CHAR, 'l', CHAR, 'e', - CHAR, 't', EOS }; - syniocf &= ~(KEYWORD|ALIAS); - t = newtp(TCOM); - ACCEPT; - XPput(args, wdcopy(let_cmd, ATEMP)); - musthave(LWORD,LETEXPR); - XPput(args, yylval.cp); - break; - } -#endif /* KSH */ - -#ifdef KSH - case DBRACKET: /* [[ .. ]] */ - syniocf &= ~(KEYWORD|ALIAS); - t = newtp(TDBRACKET); - ACCEPT; - { - Test_env te; - - te.flags = TEF_DBRACKET; - te.pos.av = &args; - te.isa = dbtestp_isa; - te.getopnd = dbtestp_getopnd; - te.eval = dbtestp_eval; - te.error = dbtestp_error; - - test_parse(&te); - } - break; -#endif /* KSH */ - - case FOR: - case SELECT: - t = newtp((c == FOR) ? TFOR : TSELECT); - musthave(LWORD, ARRAYVAR); - if (!is_wdvarname(yylval.cp, TRUE)) - yyerror("%s: bad identifier\n", - c == FOR ? "for" : "select"); - t->str = str_save(ident, ATEMP); - multiline_push(&old_multiline, c); - t->vars = wordlist(); - t->left = dogroup(); - multiline_pop(&old_multiline); - break; - - case WHILE: - case UNTIL: - multiline_push(&old_multiline, c); - t = newtp((c == WHILE) ? TWHILE : TUNTIL); - t->left = c_list(); - t->right = dogroup(); - multiline_pop(&old_multiline); - break; - - case CASE: - t = newtp(TCASE); - musthave(LWORD, 0); - t->str = yylval.cp; - multiline_push(&old_multiline, c); - t->left = caselist(); - multiline_pop(&old_multiline); - break; - - case IF: - multiline_push(&old_multiline, c); - t = newtp(TIF); - t->left = c_list(); - t->right = thenpart(); - musthave(FI, KEYWORD|ALIAS); - multiline_pop(&old_multiline); - break; - - case BANG: - syniocf &= ~(KEYWORD|ALIAS); - t = pipeline(0); - if (t == (struct op *) 0) - syntaxerr((char *) 0); - t = block(TBANG, NOBLOCK, t, NOWORDS); - break; - - case TIME: - syniocf &= ~(KEYWORD|ALIAS); - t = pipeline(0); - t = block(TTIME, t, NOBLOCK, NOWORDS); - break; - - case FUNCTION: - musthave(LWORD, 0); - t = function_body(yylval.cp, TRUE); - break; - } - - while ((iop = synio(syniocf)) != NULL) { - if (iopn >= NUFILE) - yyerror("too many redirections\n"); - iops[iopn++] = iop; - } - - if (iopn == 0) { - afree((void*) iops, ATEMP); - t->ioact = NULL; - } else { - iops[iopn++] = NULL; - iops = (struct ioword **) aresize((void*) iops, - sizeofN(struct ioword *, iopn), ATEMP); - t->ioact = iops; - } - - if (t->type == TCOM || t->type == TDBRACKET) { - XPput(args, NULL); - t->args = (char **) XPclose(args); - XPput(vars, NULL); - t->vars = (char **) XPclose(vars); - } else { - XPfree(args); - XPfree(vars); - } - - return t; -} - -static struct op * -dogroup() -{ - register int c; - register struct op *list; - - c = token(CONTIN|KEYWORD|ALIAS); - /* A {...} can be used instead of do...done for for/select loops - * but not for while/until loops - we don't need to check if it - * is a while loop because it would have been parsed as part of - * the conditional command list... - */ - if (c == DO) - c = DONE; - else if (c == '{') - c = '}'; - else - syntaxerr((char *) 0); - list = c_list(); - musthave(c, KEYWORD|ALIAS); - return list; -} - -static struct op * -thenpart() -{ - register struct op *t; - - musthave(THEN, KEYWORD|ALIAS); - t = newtp(0); - t->left = c_list(); - if (t->left == NULL) - syntaxerr((char *) 0); - t->right = elsepart(); - return (t); -} - -static struct op * -elsepart() -{ - register struct op *t; - - switch (token(KEYWORD|ALIAS|VARASN)) { - case ELSE: - if ((t = c_list()) == NULL) - syntaxerr((char *) 0); - return (t); - - case ELIF: - t = newtp(TELIF); - t->left = c_list(); - t->right = thenpart(); - return (t); - - default: - REJECT; - } - return NULL; -} - -static struct op * -caselist() -{ - register struct op *t, *tl; - int c; - - c = token(CONTIN|KEYWORD|ALIAS); - /* A {...} can be used instead of in...esac for case statements */ - if (c == IN) - c = ESAC; - else if (c == '{') - c = '}'; - else - syntaxerr((char *) 0); - t = tl = NULL; - while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */ - struct op *tc = casepart(c); - if (tl == NULL) - t = tl = tc, tl->right = NULL; - else - tl->right = tc, tl = tc; - } - musthave(c, KEYWORD|ALIAS); - return (t); -} - -static struct op * -casepart(endtok) - int endtok; -{ - register struct op *t; - register int c; - XPtrV ptns; - - XPinit(ptns, 16); - t = newtp(TPAT); - c = token(CONTIN|KEYWORD); /* no ALIAS here */ - if (c != '(') - REJECT; - do { - musthave(LWORD, 0); - XPput(ptns, yylval.cp); - } while ((c = token(0)) == '|'); - REJECT; - XPput(ptns, NULL); - t->vars = (char **) XPclose(ptns); - musthave(')', 0); - - t->left = c_list(); - if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok) - musthave(BREAK, CONTIN|KEYWORD|ALIAS); - return (t); -} - -static struct op * -function_body(name, ksh_func) - char *name; - int ksh_func; /* function foo { ... } vs foo() { .. } */ -{ - XString xs; - char *xp, *p; - struct op *t; - int old_func_parse; - - Xinit(xs, xp, 16, ATEMP); - for (p = name; ; ) { - if ((*p == EOS && Xlength(xs, xp) == 0) - || (*p != EOS && *p != CHAR && *p != QCHAR - && *p != OQUOTE && *p != CQUOTE)) - { - p = snptreef((char *) 0, 32, "%S", name); - yyerror("%s: invalid function name\n", p); - } - Xcheck(xs, xp); - if (*p == EOS) { - Xput(xs, xp, '\0'); - break; - } else if (*p == CHAR || *p == QCHAR) { - Xput(xs, xp, p[1]); - p += 2; - } else - p++; /* OQUOTE/CQUOTE */ - } - 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 - * break anything. However, for function foo, at&t ksh only accepts - * an open-brace. - */ - if (ksh_func) { - musthave('{', CONTIN|KEYWORD|ALIAS); /* } */ - REJECT; - } - - old_func_parse = e->flags & EF_FUNC_PARSE; - e->flags |= EF_FUNC_PARSE; - if ((t->left = get_command(CONTIN)) == (struct op *) 0) { - /* create empty command so foo(): will work */ - t->left = newtp(TCOM); - t->args = (char **) alloc(sizeof(char *), ATEMP); - t->args[0] = (char *) 0; - t->vars = (char **) alloc(sizeof(char *), ATEMP); - t->vars[0] = (char *) 0; - } - if (!old_func_parse) - e->flags &= ~EF_FUNC_PARSE; - - return t; -} - -static char ** -wordlist() -{ - register int c; - XPtrV args; - - XPinit(args, 16); - if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) { - if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */ - REJECT; - return NULL; - } - while ((c = token(0)) == LWORD) - XPput(args, yylval.cp); - if (c != '\n' && c != ';') - syntaxerr((char *) 0); - if (XPsize(args) == 0) { - XPfree(args); - return NULL; - } else { - XPput(args, NULL); - return (char **) XPclose(args); - } -} - -/* - * supporting functions - */ - -static struct op * -block(type, t1, t2, wp) - int type; - struct op *t1, *t2; - char **wp; -{ - register struct op *t; - - t = newtp(type); - t->left = t1; - t->right = t2; - t->vars = wp; - return (t); -} - -const struct tokeninfo { - const char *name; - short val; - short reserved; -} tokentab[] = { - /* Reserved words */ - { "if", IF, TRUE }, - { "then", THEN, TRUE }, - { "else", ELSE, TRUE }, - { "elif", ELIF, TRUE }, - { "fi", FI, TRUE }, - { "case", CASE, TRUE }, - { "esac", ESAC, TRUE }, - { "for", FOR, TRUE }, -#ifdef KSH - { "select", SELECT, TRUE }, -#endif /* KSH */ - { "while", WHILE, TRUE }, - { "until", UNTIL, TRUE }, - { "do", DO, TRUE }, - { "done", DONE, TRUE }, - { "in", IN, TRUE }, - { "function", FUNCTION, TRUE }, - { "time", TIME, TRUE }, - { "{", '{', TRUE }, - { "}", '}', TRUE }, - { "!", BANG, TRUE }, -#ifdef KSH - { "[[", DBRACKET, TRUE }, -#endif /* KSH */ - /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */ - { "&&", LOGAND, FALSE }, - { "||", LOGOR, FALSE }, - { ";;", BREAK, FALSE }, -#ifdef KSH - { "((", MDPAREN, FALSE }, - { "|&", COPROC, FALSE }, -#endif /* KSH */ - /* and some special cases... */ - { "newline", '\n', FALSE }, - { 0 } -}; - -void -initkeywords() -{ - register struct tokeninfo const *tt; - register struct tbl *p; - - tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */ - for (tt = tokentab; tt->name; tt++) { - if (tt->reserved) { - p = tenter(&keywords, tt->name, hash(tt->name)); - p->flag |= DEFINED|ISSET; - p->type = CKEYWD; - p->val.i = tt->val; - } - } -} - -static void -syntaxerr(what) - const char *what; -{ - char redir[6]; /* 2<<- is the longest redirection, I think */ - const char *s; - struct tokeninfo const *tt; - int c; - - if (!what) - what = "unexpected"; - REJECT; - c = token(0); - Again: - switch (c) { - case 0: - if (multiline.on && multiline.start_token) { - multiline.on = FALSE; /* avoid infinate loops */ - c = multiline.start_token; - source->errline = multiline.start_line; - what = "unmatched"; - goto Again; - } - /* don't quote the EOF */ - yyerror("syntax error: unexpected EOF\n"); - /*NOTREACHED*/ - - case LWORD: - s = snptreef((char *) 0, 32, "%S", yylval.cp); - break; - - case REDIR: - s = snptreef(redir, sizeof(redir), "%R", yylval.iop); - break; - - default: - for (tt = tokentab; tt->name; tt++) - if (tt->val == c) - break; - if (tt->name) - s = tt->name; - else { - if (c > 0 && c < 256) { - redir[0] = c; - redir[1] = '\0'; - } else - shf_snprintf(redir, sizeof(redir), - "?%d", c); - s = redir; - } - } - yyerror("syntax error: `%s' %s\n", s, what); -} - -static void -multiline_push(save, tok) - struct multiline_state *save; - int tok; -{ - *save = multiline; - multiline.on = TRUE; - multiline.start_token = tok; - multiline.start_line = source->line; -} - -static void -multiline_pop(saved) - struct multiline_state *saved; -{ - multiline = *saved; -} - -static struct op * -newtp(type) - int type; -{ - register struct op *t; - - t = (struct op *) alloc(sizeof(*t), ATEMP); - t->type = type; - t->u.evalflags = 0; - t->args = t->vars = NULL; - t->ioact = NULL; - t->left = t->right = NULL; - t->str = NULL; - return (t); -} - -struct op * -compile(s) - Source *s; -{ - yynerrs = 0; - multiline.on = s->type == SSTRING; - multiline.start_token = 0; - multiline.start_line = 0; - herep = heres; - source = s; - yyparse(); - return outtree; -} - -/* This kludge exists to take care of sh/at&t ksh oddity in which - * the arguments of alias/export/readonly/typeset have no field - * splitting, file globbing, or (normal) tilde expansion done. - * at&t ksh seems to do something similar to this since - * $ touch a=a; typeset a=[ab]; echo "$a" - * a=[ab] - * $ x=typeset; $x a=[ab]; echo "$a" - * a=a - * $ - */ -static int -assign_command(s) - char *s; -{ - char c = *s; - - if (Flag(FPOSIX) || !*s) - return 0; - return (c == 'a' && strcmp(s, "alias") == 0) - || (c == 'e' && strcmp(s, "export") == 0) - || (c == 'r' && strcmp(s, "readonly") == 0) - || (c == 't' && strcmp(s, "typeset") == 0); -} - -/* Check if we are in the middle of reading an alias */ -static int -inalias(s) - struct source *s; -{ - for (; s && s->type == SALIAS; s = s->next) - if (!(s->flags & SF_ALIASEND)) - return 1; - return 0; -} - - -#ifdef KSH -/* Order important - indexed by Test_meta values - * Note that ||, &&, ( and ) can't appear in as unquoted strings - * in normal shell input, so these can be interpreted unambiguously - * in the evaluation pass. - */ -static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS }; -static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS }; -static const char dbtest_not[] = { CHAR, '!', EOS }; -static const char dbtest_oparen[] = { CHAR, '(', EOS }; -static const char dbtest_cparen[] = { CHAR, ')', EOS }; -const char *const dbtest_tokens[] = { - dbtest_or, dbtest_and, dbtest_not, - dbtest_oparen, dbtest_cparen - }; -const char db_close[] = { CHAR, ']', CHAR, ']', EOS }; -const char db_lthan[] = { CHAR, '<', EOS }; -const char db_gthan[] = { CHAR, '>', EOS }; - -/* Test if the current token is a whatever. Accepts the current token if - * it is. Returns 0 if it is not, non-zero if it is (in the case of - * TM_UNOP and TM_BINOP, the returned value is a Test_op). - */ -static int -dbtestp_isa(te, meta) - Test_env *te; - Test_meta meta; -{ - int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN)); - int uqword = 0; - char *save = (char *) 0; - int ret = 0; - - /* unquoted word? */ - uqword = c == LWORD && *ident; - - if (meta == TM_OR) - ret = c == LOGOR; - else if (meta == TM_AND) - ret = c == LOGAND; - else if (meta == TM_NOT) - ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0; - else if (meta == TM_OPAREN) - ret = c == '(' /*)*/; - else if (meta == TM_CPAREN) - ret = c == /*(*/ ')'; - else if (meta == TM_UNOP || meta == TM_BINOP) { - if (meta == TM_BINOP && c == REDIR - && (yylval.iop->flag == IOREAD - || yylval.iop->flag == IOWRITE)) - { - ret = 1; - save = wdcopy(yylval.iop->flag == IOREAD ? - db_lthan : db_gthan, ATEMP); - } else if (uqword && (ret = (int) test_isop(te, meta, ident))) - save = yylval.cp; - } else /* meta == TM_END */ - ret = uqword && strcmp(yylval.cp, db_close) == 0; - if (ret) { - ACCEPT; - if (meta != TM_END) { - if (!save) - save = wdcopy(dbtest_tokens[(int) meta], ATEMP); - XPput(*te->pos.av, save); - } - } - return ret; -} - -static const char * -dbtestp_getopnd(te, op, do_eval) - Test_env *te; - Test_op op; - int do_eval; -{ - int c = tpeek(ARRAYVAR); - - if (c != LWORD) - return (const char *) 0; - - ACCEPT; - XPput(*te->pos.av, yylval.cp); - - return null; -} - -static int -dbtestp_eval(te, op, opnd1, opnd2, do_eval) - Test_env *te; - Test_op op; - const char *opnd1; - const char *opnd2; - int do_eval; -{ - return 1; -} - -static void -dbtestp_error(te, offset, msg) - Test_env *te; - int offset; - const char *msg; -{ - te->flags |= TEF_ERROR; - - if (offset < 0) { - REJECT; - /* Kludgy to say the least... */ - symbol = LWORD; - yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) - + offset); - } - syntaxerr(msg); -} -#endif /* KSH */ diff --git a/bin/pdksh/table.c b/bin/pdksh/table.c deleted file mode 100644 index a390c172c77..00000000000 --- a/bin/pdksh/table.c +++ /dev/null @@ -1,239 +0,0 @@ -/* $OpenBSD: table.c,v 1.4 1997/06/19 13:58:47 kstailey Exp $ */ - -/* - * dynamic hashed associative table for commands and variables - */ - -#include "sh.h" - -#define INIT_TBLS 8 /* initial table size (power of 2) */ - -static void texpand ARGS((struct table *tp, int nsize)); -static int tnamecmp ARGS((void *p1, void *p2)); - - -unsigned int -hash(n) - register const char * n; -{ - register unsigned int h = 0; - - while (*n != '\0') - h = 2*h + *n++; - return h * 32821; /* scatter bits */ -} - -void -tinit(tp, ap, tsize) - register struct table *tp; - register Area *ap; - int tsize; -{ - tp->areap = ap; - tp->tbls = NULL; - tp->size = tp->nfree = 0; - if (tsize) - texpand(tp, tsize); -} - -static void -texpand(tp, nsize) - register struct table *tp; - int nsize; -{ - register int i; - register struct tbl *tblp, **p; - register struct tbl **ntblp, **otblp = tp->tbls; - int osize = tp->size; - - ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap); - for (i = 0; i < nsize; i++) - ntblp[i] = NULL; - tp->size = nsize; - tp->nfree = 8*nsize/10; /* table can get 80% full */ - tp->tbls = ntblp; - if (otblp == NULL) - return; - for (i = 0; i < osize; i++) - if ((tblp = otblp[i]) != NULL) - if ((tblp->flag&DEFINED)) { - for (p = &ntblp[hash(tblp->name) - & (tp->size-1)]; - *p != NULL; p--) - if (p == ntblp) /* wrap */ - p += tp->size; - *p = tblp; - tp->nfree--; - } else if (!(tblp->flag & FINUSE)) { - afree((void*)tblp, tp->areap); - } - afree((void*)otblp, tp->areap); -} - -struct tbl * -tsearch(tp, n, h) - register struct table *tp; /* table */ - register const char *n; /* name to enter */ - unsigned int h; /* hash(n) */ -{ - register struct tbl **pp, *p; - - if (tp->size == 0) - return NULL; - - /* search for name in hashed table */ - for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) { - if (*p->name == *n && strcmp(p->name, n) == 0 - && (p->flag&DEFINED)) - return p; - if (pp == tp->tbls) /* wrap */ - pp += tp->size; - } - - return NULL; -} - -struct tbl * -tenter(tp, n, h) - register struct table *tp; /* table */ - register const char *n; /* name to enter */ - unsigned int h; /* hash(n) */ -{ - register struct tbl **pp, *p; - register int len; - - if (tp->size == 0) - texpand(tp, INIT_TBLS); - Search: - /* search for name in hashed table */ - for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) { - if (*p->name == *n && strcmp(p->name, n) == 0) - return p; /* found */ - if (pp == tp->tbls) /* wrap */ - pp += tp->size; - } - - if (tp->nfree <= 0) { /* too full */ - texpand(tp, 2*tp->size); - goto Search; - } - - /* create new tbl entry */ - len = strlen(n) + 1; - p = (struct tbl *) alloc(offsetof(struct tbl, name[0]) + len, - tp->areap); - p->flag = 0; - p->type = 0; - p->areap = tp->areap; - p->u2.field = 0; - p->u.array = (struct tbl *)0; - memcpy(p->name, n, len); - - /* enter in tp->tbls */ - tp->nfree--; - *pp = p; - return p; -} - -void -tdelete(p) - register struct tbl *p; -{ - p->flag = 0; -} - -void -twalk(ts, tp) - struct tstate *ts; - struct table *tp; -{ - ts->left = tp->size; - ts->next = tp->tbls; -} - -struct tbl * -tnext(ts) - struct tstate *ts; -{ - while (--ts->left >= 0) { - struct tbl *p = *ts->next++; - if (p != NULL && (p->flag&DEFINED)) - return p; - } - return NULL; -} - -static int -tnamecmp(p1, p2) - void *p1, *p2; -{ - return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name); -} - -struct tbl ** -tsort(tp) - register struct table *tp; -{ - register int i; - register struct tbl **p, **sp, **dp; - - p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP); - sp = tp->tbls; /* source */ - dp = p; /* dest */ - for (i = 0; i < tp->size; i++) - if ((*dp = *sp++) != NULL && (((*dp)->flag&DEFINED) || - ((*dp)->flag&ARRAY))) - dp++; - i = dp - p; - qsortp((void**)p, (size_t)i, tnamecmp); - p[i] = NULL; - return p; -} - -#ifdef PERF_DEBUG /* performance debugging */ - -void tprintinfo ARGS((struct table *tp)); - -void -tprintinfo(tp) - struct table *tp; -{ - struct tbl *te; - char *n; - unsigned int h; - int ncmp; - int totncmp = 0, maxncmp = 0; - int nentries = 0; - struct tstate ts; - - shellf("table size %d, nfree %d\n", tp->size, tp->nfree); - shellf(" Ncmp name\n"); - twalk(&ts, tp); - while ((te = tnext(&ts))) { - register struct tbl **pp, *p; - - h = hash(n = te->name); - ncmp = 0; - - /* taken from tsearch() and added counter */ - for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp); pp--) { - ncmp++; - if (*p->name == *n && strcmp(p->name, n) == 0 - && (p->flag&DEFINED)) - break; /* return p; */ - if (pp == tp->tbls) /* wrap */ - pp += tp->size; - } - shellf(" %4d %s\n", ncmp, n); - totncmp += ncmp; - nentries++; - if (ncmp > maxncmp) - maxncmp = ncmp; - } - if (nentries) - shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n", - nentries, maxncmp, - totncmp / nentries, - (totncmp % nentries) * 100 / nentries); -} -#endif /* PERF_DEBUG */ diff --git a/bin/pdksh/table.h b/bin/pdksh/table.h deleted file mode 100644 index 75215719c22..00000000000 --- a/bin/pdksh/table.h +++ /dev/null @@ -1,176 +0,0 @@ -/* $OpenBSD: table.h,v 1.3 1996/11/21 07:59:35 downsj Exp $ */ - -/* $From: table.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */ - -/* - * generic hashed associative table for commands and variables. - */ - -struct table { - Area *areap; /* area to allocate entries */ - short size, nfree; /* hash size (always 2^^n), free entries */ - struct tbl **tbls; /* hashed table items */ -}; - -struct tbl { /* table item */ - 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 */ - union { - char *s; /* string */ - long i; /* integer */ - int (*f) ARGS((char **)); /* int function */ - struct op *t; /* "function" tree */ - } val; /* value */ - int index; /* index for an array */ - 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 */ - } u; - char name[4]; /* name -- variable length */ -}; - -/* common flag bits */ -#define ALLOC BIT(0) /* val.s has been allocated */ -#define DEFINED BIT(1) /* is defined in block */ -#define ISSET BIT(2) /* has value, vp->val.[si] */ -#define EXPORT BIT(3) /* exported variable/function */ -#define TRACE BIT(4) /* var: user flagged, func: execution tracing */ -/* (start non-common flags at 8) */ -/* flag bits used for variables */ -#define SPECIAL BIT(8) /* PATH, IFS, SECONDS, etc */ -#define INTEGER BIT(9) /* val.i contains integer value */ -#define RDONLY BIT(10) /* read-only variable */ -#define LOCAL BIT(11) /* for local typeset() */ -#define ARRAY BIT(13) /* array */ -#define LJUST BIT(14) /* left justify */ -#define RJUST BIT(15) /* right justify */ -#define ZEROFIL BIT(16) /* 0 filled if RJUSTIFY, strip 0s if LJUSTIFY */ -#define LCASEV BIT(17) /* convert to lower case */ -#define UCASEV_AL BIT(18)/* convert to upper case / autoload function */ -#define INT_U BIT(19) /* unsigned integer */ -#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 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 */ -/* Attributes that can be set by the user (used to decide if an unset param - * should be repoted by set/typeset). Does not include ARRAY or LOCAL. - */ -#define USERATTRIB (EXPORT|INTEGER|RDONLY|LJUST|RJUST|ZEROFIL\ - |LCASEV|UCASEV_AL|INT_U|INT_L) - -/* command types */ -#define CNONE 0 /* undefined */ -#define CSHELL 1 /* built-in */ -#define CFUNC 2 /* function */ -#define CEXEC 4 /* executable command */ -#define CALIAS 5 /* alias */ -#define CKEYWD 6 /* keyword */ -#define CTALIAS 7 /* tracked alias */ - -/* Flags for findcom()/comexec() */ -#define FC_SPECBI BIT(0) /* special builtin */ -#define FC_FUNC BIT(1) /* function builtin */ -#define FC_REGBI BIT(2) /* regular builtin */ -#define FC_UNREGBI BIT(3) /* un-regular builtin (!special,!regular) */ -#define FC_BI (FC_SPECBI|FC_REGBI|FC_UNREGBI) -#define FC_PATH BIT(4) /* do path search */ -#define FC_DEFPATH BIT(5) /* use default path in path search */ - - -#define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */ -#define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */ -#define AI_ARGV(a, i) ((i) == 0 ? (a).argv[0] : (a).argv[(i) - (a).skip]) -#define AI_ARGC(a) ((a).argc_ - (a).skip) - -/* Argument info. Used for $#, $* for shell, functions, includes, etc. */ -struct arg_info { - int flags; /* AF_* */ - char **argv; - int argc_; - int skip; /* first arg is argv[0], second is argv[1 + skip] */ -}; - -/* - * activation record for function blocks - */ -struct block { - Area area; /* area to allocate things */ - /*struct arg_info argi;*/ - char **argv; - int argc; - struct table vars; /* local variables */ - struct table funs; /* local functions */ -#if 1 - char * error; /* error handler */ - char * exit; /* exit handler */ -#else - Trap error, exit; -#endif - struct block *next; /* enclosing block */ -}; - -/* - * Used by twalk() and tnext() routines. - */ -struct tstate { - int left; - struct tbl **next; -}; - - -EXTERN struct table taliases; /* tracked aliases */ -EXTERN struct table builtins; /* built-in commands */ -EXTERN struct table aliases; /* aliases */ -EXTERN struct table keywords; /* keywords */ -EXTERN struct table homedirs; /* homedir() cache */ - -struct builtin { - const char *name; - int (*func) ARGS((char **)); -}; - -/* these really are externs! Look in table.c for them */ -extern const struct builtin shbuiltins [], kshbuiltins []; - -/* var spec values */ -#define V_NONE 0 -#define V_PATH 1 -#define V_IFS 2 -#define V_SECONDS 3 -#define V_OPTIND 4 -#define V_MAIL 5 -#define V_MAILPATH 6 -#define V_MAILCHECK 7 -#define V_RANDOM 8 -#define V_HISTSIZE 9 -#define V_HISTFILE 10 -#define V_VISUAL 11 -#define V_EDITOR 12 -#define V_COLUMNS 13 -#define V_POSIXLY_CORRECT 14 -#define V_TMOUT 15 -#define V_TMPDIR 16 - -/* values for set_prompt() */ -#define PS1 0 /* command */ -#define PS2 1 /* command continuation */ - -EXTERN const char *path; /* PATH value */ -EXTERN const char *def_path; /* path to use if PATH not set */ -EXTERN char *tmpdir; /* TMPDIR value */ -EXTERN const char *prompt; -EXTERN int cur_prompt; /* PS1 or PS2 */ diff --git a/bin/pdksh/tests/alias.t b/bin/pdksh/tests/alias.t deleted file mode 100644 index 0db6a2594cd..00000000000 --- a/bin/pdksh/tests/alias.t +++ /dev/null @@ -1,91 +0,0 @@ -name: alias-1 -description: - Check that recursion is detected/avoided in aliases. -stdin: - alias fooBar=fooBar - fooBar - exit 0 -expected-stderr-pattern: - /fooBar.*not found.*/ ---- - -name: alias-2 -description: - Check that recursion is detected/avoided in aliases. -stdin: - alias fooBar=barFoo - alias barFoo=fooBar - fooBar - barFoo - exit 0 -expected-stderr-pattern: - /fooBar.*not found.*\n.*barFoo.*not found/ ---- - -name: alias-3 -description: - Check that recursion is detected/avoided in aliases. -stdin: - alias Echo='echo ' - alias fooBar=barFoo - alias barFoo=fooBar - Echo fooBar - unalias barFoo - Echo fooBar -expected-stdout: - fooBar - barFoo ---- - -name: alias-4 -description: - Check that alias expansion isn't done on keywords (in keyword - postitions). -stdin: - alias Echo='echo ' - alias while=While - while false; do echo hi ; done - Echo while -expected-stdout: - While ---- - -name: alias-5 -description: - Check that alias expansion done after alias with trailing space. -stdin: - alias Echo='echo ' - alias foo='bar stuff ' - alias bar='Bar1 Bar2 ' - alias stuff='Stuff' - alias blah='Blah' - Echo foo blah -expected-stdout: - Bar1 Bar2 Stuff Blah ---- - -name: alias-6 -description: - Check that alias expansion done after alias with trailing space. -stdin: - alias Echo='echo ' - alias foo='bar bar' - alias bar='Bar ' - alias blah=Blah - Echo foo blah -expected-stdout: - Bar Bar Blah ---- - -name: alias-7 -description: - Check that alias expansion done after alias with trailing space - after a keyword. -stdin: - alias X='case ' - alias Y=Z - X Y in 'Y') echo is y ;; Z) echo is z ; esac -expected-stdout: - is z ---- - diff --git a/bin/pdksh/tests/arith.t b/bin/pdksh/tests/arith.t deleted file mode 100644 index e18ea2e9d78..00000000000 --- a/bin/pdksh/tests/arith.t +++ /dev/null @@ -1,79 +0,0 @@ -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/pdksh/tests/bksl-nl.t b/bin/pdksh/tests/bksl-nl.t deleted file mode 100644 index 3fb92ff53b5..00000000000 --- a/bin/pdksh/tests/bksl-nl.t +++ /dev/null @@ -1,339 +0,0 @@ -# -# These tests deal with how \newline is handled in various situations. The -# first group of tests are places where it shouldn't be collapsed, the next -# group of tests are places where it should be collapsed. -# -name: bksl-nl-ign-1 -description: - Check that \newline is not collasped after # -stdin: - echo hi #there \ - echo folks -expected-stdout: - hi - folks ---- - -name: bksl-nl-ign-2 -description: - Check that \newline is not collasped inside single quotes -stdin: - echo 'hi \ - there' - echo folks -expected-stdout: - hi \ - there - folks ---- - -name: bksl-nl-ign-3 -description: - Check that \newline is not collasped inside single quotes -stdin: - cat << \EOF - hi \ - there - EOF -expected-stdout: - hi \ - there ---- - -name: blsk-nl-ign-4 -description: - Check interaction of aliases, single quotes and here-documents - with backslash-newline - (don't know what posix has to say about this) -stdin: - a=2 - alias x='echo hi - cat << "EOF" - foo\ - bar - some' - x - more\ - stuff$a - EOF -expected-stdout: - hi - foo\ - bar - some - more\ - stuff$a ---- - -name: blsk-nl-ign-5 -description: - Check what happens with backslash at end of input - (the old bourne shell trashes them; so do we) -stdin: ! - echo `echo foo\\`bar - echo hi\ -expected-stdout: - foobar - hi ---- - - -# -# Places \newline should be collapsed -# -name: bksl-nl-1 -description: - Check that \newline is collasped before, in the middle of, and - after words -stdin: - \ - echo hi\ - There, \ - folks -expected-stdout: - hiThere, folks ---- - -name: bksl-nl-2 -description: - Check that \newline is collasped in $ sequences - (ksh93 fails this) -stdin: - a=12 - ab=19 - echo $\ - a - echo $a\ - b - echo $\ - {a} - echo ${a\ - b} - echo ${ab\ - } -expected-stdout: - 12 - 19 - 12 - 19 - 19 ---- - -name: bksl-nl-3 -description: - Check that \newline is collasped in $(..) and `...` sequences - (ksh93 fails this) -stdin: - echo $\ - (echo foobar1) - echo $(\ - echo foobar2) - echo $(echo foo\ - bar3) - echo $(echo foobar4\ - ) - echo ` - echo stuff1` - echo `echo st\ - uff2` -expected-stdout: - foobar1 - foobar2 - foobar3 - foobar4 - stuff1 - stuff2 ---- - -name: bksl-nl-4 -description: - Check that \newline is collasped in $((..)) sequences - (ksh93 fails this) -stdin: - echo $\ - ((1+2)) - echo $(\ - (1+2+3)) - echo $((\ - 1+2+3+4)) - echo $((1+\ - 2+3+4+5)) - echo $((1+2+3+4+5+6)\ - ) -expected-stdout: - 3 - 6 - 10 - 15 - 21 ---- - -name: bksl-nl-5 -description: - Check that \newline is collasped in double quoted strings -stdin: - echo "\ - hi" - echo "foo\ - bar" - echo "folks\ - " -expected-stdout: - hi - foobar - folks ---- - -name: bksl-nl-6 -description: - Check that \newline is collasped in here document delimiters - (ksh93 fails second part of this) -stdin: - a=12 - cat << EO\ - F - a=$a - foo\ - bar - EOF - cat << E_O_F - foo - E_O_\ - F - echo done -expected-stdout: - a=12 - foobar - foo - done ---- - -name: bksl-nl-7 -description: - Check that \newline is collasped in double-quoted here-document - delimiter. -stdin: - a=12 - cat << "EO\ - F" - a=$a - foo\ - bar - EOF - echo done -expected-stdout: - a=$a - foo\ - bar - done ---- - -name: bksl-nl-8 -description: - Check that \newline is collasped in various 2+ character tokens - delimiter. - (ksh93 fails this) -stdin: - echo hi &\ - & echo there - echo foo |\ - | echo bar - cat <\ - < EOF - stuff - EOF - cat <\ - <\ - - EOF - more stuff - EOF - cat <<\ - EOF - abcdef - EOF - echo hi >\ - > /dev/null - echo $? - i=1 - case $i in - (\ - x|\ - 1\ - ) echo hi;\ - ; - (*) echo oops - esac -expected-stdout: - hi - there - foo - stuff - more stuff - abcdef - 0 - hi ---- - -name: blsk-nl-9 -description: - Check that \ at the end of an alias is collapsed when followed - by a newline - (don't know what posix has to say about this) -stdin: - alias x='echo hi\' - x - echo there -expected-stdout: - hiecho there ---- - -name: blsk-nl-10 -description: - Check that \newline in a keyword is collapsed -stdin: - i\ - f true; then\ - echo pass; el\ - se echo fail; fi -expected-stdout: - pass ---- - -# -# Places \newline should be collapsed (ksh extensions) -# - -name: blsk-nl-ksh-1 -description: - Check that \newline is collapsed in extended globbing - (ksh93 fails this) -stdin: - xxx=foo - case $xxx in - (f*\ - (\ - o\ - )\ - ) echo ok ;; - *) echo bad - esac -expected-stdout: - ok ---- - -name: blsk-nl-ksh-2 -description: - Check that \newline is collapsed in ((...)) expressions - (ksh93 fails this) -stdin: - i=1 - (\ - (\ - i=i+2\ - )\ - ) - echo $i -expected-stdout: - 3 ---- - diff --git a/bin/pdksh/tests/brkcont.t b/bin/pdksh/tests/brkcont.t deleted file mode 100644 index 1eb9c2581c9..00000000000 --- a/bin/pdksh/tests/brkcont.t +++ /dev/null @@ -1,195 +0,0 @@ -name: break-1 -description: - See if break breaks out of loops -stdin: - for i in a b c; do echo $i; break; echo bad-$i; done - echo end-1 - for i in a b c; do echo $i; break 1; echo bad-$i; done - echo end-2 - for i in a b c; do - for j in x y z; do - echo $i:$j - break - echo bad-$i - done - echo end-$i - done - echo end-3 -expected-stdout: - a - end-1 - a - end-2 - a:x - end-a - b:x - end-b - c:x - end-c - end-3 ---- - -name: break-2 -description: - See if break breaks out of nested loops -stdin: - for i in a b c; do - for j in x y z; do - echo $i:$j - break 2 - echo bad-$i - done - echo end-$i - done - echo end -expected-stdout: - a:x - end ---- - - -name: break-3 -description: - What if break used outside of any loops - (ksh88,ksh93 don't print error messages here) -stdin: - break -expected-stderr-pattern: - /.*break.*/ ---- - - -name: break-4 -description: - What if break N used when only N-1 loops - (ksh88,ksh93 don't print error messages here) -stdin: - for i in a b c; do echo $i; break 2; echo bad-$i; done - echo end -expected-stdout: - a - end -expected-stderr-pattern: - /.*break.*/ ---- - - -name: break-5 -description: - Error if break argument isn't a number -stdin: - for i in a b c; do echo $i; break abc; echo more-$i; done - echo end -expected-stdout: - a -expected-exit: e != 0 -expected-stderr-pattern: - /.*break.*/ ---- - - -name: continue-1 -description: - See if continue continues loops -stdin: - for i in a b c; do echo $i; continue; echo bad-$i ; done - echo end-1 - for i in a b c; do echo $i; continue 1; echo bad-$i; done - echo end-2 - for i in a b c; do - for j in x y z; do - echo $i:$j - continue - echo bad-$i-$j - done - echo end-$i - done - echo end-3 -expected-stdout: - a - b - c - end-1 - a - b - c - end-2 - a:x - a:y - a:z - end-a - b:x - b:y - b:z - end-b - c:x - c:y - c:z - end-c - end-3 ---- - - -name: continue-2 -description: - See if continue breaks out of nested loops -stdin: - for i in a b c; do - for j in x y z; do - echo $i:$j - continue 2 - echo bad-$i-$j - done - echo end-$i - done - echo end -expected-stdout: - a:x - b:x - c:x - end ---- - - -name: continue-3 -description: - What if continue used outside of any loops - (ksh88,ksh93 don't print error messages here) -stdin: - continue -expected-stderr-pattern: - /.*continue.*/ ---- - - -name: continue-4 -description: - What if continue N used when only N-1 loops - (ksh88,ksh93 don't print error messages here) -stdin: - for i in a b c; do echo $i; continue 2; echo bad-$i; done - echo end -expected-stdout: - a - b - c - end -expected-stderr-pattern: - /.*continue.*/ ---- - - -name: continue-5 -description: - Error if continue argument isn't a number -stdin: - for i in a b c; do echo $i; continue abc; echo more-$i; done - echo end -expected-stdout: - a -expected-exit: e != 0 -expected-stderr-pattern: - /.*continue.*/ ---- - - diff --git a/bin/pdksh/tests/cdhist.t b/bin/pdksh/tests/cdhist.t deleted file mode 100644 index 720f7d60bcc..00000000000 --- a/bin/pdksh/tests/cdhist.t +++ /dev/null @@ -1,160 +0,0 @@ -name: cd-history -description: - Test someone's CD history package (uses arrays) -stdin: - # go to known place before doing anything - cd / - - alias cd=_cd - function _cd - { - typeset -i cdlen i - typeset t - - if [ $# -eq 0 ] - then - set -- $HOME - fi - - if [ "$CDHISTFILE" -a -r "$CDHISTFILE" ] # if directory history exists - then - typeset CDHIST - i=-1 - while read -r t # read directory history file - do - CDHIST[i=i+1]=$t - done <$CDHISTFILE - fi - - if [ "${CDHIST[0]}" != "$PWD" -a "$PWD" != "" ] - then - _cdins # insert $PWD into cd history - fi - - cdlen=${#CDHIST[*]} # number of elements in history - - case "$@" in - -) # cd to new dir - if [ "$OLDPWD" = "" ] && ((cdlen>1)) - then - 'print' ${CDHIST[1]} - 'cd' ${CDHIST[1]} - _pwd - else - 'cd' $@ - _pwd - fi - ;; - -l) # print directory list - typeset -R3 num - ((i=cdlen)) - while (((i=i-1)>=0)) - do - num=$i - 'print' "$num ${CDHIST[i]}" - done - return - ;; - -[0-9]|-[0-9][0-9]) # cd to dir in list - if (((i=${1#-})<cdlen)) - then - 'print' ${CDHIST[i]} - 'cd' ${CDHIST[i]} - _pwd - else - 'cd' $@ - _pwd - fi - ;; - -*) # cd to matched dir in list - t=${1#-} - i=1 - while ((i<cdlen)) - do - case ${CDHIST[i]} in - *$t*) - 'print' ${CDHIST[i]} - 'cd' ${CDHIST[i]} - _pwd - break - ;; - esac - ((i=i+1)) - done - if ((i>=cdlen)) - then - 'cd' $@ - _pwd - fi - ;; - *) # cd to new dir - 'cd' $@ - _pwd - ;; - esac - - _cdins # insert $PWD into cd history - - if [ "$CDHISTFILE" ] - then - cdlen=${#CDHIST[*]} # number of elements in history - - i=0 - while ((i<cdlen)) - do - 'print' -r ${CDHIST[i]} # update directory history - ((i=i+1)) - done >$CDHISTFILE - fi - } - - function _cdins # insert $PWD into cd history - { # meant to be called only by _cd - typeset -i i - - ((i=0)) - while ((i<${#CDHIST[*]})) # see if dir is already in list - do - if [ "${CDHIST[$i]}" = "$PWD" ] - then - break - fi - ((i=i+1)) - done - - if ((i>22)) # limit max size of list - then - i=22 - fi - - while (((i=i-1)>=0)) # bump old dirs in list - do - CDHIST[i+1]=${CDHIST[i]} - done - - CDHIST[0]=$PWD # insert new directory in list - } - - - function _pwd - { - if [ -n "$ECD" ] - then - pwd 1>&6 - fi - } - # Start of test - cd /tmp - cd /bin - cd /etc - cd - - cd -2 - cd -l -expected-stdout: - /bin - /tmp - 3 / - 2 /etc - 1 /bin - 0 /tmp ---- diff --git a/bin/pdksh/tests/eglob.t b/bin/pdksh/tests/eglob.t deleted file mode 100644 index ea69f635fcf..00000000000 --- a/bin/pdksh/tests/eglob.t +++ /dev/null @@ -1,138 +0,0 @@ -name: eglob-bad-1 -description: - Check that globbing isn't done when glob has syntax error -perl-setup: - &touch("abcx", "abcz", "bbc"); -stdin: - echo !([*)* - echo +(a|b[)* -expected-stdout: - !([*)* - +(a|b[)* ---- - -name: eglob-bad-2 -description: - Check that globbing isn't done when glob has syntax error - (at&t ksh fails this test) -perl-setup: - &touch("abcx", "abcz", "bbc"); -stdin: - echo [a*(]*)z -expected-stdout: - [a*(]*)z ---- - -name: eglob-infinite-plus -description: - Check that shell doesn't go into infinite loop expanding +(...) - expressions. -perl-setup: - &touch("abc"); -time-limit: 3 -stdin: - echo +()c - echo +()x - echo +(*)c - echo +(*)x -expected-stdout: - +()c - +()x - abc - +(*)x ---- - -name: eglob-subst-1 -description: - Check that eglobbing isn't done on substitution results -perl-setup: - &touch("abc"); -stdin: - x='@(*)' - echo $x -expected-stdout: - @(*) ---- - -name: eglob-nomatch-1 -description: - Check that the pattern doesn't match -stdin: - echo no-file+(a|b)stuff - echo no-file+(a*(c)|b)stuff -expected-stdout: - no-file+(a|b)stuff - no-file+(a*(c)|b)stuff ---- - -name: eglob-match-1 -description: - Check that the pattern matches correctly -perl-setup: - &touch("abd", "acd"); -stdin: - echo a+(b|c)d - echo a!(@(b|B))d - echo a[b*(foo|bar)]d -expected-stdout: - abd acd - acd - abd ---- - -name: eglob-case-1 -description: - Simple negation tests -stdin: - case foo in !(foo|bar)) echo yes;; *) echo no;; esac - case bar in !(foo|bar)) echo yes;; *) echo no;; esac -expected-stdout: - no - no ---- - -name: eglob-case-2 -description: - Simple kleene tests -stdin: - case foo in *(a|b[)) echo yes;; *) echo no;; esac - case foo in *(a|b[)|f*) echo yes;; *) echo no;; esac - case '*(a|b[)' in *(a|b[)) echo yes;; *) echo no;; esac -expected-stdout: - no - yes - yes ---- - -name: eglob-trim-1 -description: - Eglobing in trim expressions... - (at&t ksh fails this - docs say # matches shortest string, ## matches - longest...) -stdin: - x=abcdef - echo 1: ${x#a|abc} - echo 2: ${x##a|abc} - echo 3: ${x%def|f} - echo 4: ${x%%f|def} -expected-stdout: - 1: bcdef - 2: def - 3: abcde - 4: abc ---- - -name: eglob-trim-2 -description: - Check eglobing works in trims... -stdin: - x=abcdef - echo ${x#*(a|b)cd} - echo "${x#*(a|b)cd}" - echo ${x#"*(a|b)cd"} -expected-stdout: - ef - ef - abcdef ---- - diff --git a/bin/pdksh/tests/glob.t b/bin/pdksh/tests/glob.t deleted file mode 100644 index c7d8e26808d..00000000000 --- a/bin/pdksh/tests/glob.t +++ /dev/null @@ -1,96 +0,0 @@ -name: glob-bad-1 -description: - Check that globbing isn't done when glob has syntax error -perl-setup: - mkdir("[x", 0777) || die "couldn't make directory [x - $!\n"; - &touch("[x/foo"); -stdin: - echo [* - echo *[x - echo [x/* -expected-stdout: - [* - *[x - [x/foo ---- - -name: glob-bad-2 -description: - Check that symbolic links aren't stat()'d -perl-setup: - mkdir("dir", 0777) || die "couldn't make directory dir - $!\n"; - &touch("dir/abc"); - symlink("non-existent-file", "dir/abc"); -stdin: - echo d*/* - echo d*/abc -expected-stdout: - dir/abc - dir/abc ---- - -name: glob-range-1 -description: - Test range matching -perl-setup: - &touch(".bc", "abc", "bbc", "cbc", "-bc"); -stdin: - echo [ab-]* - echo [-ab]* - echo [!-ab]* - echo [!ab]* - echo []ab]* -expected-stdout: - -bc abc bbc - -bc abc bbc - cbc - -bc cbc - abc bbc ---- - -name: glob-range-2 -description: - Test range matching - (at&t ksh fails this; POSIX says invalid) -perl-setup: - &touch("abc"); -stdin: - echo [a--]* -expected-stdout: - [a--]* ---- - -name: glob-range-3 -description: - Check that globbing matches the right things... -perl-setup: - &touch("a\302c"); -stdin: - echo a[Á-Ú]* -expected-stdout: - aÂc ---- - -name: glob-range-4 -description: - Results unspecified according to POSIX -perl-setup: - &touch(".bc"); -stdin: - echo [a.]* -expected-stdout: - [a.]* ---- - -name: glob-range-5 -description: - Results unspecified according to POSIX - (at&t ksh treats this like [a-cc-e]*) -perl-setup: - &touch("abc", "bbc", "cbc", "dbc", "ebc", "-bc"); -stdin: - echo [a-c-e]* -expected-stdout: - -bc abc bbc cbc ebc ---- - diff --git a/bin/pdksh/tests/heredoc.t b/bin/pdksh/tests/heredoc.t deleted file mode 100644 index 21feb925cea..00000000000 --- a/bin/pdksh/tests/heredoc.t +++ /dev/null @@ -1,144 +0,0 @@ -name: heredoc-1 -description: - Check ordering/content of redundent here documents. -stdin: - cat << EOF1 << EOF2 - hi - EOF1 - there - EOF2 -expected-stdout: - there ---- - -name: heredoc-2 -description: - Check quoted here-doc is protected. -stdin: - a=foo - cat << 'EOF' - hi\ - there$a - stuff - EO\ - F - EOF -expected-stdout: - hi\ - there$a - stuff - EO\ - F ---- - -name: heredoc-3 -description: - Check that newline isn't needed after heredoc-delimiter marker. -stdin: ! - cat << EOF - hi - there - EOF -expected-stdout: - hi - there ---- - -name: heredoc-4 -description: - Check that an error occurs if the heredoc-delimiter is missing. -stdin: ! - cat << EOF - hi - there -expected-exit: e > 0 -expected-stderr-pattern: /.*/ ---- - -name: heredoc-5 -description: - Check that backslash quotes a $, ` and \ and kills a \newline -stdin: - a=BAD - b=ok - cat << EOF - h\${a}i - h\\${b}i - th\`echo not-run\`ere - th\\`echo is-run`ere - fol\\ks - more\\ - last \ - line - EOF -expected-stdout: - h${a}i - h\oki - th`echo not-run`ere - th\is-runere - fol\ks - more\ - last line ---- - -name: heredoc-6 -description: - Check that \newline in initial here-delim word doesn't imply - a quoted here-doc. -stdin: - a=i - cat << EO\ - F - h$a - there - EOF -expected-stdout: - hi - there ---- - -name: heredoc-7 -description: - Check that double quoted $ expressions in here delimiters are - not expanded and match the delimiter. - POSIX says only quote removal is applied to the delimiter. -stdin: - a=b - cat << "E$a" - hi - h$a - hb - E$a - echo done -expected-stdout: - hi - h$a - hb - done ---- - -name: heredoc-8 -description: - Check that double quoted escaped $ expressions in here - delimiters are not expanded and match the delimiter. - POSIX says only quote removal is applied to the delimiter - (\ counts as a quote). -stdin: - a=b - cat << "E\$a" - hi - h$a - h\$a - hb - h\b - E$a - echo done -expected-stdout: - hi - h$a - h\$a - hb - h\b - done ---- - diff --git a/bin/pdksh/tests/history.t b/bin/pdksh/tests/history.t deleted file mode 100644 index 078aeb60969..00000000000 --- a/bin/pdksh/tests/history.t +++ /dev/null @@ -1,529 +0,0 @@ -# Not tested yet: -# - commands in history file are not numbered negatively -# (and a few hundred other things) - -name: history-basic -description: - See if we can test history at all -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo hi - fc -l -expected-stdout: - hi - 1 echo hi -expected-stderr-pattern: - /^X*$/ ---- - -name: history-e-minus-1 -description: - Check if more recent command is executed -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo hi - echo there - fc -e - -expected-stdout: - hi - there - there -expected-stderr-pattern: - /^X*echo there\nX*$/ ---- - -name: history-e-minus-2 -description: - Check that repeated command is printed before command - is re-executed. -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - exec 2>&1 - echo hi - echo there - fc -e - -expected-stdout-pattern: - /X*hi\nX*there\nX*echo there\nthere\nX*/ -expected-stderr-pattern: - /^X*$/ ---- - -name: history-e-minus-3 -description: - fc -e - fails when there is no history - (ksh93 has a bug that causes this to fail) - (ksh88 loops on this) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - fc -e - - echo ok -expected-stdout: - ok -expected-stderr-pattern: - /^X*.*:.*history.*\nX*$/ ---- - -name: history-e-minus-4 -description: - Check if "fc -e -" command output goes to stdout. -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc - fc -e - | (read x; echo "A $x") - echo ok -expected-stdout: - abc - A abc - ok -expected-stderr-pattern: - /^X*echo abc\nX*/ ---- - -name: history-e-minus-5 -description: - fc is replaced in history by new command. -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - echo ghi jkl - fc -e - echo - fc -l 2 4 -expected-stdout: - abc def - ghi jkl - ghi jkl - 2 echo ghi jkl - 3 echo ghi jkl - 4 fc -l 2 4 -expected-stderr-pattern: - /^X*echo ghi jkl\nX*$/ ---- - -name: history-list-1 -description: - List lists correct range - (ksh88 fails 'cause it lists the fc command) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - fc -l -- -2 -expected-stdout: - line 1 - line 2 - line 3 - 2 echo line 2 - 3 echo line 3 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-2 -description: - Lists oldest history if given pre-historic number - (ksh93 has a bug that causes this to fail) - (ksh88 fails 'cause it lists the fc command) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - fc -l -- -40 -expected-stdout: - line 1 - line 2 - line 3 - 1 echo line 1 - 2 echo line 2 - 3 echo line 3 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-3 -description: - Can give number `options' to fc -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - fc -l -3 -2 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - 2 echo line 2 - 3 echo line 3 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-4 -description: - -1 refers to previous command -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - fc -l -1 -1 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - 4 echo line 4 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-5 -description: - List command stays in history -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - fc -l -1 -1 - fc -l -2 -1 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - 4 echo line 4 - 4 echo line 4 - 5 fc -l -1 -1 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-6 -description: - HISTSIZE limits about of history kept. - (ksh88 fails 'cause it lists the fc command) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - echo line 5 - fc -l -expected-stdout: - line 1 - line 2 - line 3 - line 4 - line 5 - 4 echo line 4 - 5 echo line 5 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-7 -description: - fc allows too old/new errors in range specification -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - echo line 5 - fc -l 1 30 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - line 5 - 4 echo line 4 - 5 echo line 5 - 6 fc -l 1 30 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-r-1 -description: - test -r flag in history -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - echo line 5 - fc -l -r 2 4 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - line 5 - 4 echo line 4 - 3 echo line 3 - 2 echo line 2 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-r-2 -description: - If first is newer than last, -r is implied. -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - echo line 5 - fc -l 4 2 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - line 5 - 4 echo line 4 - 3 echo line 3 - 2 echo line 2 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-list-r-3 -description: - If first is newer than last, -r is cancelled. -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 - echo line 3 - echo line 4 - echo line 5 - fc -l -r 4 2 -expected-stdout: - line 1 - line 2 - line 3 - line 4 - line 5 - 2 echo line 2 - 3 echo line 3 - 4 echo line 4 -expected-stderr-pattern: - /^X*$/ ---- - -name: history-subst-1 -description: - Basic substitution -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - echo ghi jkl - fc -e - abc=AB 'echo a' -expected-stdout: - abc def - ghi jkl - AB def -expected-stderr-pattern: - /^X*echo AB def\nX*$/ ---- - -name: history-subst-2 -description: - Does subst find previous command? -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - echo ghi jkl - fc -e - jkl=XYZQRT 'echo g' -expected-stdout: - abc def - ghi jkl - ghi XYZQRT -expected-stderr-pattern: - /^X*echo ghi XYZQRT\nX*$/ ---- - -name: history-subst-3 -description: - Does subst find previous command when no arguments given -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - echo ghi jkl - fc -e - jkl=XYZQRT -expected-stdout: - abc def - ghi jkl - ghi XYZQRT -expected-stderr-pattern: - /^X*echo ghi XYZQRT\nX*$/ ---- - -name: history-subst-4 -description: - Global substitutions work - (ksh88 and ksh93 do not have -g option) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def asjj sadjhasdjh asdjhasd - fc -e - -g a=FooBAR -expected-stdout: - abc def asjj sadjhasdjh asdjhasd - FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd -expected-stderr-pattern: - /^X*echo FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd\nX*$/ ---- - -name: history-subst-5 -description: - Make sure searches don't find current (fc) command - (ksh88/ksh93 don't have the ? prefix thing so they fail this test) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - echo ghi jkl - fc -e - abc=AB \?abc -expected-stdout: - abc def - ghi jkl - AB def -expected-stderr-pattern: - /^X*echo AB def\nX*$/ ---- - -name: history-ed-1 -description: - Basic (ed) editing works (assumes you have generic ed editor - that prints no prompts). -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - fc echo - s/abc/FOOBAR/ - w - q -expected-stdout: - abc def - 13 - 16 - FOOBAR def -expected-stderr-pattern: - /^X*echo FOOBAR def\nX*$/ ---- - -name: history-ed-2 -description: - Correct command is edited when number given -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo line 1 - echo line 2 is here - echo line 3 - echo line 4 - fc 2 - s/is here/is changed/ - w - q -expected-stdout: - line 1 - line 2 is here - line 3 - line 4 - 20 - 23 - line 2 is changed -expected-stderr-pattern: - /^X*echo line 2 is changed\nX*$/ ---- - -name: history-ed-3 -description: - Newly created multi line commands show up as single command - in history. - (NOTE: will fail if using COMPLEX HISTORY compile time option) - (ksh88 fails 'cause it lists the fc command) -arguments: !-i! -env-setup: !ENV=./Env!HISTFILE=hist.file! -perl-setup: system("echo PS1=X > Env"); -stdin: - echo abc def - fc echo - s/abc/FOOBAR/ - $a - echo a new line - . - w - q - fc -l -expected-stdout: - abc def - 13 - 32 - FOOBAR def - a new line - 1 echo abc def - 2 echo FOOBAR def - echo a new line -expected-stderr-pattern: - /^X*echo FOOBAR def\necho a new line\nX*$/ ---- diff --git a/bin/pdksh/tests/ifs.t b/bin/pdksh/tests/ifs.t deleted file mode 100644 index a927aa301fc..00000000000 --- a/bin/pdksh/tests/ifs.t +++ /dev/null @@ -1,162 +0,0 @@ -name: IFS-space-1 -description: - Simple test, default IFS -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - set -- A B C - showargs 1 $* - showargs 2 "$*" - showargs 3 $@ - showargs 4 "$@" -expected-stdout: - <1> <A> <B> <C> - <2> <A B C> - <3> <A> <B> <C> - <4> <A> <B> <C> ---- - -name: IFS-colon-1 -description: - Simple test, IFS=: -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS=: - set -- A B C - showargs 1 $* - showargs 2 "$*" - showargs 3 $@ - showargs 4 "$@" -expected-stdout: - <1> <A> <B> <C> - <2> <A:B:C> - <3> <A> <B> <C> - <4> <A> <B> <C> ---- - -name: IFS-null-1 -description: - Simple test, IFS="" -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="" - set -- A B C - showargs 1 $* - showargs 2 "$*" - showargs 3 $@ - showargs 4 "$@" -expected-stdout: - <1> <A B C> - <2> <ABC> - <3> <A B C> - <4> <A B C> ---- - -name: IFS-space-colon-1 -description: - Simple test, IFS=<white-space>: -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="IFS:" - set -- - showargs 1 $* - showargs 2 "$*" - showargs 3 $@ - showargs 4 "$@" - showargs 5 : "$@" -expected-stdout: - <1> - <2> <> - <3> - <4> - <5> <:> ---- - -name: IFS-space-colon-2 -description: - Simple test, IFS=<white-space>: - At&t ksh fails this, POSIX says the test is correct. -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="IFS:" - set -- - showargs :"$@" -expected-stdout: - <:> ---- - -name: IFS-space-colon-3 -description: - Simple test, IFS=<white-space>: - pdksh fails both of these tests -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="IFS:" - x= - set -- - showargs "$x$@" - showargs "$@$x" -expected-fail: yes -expected-stdout: - <> - <> ---- - -name: IFS-space-colon-4 -description: - Simple test, IFS=<white-space>: -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="IFS:" - set -- - showargs "$@$@" -expected-stdout: - ---- - -name: IFS-space-colon-5 -description: - Simple test, IFS=<white-space>: - Don't know what POSIX thinks of this. at&t ksh does not do this. -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="IFS:" - set -- - showargs "${@:-}" -expected-stdout: - <> ---- - -name: IFS-subst-1 -description: - Simple test, IFS=<white-space>: -stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } - IFS="$IFS:" - x=":b: :" - echo -n '1:'; for i in $x ; do echo -n " [$i]" ; done ; echo - echo -n '2:'; for i in :b:: ; do echo -n " [$i]" ; done ; echo - showargs 3 $x - showargs 4 :b:: - x="a:b:" - echo -n '5:'; for i in $x ; do echo -n " [$i]" ; done ; echo - showargs 6 $x - x="a::c" - echo -n '7:'; for i in $x ; do echo -n " [$i]" ; done ; echo - showargs 8 $x - echo -n '9:'; for i in ${FOO-`echo -n h:i`th:ere} ; do echo -n " [$i]" ; done ; echo - showargs 10 ${FOO-`echo -n h:i`th:ere} - showargs 11 "${FOO-`echo -n h:i`th:ere}" -expected-stdout: - 1: [] [b] [] [] - 2: [:b::] - <3> <> <b> <> <> - <4> <:b::> - 5: [a] [b] [] - <6> <a> <b> <> - 7: [a] [] [c] - <8> <a> <> <c> - 9: [h] [ith] [ere] - <10> <h> <ith> <ere> - <11> <h:ith:ere> ---- - diff --git a/bin/pdksh/tests/integer.t b/bin/pdksh/tests/integer.t deleted file mode 100644 index 7e39612b3ff..00000000000 --- a/bin/pdksh/tests/integer.t +++ /dev/null @@ -1,218 +0,0 @@ -name: integer-base-err-1 -description: - Can't have 0 base (causes shell to exit) -expected-exit: e != 0 -stdin: - typeset -i i - i=3 - i=0#4 - echo $i -expected-stderr-pattern: - /^.*:.*0#4.*\n$/ ---- - -name: integer-base-err-2 -description: - Can't have multiple bases in a `constant' (causes shell to exit) - (ksh88 fails this test) -expected-exit: e != 0 -stdin: - typeset -i i - i=3 - i=2#110#11 - echo $i -expected-stderr-pattern: - /^.*:.*2#110#11.*\n$/ ---- - -name: integer-base-err-3 -description: - Syntax errors in expressions and effects on bases - (interactive so errors don't cause exits) - (ksh88 fails this test - shell exits, even with -i) -arguments: !-i! -stdin: - PS1= # minimize prompt hassles - typeset -i4 a=10 - typeset -i a=2+ - echo $a - typeset -i4 a=10 - typeset -i2 a=2+ - echo $a -expected-stderr-pattern: - /^([#\$] )?.*:.*2+.*\n.*:.*2+.*\n$/ -expected-stdout: - 4#22 - 4#22 ---- - -name: integer-base-err-4 -description: - Are invalid digits (according to base) errors? - (ksh93 fails this test) -expected-exit: e != 0 -stdin: - typeset -i i; - i=3#4 -expected-stderr-pattern: - /^([#\$] )?.*:.*3#4.*\n$/ ---- - - -name: integer-base-1 -description: - Missing number after base is treated as 0. -stdin: - typeset -i i - i=3 - i=2# - echo $i -expected-stdout: - 0 ---- - -name: integer-base-2 -description: - Check `stickyness' of base in various situations -stdin: - typeset -i i=8 - echo $i - echo ---------- A - typeset -i4 j=8 - echo $j - echo ---------- B - typeset -i k=8 - typeset -i4 k=8 - echo $k - echo ---------- C - typeset -i4 l - l=3#10 - echo $l - echo ---------- D - typeset -i m - m=3#10 - echo $m - echo ---------- E - n=2#11 - typeset -i n - echo $n - n=10 - echo $n - echo ---------- F - typeset -i8 o=12 - typeset -i4 o - echo $o - echo ---------- G - typeset -i p - let p=8#12 - echo $p -expected-stdout: - 8 - ---------- A - 4#20 - ---------- B - 4#20 - ---------- C - 4#3 - ---------- D - 3#10 - ---------- E - 2#11 - 2#1010 - ---------- F - 4#30 - ---------- G - 8#12 ---- - -name: integer-base-3 -description: - More base parsing (hmm doesn't test much..) -stdin: - typeset -i aa - aa=1+12#10+2 - echo $aa - typeset -i bb - bb=1+$aa - echo $bb - typeset -i bb - bb=$aa - echo $bb - typeset -i cc - cc=$aa - echo $cc -expected-stdout: - 15 - 16 - 15 - 15 ---- - -name: integer-base-4 -description: - Check that things not declared as integers are not made integers, - also, check if base is not reset by -i with no arguments. - (ksh93 fails - prints 10#20 - go figure) -stdin: - xx=20 - let xx=10 - typeset -i | grep '^xx=' - typeset -i4 a=10 - typeset -i a=20 - echo $a -expected-stdout: - 4#110 ---- - -name: integer-base-5 -description: - More base stuff -stdin: - typeset -i4 a=3#10 - echo $a - echo -- - typeset -i j=3 - j=~3 - echo $j - echo -- - typeset -i k=1 - x[k=k+1]=3 - echo $k - echo -- - typeset -i l - for l in 1 2+3 4; do echo $l; done -expected-stdout: - 4#3 - -- - -4 - -- - 2 - -- - 1 - 5 - 4 ---- - -name: integer-base-6 -description: - Even more base stuff - (ksh93 fails this test - prints 0) -stdin: - typeset -i7 i - i= - echo $i -expected-stdout: - 7#0 ---- - -name: integer-base-7 -description: - Check that non-integer parameters don't get bases assigned -stdin: - echo $(( zz = 8#100 )) - echo $zz -expected-stdout: - 64 - 64 ---- - diff --git a/bin/pdksh/tests/read.t b/bin/pdksh/tests/read.t deleted file mode 100644 index aced86adc32..00000000000 --- a/bin/pdksh/tests/read.t +++ /dev/null @@ -1,56 +0,0 @@ -# -# To test: -# POSIX: -# - if no -r, \ is escape character -# - \newline disappear -# - \<IFS> -> don't break here -# - \<anything-else> -> <anything-else> -# - if -r, backslash is not special -# - if stdin is tty and shell interactive -# - prompt for continuation if \newline (prompt to stderr) -# - a here-document isn't terminated after newline ???? -# - remaining vars set to empty string (not null) -# - check field splitting -# - left over fields and their seperators assigned to last var -# - exit status is normally 0 -# - exit status is > 0 on eof -# - exit status > 0 on error -# - signals interrupt reads -# extra: -# - can't change read-only variables -# - error if var name bogus -# - set -o allexport effects read -# ksh: -# x check default variable: REPLY -# - check -p, -s, -u options -# - check var?prompt stuff -# - "echo a b | read x y" sets x,y in parent shell (at&t) -# -name: read-IFS-1 -description: - Simple test, default IFS -stdin: - echo "A B " > IN - unset x y z - read x y z < IN - echo 1: "x[$x] y[$y] z[$z]" - echo 1a: ${z-z not set} - read x < IN - echo 2: "x[$x]" -expected-stdout: - 1: x[A] y[B] z[] - 1a: - 2: x[A B] ---- - -name: read-ksh-1 -description: - If no var specified, REPLY is used -stdin: - echo "abc" > IN - read < IN - echo "[$REPLY]"; -expected-stdout: - [abc] ---- - diff --git a/bin/pdksh/tests/regress.t b/bin/pdksh/tests/regress.t deleted file mode 100644 index 675ae53497a..00000000000 --- a/bin/pdksh/tests/regress.t +++ /dev/null @@ -1,770 +0,0 @@ -# -# The first 39 of these tests are from the old Bugs script. -# - -name: regression-1 -description: - Lex array code had problems with this. -stdin: - echo foo[ - n=bar - echo "hi[ $n ]=1" -expected-stdout: - foo[ - hi[ bar ]=1 ---- - - -name: regression-2 -description: - When PATH is set before running a command, the new path is - not used in doing the path search - $ echo echo hi > /tmp/q ; chmod a+rx /tmp/q - $ PATH=/tmp q - q: not found - $ - in comexec() the two lines - while (*vp != NULL) - (void) typeset(*vp++, xxx, 0); - need to be moved out of the switch to before findcom() is - called - I don't know what this will break. -stdin: - : ${PWD:-`pwd 2> /dev/null`} - : ${PWD:?"PWD not set - can't do test"} - mkdir Y - cat > Y/xxxscript << EOF - #!/bin/sh - # Need to restore path so echo can be found (some shells don't have - # it as a built-in) - PATH=\$OLDPATH - echo hi - exit 0 - EOF - chmod a+rx Y/xxxscript - export OLDPATH="$PATH" - PATH=$PWD/Y xxxscript - exit $? -expected-stdout: - hi ---- - - -# -# 3. Sun OS 4.0.x (This seems to be a problem with sun's PENDIN not being done -# properly) -# sleep 5^J ls^J ls^J ls [only first ls runs] -# vi ... ZZ (while waiting type) [some of the input gets eaten] -# [not present in SunOS 4.1.x] -#echo " [No automatic test for bug 3 - interactive]" - - -# -# 4. (fixed) -# -#echo " [Don't know what bug 4 was]" - - -# -# 5. Everywhere -# File name completion (^X,*) does not mesh well with cd and -# symbolic links. cd does path simplification wrt $PWD before -# doing the actual chdir(), while file name completion does -# not do the simplification. E.g., you are in directory A -# which has a symbolic link to directory B, you create a file -# called foobar and you then cd to the symlink to B, and type -# $ echo ../foo^X -# and the shell beeps at you. Would be more consistent to -# do the completion after simplifing the `$PWD/..'. -#echo " [No automatic test for bug 5 - interactive]" - - -name: regression-6 -description: - Parsing of $(..) expressions is non-optimal. It is - impossible to have any parentheses inside the expression. - I.e., - $ ksh -c 'echo $(echo \( )' - no closing quote - $ ksh -c 'echo $(echo "(" )' - no closing quote - $ - The solution is to hack the parsing clode in lex.c, the - question is how to hack it: should any parentheses be - escaped by a backslash, or should recursive parsing be done - (so quotes could also be used to hide hem). The former is - easier, the later better... -stdin: - echo $(echo \() -expected-stdout: - ( ---- - - -# -# 7. (fixed) -# -#echo " [Don't know what bug 7 was]" - - -# -# 8. Everywhere - NOT A BUG - this is what at&t ksh88 does -# Strange typset -x behaviour in functions. The following function -# does not set the environment variable BLAH outside the function: -# function blah -# { -# typeset -x BLAH=foobar -# } -# This function does work: -# function blah -# { BLAH=foobar; export BLAH -# } -#echo ' [Bug 8 was bogus]' - - -name: regression-9 -description: - Continue in a for loop does not work right: - for i in a b c ; do - if [ $i = b ] ; then - continue - fi - echo $i - done - Prints a forever... -stdin: - first=yes - for i in a b c ; do - if [ $i = b ] ; then - if [ $first = no ] ; then - echo 'continue in for loop broken' - break # hope break isn't broken too :-) - fi - first=no - continue - fi - done - echo bye -expected-stdout: - bye ---- - - -name: regression-10 -description: - The following: - set -- `false` - echo $? - shoud not print 0. (according to /bin/sh, at&t ksh88, and the - getopt(1) man page - not according to POSIX) -stdin: - set -- `false` - echo $? -expected-stdout: - 1 ---- - - -name: regression-11 -description: - The following: - x=/foo/bar/blah - echo ${x##*/} - should echo blah but on some machines echos /foo/bar/blah. -stdin: - x=/foo/bar/blah - echo ${x##*/} -expected-stdout: - blah ---- - - -name: regression-12 -description: - Both of the following echos produce the same output under sh/ksh.att: - #!/bin/sh - x="foo bar" - echo "`echo \"$x\"`" - echo "`echo "$x"`" - pdksh produces different output for the former (foo instead of foo\tbar) -stdin: - x="foo bar" - echo "`echo \"$x\"`" - echo "`echo "$x"`" -expected-stdout: - foo bar - foo bar ---- - - -name: regression-13 -description: - The following command hangs forever: - $ (: ; cat /etc/termcap) | sleep 2 - This is because the shell forks a shell to run the (..) command - and this shell has the pipe open. When the sleep dies, the cat - doesn't get a SIGPIPE 'cause a process (ie, the second shell) - still has the pipe open. - - NOTE: this test provokes a bizarre bug in ksh93 (shell starts reading - commands from /etc/termcap..) -time-limit: 10 -stdin: - echo A line of text that will be duplicated quite a number of times.> t1 - cat t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 > t2 - cat t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 > t1 - cat t1 t1 t1 t1 > t2 - (: ; cat t2) | sleep 1 ---- - - -name: regression-14 -description: - The command - $ (foobar) 2> /dev/null - generates no output under /bin/sh, but pdksh produces the error - foobar: not found - Also, the command - $ foobar 2> /dev/null - generates an error under /bin/sh and pdksh, but at&t ksh88 produces - no error (redirected to /dev/null). -stdin: - (you/should/not/see/this/error/1) 2> /dev/null - you/should/not/see/this/error/2 2> /dev/null - true ---- - - -name: regression-15 -description: - The command - $ whence foobar - generates a blank line under pdksh and sets the exit status to 0. - at&t ksh88 generates no output and sets the exit status to 1. Also, - the command - $ whence foobar cat - generates no output under at&t ksh88 (pdksh generates a blank line - and /bin/cat). -stdin: - whence does/not/exist > /dev/null - echo 1: $? - echo 2: $(whence does/not/exist | wc -l) - echo 3: $(whence does/not/exist cat | wc -l) -expected-stdout: - 1: 1 - 2: 0 - 3: 0 ---- - - -name: regression-16 -description: - ${var%%expr} seems to be broken in many places. On the mips - the commands - $ read line < /etc/passwd - $ echo $line - root:0:1:... - $ echo ${line%%:*} - root - $ echo $line - root - $ - change the value of line. On sun4s & pas, the echo ${line%%:*} doesn't - work. Haven't checked elsewhere... -script: - read x - y=$x - echo ${x%%:*} - echo $x -stdin: - root:asdjhasdasjhs:0:1:Root:/:/bin/sh -expected-stdout: - root - root:asdjhasdasjhs:0:1:Root:/:/bin/sh ---- - - -name: regression-17 -description: - The command - . /foo/bar - should set the exit status to non-zero (sh and at&t ksh88 do). - XXX doting a non existant file is a fatal error for a script -stdin: - . does/not/exist -expected-exit: e != 0 -expected-stderr-pattern: /.?/ ---- - - -# -# 18. Everywhere -# In vi mode ^X (and *) can dump core: -# $ ab[cd^XMemory fault (core dumped) -#echo " [No automatic test for bug 18 - interactive]" - - -name: regression-19 -description: - Both of the following echos should produce the same thing, but don't: - $ x=foo/bar - $ echo ${x%/*} - foo - $ echo "${x%/*}" - foo/bar -stdin: - x=foo/bar - echo "${x%/*}" -expected-stdout: - foo ---- - - -# -# 20. (same as 18) -# - - -name: regression-21 -description: - backslash does not work as expected in case labels: - $ x='-x' - $ case $x in - -\?) echo hi - esac - hi - $ x='-?' - $ case $x in - -\\?) echo hi - esac - hi - $ -stdin: - case -x in - -\?) echo fail - esac ---- - - -name: regression-22 -description: - Quoting backquotes inside backquotes doesn't work: - $ echo `echo hi \`echo there\` folks` - asks for more info. sh and at&t ksh88 both echo - hi there folks -stdin: - echo `echo hi \`echo there\` folks` -expected-stdout: - hi there folks ---- - - -name: regression-23 -description: - )) is not treated `correctly': - $ (echo hi ; (echo there ; echo folks)) - missing (( - $ - instead of (as sh and ksh.att) - $ (echo hi ; (echo there ; echo folks)) - hi - there - folks - $ -stdin: - ( : ; ( : ; echo hi)) -expected-stdout: - hi ---- - - -# -# 24. strangeness with file name completion involving symlinks to nowhere -# $ mkdir foo foo/bar -# $ ln -s /stuff/junk foo/bar/xx -# $ echo foo/*/xx -# (beep) -# $ -#echo " [No automatic test for bug 24 - interactive]" - - -name: regression-25 -description: - Check reading stdin in a while loop. The read should only read - a single line, not a whole stdio buffer; the cat should get - the rest. -stdin: - (echo a; echo b) | while read x ; do - echo $x - cat > /dev/null - done -expected-stdout: - a ---- - - -name: regression-26 -description: - Check reading stdin in a while loop. The read should read both - lines, not just the first. -script: - a= - while [ "$a" != xxx ] ; do - last=$x - read x - /bin/cat /dev/null | sed 's/x/y/' - a=x$a - done - echo $last -stdin: - a - b -expected-stdout: - b ---- - - -name: regression-27 -description: - The command - . /does/not/exist - should cause a script to exit. -stdin: - . does/not/exist - echo hi -expected-exit: e != 0 -expected-stderr-pattern: /does\/not\/exist/ ---- - - -name: regression-28 -description: - variable assignements not detected well -stdin: - a.x=1 echo hi -expected-exit: e != 0 -expected-stderr-pattern: /a\.x=1/ ---- - - -name: regression-29 -description: - alias expansion different from at&t ksh88 -stdin: - alias a='for ' b='i in' - a b hi ; do echo $i ; done -expected-stdout: - hi ---- - - -name: regression-30 -description: - strange characters allowed inside ${...} -stdin: - echo ${a{b}} -expected-exit: e != 0 -expected-stderr-pattern: /.?/ ---- - - -name: regression-31 -description: - Does read handle partial lines correctly -script: - a= ret= - while [ "$a" != xxx ] ; do - read x y z - ret=$? - a=x$a - done - echo "[$x]" - echo $ret -stdin: ! - a A aA - b B Bb - c -expected-stdout: - [c] - 1 ---- - - -name: regression-32 -description: - Does read set variables to null at eof? -script: - a= - while [ "$a" != xxx ] ; do - read x y z - a=x$a - done - echo 1: ${x-x not set} ${y-y not set} ${z-z not set} - echo 2: ${x:+x not null} ${y:+y not null} ${z:+z not null} -stdin: - a A Aa - b B Bb -expected-stdout: - 1: - 2: ---- - - -name: regression-33 -description: - Does umask print a leading 0 when umask is 3 digits? -stdin: - umask 222 - umask -expected-stdout: - 0222 ---- - - -# -# -# Does umask print a umask of 0 sanely? -# There is lots of variety here (0, 00, 000, and 0000 have all been -# seen in various shells...) -# -#echo ' [Bug 34 was bogus]' - - -name: regression-35 -description: - Tempory files used for here-docs in functions get trashed after - the function is parsed (before it is executed) -stdin: - f1() { - cat <<- EOF - F1 - EOF - f2() { - cat <<- EOF - F2 - EOF - } - } - f1 - f2 - unset -f f1 - f2 -expected-stdout: - F1 - F2 - F2 ---- - - -name: regression-36 -description: - Command substitution breaks reading in while loop - (test from <sjg@void.zen.oz.au>) -stdin: - (echo abcdef; echo; echo 123) | - while read line - do - # the following line breaks it - c=`echo $line | wc -c` - echo $c - done -expected-stdout: - 7 - 1 - 4 ---- - - -name: regression-37 -description: - Machines with broken times() (reported by <sjg@void.zen.oz.au>) - time does not report correct real time -stdin: - time sleep 1 -expected-stderr-pattern: !/^\s*0\.0[\s\d]+real|^\s*real[\s]+0+\.0/ ---- - - -name: regression-38 -description: - set -e doesn't ignore exit codes for if/while/until/&&/||/!. -arguments: !-e! -stdin: - if false; then echo hi ; fi - false || true - false && true - while false; do echo hi; done - echo ok -expected-stdout: - ok ---- - - -name: regression-39 -description: - set -e: errors in command substitutions aren't ignored - Not clear if they should be or not... -expected-fail: yes -arguments: !-e! -stdin: - echo `false; echo hi` -expected-stdout: - hi ---- - -name: regression-40 -description: - This used to cause a core dump -env-setup: !RANDOM=12! -stdin: - echo hi -expected-stdout: - hi ---- - -name: regression-41 -description: - foo should be set to bar (should not be empty) -stdin: - foo=` - echo bar` - echo "($foo)" -expected-stdout: - (bar) ---- - -name: regression-42 -description: - Can't use command line assignments to assign readonly parameters. -stdin: - foo=bar - readonly foo - foo=stuff env | grep '^foo' -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 (sed 's/^/X/') ---- - -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 ---- - -name: regression-45 -description: - Parameter assignments with [] recognized correctly -stdin: - FOO=*[12] - BAR=abc[ - MORE=[abc] - JUNK=a[bc - echo "<$FOO>" - echo "<$BAR>" - echo "<$MORE>" - echo "<$JUNK>" -expected-stdout: - <*[12]> - <abc[> - <[abc]> - <a[bc> ---- - -name: regression-46 -description: - Check that alias expansion works in command substitutions and - at the end of file. -stdin: - alias x='echo hi' - FOO="`x` " - echo "[$FOO]" - x -expected-stdout: - [hi ] - hi ---- - -name: regression-47 -description: - Check that aliases are fully read. -stdin: - alias x='echo hi; - echo there' - x - echo done -expected-stdout: - hi - there - done ---- - -name: regression-48 -description: - Check that (here doc) temp files are not left behind after an exec. -stdin: - mkdir foo || exit 1 - TMPDIR=$PWD/foo $0 <<- 'EOF' - x() { - sed 's/^/X /' << E_O_F - hi - there - folks - E_O_F - echo "done ($?)" - } - exec /bin/echo subtest-1 hi - EOF - echo subtest-1 foo/* - TMPDIR=$PWD/foo $0 <<- 'EOF' - sed 's/^/X /' << E_O_F; exec /bin/echo subtest-2 hi - a - few - lines - E_O_F - EOF - echo subtest-2 foo/* -expected-stdout: - subtest-1 hi - subtest-1 foo/* - X a - X few - X lines - subtest-2 hi - subtest-2 foo/* ---- - -name: regression-49 -description: - Check that unset params with attributes are reported by set, those - sans attributes are not. -stdin: - unset FOO BAR - echo X$FOO - export BAR - typeset -i BLAH - set | grep FOO - set | grep BAR - set | grep BLAH -expected-stdout: - X - BAR - BLAH ---- - diff --git a/bin/pdksh/tests/th b/bin/pdksh/tests/th deleted file mode 100644 index ebe54718ece..00000000000 --- a/bin/pdksh/tests/th +++ /dev/null @@ -1,819 +0,0 @@ -#!/usr/bin/perl - -# -# Test harness for pdksh tests. -# -# Example test: -# name: a-test -# description: -# a test to show how tests are done -# arguments: !-x!-f! -# stdin: -# echo -n * -# false -# expected-stdout: ! -# * -# expected-stderr: -# + echo -n * -# + false -# expected-exit: 1 -# --- -# This runs the test-program (eg, pdksh) with the arguments -x and -f, -# standard input is a file containing "echo hi*\nfalse\n". The program -# is expected to produce "hi*" (no trailing newline) on standard output, -# "+ echo hi*\n+false\n" on standard error, and an exit code of 1. -# -# -# Format of test files: -# - blank lines and lines starting with # are ignored -# - a test file contains a series of tests -# - a test is a series of tag:value pairs ended with a "---" line -# (leading/trailing spaces are stripped from the first line of value) -# - test tags are: -# Tag Flag Description -# ----- ---- ----------- -# name r The name of the test; should be unique -# description m What test does -# arguments M Arguments to pass to the program; -# default is no arguments. -# script m Value is written to a file which -# is passed as an argument to the program -# (after the arguments arguments) -# stdin m Value is written to a file which is -# used as standard-input for the program; -# default is to use /dev/null. -# perl-setup m Value is a perl script which is executed -# just before the test is run. Try to -# avoid using this... -# perl-cleanup m Value is a perl script which is executed -# just after the test is run. Try to -# avoid using this... -# env-setup M Value is a list of NAME=VALUE elements -# which are put in the environment before -# the test is run. If the =VALUE is -# missing, NAME is removed from the -# environment. Programs are run with -# the following minimal environment: -# USER, LOGNAME, HOME, PATH, SHELL -# (values taken from the environment of -# the test harness). -# time-limit Time limit - the program is sent a -# SIGKILL N seconds. Default is no -# limit. -# expected-fail `yes' if the test is expected to fail. -# expected-exit expected exit code. Can be a number, -# or a C expression using the variables -# e, s and w (exit code, termination -# signal, and status code). -# expected-stdout m What the test should generate on stdout; -# default is to expect no output. -# expected-stdout-pattern m A perl pattern which matches the -# expected output. -# expected-stderr m What the test should generate on stderr; -# default is to expect no output. -# expected-stderr-pattern m A perl pattern which matches the -# expected standard error. -# Flag meanings: -# r tag is required (eg, a test must have a name tag). -# m value can be multiple lines. Lines must be prefixed with -# a tab. If the value part of the initial tag:value line is -# - empty: the initial blank line is stripped. -# - a lone !: the last newline in the value is stripped; -# M value can be multiple lines (prefixed by a tab) and consists -# of multiple fields, delimited by a field seperator character. -# The value must start and end with the f-s-c. -# - -require 'signal.ph'; -require 'errno.ph'; -require 'getopts.pl'; - -($prog = $0) =~ s#.*/##; - -$Usage = <<EOF ; -Usage: $prog [-s test-set] [-p prog] [-v] test-name ... - -p p Use p as the program to test - -s s Read tests from file s; if s is a directory, it is recursively - scaned for test files (which end in .t). - -t t Use t as default time limit for tests (default is unlimited) - -v Verbose mode: print reason test failed. - test-name(s) specifies the name of the test(s) to run; if none are - specified, all tests are run. -EOF - -# -# r - required -# m - can be multi-line -# M - multi-line, but without trailing newline -# -%test_fields = ( - 'name', 'r', - 'description', 'm', - 'arguments', 'M', - 'script', 'm', - 'stdin', 'm', - 'perl-setup', 'm', - 'perl-cleanup', 'm', - 'env-setup', 'M', - 'time-limit', '', - 'expected-fail', '', - 'expected-exit', '', - 'expected-stdout', 'm', - 'expected-stdout-pattern', 'm', - 'expected-stderr', 'm', - 'expected-stderr-pattern', 'm', - ); -# Filled in by read_test() -%internal_test_fields = ( - ':full-name', 1, # file:name - ':long-name', 1, # dir/file:lineno:name - ); - -$temps = "/tmp/rts$$"; -$tempi = "/tmp/rti$$"; -$tempo = "/tmp/rto$$"; -$tempe = "/tmp/rte$$"; -$tempdir = "/tmp/rtd$$"; - -$nfailed = 0; -$nxfailed = 0; -$npassed = 0; -$nxpassed = 0; - -%known_tests = (); - -if (!&Getopts('p:s:t:v')) { - print STDERR $Usage; - exit 1; -} - -die "$prog: no program specified (use -p)\n" if !defined $opt_p; -die "$prog: no test set specified (use -s)\n" if !defined $opt_s; -$test_prog = $opt_p; -$verbose = defined $opt_v && $opt_v; -$test_set = $opt_s; -if (defined $opt_t) { - die "$prog: bad -t argument (should be number > 0): $opt_t\n" - if $opt_t !~ /^\d+$/ || $opt_t <= 0; - $default_time_limit = $opt_t; -} - -# Note which tests are to be run. -%do_test = (); -grep($do_test{$_} = 1, @ARGV); -$all_tests = @ARGV == 0; - -# Set up a very minimal environment -%new_env = (); -foreach $env (('USER', 'LOGNAME', 'HOME', 'PATH', 'SHELL')) { - $new_env{$env} = $ENV{$env} if defined $ENV{$env}; -} -%old_env = %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); - -chop($pwd = `pwd 2> /dev/null`); -die "$prog: couldn't get current working directory\n" if $pwd eq ''; -die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd); - -$test_prog = "$pwd/$test_prog" if substr($test_prog, 0, 1) ne '/'; -die "$prog: $test_prog is not executable - bye\n" if ! -x $test_prog; - -@trap_sigs = ('TERM', 'QUIT', 'INT', 'PIPE', 'HUP'); -@SIG{@trap_sigs} = ('cleanup_exit') x @trap_sigs; -$child_kill_ok = 0; -$SIG{'ALRM'} = 'catch_sigalrm'; - -$| = 1; - -if (-d $test_set) { - $file_prefix_skip = length($test_set) + 1; - $ret = &process_test_dir($test_set); -} else { - $file_prefix_skip = 0; - $ret = &process_test_file($test_set); -} -&cleanup_exit() if !defined $ret; - -$tot_failed = $nfailed + $nxfailed; -$tot_passed = $npassed + $nxpassed; -if ($tot_failed || $tot_passed) { - print "Total failed: $tot_failed"; - print " ($nxfailed unexpected)" if $nxfailed; - print " (as expected)" if $nfailed && !$nxfailed; - print "\nTotal passed: $tot_passed"; - print " ($nxpassed unexpected)" if $nxpassed; - print "\n"; -} - -&cleanup_exit('ok'); - -sub -cleanup_exit -{ - local($sig, $exitcode) = ('', 1); - - if ($_[0] eq 'ok') { - $exitcode = 0; - } elsif ($_[0] ne '') { - $sig = $_[0]; - } - - unlink($tempi, $tempo, $tempe, $temps); - &scrub_dir($tempdir) if defined $tempdir; - rmdir($tempdir) if defined $tempdir; - - if ($sig) { - $SIG{$sig} = 'DEFAULT'; - kill $sig, $$; - return; - } - exit $exitcode; -} - -sub -catch_sigalrm -{ - $SIG{'ALRM'} = 'catch_sigalrm'; - kill(9, $child_pid) if $child_kill_ok; - $child_killed = 1; -} - -sub -process_test_dir -{ - local($dir) = @_; - local($ret, $file); - local(@todo) = (); - - if (!opendir(DIR, $dir)) { - print STDERR "$prog: can't open directory $dir - $!\n"; - return undef; - } - while ($file = readdir(DIR)) { - push(@todo, $file) if $file =~ /^[^.].*\.t$/; - } - closedir(DIR); - - foreach $file (@todo) { - $file = "$dir/$file"; - if (-d $file) { - $ret = &process_test_dir($file); - } elsif (-f _) { - $ret = &process_test_file($file); - } - last if !defined $ret; - } - - return $ret; -} - -sub -process_test_file -{ - local($file) = @_; - local($ret); - - if (!open(IN, $file)) { - die "$prog: can't open $file - $!\n"; - return undef; - } - while (1) { - $ret = &read_test($file, IN, *test); - last if !defined $ret || !$ret; - next if !$all_tests && !$do_test{$test{'name'}}; - $ret = &run_test(*test); - last if !defined $ret; - } - close(IN); - - return $ret; -} - -sub -run_test -{ - local(*test) = @_; - local($name) = $test{':full-name'}; - - #print "Running test $name...\n" if $verbose; - - if (defined $test{'stdin'}) { - return undef if !&write_file($tempi, $test{'stdin'}); - $ifile = $tempi; - } else { - $ifile = '/dev/null'; - } - - if (defined $test{'script'}) { - return undef if !&write_file($temps, $test{'script'}); - } - - return undef if !&scrub_dir($tempdir); - - if (!chdir($tempdir)) { - print STDERR "$prog: couldn't cd to $tempdir - $!\n"; - return undef; - } - - if (defined $test{'perl-setup'}) { - eval $test{'perl-setup'}; - if ($@ ne '') { - print STDERR "$prog:$test{':long-name'}: error running perl-setup - $@\n"; - return undef; - } - } - - $pid = fork; - if (!defined $pid) { - print STDERR "$prog: can't fork - $!\n"; - return undef; - } - if (!$pid) { - @SIG{@trap_sigs} = ('DEFAULT') x @trap_sigs; - $SIG{'ALRM'} = 'DEFAULT'; - if (defined $test{'env-setup'}) { - local($var, $val, $i); - - foreach $var (split(substr($test{'env-setup'}, 0, 1), - $test{'env-setup'})) - { - $i = index($var, '='); - next if $i == 0 || $var eq ''; - if ($i < 0) { - delete $ENV{$var}; - } else { - $ENV{substr($var, 0, $i)} = substr($var, $i + 1); - } - } - } - if (!open(STDIN, "< $ifile")) { - print STDERR "$prog: couldn't open $ifile in child - $!\n"; - kill('TERM', $$); - } - if (!open(STDOUT, "> $tempo")) { - print STDERR "$prog: couldn't open $tempo in child - $!\n"; - kill('TERM', $$); - } - if (!open(STDERR, "> $tempe")) { - print STDOUT "$prog: couldn't open $tempe in child - $!\n"; - kill('TERM', $$); - } - @argv = ($test_prog); - if (defined $test{'arguments'}) { - push(@argv, - split(substr($test{'arguments'}, 0, 1), - substr($test{'arguments'}, 1))); - } - push(@argv, $temps) if defined $test{'script'}; - exec(@argv); - print STDERR "$prog: couldn't execute $test_prog - $!\n"; - kill('TERM', $$); - exit(95); - } - $child_pid = $pid; - $child_killed = 0; - $child_kill_ok = 1; - alarm($test{'time-limit'}) if defined $test{'time-limit'}; - while (1) { - $xpid = waitpid($pid, 0); - $child_kill_ok = 0; - if ($xpid < 0) { - next if $! == &EINTR; - print STDERR "$prog: error waiting for child - $!\n"; - return undef; - } - last; - } - $status = $?; - alarm(0) if defined $test{'time-limit'}; - - $failed = 0; - $why = ''; - - if ($child_killed) { - $failed = 1; - $why .= "\ttest timed out (limit of $test{'time-limit'} seconds)\n"; - } - - $ret = &eval_exit($test{'long-name'}, $status, $test{'expected-exit'}); - return undef if !defined $ret; - if (!$ret) { - local($expl); - - $failed = 1; - if (($status & 0xff) == 0x7f) { - $expl = "stopped"; - } elsif (($status & 0xff)) { - $expl = "signal " . ($status & 0x7f); - } else { - $expl = "exit-code " . (($status >> 8) & 0xff); - } - $why .= - "\tunexpected exit status $status ($expl), expected $test{'expected-exit'}\n"; - } - - $tmp = &check_output($test{'long-name'}, $tempo, 'stdout', - $test{'expected-stdout'}, $test{'expected-stdout-pattern'}); - return undef if !defined $tmp; - if ($tmp ne '') { - $failed = 1; - $why .= $tmp; - } - - $tmp = &check_output($test{'long-name'}, $tempe, 'stderr', - $test{'expected-stderr'}, $test{'expected-stderr-pattern'}); - return undef if !defined $tmp; - if ($tmp ne '') { - $failed = 1; - $why .= $tmp; - } - - if (defined $test{'perl-cleanup'}) { - eval $test{'perl-cleanup'}; - if ($@ ne '') { - print STDERR "$prog:$test{':long-name'}: error running perl-cleanup - $@\n"; - return undef; - } - } - - if (!chdir($pwd)) { - print STDERR "$prog: couldn't cd to $pwd - $!\n"; - return undef; - } - - if ($failed) { - if (!$test{'expected-fail'}) { - print "FAIL $name\n"; - $nxfailed++; - } else { - print "fail $name (as expected)\n"; - $nfailed++; - } - $why = "\tDescription" - . &wrap_lines($test{'description'}, " (missing)\n") - . $why; - } elsif ($test{'expected-fail'}) { - print "PASS $name (unexpectedly)\n"; - $nxpassed++; - } else { - print "pass $name\n"; - $npassed++; - } - print $why if $verbose; - return 0; -} - -sub -scrub_dir -{ - local($dir) = @_; - local(@todo) = (); - local($file); - - if (!opendir(DIR, $dir)) { - print STDERR "$prog: couldn't open direcotry $dir - $!\n"; - return undef; - } - while ($file = readdir(DIR)) { - push(@todo, $file) if $file ne '.' && $file ne '..'; - } - closedir(DIR); - foreach $file (@todo) { - $file = "$dir/$file"; - if (-d $file) { - return undef if !&scrub_dir($file); - if (!rmdir($file)) { - print STDERR "$prog: couldn't rmdir $file - $!\n"; - return undef; - } - } else { - if (!unlink($file)) { - print STDERR "$prog: couldn't unlink $file - $!\n"; - return undef; - } - } - } - return 1; -} - -sub -write_file -{ - local($file, $str) = @_; - - if (!open(TEMP, "> $file")) { - print STDERR "$prog: can't open $file - $!\n"; - return undef; - } - print TEMP $str; - if (!close(TEMP)) { - print STDERR "$prog: error writing $file - $!\n"; - return undef; - } - return 1; -} - -sub -check_output -{ - local($name, $file, $what, $expect, $expect_pat) = @_; - local($got) = ''; - local($why) = ''; - local($ret); - - if (!open(TEMP, "< $file")) { - print STDERR "$prog:$name($what): couldn't open $file after running program - $!\n"; - return undef; - } - while (<TEMP>) { - $got .= $_; - } - close(TEMP); - if (defined $expect_pat) { - $_ = $got; - $ret = eval "$expect_pat"; - if ($@ ne '') { - print STDERR "$prog:$name($what): error evaluating $what pattern: $expect_pat - $@\n"; - return undef; - } - if (!$ret) { - $why = "\tunexpected $what - wanted pattern"; - $why .= &wrap_lines($expect_pat); - $why .= "\tgot"; - $why .= &wrap_lines($got); - } - } else { - $expect = '' if !defined $expect; - if ($got ne $expect) { - $why .= "\tunexpected $what - " . &first_diff($expect, $got) . "\n"; - $why .= "\twanted"; - $why .= &wrap_lines($expect); - $why .= "\tgot"; - $why .= &wrap_lines($got); - } - } - return $why; -} - -sub -wrap_lines -{ - local($str, $empty) = @_; - local($nonl) = substr($str, -1, 1) ne "\n"; - - return (defined $empty ? $empty : " nothing\n") if $str eq ''; - substr($str, 0, 0) = ":\n"; - $str =~ s/\n/\n\t\t/g; - if ($nonl) { - $str .= "\n\t[incomplete last line]\n"; - } else { - chop($str); - chop($str); - } - return $str; -} - -sub -first_diff -{ - local($exp, $got) = @_; - local($lineno, $char) = (1, 1); - local($i, $len); - local($ce, $cg); - - $len = length($exp); - if ($len != length($got)) { - if ($len < length($got)) { - if (substr($got, 0, $len) eq $exp) { - return "got too much output"; - } - } elsif (substr($exp, 0, $len) eq $got) { - return "got too little output"; - } - $len = length($got); - } - for ($i = 0; $i < $len; $i++) { - $ce = substr($exp, $i, 1); - $cg = substr($got, $i, 1); - last if $ce ne $cg; - $char++; - if ($ce eq "\n") { - $lineno++; - $char = 1; - } - } - return "first difference: line $lineno, char $char" -} - -sub -eval_exit -{ - local($name, $status, $expect) = @_; - local($expr); - local($w, $e, $s) = ($status, ($status >> 8) & 0xff, $status & 0x7f); - - $e = -1000 if $status & 0xff; - $s = -1000 if $s == 0x7f; - if (!defined $expect) { - $expr = '$w == 0'; - } elsif ($expect =~ /^(|-)\d+$/) { - $expr = "\$e == $expect"; - } else { - $expr = $expect; - $expr =~ s/\b([wse])\b/\$$1/g; - $expr =~ s/\b(SIG[A-Z0-9]+)\b/&$1/g; - } - $w = eval $expr; - if ($@ ne '') { - print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $expect ($@)\n"; - return undef; - } - return $w; -} - -sub -read_test -{ - local($file, $in, *test) = @_; - local($field, $val, $flags, $do_chop, $need_redo, $start_lineno); - - %test = (); - while (<$in>) { - next if /^\s*$/; - next if /^ *#/; - last if /^\s*---\s*$/; - $start_lineno = $. if !defined $start_lineno; - if (!/^([-\w]+):\s*(|\S|\S.*\S)\s*$/) { - print STDERR "$prog:$file:$.: unrecognized line\n"; - return undef; - } - ($field, $val) = ($1, $2); - if (defined $test{$field}) { - print STDERR "$prog:$file:$.: multiple \"$field\" fields\n"; - return undef; - } - $flags = $test_fields{$field}; - if (!defined $flags) { - print STDERR "$prog:$file:$.: unrecognized field \"$field\"\n"; - return undef; - } - $do_chop = $flags !~ /m/; - $need_redo = 0; - if ($val eq '' || $val eq '!') { - if ($flags =~ /[Mm]/) { - $do_chop = 1 if $val eq '!'; - $val = ''; - while (<$in>) { - last if !/^\t/; - $val .= $'; - } - chop $val if $do_chop; - $do_chop = 1; - $need_redo = 1; - } elsif ($val eq '') { - print STDERR - "$prog:$file:$.: no value given for field \"$field\"\n"; - return undef; - } - } - $val .= "\n" if !$do_chop; - $test{$field} = $val; - redo if $need_redo; - } - if ($_ eq '') { - if (%test) { - print STDERR - "$prog:$file:$start_lineno: end-of-file while reading test\n"; - return undef; - } - return 0; - } - - while (($field, $val) = each %test_fields) { - if ($val =~ /r/ && !defined $test{$field}) { - print STDERR - "$prog:$file:$start_lineno: required field \"$field\" missing\n"; - return undef; - } - } - - $test{':full-name'} = substr($file, $file_prefix_skip) . ":$test{'name'}"; - $test{':long-name'} = "$file:$start_lineno:$test{'name'}"; - - # Syntax check on specific fields - if (defined $test{'expected-fail'}) { - if ($test{'expected-fail'} !~ /^(yes|no)$/) { - print STDERR - "$prog:$test{':long-name'}: bad value for expected-fail field\n"; - return undef; - } - $test{'expected-fail'} = $1 eq 'yes'; - } else { - $test{'expected-fail'} = 0; - } - if (defined $test{'arguments'}) { - local($firstc) = substr($test{'arguments'}, 0, 1); - - if (substr($test{'arguments'}, -1, 1) ne $firstc) { - print STDERR "$prog:$test{':long-name'}: arguments field doesn't start and end with the same character\n"; - return undef; - } - } - if (defined $test{'env-setup'}) { - local($firstc) = substr($test{'env-setup'}, 0, 1); - - if (substr($test{'env-setup'}, -1, 1) ne $firstc) { - print STDERR "$prog:$test{':long-name'}: env-setup field doesn't start and end with the same character\n"; - return undef; - } - } - if (defined $test{'expected-exit'}) { - local($val) = $test{'expected-exit'}; - - if ($val =~ /^(|-)\d+$/) { - if ($val < 0 || $val > 255) { - print STDERR "$prog:$test{':long-name'}: expected-exit value $val not in 0..255\n"; - return undef; - } - } elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\b[wse]\b|\bSIG[A-Z0-9]+\b)+$/) { - print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $val\n"; - return undef; - } - } else { - $test{'expected-exit'} = 0; - } - if (defined $test{'expected-stdout'} - && defined $test{'expected-stdout-pattern'}) - { - print STDERR "$prog:$test{':long-name'}: can't use both expected-stdout and expected-stdout-pattern\n"; - return undef; - } - if (defined $test{'expected-stderr'} - && defined $test{'expected-stderr-pattern'}) - { - print STDERR "$prog:$test{':long-name'}: can't use both expected-stderr and expected-stderr-pattern\n"; - return undef; - } - if (defined $test{'time-limit'}) { - if ($test{'time-limit'} !~ /^\d+$/ || $test{'time-limit'} == 0) { - print STDERR - "$prog:$test{':long-name'}: bad value for time-limit field\n"; - return undef; - } - } elsif (defined $default_time_limit) { - $test{'time-limit'} = $default_time_limit; - } - - if (defined $known_tests{$test{'name'}}) { - print STDERR "$prog:$test{':long-name'}: warning: duplicate test name ${test{'name'}}\n"; - } - $known_tests{$test{'name'}} = 1; - - return 1; -} - -sub -touch -{ - local(@files) = @_; - local($file); - - foreach $file (@files) { - if (!open(T, "> $file")) { - die "Couldn't touch $file\n"; - } - close(T); - } - return 1; -} - -sub -tty_msg -{ - local($msg) = @_; - - open(TTY, "> /dev/tty") || return 0; - print TTY $msg; - close(TTY); - return 1; -} - -sub -never_called_funcs -{ - return 0; - &tty_msg("hi\n"); - &touch("/tmp/foo"); - &never_called_funcs(); - &catch_sigalrm(); - $old_env{'foo'} = 'bar'; - $internal_test_fields{'foo'} = 'bar'; -} diff --git a/bin/pdksh/tests/th.sh b/bin/pdksh/tests/th.sh deleted file mode 100644 index 3ca78e8c955..00000000000 --- a/bin/pdksh/tests/th.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# -# Simple script to find perl and run it -# - -# Avoid common problems with ENV (though perl shouldn't let it through) -# (can you believe some shells don't have an unset???) -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 - done -done - -[ X"$perl" = X ] && { - echo "$0: can't find perl - bye\n" 1>&2 - exit 1 - } - -exec $perl "$@" diff --git a/bin/pdksh/tests/unclass1.t b/bin/pdksh/tests/unclass1.t deleted file mode 100644 index 55d4e58976f..00000000000 --- a/bin/pdksh/tests/unclass1.t +++ /dev/null @@ -1,97 +0,0 @@ -name: xxx-quoted-newline-1 -description: - Check that \<newline> works inside of ${} -stdin: - abc=2 - echo ${ab\ - c} -expected-stdout: - 2 ---- - -name: xxx-quoted-newline-2 -description: - Check that \<newline> works at the start of a here document -stdin: - cat << EO\ - F - hi - EOF -expected-stdout: - hi ---- - -name: xxx-quoted-newline-3 -description: - Check that \<newline> works at the end of a here document -stdin: - cat << EOF - hi - EO\ - F -expected-stdout: - hi ---- - -name: xxx-multi-assignment-cmd -description: - Check that assignments in a command affect subsequent assignments - in the same command -stdin: - FOO=abc - FOO=123 BAR=$FOO - echo $BAR -expected-stdout: - 123 ---- - -name: xxx-exec-environment-1 -description: - Check to see if exec sets it's environment correctly -stdin: - FOO=bar exec env -expected-stdout-pattern: - /(^|.*\n)FOO=bar\n/ ---- - -name: xxx-exec-environment-2 -description: - Check to make sure exec doesn't change environment if a program - isn't exec-ed -stdin: - env > bar1 - FOO=bar exec; env > bar2 - cmp -s bar1 bar2 ---- - -name: xxx-what-do-you-call-this-1 -stdin: - echo "${foo:-"a"}*" -expected-stdout: - a* ---- - -name: xxx-prefix-strip-1 -stdin: - foo='a cdef' - echo ${foo#a c} -expected-stdout: - def ---- - -name: xxx-prefix-strip-2 -stdin: - set a c - x='a cdef' - echo ${x#$*} -expected-stdout: - def ---- - -name: xxx-variable-syntax-1 -stdin: - echo ${:} -expected-stderr-pattern: - /bad substitution/ -expected-exit: 1 ---- diff --git a/bin/pdksh/tests/unclass2.t b/bin/pdksh/tests/unclass2.t deleted file mode 100644 index d9e14822e06..00000000000 --- a/bin/pdksh/tests/unclass2.t +++ /dev/null @@ -1,166 +0,0 @@ -name: xxx-subsitution-eval-order -description: - Check order of evaluation of expressions -stdin: - i=1 x= y= - set -A A abc def GHI j G k - echo ${A[x=(i+=1)]#${A[y=(i+=2)]}} - echo $x $y -expected-stdout: - HI - 2 4 ---- - -name: xxx-set-option-1 -description: - Check option parsing in set -stdin: - set -A -vs A 1 3 2 - echo ${A[*]} -expected-stderr: - echo ${A[*]} -expected-stdout: - 1 2 3 ---- - -name: xxx-exec-1 -description: - Check that exec exits for built-ins -arguments: !-i! -stdin: - exec print hi - echo still herre -expected-stdout: - hi -expected-stderr-pattern: /.*/ ---- - -name: xxx-while-1 -description: - Check the return value of while loops - XXX need to do same for for/select/until loops -stdin: - i=x - while [ $i != xxx ] ; do - i=x$i - if [ $i = xxx ] ; then - false - continue - fi - done - echo loop1=$? - - i=x - while [ $i != xxx ] ; do - i=x$i - if [ $i = xxx ] ; then - false - break - fi - done - echo loop2=$? - - i=x - while [ $i != xxx ] ; do - i=x$i - false - done - echo loop3=$? -expected-stdout: - loop1=0 - loop2=0 - loop3=1 ---- - -name: xxx-status-1 -description: - Check that blank lines don't clear $? -arguments: !-i! -stdin: - (exit 1) - echo $? - (exit 1) - - echo $? - true -expected-stdout: - 1 - 1 -expected-stderr-pattern: /.*/ ---- - -name: xxx-status-2 -description: - Check that $? is preserved in subshells, includes, traps. -stdin: - (exit 1) - - echo blank: $? - - (exit 2) - (echo subshell: $?) - - echo 'echo include: $?' > foo - (exit 3) - . ./foo - - trap 'echo trap: $?' ERR - (exit 4) - echo exit: $? -expected-stdout: - blank: 1 - subshell: 2 - include: 3 - trap: 4 - exit: 4 ---- - -name: xxx-clean-chars-1 -description: - Check MAGIC character is stuffed correctly -stdin: - echo `echo [£` -expected-stdout: - [£ ---- - -name: xxx-param-subst-qmark-1 -description: - Check suppresion of error message with null string. According to - POSIX, it shouldn't print the error as `word' isn't ommitted. -stdin: - unset foo - x= - echo x${foo?$x} -expected-exit: 1 -expected-fail: yes -expected-stderr-pattern: !/not set/ ---- - -name: xxx-param-_-1 -description: - Check c flag is set. -arguments: !-c!echo "[$-]"! -expected-stdout-pattern: /^\[.*c.*\]$/ ---- - -name: env-prompt -description: - Check that prompt not printed when processing ENV -env-setup: !ENV=./foo! -perl-setup: - system("cat > foo << EOF - XXX=12 - PS1='X ' - false && echo hmmm - EOF - "); -arguments: !-i! -stdin: - echo hi${XXX}there -expected-stdout: - hi12there -expected-stderr: ! - X X ---- - diff --git a/bin/pdksh/tests/version.t b/bin/pdksh/tests/version.t deleted file mode 100644 index 23d834015fa..00000000000 --- a/bin/pdksh/tests/version.t +++ /dev/null @@ -1,8 +0,0 @@ -name: version-1 -description: - Check version of shell. -stdin: - echo $KSH_VERSION -expected-stdout: - @(#)PD KSH v5.2.12 96/10/29 ---- diff --git a/bin/pdksh/trap.c b/bin/pdksh/trap.c deleted file mode 100644 index f1efe6451d9..00000000000 --- a/bin/pdksh/trap.c +++ /dev/null @@ -1,432 +0,0 @@ -/* $OpenBSD: trap.c,v 1.6 1997/09/01 18:30:13 deraadt Exp $ */ - -/* - * signal handling - */ - -/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */ -#define FROM_TRAP_C -#include "sh.h" - -/* Table is indexed by signal number - * - * The script siglist.sh generates siglist.out, which is a sorted, complete - * list of signals - */ -Trap sigtraps[SIGNALS+1] = { - { SIGEXIT_, "EXIT", "Signal 0" }, -#include "siglist.out" /* generated by siglist.sh */ - { SIGERR_, "ERR", "Error handler" }, - }; - -static struct sigaction Sigact_ign, Sigact_trap; - -void -inittraps() -{ -#ifdef HAVE_SYS_SIGLIST -# ifndef SYS_SIGLIST_DECLARED - extern char *sys_siglist[]; -# endif - int i; - - /* Use system description, if available, for unknown signals... */ - for (i = 0; i < NSIG; i++) - if (!sigtraps[i].name && sys_siglist[i][0]) - sigtraps[i].mess = sys_siglist[i]; -#endif /* HAVE_SYS_SIGLIST */ - - sigemptyset(&Sigact_ign.sa_mask); - Sigact_ign.sa_flags = KSH_SA_FLAGS; - Sigact_ign.sa_handler = SIG_IGN; - Sigact_trap = Sigact_ign; - Sigact_trap.sa_handler = trapsig; - - sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR; - sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR; - sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */ - sigtraps[SIGHUP].flags |= TF_FATAL; - sigtraps[SIGCHLD].flags |= TF_SHELL_USES; - - /* these are always caught so we can clean up any temproary files. */ - setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG); - setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG); - setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG); - 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_SHTRAP); -} - -static RETSIGTYPE -alarm_catcher(sig) - int sig; -{ - if (ksh_tmout_state == TMOUT_READING) { - int left = alarm(0); - - if (left == 0) { - ksh_tmout_state = TMOUT_LEAVING; - intrsig = 1; - } else - alarm(left); - } - return RETSIGVAL; -} -#endif /* KSH */ - -Trap * -gettrap(name) - const char *name; -{ - int i; - register Trap *p; - - if (digit(*name)) { - int n; - - if (getn(name, &n) && 0 <= n && n < SIGNALS) - return &sigtraps[n]; - return NULL; - } - for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) - if (p->name && strcasecmp(p->name, name) == 0) - return p; - return NULL; -} - -/* - * trap signal handler - */ -RETSIGTYPE -trapsig(i) - int i; -{ - Trap *p = &sigtraps[i]; - int save_errno = errno; - - trap = p->set = 1; - if (p->flags & TF_DFL_INTR) - intrsig = 1; - if ((p->flags & TF_FATAL) && !p->trap) { - 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); -#endif /* V7_SIGNALS */ - errno = save_errno; - return RETSIGVAL; -} - -/* called when we want to allow the user to ^C out of something - won't - * work if user has trapped SIGINT. - */ -void -intrcheck() -{ - if (intrsig) - runtraps(TF_DFL_INTR|TF_FATAL); -} - -/* called after EINTR to check if a signal with normally causes process - * termination has been received. - */ -int -fatal_trap_check() -{ - int i; - Trap *p; - - /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */ - for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) - if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL))) - /* return value is used as an exit code */ - return 128 + p->signal; - return 0; -} - -/* Returns the signal number of any pending traps: ie, a signal which has - * occured for which a trap has been set or for which the TF_DFL_INTR flag - * is set. - */ -int -trap_pending() -{ - int i; - Trap *p; - - for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) - if (p->set && ((p->trap && p->trap[0]) - || ((p->flags & (TF_DFL_INTR|TF_FATAL)) - && !p->trap))) - return p->signal; - return 0; -} - -/* - * run any pending traps. If intr is set, only run traps that - * can interrupt commands. - */ -void -runtraps(flag) - int flag; -{ - int i; - register Trap *p; - -#ifdef KSH - if (ksh_tmout_state == TMOUT_LEAVING) { - ksh_tmout_state = TMOUT_EXECUTING; - warningf(FALSE, "timed out waiting for input"); - unwind(LEXIT); - } else - /* XXX: this means the alarm will have no effect if a trap - * is caught after the alarm() was started...not good. - */ - ksh_tmout_state = TMOUT_EXECUTING; -#endif /* KSH */ - if (!flag) - trap = 0; - if (flag & TF_DFL_INTR) - intrsig = 0; - if (flag & TF_FATAL) - fatal_trap = 0; - for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) - if (p->set && (!flag - || ((p->flags & flag) && p->trap == (char *) 0))) - runtrap(p); -} - -void -runtrap(p) - Trap *p; -{ - int i = p->signal; - char *trapstr = p->trap; - int oexstat; - int UNINITIALIZED(old_changed); - - p->set = 0; - if (trapstr == (char *) 0) { /* SIG_DFL */ - if (p->flags & TF_FATAL) { - /* eg, SIGHUP */ - exstat = 128 + i; - unwind(LLEAVE); - } - if (p->flags & TF_DFL_INTR) { - /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */ - exstat = 128 + i; - unwind(LINTR); - } - return; - } - if (trapstr[0] == '\0') /* SIG_IGN */ - return; - if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */ - old_changed = p->flags & TF_CHANGED; - p->flags &= ~TF_CHANGED; - p->trap = (char *) 0; - } - oexstat = exstat; - command(trapstr); - exstat = oexstat; - if (i == SIGEXIT_ || i == SIGERR_) { - if (p->flags & TF_CHANGED) - /* don't clear TF_CHANGED */ - afree(trapstr, APERM); - else - p->trap = trapstr; - p->flags |= old_changed; - } -} - -/* clear pending traps and reset user's trap handlers; used after fork(2) */ -void -cleartraps() -{ - int i; - Trap *p; - - trap = 0; - intrsig = 0; - fatal_trap = 0; - for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) { - p->set = 0; - if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0])) - settrap(p, (char *) 0); - } -} - -/* restore signals just before an exec(2) */ -void -restoresigs() -{ - int i; - Trap *p; - - for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) - if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL)) - setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL, - SS_RESTORE_CURR|SS_FORCE); -} - -void -settrap(p, s) - Trap *p; - char *s; -{ - handler_t f; - - if (p->trap) - afree(p->trap, APERM); - p->trap = str_save(s, APERM); /* handles s == 0 */ - p->flags |= TF_CHANGED; - f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN; - - p->flags |= TF_USER_SET; - if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL) - f = trapsig; - else if (p->flags & TF_SHELL_USES) { - if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) { - /* do what user wants at exec time */ - p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); - if (f == SIG_IGN) - p->flags |= TF_EXEC_IGN; - else - p->flags |= TF_EXEC_DFL; - } - /* assumes handler already set to what shell wants it - * (normally trapsig, but could be j_sigchld() or SIG_IGN) - */ - return; - } - - /* todo: should we let user know signal is ignored? how? */ - setsig(p, f, SS_RESTORE_CURR|SS_USER); -} - -/* Called by c_print() when writing to a co-process to ensure SIGPIPE won't - * kill shell (unless user catches it and exits) - */ -int -block_pipe() -{ - int restore_dfl = 0; - Trap *p = &sigtraps[SIGPIPE]; - - if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) { - setsig(p, SIG_IGN, SS_RESTORE_CURR); - if (p->flags & TF_ORIG_DFL) - restore_dfl = 1; - } else if (p->cursig == SIG_DFL) { - setsig(p, SIG_IGN, SS_RESTORE_CURR); - restore_dfl = 1; /* restore to SIG_DFL */ - } - return restore_dfl; -} - -/* Called by c_print() to undo whatever block_pipe() did */ -void -restore_pipe(restore_dfl) - int restore_dfl; -{ - if (restore_dfl) - setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR); -} - -/* Set action for a signal. Action may not be set if original - * action was SIG_IGN, depending on the value of flags and - * FTALKING. - */ -int -setsig(p, f, flags) - Trap *p; - handler_t f; - int flags; -{ - struct sigaction sigact; - - 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; - } - - /* 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; - - 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); - sigact.sa_flags = KSH_SA_FLAGS; - sigact.sa_handler = f; - sigaction(p->signal, &sigact, (struct sigaction *) 0); - } - - return 1; -} - -/* control what signal is set to before an exec() */ -void -setexecsig(p, restore) - Trap *p; - int restore; -{ - /* XXX debugging */ - if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) - internal_errorf(1, "setexecsig: unset signal %d(%s)", - p->signal, p->name); - - /* restore original value for exec'd kids */ - p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); - switch (restore & SS_RESTORE_MASK) { - case SS_RESTORE_CURR: /* leave things as they currently are */ - break; - case SS_RESTORE_ORIG: - p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL; - break; - case SS_RESTORE_DFL: - p->flags |= TF_EXEC_DFL; - break; - case SS_RESTORE_IGN: - p->flags |= TF_EXEC_IGN; - break; - } -} diff --git a/bin/pdksh/tree.c b/bin/pdksh/tree.c deleted file mode 100644 index 93e3f9d7de7..00000000000 --- a/bin/pdksh/tree.c +++ /dev/null @@ -1,656 +0,0 @@ -/* $OpenBSD: tree.c,v 1.5 1997/09/01 18:30:15 deraadt Exp $ */ - -/* - * command tree climbing - */ - -#include "sh.h" - -#define INDENT 4 - -#define tputc(c, shf) shf_putchar(c, shf); -static void ptree ARGS((struct op *t, int indent, struct shf *f)); -static void pioact ARGS((struct shf *f, int indent, struct ioword *iop)); -static void tputC ARGS((int c, struct shf *shf)); -static void tputS ARGS((char *wp, struct shf *shf)); -static void vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va)); -static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap)); -static void iofree ARGS((struct ioword **iow, Area *ap)); - -/* - * print a command tree - */ - -static void -ptree(t, indent, shf) - register struct op *t; - int indent; - register struct shf *shf; -{ - register char **w; - struct ioword **ioact; - struct op *t1; - - Chain: - if (t == NULL) - return; - switch (t->type) { - case TCOM: - if (t->vars) - for (w = t->vars; *w != NULL; ) - fptreef(shf, indent, "%S ", *w++); - else - fptreef(shf, indent, "#no-vars# "); - if (t->args) - for (w = t->args; *w != NULL; ) - fptreef(shf, indent, "%S ", *w++); - else - fptreef(shf, indent, "#no-args# "); - break; - case TEXEC: - t = t->left; - goto Chain; - case TPAREN: - fptreef(shf, indent + 2, "( %T) ", t->left); - break; - case TPIPE: - fptreef(shf, indent, "%T| ", t->left); - t = t->right; - goto Chain; - case TLIST: - fptreef(shf, indent, "%T%;", t->left); - t = t->right; - goto Chain; - case TOR: - case TAND: - fptreef(shf, indent, "%T%s %T", - t->left, (t->type==TOR) ? "||" : "&&", t->right); - break; - case TBANG: - fptreef(shf, indent, "! "); - t = t->right; - goto Chain; - case TDBRACKET: - { - int i; - - fptreef(shf, indent, "[["); - for (i = 0; t->args[i]; i++) - fptreef(shf, indent, " %S", t->args[i]); - fptreef(shf, indent, " ]] "); - break; - } -#ifdef KSH - case TSELECT: - fptreef(shf, indent, "select %s ", t->str); - /* fall through */ -#endif /* KSH */ - case TFOR: - if (t->type == TFOR) - fptreef(shf, indent, "for %s ", t->str); - if (t->vars != NULL) { - fptreef(shf, indent, "in "); - for (w = t->vars; *w; ) - fptreef(shf, indent, "%S ", *w++); - fptreef(shf, indent, "%;"); - } - fptreef(shf, indent + INDENT, "do%N%T", t->left); - fptreef(shf, indent, "%;done "); - break; - case TCASE: - fptreef(shf, indent, "case %S in", t->str); - for (t1 = t->left; t1 != NULL; t1 = t1->right) { - fptreef(shf, indent, "%N("); - for (w = t1->vars; *w != NULL; w++) - fptreef(shf, indent, "%S%c", *w, - (w[1] != NULL) ? '|' : ')'); - fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left); - } - fptreef(shf, indent, "%Nesac "); - break; - case TIF: - case TELIF: - /* 3 == strlen("if ") */ - fptreef(shf, indent + 3, "if %T", t->left); - for (;;) { - t = t->right; - if (t->left != NULL) { - fptreef(shf, indent, "%;"); - fptreef(shf, indent + INDENT, "then%N%T", - t->left); - } - if (t->right == NULL || t->right->type != TELIF) - break; - t = t->right; - fptreef(shf, indent, "%;"); - /* 5 == strlen("elif ") */ - fptreef(shf, indent + 5, "elif %T", t->left); - } - if (t->right != NULL) { - fptreef(shf, indent, "%;"); - fptreef(shf, indent + INDENT, "else%;%T", t->right); - } - fptreef(shf, indent, "%;fi "); - break; - case TWHILE: - case TUNTIL: - /* 6 == strlen("while"/"until") */ - fptreef(shf, indent + 6, "%s %T", - (t->type==TWHILE) ? "while" : "until", - t->left); - fptreef(shf, indent, "%;do"); - fptreef(shf, indent + INDENT, "%;%T", t->right); - fptreef(shf, indent, "%;done "); - break; - case TBRACE: - fptreef(shf, indent + INDENT, "{%;%T", t->left); - fptreef(shf, indent, "%;} "); - break; - case TCOPROC: - fptreef(shf, indent, "%T|& ", t->left); - break; - case TASYNC: - fptreef(shf, indent, "%T& ", t->left); - break; - case TFUNCT: - fptreef(shf, indent, "function %s %T", t->str, t->left); - break; - case TTIME: - fptreef(shf, indent, "time %T", t->left); - break; - default: - fptreef(shf, indent, "<botch>"); - break; - } - if ((ioact = t->ioact) != NULL) { - int need_nl = 0; - - while (*ioact != NULL) - pioact(shf, indent, *ioact++); - /* Print here documents after everything else... */ - for (ioact = t->ioact; *ioact != NULL; ) { - struct ioword *iop = *ioact++; - - /* name is 0 when tracing (set -x) */ - if ((iop->flag & IOTYPE) == IOHERE && iop->name) { - struct shf *rshf; - char buf[1024]; - int n; - - tputc('\n', shf); - if ((rshf = shf_open(iop->name, O_RDONLY, 0, 0))) { - while ((n = shf_read(buf, sizeof(buf), rshf)) - > 0) - shf_write(buf, n, shf); - shf_close(rshf); - } else - errorf("can't open %s - %s", - iop->name, strerror(errno)); - fptreef(shf, indent, "%s", evalstr(iop->delim, 0)); - need_nl = 1; - } - } - /* Last delimiter must be followed by a newline (this often - * leads to an extra blank line, but its not worth worrying - * about) - */ - if (need_nl) - tputc('\n', shf); - } -} - -static void -pioact(shf, indent, iop) - register struct shf *shf; - int indent; - register struct ioword *iop; -{ - int flag = iop->flag; - int type = flag & IOTYPE; - int expected; - - expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 - : (type == IOCAT || type == IOWRITE) ? 1 - : (type == IODUP && (iop->unit == !(flag & IORDUP))) ? - iop->unit - : iop->unit + 1; - if (iop->unit != expected) - tputc('0' + iop->unit, shf); - - switch (type) { - case IOREAD: - fptreef(shf, indent, "< "); - break; - case IOHERE: - if (flag&IOSKIP) - fptreef(shf, indent, "<<- "); - else - fptreef(shf, indent, "<< "); - break; - case IOCAT: - fptreef(shf, indent, ">> "); - break; - case IOWRITE: - if (flag&IOCLOB) - fptreef(shf, indent, ">| "); - else - fptreef(shf, indent, "> "); - break; - case IORDWR: - fptreef(shf, indent, "<> "); - break; - case IODUP: - if (flag & IORDUP) - fptreef(shf, indent, "<&"); - else - fptreef(shf, indent, ">&"); - break; - } - /* name/delim are 0 when printing syntax errors */ - if (type == IOHERE) { - if (iop->delim) - fptreef(shf, indent, "%S ", iop->delim); - } else if (iop->name) - fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", - iop->name); -} - - -/* - * variants of fputc, fputs for ptreef and snptreef - */ - -static void -tputC(c, shf) - register int c; - register struct shf *shf; -{ - if ((c&0x60) == 0) { /* C0|C1 */ - tputc((c&0x80) ? '$' : '^', shf); - tputc(((c&0x7F)|0x40), shf); - } else if ((c&0x7F) == 0x7F) { /* DEL */ - tputc((c&0x80) ? '$' : '^', shf); - tputc('?', shf); - } else - tputc(c, shf); -} - -static void -tputS(wp, shf) - register char *wp; - register struct shf *shf; -{ - register int c, quoted=0; - - while (1) - switch ((c = *wp++)) { - case EOS: - return; - case CHAR: - tputC(*wp++, shf); - break; - case QCHAR: - c = *wp++; - if (!quoted || (c == '"' || c == '`' || c == '$')) - tputc('\\', shf); - tputC(c, shf); - break; - case COMSUB: - tputc('$', shf); - tputc('(', shf); - while (*wp != 0) - tputC(*wp++, shf); - tputc(')', shf); - break; - case EXPRSUB: - tputc('$', shf); - tputc('(', shf); - tputc('(', shf); - while (*wp != 0) - tputC(*wp++, shf); - tputc(')', shf); - tputc(')', shf); - break; - case OQUOTE: - quoted = 1; - tputc('"', shf); - break; - case CQUOTE: - quoted = 0; - tputc('"', shf); - break; - case OSUBST: - tputc('$', shf); - tputc('{', shf); - while ((c = *wp++) != 0) - tputC(c, shf); - break; - case CSUBST: - tputc('}', shf); - break; -#ifdef KSH - case OPAT: - tputc(*wp++, shf); - tputc('(', shf); - break; - case SPAT: - tputc('|', shf); - break; - case CPAT: - tputc(')', shf); - break; -#endif /* KSH */ - } -} - -/* - * this is the _only_ way to reliably handle - * variable args with an ANSI compiler - */ -/* VARARGS */ -int -#ifdef HAVE_PROTOTYPES -fptreef(struct shf *shf, int indent, const char *fmt, ...) -#else -fptreef(shf, indent, fmt, va_alist) - struct shf *shf; - int indent; - const char *fmt; - va_dcl -#endif -{ - va_list va; - - SH_VA_START(va, fmt); - - vfptreef(shf, indent, fmt, va); - va_end(va); - return 0; -} - -/* VARARGS */ -char * -#ifdef HAVE_PROTOTYPES -snptreef(char *s, int n, const char *fmt, ...) -#else -snptreef(s, n, fmt, va_alist) - char *s; - int n; - const char *fmt; - va_dcl -#endif -{ - va_list va; - struct shf shf; - - shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); - - SH_VA_START(va, fmt); - vfptreef(&shf, 0, fmt, va); - va_end(va); - - return shf_sclose(&shf); /* null terminates */ -} - -static void -vfptreef(shf, indent, fmt, va) - register struct shf *shf; - int indent; - const char *fmt; - register va_list va; -{ - register int c; - - while ((c = *fmt++)) - if (c == '%') { - register long n; - register char *p; - int neg; - - switch ((c = *fmt++)) { - case 'c': - tputc(va_arg(va, int), shf); - break; - case 's': - p = va_arg(va, char *); - while (*p) - tputc(*p++, shf); - break; - case 'S': /* word */ - p = va_arg(va, char *); - tputS(p, shf); - break; - case 'd': case 'u': /* decimal */ - n = (c == 'd') ? va_arg(va, int) - : va_arg(va, unsigned int); - neg = c=='d' && n<0; - p = ulton((neg) ? -n : n, 10); - if (neg) - *--p = '-'; - while (*p) - tputc(*p++, shf); - break; - case 'T': /* format tree */ - ptree(va_arg(va, struct op *), indent, shf); - break; - case ';': /* newline or ; */ - case 'N': /* newline or space */ - if (shf->flags & SHF_STRING) { - if (c == ';') - tputc(';', shf); - tputc(' ', shf); - } else { - int i; - - tputc('\n', shf); - for (i = indent; i >= 8; i -= 8) - tputc('\t', shf); - for (; i > 0; --i) - tputc(' ', shf); - } - break; - case 'R': - pioact(shf, indent, va_arg(va, struct ioword *)); - break; - default: - tputc(c, shf); - break; - } - } else - tputc(c, shf); -} - -/* - * copy tree (for function definition) - */ - -struct op * -tcopy(t, ap) - register struct op *t; - Area *ap; -{ - register struct op *r; - register char **tw, **rw; - - if (t == NULL) - return NULL; - - r = (struct op *) alloc(sizeof(struct op), ap); - - r->type = t->type; - r->u.evalflags = t->u.evalflags; - - r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap); - - if (t->vars == NULL) - r->vars = NULL; - else { - for (tw = t->vars; *tw++ != NULL; ) - ; - rw = r->vars = (char **) - alloc((int)(tw - t->vars) * sizeof(*tw), ap); - for (tw = t->vars; *tw != NULL; ) - *rw++ = wdcopy(*tw++, ap); - *rw = NULL; - } - - if (t->args == NULL) - r->args = NULL; - else { - for (tw = t->args; *tw++ != NULL; ) - ; - rw = r->args = (char **) - alloc((int)(tw - t->args) * sizeof(*tw), ap); - for (tw = t->args; *tw != NULL; ) - *rw++ = wdcopy(*tw++, ap); - *rw = NULL; - } - - r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); - - r->left = tcopy(t->left, ap); - r->right = tcopy(t->right, ap); - - return r; -} - -char * -wdcopy(wp, ap) - const char *wp; - Area *ap; -{ - size_t len = wdscan(wp, EOS) - wp; - return memcpy(alloc(len, ap), wp, len); -} - -/* return the position of prefix c in wp plus 1 */ -char * -wdscan(wp, c) - register const char *wp; - register int c; -{ - register int nest = 0; - - while (1) - switch (*wp++) { - case EOS: - return (char *) wp; - case CHAR: - case QCHAR: - wp++; - break; - case COMSUB: - case EXPRSUB: - while (*wp++ != 0) - ; - break; - case OQUOTE: - case CQUOTE: - break; - case OSUBST: - nest++; - while (*wp++ != '\0') - ; - break; - case CSUBST: - if (c == CSUBST && nest == 0) - return (char *) wp; - nest--; - break; -#ifdef KSH - case OPAT: - nest++; - wp++; - break; - case SPAT: - case CPAT: - if (c == wp[-1] && nest == 0) - return (char *) wp; - if (wp[-1] == CPAT) - nest--; - break; -#endif /* KSH */ - } -} - -static struct ioword ** -iocopy(iow, ap) - register struct ioword **iow; - Area *ap; -{ - register struct ioword **ior; - register int i; - - for (ior = iow; *ior++ != NULL; ) - ; - ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap); - - for (i = 0; iow[i] != NULL; i++) { - register struct ioword *p, *q; - - p = iow[i]; - q = (struct ioword *) alloc(sizeof(*p), ap); - ior[i] = q; - *q = *p; - if (p->name != (char *) 0) - q->name = wdcopy(p->name, ap); - if (p->delim != (char *) 0) - q->delim = wdcopy(p->delim, ap); - } - ior[i] = NULL; - - return ior; -} - -/* - * free tree (for function definition) - */ - -void -tfree(t, ap) - register struct op *t; - Area *ap; -{ - register char **w; - - if (t == NULL) - return; - - if (t->str != NULL) - afree((void*)t->str, ap); - - if (t->vars != NULL) { - for (w = t->vars; *w != NULL; w++) - afree((void*)*w, ap); - afree((void*)t->vars, ap); - } - - if (t->args != NULL) { - for (w = t->args; *w != NULL; w++) - afree((void*)*w, ap); - afree((void*)t->args, ap); - } - - if (t->ioact != NULL) - iofree(t->ioact, ap); - - tfree(t->left, ap); - tfree(t->right, ap); - - afree((void*)t, ap); -} - -static void -iofree(iow, ap) - struct ioword **iow; - Area *ap; -{ - register struct ioword **iop; - register struct ioword *p; - - for (iop = iow; (p = *iop++) != NULL; ) { - if (p->name != NULL) - afree((void*)p->name, ap); - afree((void*)p, ap); - } -} diff --git a/bin/pdksh/tree.h b/bin/pdksh/tree.h deleted file mode 100644 index 863061dd91d..00000000000 --- a/bin/pdksh/tree.h +++ /dev/null @@ -1,137 +0,0 @@ -/* $OpenBSD: tree.h,v 1.2 1996/08/19 20:09:02 downsj Exp $ */ - -/* - * command trees for compile/execute - */ - -/* $From: tree.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */ - -#define NOBLOCK ((struct op *)NULL) -#define NOWORD ((char *)NULL) -#define NOWORDS ((char **)NULL) - -/* - * Description of a command or an operation on commands. - */ -struct op { - short type; /* operation type, see below */ - 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, < > >>) */ - struct op *left, *right; /* descendents */ - char *str; /* word for case; identifier for for, - * select, and functions; - * path to execute for TEXEC - */ -}; - -/* Tree.type values */ -#define TEOF 0 -#define TCOM 1 /* command */ -#define TPAREN 2 /* (c-list) */ -#define TPIPE 3 /* a | b */ -#define TLIST 4 /* a ; b */ -#define TOR 5 /* || */ -#define TAND 6 /* && */ -#define TBANG 7 /* ! */ -#define TDBRACKET 8 /* [[ .. ]] */ -#define TFOR 9 -#define TSELECT 10 -#define TCASE 11 -#define TIF 12 -#define TWHILE 13 -#define TUNTIL 14 -#define TELIF 15 -#define TPAT 16 /* pattern in case */ -#define TBRACE 17 /* {c-list} */ -#define TASYNC 18 /* c & */ -#define TFUNCT 19 /* function name { command; } */ -#define TTIME 20 /* time pipeline */ -#define TEXEC 21 /* fork/exec eval'd TCOM */ -#define TCOPROC 22 /* coprocess |& */ - -/* - * prefix codes for words in command tree - */ -#define EOS 0 /* end of string */ -#define CHAR 1 /* unquoted character */ -#define QCHAR 2 /* quoted character */ -#define COMSUB 3 /* $() substitution (0 terminated) */ -#define EXPRSUB 4 /* $(()) substitution (0 terminated) */ -#define OQUOTE 5 /* opening " or ' */ -#define CQUOTE 6 /* closing " or ' */ -#define OSUBST 7 /* opening ${ substitution */ -#define CSUBST 8 /* closing } of above */ -#define OPAT 9 /* open pattern: *(, @(, etc. */ -#define SPAT 10 /* seperate pattern: | */ -#define CPAT 11 /* close pattern: ) */ - -/* - * IO redirection - */ -struct ioword { - int unit; /* unit affected */ - int flag; /* action (below) */ - char *name; /* file name */ - char *delim; /* delimiter for <<,<<- */ -}; - -/* ioword.flag - type of redirection */ -#define IOTYPE 0xF /* type: bits 0:3 */ -#define IOREAD 0x1 /* < */ -#define IOWRITE 0x2 /* > */ -#define IORDWR 0x3 /* <>: todo */ -#define IOHERE 0x4 /* << (here file) */ -#define IOCAT 0x5 /* >> */ -#define IODUP 0x6 /* <&/>& */ -#define IOEVAL BIT(4) /* expand in << */ -#define IOSKIP BIT(5) /* <<-, skip ^\t* */ -#define IOCLOB BIT(6) /* >|, override -o noclobber */ -#define IORDUP BIT(7) /* x<&y (as opposed to x>&y) */ -#define IONAMEXP BIT(8) /* name has been expanded */ - -/* execute/exchild flags */ -#define XEXEC BIT(0) /* execute without forking */ -#define XFORK BIT(1) /* fork before executing */ -#define XBGND BIT(2) /* command & */ -#define XPIPEI BIT(3) /* input is pipe */ -#define XPIPEO BIT(4) /* output is pipe */ -#define XPIPE (XPIPEI|XPIPEO) /* member of pipe */ -#define XXCOM BIT(5) /* `...` command */ -#define XPCLOSE BIT(6) /* exchild: close close_fd in parent */ -#define XCCLOSE BIT(7) /* exchild: close close_fd in child */ -#define XERROK BIT(8) /* non-zero exit ok (for set -e) */ -#define XCOPROC BIT(9) /* starting a co-process */ - -/* - * flags to control expansion of words (assumed by t->evalflags to fit - * in a short) - */ -#define DOBLANK BIT(0) /* perform blank interpretation */ -#define DOGLOB BIT(1) /* expand [?* */ -#define DOPAT BIT(2) /* quote *?[ */ -#define DOTILDE BIT(3) /* normal ~ expansion (first char) */ -#define DONTRUNCOMMAND BIT(4) /* do not run $(command) things */ -#define DOASNTILDE BIT(5) /* assignment ~ expansion (after =, :) */ -#define DOBRACE_ BIT(6) /* used by expand(): do brace expansion */ -#define DOMAGIC_ BIT(7) /* used by expand(): string contains MAGIC */ -#define DOTEMP_ BIT(8) /* ditto : in word part of ${..[%#=?]..} */ -#define DOVACHECK BIT(9) /* var assign check (for typeset, set, etc) */ -#define DOMARKDIRS BIT(10) /* force markdirs behaviour */ - -/* - * The arguments of [[ .. ]] expressions are kept in t->args[] and flags - * indicating how the arguments have been munged are kept in t->vars[]. - * The contents of t->vars[] are stuffed strings (so they can be treated - * like all other t->vars[]) in which the second character is the one that - * is examined. The DB_* defines are the values for these second characters. - */ -#define DB_NORM 1 /* normal argument */ -#define DB_OR 2 /* || -> -o conversion */ -#define DB_AND 3 /* && -> -a conversion */ -#define DB_BE 4 /* an inserted -BE */ -#define DB_PAT 5 /* a pattern argument */ diff --git a/bin/pdksh/tty.c b/bin/pdksh/tty.c deleted file mode 100644 index 00a94cd3ae6..00000000000 --- a/bin/pdksh/tty.c +++ /dev/null @@ -1,179 +0,0 @@ -/* $OpenBSD: tty.c,v 1.2 1996/10/01 02:05:51 downsj Exp $ */ - -#include "sh.h" -#include "ksh_stat.h" -#define EXTERN -#include "tty.h" -#undef EXTERN - -int -get_tty(fd, ts) - int fd; - TTY_state *ts; -{ - int ret; - -# ifdef HAVE_TERMIOS_H - ret = tcgetattr(fd, ts); -# else /* HAVE_TERIOS_H */ -# ifdef HAVE_TERMIO_H - ret = ioctl(fd, TCGETA, ts); -# else /* HAVE_TERMIO_H */ - ret = ioctl(fd, TIOCGETP, &ts->sgttyb); -# ifdef TIOCGATC - if (ioctl(fd, TIOCGATC, &ts->lchars) < 0) - ret = -1; -# else - if (ioctl(fd, TIOCGETC, &ts->tchars) < 0) - ret = -1; -# ifdef TIOCGLTC - if (ioctl(fd, TIOCGLTC, &ts->ltchars) < 0) - ret = -1; -# endif /* TIOCGLTC */ -# endif /* TIOCGATC */ -# endif /* HAVE_TERMIO_H */ -# endif /* HAVE_TERIOS_H */ - return ret; -} - -int -set_tty(fd, ts, flags) - int fd; - TTY_state *ts; - int flags; -{ - int ret = 0; - -# ifdef HAVE_TERMIOS_H - ret = tcsetattr(fd, TCSADRAIN, ts); -# else /* HAVE_TERIOS_H */ -# ifdef HAVE_TERMIO_H -# ifndef TCSETAW /* e.g. Cray-2 */ - /* first wait for output to drain */ -# ifdef TCSBRK - if (ioctl(tty_fd, TCSBRK, 1) < 0) - ret = -1; -# else /* the following kludge is minimally intrusive, but sometimes fails */ - if (flags & TF_WAIT) - sleep((unsigned)1); /* fake it */ -# endif -# endif /* !TCSETAW */ -# if defined(_BSD_SYSV) || !defined(TCSETAW) -/* _BSD_SYSV must force TIOCSETN instead of TIOCSETP (preserve type-ahead) */ - if (ioctl(tty_fd, TCSETA, ts) < 0) - ret = -1; -# else - if (ioctl(tty_fd, TCSETAW, ts) < 0) - ret = -1; -# endif -# else /* HAVE_TERMIO_H */ -# if defined(__mips) && (defined(_SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43)) - /* Under RISC/os 5.00, bsd43 environment, after a tty driver - * generated interrupt (eg, INTR, TSTP), all output to tty is - * lost until a SETP is done (there must be a better way of - * doing this...). - */ - if (flags & TF_MIPSKLUDGE) - ret = ioctl(fd, TIOCSETP, &ts->sgttyb); - else -# endif /* _SYSTYPE_BSD43 */ - ret = ioctl(fd, TIOCSETN, &ts->sgttyb); -# ifdef TIOCGATC - if (ioctl(fd, TIOCSATC, &ts->lchars) < 0) - ret = -1; -# else - if (ioctl(fd, TIOCSETC, &ts->tchars) < 0) - ret = -1; -# ifdef TIOCGLTC - if (ioctl(fd, TIOCSLTC, &ts->ltchars) < 0) - ret = -1; -# endif /* TIOCGLTC */ -# endif /* TIOCGATC */ -# endif /* HAVE_TERMIO_H */ -# endif /* HAVE_TERIOS_H */ - return ret; -} - - -/* Initialize tty_fd. Used for saving/reseting tty modes upon - * foreground job completion and for setting up tty process group. - */ -void -tty_init(init_ttystate) - int init_ttystate; -{ - int do_close = 1; - int tfd; - - if (tty_fd >= 0) { - close(tty_fd); - tty_fd = -1; - } - tty_devtty = 1; - - /* SCO can't job control on /dev/tty, so don't try... */ -#if !defined(__SCO__) - if ((tfd = open("/dev/tty", O_RDWR, 0)) < 0) { -#ifdef __NeXT - /* rlogin on NeXT boxes does not set up the controlling tty, - * so force it to be done here... - */ - { - extern char *ttyname ARGS((int)); - char *s = ttyname(isatty(2) ? 2 : 0); - int fd; - - if (s && (fd = open(s, O_RDWR, 0)) >= 0) { - close(fd); - tfd = open("/dev/tty", O_RDWR, 0); - } - } -#endif /* __NeXT */ - -/* X11R5 xterm on mips doesn't set controlling tty properly - temporary hack */ -# if !defined(__mips) || !(defined(_SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43)) - if (tfd < 0) { - tty_devtty = 0; - warningf(FALSE, - "No controlling tty (open /dev/tty: %s)", - strerror(errno)); - } -# endif /* __mips */ - } -#else /* !__SCO__ */ - tfd = -1; -#endif /* __SCO__ */ - - if (tfd < 0) { - do_close = 0; - if (isatty(0)) - tfd = 0; - else if (isatty(2)) - tfd = 2; - else { - warningf(FALSE, "Can't find tty file descriptor"); - return; - } - } - if ((tty_fd = ksh_dupbase(tfd, FDBASE)) < 0) { - warningf(FALSE, "j_ttyinit: dup of tty fd failed: %s", - strerror(errno)); - } else if (fd_clexec(tty_fd) < 0) { - warningf(FALSE, "j_ttyinit: can't set close-on-exec flag: %s", - strerror(errno)); - close(tty_fd); - tty_fd = -1; - } else if (init_ttystate) - get_tty(tty_fd, &tty_state); - if (do_close) - close(tfd); -} - -void -tty_close() -{ - if (tty_fd >= 0) { - close(tty_fd); - tty_fd = -1; - } -} diff --git a/bin/pdksh/tty.h b/bin/pdksh/tty.h deleted file mode 100644 index a6cd2dae1e9..00000000000 --- a/bin/pdksh/tty.h +++ /dev/null @@ -1,109 +0,0 @@ -/* $OpenBSD: tty.h,v 1.2 1996/11/21 07:59:36 downsj Exp $ */ - -/* - tty.h -- centralized definitions for a variety of terminal interfaces - - created by DPK, Oct. 1986 - - Rearranged to work with autoconf, added TTY_state, get_tty/set_tty - Michael Rendell, May '94 - - last edit: 30-Jul-1987 D A Gwyn -*/ - -/* some useful #defines */ -#ifdef EXTERN -# define I__(i) = i -#else -# define I__(i) -# define EXTERN extern -# define EXTERN_DEFINED -#endif - -/* Don't know of a system on which including sys/ioctl.h with termios.h - * causes problems. If there is one, these lines need to be deleted and - * aclocal.m4 needs to have stuff un-commented. - */ -#ifdef SYS_IOCTL_WITH_TERMIOS -# define SYS_IOCTL_WITH_TERMIOS -#endif /* SYS_IOCTL_WITH_TERMIOS */ -#ifdef SYS_IOCTL_WITH_TERMIO -# define SYS_IOCTL_WITH_TERMIO -#endif /* SYS_IOCTL_WITH_TERMIO */ - -#ifdef HAVE_TERMIOS_H -# include <termios.h> -# ifdef SYS_IOCTL_WITH_TERMIOS -# if !(defined(sun) && !defined(__svr4__)) /* too many warnings on sunos */ - /* Need to include sys/ioctl.h on some systems to get the TIOCGWINSZ - * stuff (eg, digital unix). - */ -# include <sys/ioctl.h> -# endif /* !(sun && !__svr4__) */ -# endif /* SYS_IOCTL_WITH_TERMIOS */ -typedef struct termios TTY_state; -#else -# ifdef HAVE_TERMIO_H -# include <termio.h> -# ifdef SYS_IOCTL_WITH_TERMIO -# include <sys/ioctl.h> /* see comment above in termios stuff */ -# endif /* SYS_IOCTL_WITH_TERMIO */ -# if _BSD_SYSV /* BRL UNIX System V emulation */ -# ifndef NTTYDISC -# define TIOCGETD _IOR( 't', 0, int ) -# define TIOCSETD _IOW( 't', 1, int ) -# define NTTYDISC 2 -# endif -# ifndef TIOCSTI -# define TIOCSTI _IOW( 't', 114, char ) -# endif -# ifndef TIOCSPGRP -# define TIOCSPGRP _IOW( 't', 118, int ) -# endif -# endif /* _BSD_SYSV */ -typedef struct termio TTY_state; -# else /* HAVE_TERMIO_H */ -/* Assume BSD tty stuff. Uses TIOCGETP, TIOCSETN; uses TIOCGATC/TIOCSATC if - * available, otherwise it uses TIOCGETC/TIOCSETC (also uses TIOCGLTC/TIOCSLTC - * if available) - */ -# ifdef _MINIX -# include <sgtty.h> -# define TIOCSETN TIOCSETP -# else -# include <sys/ioctl.h> -# endif -typedef struct { - struct sgttyb sgttyb; -# ifdef TIOCGATC - struct lchars lchars; -# else /* TIOCGATC */ - struct tchars tchars; -# ifdef TIOCGLTC - struct ltchars ltchars; -# endif /* TIOCGLTC */ -# endif /* TIOCGATC */ -} TTY_state; -# endif /* HAVE_TERMIO_H */ -#endif /* HAVE_TERMIOS_H */ - -/* Flags for set_tty() */ -#define TF_NONE 0x00 -#define TF_WAIT 0x01 /* drain output, even it requires sleep() */ -#define TF_MIPSKLUDGE 0x02 /* kludge to unwedge RISC/os 5.0 tty driver */ - -EXTERN int tty_fd I__(-1); /* dup'd tty file descriptor */ -EXTERN int tty_devtty; /* true if tty_fd is from /dev/tty */ -EXTERN TTY_state tty_state; /* saved tty state */ - -extern int get_tty ARGS((int fd, TTY_state *ts)); -extern int set_tty ARGS((int fd, TTY_state *ts, int flags)); -extern void tty_init ARGS((int init_ttystate)); -extern void tty_close ARGS((void)); - -/* be sure not to interfere with anyone else's idea about EXTERN */ -#ifdef EXTERN_DEFINED -# undef EXTERN_DEFINED -# undef EXTERN -#endif -#undef I__ diff --git a/bin/pdksh/var.c b/bin/pdksh/var.c deleted file mode 100644 index 8350846a148..00000000000 --- a/bin/pdksh/var.c +++ /dev/null @@ -1,1137 +0,0 @@ -/* $OpenBSD: var.c,v 1.6 1997/09/01 18:30:16 deraadt Exp $ */ - -#include "sh.h" -#include "ksh_time.h" -#include "ksh_limval.h" -#include "ksh_stat.h" -#include <ctype.h> - -/* - * Variables - * - * WARNING: unreadable code, needs a rewrite - * - * if (flag&INTEGER), val.i contains integer value, and type contains base. - * otherwise, (val.s + type) contains string value. - * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. - */ -static struct tbl vtemp; -static struct table specials; -static char *formatstr ARGS((struct tbl *vp, const char *s)); -static void export ARGS((struct tbl *vp, const char *val)); -static int special ARGS((const char *name)); -static void getspec ARGS((struct tbl *vp)); -static void setspec ARGS((struct tbl *vp)); -static void unsetspec ARGS((struct tbl *vp)); -static struct tbl *arraysearch ARGS((struct tbl *, int)); - -/* - * create a new block for function calls and simple commands - * assume caller has allocated and set up e->loc - */ -void -newblock() -{ - register struct block *l; - static char *const empty[] = {null}; - - l = (struct block *) alloc(sizeof(struct block), ATEMP); - ainit(&l->area); - if (!e->loc) { - l->argc = 0; - l->argv = (char **) empty; - } else { - l->argc = e->loc->argc; - l->argv = e->loc->argv; - } - l->exit = l->error = NULL; - tinit(&l->vars, &l->area, 0); - tinit(&l->funs, &l->area, 0); - l->next = e->loc; - e->loc = l; -} - -/* - * pop a block handling special variables - */ -void -popblock() -{ - register struct block *l = e->loc; - register struct tbl *vp, **vpp = l->vars.tbls, *vq; - register int i; - - e->loc = l->next; /* pop block */ - for (i = l->vars.size; --i >= 0; ) - if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) - if ((vq = global(vp->name))->flag & ISSET) - setspec(vq); - else - unsetspec(vq); - afreeall(&l->area); - afree(l, ATEMP); -} - -/* called by main() to initialize variable data structures */ -void -initvar() -{ - static const struct { - const char *name; - int v; - } names[] = { - { "COLUMNS", V_COLUMNS }, - { "IFS", V_IFS }, - { "OPTIND", V_OPTIND }, - { "PATH", V_PATH }, - { "POSIXLY_CORRECT", V_POSIXLY_CORRECT }, - { "TMPDIR", V_TMPDIR }, -#ifdef HISTORY - { "HISTFILE", V_HISTFILE }, - { "HISTSIZE", V_HISTSIZE }, -#endif /* HISTORY */ -#ifdef EDIT - { "EDITOR", V_EDITOR }, - { "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 }, -#endif /* KSH */ - { (char *) 0, 0 } - }; - int i; - struct tbl *tp; - - tinit(&specials, APERM, 32); /* must be 2^n (currently 16 speciasl) */ - for (i = 0; names[i].name; i++) { - tp = tenter(&specials, names[i].name, hash(names[i].name)); - tp->flag = DEFINED|ISSET; - tp->type = names[i].v; - } -} - -/* Used to calculate an array index for global()/local(). Sets *arrayp to - * non-zero if this is an array, sets *valp to the array index, returns - * the basename of the array. - */ -const char * -array_index_calc(n, arrayp, valp) - const char *n; - bool_t *arrayp; - int *valp; -{ - const char *p; - int len; - - *arrayp = FALSE; - p = skip_varname(n, FALSE); - if (p != n && *p == '[' && (len = array_ref_len(p))) { - char *sub, *tmp; - long rval; - - /* Calculate the value of the subscript */ - *arrayp = TRUE; - tmp = str_nsave(p+1, len-2, ATEMP); - sub = substitute(tmp, 0); - afree(tmp, ATEMP); - n = str_nsave(n, p - n, ATEMP); - evaluate(sub, &rval, FALSE); - if (rval < 0 || rval > ARRAYMAX) - errorf("%s: subscript out of range", n); - *valp = rval; - afree(sub, ATEMP); - } - return n; -} - -/* - * Search for variable, if not found create globally. - */ -struct tbl * -global(n) - register const char *n; -{ - register struct block *l = e->loc; - register struct tbl *vp; - register int c; - unsigned h; - bool_t array; - int val; - - /* Check to see if this is an array */ - n = array_index_calc(n, &array, &val); - h = hash(n); - c = n[0]; - if (!letter(c)) { - if (array) - errorf("bad substitution"); - vp = &vtemp; - vp->flag = (DEFINED|RDONLY); - vp->type = 0; - vp->areap = ATEMP; - *vp->name = c; - if (digit(c)) { - for (c = 0; digit(*n); n++) - c = c*10 + *n-'0'; - if (c <= l->argc) - setstr(vp, l->argv[c]); - return vp; - } - if (n[1] != '\0') - return vp; - vp->flag |= ISSET|INTEGER; - switch (c) { - case '$': - vp->val.i = kshpid; - break; - case '!': - /* If no job, expand to nothing */ - if ((vp->val.i = j_async()) == 0) - vp->flag &= ~(ISSET|INTEGER); - break; - case '?': - vp->val.i = exstat; - break; - case '#': - vp->val.i = l->argc; - break; - case '-': - vp->flag &= ~INTEGER; - vp->val.s = getoptions(); - break; - default: - vp->flag &= ~(ISSET|INTEGER); - } - return vp; - } - for (l = e->loc; ; l = l->next) { - vp = tsearch(&l->vars, n, h); - if (vp != NULL) - if (array) - return arraysearch(vp, val); - else - return vp; - if (l->next == NULL) - break; - } - vp = tenter(&l->vars, n, h); - if (array) - vp = arraysearch(vp, val); - vp->flag |= DEFINED; - if (special(n)) - vp->flag |= SPECIAL; - return vp; -} - -/* - * Search for local variable, if not found create locally. - */ -struct tbl * -local(n, copy) - register const char *n; - bool_t copy; -{ - register struct block *l = e->loc; - register struct tbl *vp; - unsigned h; - bool_t array; - int val; - - /* Check to see if this is an array */ - n = array_index_calc(n, &array, &val); - h = hash(n); - if (!letter(*n)) { - vp = &vtemp; - vp->flag = DEFINED|RDONLY; - vp->type = 0; - vp->areap = ATEMP; - return vp; - } - vp = tenter(&l->vars, n, h); - if (copy && !(vp->flag & DEFINED)) { - struct block *ll = l; - struct tbl *vq = (struct tbl *) 0; - - while ((ll = ll->next) && !(vq = tsearch(&ll->vars, n, h))) - ; - if (vq) { - vp->flag |= vq->flag & (EXPORT|INTEGER|RDONLY - |LJUST|RJUST|ZEROFIL - |LCASEV|UCASEV_AL|INT_U|INT_L); - if (vq->flag & INTEGER) - vp->type = vq->type; - vp->u2.field = vq->u2.field; - } - } - if (array) - vp = arraysearch(vp, val); - vp->flag |= DEFINED; - if (special(n)) - vp->flag |= SPECIAL; - return vp; -} - -/* get variable string value */ -char * -str_val(vp) - register struct tbl *vp; -{ - char *s; - - if ((vp->flag&SPECIAL)) - getspec(vp); - if (!(vp->flag&ISSET)) - s = null; /* special to dollar() */ - else if (!(vp->flag&INTEGER)) /* string source */ - s = vp->val.s + vp->type; - else { /* integer source */ - /* worst case number length is when base=2, so use BITS(long) */ - /* minus base # number null */ - static char strbuf[1 + 2 + 1 + BITS(long) + 1]; - const char *digits = (vp->flag & UCASEV_AL) ? - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - : "0123456789abcdefghijklmnopqrstuvwxyz"; - register unsigned long n; - register int base; - - s = strbuf + sizeof(strbuf); - if (vp->flag & INT_U) - n = (unsigned long) vp->val.i; - else - n = (vp->val.i < 0) ? -vp->val.i : vp->val.i; - base = (vp->type == 0) ? 10 : vp->type; - - *--s = '\0'; - do { - *--s = digits[n % base]; - n /= base; - } while (n != 0); - if (base != 10) { - *--s = '#'; - *--s = digits[base % 10]; - if (base >= 10) - *--s = digits[base / 10]; - } - if (!(vp->flag & INT_U) && vp->val.i < 0) - *--s = '-'; - if (vp->flag & (RJUST|LJUST)) /* case already dealt with */ - s = formatstr(vp, s); - } - return s; -} - -/* get variable integer value, with error checking */ -long -intval(vp) - register struct tbl *vp; -{ - long num; - int base; - - base = getint(vp, &num); - if (base == -1) - /* XXX check calls - is error here ok by POSIX? */ - errorf("%s: bad number", str_val(vp)); - return num; -} - -/* set variable to string value */ -void -setstr(vq, s) - register struct tbl *vq; - const char *s; -{ - if (!(vq->flag&INTEGER)) { /* string dest */ - if ((vq->flag&ALLOC)) { - /* debugging */ - if (s >= vq->val.s - && s <= vq->val.s + strlen(vq->val.s)) - internal_errorf(TRUE, - "setstr: %s=%s: assigning to self", - vq->name, s); - afree((void*)vq->val.s, vq->areap); - } - vq->flag &= ~(ISSET|ALLOC); - vq->type = 0; - if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) - s = formatstr(vq, s); - if ((vq->flag&EXPORT)) - export(vq, s); - else { - vq->val.s = str_save(s, vq->areap); - if (vq->val.s) /* <sjg> don't lie */ - vq->flag |= ALLOC; - } - } else /* integer dest */ - /* XXX is this correct? */ - v_evaluate(vq, s, FALSE); - vq->flag |= ISSET; - if ((vq->flag&SPECIAL)) - setspec(vq); -} - -/* set variable to integer */ -void -setint(vq, n) - register struct tbl *vq; - long n; -{ - if (!(vq->flag&INTEGER)) { - register struct tbl *vp = &vtemp; - vp->flag = (ISSET|INTEGER); - vp->type = 0; - vp->areap = ATEMP; - vp->val.i = n; - setstr(vq, str_val(vp)); - } else - vq->val.i = n; - vq->flag |= ISSET; - if ((vq->flag&SPECIAL)) - setspec(vq); -} - -int -getint(vp, nump) - struct tbl *vp; - long *nump; -{ - register char *s; - register int c; - int base, neg; - int have_base = 0; - long num; - - if (vp->flag&SPECIAL) - getspec(vp); - /* XXX is it possible for ISSET to be set and val.s to be 0? */ - if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) - return -1; - if (vp->flag&INTEGER) { - *nump = vp->val.i; - return vp->type; - } - s = vp->val.s + vp->type; - if (s == NULL) /* redundent given initial test */ - s = null; - base = 10; - num = 0; - neg = 0; - for (c = *s++; c ; c = *s++) { - if (c == '-') { - neg++; - } else if (c == '#') { - base = (int) num; - if (have_base || base < 2 || base > 36) - return -1; - num = 0; - have_base = 1; - } else if (letnum(c)) { - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; /* todo: assumes ascii */ - else if (isupper(c)) - c -= 'A' - 10; /* todo: assumes ascii */ - else - c = -1; /* _: force error */ - if (c < 0 || c >= base) - return -1; - num = num * base + c; - } else - return -1; - } - if (neg) - num = -num; - *nump = num; - return base; -} - -/* convert variable vq to integer variable, setting its value from vp - * (vq and vp may be the same) - */ -struct tbl * -setint_v(vq, vp) - register struct tbl *vq, *vp; -{ - int base; - long num; - - if ((base = getint(vp, &num)) == -1) - return NULL; - if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { - vq->flag &= ~ALLOC; - afree(vq->val.s, vq->areap); - } - vq->val.i = num; - if (vq->type == 0) /* default base */ - vq->type = base; - vq->flag |= ISSET|INTEGER; - if (vq->flag&SPECIAL) - setspec(vq); - return vq; -} - -static char * -formatstr(vp, s) - struct tbl *vp; - const char *s; -{ - int olen, nlen; - char *p, *q; - - olen = strlen(s); - - if (vp->flag & (RJUST|LJUST)) { - if (!vp->u2.field) /* default field width */ - vp->u2.field = olen; - nlen = vp->u2.field; - } else - nlen = olen; - - p = (char *) alloc(nlen + 1, ATEMP); - if (vp->flag & (RJUST|LJUST)) { - int slen; - - if (vp->flag & RJUST) { - const char *q = s + olen; - /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */ - while (q > s && isspace(q[-1])) - --q; - slen = q - s; - 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->u2.field - slen, null, slen, s); - } else { - /* strip leading spaces/zeros */ - while (isspace(*s)) - s++; - if (vp->flag & ZEROFIL) - while (*s == '0') - s++; - shf_snprintf(p, nlen + 1, "%-*.*s", - vp->u2.field, vp->u2.field, s); - } - } else - memcpy(p, s, olen + 1); - - if (vp->flag & UCASEV_AL) { - for (q = p; *q; q++) - if (islower(*q)) - *q = toupper(*q); - } else if (vp->flag & LCASEV) { - for (q = p; *q; q++) - if (isupper(*q)) - *q = tolower(*q); - } - - return p; -} - -/* - * make vp->val.s be "name=value" for quick exporting. - */ -static void -export(vp, val) - register struct tbl *vp; - const char *val; -{ - register char *xp; - char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; - int namelen = strlen(vp->name); - int vallen = strlen(val) + 1; - - vp->flag |= ALLOC; - xp = (char*)alloc(namelen + 1 + vallen, vp->areap); - memcpy(vp->val.s = xp, vp->name, namelen); - xp += namelen; - *xp++ = '='; - vp->type = xp - vp->val.s; /* offset to value */ - memcpy(xp, val, vallen); - if (op != NULL) - afree((void*)op, vp->areap); -} - -/* - * lookup variable (according to (set&LOCAL)), - * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, - * LCASEV, UCASEV_AL), and optionally set its value if an assignment. - */ -struct tbl * -typeset(var, set, clr, field, base) - register const char *var; - Tflag clr, set; - int field, base; -{ - register struct tbl *vp; - struct tbl *vpbase, *t; - char *tvar; - const char *val; - - /* check for valid variable name, search for value */ - val = skip_varname(var, FALSE); - if (val == var) - return NULL; - if (*val == '[') { - int len; - - len = array_ref_len(val); - if (len == 0) - return NULL; - /* IMPORT is only used when the shell starts up and is - * setting up its environment. Allow only simple array - * references at this time since parameter/command substitution - * is preformed on the [expression], which would be a major - * security hole. - */ - if (set & IMPORT) { - int i; - for (i = 1; i < len - 1; i++) - if (!digit(val[i])) - return NULL; - } - val += len; - } - if (*val == '=') - tvar = str_nsave(var, val++ - var, ATEMP); - else { - /* Importing from original envirnment: must have an = */ - if (set & IMPORT) - return NULL; - tvar = (char *) var; - val = NULL; - } - - /* Prevent typeset from creating a local PATH/ENV/SHELL */ - if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 - || strcmp(tvar, "ENV") == 0 - || strcmp(tvar, "SHELL") == 0)) - errorf("%s: restricted", 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; - - /* only allow export flag to be set. at&t ksh allows any attribute to - * be changed, which means it can be truncated or modified - * (-L/-R/-Z/-i). - */ - if ((vpbase->flag&RDONLY) - && (val || clr || (set & ~EXPORT))) - /* XXX check calls - is error here ok by POSIX? */ - errorf("%s: is read only", tvar); - if (val) - afree(tvar, ATEMP); - - /* most calls are with set/clr == 0 */ - if (set | clr) { - /* XXX if x[0] isn't set, there will be problems: need to have - * one copy of attributes for arrays... - */ - for (t = vpbase; t; t = t->u.array) { - int fake_assign; - char UNINITIALIZED(*s); - char UNINITIALIZED(*free_me); - - fake_assign = (t->flag & ISSET) && (!val || t != vp) - && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) - || ((t->flag & INTEGER) && (clr & INTEGER)) - || (!(t->flag & INTEGER) && (set & INTEGER))); - if (fake_assign) { - if (t->flag & INTEGER) { - s = str_val(t); - free_me = (char *) 0; - } else { - s = t->val.s + t->type; - free_me = (t->flag & ALLOC) ? t->val.s - : (char *) 0; - } - t->flag &= ~ALLOC; - } - if (!(t->flag & INTEGER) && (set & INTEGER)) { - t->type = 0; - t->flag &= ~ALLOC; - } - t->flag = (t->flag | set) & ~clr; - /* Don't change base if assignment is to be done, - * in case assignment fails. - */ - if ((set & INTEGER) && base > 0 && (!val || t != vp)) - t->type = base; - if (set & (LJUST|RJUST|ZEROFIL)) - t->u2.field = field; - if (fake_assign) { - setstr(t, s); - if (free_me) - afree((void *) free_me, t->areap); - } - } - } - - if (val != NULL) { - if (vp->flag&INTEGER) { - /* do not zero base before assignment */ - setstr(vp, val); - /* Done after assignment to override default */ - if (base > 0) - vp->type = base; - } else - setstr(vp, val); - } - - /* only x[0] is ever exported, so use vpbase */ - if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) - && vpbase->type == 0) - export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); - - return vp; -} - -/* Unset a variable. array_ref is set if there was an array reference in - * the name lookup (eg, x[2]). - */ -void -unset(vp, array_ref) - register struct tbl *vp; - int array_ref; -{ - if (vp->flag & ALLOC) - afree((void*)vp->val.s, vp->areap); - if ((vp->flag & ARRAY) && !array_ref) { - struct tbl *a, *tmp; - - /* Free up entire array */ - for (a = vp->u.array; a; ) { - tmp = a; - a = a->u.array; - if (tmp->flag & ALLOC) - afree((void *) tmp->val.s, tmp->areap); - afree(tmp, tmp->areap); - } - vp->u.array = (struct tbl *) 0; - } - /* 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); /* responsible for `unspecial'ing var */ -} - -/* return a pointer to the first char past a legal variable name (returns the - * argument if there is no legal name, returns * a pointer to the terminating - * null if whole string is legal). - */ -char * -skip_varname(s, aok) - const char *s; - int aok; -{ - int alen; - - if (s && letter(*s)) { - while (*++s && letnum(*s)) - ; - if (aok && *s == '[' && (alen = array_ref_len(s))) - s += alen; - } - return (char *) s; -} - -/* Return a pointer to the first character past any legal variable name. */ -char * -skip_wdvarname(s, aok) - const char *s; - int aok; /* skip array de-reference? */ -{ - if (s[0] == CHAR && letter(s[1])) { - do - s += 2; - while (s[0] == CHAR && letnum(s[1])); - if (aok && s[0] == CHAR && s[1] == '[') { - /* skip possible array de-reference */ - const char *p = s; - char c; - int depth = 0; - - while (1) { - if (p[0] != CHAR) - break; - c = p[1]; - p += 2; - if (c == '[') - depth++; - else if (c == ']' && --depth == 0) { - s = p; - break; - } - } - } - } - return (char *) s; -} - -/* Check if coded string s is a variable name */ -int -is_wdvarname(s, aok) - const char *s; - int aok; -{ - char *p = skip_wdvarname(s, aok); - - return p != s && p[0] == EOS; -} - -/* Check if coded string s is a variable assignment */ -int -is_wdvarassign(s) - const char *s; -{ - char *p = skip_wdvarname(s, TRUE); - - return p != s && p[0] == CHAR && p[1] == '='; -} - -/* - * Make the exported environment from the exported names in the dictionary. - */ -char ** -makenv() -{ - struct block *l = e->loc; - XPtrV env; - register struct tbl *vp, **vpp; - register int i; - - XPinit(env, 64); - for (l = e->loc; l != NULL; l = l->next) - for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; ) - if ((vp = *vpp++) != NULL - && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { - register struct block *l2; - register struct tbl *vp2; - unsigned h = hash(vp->name); - - /* unexport any redefined instances */ - for (l2 = l->next; l2 != NULL; l2 = l2->next) { - vp2 = tsearch(&l2->vars, vp->name, h); - if (vp2 != NULL) - vp2->flag &= ~EXPORT; - } - if ((vp->flag&INTEGER)) { - /* integer to string */ - char *val; - val = str_val(vp); - vp->flag &= ~INTEGER; - setstr(vp, val); - } - XPput(env, vp->val.s); - } - XPput(env, NULL); - return (char **) XPclose(env); -} - -/* - * handle special variables with side effects - PATH, SECONDS. - */ - -/* Test if name is a special parameter */ -static int -special(name) - register const char * name; -{ - register struct tbl *tp; - - tp = tsearch(&specials, name, hash(name)); - return tp ? tp->type : V_NONE; -} - -#ifdef KSH -static time_t seconds; /* time SECONDS last set */ -#endif /* KSH */ - -static void -getspec(vp) - register struct tbl *vp; -{ - switch (special(vp->name)) { -#ifdef KSH - case V_SECONDS: - vp->flag &= ~SPECIAL; - setint(vp, (long) (time((time_t *)0) - seconds)); - vp->flag |= SPECIAL; - break; - case V_RANDOM: - vp->flag &= ~SPECIAL; - setint(vp, (long) (rand() & 0x7fff)); - vp->flag |= SPECIAL; - break; -#endif /* KSH */ -#ifdef HISTORY - case V_HISTSIZE: - vp->flag &= ~SPECIAL; - setint(vp, (long) histsize); - vp->flag |= SPECIAL; - break; -#endif /* HISTORY */ - } -} - -static void -setspec(vp) - register struct tbl *vp; -{ - char *s; - - switch (special(vp->name)) { - case V_PATH: - path = str_val(vp); - flushcom(1); /* clear tracked aliases */ - break; - case V_IFS: - setctypes(s = str_val(vp), C_IFS); - ifs0 = *s; - break; - case V_OPTIND: - getopts_reset((int) intval(vp)); - break; - case V_POSIXLY_CORRECT: - change_flag(FPOSIX, OF_SPECIAL, 1); - break; - case V_TMPDIR: - if (tmpdir) { - afree(tmpdir, APERM); - tmpdir = (char *) 0; - } - /* Use tmpdir iff it is an absolute path, is writable and - * searchable and is a directory... - */ - { - struct stat statb; - s = str_val(vp); - if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0 - && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) - tmpdir = str_save(s, APERM); - } - break; -#ifdef HISTORY - case V_HISTSIZE: - vp->flag &= ~SPECIAL; - sethistsize((int) intval(vp)); - vp->flag |= SPECIAL; - break; - case V_HISTFILE: - sethistfile(str_val(vp)); - break; -#endif /* HISTORY */ -#ifdef EDIT - case V_VISUAL: - set_editmode(str_val(vp)); - break; - case V_EDITOR: - if (!(global("VISUAL")->flag & ISSET)) - set_editmode(str_val(vp)); - break; - case V_COLUMNS: - if ((x_cols = intval(vp)) <= MIN_COLS) - x_cols = MIN_COLS; - 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)); - vp->flag |= SPECIAL; - break; - case V_SECONDS: - vp->flag &= ~SPECIAL; - seconds = time((time_t*) 0) - intval(vp); - vp->flag |= SPECIAL; - break; - case V_TMOUT: - /* at&t ksh seems to do this (only listen if integer) */ - if (vp->flag & INTEGER) - ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; - break; -#endif /* KSH */ - } -} - -static void -unsetspec(vp) - register struct tbl *vp; -{ - switch (special(vp->name)) { - case V_PATH: - path = def_path; - flushcom(1); /* clear tracked aliases */ - break; - case V_IFS: - setctypes(" \t\n", C_IFS); - ifs0 = ' '; - break; - case V_TMPDIR: - /* should not become unspecial */ - if (tmpdir) { - afree(tmpdir, APERM); - tmpdir = (char *) 0; - } - 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 - * useful (eg, after "TMOUT=60; unset TMOUT", user - * can't get rid of the timeout...). Should be handled - * by generic unset code... - */ - ksh_tmout = 0; - break; -#endif /* KSH */ - /* todo: generic action for specials (at&t says variables - * lose their special meaning when unset but global() checks - * the name of new vars to see if they are special) - * lose meaning: _, ERRNO, LINENO, MAILCHECK, - * OPTARG, OPTIND, RANDOM, SECONDS, TMOUT. - * unknown: MAIL, MAILPATH, HISTSIZE, HISTFILE, - * no effect: IFS, COLUMNS, PATH, TMPDIR, - * VISUAL, EDITOR, - * POSIXLY_CORRECT (use set +o posix instead) - */ - } -} - -/* - * Search for (and possibly create) a table entry starting with - * vp, indexed by val. - */ -static struct tbl * -arraysearch(vp, val) - struct tbl *vp; - int val; -{ - struct tbl *prev, *curr, *new; - - vp->flag |= ARRAY|DEFINED; - - /* The table entry is always [0] */ - if (val == 0) { - vp->index = 0; - return vp; - } - prev = vp; - curr = vp->u.array; - while (curr && curr->index < val) { - prev = curr; - curr = curr->u.array; - } - if (curr && curr->index == val) { - if (curr->flag&ISSET) - return curr; - else - new = curr; - } else - new = (struct tbl *)alloc(sizeof(struct tbl)+strlen(vp->name)+1, vp->areap); - strcpy(new->name, vp->name); - new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL); - new->type = vp->type; - new->areap = vp->areap; - new->u2.field = vp->u2.field; - new->index = val; - if (curr != new) { /* not reusing old array entry */ - prev->u.array = new; - new->u.array = curr; - } - return new; -} - -/* Return the length of an array reference (eg, [1+2]) - cp is assumed - * to point to the open bracket. Returns 0 if there is no matching closing - * bracket. - */ -int -array_ref_len(cp) - const char *cp; -{ - const char *s = cp; - int c; - int depth = 0; - - while ((c = *s++) && (c != ']' || --depth)) - if (c == '[') - depth++; - if (!c) - return 0; - return s - cp; -} - -/* - * Make a copy of the base of an array name - */ -char * -arrayname(str) - const char *str; -{ - const char *p; - - if ((p = strchr(str, '[')) == 0) - /* Shouldn't happen, but why worry? */ - return (char *) str; - - return str_nsave(str, p - str, ATEMP); -} - -/* Set (or overwrite, if !reset) the array variable var to the values in vals. - */ -void -set_array(var, reset, vals) - const char *var; - int reset; - char **vals; -{ - struct tbl *vp, *vq; - int i; - - /* to get local array, use "typeset foo; set -A foo" */ - vp = global(var); - - /* Note: at&t ksh allows set -A but not set +A of a read-only var */ - if ((vp->flag&RDONLY)) - errorf("%s: is read only", var); - /* This code is quite non-optimal */ - 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/pdksh/version.c b/bin/pdksh/version.c deleted file mode 100644 index 54394213105..00000000000 --- a/bin/pdksh/version.c +++ /dev/null @@ -1,10 +0,0 @@ -/* $OpenBSD: version.c,v 1.5 1996/11/21 07:59:37 downsj Exp $ */ - -/* - * value of $KSH_VERSION (or $SH_VERSION) - */ - -#include "sh.h" - -const char ksh_version [] = - "@(#)PD KSH v5.2.12 96/10/29"; diff --git a/bin/pdksh/vi.c b/bin/pdksh/vi.c deleted file mode 100644 index 81950b224a3..00000000000 --- a/bin/pdksh/vi.c +++ /dev/null @@ -1,2174 +0,0 @@ -/* $OpenBSD: vi.c,v 1.5 1997/06/19 13:58:49 kstailey Exp $ */ - -/* - * vi command editing - * written by John Rochester (initially for nsh) - * bludgeoned to fit pdksh by Larry Bouzane, Jeff Sparkes & Eric Gisin - * - */ -#include "config.h" -#ifdef VI - -#include "sh.h" -#include <ctype.h> -#include "ksh_stat.h" /* completion */ -#include "edit.h" - -#define CMDLEN 1024 -#define Ctrl(c) (c&0x1f) -#define is_wordch(c) (letnum(c)) - -struct edstate { - int winleft; - char *cbuf; - int cbufsize; - int linelen; - int cursor; -}; - - -static int vi_hook ARGS((int ch)); -static void vi_reset ARGS((char *buf, size_t len)); -static int nextstate ARGS((int ch)); -static int vi_insert ARGS((int ch)); -static int vi_cmd ARGS((int argcnt, const char *cmd)); -static int domove ARGS((int argcnt, const char *cmd, int sub)); -static int redo_insert ARGS((int count)); -static void yank_range ARGS((int a, int b)); -static int bracktype ARGS((int ch)); -static void save_cbuf ARGS((void)); -static void restore_cbuf ARGS((void)); -static void edit_reset ARGS((char *buf, size_t len)); -static int putbuf ARGS((const char *buf, int len, int repl)); -static void del_range ARGS((int a, int b)); -static int findch ARGS((int ch, int cnt, int forw, int incl)); -static int forwword ARGS((int argcnt)); -static int backword ARGS((int argcnt)); -static int endword ARGS((int argcnt)); -static int Forwword ARGS((int argcnt)); -static int Backword ARGS((int argcnt)); -static int Endword ARGS((int argcnt)); -static int grabhist ARGS((int save, int n)); -static int grabsearch ARGS((int save, int start, int fwd, char *pat)); -static void redraw_line ARGS((int newline)); -static void refresh ARGS((int leftside)); -static int outofwin ARGS((void)); -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 expand_word ARGS((int command)); -static int complete_word ARGS((int command, int count)); -static int print_expansions ARGS((struct edstate *e, int command)); -static int char_len ARGS((int c)); -static void x_vi_zotc ARGS((int c)); -static void vi_pprompt ARGS((int full)); -static void vi_error ARGS((void)); -static void vi_macro_reset ARGS((void)); - -#define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */ -#define M_ 0x2 /* movement command (h, l, etc.) */ -#define E_ 0x4 /* extended command (c, d, y) */ -#define X_ 0x8 /* long command (@, f, F, t, T, etc.) */ -#define U_ 0x10 /* an UN-undoable command (that isn't a M_) */ -#define B_ 0x20 /* bad command (^@) */ -#define Z_ 0x40 /* repeat count defaults to 0 (not 1) */ -#define S_ 0x80 /* search (/, ?) */ - -#define is_bad(c) (classify[(c)&0x7f]&B_) -#define is_cmd(c) (classify[(c)&0x7f]&(M_|E_|C_|U_)) -#define is_move(c) (classify[(c)&0x7f]&M_) -#define is_extend(c) (classify[(c)&0x7f]&E_) -#define is_long(c) (classify[(c)&0x7f]&X_) -#define is_undoable(c) (!(classify[(c)&0x7f]&U_)) -#define is_srch(c) (classify[(c)&0x7f]&S_) -#define is_zerocount(c) (classify[(c)&0x7f]&Z_) - -const unsigned char classify[128] = { - /* 0 1 2 3 4 5 6 7 */ - /* 0 ^@ ^A ^B ^C ^D ^E ^F ^G */ - B_, 0, 0, 0, 0, C_|U_, C_|Z_, 0, - /* 01 ^H ^I ^J ^K ^L ^M ^N ^O */ - M_, C_|Z_, 0, 0, C_|U_, 0, C_, 0, - /* 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, C_|Z_, 0, 0, 0, 0, - /* 04 <space> ! " # $ % & ' */ - M_, 0, 0, C_, M_, M_, 0, 0, - /* 05 ( ) * + , - . / */ - 0, 0, C_, C_, M_, C_, 0, C_|S_, - /* 06 0 1 2 3 4 5 6 7 */ - M_, 0, 0, 0, 0, 0, 0, 0, - /* 07 8 9 : ; < = > ? */ - 0, 0, 0, M_, 0, C_, 0, C_|S_, - /* 010 @ A B C D E F G */ - C_|X_, C_, M_, C_, C_, M_, M_|X_, C_|U_|Z_, - /* 011 H I J K L M N O */ - 0, C_, 0, 0, 0, 0, C_|U_, 0, - /* 012 P Q R S T U V W */ - C_, 0, C_, C_, M_|X_, C_, 0, M_, - /* 013 X Y Z [ \ ] ^ _ */ - C_, C_|U_, 0, 0, C_|Z_, 0, M_, C_|Z_, - /* 014 ` a b c d e f g */ - 0, C_, M_, E_, E_, M_, M_|X_, C_|Z_, - /* 015 h i j k l m n o */ - M_, C_, C_|U_, C_|U_, M_, 0, C_|U_, 0, - /* 016 p q r s t u v w */ - C_, 0, X_, C_, M_|X_, C_|U_, C_|U_|Z_,M_, - /* 017 x y z { | } ~ ^? */ - C_, E_|U_, 0, 0, M_|Z_, 0, C_, 0 -}; - -#define MAXVICMD 3 -#define SRCHLEN 40 - -#define INSERT 1 -#define REPLACE 2 - -#define VNORMAL 0 /* command, insert or replace mode */ -#define VARG1 1 /* digit prefix (first, eg, 5l) */ -#define VEXTCMD 2 /* cmd + movement (eg, cl) */ -#define VARG2 3 /* digit prefix (second, eg, 2c3l) */ -#define VXCH 4 /* f, F, t, T, @ */ -#define VFAIL 5 /* bad command */ -#define VCMD 6 /* single char command (eg, X) */ -#define VREDO 7 /* . */ -#define VLIT 8 /* ^V */ -#define VSEARCH 9 /* /, ? */ -#define VVERSION 10 /* <ESC> ^V */ - -static char undocbuf[CMDLEN]; - -static struct edstate *save_edstate ARGS((struct edstate *old)); -static void restore_edstate ARGS((struct edstate *old, struct edstate *new)); -static void free_edstate ARGS((struct edstate *old)); - -static struct edstate ebuf; -static struct edstate undobuf = { 0, undocbuf, CMDLEN, 0, 0 }; - -static struct edstate *es; /* current editor state */ -static struct edstate *undo; - -static char ibuf[CMDLEN]; /* input buffer */ -static int first_insert; /* set when starting in insert mode */ -static int saved_inslen; /* saved inslen for first insert */ -static int inslen; /* length of input buffer */ -static int srchlen; /* length of current search pattern */ -static char ybuf[CMDLEN]; /* yank buffer */ -static int yanklen; /* length of yank buffer */ -static int fsavecmd = ' '; /* last find command */ -static int fsavech; /* character to find */ -static char lastcmd[MAXVICMD]; /* last non-move command */ -static int lastac; /* argcnt for lastcmd */ -static int lastsearch = ' '; /* last search command */ -static char srchpat[SRCHLEN]; /* last search pattern */ -static int insert; /* non-zero in insert mode */ -static int hnum; /* position in history */ -static int ohnum; /* history line copied (after mod) */ -static int hlast; /* 1 past last position in history */ -static int modified; /* buffer has been "modified" */ -static int state; - -/* Information for keeping track of macros that are being expanded. - * The format of buf is the alias contents followed by a null byte followed - * by the name (letter) of the alias. The end of the buffer is marked by - * a double null. The name of the alias is stored so recursive macros can - * be detected. - */ -struct macro_state { - unsigned char *p; /* current position in buf */ - unsigned char *buf; /* pointer to macro(s) being expanded */ - int len; /* how much data in buffer */ -}; -static struct macro_state macro; - -enum expand_mode { NONE, EXPAND, COMPLETE, PRINT }; -static enum expand_mode expanded = NONE;/* last input was expanded */ - -int -x_vi(buf, len) - char *buf; - size_t len; -{ - int c; - - vi_reset(buf, len > CMDLEN ? CMDLEN : len); - vi_pprompt(1); - x_flush(); - while (1) { - if (macro.p) { - c = *macro.p++; - /* end of current macro? */ - if (!c) { - /* more macros left to finish? */ - if (*macro.p++) - continue; - /* must be the end of all the macros */ - vi_macro_reset(); - c = x_getc(); - } - } else - c = x_getc(); - if (c == -1) - break; - if (state != VLIT) { - if (c == edchars.intr || c == edchars.quit) { - /* pretend we got an interrupt */ - x_vi_zotc(c); - x_flush(); - trapsig(c == edchars.intr ? SIGINT : SIGQUIT); - x_mode(FALSE); - unwind(LSHELL); - } else if (c == edchars.eof && state != VVERSION) { - if (es->linelen == 0) { - x_vi_zotc(edchars.eof); - c = -1; - break; - } - continue; - } - } - if (vi_hook(c)) - break; - x_flush(); - } - - x_putc('\r'); x_putc('\n'); x_flush(); - - if (c == -1) - return -1; - - if (es->cbuf != buf) - memmove(buf, es->cbuf, es->linelen); - - buf[es->linelen++] = '\n'; - - return es->linelen; -} - -static int -vi_hook(ch) - int ch; -{ - static char curcmd[MAXVICMD]; - static char locpat[SRCHLEN]; - static int cmdlen; - static int argc1, argc2; - - switch (state) { - - case VNORMAL: - if (insert != 0) { - if (ch == Ctrl('v')) { - state = VLIT; - ch = '^'; - } - switch (vi_insert(ch)) { - case -1: -#ifdef OS2 - /* Arrow keys generate 0xe0X, where X is H.. */ - state = VCMD; - argc1 = 1; - switch (x_getc()) { - case 'H': - *curcmd='k'; - break; - case 'K': - *curcmd='h'; - break; - case 'P': - *curcmd='j'; - break; - case 'M': - *curcmd='l'; - break; - default: - vi_error(); - state = VNORMAL; - } - break; -#else /* OS2 */ - vi_error(); - state = VNORMAL; -#endif /* OS2 */ - break; - case 0: - if (state == VLIT) { - es->cursor--; - refresh(0); - } else - refresh(insert != 0); - break; - case 1: - return 1; - } - } else { - if (ch == '\r' || ch == '\n') - return 1; - cmdlen = 0; - argc1 = 0; - if (ch >= '1' && ch <= '9') { - argc1 = ch - '0'; - state = VARG1; - } else { - curcmd[cmdlen++] = ch; - state = nextstate(ch); - if (state == VSEARCH) { - save_cbuf(); - es->cursor = 0; - es->linelen = 0; - if (ch == '/') { - if (putbuf("/", 1, 0) != 0) { - return -1; - } - } else if (putbuf("?", 1, 0) != 0) - return -1; - refresh(0); - } - if (state == VVERSION) { - save_cbuf(); - es->cursor = 0; - es->linelen = 0; - putbuf(ksh_version + 4, - strlen(ksh_version + 4), 0); - refresh(0); - } - } - } - break; - - case VLIT: - if (is_bad(ch)) { - del_range(es->cursor, es->cursor + 1); - vi_error(); - } else - es->cbuf[es->cursor++] = ch; - refresh(1); - state = VNORMAL; - break; - - case VVERSION: - restore_cbuf(); - state = VNORMAL; - refresh(0); - break; - - case VARG1: - if (isdigit(ch)) - argc1 = argc1 * 10 + ch - '0'; - else { - curcmd[cmdlen++] = ch; - state = nextstate(ch); - } - break; - - case VEXTCMD: - argc2 = 0; - if (ch >= '1' && ch <= '9') { - argc2 = ch - '0'; - state = VARG2; - return 0; - } else { - curcmd[cmdlen++] = ch; - if (ch == curcmd[0]) - state = VCMD; - else if (is_move(ch)) - state = nextstate(ch); - else - state = VFAIL; - } - break; - - case VARG2: - if (isdigit(ch)) - argc2 = argc2 * 10 + ch - '0'; - else { - if (argc1 == 0) - argc1 = argc2; - else - argc1 *= argc2; - curcmd[cmdlen++] = ch; - if (ch == curcmd[0]) - state = VCMD; - else if (is_move(ch)) - state = nextstate(ch); - else - state = VFAIL; - } - break; - - case VXCH: - if (ch == Ctrl('[')) - state = VNORMAL; - else { - curcmd[cmdlen++] = ch; - state = VCMD; - } - break; - - case VSEARCH: - if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) { - restore_cbuf(); - /* Repeat last search? */ - if (srchlen == 0) { - if (!srchpat[0]) { - vi_error(); - state = VNORMAL; - refresh(0); - return 0; - } - } else { - locpat[srchlen] = '\0'; - (void) strcpy(srchpat, locpat); - } - state = VCMD; - } else if (ch == edchars.erase || ch == Ctrl('h')) { - if (srchlen != 0) { - srchlen--; - es->linelen -= char_len((unsigned char) locpat[srchlen]); - es->cursor = es->linelen; - refresh(0); - return 0; - } - restore_cbuf(); - state = VNORMAL; - refresh(0); - } else if (ch == edchars.kill) { - srchlen = 0; - es->linelen = 1; - es->cursor = 1; - refresh(0); - return 0; - } else if (ch == edchars.werase) { - int i; - int n = srchlen; - - while (n > 0 && isspace(locpat[n - 1])) - n--; - while (n > 0 && !isspace(locpat[n - 1])) - n--; - for (i = srchlen; --i >= n; ) - es->linelen -= char_len((unsigned char) locpat[i]); - srchlen = n; - es->cursor = es->linelen; - refresh(0); - return 0; - } else { - if (srchlen == SRCHLEN - 1) - vi_error(); - else { - locpat[srchlen++] = ch; - if ((ch & 0x80) && Flag(FVISHOW8)) { - es->cbuf[es->linelen++] = 'M'; - es->cbuf[es->linelen++] = '-'; - ch &= 0x7f; - } - if (ch < ' ' || ch == 0x7f) { - es->cbuf[es->linelen++] = '^'; - es->cbuf[es->linelen++] = ch ^ '@'; - } else - es->cbuf[es->linelen++] = ch; - es->cursor = es->linelen; - refresh(0); - } - return 0; - } - break; - } - - switch (state) { - case VCMD: - state = VNORMAL; - switch (vi_cmd(argc1, curcmd)) { - case -1: - vi_error(); - refresh(0); - break; - case 0: - if (insert != 0) - inslen = 0; - refresh(insert != 0); - break; - case 1: - refresh(0); - return 1; - case 2: - /* back from a 'v' command - don't redraw the screen */ - return 1; - } - break; - - case VREDO: - state = VNORMAL; - if (argc1 != 0) - lastac = argc1; - switch (vi_cmd(lastac, lastcmd) != 0) { - case -1: - vi_error(); - refresh(0); - break; - case 0: - if (insert != 0) { - if (lastcmd[0] == 's' || lastcmd[0] == 'c' || - lastcmd[0] == 'C') { - if (redo_insert(1) != 0) - vi_error(); - } else { - if (redo_insert(lastac) != 0) - vi_error(); - } - } - refresh(0); - break; - case 1: - refresh(0); - return 1; - case 2: - /* back from a 'v' command - don't redraw the screen */ - return 1; - } - break; - - case VFAIL: - state = VNORMAL; - vi_error(); - break; - } - return 0; -} - -static void -vi_reset(buf, len) - char *buf; - size_t len; -{ - state = VNORMAL; - ohnum = hnum = hlast = histnum(-1) + 1; - insert = INSERT; - saved_inslen = inslen; - first_insert = 1; - inslen = 0; - modified = 1; - vi_macro_reset(); - edit_reset(buf, len); -} - -static int -nextstate(ch) - int ch; -{ - if (is_extend(ch)) - return VEXTCMD; - else if (is_srch(ch)) - return VSEARCH; - else if (is_long(ch)) - return VXCH; - else if (ch == '.') - return VREDO; - else if (ch == Ctrl('v')) - return VVERSION; - else if (is_cmd(ch)) - return VCMD; - else - return VFAIL; -} - -static int -vi_insert(ch) - int ch; -{ - int tcursor; - - if (ch == edchars.erase || ch == Ctrl('h')) { - if (insert == REPLACE) { - if (es->cursor == undo->cursor) { - vi_error(); - return 0; - } - if (inslen > 0) - inslen--; - es->cursor--; - if (es->cursor >= undo->linelen) - es->linelen--; - else - es->cbuf[es->cursor] = undo->cbuf[es->cursor]; - } else { - if (es->cursor == 0) { - /* x_putc(BEL); no annoying bell here */ - return 0; - } - if (inslen > 0) - inslen--; - es->cursor--; - es->linelen--; - memmove(&es->cbuf[es->cursor], &es->cbuf[es->cursor+1], - es->linelen - es->cursor + 1); - } - expanded = NONE; - return 0; - } - if (ch == edchars.kill) { - if (es->cursor != 0) { - inslen = 0; - memmove(es->cbuf, &es->cbuf[es->cursor], - es->linelen - es->cursor); - es->linelen -= es->cursor; - es->cursor = 0; - } - expanded = NONE; - return 0; - } - if (ch == edchars.werase) { - if (es->cursor != 0) { - tcursor = Backword(1); - memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor], - es->linelen - es->cursor); - es->linelen -= es->cursor - tcursor; - if (inslen < es->cursor - tcursor) - inslen = 0; - else - inslen -= es->cursor - tcursor; - es->cursor = tcursor; - } - expanded = NONE; - return 0; - } - /* If any chars are entered before escape, trash the saved insert - * buffer (if user inserts & deletes char, ibuf gets trashed and - * we don't want to use it) - */ - if (first_insert && ch != Ctrl('[')) - saved_inslen = 0; - switch (ch) { - -#ifdef OS2 - case 224: /* function key prefix */ -#endif /* OS2 */ - case '\0': - return -1; - - case '\r': - case '\n': - return 1; - - case Ctrl('['): - expanded = NONE; - if (first_insert) { - first_insert = 0; - if (inslen == 0) { - inslen = saved_inslen; - return redo_insert(0); - } - lastcmd[0] = 'a'; - lastac = 1; - } - if (lastcmd[0] == 's' || lastcmd[0] == 'c' || - lastcmd[0] == 'C') - return redo_insert(0); - else - return redo_insert(lastac - 1); - - /* { Begin nonstandard vi commands */ - case Ctrl('x'): - expand_word(0); - break; - - case Ctrl('f'): - complete_word(0, 0); - break; - - case Ctrl('e'): - print_expansions(es, 0); - break; - - case Ctrl('i'): - if (Flag(FVITABCOMPLETE)) { - complete_word(0, 0); - break; - } - /* FALLTHROUGH */ - /* End nonstandard vi commands } */ - - default: - if (es->linelen == es->cbufsize - 1) - return -1; - ibuf[inslen++] = ch; - if (insert == INSERT) { - memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor], - es->linelen - es->cursor); - es->linelen++; - } - es->cbuf[es->cursor++] = ch; - if (insert == REPLACE && es->cursor > es->linelen) - es->linelen++; - expanded = NONE; - } - return 0; -} - -static int -vi_cmd(argcnt, cmd) - int argcnt; - const char *cmd; -{ - int ncursor; - int cur, c1, c2, c3 = 0; - int any; - struct edstate *t; - - if (argcnt == 0 && !is_zerocount(*cmd)) - argcnt = 1; - - if (is_move(*cmd)) { - if ((cur = domove(argcnt, cmd, 0)) >= 0) { - if (cur == es->linelen && cur != 0) - cur--; - es->cursor = cur; - } else - return -1; - } else { - /* Don't save state in middle of macro.. */ - if (is_undoable(*cmd) && !macro.p) { - undo->winleft = es->winleft; - memmove(undo->cbuf, es->cbuf, es->linelen); - undo->linelen = es->linelen; - undo->cursor = es->cursor; - lastac = argcnt; - memmove(lastcmd, cmd, MAXVICMD); - } - switch (*cmd) { - - case Ctrl('l'): - case Ctrl('r'): - redraw_line(1); - break; - - case '@': - { - static char alias[] = "_\0"; - struct tbl *ap; - int olen, nlen; - char *p, *nbuf; - - /* lookup letter in alias list... */ - alias[1] = cmd[1]; - ap = tsearch(&aliases, alias, hash(alias)); - if (!cmd[1] || !ap || !(ap->flag & ISSET)) - return -1; - /* check if this is a recursive call... */ - if ((p = (char *) macro.p)) - while ((p = strchr(p, '\0')) && p[1]) - if (*++p == cmd[1]) - return -1; - /* insert alias into macro buffer */ - nlen = strlen(ap->val.s) + 1; - olen = !macro.p ? 2 - : macro.len - (macro.p - macro.buf); - nbuf = alloc(nlen + 1 + olen, APERM); - memcpy(nbuf, ap->val.s, nlen); - nbuf[nlen++] = cmd[1]; - if (macro.p) { - memcpy(nbuf + nlen, macro.p, olen); - afree(macro.buf, APERM); - nlen += olen; - } else { - nbuf[nlen++] = '\0'; - nbuf[nlen++] = '\0'; - } - macro.p = macro.buf = (unsigned char *) nbuf; - macro.len = nlen; - } - break; - - case 'a': - modified = 1; hnum = hlast; - if (es->linelen != 0) - es->cursor++; - insert = INSERT; - break; - - case 'A': - modified = 1; hnum = hlast; - del_range(0, 0); - es->cursor = es->linelen; - insert = INSERT; - break; - - case 'S': - es->cursor = domove(1, "^", 1); - del_range(es->cursor, es->linelen); - modified = 1; hnum = hlast; - insert = INSERT; - break; - - case 'Y': - cmd = "y$"; - /* ahhhhhh... */ - case 'c': - case 'd': - case 'y': - if (*cmd == cmd[1]) { - c1 = *cmd == 'c' ? domove(1, "^", 1) : 0; - c2 = es->linelen; - } else if (!is_move(cmd[1])) - return -1; - else { - if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0) - return -1; - if (*cmd == 'c' && - (cmd[1]=='w' || cmd[1]=='W') && - !isspace(es->cbuf[es->cursor])) { - while (isspace(es->cbuf[--ncursor])) - ; - ncursor++; - } - if (ncursor > es->cursor) { - c1 = es->cursor; - c2 = ncursor; - } else { - c1 = ncursor; - c2 = es->cursor; - if (cmd[1] == '%') - c2++; - } - } - if (*cmd != 'c' && c1 != c2) - yank_range(c1, c2); - if (*cmd != 'y') { - del_range(c1, c2); - es->cursor = c1; - } - if (*cmd == 'c') { - modified = 1; hnum = hlast; - insert = INSERT; - } - break; - - case 'p': - modified = 1; hnum = hlast; - if (es->linelen != 0) - es->cursor++; - while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0) - ; - if (es->cursor != 0) - es->cursor--; - if (argcnt != 0) - return -1; - break; - - case 'P': - modified = 1; hnum = hlast; - any = 0; - while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0) - any = 1; - if (any && es->cursor != 0) - es->cursor--; - if (argcnt != 0) - return -1; - break; - - case 'C': - modified = 1; hnum = hlast; - del_range(es->cursor, es->linelen); - insert = INSERT; - break; - - case 'D': - yank_range(es->cursor, es->linelen); - del_range(es->cursor, es->linelen); - if (es->cursor != 0) - es->cursor--; - break; - - case 'g': - if (!argcnt) - argcnt = hlast + 1; - /* fall through */ - case 'G': - if (!argcnt) - argcnt = 1; - else - argcnt = hlast - (source->line - argcnt); - if (grabhist(modified, argcnt - 1) < 0) - return -1; - else { - modified = 0; - hnum = argcnt - 1; - } - break; - - case 'i': - modified = 1; hnum = hlast; - insert = INSERT; - break; - - case 'I': - modified = 1; hnum = hlast; - es->cursor = domove(1, "^", 1); - insert = INSERT; - break; - - case 'j': - case '+': - case Ctrl('n'): - if (grabhist(modified, hnum + argcnt) < 0) - return -1; - else { - modified = 0; - hnum += argcnt; - } - break; - - case 'k': - case '-': - case Ctrl('p'): - if (grabhist(modified, hnum - argcnt) < 0) - return -1; - else { - modified = 0; - hnum -= argcnt; - } - break; - - case 'r': - if (es->linelen == 0) - return -1; - modified = 1; hnum = hlast; - if (cmd[1] == 0) - vi_error(); - else - es->cbuf[es->cursor] = cmd[1]; - break; - - case 'R': - modified = 1; hnum = hlast; - insert = REPLACE; - break; - - case 's': - if (es->linelen == 0) - return -1; - modified = 1; hnum = hlast; - if (es->cursor + argcnt > es->linelen) - argcnt = es->linelen - es->cursor; - del_range(es->cursor, es->cursor + argcnt); - insert = INSERT; - break; - - case 'v': - if (es->linelen == 0) - return -1; - if (!argcnt) { - if (modified) { - es->cbuf[es->linelen] = '\0'; - source->line++; - histsave(source->line, es->cbuf, 1); - } else - argcnt = source->line + 1 - - (hlast - hnum); - } - shf_snprintf(es->cbuf, es->cbufsize, - argcnt ? "%s %d" : "%s", - "fc -e ${VISUAL:-${EDITOR:-vi}} --", - argcnt); - es->linelen = strlen(es->cbuf); - return 2; - - case 'x': - if (es->linelen == 0) - return -1; - modified = 1; hnum = hlast; - if (es->cursor + argcnt > es->linelen) - argcnt = es->linelen - es->cursor; - yank_range(es->cursor, es->cursor + argcnt); - del_range(es->cursor, es->cursor + argcnt); - break; - - case 'X': - if (es->cursor > 0) { - modified = 1; hnum = hlast; - if (es->cursor < argcnt) - argcnt = es->cursor; - yank_range(es->cursor - argcnt, es->cursor); - del_range(es->cursor - argcnt, es->cursor); - es->cursor -= argcnt; - } else - return -1; - break; - - case 'u': - t = es; - es = undo; - undo = t; - break; - - case 'U': - if (!modified) - return -1; - if (grabhist(modified, ohnum) < 0) - return -1; - modified = 0; - hnum = ohnum; - break; - - case '?': - if (hnum == hlast) - hnum = -1; - /* ahhh */ - case '/': - c3 = 1; - srchlen = 0; - lastsearch = *cmd; - /* fall through */ - case 'n': - case 'N': - if (lastsearch == ' ') - return -1; - if (lastsearch == '?') - c1 = 1; - else - c1 = 0; - if (*cmd == 'N') - c1 = !c1; - if ((c2 = grabsearch(modified, hnum, - c1, srchpat)) < 0) { - if (c3) { - restore_cbuf(); - refresh(0); - } - return -1; - } else { - modified = 0; - hnum = c2; - ohnum = hnum; - } - break; - case '_': { - int inspace; - char *p, *sp; - - if (histnum(-1) < 0) - return -1; - p = *histpos(); -#define issp(c) (isspace((c)) || (c) == '\n') - if (argcnt) { - while (*p && issp(*p)) - p++; - while (*p && --argcnt) { - while (*p && !issp(*p)) - p++; - while (*p && issp(*p)) - p++; - } - if (!*p) - return -1; - sp = p; - } else { - sp = p; - inspace = 0; - while (*p) { - if (issp(*p)) - inspace = 1; - else if (inspace) { - inspace = 0; - sp = p; - } - p++; - } - p = sp; - } - modified = 1; hnum = hlast; - if (es->cursor != es->linelen) - es->cursor++; - while (*p && !issp(*p)) { - argcnt++; - p++; - } - if (putbuf(space, 1, 0) != 0) - argcnt = -1; - else if (putbuf(sp, argcnt, 0) != 0) - argcnt = -1; - if (argcnt < 0) { - if (es->cursor != 0) - es->cursor--; - return -1; - } - insert = INSERT; - } - break; - - case '~': { - char *p; - int i; - - if (es->linelen == 0) - return -1; - for (i = 0; i < argcnt; i++) { - p = &es->cbuf[es->cursor]; - if (islower(*p)) { - modified = 1; hnum = hlast; - *p = toupper(*p); - } else if (isupper(*p)) { - modified = 1; hnum = hlast; - *p = tolower(*p); - } - if (es->cursor < es->linelen - 1) - es->cursor++; - } - break; - } - - case '#': - { - 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 */ - print_expansions(es, 1); - break; - - - case Ctrl('i'): /* Nonstandard vi/ksh */ - if (!Flag(FVITABCOMPLETE)) - return -1; - complete_word(1, argcnt); - break; - - 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); - break; - - - case '*': /* at&t ksh */ - case Ctrl('x'): /* Nonstandard vi/ksh */ - expand_word(1); - break; - } - if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen) - es->cursor--; - } - return 0; -} - -static int -domove(argcnt, cmd, sub) - int argcnt; - const char *cmd; - int sub; -{ - int bcount, UNINITIALIZED(i), t; - int UNINITIALIZED(ncursor); - - switch (*cmd) { - - case 'b': - if (!sub && es->cursor == 0) - return -1; - ncursor = backword(argcnt); - break; - - case 'B': - if (!sub && es->cursor == 0) - return -1; - ncursor = Backword(argcnt); - break; - - case 'e': - if (!sub && es->cursor + 1 >= es->linelen) - return -1; - ncursor = endword(argcnt); - if (sub && ncursor < es->linelen) - ncursor++; - break; - - case 'E': - if (!sub && es->cursor + 1 >= es->linelen) - return -1; - ncursor = Endword(argcnt); - if (sub && ncursor < es->linelen) - ncursor++; - break; - - case 'f': - case 'F': - case 't': - case 'T': - fsavecmd = *cmd; - fsavech = cmd[1]; - /* drop through */ - - case ',': - case ';': - if (fsavecmd == ' ') - return -1; - i = fsavecmd == 'f' || fsavecmd == 'F'; - t = fsavecmd > 'a'; - if (*cmd == ',') - t = !t; - if ((ncursor = findch(fsavech, argcnt, t, i)) < 0) - return -1; - if (sub && t) - ncursor++; - break; - - case 'h': - case Ctrl('h'): - if (!sub && es->cursor == 0) - return -1; - ncursor = es->cursor - argcnt; - if (ncursor < 0) - ncursor = 0; - break; - - case ' ': - case 'l': - if (!sub && es->cursor + 1 >= es->linelen) - return -1; - if (es->linelen != 0) { - ncursor = es->cursor + argcnt; - if (ncursor > es->linelen) - ncursor = es->linelen; - } - break; - - case 'w': - if (!sub && es->cursor + 1 >= es->linelen) - return -1; - ncursor = forwword(argcnt); - break; - - case 'W': - if (!sub && es->cursor + 1 >= es->linelen) - return -1; - ncursor = Forwword(argcnt); - break; - - case '0': - ncursor = 0; - break; - - case '^': - ncursor = 0; - while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor])) - ncursor++; - break; - - case '|': - ncursor = argcnt; - if (ncursor > es->linelen) - ncursor = es->linelen; - if (ncursor) - ncursor--; - break; - - case '$': - if (es->linelen != 0) - ncursor = es->linelen; - else - ncursor = 0; - break; - - case '%': - ncursor = es->cursor; - while (ncursor < es->linelen && - (i = bracktype(es->cbuf[ncursor])) == 0) - ncursor++; - if (ncursor == es->linelen) - return -1; - bcount = 1; - do { - if (i > 0) { - if (++ncursor >= es->linelen) - return -1; - } else { - if (--ncursor < 0) - return -1; - } - t = bracktype(es->cbuf[ncursor]); - if (t == i) - bcount++; - else if (t == -i) - bcount--; - } while (bcount != 0); - if (sub && i > 0) - ncursor++; - break; - - default: - return -1; - } - return ncursor; -} - -static int -redo_insert(count) - int count; -{ - while (count-- > 0) - if (putbuf(ibuf, inslen, insert==REPLACE) != 0) - return -1; - if (es->cursor > 0) - es->cursor--; - insert = 0; - return 0; -} - -static void -yank_range(a, b) - int a, b; -{ - yanklen = b - a; - if (yanklen != 0) - memmove(ybuf, &es->cbuf[a], yanklen); -} - -static int -bracktype(ch) - int ch; -{ - switch (ch) { - - case '(': - return 1; - - case '[': - return 2; - - case '{': - return 3; - - case ')': - return -1; - - case ']': - return -2; - - case '}': - return -3; - - default: - return 0; - } -} - -/* - * Non user interface editor routines below here - */ - -static int cur_col; /* current column on line */ -static int pwidth; /* width of prompt */ -static int prompt_trunc; /* how much of prompt to truncate */ -static int prompt_skip; /* how much of prompt to skip */ -static int winwidth; /* width of window */ -static char *wbuf[2]; /* window buffers */ -static int wbuf_len; /* length of window buffers (x_cols-3)*/ -static int win; /* window buffer in use */ -static char morec; /* more character at right of window */ -static int lastref; /* argument to last refresh() */ -static char holdbuf[CMDLEN]; /* place to hold last edit buffer */ -static int holdlen; /* length of holdbuf */ - -static void -save_cbuf() -{ - memmove(holdbuf, es->cbuf, es->linelen); - holdlen = es->linelen; - holdbuf[holdlen] = '\0'; -} - -static void -restore_cbuf() -{ - es->cursor = 0; - es->linelen = holdlen; - memmove(es->cbuf, holdbuf, holdlen); -} - -/* return a new edstate */ -static struct edstate * -save_edstate(old) - struct edstate *old; -{ - struct edstate *new; - - new = (struct edstate *)alloc(sizeof(struct edstate), APERM); - new->cbuf = alloc(old->cbufsize, APERM); - new->cbufsize = old->cbufsize; - strcpy(new->cbuf, old->cbuf); - new->linelen = old->linelen; - new->cursor = old->cursor; - new->winleft = old->winleft; - return new; -} - -static void -restore_edstate(new, old) - struct edstate *old, *new; -{ - strncpy(new->cbuf, old->cbuf, old->linelen); - new->linelen = old->linelen; - new->cursor = old->cursor; - new->winleft = old->winleft; - free_edstate(old); -} - -static void -free_edstate(old) - struct edstate *old; -{ - afree(old->cbuf, APERM); - afree((char *)old, APERM); -} - - - -static void -edit_reset(buf, len) - char *buf; - size_t len; -{ - const char *p; - - es = &ebuf; - es->cbuf = buf; - es->cbufsize = len; - undo = &undobuf; - undo->cbufsize = len; - - es->linelen = undo->linelen = 0; - es->cursor = undo->cursor = 0; - es->winleft = undo->winleft = 0; - - cur_col = pwidth = promptlen(prompt, &p); - prompt_skip = p - prompt; - if (pwidth > x_cols - 3 - MIN_EDIT_SPACE) { - cur_col = x_cols - 3 - MIN_EDIT_SPACE; - prompt_trunc = pwidth - cur_col; - pwidth -= prompt_trunc; - } else - prompt_trunc = 0; - if (!wbuf_len || wbuf_len != x_cols - 3) { - wbuf_len = x_cols - 3; - wbuf[0] = aresize(wbuf[0], wbuf_len, APERM); - wbuf[1] = aresize(wbuf[1], wbuf_len, APERM); - } - (void) memset(wbuf[0], ' ', wbuf_len); - (void) memset(wbuf[1], ' ', wbuf_len); - winwidth = x_cols - pwidth - 3; - win = 0; - morec = ' '; - lastref = 1; - holdlen = 0; -} - -static int -putbuf(buf, len, repl) - const char *buf; - int len; - int repl; -{ - if (len == 0) - return 0; - if (repl) { - if (es->cursor + len >= es->cbufsize) - return -1; - if (es->cursor + len > es->linelen) - es->linelen = es->cursor + len; - } else { - if (es->linelen + len >= es->cbufsize) - return -1; - memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor], - es->linelen - es->cursor); - es->linelen += len; - } - memmove(&es->cbuf[es->cursor], buf, len); - es->cursor += len; - return 0; -} - -static void -del_range(a, b) - int a, b; -{ - if (es->linelen != b) - memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b); - es->linelen -= b - a; -} - -static int -findch(ch, cnt, forw, incl) - int ch; - int cnt; - int forw; - int incl; -{ - int ncursor; - - if (es->linelen == 0) - return -1; - ncursor = es->cursor; - while (cnt--) { - do { - if (forw) { - if (++ncursor == es->linelen) - return -1; - } else { - if (--ncursor < 0) - return -1; - } - } while (es->cbuf[ncursor] != ch); - } - if (!incl) { - if (forw) - ncursor--; - else - ncursor++; - } - return ncursor; -} - -static int -forwword(argcnt) - int argcnt; -{ - int ncursor; - - ncursor = es->cursor; - while (ncursor < es->linelen && argcnt--) { - if (is_wordch(es->cbuf[ncursor])) - while (is_wordch(es->cbuf[ncursor]) && - ncursor < es->linelen) - ncursor++; - else if (!isspace(es->cbuf[ncursor])) - while (!is_wordch(es->cbuf[ncursor]) && - !isspace(es->cbuf[ncursor]) && - ncursor < es->linelen) - ncursor++; - while (isspace(es->cbuf[ncursor]) && ncursor < es->linelen) - ncursor++; - } - return ncursor; -} - -static int -backword(argcnt) - int argcnt; -{ - int ncursor; - - ncursor = es->cursor; - while (ncursor > 0 && argcnt--) { - while (--ncursor > 0 && isspace(es->cbuf[ncursor])) - ; - if (ncursor > 0) { - if (is_wordch(es->cbuf[ncursor])) - while (--ncursor >= 0 && - is_wordch(es->cbuf[ncursor])) - ; - else - while (--ncursor >= 0 && - !is_wordch(es->cbuf[ncursor]) && - !isspace(es->cbuf[ncursor])) - ; - ncursor++; - } - } - return ncursor; -} - -static int -endword(argcnt) - int argcnt; -{ - int ncursor; - - ncursor = es->cursor; - while (ncursor < es->linelen && argcnt--) { - while (++ncursor < es->linelen - 1 && - isspace(es->cbuf[ncursor])) - ; - if (ncursor < es->linelen - 1) { - if (is_wordch(es->cbuf[ncursor])) - while (++ncursor < es->linelen && - is_wordch(es->cbuf[ncursor])) - ; - else - while (++ncursor < es->linelen && - !is_wordch(es->cbuf[ncursor]) && - !isspace(es->cbuf[ncursor])) - ; - ncursor--; - } - } - return ncursor; -} - -static int -Forwword(argcnt) - int argcnt; -{ - int ncursor; - - ncursor = es->cursor; - while (ncursor < es->linelen && argcnt--) { - while (!isspace(es->cbuf[ncursor]) && ncursor < es->linelen) - ncursor++; - while (isspace(es->cbuf[ncursor]) && ncursor < es->linelen) - ncursor++; - } - return ncursor; -} - -static int -Backword(argcnt) - int argcnt; -{ - int ncursor; - - ncursor = es->cursor; - while (ncursor > 0 && argcnt--) { - while (--ncursor >= 0 && isspace(es->cbuf[ncursor])) - ; - while (ncursor >= 0 && !isspace(es->cbuf[ncursor])) - ncursor--; - ncursor++; - } - return ncursor; -} - -static int -Endword(argcnt) - int argcnt; -{ - int ncursor; - - ncursor = es->cursor; - while (ncursor < es->linelen - 1 && argcnt--) { - while (++ncursor < es->linelen - 1 && - isspace(es->cbuf[ncursor])) - ; - if (ncursor < es->linelen - 1) { - while (++ncursor < es->linelen && - !isspace(es->cbuf[ncursor])) - ; - ncursor--; - } - } - return ncursor; -} - -static int -grabhist(save, n) - int save; - int n; -{ - char *hptr; - - if (n < 0 || n > hlast) - return -1; - if (n == hlast) { - restore_cbuf(); - ohnum = n; - return 0; - } - (void) histnum(n); - if ((hptr = *histpos()) == NULL) { - internal_errorf(0, "grabhist: bad history array"); - return -1; - } - if (save) - save_cbuf(); - if ((es->linelen = strlen(hptr)) >= es->cbufsize) - es->linelen = es->cbufsize - 1; - memmove(es->cbuf, hptr, es->linelen); - es->cursor = 0; - ohnum = n; - return 0; -} - -static int -grabsearch(save, start, fwd, pat) - int save, start, fwd; - char *pat; -{ - char *hptr; - int hist; - int anchored; - - if ((start == 0 && fwd == 0) || (start >= hlast-1 && fwd == 1)) - return -1; - if (fwd) - start++; - else - start--; - anchored = *pat == '^' ? (++pat, 1) : 0; - if ((hist = findhist(start, fwd, pat, anchored)) < 0) { - /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */ - /* XXX should FILECMP be strncmp? */ - if (start != 0 && fwd && FILECMP(holdbuf, pat) >= 0) { - restore_cbuf(); - return 0; - } else - return -1; - } - if (save) - save_cbuf(); - histnum(hist); - hptr = *histpos(); - if ((es->linelen = strlen(hptr)) >= es->cbufsize) - es->linelen = es->cbufsize - 1; - memmove(es->cbuf, hptr, es->linelen); - es->cursor = 0; - return hist; -} - -static void -redraw_line(newline) - int newline; -{ - (void) memset(wbuf[win], ' ', wbuf_len); - if (newline) { - x_putc('\r'); - x_putc('\n'); - } - vi_pprompt(0); - cur_col = pwidth; - morec = ' '; -} - -static void -refresh(leftside) - int leftside; -{ - if (leftside < 0) - leftside = lastref; - else - lastref = leftside; - if (outofwin()) - rewindow(); - display(wbuf[1 - win], wbuf[win], leftside); - win = 1 - win; -} - -static int -outofwin() -{ - int cur, col; - - if (es->cursor < es->winleft) - return 1; - col = 0; - cur = es->winleft; - while (cur < es->cursor) - col = newcol((unsigned char) es->cbuf[cur++], col); - if (col >= winwidth) - return 1; - return 0; -} - -static void -rewindow() -{ - register int tcur, tcol; - int holdcur1, holdcol1; - int holdcur2, holdcol2; - - holdcur1 = holdcur2 = tcur = 0; - holdcol1 = holdcol2 = tcol = 0; - while (tcur < es->cursor) { - if (tcol - holdcol2 > winwidth / 2) { - holdcur1 = holdcur2; - holdcol1 = holdcol2; - holdcur2 = tcur; - holdcol2 = tcol; - } - tcol = newcol((unsigned char) es->cbuf[tcur++], tcol); - } - while (tcol - holdcol1 > winwidth / 2) - holdcol1 = newcol((unsigned char) es->cbuf[holdcur1++], - holdcol1); - es->winleft = holdcur1; -} - -static int -newcol(ch, col) - int ch, col; -{ - if (ch == '\t') - return (col | 7) + 1; - return col + char_len(ch); -} - -static void -display(wb1, wb2, leftside) - char *wb1, *wb2; - int leftside; -{ - unsigned char ch; - char *twb1, *twb2, mc; - int cur, col, cnt; - int UNINITIALIZED(ncol); - int moreright; - - col = 0; - cur = es->winleft; - moreright = 0; - twb1 = wb1; - while (col < winwidth && cur < es->linelen) { - if (cur == es->cursor && leftside) - ncol = col + pwidth; - if ((ch = es->cbuf[cur]) == '\t') { - do { - *twb1++ = ' '; - } while (++col < winwidth && (col & 7) != 0); - } else { - if ((ch & 0x80) && Flag(FVISHOW8)) { - *twb1++ = 'M'; - if (++col < winwidth) { - *twb1++ = '-'; - col++; - } - ch &= 0x7f; - } - if (col < winwidth) { - if (ch < ' ' || ch == 0x7f) { - *twb1++ = '^'; - if (++col < winwidth) { - *twb1++ = ch ^ '@'; - col++; - } - } else { - *twb1++ = ch; - col++; - } - } - } - if (cur == es->cursor && !leftside) - ncol = col + pwidth - 1; - cur++; - } - if (cur == es->cursor) - ncol = col + pwidth; - if (col < winwidth) { - while (col < winwidth) { - *twb1++ = ' '; - col++; - } - } else - moreright++; - *twb1 = ' '; - - col = pwidth; - cnt = winwidth; - twb1 = wb1; - twb2 = wb2; - while (cnt--) { - if (*twb1 != *twb2) { - if (cur_col != col) - ed_mov_opt(col, wb1); - x_putc(*twb1); - cur_col++; - } - twb1++; - twb2++; - col++; - } - if (es->winleft > 0 && moreright) - /* POSIX says to use * for this but that is a globbing - * character and may confuse people; + is more innocuous - */ - mc = '+'; - else if (es->winleft > 0) - mc = '<'; - else if (moreright) - mc = '>'; - else - mc = ' '; - if (mc != morec) { - ed_mov_opt(pwidth + winwidth + 1, wb1); - x_putc(mc); - cur_col++; - morec = mc; - } - if (cur_col != ncol) - ed_mov_opt(ncol, wb1); -} - -static void -ed_mov_opt(col, wb) - int col; - char *wb; -{ - if (col < cur_col) { - if (col + 1 < cur_col - col) { - x_putc('\r'); - vi_pprompt(0); - cur_col = pwidth; - while (cur_col++ < col) - x_putc(*wb++); - } else { - while (cur_col-- > col) - x_putc('\b'); - } - } else { - wb = &wb[cur_col - pwidth]; - while (cur_col++ < col) - x_putc(*wb++); - } - cur_col = col; -} - - -/* replace word with all expansions (ie, expand word*) */ -static int -expand_word(command) - int command; -{ - static struct edstate *buf; - int rval = 0; - int nwords; - int start, end; - char **words; - int i; - - /* Undo previous expansion */ - if (command == 0 && expanded == EXPAND && buf) { - restore_edstate(es, buf); - buf = 0; - expanded = NONE; - return 0; - } - if (buf) { - free_edstate(buf); - buf = 0; - } - - nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH, - es->cbuf, es->linelen, es->cursor, - &start, &end, &words, (int *) 0); - if (nwords == 0) { - vi_error(); - return -1; - } - - buf = save_edstate(es); - expanded = EXPAND; - del_range(start, end); - es->cursor = start; - for (i = 0; i < nwords; ) { - if (putbuf(words[i], (int) strlen(words[i]), 0) != 0) { - rval = -1; - break; - } - if (++i < nwords && putbuf(space, 1, 0) != 0) { - rval = -1; - break; - } - } - i = buf->cursor - end; - if (rval == 0 && i > 0) - es->cursor += i; - modified = 1; hnum = hlast; - insert = INSERT; - lastac = 0; - refresh(0); - return rval; -} - -static int -complete_word(command, count) - int command; - int count; -{ - static struct edstate *buf; - int rval = 0; - int nwords; - int start, end; - char **words; - char *match; - int match_len; - int is_unique; - int is_command; - - /* Undo previous completion */ - if (command == 0 && expanded == COMPLETE && buf) { - print_expansions(buf, 0); - expanded = PRINT; - return 0; - } - if (command == 0 && expanded == PRINT && buf) { - restore_edstate(es, buf); - buf = 0; - expanded = NONE; - return 0; - } - if (buf) { - free_edstate(buf); - buf = 0; - } - - /* XCF_FULLPATH for count 'cause the menu printed by print_expansions() - * was done this way. - */ - nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0), - es->cbuf, es->linelen, es->cursor, - &start, &end, &words, &is_command); - if (nwords == 0) { - vi_error(); - return -1; - } - if (count) { - int i; - - count--; - if (count >= nwords) { - vi_error(); - x_print_expansions(nwords, words, is_command); - x_free_words(nwords, words); - redraw_line(0); - return -1; - } - /* - * Expand the count'th word to its basename - */ - if (is_command) { - match = words[count] - + x_basename(words[count], (char *) 0); - /* If more than one possible match, use full path */ - for (i = 0; i < nwords; i++) - if (i != count && - FILECMP(words[i] - + x_basename(words[i], (char *) 0), - match) == 0) - { - match = words[count]; - break; - } - } else - match = words[count]; - match_len = strlen(match); - is_unique = 1; - /* expanded = PRINT; next call undo */ - } else { - match = words[0]; - match_len = x_longest_prefix(nwords, words); - expanded = COMPLETE; /* next call will list completions */ - is_unique = nwords == 1; - } - - buf = save_edstate(es); - del_range(start, end); - es->cursor = start; - if (putbuf(match, match_len, 0) != 0) - rval = -1; - else if (is_unique) { - /* If exact match, don't undo. Allows directory completions - * to be used (ie, complete the next portion of the path). - */ - expanded = NONE; - - /* If not a directory, add a space to the end... */ - if (match_len > 0 && !ISDIRSEP(match[match_len - 1])) - rval = putbuf(space, 1, 0); - } - x_free_words(nwords, words); - - modified = 1; hnum = hlast; - insert = INSERT; - lastac = 0; /* prevent this from being redone... */ - refresh(0); - - return rval; -} - -static int -print_expansions(e, command) - struct edstate *e; - int command; -{ - int nwords; - int start, end; - char **words; - int is_command; - - nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH, - e->cbuf, e->linelen, e->cursor, - &start, &end, &words, &is_command); - if (nwords == 0) { - vi_error(); - return -1; - } - x_print_expansions(nwords, words, is_command); - x_free_words(nwords, words); - redraw_line(0); - return 0; -} - -/* How long is char when displayed (not counting tabs) */ -static int -char_len(c) - int c; -{ - int len = 1; - - if ((c & 0x80) && Flag(FVISHOW8)) { - len += 2; - c &= 0x7f; - } - if (c < ' ' || c == 0x7f) - len++; - return len; -} - -/* Similar to x_zotc(emacs.c), but no tab wierdness */ -static void -x_vi_zotc(c) - int c; -{ - if (Flag(FVISHOW8) && (c & 0x80)) { - x_puts("M-"); - c &= 0x7f; - } - if (c < ' ' || c == 0x7f) { - x_putc('^'); - c ^= '@'; - } - x_putc(c); -} - -static void -vi_pprompt(full) - int full; -{ - pprompt(prompt + (full ? 0 : prompt_skip), prompt_trunc); -} - -static void -vi_error() -{ - /* Beem out of any macros as soon as an error occurs */ - vi_macro_reset(); - x_putc(BEL); - x_flush(); -} - -static void -vi_macro_reset() -{ - if (macro.p) { - afree(macro.buf, APERM); - memset((char *) ¯o, 0, sizeof(macro)); - } -} - -#endif /* VI */ |