From 6bb38f6a01dbf4bbd584e038ceace0a00faa27bb Mon Sep 17 00:00:00 2001 From: Byron Rakitzis Date: Wed, 27 May 1992 00:00:01 +0100 Subject: release: rc-1.4 --- .gitignore | 0 CHANGES | 171 +++++ COPYRIGHT | 26 + EXAMPLES | 749 +++++++++++++++++++++ Makefile | 65 ++ README | 100 +++ addon.c | 22 + addon.h | 38 ++ builtins.c | 532 +++++++++++++++ config.h-dist | 204 ++++++ cpp | 38 ++ except.c | 140 ++++ exec.c | 119 ++++ execve.c | 61 ++ fn.c | 266 ++++++++ footobar.c | 368 +++++++++++ getopt.c | 50 ++ glob.c | 240 +++++++ glom.c | 420 ++++++++++++ hash.c | 302 +++++++++ heredoc.c | 156 +++++ history/Makefile | 6 + history/history.1 | 234 +++++++ history/history.c | 333 ++++++++++ input.c | 373 +++++++++++ jbwrap.h | 10 + lex.c | 398 ++++++++++++ list.c | 57 ++ main.c | 115 ++++ match.c | 99 +++ mksignal | 75 +++ nalloc.c | 137 ++++ open.c | 29 + parse.y | 174 +++++ print.c | 456 +++++++++++++ proto.h | 81 +++ rc.1 | 1880 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rc.h | 380 +++++++++++ redir.c | 77 +++ signal.c | 75 +++ status.c | 139 ++++ tree.c | 172 +++++ trip.rc | Bin 0 -> 14684 bytes utils.c | 125 ++++ var.c | 226 +++++++ version.c | 1 + wait.c | 124 ++++ walk.c | 344 ++++++++++ which.c | 114 ++++ 49 files changed, 10301 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGES create mode 100644 COPYRIGHT create mode 100644 EXAMPLES create mode 100644 Makefile create mode 100644 README create mode 100644 addon.c create mode 100644 addon.h create mode 100644 builtins.c create mode 100644 config.h-dist create mode 100644 cpp create mode 100644 except.c create mode 100644 exec.c create mode 100644 execve.c create mode 100644 fn.c create mode 100644 footobar.c create mode 100644 getopt.c create mode 100644 glob.c create mode 100644 glom.c create mode 100644 hash.c create mode 100644 heredoc.c create mode 100644 history/Makefile create mode 100644 history/history.1 create mode 100644 history/history.c create mode 100644 input.c create mode 100644 jbwrap.h create mode 100644 lex.c create mode 100644 list.c create mode 100644 main.c create mode 100644 match.c create mode 100755 mksignal create mode 100644 nalloc.c create mode 100644 open.c create mode 100644 parse.y create mode 100644 print.c create mode 100644 proto.h create mode 100644 rc.1 create mode 100644 rc.h create mode 100644 redir.c create mode 100644 signal.c create mode 100644 status.c create mode 100644 tree.c create mode 100644 trip.rc create mode 100644 utils.c create mode 100644 var.c create mode 100644 version.c create mode 100644 wait.c create mode 100644 walk.c create mode 100644 which.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..8456cd5 --- /dev/null +++ b/CHANGES @@ -0,0 +1,171 @@ +Changes since 1.2: (Too many to count!) + +A memory stomping bug was fixed (provoked by assigning a variable +to its old value plus something else). + +Better signal handling; a real signal handler which manages a queue +of pending signals was added. + +rc now ignores SIGQUIT and traps SIGINT even in non-interactive +mode. Thus, + + rc ed.sh + +will not do mysterious things if the shell script "ed.sh" calls a +command like "ed" and then you hit ^C. + +rc now opens 0, 1, 2 on /dev/null if they are inherited closed. +rc -o prevents this. + +A couple of stupid O(n^2) string appends were replaced with O(n) +loops. This should make foo=`{cat /etc/termcap} bar=$^foo a little +faster :-) + +Returning a list of signals from a function is now legal, so "return +$status" should always work. + +The code has been revised, new printing routines have been added. + +rc no longer uses redundant braces when exporting functions. + +A first stab at a verification suite has been added (trip.rc). +(someone, please help me make this comprehensive!) + +rc -p now does not initialize functions from the environment. This +should make it easier to write shell scripts that don't need to +assume anything about the environment. + +Inherited ignored signals are now ignored in the current shell and +passed on ignored to the child processes. whatis -s also reflects +this information. + +A file descriptor leak in the /dev/fd implementation of >{} was +fixed. + +A variable set to '' was not imported from the environment; this +has been fixed. + +Changes since 1.3beta: + +New Makefile/config.h setup. + +builtin echo may now be conditionally included out, to use a Goldwynism. + +builtin exit takes any legal exit status. If the status is not all zeros, +rc exits with 1. (having "exit sigiot" produce a core dump would be going +a little far, I think.) + +limit does not append a unit after a zero limit; 0g was too confusing. + +exec > /nonexistentfile does not cause rc to exit any more. + +If a noninteractive rc is started with sigint ignored, rc does not install +its own signal handler. + +error messages produced by rc in a subshell were cleaned up. (rc erroneously +reset the 'interactive' flag after a fork) + +print.c was cleaned up a little; no functionality was changed, but should +be more portable now. + +a bug in rc-1.3beta (not previous versions) was fixed: setting the first +element of $path to '' caused PATH to be exported as '':etc.. + +getopt's "illegal option" message was gratuitously changed to something +less abrupt. + +some dead code was removed from input.c + +%term was changed to %token in parse.y; apparently newer yacc's don't grok +%term any more. + +a race condition in the signal handler was fixed. + +the variable in for() was getting evaluated each time through the loop +(e.g., for (`{echo i;date>[1=2]} in 1 2 3)echo $i would print the date +three times). This was cleaned up. + +a redundant fork() was removed from walk.c; this showed up when running +a braced command with a redirection in the background. e.g., {a;b}>c& + +man pages for history and rc were cleaned up by david (thanks). + +rc set SIGQUIT and SIGTERM to SIG_DFL on background jobs---even when +trying to do old-style backgrounding (i.e., don't use process groups, +just ignore SIGINT & SIGQUIT & SIGTERM). + +$0 is now changed to the name of the signal when entering a signal +handler. Thus it's possible to write code like + + fn sigint sigterm sigquit { + switch ($0) { + case sigint + ... + case sigterm + ... + +wait with no arguments now prints the pid of any and all children +that died with a signal. e.g., + + ; wait + 25321: terminated + 25325: terminated + +as opposed to + + ; wait + terminated + +An error saving/restoring state in the input stream code would +cause rc to exit with the (erroneous) command: + + eval '|[a' + +FIFO's were not removed in a backgrounded command, e.g., + + cat <{echo hi}& + +Changes since rc-1.4beta: + +getopt was renamed to rc_getopt to avoid libc collisions. + +$cdpath with a / in it caused a cd to sometimes have two //'s at the +front of the path. This is reserved by POSIX, so I changed it to skip +one of the /'s. + +signal handling now emulates sh in the way I described in a previous +message: the race condition present in older rc's whereby some SIGINTs +got lost is now gone; any SIGINT received during a wait() is acted upon +at the end of the wait(), unless of course SIGINT is being deliberately +ignored. + +getopt was renamed to avoid naming conflicts with libc. Also a sound +move since rc_getopt is no longer quite libc-getopt compatible; I had +to add in a mechanism for resetting getopt. + +signal handler code in fn.c was cleaned up; there were several bugs +in rc-1.4beta, notably the shell sometimes spawned background jobs +with SIGTERM ignored. I took the opportunity to make things a little +cleaner here. + +a quasi-memory leak in the code for while() was fixed: a long-running +while that had rc commands allocating memory in it could cause the +shell to grow without bounds. I fixed this by placing the while loop +(*and* test!) inside a new allocation arena each time through the loop. + +A new configuration parameter, NOJOB, was added to allow you to force +v7-style backgrounding (no setpgrp, ignore SIGINT and SIGTERM). + +The FIFO code was reworked a little. It should be more robust now--- +FIFOs get removed at the end of the command of the argument list +that they were on: + + fn foo {echo $*; cat $*} + foo<{echo hi} + +now works as expected. Also FIFO names are pushed onto the exception +stack so that their removal occurs in the face of exceptions and so +on. + +A memory leak in treefree() was plugged up --- the root node of a +function was not getting freed. diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..279f66c --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,26 @@ +/* + * Copyright 1991 Byron Rakitzis. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * + * 4. This notice may not be removed or altered. + * + * [this copyright notice is adapted from Henry Spencer's + * "awf" copyright notice.] + */ diff --git a/EXAMPLES b/EXAMPLES new file mode 100644 index 0000000..90bd8df --- /dev/null +++ b/EXAMPLES @@ -0,0 +1,749 @@ +There is no repository for useful rc code snippets as yet, so I'm including +a (short) file in the distribution with some helpful/intriguing pieces of +rc code. + +A sample .rcrc +-------------- +Here is the .rcrc I use on archone: + +umask 022 +path=(/bin /usr/bin /usr/ucb) +ht=`/usr/arch/bin/hosttype +h=$home +history=$h/.history +bin=$h/bin/$ht +lib=$h/lib/$ht +sh=$h/bin/sh +include=$h/lib/include + +switch ($ht) { +case sun* + OBERON='. '$h/other/oberon + p=/usr/ucb + compiler='gcc -Wall -O -g' + MANPATH=$h/man:/usr/arch/man:/usr/man + if (! ~ $TERM ()) { + stty dec + /usr/arch/bin/msgs -q + } +case next + p=(/usr/ucb /usr/bin /NextApps) + compiler='cc -Wall -O -g -DNODIRENT' + MANPATH=$h/man:/usr/arch/man:/usr/man + if (! ~ $TERM ()) + stty dec +case sgi + p=(/usr/ucb /usr/sbin /usr/bin) + compiler='gcc -Wall -O -g -DNOSIGCLD' + MANPATH=$h/man:/usr/arch/man:/usr/catman + if (!{~ $TERM () || ~ $TERM *iris*}) + stty line 1 intr '' erase '' kill '' +case * + echo .rcrc not configured for this machine +} + +path=(. $sh $bin /usr/arch/bin $p /bin /usr/bin/X11 /etc /usr/etc) +cdpath=(. .. $h $h/src $h/misc $h/other $h/adm) +RNINIT=-d$h' -t -M -2400-h -2400+hfrom'; DOTDIR=$h/misc/news +PRINTER=lw + +fn s { + echo $status +} +fn cd { + builtin cd $1 && \ + switch ($1) { + case () + dir=$home + case * + dir=() + } +} +fn pwd { + if (~ $dir ()) + dir=`/bin/pwd + echo $dir +} +fn x { + if (~ `tty /dev/console) + clear_colormap + clear + exit +} +fn p { + if (~ $history ()) { + echo '$history not set' >[1=2] + return 1 + } + + if (! ~ $#* 0 1 2) { + echo usage: $0 '[egrep pattern] [sed command]' >[1=2] + return 1 + } + + command=`{ + egrep -v '^[ ]*p([ ]+|$)' $history | switch ($#*) { + case 0 + cat + case 1 + egrep $1 + case 2 + egrep $1 | sed $2 + } | tail -1 + } + + echo $command + eval $command +} + +if (~ $TERM dialup network) { + TERM=vt100 + biff y +} + +A front-end to NeXT's "openfile" +-------------------------------- + +Named after the sam "B" command for opening a file, this script was written +by Paul Haahr. (Assumes the "pick" command from Kernighan and Pike is also +in your path.) + +#!/bin/rc +if (~ $#* 0) + exec openfile +create = () +files = () +for (i in $*) + if (test -f $i) { + files = ($files $i) + } else { + create = ($create $i) + } +create = `{ pick $create } +files = ($files $create) +for (i in $create) + > $i +if (! ~ $#files 0) + openfile $files + +A read function +--------------- + +Unlike sh, rc doesn't have a read. This clever alternative returns an +exit status as well as fetch a variable. Use as + + read foo + +to set $foo to a single line from the terminal. + +(due to John Mackin ) + +fn read { + x=() { + x = `` ($nl) { awk '{print; print 0; exit}' ^ $nl ^ \ + 'END {print 1; print 1}' } + $1 = $x(1) + return $x(2) + } +} + +From cs.wisc.edu!dws Fri Aug 2 18:16:14 1991 + +#------- +# ls front end +#------- +fn ls \ +{ + test -t 1 && * = (-FCb $*) + builtin ls $* +} +#------- +# nl - holds a newline, useful in certain command substitutions +#------- +nl=' +' +#------- +# show - tell me about a name +# +# Runs possibly dangerous things through cat -v in order to protect +# me from the effects of control characters I might have in the +# environment. +#------- +fn show \ +{ + * = `` $nl {whatis -- $*} + for(itis) + { + switch($^itis) + { + case 'fn '* ; echo $itis | cat -v -t + case builtin* ; echo $itis + case /* ; file $itis; ls -ld $itis + case *'='* ; echo $itis | cat -v -t + case * ; echo $itis: UNKNOWN: update show + } + } + itis = () +} +#------- +# Tell me automatically when a command has a nonzero status. +#------- +fn prompt \ +{ + Status = $status + ~ $Status 0 || echo '[status '$Status']' +} + +#------- +# chop - echo the given list, less its final member +# +# e.g. chop (a b c) -> (a b) +#------- +fn chop { + ~ $#* 0 1 && return 0 + ans = '' { # local variable + ans = () + while(! ~ $#* 1) + { + ans = ($ans $1) + shift + } + echo $ans + } +} + +From arnold@audiofax.com Thu May 30 08:49:51 1991 + +# cd.rc --- souped up version of cd + +# this is designed to emulate the fancy version of cd in ksh, +# so if you're a purist, feel free to gag + +_cwd=$home +_oldcwd=$home + +fn cd { + if (~ $#* 0) { + if (~ $_cwd $home) { # do nothing + } else { + builtin cd && { _oldcwd=$_cwd ; _cwd=$home } + } + } else if (~ $#* 1) { + if (~ $1 -) { + _t=$_cwd + builtin cd $_oldcwd && { + _cwd=$_oldcwd + _oldcwd=$_t + echo $_cwd + } + _t=() + } else { + # if a cd happens through the cdpath, rc echos + # the directory on its own. all we have to do + # is track where we end up + _dopwd = 1 + { ~ $1 /* } && _dopwd = 0 # absolute path + builtin cd $1 && { + _oldcwd=$_cwd + _cwd=$1 + { ~ $_dopwd 1 } && _cwd=`/bin/pwd + } + _dopwd=() + } + } else if (~ $#* 2) { + _t=`{ echo $_cwd | sed 's<'$1'<'$2'<' } + builtin cd $_t && { + _oldcwd=$_cwd + _cwd=$_t + echo $_cwd + } + _t=() + } else { + echo cd: takes 0, 1, or 2 arguments >[1=2] + builtin cd $1 && { _oldcwd=$_cwd ; _cwd=`/bin/pwd ; echo $_cwd } + } +} + +fn pwd { echo $_cwd } + +From vlsi.cs.caltech.edu!drazen Tue Jan 21 16:03:14 1992 + +# A kill builtin. + +#ifdef B_KILL +#include +static void b_kill(char **av) +{ + int signal = SIGTERM; + int n = 1; + pid_t pid; + boolean res; + + if (!av[1]) { + set(TRUE); + return; + } +#undef STRCMP +#define STRCMP strcmp + if ( '-' == av[1][0]) { + char *p = 1+av[1]; + if (0 == strcmp(av[1], "-l")){ + int r; const int nsig = NUMOFSIGNALS; + const int C = 4, R = 1 + (int)((nsig-2)/C); + for (r=1; r<=R; r++){ + int j; + for (j=r; j; Thu, 2 Apr 1992 02:50:56 -0600 +Received: by thor.acc.stolaf.edu; Thu, 2 Apr 92 02:49:31 -0600 +Date: Thu, 2 Apr 1992 02:49:31 -0600 +From: quanstro@acc.stolaf.edu +Message-Id: <9204020849.AA26566@thor.acc.stolaf.edu> +To: byron@archone.tamu.edu +Subject: EXAMPLES in 1.4beta +Status: RO + + +I have a little bit of code which might be a little more general than +the souped-up version that is already there. Here it is, if you are +interested. + +# directory functions ################################################### +fn pwd { echo $PWD; } + +fn pushd { + dirs = ($PWD $dirs); + builtin cd $*; + PWD = `{builtin pwd}; +} + +fn popd { + switch ($#*) + { + case 0 + ; + case 1 + echo 'popd: argument '^$1^' ignored.' >[1=2]; + case * + echo 'popd: usage: popd [n].'; + } + + if (! ~ $dirs ()) + { + builtin cd $dirs(1); + PWD = $dirs(1); + echo $PWD; + * = $dirs; + shift + dirs = $*; + } +} + +fn cd { + ~ $* () && * = $home; + !~ $#* 1 && echo 'cd: too many arguments' >[1=2] && return 1; + + if (test -r $* ) { + pushd $*; + } else { + echo cd: $* does not exist. >[1=2] + return 1; + } +} + +fn back { popd $*; } + +fn Back { + cd $home; + PWD = $home; + dirs = (); +} + +fn dirs { + echo $dirs; +} + +PWD = `{builtin pwd} ; dirs = $PWD # kickstart + + + + + +From acc.stolaf.edu!quanstro Thu Apr 2 02:53:40 1992 +Received: from thor.acc.stolaf.edu ([130.71.192.1]) by archone.tamu.edu with SMTP id <45339>; Thu, 2 Apr 1992 02:53:38 -0600 +Received: by thor.acc.stolaf.edu; Thu, 2 Apr 92 02:51:46 -0600 +Date: Thu, 2 Apr 1992 02:51:46 -0600 +From: quanstro@acc.stolaf.edu +Message-Id: <9204020851.AA26573@thor.acc.stolaf.edu> +To: byron@archone.tamu.edu +Subject: EXAMPLES +Status: RO + + +Little yp hack which act's like ~ w/o syntatic sugar (for those who do +not have the luxury of seting up symbolic links to all user's homes + +# user function ######################################################### +fn u user { + info = () + info = `` (':') {ypmatch $1 passwd >[2] /dev/null } + + if (~ $info ()) { + echo user $1 unknown >[1=2]; + return 1; + } else { + echo $info(6) + if (~ $0 user) + cd $info(6) + } +} + + +From stolaf.edu!quanstro Sun Apr 5 04:53:34 1992 +Date: Sun, 5 Apr 1992 04:53:08 -0500 +From: quanstro@stolaf.edu (Erik Quanstrom) +To: byron@archone.tamu.edu +Subject: man written in rc +Status: RO + +I whipped this up because the NeXTs here insist on using MANPAGER +instead of PAGER and otherwise being obnoxious . . . + +Anyway ... I hope you approve + +#!/bin/rc +######################################################################### +# file: man # +# # +# object: display man pages # +# # +# bugs: * slow # +# * does not know about fmt files # +# # +# Erik Quanstrom # +# 11. Februar 1992 # +######################################################################### +PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:$PATH ; +TROFF = (nroff -hq -Tcrt); +macros=an; +sections=(cat1 cat2 cat3 cat4 cat5 cat6 cat7 cat8 catl man1 man2 man3 man4 \ + man5 man6 man7 man8 manl) +$nl=' +' +fn sigint sighup sigquit sigalrm sigterm { rm -f $Bat; exit 2;} + +fn usage { + echo usage: $0 [-] [-t] [-M path] [-T macros] [[section] title] ...>[1=2]; + exit 1; +} + +n=(); +fn shiftn { + n=($n 1) +} + +~ $PAGER () && test -t 1 && PAGER=more; #default pager + +while (~ $1 -*) + { + switch ($1) + { + case - + if (~ $PAGER troff) + echo bad combination of flags >[1=2] && usage; + PAGER=cat; + case -t + ~ TROFF () && TROFF = (troff -t); + ~ TCAT () && PAGER=(lpr -t); + case -M + shift; + ~ $1 () && usage; + + MANPATH=$1; + case -T + shift; + ~ $1 () && usage; + macros=$1; + case -k + fflag=(); kflag=1; + shift; + break; + case -f + # locate related too filenames + kflag=(); fflag=1; + shift; + break; + case -* + echo bad flag '`'^$1^'''' >[1=2]; + usage; + } + shift; + } + +if (!~ $#* 1) { + ~ $1 [l1-8] && { sname=$1 ; sections=(cat man)^$1 ; shift } + #hack for sun-style man pages + ~ $1 [l1-8]? && { sname=$1 ; sections=(cat man)^`{echo $1| cut -c1} ; shift } +} + +if (~ 1 $fflag $kflag) { + dirlist=(); + for (d in ``(:$nl) {echo $MANPATH}) + test -s $d^/whatis && dirlist=($dirlist $d^/whatis); + + ~ $1 () && usage; + + if (~ $fflag 1) { + while (!~ $1 ()) { + cmd=`{echo $1 | sed 's/^.*\///g'} + egrep -h '^'^$cmd' ' $dirlist; + shift; + } + } else { + while (!~ $1 ()) { + grep -h $1 $dirlist; + shift; + } + } + exit 0; +} + +s=0; +while (!~ $1 ()) { + for (dir in ``(:$nl) {echo $MANPATH}) { + filelist=($filelist `{echo $dir/^$sections^/$1^.* |\ + tr ' ' '\12' | grep -v '*'}) + + # coment this out if you don't care about speed, but + # would rather find all the pages. + ~ $filelist () || break; + } + + if (~ $filelist ()) { + if (~ $#sections 2) { + echo no entry for $1 in section '`'$sname'''' of the manual >[1=2]; + } else { + echo no entry for '`'$1'''' found. >[1=2]; + } + s=1; + } else { + + echo $filelist '(' $#filelist ')' >[1=2]; + + for (file in $filelist) { + if (~ $file */cat[1-8l]/*) { + Cat = ($Cat $file); + } else { + # search for dups + dont=() + for (x in $Cat) { + if (~ `{echo $x | sed 's/\/[mc]a[nt][1-8l]//'} \ + `{echo $file | sed 's/\/[mc]a[nt][1-8l]//'}) { + dont=1; + break; + } + } + + if (~ $dont ()) { + cd `{echo $file | sed 's/man[1-8].*//'} + echo -n Formatting ... + $TROFF -m^$macros $file > /tmp/man^$pid^$#n && \ + Bat = ($Bat /tmp/man^$pid^$#n) + + shiftn; + echo ' 'done. + } + } + } + } + shift; +} + +{ !~ () $Cat || !~ () $Bat } && $PAGER $Cat $Bat; + +rm -f $Bat; +~ $s () || exit $s; + +exit 0; + + + +From osf.org!rsalz Thu Apr 23 16:22:32 1992 +Date: Thu, 23 Apr 1992 16:22:07 -0500 +From: rsalz@osf.org +To: byron@archone.tamu.edu +Subject: One for your EXAMPLES file +Status: RO + +Use + trimhist [-#lines] +trims your history file back; useful for folks with dis quota's :-) +fn trimhist { p1=-100 { + cp $history $history^'~' + ~ $#* 1 && p1=$1 + tail $p1 <$history^'~' >$history + rm $history^'~' +} } + +From Pa.dec.com!uucp Mon Apr 27 12:25:02 1992 +Date: Mon, 27 Apr 1992 12:15:18 -0500 +From: haahr@adobe.com +To: Byron Rakitzis +Subject: a neat little rc script + +what you have to know to understand this: + $md for me is usually obj.$machine + my mkfiles build *.o, *.a, and the a.outs in $md + this is my acc script, which i use for compiling adobe routines +--- +#! /user/haahr/bin/next/rc + +cc = cc +proto = '-DPROTOTYPES=1' + +switch ($md) { +case noproto.$machine; proto = '-DPROTOTYPES=0' +case gprof.$machine; cc = ($cc -pg) +case prof.$machine; cc = ($cc -p) +case lcomp.$machine; cc = lcomp +} +exec $cc $proto '-DPACKAGE_SPECS="package.h"' '-DISP=isp_mc68020' '-DOS=os_mach' $* + +From rc-owner Tue May 12 14:54:10 1992 +Received: from postman.osf.org ([130.105.1.152]) by archone.tamu.edu with SMTP id <45337>; Tue, 12 May 1992 14:38:16 -0500 +Received: from earth.osf.org by postman.osf.org (5.64+/OSF 1.0) + id AA14480; Tue, 12 May 92 13:25:03 -0400 +Received: by earth.osf.org (5.64/4.7) id AA03499; Tue, 12 May 92 13:25:02 -0400 +Date: Tue, 12 May 1992 12:25:02 -0500 +From: rsalz@osf.org +Message-Id: <9205121725.AA03499@earth.osf.org> +To: rc@archone.tamu.edu +Subject: Useful function +Status: R + +It looks like line noise, but it turns things like + /home/rsalz/foo/bar +into + ~/foo/bar + +Useful for when you put your current directory up in your icon title. +By duplicating the $home section you can make things like + /project/dce/build/dce1.0.1/src/rpc +become + $MYBT/src/rpc + +## If a pathname starts with $home, turn $home into ~. Uses all built-ins. +fn tildepath { p1=() i=() { + p1=$1 + switch ($p1) { + case $home $home/* + # Split arg into components + *=`` (/) { echo -n $p1 } + # Shift down by number of components in $home + for (i in `` (/) { echo -n $home } ) shift + # Glue back together + p1='~' + for (i) p1=$p1 ^ '/' ^ $i + echo $p1 + case * + echo $p1 + } + return 0 +} } + +From osf.org!rsalz Tue May 12 15:47:12 1992 +Received: from postman.osf.org ([130.105.1.152]) by archone.tamu.edu with SMTP id <45316>; Tue, 12 May 1992 15:47:06 -0500 +Received: from earth.osf.org by postman.osf.org (5.64+/OSF 1.0) + id AA21070; Tue, 12 May 92 16:46:58 -0400 +Received: by earth.osf.org (5.64/4.7) id AA09396; Tue, 12 May 92 16:46:56 -0400 +Date: Tue, 12 May 1992 15:46:56 -0500 +From: rsalz@osf.org +Message-Id: <9205122046.AA09396@earth.osf.org> +To: byron@archone.tamu.edu +Subject: Re: Useful function +Status: R + +>wow. thanks, i'll add it to EXAMPLES. +Glad you like. Getting something added to EXAMPLES has been a goal of mine... + +I've been thinking, a bit, about a more general way of doing it. I want +a "prefix-sub" function, like this + prefix $some_path var1 var2 var3 var4 var5 +That would take some_path and replace any leading $var1 (etc) values +with the variable name. Return on the first match. + +Hmm -- come to think of it, that's very easy to do: + +# Use pathprefix filename var1 var2 var3 +# returns filename, with leading prefixes (in $var1...) turned into the +# string $var1... +fn pathprefix { p1=() i=() j=() { + p1=$1 ; shift + for (i) { + ~ $p1 $$i $$i^/* && { + *=`` (/) { echo -n $p1 } + for (j in `` (/) { echo -n $$i } ) shift + p1='$'^$i + for (j) p1=$p1 ^ '/' ^ $j + echo $p1 + return 0 + } + } + echo $p1 + return 0 +} } + +home=/user/users/rsalz +z=/usr/users +pathprefix /usr/users/rsalz home usr # --> $home +pathprefix /usr/users/rsalz z # --> $z/rsalz +pathprefix /usr/users/rsalz/foo z home # --> $z/rsalz/foo +pathprefix /usr/users/rsalz/foo home # --> $home/foo + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7306f36 --- /dev/null +++ b/Makefile @@ -0,0 +1,65 @@ +# Makefile for rc. + +# Please check the configuration parameters in config.h (and if you want +# to make sure, the definitions in proto.h) to make sure they are correct +# for your system. + +SHELL=/bin/sh + +# Uncomment this line if you have defined the NOEXECVE macro in config.h +#EXECVE=execve.o + +# Define this macro if you wish to extend rc via locally-defined builtins. +# An interface is provided in addon.[ch]. Note that the author does not +# endorse any such extensions, rather hopes that this way rc will become +# useful to more people. +#ADDON=addon.o + +# Use an ANSI compiler (or at least one that groks prototypes and void *): +CC=gcc -g -O +CFLAGS= +LDFLAGS= + +# You may substitute "bison -y" for yacc. (You want to choose the one that +# makes a smaller y.tab.c.) +YACC=yacc + +OBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \ + glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \ + nalloc.o open.o print.o redir.o sigmsgs.o signal.o status.o tree.o \ + utils.o var.o version.o wait.o walk.o which.o y.tab.o + +# If rc is compiled with READLINE defined, you must supply the correct +# arguments to ld on this line. Typically this would be something like: +# +# $(CC) -o $@ $(OBJS) -lreadline -ltermcap + +rc: $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) + +sigmsgs.c: mksignal + sh mksignal /usr/include/sys/signal.h + +y.tab.c: parse.y + $(YACC) -d parse.y + +config.h: config.h-dist + cp config.h-dist config.h + +trip: rc + ./rc -p < trip.rc + +clean: force + rm -f *.o *.tab.* sigmsgs.* + +history: force + cd history; make CC="$(CC)" $(HISTORYMAKEFLAGS) + +force: + +# dependencies: + +$(OBJS): config.h +sigmsgs.h: sigmsgs.c +lex.o y.tab.o: y.tab.c +builtins.c fn.c status.c hash.c: sigmsgs.h diff --git a/README b/README new file mode 100644 index 0000000..401fa8f --- /dev/null +++ b/README @@ -0,0 +1,100 @@ +This is release 1.4 of rc. + +Read COPYRIGHT for copying information. All files are + +Copyright 1991, Byron Rakitzis. + +COMPILING + +rc was written in portable ANSI C. If you don't have an ANSI compiler +like gcc or something close (e.g., sgi's cc) read further down on +how to convert rc's source to old C. + +Please read the Makefile, and copy config.h-dist to config.h and +examine the parameters in there; they let you customize rc to your +Unix. For example, some Unices support /dev/fd, or some have FIFOs. +If you do not perform this step then the Makefile will automatically +copy config.h-dist to config.h and proceed assuming that everything +is ok. Note that config.h-dist supplies default parameter configurations +for SunOS, NeXT-OS, Irix, Ultrix and some others. Finally, if you're +having trouble you may want to look at proto.h and see if everything +in there jibes with your system. + +After you've built rc, you may wish to run it through a test script +to see that everything is ok. Type "make trip" for this. This will +produce some output, and end with "trip is complete". If the trip +ends with "trip took a wrong turn..." then drop me a line. + +To compile the history program, go into the history subdirectory +and type "make". This will create a binary called "history". However, +in order for it to work as advertised it must be installed into +your bin as four files named -, --, -p and --p. (these can be soft +or hard links to the same file) + +rc may also be linked with either GNU readline (10,000+ lines of +code!) or a supplied readline-like system by Simmule Turner (1,000+ +lines of code). See the Makefile on how to do this. + +BUGS + +Send bug reports to byron@archone.tamu.edu. If a core dump is +generated, sending me a backtrace will help me out a great deal. You +can get a backtrace like this: + + ; gdb rc core + (gdb) where + <<>> + (gdb) + +Also, always report the machine, compiler and OS used to make rc. It's +possible I may have access to a machine of that type, in which case it +becomes much easier for me to track the bug down. + +If you are using gcc, please make sure that you have a recent version of +the compiler (1.39 and up) before you send me a note; I have found that +older versions of gcc choke over rc and generate bad code on several +architectures. (this is especially relevant for the the MIPS architecture) + +FEEPING CREATURISM + +See the end of the man page, under "INCOMPATABILITIES" for (known?) +differences from the "real" rc. Most of these changes were necessary +to get rc to work in a reasonable fashion on a real (i.e., commercial, +non-Labs) UNIX system; a few were changes motivated by concern +about some inadequacies in the original design. + +OLD C + +If you need to convert rc's source into K&R C, you need to run the +source through a filter called "unproto", posted in comp.sources.misc. +A sample "cpp" shell script that I used to run unproto under SunOS +is supplied with rc. + +CREDITS + +This shell was written by me, Byron Rakitzis, but kudos go to Paul +Haahr for letting me know what a shell should do and for contributing +certain bits and pieces to rc (notably the limits code, print.c, +most of which.c and the backquote redirection code), and to Hugh +Redelmeier for running rc through his fussy ANSI compiler and +thereby provoking interesting discussions about portability, and +also for providing many valuable suggestions for improving rc's +code in general. Finally, many thanks go to David Sanderson, for +reworking the man page to format well with troff, and for providing +many suggestions both for rc and its man page. + +Thanks to Boyd Roberts for the original history.c, and to Hugh +again for re-working parts of that code. + +Of course, without Tom Duff's design of the original rc, I could +not have written this shell (though I probably would have written +*a* shell). Almost of all of the features, with minor exceptions, +have been implemented as described in the Unix v10 manuals. Hats +off to td for designing a C-like, minimal but very useful shell. + +Tom Duff has kindly given permission for the paper he wrote for +UKUUG to be distributed with this version of rc (called "plan9.ps" +in the same ftp directory as the shell). Please read this paper +bearing in mind that it describes a program that was written at +AT&T and that the version of rc presented here differs in some +respects. diff --git a/addon.c b/addon.c new file mode 100644 index 0000000..df3fcd7 --- /dev/null +++ b/addon.c @@ -0,0 +1,22 @@ +/* + This file contains the implementations of any locally defined + builtins. +*/ + +#ifdef DWS + +/* + This is what DaviD Sanderson (dws@cs.wisc.edu) uses. +*/ + +#include +#include +#include + +#include "rc.h" /* for bool TRUE, FALSE */ +#include "addon.h" + +#include "addon/access.c" +#include "addon/test.c" + +#endif diff --git a/addon.h b/addon.h new file mode 100644 index 0000000..25f2312 --- /dev/null +++ b/addon.h @@ -0,0 +1,38 @@ +/* + This file is the interface to the rest of rc for any locally + defined addon builtins. By default there are none. + The interface consists of the following macro. + + ADDONS A comma-separated list of pairs of function pointers + and string literals. + + The addon functions must also have proper prototypes in this file. + The builtins all have the form: + + void b_NAME(char **av); + + Builtins report their exit status using set(TRUE) or set(FALSE). + + Example: + + #define ADDONS { b_test, "test" }, + extern void b_test(char **av); +*/ + +#define ADDONS /* no addons by default */ + +#ifdef DWS + +/* + This is what DaviD Sanderson (dws@cs.wisc.edu) uses. +*/ + +#undef ADDONS +#define ADDONS { b_access, "access" },\ + { b_test, "test" },\ + { b_test, "[" }, + +extern void b_access(char **av); +extern void b_test(char **av); + +#endif diff --git a/builtins.c b/builtins.c new file mode 100644 index 0000000..d9b2e2e --- /dev/null +++ b/builtins.c @@ -0,0 +1,532 @@ +/* builtins.c: the collection of rc's builtin commands */ + +/* + NOTE: rc's builtins do not call "rc_error" because they are + commands, and rc errors usually arise from syntax errors. e.g., + you probably don't want interpretation of a shell script to stop + because of a bad umask. +*/ + +#include +#include +#include +#include "rc.h" +#include "jbwrap.h" +#ifndef NOLIMITS +#include +#include +#endif +#include "addon.h" + +extern int umask(int); + +static void b_break(char **), b_cd(char **), b_eval(char **), b_exit(char **), + b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **), + b_wait(char **), b_whatis(char **); + +#ifndef NOLIMITS +static void b_limit(char **); +#endif +#ifndef NOECHO +static void b_echo(char **); +#endif + +static struct { + builtin_t *p; + char *name; +} builtins[] = { + { b_break, "break" }, + { b_builtin, "builtin" }, + { b_cd, "cd" }, +#ifndef NOECHO + { b_echo, "echo" }, +#endif + { b_eval, "eval" }, + { b_exec, "exec" }, + { b_exit, "exit" }, +#ifndef NOLIMITS + { b_limit, "limit" }, +#endif + { b_newpgrp, "newpgrp" }, + { b_return, "return" }, + { b_shift, "shift" }, + { b_umask, "umask" }, + { b_wait, "wait" }, + { b_whatis, "whatis" }, + { b_dot, "." }, + ADDONS +}; + +extern builtin_t *isbuiltin(char *s) { + int i; + for (i = 0; i < arraysize(builtins); i++) + if (streq(builtins[i].name, s)) + return builtins[i].p; + return NULL; +} + +/* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */ + +extern void funcall(char **av) { + Jbwrap j; + Estack e1, e2; + Edata jreturn, star; + if (setjmp(j.j)) + return; + starassign(*av, av+1, TRUE); + jreturn.jb = &j; + star.name = "*"; + except(eReturn, jreturn, &e1); + except(eVarstack, star, &e2); + walk(treecpy(fnlookup(*av), nalloc), TRUE); + varrm("*", TRUE); + unexcept(); /* eVarstack */ + unexcept(); /* eReturn */ +} + +static void arg_count(char *name) { + fprint(2, "too many arguments to %s\n", name); + set(FALSE); +} + +static void badnum(char *num) { + fprint(2, "%s is a bad number\n", num); + set(FALSE); +} + +/* a dummy command. (exec() performs "exec" simply by not forking) */ + +extern void b_exec(char **av) { +} + +#ifndef NOECHO +/* echo -n omits a newline. echo -- -n echos '-n' */ + +static void b_echo(char **av) { + char *format = "%A\n"; + if (*++av != NULL) { + if (streq(*av, "-n")) + format = "%A", av++; + else if (streq(*av, "--")) + av++; + } + fprint(1, format, av); + set(TRUE); +} +#endif + +/* cd. traverse $cdpath if the directory given is not an absolute pathname */ + +static void b_cd(char **av) { + List *s, nil; + char *path = NULL; + SIZE_T t, pathlen = 0; + if (*++av == NULL) { + s = varlookup("home"); + *av = (s == NULL) ? "/" : s->w; + } else if (av[1] != NULL) { + arg_count("cd"); + return; + } + if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */ + if (chdir(*av) < 0) { + set(FALSE); + uerror(*av); + } else + set(TRUE); + } else { + s = varlookup("cdpath"); + if (s == NULL) { + s = &nil; + nil.w = ""; + nil.n = NULL; + } + do { + if (s != &nil && *s->w != '\0') { + t = strlen(*av) + strlen(s->w) + 2; + if (t > pathlen) + path = nalloc(pathlen = t); + strcpy(path, s->w); + if (!streq(s->w, "/")) /* "//" is special to POSIX */ + strcat(path, "/"); + strcat(path, *av); + } else { + pathlen = 0; + path = *av; + } + if (chdir(path) >= 0) { + set(TRUE); + if (interactive && *s->w != '\0' && !streq(s->w, ".")) + fprint(1, "%s\n", path); + return; + } + s = s->n; + } while (s != NULL); + fprint(2, "couldn't cd to %s\n", *av); + set(FALSE); + } +} + +static void b_umask(char **av) { + int i; + if (*++av == NULL) { + set(TRUE); + i = umask(0); + umask(i); + fprint(1, "0%o\n", i); + } else if (av[1] == NULL) { + i = o2u(*av); + if ((unsigned int) i > 0777) { + fprint(2, "bad umask\n"); + set(FALSE); + } else { + umask(i); + set(TRUE); + } + } else { + arg_count("umask"); + return; + } +} + +static void b_exit(char **av) { + if (*++av != NULL) + ssetstatus(av); + rc_exit(getstatus()); +} + +/* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */ + +static void b_return(char **av) { + if (*++av != NULL) + ssetstatus(av); + rc_raise(eReturn); +} + +/* raise a "break" exception for breaking out of for and while loops */ + +static void b_break(char **av) { + if (av[1] != NULL) { + arg_count("break"); + return; + } + rc_raise(eBreak); +} + +/* shift $* n places (default 1) */ + +static void b_shift(char **av) { + int shift = (av[1] == NULL ? 1 : a2u(av[1])); + List *s, *dollarzero; + if (av[1] != NULL && av[2] != NULL) { + arg_count("shift"); + return; + } + if (shift < 0) { + badnum(av[1]); + return; + } + s = varlookup("*")->n; + dollarzero = varlookup("0"); + while (s != NULL && shift != 0) { + s = s->n; + --shift; + } + if (s == NULL && shift != 0) { + fprint(2, "cannot shift\n"); + set(FALSE); + } else { + varassign("*", append(dollarzero, s), FALSE); + set(TRUE); + } +} + +/* dud function */ + +extern void b_builtin(char **av) { +} + +/* wait for a given process, or all outstanding processes */ + +static void b_wait(char **av) { + int stat, pid; + if (av[1] == NULL) { + waitforall(); + return; + } + if (av[2] != NULL) { + arg_count("wait"); + return; + } + if ((pid = a2u(av[1])) < 0) { + badnum(av[1]); + return; + } + if (rc_wait4(pid, &stat, FALSE) > 0) + setstatus(pid, stat); + else + set(FALSE); + SIGCHK; +} + +/* + whatis without arguments prints all variables and functions. Otherwise, check to see if a name + is defined as a variable, function or pathname. +*/ + +static void b_whatis(char **av) { + bool f, found; + bool ess = FALSE; + int i, ac, c; + List *s; + Node *n; + char *e; + for (rc_optind = ac = 0; av[ac] != NULL; ac++) + ; /* count the arguments for getopt */ + while ((c = rc_getopt(ac, av, "s")) == 's') + ess = TRUE; + if (c != -1) { + set(FALSE); + return; + } + av += rc_optind; + if (*av == NULL && !ess) { + whatare_all_vars(); + set(TRUE); + return; + } + if (ess) + whatare_all_signals(); + found = TRUE; + for (i = 0; av[i] != NULL; i++) { + f = FALSE; + errno = ENOENT; + if ((s = varlookup(av[i])) != NULL) { + f = TRUE; + prettyprint_var(1, av[i], s); + } + if ((n = fnlookup(av[i])) != NULL) { + f = TRUE; + prettyprint_fn(1, av[i], n); + } else if (isbuiltin(av[i]) != NULL) { + f = TRUE; + fprint(1, "builtin %s\n", av[i]); + } else if ((e = which(av[i], FALSE)) != NULL) { + f = TRUE; + fprint(1, "%s\n", e); + } + if (!f) { + found = FALSE; + if (errno != ENOENT) + uerror(av[i]); + else + fprint(2, "%s not found\n", av[i]); + } + } + set(found); +} + +/* push a string to be eval'ed onto the input stack. evaluate it */ + +static void b_eval(char **av) { + bool i = interactive; + if (av[1] == NULL) + return; + interactive = FALSE; + pushstring(av + 1, i); /* don't reset line numbers on noninteractive eval */ + doit(TRUE); + interactive = i; +} + +/* + push a file to be interpreted onto the input stack. with "-i" treat this as an interactive + input source. +*/ + +extern void b_dot(char **av) { + int fd; + bool old_i = interactive, i = FALSE; + Estack e; + Edata star; + av++; + if (*av == NULL) + return; + if (streq(*av, "-i")) { + av++; + i = TRUE; + } + if (dasheye) { /* rc -i file has to do the right thing. reset the dasheye state to FALSE, though. */ + dasheye = FALSE; + i = TRUE; + } + if (*av == NULL) + return; + fd = rc_open(*av, rFrom); + if (fd < 0) { + if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */ + rcrc = FALSE; + else { + uerror(*av); + set(FALSE); + } + return; + } + rcrc = FALSE; + starassign(*av, av+1, TRUE); + pushfd(fd); + interactive = i; + star.name = "*"; + except(eVarstack, star, &e); + doit(TRUE); + varrm("*", TRUE); + unexcept(); /* eVarstack */ + interactive = old_i; +} + +/* put rc into a new pgrp. Used on the NeXT where the Terminal program is broken (sigh) */ + +static void b_newpgrp(char **av) { + if (av[1] != NULL) { + arg_count("newpgrp"); + return; + } + setpgrp(rc_pid, rc_pid); +#ifdef TIOCSPGRP + ioctl(2, TIOCSPGRP, &rc_pid); +#endif +} + +/* Berkeley limit support was cleaned up by Paul Haahr. */ + +#ifndef NOLIMITS +typedef struct Suffix Suffix; +struct Suffix { + const Suffix *next; + long amount; + char *name; +}; + +static const Suffix + kbsuf = { NULL, 1024, "k" }, + mbsuf = { &kbsuf, 1024*1024, "m" }, + gbsuf = { &mbsuf, 1024*1024*1024, "g" }, + stsuf = { NULL, 1, "s" }, + mtsuf = { &stsuf, 60, "m" }, + htsuf = { &mtsuf, 60*60, "h" }; +#define SIZESUF &gbsuf +#define TIMESUF &htsuf +#define NOSUF ((Suffix *) NULL) /* for RLIMIT_NOFILE on SunOS 4.1 */ + +typedef struct { + char *name; + int flag; + const Suffix *suffix; +} Limit; +static const Limit limits[] = { + { "cputime", RLIMIT_CPU, TIMESUF }, + { "filesize", RLIMIT_FSIZE, SIZESUF }, + { "datasize", RLIMIT_DATA, SIZESUF }, + { "stacksize", RLIMIT_STACK, SIZESUF }, + { "coredumpsize", RLIMIT_CORE, SIZESUF }, +#ifdef RLIMIT_RSS /* SysVr4 does not have this */ + { "memoryuse", RLIMIT_RSS, SIZESUF }, +#endif +#ifdef RLIMIT_VMEM /* instead, they have this! */ + { "vmemory", RLIMIT_VMEM, SIZESUF }, +#endif +#ifdef RLIMIT_NOFILE /* SunOS 4.1 adds a limit on file descriptors */ + { "descriptors", RLIMIT_NOFILE, NOSUF }, +#endif + { NULL, 0, NULL } +}; + +extern int getrlimit(int, struct rlimit *); +extern int setrlimit(int, struct rlimit *); + +static void printlimit(const Limit *limit, bool hard) { + struct rlimit rlim; + long lim; + getrlimit(limit->flag, &rlim); + if (hard) + lim = rlim.rlim_max; + else + lim = rlim.rlim_cur; + if (lim == RLIM_INFINITY) + fprint(1, "%s \tunlimited\n", limit->name); + else { + const Suffix *suf; + for (suf = limit->suffix; suf != NULL; suf = suf->next) + if (lim % suf->amount == 0 && (lim != 0 || suf->amount > 1)) { + lim /= suf->amount; + break; + } + fprint(1, "%s \t%d%s\n", limit->name, lim, (suf == NULL || lim == 0) ? "" : suf->name); + } +} + +static long parselimit(const Limit *limit, char *s) { + char *t; + int len = strlen(s); + long lim = 1; + const Suffix *suf = limit->suffix; + if (streq(s, "unlimited")) + return RLIM_INFINITY; + if (suf == TIMESUF && (t = strchr(s, ':')) != NULL) { + *t++ = '\0'; + lim = 60 * a2u(s) + a2u(t); + } else { + for (; suf != NULL; suf = suf->next) + if (streq(suf->name, s + len - strlen(suf->name))) { + s[len - strlen(suf->name)] = '\0'; + lim *= suf->amount; + break; + } + lim *= a2u(s); + } + return lim; +} + +static void b_limit(char **av) { + const Limit *lp = limits; + bool hard = FALSE; + if (*++av != NULL && streq(*av, "-h")) { + av++; + hard = TRUE; + } + if (*av == NULL) { + for (; lp->name != NULL; lp++) + printlimit(lp, hard); + return; + } + for (;; lp++) { + if (lp->name == NULL) { + fprint(2, "no such limit\n"); + set(FALSE); + return; + } + if (streq(*av, lp->name)) + break; + } + if (*++av == NULL) + printlimit(lp, hard); + else { + struct rlimit rlim; + long pl; + getrlimit(lp->flag, &rlim); + if ((pl = parselimit(lp, *av)) < 0) { + fprint(2, "bad limit\n"); + set(FALSE); + return; + } + if (hard) + rlim.rlim_max = pl; + else + rlim.rlim_cur = pl; + if (setrlimit(lp->flag, &rlim) == -1) { + uerror("setrlimit"); + set(FALSE); + } else + set(TRUE); + } +} +#endif diff --git a/config.h-dist b/config.h-dist new file mode 100644 index 0000000..5be81eb --- /dev/null +++ b/config.h-dist @@ -0,0 +1,204 @@ +/* Copy config.h-dist to config.h and edit config.h, don't edit this file */ + +/* + * Configuration parameters for rc. Suggested defaults are at the bottom + * of this file (you should probably look at those first to see if your + * system matches one of them; you can search for the beginning of the + * defaults section by looking for the string "#ifndef CUSTOM"). If you + * want to override the suggested defaults, define the macro CUSTOM. +#define CUSTOM + */ + +/* + * (Note that certain default settings redefine this macro) + * DEFAULTPATH the default search path that rc uses when it is started + * without either a $PATH or $path environment variable. You must pick + * something sensible for your system if you don't like the path shown + * below. + */ +#define DEFAULTPATH "/usr/ucb", "/usr/bin", "/bin", "." + +/* + * Define the macro NODIRENT if your system has but not + * . (e.g., NeXT-OS and RISCos) +#define NODIRENT + */ + +/* + * Define the macro SVSIGS if your system has System V signal semantics, + * i.e., if "slow" system calls are interrupted rather than resumed + * after returning from an interrupt handler. (If you are not sure what + * this means, see the man page for signal(2). In any case, it is probably + * safe to leave this macro undefined.) +#define SVSIGS + */ + +/* + * Define the macro NOCMDARG if you do not have /dev/fd or fifos on your + * system. You may also want to define this if you have broken fifos. +#define NOCMDARG + */ + +/* + * Define TMPDIR if you need to have rc create its fifos in a directory + * other than /tmp. For example, if you have a Sun with /tmp mounted + * as a ramdisk (type "tmpfs") then you cannot use fifos in /tmp (sigh). +#define TMPDIR "/var/tmp" + */ + +/* + * Define the macro DEVFD if your system supports /dev/fd. +#define DEVFD + */ + +/* + * Define the macro NOLIMITS if your system does not support Berkeley + * limits. +#define NOLIMITS + */ + +/* + * Define the macro NOSIGCLD if your system uses SIGCLD in the System + * V way. (e.g., sgi's Irix) +#define NOSIGCLD + */ + +/* + * Define the macro READLINE if you want rc to call GNU readline + * instead of read(2) on interactive shells. +#define READLINE + */ + +/* + * Define the macro NOEXECVE if your Unix does not interpret #! in the + * kernel, and uncomment the EXECVE variable in the Makefile. +#define NOEXECVE + */ + +/* + * If you want rc to default to some interpreter for files which don't + * have a legal #! on the first line, define the macro DEFAULTINTERP. +#define DEFAULTINTERP "/bin/sh" + */ + +/* + * If your /bin/sh (or another program you care about) rejects environment + * variables with special characters in them (such as ':' or '-'), rc can + * put out ugly variable names using [_0-9a-zA-Z] that encode the real name; + * define PROTECT_ENV for this hack. (Known offenders: every sh I have tried; + * SunOS (silently discards), NeXT (aborts with error), SGI (aborts with + * error), Ultrix (sh seems to work, sh5 aborts with error)) +#define PROTECT_ENV + */ + +/* + * Define the macro NOECHO if you wish to omit rc's echo builtin from the + * compile. +#define NOECHO + */ + +/* + * Define the NOJOB if you do *not* wish rc to perform backgrounding + * as if it were a job-control shell; that is, if you do *not* wish + * it to put a command spawned in the background into a new process + * group. Since most systems support job control and since there are + * many broken programs that do not behave correctly when backgrounded + * in a v7 non-job-control fashion, rc by default performs a job- + * control-like backgrounding. +#define NOJOB + */ + +/* Beginning of defaults section: */ + +#ifndef CUSTOM + +/* + * Suggested settings for Sun, NeXT and sgi (machines here at TAMU): + */ + +#ifdef NeXT /* Used on NextOS 2.1 */ +#define NODIRENT +#define PROTECT_ENV +#define NOCMDARG +#endif + +#ifdef sgi /* Used on Irix 3.3.[12] */ +#define SVSIGS +#define NOSIGCLD +#define PROTECT_ENV +#undef DEFAULTPATH +#define DEFAULTPATH "/usr/bsd", "/usr/sbin", "/usr/bin", "/bin", "." +#endif + +#ifdef sun /* Used on SunOS 4.1.1 */ +#define PROTECT_ENV +#undef DEFAULTPATH +#define DEFAULTPATH "/usr/ucb", "/usr/bin", "." +#endif + +/* + * Suggested settings for HP300 running 4.3BSD-utah (DWS): + */ + +#if defined(hp300) && !defined(hpux) +#define NODIRENT +#define NOCMDARG +#define DEFAULTINTERP "/bin/sh" +#define PROTECT_ENV +#endif + +/* + * Suggested settings for Ultrix + */ + +#ifdef ultrix +#define PROTECT_ENV +#define DEFAULTINTERP "/bin/sh" /* so /bin/true can work */ +#endif + +/* + * Suggested settings for RISCos 4.52 + */ + +/* + This doesn't work without interfering with other MIPS-based + systems' configuration. Please do it by hand. +*/ + +#if defined(host_mips) && defined(MIPSEB) && defined(SYSTYPE_BSD43) +#define NODIRENT +#define PROTECT_ENV +#endif + +/* + * Suggested settings for AIX + */ + +#ifdef _AIX +#define PROTECT_ENV +#endif + +/* + * Suggested settings for OSF/1 1.0 + */ + +#ifdef OSF1 +#define PROTECT_ENV +#endif + +/* + * Suggested settings for Unicos XXX + */ + +#ifdef cray +#define PROTECT_ENV +#define NOLIMITS +#define word _word +#define DEFAULTINTERP "/bin/sh" +#endif + +#endif /* CUSTOM */ + +#ifndef TMPDIR +#define TMPDIR "/tmp" +#endif diff --git a/cpp b/cpp new file mode 100644 index 0000000..e3ac656 --- /dev/null +++ b/cpp @@ -0,0 +1,38 @@ +#!/bin/sh + +# @(#) cpp.sh 1.3 92/01/15 21:53:22 + +# Unprototypeing preprocessor for pre-ANSI C compilers. On some systems, +# this script can be as simple as: +# +# /lib/cpp "$@" | unproto +# +# However, some cc(1) drivers specify output file names on the +# preprocessor command line, so this shell script must be prepared to +# intercept them. Depending on the driver program, the cpp options may +# even go before or after the file name argument(s). The script below +# tries to tackle all these cases. +# +# You may want to add -Ipath_to_stdarg.h_file, -Dvoid=, -Dvolatile=, +# and even -D__STDC__. + +## (This is what I used while testing with the SunOS C compiler. +## Also, I added "-Qpath ." to CFLAGS so that cpp would be +## run out of the current directory. --- Byron) +cpp_args="-I/u/byron/lib/sun4 -Dconst= -Dvolatile=" + +while : +do + case $1 in + "") break;; + -*) cpp_args="$cpp_args $1";; + *) cpp_args="$cpp_args $1" + case $2 in + ""|-*) ;; + *) exec 1> $2 || exit 1; shift;; + esac;; + esac + shift +done + +/lib/cpp $cpp_args | unproto diff --git a/except.c b/except.c new file mode 100644 index 0000000..48ea008 --- /dev/null +++ b/except.c @@ -0,0 +1,140 @@ +#include +#include +#include "rc.h" +#include "jbwrap.h" + +/* + A return goes back stack frames to the last return. A break does + not. A signal goes to the last interactive level. (see below) +*/ + +bool nl_on_intr = TRUE; + +static Estack *estack; + +/* add an exception to the input stack. */ + +extern void except(ecodes e, Edata data, Estack *ex) { + ex->prev = estack; + estack = ex; + estack->e = e; + estack->data = data; + if (e == eError || e == eBreak || e == eReturn) + estack->interactive = interactive; +} + +/* remove an exception, restore last interactive value */ + +extern void unexcept() { + switch (estack->e) { + default: + break; + case eError: + interactive = estack->interactive; + break; + case eArena: + restoreblock(estack->data.b); + break; + case eFifo: + unlink(estack->data.name); + break; + case eFd: + close(estack->data.fd); + break; + } + estack = estack->prev; +} + +/* + Raise an exception. The rules are pretty complicated: you can return + from a loop inside a function, but you can't break from a function + inside of a loop. On errors, rc_raise() goes back to the LAST + INTERACTIVE stack frame. If no such frame exists, then rc_raise() + exits the shell. This is what happens, say, when there is a syntax + error in a noninteractive shell script. While traversing the + exception stack backwards, rc_raise() also removes input sources + (closing file-descriptors, etc.) and pops instances of variables + that have been pushed onto the variable stack (e.g., for a function + call (for $*) or a local assignment). +*/ + +extern void rc_raise(ecodes e) { + if (e == eError && rc_pid != getpid()) + exit(1); /* child processes exit on an error/signal */ + for (; estack != NULL; estack = estack->prev) + if (estack->e != e) { + if (e == eBreak && estack->e != eArena) + rc_error("break outside of loop"); + else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */ + rc_error("return outside of function"); + switch (estack->e) { + default: + break; + case eVarstack: + varrm(estack->data.name, TRUE); + break; + case eArena: + restoreblock(estack->data.b); + break; + case eFifo: + unlink(estack->data.name); + break; + case eFd: + close(estack->data.fd); + break; + } + } else { + if (e == eError && !estack->interactive) { + popinput(); + } else { + Jbwrap *j = estack->data.jb; + + interactive = estack->interactive; + estack = estack->prev; + longjmp(j->j, 1); + } + } + rc_exit(1); /* top of exception stack */ +} + +extern bool outstanding_cmdarg() { + return estack->e == eFifo || estack->e == eFd; +} + +extern void pop_cmdarg(bool remove) { + for (; estack != NULL; estack = estack->prev) + switch (estack->e) { + case eFifo: + if (remove) + unlink(estack->data.name); + break; + case eFd: + if (remove) + close(estack->data.fd); + break; + default: + return; + } +} + +/* exception handlers */ + +extern void rc_error(char *s) { + pr_error(s); + set(FALSE); + redirq = NULL; + cond = FALSE; /* no longer inside conditional */ + rc_raise(eError); +} + +extern void sigint(int s) { + if (s != SIGINT) + panic("s != SIGINT in sigint catcher"); + /* this is the newline you see when you hit ^C while typing a command */ + if (nl_on_intr) + fprint(2, "\n"); + nl_on_intr = TRUE; + redirq = NULL; + cond = FALSE; + rc_raise(eError); +} diff --git a/exec.c b/exec.c new file mode 100644 index 0000000..38d627c --- /dev/null +++ b/exec.c @@ -0,0 +1,119 @@ +/* exec.c */ +#include +#include +#include +#include "rc.h" +#include "jbwrap.h" + +/* + Takes an argument list and does the appropriate thing (calls a + builtin, calls a function, etc.) +*/ + +extern void exec(List *s, bool parent) { + char **av, **ev = NULL; + int pid, stat; + builtin_t *b; + char *path = NULL; + bool didfork, returning, saw_exec, saw_builtin; + av = list2array(s, dashex); + saw_builtin = saw_exec = FALSE; + do { + if (*av == NULL || isabsolute(*av)) + b = NULL; + else if (!saw_builtin && fnlookup(*av) != NULL) + b = funcall; + else + b = isbuiltin(*av); + + /* + a builtin applies only to the immmediately following + command, e.g., builtin exec echo hi + */ + saw_builtin = FALSE; + + if (b == b_exec) { + av++; + saw_exec = TRUE; + parent = FALSE; + } else if (b == b_builtin) { + av++; + saw_builtin = TRUE; + } + } while (b == b_exec || b == b_builtin); + if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */ + doredirs(); + return; + } + /* force an exit on exec with any rc_error, but not for null commands as above */ + if (saw_exec) + rc_pid = -1; + if (b == NULL) { + path = which(*av, TRUE); + if (path == NULL && *av != NULL) { /* perform null commands for redirections */ + set(FALSE); + redirq = NULL; + if (parent) + return; + rc_exit(1); + } + ev = makeenv(); /* environment only needs to be built for execve() */ + } + /* + If parent & the redirq is nonnull, builtin or not it has to fork. + If the fifoq is nonnull, then it must be emptied at the end so we + must fork no matter what. + */ + if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) { + pid = rc_fork(); + didfork = TRUE; + } else { + pid = 0; + didfork = FALSE; + } + returning = (!didfork && parent); + switch (pid) { + case -1: + uerror("fork"); + rc_error(NULL); + /* NOTREACHED */ + case 0: + if (!returning) + setsigdefaults(FALSE); + pop_cmdarg(FALSE); + doredirs(); + + /* null commands performed for redirections */ + if (*av == NULL || b != NULL) { + if (b != NULL) + (*b)(av); + if (returning) + return; + rc_exit(getstatus()); + } +#ifdef NOEXECVE + my_execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */ +#else + execve(path, (const char **) av, (const char **) ev); +#endif +#ifdef DEFAULTINTERP + if (errno == ENOEXEC) { + *av = path; + *--av = DEFAULTINTERP; + execve(*av, (const char **) av, (const char **) ev); + } +#endif + uerror(*av); + rc_exit(1); + /* NOTREACHED */ + default: + redirq = NULL; + rc_wait4(pid, &stat, TRUE); + setstatus(-1, stat); + if ((stat & 0xff) == 0) + nl_on_intr = FALSE; + SIGCHK; + nl_on_intr = TRUE; + pop_cmdarg(TRUE); + } +} diff --git a/execve.c b/execve.c new file mode 100644 index 0000000..b21b30c --- /dev/null +++ b/execve.c @@ -0,0 +1,61 @@ +/* execve.c: an execve() for geriatric unices without #! */ + +/* + NOTE: this file depends on a hack in footobar.c which places two free spots before + av[][] so that execve does not have to call malloc. +*/ + +#include +#include "rc.h" + +#define giveupif(x) { if (x) goto fail; } + +extern int my_execve(const char *path, const char **av, const char **ev) { + int fd, len, fst, snd, end; + bool noarg; + char pb[256]; /* arbitrary but generous limit */ + execve(path, av, ev); + if (errno != ENOEXEC) + return -1; + fd = rc_open(path, rFrom); + giveupif(fd < 0); + len = read(fd, pb, sizeof pb); + close(fd); + /* reject scripts which don't begin with #! */ + giveupif(len <= 0 || pb[0] != '#' || pb[1] != '!'); + for (fst = 2; fst < len && (pb[fst] == ' ' || pb[fst] == '\t'); fst++) + ; /* skip leading whitespace */ + giveupif(fst == len); + for (snd = fst; snd < len && pb[snd] != ' ' && pb[snd] != '\t' && pb[snd] != '\n'; snd++) + ; /* skip first arg */ + giveupif(snd == len); + noarg = (pb[snd] == '\n'); + pb[snd++] = '\0'; /* null terminate the first arg */ + if (!noarg) { + while (snd < len && (pb[snd] == ' ' || pb[snd] == '\t')) + snd++; /* skip whitespace to second arg */ + giveupif(snd == len); + noarg = (pb[snd] == '\n'); /* could have trailing whitespace after only one arg */ + if (!noarg) { + for (end = snd; end < len && pb[end] != ' ' && pb[end] != '\t' && pb[end] != '\n'; end++) + ; /* skip to the end of the second arg */ + giveupif(end == len); + if (pb[end] == '\n') { + pb[end] = '\0'; /* null terminate the first arg */ + } else { /* else check for a spurious third arg */ + pb[end++] = '\0'; + while (end < len && (pb[end] == ' ' || pb[end] == '\t')) + end++; + giveupif(end == len || pb[end] != '\n'); + } + } + } + *av = path; + if (!noarg) + *--av = pb + snd; + *--av = pb + fst; + execve(*av, av, ev); + return -1; +fail: errno = ENOEXEC; + return -1; +} diff --git a/fn.c b/fn.c new file mode 100644 index 0000000..02de02b --- /dev/null +++ b/fn.c @@ -0,0 +1,266 @@ +/* + fn.c: functions for adding and deleting functions from the symbol table. + Support for signal handlers is also found here. +*/ + +#include +#include +#include "rc.h" +#include "sigmsgs.h" + +static void fn_handler(int), dud_handler(int); + +static bool runexit = FALSE; +static Node *handlers[NUMOFSIGNALS], null; +static void (*def_sigint)(int) = SIG_DFL, + (*def_sigquit)(int) = SIG_DFL, + (*def_sigterm)(int) = SIG_DFL; + +/* + Set signals to default values for rc. This means that interactive + shells ignore SIGTERM, etc. +*/ + +extern void inithandler() { + int i; + null.type = nBody; + null.u[0].p = null.u[1].p = NULL; + for (i = 1; i < NUMOFSIGNALS; i++) +#ifdef NOSIGCLD + if (i != SIGCLD) +#endif + if (sighandlers[i] == SIG_IGN) + fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */ + if (interactive || sighandlers[SIGINT] != SIG_IGN) { + def_sigint = sigint; + fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */ + } + if (!dashdee) { + if (interactive || sighandlers[SIGQUIT] != SIG_IGN) { + def_sigquit = dud_handler; + fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */ + } + if (interactive) { + def_sigterm = dud_handler; + fnrm("sigterm"); /* ditto for SIGTERM */ + } + } +} + +/* only run this in a child process! resets signals to their default values */ + +extern void setsigdefaults(bool sysvbackground) { + int i; + /* + General housekeeping: setsigdefaults happens after fork(), + so it's a convenient place to clean up open file descriptors. + (history file, scripts, etc.) + */ + closefds(); + /* + Restore signals to SIG_DFL, paying close attention to + a few quirks: SIGINT, SIGQUIT and are treated specially + depending on whether we are doing v7-style backgrounding + or not; the default action for SIGINT, SIGQUIT and SIGTERM + must be set to the appropriate action; finally, care must + be taken not to set to SIG_DFL any signals which are being + ignored. + */ + for (i = 1; i < NUMOFSIGNALS; i++) + if (sighandlers[i] != SIG_IGN) { + handlers[i] = NULL; + switch (i) { + case SIGINT: + if (sysvbackground) { + def_sigint = SIG_IGN; + fnassign("sigint", NULL); /* ignore */ + } else { + def_sigint = SIG_DFL; + goto sigcommon; + } + break; + case SIGQUIT: + if (sysvbackground) { + def_sigquit = SIG_IGN; + fnassign("sigquit", NULL); /* ignore */ + } else { + def_sigquit = SIG_DFL; + goto sigcommon; + } + break; + case SIGTERM: + def_sigterm = SIG_DFL; + /* FALLTHROUGH */ + sigcommon: + default: + if (sighandlers[i] != SIG_DFL) { + rc_signal(i, SIG_DFL); + delete_fn(signals[i].name); + } + } + } + delete_fn("sigexit"); + runexit = FALSE; /* No sigexit on subshells */ +} + +/* rc's exit. if runexit is set, run the sigexit function. */ + +extern void rc_exit(int stat) { + static char *sigexit[2] = { + "sigexit", + NULL + }; + if (runexit) { + runexit = FALSE; + funcall(sigexit); + stat = getstatus(); + } + exit(stat); +} + +/* The signal handler for all functions. calls walk() */ + +static void fn_handler(int s) { + List *dollarzero; + Estack e; + Edata star; + int olderrno; + if (s < 1 || s >= NUMOFSIGNALS) + panic("unknown signal"); + olderrno = errno; + dollarzero = nnew(List); + dollarzero->w = signals[s].name; + dollarzero->n = NULL; + varassign("*", dollarzero, TRUE); + star.name = "*"; + except(eVarstack, star, &e); + walk(handlers[s], TRUE); + varrm("*", TRUE); + unexcept(); /* eVarstack */ + errno = olderrno; +} + +/* A dud signal handler for SIGQUIT and SIGTERM */ + +static void dud_handler(int s) { +} + +/* + Assign a function in Node form. Check to see if the function is also + a signal, and set the signal vectors appropriately. +*/ + +extern void fnassign(char *name, Node *def) { + Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */ + Function *new = get_fn_place(name); + int i; + new->def = newdef; + new->extdef = NULL; + if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */ +#ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */ + if (streq(name, "sigcld")) + rc_error("can't trap SIGCLD"); +#endif + if (streq(name, "sigexit")) + runexit = TRUE; + for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */ + if (streq(signals[i].name, name)) { + handlers[i] = newdef; + if (def == NULL) + rc_signal(i, SIG_IGN); + else + rc_signal(i, fn_handler); + break; + } + } +} + +/* Assign a function from the environment. Store just the external representation */ + +extern void fnassign_string(char *extdef) { + char *name = get_name(extdef+3); /* +3 to skip over "fn_" */ + Function *new; + if (name == NULL) + return; + new = get_fn_place(name); + new->def = NULL; + new->extdef = ecpy(extdef); +} + +/* Return a function in Node form, evaluating an entry from the environment if necessary */ + +extern Node *fnlookup(char *name) { + Function *look = lookup_fn(name); + Node *ret; + if (look == NULL) + return NULL; /* not found */ + if (look->def != NULL) + return look->def; + if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */ + return &null; + ret = parse_fn(name, look->extdef); + if (ret == NULL) { + efree(look->extdef); + look->extdef = NULL; + return &null; + } else { + return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */ + } +} + +/* Return a function in string form (used by makeenv) */ + +extern char *fnlookup_string(char *name) { + Function *look = lookup_fn(name); + + if (look == NULL) + return NULL; + if (look->extdef != NULL) + return look->extdef; + return look->extdef = fun2str(name, look->def); +} + +/* + Remove a function from the symbol table. If it also defines a signal + handler, restore the signal handler to its default value. +*/ + +extern void fnrm(char *name) { + int i; + for (i = 1; i < NUMOFSIGNALS; i++) + if (streq(signals[i].name, name)) { + handlers[i] = NULL; + switch (i) { + case SIGINT: + rc_signal(i, def_sigint); + break; + case SIGQUIT: + rc_signal(i, def_sigquit); + break; + case SIGTERM: + rc_signal(i, def_sigterm); + break; + default: + rc_signal(i, SIG_DFL); + } + } + if (streq(name, "sigexit")) + runexit = FALSE; + delete_fn(name); +} + +extern void whatare_all_signals() { + int i; + for (i = 1; i < NUMOFSIGNALS; i++) + if (*signals[i].name != '\0') + if (sighandlers[i] == SIG_IGN) + fprint(1, "fn %s {}\n", signals[i].name); + else if (sighandlers[i] == fn_handler) + fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]); + else + fprint(1, "fn %s\n", signals[i].name); +} + +extern void prettyprint_fn(int fd, char *name, Node *n) { + fprint(fd, "fn %S {%T}\n", name, n); +} diff --git a/footobar.c b/footobar.c new file mode 100644 index 0000000..f50db3c --- /dev/null +++ b/footobar.c @@ -0,0 +1,368 @@ +/* + footobar.c: a collection of functions to convert internal representations of + variables and functions to external representations, and vice versa +*/ + +#include "rc.h" + +#define FSCHAR '\1' +#define FSSTRING "\1" + +static char *getenvw(char *, bool); + +#ifdef PROTECT_ENV +static bool Fconv(Format *f, int ignore) { /* protect an exported name from brain-dead shells */ + int c; + unsigned const char *s = va_arg(f->args, unsigned const char *); + + while ((c = *s++) != '\0') + if (dnw[c] || c == '*' || (c == '_' && *s == '_')) + fmtprint(f, "__%02x", c); + else + fmtputc(f, c); + return FALSE; +} +#endif + +/* used to turn a function in Node * form into something we can export to the environment */ + +extern char *fun2str(char *name, Node *n) { + return mprint("fn_%F={%T}", name, n); +} + +/* convert a redirection to a printable form */ + +static bool Dconv(Format *f, int ignore) { + const char *name = "?"; + int n = va_arg(f->args, int); + switch (n) { + case rCreate: name = ">"; break; + case rAppend: name = ">>"; break; + case rFrom: name = "<"; break; + case rHeredoc: name = "<<"; break; + case rHerestring: name = "<<<"; break; + } + fmtcat(f, name); + return FALSE; +} + +/* defaultfd -- return the default fd for a given redirection operation */ + +extern int defaultfd(int op) { + return (op == rCreate || op == rAppend) ? 1 : 0; +} + +/* convert a function in Node * form into something rc can parse (and humans can read?) */ + +static bool Tconv(Format *f, int ignore) { + Node *n = va_arg(f->args, Node *); + if (n == NULL) { + fmtprint(f, "()"); + return FALSE; + } + switch (n->type) { + case nWord: fmtprint(f, "%S", n->u[0].s); break; + case nQword: fmtprint(f, "%#S", n->u[0].s); break; + case nBang: fmtprint(f, "! %T", n->u[0].p); break; + case nCase: fmtprint(f, "case %T", n->u[0].p); break; + case nNowait: fmtprint(f, "%T&", n->u[0].p); break; + case nCount: fmtprint(f, "$#%T", n->u[0].p); break; + case nFlat: fmtprint(f, "$^%T", n->u[0].p); break; + case nRmfn: fmtprint(f, "fn %T", n->u[0].p); break; + case nSubshell: fmtprint(f, "@ %T", n->u[0].p); break; + case nVar: fmtprint(f, "$%T", n->u[0].p); break; + case nAndalso: fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p); break; + case nAssign: fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p); break; + case nConcat: fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p); break; + case nElse: fmtprint(f, "{%T}else %T", n->u[0].p, n->u[1].p); break; + case nNewfn: fmtprint(f, "fn %T {%T}", n->u[0].p, n->u[1].p); break; + case nIf: fmtprint(f, "if(%T)%T", n->u[0].p, n->u[1].p); break; + case nOrelse: fmtprint(f, "%T||%T", n->u[0].p, n->u[1].p); break; + case nArgs: fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); break; + case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break; + case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break; + case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; + case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break; + case nLappend: fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); break; + case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break; + case nDup: + if (n->u[2].i != -1) + fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i); + else + fmtprint(f, "%D[%d=]", n->u[0].i, n->u[1].i); + break; + case nBackq: { + Node *n0 = n->u[0].p, *n00; + if (n0 != NULL && n0->type == nVar + && (n00 = n0->u[0].p) != NULL && n00->type == nWord && streq(n00->u[0].s, "ifs")) + fmtprint(f, "`"); + else + fmtprint(f, "``%T", n0); + fmtprint(f, "{%T}", n->u[1].p); + break; + } + case nCbody: + case nBody: { + Node *n0 = n->u[0].p; + if (n0 != NULL) + fmtprint(f, "%T", n->u[0].p); + if (n->u[1].p != NULL) { + if (n0 != NULL && n0->type != nNowait) + fmtprint(f, ";"); + fmtprint(f, "%T", n->u[1].p); + } + break; + } + case nBrace: + fmtprint(f, "{%T}", n->u[0].p); + if (n->u[1].p != NULL) + fmtprint(f, "%T", n->u[1].p); + break; + case nEpilog: + case nPre: + fmtprint(f, "%T", n->u[0].p); + if (n->u[1].p != NULL) + fmtprint(f, " %T", n->u[1].p); + break; + case nPipe: { + int ofd = n->u[0].i, ifd = n->u[1].i; + fmtprint(f, "%T|", n->u[2].p); + if (ifd != 0) + fmtprint(f, "[%d=%d]", ofd, ifd); + else if (ofd != 1) + fmtprint(f, "[%d]", ofd); + fmtprint(f, "%T", n->u[3].p); + break; + } + case nRedir: { + int op = n->u[0].i; + fmtprint(f, "%D", op); + if (n->u[1].i != defaultfd(op)) + fmtprint(f, "[%d]", n->u[1].i); + fmtprint(f, "%T", n->u[2].p); + break; + } + case nNmpipe: { + int op = n->u[0].i; + fmtprint(f, "%D", op); + if (n->u[1].i != defaultfd(op)) + fmtprint(f, "[%d]", n->u[1].i); + fmtprint(f, "{%T}", n->u[2].p); + break; + } + } + return FALSE; +} + +/* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */ + +extern char *list2str(char *name, List *s) { + SIZE_T size, step; + List *t; + char *w, *x; + name = nprint("%F", name); + size = strlen(name) + listlen(s); + w = ealloc(size + 2); + t = s; + x = w; + strcpy(x, name); + strcpy(x += strlen(name), "="); + strcpy(x += conststrlen("="), t->w); + for (x += strlen(t->w), s = s->n; s != NULL; s = s->n) { + memcpy(x, FSSTRING, step = conststrlen(FSSTRING)); + x += step; + memcpy(x, s->w, step = strlen(s->w)); + x += step; + } + *x = '\0'; + return w; +} + +/* convert a List to an array, for execve() */ + +extern char **list2array(List *s, bool print) { + char **av; + int i; + + /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */ + av = nalloc((listnel(s) + 4) * sizeof (char *)); + av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */ + if (print) + fprint(2, "%L\n", s, " "); + for (i = 0; s != NULL; i++) { + av[i] = s->w; + s = s->n; + } + av[i] = NULL; + return av; +} + +/* figure out the name of a variable given an environment string. copy this into malloc space */ + +extern char *get_name(char *s) { + int c; + SIZE_T i; + char *r, *namebuf; + for (i = 0; s[i] != '\0' && s[i] != '='; i++) + ; + if (s[i] == '\0') + return NULL; + r = namebuf = ealloc(i + 1); + while (1) + switch (c = *s++) { + case '=': + *r++ = '\0'; + return namebuf; +#ifdef PROTECT_ENV + case '_': + if (*s == '_') { + static const char hexchar[] = "0123456789abcdef"; + char *h1 = strchr(hexchar, s[1]); + char *h2 = strchr(hexchar, s[2]); + if (h1 != NULL && h2 != NULL) { + *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar); + s += 3; + break; + } + } + /* FALLTHROUGH */ +#endif + default: + *r++ = c; + break; + } +} + +/* get the next word from a variable's value as represented in the environment. */ + +static char *getenvw(char *s, bool saw_alpha) { + SIZE_T i; + char *r; + for (i = 0; s[i] != '\0' && s[i] != FSCHAR; i++) + ; + if (i == 0) { + if (s[i] == '\0' && !saw_alpha) + return NULL; + else + return clear(enew(char), (SIZE_T) 1); + } + r = strncpy(ealloc(i + 1), s, i); + r[i] = '\0'; + return r; +} + +/* take an environment entry for a variable (elements ^A separated) and turn it into a List */ + +extern List *parse_var(char *name, char *extdef) { + List *r, *top; + char *f; + bool saw_alpha; + top = r = enew(List); + extdef = strchr(extdef, '=') + 1; + if ((f = getenvw(extdef, FALSE)) == NULL) { + r->w = ""; + r->m = NULL; + r->n = NULL; + } else { + while (1) { + r->w = f; + r->m = NULL; + extdef += strlen(f); + if (*extdef == FSCHAR) { + extdef++; + saw_alpha = TRUE; + } else { + saw_alpha = FALSE; + } + if ((f = getenvw(extdef, saw_alpha)) == NULL) { + r->n = NULL; + break; + } + r = r->n = enew(List); + } + } + return top; +} + +/* get an environment entry for a function and have rc parse it. */ + +#define PREFIX "fn x" +#define PRELEN conststrlen(PREFIX) +extern Node *parse_fn(char *name, char *extdef) { + Node *def; + char *s, old[PRELEN]; + if ((s = strchr(extdef, '=')) == NULL) + return NULL; + memcpy(old, s -= (PRELEN-1), PRELEN); + memcpy(s, PREFIX, PRELEN); + def = parseline(s); + memcpy(s, old, PRELEN); + return (def == NULL || def->type != nNewfn) ? NULL : def->u[1].p; +} + +static bool Aconv(Format *f, int c) { + char **a = va_arg(f->args, char **); + if (*a != NULL) { + fmtcat(f, *a); + while (*++a != NULL) + fmtprint(f, " %s", *a); + } + return FALSE; +} + +static bool Lconv(Format *f, int c) { + List *l = va_arg(f->args, List *); + char *sep = va_arg(f->args, char *); + char *fmt = (f->flags & FMT_leftside) ? "%s%s" : "%-S%s"; + if (l == NULL && (f->flags & FMT_leftside) == 0) + fmtprint(f, "()"); + else { + List *s; + for (s = l; s != NULL; s = s->n) + fmtprint(f, fmt, s->w, s->n == NULL ? "" : sep); + } + return FALSE; +} + +#define ISMETA(c) (c == '*' || c == '?' || c == '[') + +static bool Sconv(Format *f, int ignore) { + int c; + unsigned char *s = va_arg(f->args, unsigned char *), *t = s; + bool quoted = (f->flags & FMT_altform) != 0; /* '#' */ + bool metaquote = (f->flags & FMT_leftside) != 0; /* '-' */ + if (*s == '\0') { + fmtprint(f, "''"); + return FALSE; + } + if (!quoted) { + while ((c = *t++) != '\0') + if (nw[c] == 1 || (metaquote && ISMETA(c))) + goto quoteit; + fmtprint(f, "%s", s); + return FALSE; + } +quoteit: + fmtputc(f, '\''); + while ((c = *s++) != '\0') { + fmtputc(f, c); + if (c == '\'') + fmtputc(f, '\''); + + } + fmtputc(f, '\''); + return FALSE; +} + +void initprint(void) { + fmtinstall('A', Aconv); + fmtinstall('L', Lconv); + fmtinstall('S', Sconv); + fmtinstall('T', Tconv); + fmtinstall('D', Dconv); +#ifdef PROTECT_ENV + fmtinstall('F', Fconv); +#else + fmtinstall('F', fmtinstall('s', NULL)); +#endif +} diff --git a/getopt.c b/getopt.c new file mode 100644 index 0000000..423b84a --- /dev/null +++ b/getopt.c @@ -0,0 +1,50 @@ +#include "rc.h" + +int rc_opterr = 1; +int rc_optind = 1; +int rc_optopt; +char *rc_optarg; + +/* getopt routine courtesy of David Sanderson */ + +extern int rc_getopt(int argc, char **argv, char *opts) { + static int sp = 1; + int c; + char *cp; + if (rc_optind == 0) /* reset rc_getopt() */ + rc_optind = sp = 1; + if (sp == 1) + if (rc_optind >= argc || argv[rc_optind][0] != '-' || argv[rc_optind][1] == '\0') { + return -1; + } else if (strcmp(argv[rc_optind], "--") == 0) { + rc_optind++; + return -1; + } + rc_optopt = c = argv[rc_optind][sp]; + if (c == ':' || (cp=strchr(opts, c)) == 0) { + fprint(2, "%s: bad option: -%c\n", argv[0], c); + if (argv[rc_optind][++sp] == '\0') { + rc_optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') { + if (argv[rc_optind][sp+1] != '\0') { + rc_optarg = &argv[rc_optind++][sp+1]; + } else if (++rc_optind >= argc) { + fprint(2, "%s: option requires an argument -- %c\n", argv[0], c); + sp = 1; + return '?'; + } else + rc_optarg = argv[rc_optind++]; + sp = 1; + } else { + if (argv[rc_optind][++sp] == '\0') { + sp = 1; + rc_optind++; + } + rc_optarg = NULL; + } + return c; +} diff --git a/glob.c b/glob.c new file mode 100644 index 0000000..1b0121b --- /dev/null +++ b/glob.c @@ -0,0 +1,240 @@ +/* glob.c: rc's (ugly) globber. This code is not elegant, but it works */ + +#include +#include +#include "rc.h" +#ifdef NODIRENT +#include +#define dirent direct /* need to get the struct declaraction right */ +#else +#include +#endif + +static List *dmatch(char *, char *, char *); +static List *doglob(char *, char *); +static List *lglob(List *, char *, char *, SIZE_T); +static List *sort(List *); + +/* + Matches a list of words s against a list of patterns p. Returns true iff + a pattern in p matches a word in s. () matches (), but otherwise null + patterns match nothing. +*/ + +extern bool lmatch(List *s, List *p) { + List *q; + int i; + bool okay; + if (s == NULL) { + if (p == NULL) /* null matches null */ + return TRUE; + for (; p != NULL; p = p->n) { /* one or more stars match null */ + if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */ + okay = TRUE; + for (i = 0; p->w[i] != '\0'; i++) + if (p->w[i] != '*' || p->m[i] != 1) { + okay = FALSE; + break; + } + if (okay) + return TRUE; + } + } + return FALSE; + } + for (; s != NULL; s = s->n) + for (q = p; q != NULL; q = q->n) + if (match(q->w, q->m, s->w)) + return TRUE; + return FALSE; +} + +/* + Globs a list; checks to see if each element in the list has a metacharacter. If it + does, it is globbed, and the output is sorted. +*/ + +extern List *glob(List *s) { + List *top, *r; + bool meta; + for (r = s, meta = FALSE; r != NULL; r = r->n) + if (r->m != NULL) + meta = TRUE; + if (!meta) + return s; /* don't copy lists with no metacharacters in them */ + for (top = r = NULL; s != NULL; s = s->n) { + if (s->m == NULL) { /* no metacharacters; just tack on to the return list */ + if (top == NULL) + top = r = nnew(List); + else + r = r->n = nnew(List); + r->w = s->w; + } else { + if (top == NULL) + top = r = sort(doglob(s->w, s->m)); + else + r->n = sort(doglob(s->w, s->m)); + while (r->n != NULL) + r = r->n; + } + } + r->n = NULL; + return top; +} + +/* Matches a pattern p against the contents of directory d */ + +static List *dmatch(char *d, char *p, char *m) { + bool matched = FALSE; + List *top, *r; + static DIR *dirp; + static struct dirent *dp; + static struct stat s; + /* prototypes for XXXdir functions. comment out if necessary */ + extern DIR *opendir(const char *); + extern struct dirent *readdir(DIR *); + /*extern int closedir(DIR *);*/ + + top = r = NULL; + /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */ + if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR || (dirp = opendir(d)) == NULL) + return NULL; + while ((dp = readdir(dirp)) != NULL) + if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */ + matched = TRUE; + if (top == NULL) + top = r = nnew(List); + else + r = r->n = nnew(List); + r->w = ncpy(dp->d_name); + r->m = NULL; + } + closedir(dirp); + if (!matched) + return NULL; + r->n = NULL; + return top; +} + +/* + lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*" + will return a list with all the files in /tmp, /usr, and /bin. NULL on no match. + slashcount indicates the number of slashes to stick between the directory and the + matched name. e.g., for matching ////tmp/////foo* +*/ + +static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) { + List *q, *r, *top, foo; + static List slash; + static SIZE_T slashsize = 0; + if (slashcount + 1 > slashsize) { + slash.w = ealloc(slashcount + 1); + slashsize = slashcount; + } + slash.w[slashcount] = '\0'; + while (slashcount > 0) + slash.w[--slashcount] = '/'; + for (top = r = NULL; s != NULL; s = s->n) { + q = dmatch(s->w, p, m); + if (q != NULL) { + foo.w = s->w; + foo.m = NULL; + foo.n = NULL; + if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */ + q = concat(&slash, q); /* dir/name with slash */ + q = concat(&foo, q); + if (r == NULL) + top = r = q; + else + r->n = q; + while (r->n != NULL) + r = r->n; + } + } + return top; +} + +/* + Doglob globs a pathname in pattern form against a unix path. Returns the original + pattern (cleaned of metacharacters) on failure, or the globbed string(s). +*/ + +static List *doglob(char *w, char *m) { + static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL; + static SIZE_T dsize = 0; + char *d, *p, *md, *mp; + SIZE_T psize; + char *s = w; + List firstdir; + List *matched; + if ((psize = strlen(w) + 1) > dsize || dir == NULL) { + efree(dir); efree(pattern); efree(metadir); efree(metapattern); + dir = ealloc(psize); + pattern = ealloc(psize); + metadir = ealloc(psize); + metapattern = ealloc(psize); + dsize = psize; + } + d = dir; + p = pattern; + md = metadir; + mp = metapattern; + if (*s == '/') + while (*s == '/') + *d++ = *s++, *md++ = *m++; + else + while (*s != '/' && *s != '\0') + *d++ = *s++, *md++ = *m++; /* get first directory component */ + *d = '\0'; + /* + Special case: no slashes in the pattern, i.e., open the current directory. + Remember that w cannot consist of slashes alone (the other way *s could be + zero) since doglob gets called iff there's a metacharacter to be matched + */ + if (*s == '\0') { + matched = dmatch(".", dir, metadir); + goto end; + } + if (*w == '/') { + firstdir.w = dir; + firstdir.m = metadir; + firstdir.n = NULL; + matched = &firstdir; + } else { + /* + we must glob against current directory, + since the first character is not a slash. + */ + matched = dmatch(".", dir, metadir); + } + do { + SIZE_T slashcount; + SIGCHK; + for (slashcount = 0; *s == '/'; s++, m++) + slashcount++; /* skip slashes */ + while (*s != '/' && *s != '\0') + *p++ = *s++, *mp++ = *m++; /* get pattern */ + *p = '\0'; + matched = lglob(matched, pattern, metapattern, slashcount); + p = pattern, mp = metapattern; + } while (*s != '\0'); +end: if (matched == NULL) { + matched = nnew(List); + matched->w = w; + matched->m = NULL; + matched->n = NULL; + } + return matched; +} + +static List *sort(List *s) { + SIZE_T nel = listnel(s); + if (nel > 1) { + char **a; + List *t; + qsort(a = list2array(s, FALSE), nel, sizeof(char *), starstrcmp); + for (t = s; t != NULL; t = t->n) + t->w = *a++; + } + return s; +} diff --git a/glom.c b/glom.c new file mode 100644 index 0000000..a82183c --- /dev/null +++ b/glom.c @@ -0,0 +1,420 @@ +/* glom.c: builds an argument list out of words, variables, etc. */ + +#include +#include +#include +#include "rc.h" +#if !defined(S_IFIFO) && !defined(DEVFD) +#define NOCMDARG +#endif + +static List *backq(Node *, Node *); +static List *bqinput(List *, int); +static List *count(List *); +static List *mkcmdarg(Node *); + +Rq *redirq = NULL; + +extern List *word(char *w, char *m) { + List *s = NULL; + if (w != NULL) { + s = nnew(List); + s->w = w; + s->m = m; + s->n = NULL; + } + return s; +} + +/* + Append list s2 to list s1 by copying s1 and making the new copy + point at s2. +*/ + +extern List *append(List *s1, List *s2) { + List *r, *top; + if (s1 == NULL) + return s2; + if (s2 == NULL) + return s1; + for (r = top = nnew(List); 1; r = r->n = nnew(List)) { + r->w = s1->w; + r->m = s1->m; + if ((s1 = s1->n) == NULL) + break; + } + r->n = s2; + return top; +} + +extern List *concat(List *s1, List *s2) { + int n1, n2; + List *r, *top; + if (s1 == NULL) + return s2; + if (s2 == NULL) + return s1; + if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1) + rc_error("bad concatenation"); + for (r = top = nnew(List); 1; r = r->n = nnew(List)) { + SIZE_T x = strlen(s1->w); + SIZE_T y = strlen(s2->w); + SIZE_T z = x + y + 1; + r->w = nalloc(z); + strcpy(r->w, s1->w); + strcat(r->w, s2->w); + if (s1->m == NULL && s2->m == NULL) { + r->m = NULL; + } else { + r->m = nalloc(z); + if (s1->m == NULL) + clear(r->m, x); + else + memcpy(r->m, s1->m, x); + if (s2->m == NULL) + clear(&r->m[x], y); + else + memcpy(&r->m[x], s2->m, y); + r->m[z] = 0; + } + if (n1 > 1) + s1 = s1->n; + if (n2 > 1) + s2 = s2->n; + if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1)) + break; + } + r->n = NULL; + return top; +} + +extern List *varsub(List *var, List *subs) { + List *r, *top; + int n = listnel(var); + for (top = r = NULL; subs != NULL; subs = subs->n) { + int i = a2u(subs->w); + if (i < 1) + rc_error("bad subscript"); + if (i <= n) { + List *sub = var; + while (--i) + sub = sub->n; /* loop until sub == var(i) */ + if (top == NULL) + top = r = nnew(List); + else + r = r->n = nnew(List); + r->w = sub->w; + r->m = sub->m; + } + } + if (top != NULL) + r->n = NULL; + return top; +} + +extern List *flatten(List *s) { + List *r; + SIZE_T step; + char *f; + if (s == NULL || s->n == NULL) + return s; + r = nnew(List); + f = r->w = nalloc(listlen(s) + 1); + r->m = NULL; /* flattened lists come from variables, so no meta */ + r->n = NULL; + strcpy(f, s->w); + f += strlen(s->w); + do { + *f++ = ' '; + s = s->n; + step = strlen(s->w); + memcpy(f, s->w, step); + f += step; + } while (s->n != NULL); + *f = '\0'; + return r; +} + +static List *count(List *l) { + List *s = nnew(List); + s->w = nprint("%d", listnel(l)); + s->n = NULL; + s->m = NULL; + return s; +} + +extern void assign(List *s1, List *s2, bool stack) { + List *val = s2; + if (s1 == NULL) + rc_error("null variable name"); + if (s1->n != NULL) + rc_error("multi-word variable name"); + if (*s1->w == '\0') + rc_error("zero-length variable name"); + if (a2u(s1->w) != -1) + rc_error("numeric variable name"); + if (strchr(s1->w, '=') != NULL) + rc_error("'=' in variable name"); + if (*s1->w == '*' && s1->w[1] == '\0') + val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */ + if (s2 != NULL || stack) { + if (dashex) + prettyprint_var(2, s1->w, val); + varassign(s1->w, val, stack); + alias(s1->w, varlookup(s1->w), stack); + } else { + if (dashex) + prettyprint_var(2, s1->w, NULL); + varrm(s1->w, stack); + } +} + +/* + The following two functions are by the courtesy of Paul Haahr, + who could not stand the incompetence of my own backquote implementation. +*/ + +#define BUFSIZE ((SIZE_T) 1000) + +static List *bqinput(List *ifs, int fd) { + char *end, *bufend, *s; + List *r, *top, *prev; + SIZE_T remain, bufsize; + char isifs[256]; + int n, state; /* a simple FSA is used to read in data */ + + clear(isifs, sizeof isifs); + for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n) + for (s = ifs->w; *s != '\0'; s++) + isifs[*(unsigned char *)s] = TRUE; + remain = bufsize = BUFSIZE; + top = r = nnew(List); + r->w = end = nalloc(bufsize + 1); + r->m = NULL; + state = 0; + prev = NULL; + + while (1) { + if (remain == 0) { /* is the string bigger than the buffer? */ + SIZE_T m = end - r->w; + char *buf; + while (bufsize < m + BUFSIZE) + bufsize *= 2; + buf = nalloc(bufsize + 1); + memcpy(buf, r->w, m); + r->w = buf; + end = &buf[m]; + remain = bufsize - m; + } + if ((n = rc_read(fd, end, remain)) <= 0) { + if (n == 0) + /* break */ break; + uerror("backquote read"); + rc_error(NULL); + } + remain -= n; + for (bufend = &end[n]; end < bufend; end++) + if (state == 0) { + if (!isifs[*(unsigned char *)end]) { + state = 1; + r->w = end; + } + } else { + if (isifs[*(unsigned char *)end]) { + state = 0; + *end = '\0'; + prev = r; + r = r->n = nnew(List); + r->w = end+1; + r->m = NULL; + } + } + } + if (state == 1) { /* terminate last string */ + *end = '\0'; + r->n = NULL; + } else { + if (prev == NULL) /* no input at all? */ + top = NULL; + else + prev->n = NULL; /* else terminate list */ + } + return top; +} + +static List *backq(Node *ifs, Node *n) { + int p[2], pid, sp; + List *bq; + if (n == NULL) + return NULL; + if (pipe(p) < 0) { + uerror("pipe"); + rc_error(NULL); + } + if ((pid = rc_fork()) == 0) { + setsigdefaults(FALSE); + mvfd(p[1], 1); + close(p[0]); + redirq = NULL; + walk(n, FALSE); + exit(getstatus()); + } + close(p[1]); + bq = bqinput(glom(ifs), p[0]); + close(p[0]); + rc_wait4(pid, &sp, TRUE); + statprint(-1, sp); + SIGCHK; + return bq; +} + +extern void qredir(Node *n) { + Rq *next; + if (redirq == NULL) { + next = redirq = nnew(Rq); + } else { + for (next = redirq; next->n != NULL; next = next->n) + ; + next->n = nnew(Rq); + next = next->n; + } + next->r = n; + next->n = NULL; +} + +#ifdef NOCMDARG +static List *mkcmdarg(Node *n) { + rc_error("named pipes are not supported"); + return NULL; +} +#else +#ifndef DEVFD +static List *mkcmdarg(Node *n) { + int fd; + char *name; + Edata efifo; + Estack *e = enew(Estack); + List *ret = nnew(List); + static int fifonumber = 0; + name = nprint("%s/rc%d.%d", TMPDIR, getpid(), fifonumber++); + if (mknod(name, S_IFIFO | 0666, 0) < 0) { + uerror("mknod"); + return NULL; + } + if (rc_fork() == 0) { + setsigdefaults(FALSE); + fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */ + if (fd < 0) { + uerror("open"); + exit(1); + } + if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */ + exit(1); + redirq = NULL; + walk(n->u[2].p, FALSE); + exit(getstatus()); + } + efifo.name = name; + except(eFifo, efifo, e); + ret->w = name; + ret->m = NULL; + ret->n = NULL; + return ret; +} +#else +static List *mkcmdarg(Node *n) { + char *name; + List *ret = nnew(List); + Estack *e = nnew(Estack); + Edata efd; + int p[2]; + if (pipe(p) < 0) { + uerror("pipe"); + return NULL; + } + if (rc_fork() == 0) { + setsigdefaults(FALSE); + if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */ + exit(1); + close(p[n->u[0].i != rFrom]); + redirq = NULL; + walk(n->u[2].p, FALSE); + exit(getstatus()); + } + name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]); + efd.fd = p[n->u[0].i != rFrom]; + except(eFd, efd, e); + close(p[n->u[0].i == rFrom]); + ret->w = name; + ret->m = NULL; + ret->n = NULL; + return ret; +} +#endif /* DEVFD */ +#endif /* !NOCMDARG */ + +extern List *glom(Node *n) { + List *v, *head, *tail; + Node *words; + if (n == NULL) + return NULL; + switch (n->type) { + case nArgs: + case nLappend: + words = n->u[0].p; + tail = NULL; + while (words != NULL && (words->type == nArgs || words->type == nLappend)) { + if (words->u[1].p != NULL && words->u[1].p->type != nWord && words->u[1].p->type != nQword) + break; + head = glom(words->u[1].p); + if (head != NULL) { + head->n = tail; + tail = head; + } + words = words->u[0].p; + } + v = append(glom(words), tail); /* force left to right evaluation */ + return append(v, glom(n->u[1].p)); + case nBackq: + return backq(n->u[0].p, n->u[1].p); + case nConcat: + head = glom(n->u[0].p); /* force left-to-right evaluation */ + return concat(head, glom(n->u[1].p)); + case nDup: + case nRedir: + qredir(n); + return NULL; + case nWord: + case nQword: + return word(n->u[0].s, n->u[1].s); + case nNmpipe: + return mkcmdarg(n); + default: + /* + The next four operations depend on the left-child of glom + to be a variable name. Therefore the variable is looked up + here. + */ + if ((v = glom(n->u[0].p)) == NULL) + rc_error("null variable name"); + if (v->n != NULL) + rc_error("multi-word variable name"); + if (*v->w == '\0') + rc_error("zero-length variable name"); + v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w); + switch (n->type) { + default: + panic("unexpected node in glom"); + exit(1); + /* NOTREACHED */ + case nCount: + return count(v); + case nFlat: + return flatten(v); + case nVar: + return v; + case nVarsub: + return varsub(v, glom(n->u[1].p)); + } + } +} diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..9397218 --- /dev/null +++ b/hash.c @@ -0,0 +1,302 @@ +/* hash.c: hash table support for functions and variables. */ + +/* + Functions and variables are cached in both internal and external + form for performance. Thus a variable which is never "dereferenced" + with a $ is passed on to rc's children untouched. This is not so + important for variables, but is a big win for functions, where a call + to yyparse() is involved. +*/ + +#include "rc.h" +#include "sigmsgs.h" + +static bool var_exportable(char *); +static bool fn_exportable(char *); +static int hash(char *, int); +static int find(char *, Htab *, int); +static void free_fn(Function *); + +Htab *fp; +Htab *vp; +static int fused, fsize, vused, vsize; +static char **env; +static int bozosize; +static int envsize; +static bool env_dirty = TRUE; +static char *dead = ""; + +#define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */ + +extern void inithash() { + Htab *fpp, *vpp; + int i; + fp = ealloc(sizeof(Htab) * HASHSIZE); + vp = ealloc(sizeof(Htab) * HASHSIZE); + fused = vused = 0; + fsize = vsize = HASHSIZE; + for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++) + vpp->name = fpp->name = NULL; +} + +#define ADV() {if ((c = *s++) == '\0') break;} + +/* hash function courtesy of paul haahr */ + +static int hash(char *s, int size) { + int c, n = 0; + while (1) { + ADV(); + n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1); + ADV(); + n ^= (c << 14) + (c << 7) + (c << 4) + c; + ADV(); + n ^= (~c << 11) | ((c << 3) ^ (c >> 1)); + ADV(); + n -= (c << 16) | (c << 9) | (c << 2) | (c & 3); + } + if (n < 0) + n = ~n; + return n & (size - 1); /* need power of 2 size */ +} + +static bool rehash(Htab *ht) { + int i, j, size; + int newsize, newused; + Htab *newhtab; + if (ht == fp) { + if (fsize > 2 * fused) + return FALSE; + size = fsize; + } else { + if (vsize > 2 * vused) + return FALSE; + size = vsize; + } + newsize = 2 * size; + newhtab = ealloc(newsize * sizeof(Htab)); + for (i = 0; i < newsize; i++) + newhtab[i].name = NULL; + for (i = newused = 0; i < size; i++) + if (ht[i].name != NULL && ht[i].name != dead) { + newused++; + j = hash(ht[i].name, newsize); + while (newhtab[j].name != NULL) { + j++; + j &= (newsize - 1); + } + newhtab[j].name = ht[i].name; + newhtab[j].p = ht[i].p; + } + if (ht == fp) { + fused = newused; + fp = newhtab; + fsize = newsize; + } else { + vused = newused; + vp = newhtab; + vsize = newsize; + } + efree(ht); + return TRUE; +} + +#define varfind(s) find(s, vp, vsize) +#define fnfind(s) find(s, fp, fsize) + +static int find(char *s, Htab *ht, int size) { + int h = hash(s, size); + while (ht[h].name != NULL && !streq(ht[h].name, s)) { + h++; + h &= size - 1; + } + return h; +} + +extern void *lookup(char *s, Htab *ht) { + int h = find(s, ht, ht == fp ? fsize : vsize); + return (ht[h].name == NULL) ? NULL : ht[h].p; +} + +extern Function *get_fn_place(char *s) { + int h = fnfind(s); + env_dirty = TRUE; + if (fp[h].name == NULL) { + if (rehash(fp)) + h = fnfind(s); + fused++; + fp[h].name = ecpy(s); + fp[h].p = enew(Function); + } else + free_fn(fp[h].p); + return fp[h].p; +} + +extern Variable *get_var_place(char *s, bool stack) { + Variable *new; + int h = varfind(s); + + env_dirty = TRUE; + + if (vp[h].name == NULL) { + if (rehash(vp)) + h = varfind(s); + vused++; + vp[h].name = ecpy(s); + vp[h].p = enew(Variable); + ((Variable *)vp[h].p)->n = NULL; + return vp[h].p; + } else { + if (stack) { /* increase the stack by 1 */ + new = enew(Variable); + new->n = vp[h].p; + return vp[h].p = new; + } else { /* trample the top of the stack */ + new = vp[h].p; + efree(new->extdef); + listfree(new->def); + return new; + } + } +} + +extern void delete_fn(char *s) { + int h = fnfind(s); + if (fp[h].name == NULL) + return; /* not found */ + env_dirty = TRUE; + free_fn(fp[h].p); + efree(fp[h].p); + efree(fp[h].name); + if (fp[(h+1)&(fsize-1)].name == NULL) { + --fused; + fp[h].name = NULL; + } else { + fp[h].name = dead; + } +} + +extern void delete_var(char *s, bool stack) { + int h = varfind(s); + Variable *v; + if (vp[h].name == NULL) + return; /* not found */ + env_dirty = TRUE; + v = vp[h].p; + efree(v->extdef); + listfree(v->def); + if (v->n != NULL) { /* This is the top of a stack */ + if (stack) { /* pop */ + vp[h].p = v->n; + efree(v); + } else { /* else just empty */ + v->extdef = NULL; + v->def = NULL; + } + } else { /* needs to be removed from the hash table */ + efree(v); + efree(vp[h].name); + if (vp[(h+1)&(vsize-1)].name == NULL) { + --vused; + vp[h].name = NULL; + } else { + vp[h].name = dead; + } + } +} + +static void free_fn(Function *f) { + treefree(f->def); + efree(f->extdef); +} + +extern void initenv(char **envp) { + int n; + for (n = 0; envp[n] != NULL; n++) + ; + n++; /* one for the null terminator */ + if (n < HASHSIZE) + n = HASHSIZE; + env = ealloc((envsize = 2 * n) * sizeof (char *)); + for (; *envp != NULL; envp++) + if (strncmp(*envp, "fn_", conststrlen("fn_")) == 0) { + if (!dashpee) + fnassign_string(*envp); + } else { + if (!varassign_string(*envp)) /* add to bozo env */ + env[bozosize++] = *envp; + } +} + +static bool var_exportable(char *s) { + static char *notforexport[] = { + "apid", "pid", "apids", "*", "ifs" + }; + int i; + for (i = 0; i < arraysize(notforexport); i++) + if (streq(s, notforexport[i])) + return FALSE; + return TRUE; +} + +static bool fn_exportable(char *s) { + int i; + if (strncmp(s, "sig", conststrlen("sig")) == 0) { /* small speed hack */ + for (i = 0; i < NUMOFSIGNALS; i++) + if (streq(s, signals[i].name)) + return FALSE; + if (streq(s, "sigexit")) + return FALSE; + } + return TRUE; +} + +extern char **makeenv() { + int ep, i; + char *v; + if (!env_dirty) + return env; + env_dirty = FALSE; + ep = bozosize; + if (vsize + fsize + 1 + bozosize > envsize) { + envsize = 2 * (bozosize + vsize + fsize + 1); + env = erealloc(env, envsize * sizeof(char *)); + } + for (i = 0; i < vsize; i++) { + if (vp[i].name == NULL || vp[i].name == dead || !var_exportable(vp[i].name)) + continue; + v = varlookup_string(vp[i].name); + if (v != NULL) + env[ep++] = v; + } + for (i = 0; i < fsize; i++) { + if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name)) + continue; + env[ep++] = fnlookup_string(fp[i].name); + } + env[ep] = NULL; + qsort(env, (SIZE_T) ep, sizeof(char *), starstrcmp); + return env; +} + +extern void whatare_all_vars() { + int i; + List *s; + for (i = 0; i < vsize; i++) + if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL) + prettyprint_var(1, vp[i].name, s); + for (i = 0; i < fsize; i++) + if (fp[i].name != NULL && fp[i].name != dead) + prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name)); +} + +/* fake getenv() for readline() follows: */ + +#ifdef READLINE +extern char *getenv(const char *name) { + List *s; + if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL) + return NULL; + return s->w; +} +#endif diff --git a/heredoc.c b/heredoc.c new file mode 100644 index 0000000..3930d9e --- /dev/null +++ b/heredoc.c @@ -0,0 +1,156 @@ +/* heredoc.c: heredoc slurping is done here */ + +#include "rc.h" + +struct Hq { + Node *doc; + char *name; + Hq *n; + bool quoted; +} *hq; + +static bool dead = FALSE; + +/* + * read in a heredocument. A clever trick: skip over any partially matched end-of-file + * marker storing only the number of characters matched. If the whole marker is matched, + * return from readheredoc(). If only part of the marker is matched, copy that part into + * the heredocument. + * + * BUG: if the eof string contains a newline, the state can get confused, and the + * heredoc may continue past where it should. on the other hand, /bin/sh seems to + * never get out of its readheredoc() when the heredoc string contains a newline + */ + +static char *readheredoc(char *eof) { + int c; + char *t, *buf, *bufend; + unsigned char *s; + SIZE_T bufsize; + t = buf = nalloc(bufsize = 512); + bufend = &buf[bufsize]; + dead = FALSE; +#define RESIZE(extra) { \ + char *nbuf; \ + bufsize = bufsize * 2 + extra; \ + nbuf = nalloc(bufsize); \ + memcpy(nbuf, buf, (SIZE_T) (t - buf)); \ + t = nbuf + (t - buf); \ + buf = nbuf; \ + bufend = &buf[bufsize]; \ + } + for (;;) { + print_prompt2(); + for (s = (unsigned char *) eof; (c = gchar()) == *s; s++) + ; + if (*s == '\0' && (c == '\n' || c == EOF)) { + *t++ = '\0'; + return buf; + } + if (s != (unsigned char *) eof) { + SIZE_T len = s - (unsigned char *) eof; + if (t + len >= bufend) + RESIZE(len); + memcpy(t, eof, len); + t += len; + } + for (;; c = gchar()) { + if (c == EOF) { + yyerror("heredoc incomplete"); + dead = TRUE; + return NULL; + } + if (t + 1 >= bufend) + RESIZE(0); + *t++ = c; + if (c == '\n') + break; + } + } +} + +/* parseheredoc -- turn a heredoc with variable references into a node chain */ + +static Node *parseheredoc(char *s) { + int c = *s; + Node *result = NULL; + while (TRUE) { + Node *node; + switch (c) { + default: { + char *begin = s; + while ((c = *s++) != '\0' && c != '$') + ; + *--s = '\0'; + node = mk(nQword, begin, NULL); + break; + } + case '$': { + char *begin = ++s, *var; + c = *s++; + if (c == '$') { + node = mk(nQword, "$", NULL); + c = *s; + } else { + SIZE_T len = 0; + do + len++; + while (!dnw[c = *(unsigned char *) s++]); + if (c == '^') + c = *s; + else + s--; + var = nalloc(len + 1); + var[len] = '\0'; + memcpy(var, begin, len); + node = mk(nFlat, mk(nWord, var, NULL)); + } + break; + } + case '\0': + return result; + } + result = (result == NULL) ? node : mk(nConcat, result, node); + } +} + +/* read in heredocs when yyparse hits a newline. called from yyparse */ + +extern int heredoc(int end) { + Hq *here; + if ((here = hq) != NULL) { + hq = NULL; + if (end) { + yyerror("heredoc incomplete"); + return FALSE; + } + do { + Node *n = here->doc; + char *s = readheredoc(here->name); + if (dead) + return FALSE; + n->u[2].p = here->quoted ? mk(nQword, s, NULL) : parseheredoc(s); + n->u[0].i = rHerestring; + } while ((here = here->n) != NULL); + } + return TRUE; +} + +/* queue pending heredocs into a queue. called from yyparse */ + +extern int qdoc(Node *name, Node *n) { + Hq *new, **prev; + if (name->type != nWord && name->type != nQword) { + yyerror("eof-marker not a single literal word"); + flushu(); + return FALSE; + } + for (prev = &hq; (new = *prev) != NULL; prev = &new->n) + ; + *prev = new = nnew(Hq); + new->name = name->u[0].s; + new->quoted = (name->type == nQword); + new->doc = n; + new->n = NULL; + return TRUE; +} diff --git a/history/Makefile b/history/Makefile new file mode 100644 index 0000000..4655947 --- /dev/null +++ b/history/Makefile @@ -0,0 +1,6 @@ +CC=gcc -g -O + +history: history.c + $(CC) -o history history.c + @echo 'Now install "history" as -, --, -p and --p in your bin directory' + @echo '(for example, by making them links to the same file)' diff --git a/history/history.1 b/history/history.1 new file mode 100644 index 0000000..18ed28f --- /dev/null +++ b/history/history.1 @@ -0,0 +1,234 @@ +.\" history.1 +.\"------- +.\" See rc.1 for man page portability notes. +.\"------- +.\" Dd distance to space vertically before a "display" +.\" These are what n/troff use for interparagraph distance +.\"------- +.if t .nr Dd .4v +.if n .nr Dd 1v +.\"------- +.\" Ds begin a display, indented .5 inches from the surrounding text. +.\" +.\" Note that uses of Ds and De may NOT be nested. +.\"------- +.de Ds +.\" .RS \\$1 +.sp \\n(Ddu +.in +0.5i +.nf +.. +.\"------- +.\" De end a display (no trailing vertical spacing) +.\"------- +.de De +.fi +.in +.\" .RE +.. +.\"------- +.\" I stole the Xf macro from the -man macros on my machine (originally +.\" "}S", I renamed it so that it won't conflict). +.\"------- +.\" Set Cf to the name of the constant width font. +.\" It will be "C" or "(CW", typically. +.\" NOTEZ BIEN the lines defining Cf must have no trailing white space: +.\"------- +.if t .ds Cf C +.if n .ds Cf R +.\"------- +.\" Rc - Alternate Roman and Courier +.\"------- +.de Rc +.Xf R \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Ic - Alternate Italic and Courier +.\"------- +.de Ic +.Xf I \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Bc - Alternate Bold and Courier +.\"------- +.de Bc +.Xf B \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Cr - Alternate Courier and Roman +.\"------- +.de Cr +.Xf \\*(Cf R \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Ci - Alternate Courier and Italic +.\"------- +.de Ci +.Xf \\*(Cf I \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Cb - Alternate Courier and Bold +.\"------- +.de Cb +.Xf \\*(Cf B \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Xf - Alternate fonts +.\" +.\" \$1 - first font +.\" \$2 - second font +.\" \$3 - desired word with embedded font changes, built up by recursion +.\" \$4 - text for first font +.\" \$5 - \$9 - remaining args +.\" +.\" Every time we are called: +.\" +.\" If there is something in \$4 +.\" then Call ourself with the fonts switched, +.\" with a new word made of the current word (\$3) and \$4 +.\" rendered in the first font, +.\" and with the remaining args following \$4. +.\" else We are done recursing. \$3 holds the desired output +.\" word. We emit \$3, change to Roman font, and restore +.\" the point size to the default. +.\" fi +.\" +.\" Use Xi to add a little bit of space after italic text. +.\"------- +.de Xf +.ds Xi +.\"------- +.\" I used to test for the italic font both by its font position +.\" and its name. Now just test by its name. +.\" +.\" .if "\\$1"2" .if !"\\$5"" .ds Xi \^ +.\"------- +.if "\\$1"I" .if !"\\$5"" .ds Xi \^ +.\"------- +.\" This is my original code to deal with the recursion. +.\" Evidently some nroffs can't deal with it. +.\"------- +.\" .ie !"\\$4"" \{\ +.\" . Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" +.\" .\} +.\" .el \{\\$3 +.\" . ft R \" Restore the default font, since we don't know +.\" . \" what the last font change was. +.\" . ps 10 \" Restore the default point size, since it might +.\" . \" have been changed by an argument to this macro. +.\" .\} +.\"------- +.\" Here is more portable (though less pretty) code to deal with +.\" the recursion. +.\"------- +.if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" +.if "\\$4"" \\$3\fR\s10 +.. +.TH HISTORY 1 "30 July 1991" +.SH NAME +\-, \-\|\-, \-p, \-\|\-p \- shell history programs +.SH SYNOPSIS +.B \- +.RI [ pattern ...] +.RI [ substitution ...] +.SH DESCRIPTION +This set of programs provides a crude history mechanism for the shell +.IR rc (1). +It is based on the v8 UNIX programs +.IR = , +.IR == , +etc. +.PP +The program +.RI `` \- '' +runs the shell on the command it is requested to find. +The program +.RI `` \-\|\- '' +edits that command first. +The programs +.RI `` \-p '' +and +.RI `` \-\|\-p '' +are similar, except that they print the final command on their standard +output instead of running the shell. +.PP +The commands work by looking for a file +named by the environment variable +.Cr $history , +and by searching for previous commands in this file. +Old commands can be edited, +or simply re-executed according to the rules below: +.PP +A command is searched for by examining the lines in +.Cr $history +in reverse order. +Lines which contain a previous invocation of the history +program itself are ignored. +If one or more +.I pattern +is supplied on the command line, +then the patterns are used as a means of +limiting the search. +Patterns match any substring of a previous command, +and if more than one pattern is present then all patterns must be +matched before a command is selected. +.PP +Substitutions may also be specified on the command line. +These have the syntax: +.Ds +.Ic old : new +.De +.PP +(Note that the +.I old +pattern is used as a search-limiting pattern also.) +Substitutions happen on the first match. +.PP +Finally, a command may be edited in a crude line-mode fashion: +The line to be edited is printed out, and below it the user +supplies modifications to the command: +.TP +.B any character +Replaces the character above. +.TP +.B space or tab +Skips over the above character(s). +.TP +.B # +Deletes one character. +.TP +.B % +Replaces one character with a space. +.TP +.B ^ +Inserts the rest of the typed line just before the character. +.TP +.B $ +Deletes the rest of the line from that character on, and replaces +it with the rest of the typed line. +.TP +.B + +Appends the rest of the typed line. +.TP +.B \- +Backs up to a previous command satisfying the same matching +constraints. +.TP +.B end of file +If an end-of-file is read from the keyboard by the editor, +it aborts with exit status 1 and does not produce any output. +.SH EXAMPLES +The history programs work best when their output is reinterpreted by +the shell using an +.Cr eval +command. +This can be achieved by writing a shell function to perform the +reinterpretation: +.Ds +.Cr "fn - -- {" +.Cr " comm = \`{$0^p $*}" +.Cr " if (! ~ $#comm 0) {" +.Cr " echo $comm >[1=2]" +.Cr " eval $comm" +.Cr " }" +.Cr "}" diff --git a/history/history.c b/history/history.c new file mode 100644 index 0000000..5f2cece --- /dev/null +++ b/history/history.c @@ -0,0 +1,333 @@ +/* + history.c -- primitive history mechanism + + Paul Haahr & Byron Rakitzis, July 1991. + + This program mimics the att v8 = and == history programs. + The edit() algorithm was adapted from a similar program + that Boyd Roberts wrote, but otherwise all the code has + been written from scratch. + + edit() was subsequently redone by Hugh Redelmeier in order + to correctly deal with tab characters in the source line. + + BUGS: + There is an implicit assumption that commands are no + more than 1k characters long. +*/ + +#include +#include +#include + +static char *id = "@(#) history.c 8/91"; + +#undef FALSE +#undef TRUE +typedef enum { FALSE, TRUE } bool; + +#define CHUNKSIZE 65536 + +static struct { + char *old, *new; +} *replace; + +static char **search, *progname, *history; +static char me; /* typically ':' or '-' */ +static bool editit = FALSE, printit = FALSE; +static int nreplace = 0, nsearch = 0; +static FILE *fp; + +static void *ealloc(size_t n) { + void *p = (void *) malloc(n); + if (p == NULL) { + perror("malloc"); + exit(1); + } + return p; +} + +static void *erealloc(void *p, size_t n) { + p = (void *) realloc(p, n); + if (p == NULL) { + perror("realloc"); + exit(1); + } + return p; +} + +static char *newstr() { + return ealloc((size_t)1024); +} + +static char *basename(char *s) { + char *t = strrchr(s, '/'); + return (t == NULL) ? s : t + 1; +} + +/* stupid O(n^2) substring matching routine */ + +static char *isin(char *target, char *pattern) { + size_t plen = strlen(pattern); + size_t tlen = strlen(target); + for (; tlen >= plen; target++, --tlen) + if (strncmp(target, pattern, plen) == 0) + return target; + return NULL; +} + +/* replace the first match in the string with "new" */ +static char *sub(char *s, char *old, char *new) { + char *t, *u; + + t = isin(s, old); + u = newstr(); + + *t = '\0'; + while (*old != '\0') + old++, t++; + strcpy(u, s); + strcat(u, new); + strcat(u, t); + return u; +} + +static char *edit(char *s) { + char *final, *f, *end; + int col; + bool ins; + +start: + fprintf(stderr, "%s\n", s); + f = final = newstr(); + end = s + strlen(s); + col = 0; + ins = FALSE; + + for (;; col++) { + int c = getchar(); + + if (c == me && col == 0) { + int peekc = getchar(); + if (peekc == '\n') + return NULL; + ungetc(peekc, stdin); + } + if (c == '\n') { + if (col == 0) + return s; + + while (s < end) /* copy remainder of string */ + *f++ = *s++; + *f = '\0'; + s = final; + goto start; + } else if (ins || s>=end) { + /* col need not be accurate -- tabs need not be interpreted */ + *f++ = c; + } else { + switch (c) { + case '+': + while (s < end) + *f++ = *s++; + *f = '\0'; + continue; + case '%': + c = ' '; + /* FALLTHROUGH */ + default: + *f++ = c; + break; + case EOF: + exit(1); + /* NOTREACHED */ + case ' ': + if (*s == '\t') { + int oldcol = col; + + for (;; col++) { + int peekc; + + if ((col&07) == 07) { + *f++ = '\t'; /* we spaced past a tab */ + break; + } + peekc = getchar(); + if (peekc != ' ') { + ungetc(peekc, stdin); + if (peekc != '\n') { + /* we spaced partially into a tab */ + do { + *f++ = ' '; + oldcol++; + } while (oldcol <= col); + } + break; + } + } + } else { + *f++ = *s; + } + break; + case '#': + break; + case '$': + end = s; /* truncate s */ + continue; /* skip incrementing s */ + case '^': + ins = TRUE; + continue; /* skip incrementing s */ + case '\t': + for (;; col++) { + if ((*f++ = s 0) { + count += nread; + if (size - count == 0) + buf = erealloc(buf, size *= 4); + } + if (nread == -1) { + perror(history); + exit(1); + } + *last = buf + count; + return buf; +} + +static char *getcommand() { + char *s, *t; + static char *hist = NULL, *last; + + if (hist == NULL) { + hist = readhistoryfile(&last); + *--last = '\0'; /* trim final newline */ + } + +again: s = last; + if (s < hist) + return NULL; + while (*--s != '\n') + if (s <= hist) { + last = hist - 1; + return hist; + } + *s = '\0'; + last = s++; + + /* + * if the command contains the "me" character at the start of the line + * or after any of [`{|()] then try again + */ + + for (t = s; *t != '\0'; t++) + if (*t == me) { + char *u = t - 1; + while (u >= s && (*u == ' ' || *u == '\t')) + --u; + if (u < s || *u == '`' || *u == '{' || *u == '|' || *u == '(' || *u == ')') + goto again; + } + return s; +} + +int main(int argc, char **argv) { + int i; + char *s; + + s = progname = basename(argv[0]); + me = *s++; + if (*s == me) { + s++; + editit = TRUE; + } + if (*s == 'p') { + s++; + printit = TRUE; + } +/* Nahh... + if (*s != '\0') { + fprintf(stderr, "\"%s\": bad name for history program\n", progname); + exit(1); + } +*/ + + if (argc > 1) { + replace = ealloc((argc - 1) * sizeof *replace); + search = ealloc((argc - 1) * sizeof *search); + } + for (i = 1; i < argc; i++) + if ((s = strchr(argv[i], ':')) == NULL) + search[nsearch++] = argv[i]; + else { + *(char *)s = '\0'; /* do we confuse ps too much? */ + replace[nreplace].old = argv[i]; + replace[nreplace].new = s + 1; + nreplace++; + } + +next: s = getcommand(); + if (s == NULL) { + fprintf(stderr, "command not matched\n"); + return 1; + } + for (i = 0; i < nsearch; i++) + if (!isin(s, search[i])) + goto next; + for (i = 0; i < nreplace; i++) + if (!isin(s, replace[i].old)) + goto next; + else + s = sub(s, replace[i].old, replace[i].new); + if (editit) { + s = edit(s); + if (s == NULL) + goto next; + } + fseek(fp, 0, 2); /* 2 == end of file. i.e., append command to $history */ + fprintf(fp, "%s\n", s); + fclose(fp); + if (printit) + printf("%s\n", s); + else { + char *shell = getenv("SHELL"); + + if (!editit) + fprintf(stderr, "%s\n", s); + if (shell == NULL) + shell = "/bin/sh"; + execl(shell, basename(shell), "-c", s, NULL); + perror(shell); + exit(1); + } + return 0; +} diff --git a/input.c b/input.c new file mode 100644 index 0000000..9018a54 --- /dev/null +++ b/input.c @@ -0,0 +1,373 @@ +/* input.c: i/o routines for files and pseudo-files (strings) */ + +#include +#include +#include "rc.h" +#include "jbwrap.h" + +/* + NB: character unget is supported for up to two characters, but NOT + in the case of EOF. Since EOF does not fit in a char, it is easiest + to support only one unget of EOF. +*/ + +typedef struct Input { + inputtype t; + char *ibuf; + int fd, index, read, lineno, last; + bool saved, eofread; +} Input; + +#define BUFSIZE ((SIZE_T) 256) + +#ifdef READLINE +extern char *readline(char *); +extern void add_history(char *); +static char *rlinebuf; +#endif + +char *prompt, *prompt2; +bool rcrc; + +static int dead(void); +static int fdgchar(void); +static int stringgchar(void); +static void history(void); +static void ugdead(int); +static void pushcommon(void); + +static char *inbuf; +static SIZE_T istacksize, chars_out, chars_in; +static bool eofread = FALSE, save_lineno = TRUE; +static Input *istack, *itop; +static char *histstr; +static int histfd; + +static int (*realgchar)(void); +static void (*realugchar)(int); + +int last; + +extern int gchar() { + if (eofread) { + eofread = FALSE; + return last = EOF; + } + return (*realgchar)(); +} + +extern void ugchar(int c) { + (*realugchar)(c); +} + +static int dead() { + return last = EOF; +} + +static void ugdead(int c) { + return; +} + +static void ugalive(int c) { + if (c == EOF) + eofread = TRUE; + else + inbuf[--chars_out] = c; +} + +/* get the next character from a string. */ + +static int stringgchar() { + return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); +} + +/* signal-safe readline wrapper */ + +#ifdef READLINE +#ifndef SVSIGS +static char *rc_readline(char *prompt) { + char *r; + interrupt_happened = FALSE; + if (!setjmp(slowbuf.j)) { + slow = TRUE; + if (!interrupt_happened) + r = readline(prompt); + else + r = NULL; + } else + r = NULL; + slow = FALSE; + if (r == NULL) + errno = EINTR; + SIGCHK; + return r; +} +#else +#define rc_readline readline +#endif /* SVSIGS */ +#endif /* READLINE */ + +/* + read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor + the buffer to look like a regular fdgchar buffer. +*/ + +static int fdgchar() { + if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */ + while (1) { +#ifdef READLINE + if (interactive && istack->fd == 0) { + rlinebuf = readline(prompt); + if (rlinebuf == NULL) { + chars_in = 0; + } else { + if (*rlinebuf != '\0') + add_history(rlinebuf); + chars_in = strlen(rlinebuf) + 1; + efree(inbuf); + inbuf = ealloc(chars_in + 3); + strcpy(inbuf+2, rlinebuf); + strcat(inbuf+2, "\n"); + } + } else +#endif + { + long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE); + if (r < 0) { + if (errno == EINTR) + continue; /* Suppose it was interrupted by a signal */ + uerror("read"); + rc_exit(1); + } + chars_in = (SIZE_T) r; + } + break; + } + if (chars_in == 0) + return last = EOF; + chars_out = 2; + if (dashvee) + writeall(2, inbuf + 2, chars_in); + history(); + } + return last = inbuf[chars_out++]; +} + +/* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */ + +extern void initinput() { + istack = itop = ealloc(istacksize = 256 * sizeof (Input)); + istack->t = iFd; + istack->fd = -1; + realugchar = ugalive; +} + +/* push an input source onto the stack. set up a new input buffer, and set gchar() */ + +static void pushcommon() { + SIZE_T idiff; + istack->index = chars_out; + istack->read = chars_in; + istack->ibuf = inbuf; + istack->lineno = lineno; + istack->saved = save_lineno; + istack->last = last; + istack->eofread = eofread; + istack++; + idiff = istack - itop; + if (idiff >= istacksize / sizeof (Input)) { + itop = erealloc(itop, istacksize *= 2); + istack = itop + idiff; + } + realugchar = ugalive; + chars_out = 2; + chars_in = 0; +} + +extern void pushfd(int fd) { + pushcommon(); + istack->t = iFd; + save_lineno = TRUE; + istack->fd = fd; + realgchar = fdgchar; + inbuf = ealloc(BUFSIZE + 2); + lineno = 1; +} + +extern void pushstring(char **a, bool save) { + pushcommon(); + istack->t = iString; + save_lineno = save; + inbuf = mprint("..%A", a); + realgchar = stringgchar; + if (save_lineno) + lineno = 1; + else + --lineno; +} + +/* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */ + +extern void popinput() { + if (istack->t == iFd) + close(istack->fd); + efree(inbuf); + --istack; + realgchar = (istack->t == iString ? stringgchar : fdgchar); + if (istack->fd == -1) { /* top of input stack */ + realgchar = dead; + realugchar = ugdead; + } + last = istack->last; + eofread = istack->eofread; + inbuf = istack->ibuf; + chars_out = istack->index; + chars_in = istack->read; + if (save_lineno) + lineno = istack->lineno; + else + lineno++; + save_lineno = istack->saved; +} + +/* flush input characters upto newline. Used by scanerror() */ + +extern void flushu() { + int c; + if (last == '\n' || last == EOF) + return; + while ((c = gchar()) != '\n' && c != EOF) + ; /* skip to newline */ + if (c == EOF) + ugchar(c); +} + +/* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */ + +extern Node *doit(bool execit) { + bool eof; + Jbwrap j; + Estack e1, e2; + Edata jerror; + if (dashen) + execit = FALSE; + setjmp(j.j); + jerror.jb = &j; + except(eError, jerror, &e1); + for (eof = FALSE; !eof;) { + Edata block; + block.b = newblock(); + except(eArena, block, &e2); + SIGCHK; + if (dashell) { + char *fname[3]; + fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w; + fname[2] = NULL; + rcrc = TRUE; + dashell = FALSE; + b_dot(fname); + } + if (interactive) { + List *s; + if (!dashen && fnlookup("prompt") != NULL) { + static char *arglist[] = { "prompt", NULL }; + funcall(arglist); + } + if ((s = varlookup("prompt")) != NULL) { +#ifdef READLINE + prompt = s->w; +#else + fprint(2, "%s", s->w); +#endif + prompt2 = (s->n == NULL ? "" : s->n->w); + } + } + inityy(); + if (yyparse() == 1 && execit) + rc_raise(eError); + eof = (last == EOF); /* "last" can be clobbered during a walk() */ + if (parsetree != NULL) { + if (execit) + walk(parsetree, TRUE); + else if (dashex && dashen) + fprint(2, "%T\n", parsetree); + } + unexcept(); /* eArena */ + } + popinput(); + unexcept(); /* eError */ + return parsetree; +} + +/* parse a function imported from the environment */ + +extern Node *parseline(char *extdef) { + int i = interactive; + char *in[2]; + Node *fun; + in[0] = extdef; + in[1] = NULL; + interactive = FALSE; + pushstring(in, TRUE); + fun = doit(FALSE); + interactive = i; + return fun; +} + +/* write last command out to a file. Check to see if $history has changed, also */ + +static void history() { + List *histlist; + SIZE_T a; + if (!interactive) + return; + if ((histlist = varlookup("history")) == NULL) { + if (histstr != NULL) { + efree(histstr); + close(histfd); + histstr = NULL; + } + return; + } + if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */ + if (histstr != NULL) { + efree(histstr); + close(histfd); + } + histstr = ecpy(histlist->w); + histfd = rc_open(histstr, rAppend); + if (histfd < 0) { + uerror(histstr); + efree(histstr); + histstr = NULL; + varrm("history", FALSE); + } + } + /* + Small unix hack: since read() reads only up to a newline + from a terminal, then presumably this write() will write at + most only one input line at a time. + */ + for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */ + if (inbuf[a] == '#' || inbuf[a] == '\n') + return; + if (inbuf[a] != ' ' && inbuf[a] != '\t') + break; + } + writeall(histfd, inbuf + 2, chars_in); +} + +/* close file descriptors after a fork() */ + +extern void closefds() { + Input *i; + if (histstr != NULL) { /* Close an open history file */ + close(histfd); + histstr = NULL; /* But prevent re-closing of the same file-descriptor */ + } + for (i = istack; i != itop; --i) /* close open scripts */ + if (i->t == iFd && i->fd > 2) { + close(i->fd); + i->fd = -1; + } +} diff --git a/jbwrap.h b/jbwrap.h new file mode 100644 index 0000000..a31ef19 --- /dev/null +++ b/jbwrap.h @@ -0,0 +1,10 @@ +/* certain braindamaged environments don't define jmp_buf as an array, so... */ + +struct Jbwrap { + jmp_buf j; +}; + +extern Jbwrap slowbuf; /* for getting out of interrupts while performing slow i/o on BSD */ + +extern int setjmp(jmp_buf); +extern void longjmp(jmp_buf, int); diff --git a/lex.c b/lex.c new file mode 100644 index 0000000..90be65d --- /dev/null +++ b/lex.c @@ -0,0 +1,398 @@ +/* lex.c: rc's lexical analyzer */ + +#include "rc.h" +#include "y.tab.h" + +/* + Special characters (i.e., "non-word") in rc: + \t \n # ; & | ^ $ = ~ ` ' { } @ ! ( ) < > \ + + The lexical analyzer is fairly straightforward. The only really + unclean part concerns backslash continuation and "double + backslashes". A backslash followed by a newline is treated as a + space, otherwise backslash is not a special characeter (i.e., + it can be part of a word). This introduces a host of unwanted + special cases. In our case, \ cannot be a word character, since + we wish to read in all word characters in a tight loop. + + Note: to save the trouble of declaring these arrays with TRUEs + and FALSEs, I am assuming that FALSE = 0, TRUE = 1. (and so is + it declared in rc.h) +*/ + +#define BUFSIZE ((SIZE_T) 1000) /* malloc hates power of 2 buffers? */ +#define BUFMAX (8 * BUFSIZE) /* How big the buffer can get before we re-allocate the + space at BUFSIZE again. Premature optimization? Maybe. + */ + +typedef enum wordstates { + NW, RW, KW /* "nonword", "realword", "keyword" */ +} wordstates; + +static void getpair(int); + +int lineno; + +const char nw[] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const char dnw[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static SIZE_T bufsize = BUFSIZE; +static char *realbuf = NULL; +static bool newline = FALSE; +static bool errset = FALSE; +static bool prerror = FALSE; +static wordstates w = NW; +static int fd_left, fd_right; + +#define checkfreecaret {if (w != NW) { w = NW; ugchar(c); return '^'; }} + +enum filedescriptors { + UNSET = -9, CLOSED = -1 +}; + +extern int yylex() { + static bool dollar = FALSE; + bool saw_meta = FALSE; + int c; + SIZE_T i; /* The purpose of all these local assignments is to */ + const char *meta; /* allow optimizing compilers like gcc to load these */ + char *buf = realbuf; /* values into registers. On a sparc this is a */ + YYSTYPE *y = &yylval; /* win, in code size *and* execution time */ + if (errset) { + errset = FALSE; + return '\n'; + } + /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */ + meta = (dollar ? dnw : nw); + dollar = FALSE; + if (newline) { + --lineno; /* slight space optimization; print_prompt2() always increments lineno */ + print_prompt2(); + newline = FALSE; + } +top: while ((c = gchar()) == ' ' || c == '\t') + w = NW; + if (c == EOF) + return END; + if (!meta[(unsigned char) c]) { /* it's a word or keyword. */ + checkfreecaret; + w = RW; + i = 0; + read: do { + buf[i++] = c; + if (c == '?' || c == '[' || c == '*') + saw_meta = TRUE; + if (i >= bufsize) + buf = realbuf = erealloc(buf, bufsize *= 2); + } while ((c = gchar()) != EOF && !meta[(unsigned char) c]); + while (c == '\\') { + if ((c = gchar()) == '\n') { + print_prompt2(); + c = ' '; /* Pretend a space was read */ + break; + } else { + bs: if (meta != dnw) { /* all words but varnames may have a bslash */ + buf[i++] = '\\'; + if (i >= bufsize) + buf = realbuf = erealloc(buf, bufsize *= 2); + if (!meta[(unsigned char) c]) + goto read; + } else { + ugchar(c); + c = '\\'; + break; + } + } + } + ugchar(c); + buf[i] = '\0'; + w = KW; + if (i == 2) { + if (*buf == 'i' && buf[1] == 'f') return IF; + if (*buf == 'f' && buf[1] == 'n') return FN; + if (*buf == 'i' && buf[1] == 'n') return IN; + } + if (streq(buf, "for")) return FOR; + if (streq(buf, "else")) return ELSE; + if (streq(buf, "switch")) return SWITCH; + if (streq(buf, "while")) return WHILE; + if (streq(buf, "case")) return CASE; + w = RW; + y->word.w = ncpy(buf); + if (saw_meta) { + char *r, *s; + + y->word.m = nalloc(strlen(buf) + 1); + for (r = buf, s = y->word.m; *r != '\0'; r++, s++) + *s = (*r == '?' || *r == '[' || *r == '*'); + } else { + y->word.m = NULL; + } + return WORD; + } + if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') { + checkfreecaret; + if (c == '!' || c == '@' || c == '~') + w = KW; + } + switch (c) { + case '\0': + pr_error("warning: null character ignored"); + goto top; + case '!': + return BANG; + case '@': + return SUBSHELL; + case '~': + return TWIDDLE; + case '`': + c = gchar(); + if (c == '`') + return BACKBACK; + ugchar(c); + return '`'; + case '$': + dollar = TRUE; + c = gchar(); + if (c == '#') + return COUNT; + if (c == '^') + return FLAT; + ugchar(c); + return '$'; + case '\'': + w = RW; + i = 0; + do { + buf[i++] = c; + if (c == '\n') + print_prompt2(); + if (c == EOF) { + w = NW; + scanerror("eof in quoted string"); + return HUH; + } + if (i >= bufsize) + buf = realbuf = erealloc(buf, bufsize *= 2); + } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */ + ugchar(c); + buf[i] = '\0'; + y->word.w = ncpy(buf); + y->word.m = NULL; + return WORD; + case '\\': + if ((c = gchar()) == '\n') { + print_prompt2(); + goto top; /* Pretend it was just another space. */ + } + ugchar(c); + c = '\\'; + checkfreecaret; + c = gchar(); + i = 0; + goto bs; + case '(': + if (w == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */ + c = SUB; + w = NW; + return c; + case '#': + while ((c = gchar()) != '\n') /* skip comment until newline */ + if (c == EOF) + return END; + /* FALLTHROUGH */ + case '\n': + lineno++; + newline = TRUE; + /* FALLTHROUGH */ + case ';': + case '^': + case ')': + case '=': + case '{': case '}': + w = NW; + return c; + case '&': + w = NW; + c = gchar(); + if (c == '&') + return ANDAND; + ugchar(c); + return '&'; + case '|': + w = NW; + c = gchar(); + if (c == '|') + return OROR; + getpair(c); + if (errset) + return HUH; + if ((y->pipe.left = fd_left) == UNSET) + y->pipe.left = 1; /* default to fd 1 */ + if ((y->pipe.right = fd_right) == UNSET) + y->pipe.right = 0; /* default to fd 0 */ + if (y->pipe.right == CLOSED) { + scanerror("expected digit after '='"); /* can't close a pipe */ + return HUH; + } + return PIPE; + case '>': + c = gchar(); + if (c == '>') { + c = gchar(); + y->redir.type = rAppend; + } else + y->redir.type = rCreate; + y->redir.fd = 1; + goto common; + case '<': + c = gchar(); + if (c == '<') { + c = gchar(); + if (c == '<') { + c = gchar(); + y->redir.type = rHerestring; + } else { + y->redir.type = rHeredoc; + } + } else + y->redir.type = rFrom; + y->redir.fd = 0; + common: + w = NW; + getpair(c); + if (errset) + return HUH; + if (fd_right == UNSET) { /* redirection, not dup */ + if (fd_left != UNSET) { + y->redir.fd = fd_left; + return SREDIR; + } + return (y->redir.type == rFrom || y->redir.type == rCreate) ? REDIR : SREDIR; + } else { /* dup; recast yylval */ + y->dup.type = y->redir.type; + y->dup.left = fd_left; + y->dup.right = fd_right; + return DUP; + } + default: + w = NW; + return c; /* don't know what it is, let yacc barf on it */ + } +} + +extern void yyerror(const char *s) { + char *tok; + if (prerror) { /* don't print "syntax error" if there's a more informative scanerror */ + prerror = FALSE; + return; + } + if (!interactive) { + if (w != NW) + tok = realbuf; + else if (last == EOF) + tok = "eof"; + else if (last == '\n') + tok = "end of line"; + else + tok = nprint((last < 32 || last > 126) ? "(decimal %d)" : "'%c'", last); + fprint(2, "line %d: %s near %s\n", lineno - (last == '\n'), s, tok); + } else + fprint(2, "%s\n", s); +} + +extern void scanerror(char *s) { + flushu(); /* flush upto newline */ + yyerror(s); + errset = prerror = TRUE; +} + +extern void inityy() { + newline = FALSE; + w = NW; + hq = NULL; + /* return memory to the system if the buffer got too large */ + if (bufsize > BUFMAX && realbuf != NULL) { + efree(realbuf); + bufsize = BUFSIZE; + realbuf = ealloc(bufsize); + } else if (realbuf == NULL) + realbuf = ealloc(bufsize); +} + +extern void print_prompt2() { + lineno++; +#ifdef READLINE + prompt = prompt2; +#else + if (interactive) + fprint(2, "%s", prompt2); +#endif +} + +/* + Scan in a pair of integers for redirections like >[2=1]. CLOSED represents a closed file + descriptor (i.e., >[2=]) and UNSET represents an undesignated file descriptor (e.g., + >[2] is represented as (2,UNSET). + + This function makes use of unsigned compares to make range tests in one compare operation. +*/ + +static void getpair(int c) { + int n; + fd_left = fd_right = UNSET; + if (c != '[') { + ugchar(c); + return; + } + if ((unsigned int) (n = gchar() - '0') > 9) { + scanerror("expected digit after '['"); + return; + } + while ((unsigned int) (c = gchar() - '0') <= 9) + n = n * 10 + c; + fd_left = n; + c += '0'; + switch (c) { + default: + scanerror("expected '=' or ']' after digit"); + return; + case ']': + return; + case '=': + if ((unsigned int) (n = gchar() - '0') > 9) { + if (n != ']' - '0') { + scanerror("expected digit or ']' after '='"); + return; + } + fd_right = CLOSED; + } else { + while ((unsigned int) (c = gchar() - '0') <= 9) + n = n * 10 + c; + if (c != ']' - '0') { + scanerror("expected ']' after digit"); + return; + } + fd_right = n; + } + } +} diff --git a/list.c b/list.c new file mode 100644 index 0000000..f795485 --- /dev/null +++ b/list.c @@ -0,0 +1,57 @@ +/* list.c: routines for manipulating the List type */ + +#include "rc.h" + +/* + These list routines assign meta values of null to the resulting lists; + it is impossible to glob with the value of a variable unless this value + is rescanned with eval---therefore it is safe to throw away the meta-ness + of the list. +*/ + +/* free a list from malloc space */ + +extern void listfree(List *p) { + while (p != NULL) { + List *n = p->n; + efree(p->w); + efree(p); + p = n; + } +} + +/* Copy list into malloc space (for storing a variable) */ + +extern List *listcpy(List *s, void *(*alloc)(SIZE_T)) { + List *top, *r; + for (top = r = NULL; s != NULL; s = s->n) { + if (top == NULL) + r = top = (*alloc)(sizeof (List)); + else + r = r->n = (*alloc)(sizeof (List)); + r->w = (*alloc)(strlen(s->w) + 1); + strcpy(r->w, s->w); + r->m = NULL; + } + if (r != NULL) + r->n = NULL; + return top; +} + +/* Length of list */ + +extern SIZE_T listlen(List *s) { + SIZE_T size; + for (size = 0; s != NULL; s = s->n) + size += strlen(s->w) + 1; + return size; +} + +/* Number of elements in list */ + +extern int listnel(List *s) { + int nel; + for (nel = 0; s != NULL; s = s->n) + nel++; + return nel; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..0b65adf --- /dev/null +++ b/main.c @@ -0,0 +1,115 @@ +/* main.c: handles initialization of rc and command line options */ + +#include "rc.h" + +bool dashdee, dashee, dashvee, dashex, dashell, dasheye, + dashen, dashpee, interactive; +int rc_pid; + +static bool dashoh; + +static void assigndefault(char *,...); +static void checkfd(int, enum redirtype); + +extern void main(int argc, char *argv[], char *envp[]) { + char *dashsee[2], *dollarzero, *null[1]; + int c; + initprint(); + dashsee[0] = dashsee[1] = NULL; + dollarzero = argv[0]; + rc_pid = getpid(); + dashell = (*argv[0] == '-'); /* Unix tradition */ + while ((c = rc_getopt(argc, argv, "nolpeivdxc:")) != -1) + switch (c) { + case 'l': + dashell = TRUE; + break; + case 'e': + dashee = TRUE; + break; + case 'i': + dasheye = interactive = TRUE; + break; + case 'v': + dashvee = TRUE; + break; + case 'x': + dashex = TRUE; + break; + case 'd': + dashdee = TRUE; + break; + case 'c': + dashsee[0] = rc_optarg; + goto quitopts; + case 'n': + dashen = TRUE; + break; + case 'p': + dashpee = TRUE; + break; + case 'o': + dashoh = TRUE; + break; + case '?': + exit(1); + } +quitopts: + argv += rc_optind; + /* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */ + if (!dasheye && dashsee[0] == NULL && *argv == NULL) + interactive = isatty(0); + if (!dashoh) { + checkfd(0, rFrom); + checkfd(1, rCreate); + checkfd(2, rCreate); + } + initsignal(); + inithash(); + initparse(); + assigndefault("prompt", "; ", "", (void *)0); +#ifdef DEFAULTPATH + assigndefault("path", DEFAULTPATH, (void *)0); +#endif + assigndefault("ifs", " ", "\t", "\n", (void *)0); + assigndefault("pid", nprint("%d", rc_pid), (void *)0); + initenv(envp); + initinput(); + null[0] = NULL; + starassign(dollarzero, null, FALSE); /* assign $0 to $* */ + inithandler(); + if (dashsee[0] != NULL) { /* input from the -c flag? */ + if (*argv != NULL) + starassign(dollarzero, argv, FALSE); + pushstring(dashsee, TRUE); + } else if (*argv != NULL) { /* else from a file? */ + b_dot(--argv); + rc_exit(getstatus()); + } else { /* else stdin */ + pushfd(0); + } + dasheye = FALSE; + doit(TRUE); + rc_exit(getstatus()); +} + +static void assigndefault(char *name,...) { + va_list ap; + List *l; + char *v; + va_start(ap, name); + for (l = NULL; (v = va_arg(ap, char *)) != NULL;) + l = append(l, word(v, NULL)); + varassign(name, l, FALSE); + if (streq(name, "path")) + alias(name, l, FALSE); + va_end(ap); +} + +/* open an fd on /dev/null if it is inherited closed */ + +static void checkfd(int fd, enum redirtype r) { + int new = rc_open("/dev/null", r); + if (new != fd && new != -1) + close(new); +} diff --git a/match.c b/match.c new file mode 100644 index 0000000..6f87614 --- /dev/null +++ b/match.c @@ -0,0 +1,99 @@ +/* match.c: pattern matching routines */ + +#include "rc.h" + +static int rangematch(char *, char); + +enum { RANGE_FAIL = -1, RANGE_ERROR = -2 }; + +/* match() matches a single pattern against a single string. */ + +extern bool match(char *p, char *m, char *s) { + int i, j; + if (m == NULL) + return streq(p, s); + i = 0; + while (1) { + if (p[i] == '\0') + return *s == '\0'; + else if (m[i]) { + switch (p[i++]) { + case '?': + if (*s++ == '\0') + return FALSE; + break; + case '*': + while (p[i] == '*' && m[i] == 1) /* collapse multiple stars */ + i++; + if (p[i] == '\0') /* star at end of pattern? */ + return TRUE; + while (*s != '\0') + if (match(p + i, m + i, s++)) + return TRUE; + return FALSE; + case '[': + if (*s == '\0') + return FALSE; + switch (j = rangematch(p + i, *s)) { + default: + i += j; + break; + case RANGE_FAIL: + return FALSE; + case RANGE_ERROR: + if (*s != '[') + return FALSE; + } + s++; + break; + default: + panic("bad metacharacter in match"); + /* NOTREACHED */ + return FALSE; /* hush up gcc -Wall */ + } + } else if (p[i++] != *s++) + return FALSE; + } +} + +/* + From the ed(1) man pages (on ranges): + + The `-' is treated as an ordinary character if it occurs first + (or first after an initial ^) or last in the string. + + The right square bracket does not terminate the enclosed string + if it is the first character (after an initial `^', if any), in + the bracketed string. + + rangematch() matches a single character against a class, and returns + an integer offset to the end of the range on success, or -1 on + failure. +*/ + +static int rangematch(char *p, char c) { + char *orig = p; + bool neg = (*p == '~'); + bool matched = FALSE; + if (neg) + p++; + if (*p == ']') { + p++; + matched = (c == ']'); + } + for (; *p != ']'; p++) { + if (*p == '\0') + return RANGE_ERROR; /* bad syntax */ + if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */ + if (c >= *p) + matched |= (c <= p[2]); + p += 2; + } else { + matched |= (*p == c); + } + } + if (matched ^ neg) + return p - orig + 1; /* skip the right-bracket */ + else + return RANGE_FAIL; +} diff --git a/mksignal b/mksignal new file mode 100755 index 0000000..9a9b968 --- /dev/null +++ b/mksignal @@ -0,0 +1,75 @@ +#!/bin/sh +# generate rc's internal signal table from signal.h + +exec > sigmsgs.c + +echo '#include "sigmsgs.h"' +echo +echo 'Sigmsgs signals[] = {' + +sed ' s/\/\*[ ]*// + s/[ ]*\*\/// + s/([@*+!]) // + s/[ ]*([a-zA-Z,->& ]*)[ ]*// + s/^[ ]*\#[ ]*define/\#define/ + s/[ ]*signal$//' $1 | +awk ' + BEGIN { + # assign to nomesg["SIGNAME"] to suppress a long message + nomesg["SIGINT"] = 1 + nomesg["SIGPIPE"] = 1 + # assign to mesg["SIGNAME"] to override a message + mesg["SIGHUP"] = "hangup" + mesg["SIGKILL"] = "killed" + mesg["SIGQUIT"] = "quit" + mesg["SIGTERM"] = "terminated" + mesg["SIGURG"] = "urgent condition on i/o channel" + mesg["SIGSTOP"] = "stop signal not from tty" + mesg["SIGTSTP"] = "stopped" + mesg["SIGCONT"] = "continue" + mesg["SIGCHLD"] = "child stop or exit" + mesg["SIGTTIN"] = "background tty read" + mesg["SIGTTOU"] = "background tty write" + # assign to ignore["SIGNAME"] to explicitly ignore a named signal + ignore["SIGMAX"] = 1 + } + $1 == "#define" && $2 == "NSIG" && $3 ~ /^[0-9]+$/ { nsig = $3 } + $1 == "#define" && $2 ~ /^SIG/ && $3 ~ /^[0-9]+$/ && sig[$3] == "" && ignore[$2] == 0 { + sig[$3] = $2 + if ($3 > max) + max = $3 + if (mesg[$2] == "" && nomesg[$2] == 0) { + str = $4 + for (i = 5; i <= NF; i++) + str = str " " $i + mesg[$2] = str + } + } + END { + if (nsig == 0) + nsig = max + 1 + printf " {!!, !!},\n" + for (i = 1; i < nsig; i++) { + if (sig[i] == "") + printf " {!!, !!},\n" + else + printf " {!%s!, !%s!},\n", sig[i], mesg[sig[i]] + } + } +' | +tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!' 'abcdefghijklmnopqrstuvwxyz"' + +echo '};' + +exec > sigmsgs.h + +echo 'typedef struct {' +echo ' char *name, *msg;' +echo '} Sigmsgs;' +echo 'extern Sigmsgs signals[];' + +grep '^ ' sigmsgs.c | # the thing in quotes is ^ +awk ' + { sum = sum + 1; } + END { print "#define NUMOFSIGNALS", sum } +' diff --git a/nalloc.c b/nalloc.c new file mode 100644 index 0000000..5498e38 --- /dev/null +++ b/nalloc.c @@ -0,0 +1,137 @@ +/* nalloc.c: a simple single-arena allocator for command-line-lifetime allocation */ +#include "rc.h" + +static struct Block { + SIZE_T used, size; + char *mem; + Block *n; +} *fl, *ul; + +/* alignto() works only with power of 2 blocks and assumes 2's complement arithmetic */ +#define alignto(m, n) ((m + n - 1) & ~(n - 1)) +#define BLOCKSIZE ((SIZE_T) 4096) + +/* Allocate a block from the free list or malloc one if none in the fl fit */ + +static void getblock(SIZE_T n) { + Block *r, *p; + for (r = fl, p = NULL; r != NULL; p = r, r = r->n) + if (n <= r->size) + break; /* look for a block which fits the request */ + if (r != NULL) { /* if one is found, take it off the free list */ + if (p != NULL) + p->n = r->n; + else + fl = r->n; + } else { /* else allocate a new block */ + r = enew(Block); + r->mem = ealloc(r->size = alignto(n, BLOCKSIZE)); + } + r->used = 0; + r->n = ul; + ul = r; +} + +/* + A fast single-arena allocator. Looks at the current block, and if + there is not enough room, it goes to getblock() for more. "ul" + stands for "used list", and the head of the list is the current + block. "ulp" is a register cache for "ul"; this routine is hacked + for speed. (sigh, optimizing RISC compilers still can't cache the + address of a global in a register) +*/ + +extern void *nalloc(SIZE_T n) { + SIZE_T base; + Block *ulp; + n = alignto(n, sizeof (ALIGN_T)); + ulp = ul; + if (ulp != NULL && n + (base = ulp->used) < ulp->size) { + ulp->used = base + n; + return &ulp->mem[base]; + } else { + getblock(n); /* assert(ul->used) == 0 */ + (ulp = ul)->used = n; + return &ulp->mem[0]; + } +} + +/* + Frees memory from nalloc space by putting it on the free list. + Returns free blocks to the system, retaining at least MAXMEM bytes + worth of blocks for nalloc. +*/ + +#define MAXMEM 500000 + +extern void nfree() { + SIZE_T count; + Block *r; + if (ul == NULL) + return; + for (r = ul; r->n != NULL; r = r->n) + ; /* get to end of used list */ + r->n = fl; /* tack free list onto it */ + fl = ul; /* and make it the free list */ + ul = NULL; /* finally, zero out the used list */ + for (r = fl, count = r->size; r->n != NULL; r = r->n, count += r->size) { + if (count >= MAXMEM) { + Block *tmp = r; + r = r->n; + tmp->n = NULL; /* terminate the free list */ + while (r != NULL) { /* free memory off the tail of the free list */ + tmp = r->n; + efree(r->mem); + efree(r); + r = tmp; + } + return; + } + } +} + +/* + "Allocates" a new arena by zeroing out the old one. Up to the + calling routine to keep the old value of the block around. +*/ + +extern Block *newblock() { + Block *old = ul; + ul = NULL; + return old; +} + +/* "Restores" an arena to its saved value. */ + +extern void restoreblock(Block *old) { + nfree(); + ul = old; +} + +/* generic memory allocation functions */ + +extern void *ealloc(SIZE_T n) { + extern void *malloc(SIZE_T); + void *p = malloc(n); + if (p == NULL) { + uerror("malloc"); + rc_exit(1); + } + return p; +} + +extern void *erealloc(void *p, SIZE_T n) { + extern void *realloc(void *, SIZE_T); + if ((p = realloc(p, n)) == NULL) { + uerror("realloc"); + rc_exit(1); + } + return p; +} + +extern void efree(void *p) { + extern void free(void *); + if (p != NULL) + free(p); +} + diff --git a/open.c b/open.c new file mode 100644 index 0000000..7287e0e --- /dev/null +++ b/open.c @@ -0,0 +1,29 @@ +/* open.c: to insulate from the rest of rc. */ + +#include +#include "rc.h" + +/* prototype for open() follows. comment out if necessary */ + +/*extern int open(const char *, int,...);*/ + +/* + Opens a file with the necessary flags. Assumes the following + declaration for redirtype: + + enum redirtype { + rFrom, rCreate, rAppend, rHeredoc, rHerestring + }; +*/ + +static const int mode_masks[] = { + /* rFrom */ O_RDONLY, + /* rCreate */ O_TRUNC | O_CREAT | O_WRONLY, + /* rAppend */ O_APPEND | O_CREAT | O_WRONLY +}; + +extern int rc_open(const char *name, redirtype m) { + if ((unsigned) m >= arraysize(mode_masks)) + panic("bad mode passed to rc_open"); + return open(name, mode_masks[m], 0666); +} diff --git a/parse.y b/parse.y new file mode 100644 index 0000000..f1f5526 --- /dev/null +++ b/parse.y @@ -0,0 +1,174 @@ +/* parse.y */ + +/* + * Adapted from rc grammar, v10 manuals, volume 2. + */ + +%{ +#include "rc.h" +#ifndef lint +#define lint /* hush up gcc -Wall, leave out the dumb sccsid's. */ +#endif +static Node *star, *nolist; +Node *parsetree; /* not using yylval because bison declares it as an auto */ +%} + +%token ANDAND BACKBACK BANG CASE COUNT DUP ELSE END FLAT FN FOR IF IN +%token OROR PIPE REDIR SREDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH + +%left WHILE ')' ELSE +%left ANDAND OROR '\n' +%left BANG SUBSHELL +%left PIPE +%right '$' +%left SUB +/* +*/ + +%union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} + +%type REDIR SREDIR +%type PIPE +%type DUP +%type WORD +%type keyword +%type assign body brace case cbody cmd cmdsa cmdsan comword epilog + first line nlwords paren redir sword simple iftail word words + +%start rc + +%% + +rc : line end { parsetree = $1; YYACCEPT; } + | error end { yyerrok; parsetree = NULL; YYABORT; } + +/* an rc line may end in end-of-file as well as newline, e.g., rc -c 'ls' */ +end : END /* EOF */ { if (!heredoc(1)) YYABORT; } /* flag error if there is a heredoc in the queue */ + | '\n' { if (!heredoc(0)) YYABORT; } /* get heredoc on \n */ + +/* a cmdsa is a command followed by ampersand or newline (used in "line" and "body") */ +cmdsa : cmd ';' + | cmd '&' { $$ = ($1 != NULL ? mk(nNowait,$1) : $1); } + +/* a line is a single command, or a command terminated by ; or & followed by a line (recursive) */ +line : cmd + | cmdsa line { $$ = ($1 != NULL ? mk(nBody,$1,$2) : $2); } + +/* a body is like a line, only commands may also be terminated by newline */ +body : cmd + | cmdsan body { $$ = ($1 == NULL ? $2 : $2 == NULL ? $1 : mk(nBody,$1,$2)); } + +cmdsan : cmdsa + | cmd '\n' { $$ = $1; if (!heredoc(0)) YYABORT; } /* get h.d. on \n */ + +brace : '{' body '}' { $$ = $2; } + +paren : '(' body ')' { $$ = $2; } + +assign : first '=' word { $$ = mk(nAssign,$1,$3); } + +epilog : { $$ = NULL; } + | redir epilog { $$ = mk(nEpilog,$1,$2); } + +/* a redirection is a dup (e.g., >[1=2]) or a file redirection. (e.g., > /dev/null) */ +redir : DUP { $$ = mk(nDup,$1.type,$1.left,$1.right); } + | REDIR word { $$ = mk(nRedir,$1.type,$1.fd,$2); + if ($1.type == rHeredoc && !qdoc($2, $$)) YYABORT; /* queue heredocs up */ + } + | SREDIR word { $$ = mk(nRedir,$1.type,$1.fd,$2); + if ($1.type == rHeredoc && !qdoc($2, $$)) YYABORT; /* queue heredocs up */ + } + +case : CASE words ';' { $$ = mk(nCase, $2); } + | CASE words '\n' { $$ = mk(nCase, $2); } + +cbody : cmd { $$ = mk(nCbody, $1, NULL); } + | case cbody { $$ = mk(nCbody, $1, $2); } + | cmdsan cbody { $$ = mk(nCbody, $1, $2); } + +iftail : cmd %prec ELSE + | brace ELSE optnl cmd { $$ = mk(nElse,$1,$4); } + +cmd : /* empty */ %prec WHILE { $$ = NULL; } + | simple + | brace epilog { $$ = mk(nBrace,$1,$2); } + | IF paren optnl iftail { $$ = mk(nIf,$2,$4); } + | FOR '(' word IN words ')' optnl cmd { $$ = mk(nForin,$3,$5,$8); } + | FOR '(' word ')' optnl cmd { $$ = mk(nForin,$3,star,$6); } + | WHILE paren optnl cmd { $$ = mk(nWhile,$2,$4); } + | SWITCH '(' word ')' optnl '{' cbody '}' { $$ = mk(nSwitch,$3,$7); } + | TWIDDLE optcaret word words { $$ = mk(nMatch,$3,$4); } + | cmd ANDAND optnl cmd { $$ = mk(nAndalso,$1,$4); } + | cmd OROR optnl cmd { $$ = mk(nOrelse,$1,$4); } + | cmd PIPE optnl cmd { $$ = mk(nPipe,$2.left,$2.right,$1,$4); } + | redir cmd %prec BANG { $$ = ($2 != NULL ? mk(nPre,$1,$2) : $1); } + | assign cmd %prec BANG { $$ = ($2 != NULL ? mk(nPre,$1,$2) : $1); } + | BANG optcaret cmd { $$ = mk(nBang,$3); } + | SUBSHELL optcaret cmd { $$ = mk(nSubshell,$3); } + | FN words brace { $$ = mk(nNewfn,$2,$3); } + | FN words { $$ = mk(nRmfn,$2); } + +optcaret : /* empty */ + | '^' + +simple : first + | simple word { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); } + | simple redir { $$ = mk(nArgs,$1,$2); } + +first : comword + | first '^' sword { $$ = mk(nConcat,$1,$3); } + +sword : comword + | keyword { $$ = mk(nWord,$1, NULL); } + +word : sword + | word '^' sword { $$ = mk(nConcat,$1,$3); } + +comword : '$' sword { $$ = mk(nVar,$2); } + | '$' sword SUB words ')' { $$ = mk(nVarsub,$2,$4); } + | COUNT sword { $$ = mk(nCount,$2); } + | FLAT sword { $$ = mk(nFlat, $2); } + | '`' sword { $$ = mk(nBackq,nolist,$2); } + | '`' brace { $$ = mk(nBackq,nolist,$2); } + | BACKBACK word brace { $$ = mk(nBackq,$2,$3); } + | BACKBACK word sword { $$ = mk(nBackq,$2,$3); } + | '(' nlwords ')' { $$ = $2; } + | REDIR brace { $$ = mk(nNmpipe,$1.type,$1.fd,$2); } + | WORD { $$ = ($1.w[0] == '\'') ? mk(nQword, $1.w+1, NULL) : mk(nWord,$1.w, $1.m); } + +keyword : FOR { $$ = "for"; } + | IN { $$ = "in"; } + | WHILE { $$ = "while"; } + | IF { $$ = "if"; } + | SWITCH { $$ = "switch"; } + | FN { $$ = "fn"; } + | ELSE { $$ = "else"; } + | CASE { $$ = "case"; } + | TWIDDLE { $$ = "~"; } + | BANG { $$ = "!"; } + | SUBSHELL { $$ = "@"; } + +words : { $$ = NULL; } + | words word { $$ = ($1 != NULL ? ($2 != NULL ? mk(nLappend,$1,$2) : $1) : $2); } + +nlwords : { $$ = NULL; } + | nlwords '\n' + | nlwords word { $$ = ($1 != NULL ? ($2 != NULL ? mk(nLappend,$1,$2) : $1) : $2); } + +optnl : /* empty */ + | optnl '\n' + +%% + +void initparse() { + star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc); + nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc); +} + diff --git a/print.c b/print.c new file mode 100644 index 0000000..36fefb5 --- /dev/null +++ b/print.c @@ -0,0 +1,456 @@ +/* print.c -- formatted printing routines (Paul Haahr, 12/91) */ + +#include "rc.h" +#include + +#define PRINT_ALLOCSIZE ((SIZE_T)64) +#define SPRINT_BUFSIZ ((SIZE_T)1024) + +#define MAXCONV 256 + +/* + * conversion functions + * true return -> flag changes only, not a conversion + */ + +#define Flag(name, flag) \ +static bool name(Format *format, int c) { \ + format->flags |= flag; \ + return TRUE; \ +} + +Flag(uconv, FMT_unsigned) +Flag(hconv, FMT_short) +Flag(lconv, FMT_long) +Flag(altconv, FMT_altform) +Flag(leftconv, FMT_leftside) +Flag(dotconv, FMT_f2set) + +static bool digitconv(Format *format, int c) { + if (format->flags & FMT_f2set) + format->f2 = 10 * format->f2 + c - '0'; + else { + format->flags |= FMT_f1set; + format->f1 = 10 * format->f1 + c - '0'; + } + return TRUE; +} + +static bool zeroconv(Format *format, int c) { + if (format->flags & (FMT_f1set | FMT_f2set)) + return digitconv(format, '0'); + format->flags |= FMT_zeropad; + return TRUE; +} + +static void pad(Format *format, SIZE_T len, int c) { + while (len-- != 0) + fmtputc(format, c); +} + +static bool sconv(Format *format, int c) { + char *s = va_arg(format->args, char *); + if ((format->flags & FMT_f1set) == 0) + fmtcat(format, s); + else { + SIZE_T len = strlen(s), width = format->f1 - len; + if (format->flags & FMT_leftside) { + fmtappend(format, s, len); + pad(format, width, ' '); + } else { + pad(format, width, ' '); + fmtappend(format, s, len); + } + } + return FALSE; +} + +static char *utoa(unsigned long u, char *t, unsigned int radix, const char *digit) { + if (u >= radix) { + t = utoa(u / radix, t, radix, digit); + u %= radix; + } + *t++ = digit[u]; + return t; +} + +static void intconv(Format *format, unsigned int radix, int upper, const char *altform) { + static const char * const table[] = { + "0123456789abcdefghijklmnopqrstuvwxyz", + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + }; + char padchar; + SIZE_T len, pre, zeroes, padding, width; + long n, flags; + unsigned long u; + char number[64], prefix[20]; + + if (radix > 36) + return; + + flags = format->flags; + if (flags & FMT_long) + n = va_arg(format->args, long); + else if (flags & FMT_short) + n = va_arg(format->args, short); + else + n = va_arg(format->args, int); + + pre = 0; + if ((flags & FMT_unsigned) || n >= 0) + u = n; + else { + prefix[pre++] = '-'; + u = -n; + } + + if (flags & FMT_altform) + while (*altform != '\0') + prefix[pre++] = *altform++; + + len = utoa(u, number, radix, table[upper]) - number; + if ((flags & FMT_f2set) && (SIZE_T) format->f2 > len) + zeroes = format->f2 - len; + else + zeroes = 0; + + width = pre + zeroes + len; + if ((flags & FMT_f1set) && (SIZE_T) format->f1 > width) { + padding = format->f1 - width; + } else + padding = 0; + + padchar = ' '; + if (padding > 0 && flags & FMT_zeropad) { + padchar = '0'; + if ((flags & FMT_leftside) == 0) { + zeroes += padding; + padding = 0; + } + } + + + if ((flags & FMT_leftside) == 0) + pad(format, padding, padchar); + fmtappend(format, prefix, pre); + pad(format, zeroes, '0'); + fmtappend(format, number, len); + if (flags & FMT_leftside) + pad(format, padding, padchar); +} + +static bool cconv(Format *format, int c) { + fmtputc(format, va_arg(format->args, int)); + return FALSE; +} + +static bool dconv(Format *format, int c) { + intconv(format, 10, 0, ""); + return FALSE; +} + +static bool oconv(Format *format, int c) { + intconv(format, 8, 0, "0"); + return FALSE; +} + +static bool xconv(Format *format, int c) { + intconv(format, 16, 0, "0x"); + return FALSE; +} + +static bool pctconv(Format *format, int c) { + fmtputc(format, '%'); + return FALSE; +} + +static bool badconv(Format *format, int c) { + panic("bad conversion character in printfmt"); + /* NOTREACHED */ + return FALSE; /* hush up gcc -Wall */ +} + + +/* + * conversion table management + */ + +static Conv fmttab[MAXCONV]; + +static void inittab(void) { + int i; + for (i = 0; i < MAXCONV; i++) + fmttab[i] = badconv; + + fmttab['s'] = sconv; + fmttab['c'] = cconv; + fmttab['d'] = dconv; + fmttab['o'] = oconv; + fmttab['x'] = xconv; + fmttab['%'] = pctconv; + + fmttab['u'] = uconv; + fmttab['h'] = hconv; + fmttab['l'] = lconv; + fmttab['#'] = altconv; + fmttab['-'] = leftconv; + fmttab['.'] = dotconv; + + fmttab['0'] = zeroconv; + for (i = '1'; i <= '9'; i++) + fmttab[i] = digitconv; +} + +extern bool (*fmtinstall(int c, bool (*f)(Format *, int)))(Format *, int) { +/*Conv fmtinstall(int c, Conv f) {*/ + Conv oldf; + if (fmttab[0] == NULL) + inittab(); + c &= MAXCONV - 1; + oldf = fmttab[c]; + if (f != NULL) + fmttab[c] = f; + return oldf; +} + + +/* + * functions for inserting strings in the format buffer + */ + +extern void fmtappend(Format *format, const char *s, SIZE_T len) { + while (format->buf + len > format->bufend) { + SIZE_T split = format->bufend - format->buf; + memcpy(format->buf, s, split); + format->buf += split; + s += split; + len -= split; + (*format->grow)(format, len); + } + memcpy(format->buf, s, len); + format->buf += len; +} + +extern void fmtcat(Format *format, const char *s) { + fmtappend(format, s, strlen(s)); +} + +/* + * printfmt -- the driver routine + */ + +extern int printfmt(Format *format, const char *fmt) { + unsigned const char *s = (unsigned const char *) fmt; + + if (fmttab[0] == NULL) + inittab(); + + for (;;) { + int c = *s++; + switch (c) { + case '%': + format->flags = format->f1 = format->f2 = 0; + do + c = *s++; + while ((*fmttab[c])(format, c)); + break; + case '\0': + return format->buf - format->bufbegin + format->flushed; + default: + fmtputc(format, c); + break; + } + } +} + + +/* + * the public entry points + */ + +extern int fmtprint(Format *format, const char *fmt,...) { + int n = -format->flushed; + va_list saveargs = format->args; + + va_start(format->args, fmt); + n += printfmt(format, fmt); + va_end(format->args); + format->args = saveargs; + + return n + format->flushed; +} + +static void fprint_flush(Format *format, SIZE_T more) { + SIZE_T n = format->buf - format->bufbegin; + char *buf = format->bufbegin; + + format->flushed += n; + format->buf = format->bufbegin; + writeall(format->u.n, buf, n); +} + +extern int fprint(int fd, const char *fmt,...) { + char buf[1024]; + Format format; + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + sizeof buf; + format.grow = fprint_flush; + format.flushed = 0; + format.u.n = fd; + + va_start(format.args, fmt); + printfmt(&format, fmt); + va_end(format.args); + + fprint_flush(&format, (SIZE_T) 0); + return format.flushed; +} + +static void memprint_grow(Format *format, SIZE_T more) { + char *buf; + SIZE_T len = format->bufend - format->bufbegin + 1; + len = (len >= more) + ? len * 2 + : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1); + if (format->u.n) + buf = erealloc(format->bufbegin, len); + else { + SIZE_T used = format->buf - format->bufbegin; + buf = nalloc(len); + memcpy(buf, format->bufbegin, used); + } + format->buf = buf + (format->buf - format->bufbegin); + format->bufbegin = buf; + format->bufend = buf + len - 1; +} + +static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) { + format->buf = buf; + format->bufbegin = buf; + format->bufend = buf + len - 1; + format->grow = memprint_grow; + format->flushed = 0; + printfmt(format, fmt); + *format->buf = '\0'; + return format->bufbegin; +} + +extern char *mprint(const char *fmt,...) { + Format format; + char *result; + format.u.n = 1; + va_start(format.args, fmt); + result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); + va_end(format.args); + return result; +} + +extern char *nprint(const char *fmt,...) { + Format format; + char *result; + format.u.n = 0; + va_start(format.args, fmt); + result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); + va_end(format.args); + return result; +} + + +/* THESE ARE UNUSED IN rc */ + +#if 0 + +extern int print(const char *fmt,...) { + char buf[1024]; + Format format; + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + sizeof buf; + format.grow = fprint_flush; + format.flushed = 0; + format.u.n = 1; + + va_start(format.args, fmt); + printfmt(&format, fmt); + va_end(format.args); + + fprint_flush(&format, 0); + return format.flushed; +} + +extern int eprint(const char *fmt,...) { + char buf[1024]; + Format format; + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + sizeof buf; + format.grow = fprint_flush; + format.flushed = 0; + format.u.n = 2; + + va_start(format.args, fmt); + printfmt(&format, fmt); + va_end(format.args); + + fprint_flush(&format, 0); + return format.flushed; +} + +static void snprint_grow(Format *format, SIZE_T more) { + longjmp(format->u.p, 1); +} + +extern int snprint(char *buf, int buflen, const char *fmt,...) { + int n; + jmp_buf jbuf; + Format format; + + if (setjmp(jbuf)) { + *format.buf = '\0'; + return format.buf - format.bufbegin; + } + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + buflen - 1; + format.grow = snprint_grow; + format.flushed = 0; + format.u.p = jbuf; + + va_start(format.args, fmt); + n = printfmt(&format, fmt); + va_end(format.args); + + *format.buf = '\0'; + return n; +} + +extern int sprint(char *buf, const char *fmt,...) { + int n; + jmp_buf jbuf; + Format format; + + if (setjmp(jbuf)) { + *format.buf = '\0'; + return format.buf - format.bufbegin; + } + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + SPRINT_BUFSIZ - 1; + format.grow = snprint_grow; + format.flushed = 0; + format.u.p = jbuf; + + va_start(format.args, fmt); + n = printfmt(&format, fmt); + va_end(format.args); + + *format.buf = '\0'; + return n; +} +#endif diff --git a/proto.h b/proto.h new file mode 100644 index 0000000..a599537 --- /dev/null +++ b/proto.h @@ -0,0 +1,81 @@ +/* proto.h + This file provides a definition for size_t and align_t that + should work for your system. If it does not, it is up to you to + make it the right thing. The problem is that I cannot rely upon + to do the right thing on machines which don't + yet have ansi header files. Note that on many RISC machines, + align_t must be at least 32 bits wide, and sparc doubles are + aligned on 64 bit boundaries, but of course rc does not use + doubles in its code, so the "typedef long ALIGN_T" is good + enough in the sparc's case. Also for performance reasons on a + VAX one would probably want align_t to be 32 bits wide. + + You can override these definitions with compile-line definitions + of the same macros. +*/ + +#ifndef ALIGN_T +typedef long ALIGN_T; +#endif +#ifndef SIZE_T +typedef unsigned int SIZE_T; +#endif +#ifndef MODE_T +typedef short int MODE_T; +#endif +#ifndef PID_T +typedef int PID_T; +#endif +#ifndef SIG_ATOMIC_T +typedef int SIG_ATOMIC_T; +#endif + +/* fake stdlib.h */ + +extern void exit(int); +extern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *)); + +/* fake string.h */ + +extern int strncmp(const char *, const char *, SIZE_T); +extern int strcmp(const char *, const char *); +extern SIZE_T strlen(const char *); +extern char *strchr(const char *, int); +extern char *strrchr(const char *, int); +extern char *strcpy(char *, const char *); +extern char *strncpy(char *, const char *, SIZE_T); +extern char *strcat(char *, const char *); +extern char *strncat(char *, const char *, SIZE_T); +extern void *memcpy(void *, const void *, SIZE_T); + +/* fake unistd.h */ + +extern PID_T fork(void); +extern PID_T getpid(void); +extern char *getenv(const char *); +extern int chdir(const char *); +extern int close(int); +extern int dup(int); +extern int dup2(int, int); +extern int execve(const char *, const char **, const char **); +extern int execl(const char *,...); +extern int getegid(void); +extern int geteuid(void); +extern int getgroups(int, int *); +/*extern int ioctl(int, long,...);*/ /* too much trouble leaving this uncommented */ +extern int isatty(int); +#ifndef SYSVR4 /* declares AND defines this in sys/stat.h!! */ +extern int mknod(const char *, int, int); +#endif +extern int pipe(int *); +extern int read(int, void *, unsigned int); +extern int setpgrp(int, PID_T); +extern int unlink(const char *); +extern int wait(int *); +extern int write(int, const void *, unsigned int); + +/* fake errno.h for mips (which doesn't declare errno in errno.h!?!?) */ + +#ifdef host_mips +extern int errno; +#endif diff --git a/rc.1 b/rc.1 new file mode 100644 index 0000000..c9f9e08 --- /dev/null +++ b/rc.1 @@ -0,0 +1,1880 @@ +.\" rc.1 +.\"------- +.\" Man page portability notes +.\" +.\" These are some notes on conventions to maintain for greatest +.\" portability of this man page to various other versions of +.\" nroff. +.\" +.\" When you want a \ to appear in the output, use \e in the man page. +.\" (NOTE this comes up in the rc grammar, where to print out '\n' the +.\" man page must contain '\en'.) +.\" +.\" Evidently not all versions of nroff allow the omission of the +.\" terminal " on a macro argument. Thus what could be written +.\" +.\" .Cr "exec >[2] err.out +.\" +.\" in true nroffs must be written +.\" +.\" .Cr "exec >[2] err.out" +.\" +.\" instead. +.\" +.\" Use symbolic font names (e.g. R, I, B) instead of the standard +.\" font positions 1, 2, 3. Note that for Xf to work the standard +.\" font names must be single characters. +.\" +.\" Not all man macros have the RS and RE requests (I altered the Ds +.\" and De macros and the calls to Ds accordingly). +.\" +.\" Thanks to Michael Haardt (u31b3hs@cip-s01.informatik.rwth-aachen.de) +.\" for pointing out these problems. +.\" +.\" Note that sentences should end at the end of a line. nroff and +.\" troff will supply the correct intersentence spacing, but only if +.\" the sentences end at the end of a line. Explicit spaces, if given, +.\" are apparently honored and the normal intersentence spacing is +.\" supressed. +.\" +.\" DaviD W. Sanderson +.\"------- +.\" Dd distance to space vertically before a "display" +.\" These are what n/troff use for interparagraph distance +.\"------- +.if t .nr Dd .4v +.if n .nr Dd 1v +.\"------- +.\" Ds begin a display, indented .5 inches from the surrounding text. +.\" +.\" Note that uses of Ds and De may NOT be nested. +.\"------- +.de Ds +.\" .RS \\$1 +.sp \\n(Ddu +.in +0.5i +.nf +.. +.\"------- +.\" De end a display (no trailing vertical spacing) +.\"------- +.de De +.fi +.in +.\" .RE +.. +.\"------- +.\" I stole the Xf macro from the -man macros on my machine (originally +.\" "}S", I renamed it so that it won't conflict). +.\"------- +.\" Set Cf to the name of the constant width font. +.\" It will be "C" or "(CW", typically. +.\" NOTEZ BIEN the lines defining Cf must have no trailing white space: +.\"------- +.if t .ds Cf C +.if n .ds Cf R +.\"------- +.\" Rc - Alternate Roman and Courier +.\"------- +.de Rc +.Xf R \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Ic - Alternate Italic and Courier +.\"------- +.de Ic +.Xf I \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Bc - Alternate Bold and Courier +.\"------- +.de Bc +.Xf B \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Cr - Alternate Courier and Roman +.\"------- +.de Cr +.Xf \\*(Cf R \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Ci - Alternate Courier and Italic +.\"------- +.de Ci +.Xf \\*(Cf I \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Cb - Alternate Courier and Bold +.\"------- +.de Cb +.Xf \\*(Cf B \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Xf - Alternate fonts +.\" +.\" \$1 - first font +.\" \$2 - second font +.\" \$3 - desired word with embedded font changes, built up by recursion +.\" \$4 - text for first font +.\" \$5 - \$9 - remaining args +.\" +.\" Every time we are called: +.\" +.\" If there is something in \$4 +.\" then Call ourself with the fonts switched, +.\" with a new word made of the current word (\$3) and \$4 +.\" rendered in the first font, +.\" and with the remaining args following \$4. +.\" else We are done recursing. \$3 holds the desired output +.\" word. We emit \$3, change to Roman font, and restore +.\" the point size to the default. +.\" fi +.\" +.\" Use Xi to add a little bit of space after italic text. +.\"------- +.de Xf +.ds Xi +.\"------- +.\" I used to test for the italic font both by its font position +.\" and its name. Now just test by its name. +.\" +.\" .if "\\$1"2" .if !"\\$5"" .ds Xi \^ +.\"------- +.if "\\$1"I" .if !"\\$5"" .ds Xi \^ +.\"------- +.\" This is my original code to deal with the recursion. +.\" Evidently some nroffs can't deal with it. +.\"------- +.\" .ie !"\\$4"" \{\ +.\" . Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" +.\" .\} +.\" .el \{\\$3 +.\" . ft R \" Restore the default font, since we don't know +.\" . \" what the last font change was. +.\" . ps 10 \" Restore the default point size, since it might +.\" . \" have been changed by an argument to this macro. +.\" .\} +.\"------- +.\" Here is more portable (though less pretty) code to deal with +.\" the recursion. +.\"------- +.if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" +.if "\\$4"" \\$3\fR\s10 +.. +.TH RC 1 "28 April 1991" +.SH NAME +rc \- shell +.SH SYNOPSIS +.B rc +.RB [ \-eixvldnpo ] +.RB [ \-c +.IR command ] +.RI [ arguments ] +.SH DESCRIPTION +.I rc +is a command interpreter and programming language similar to +.IR sh (1). +It is based on the AT&T Plan 9 shell of the same name. +The shell offers a C-like syntax (much more so than the C shell), +and a powerful mechanism for manipulating variables. +It is reasonably small and reasonably fast, +especially when compared to contemporary shells. +Its use is intended to be interactive, +but the language lends itself well to scripts. +.SH OPTIONS +.TP +.Cr \-e +If the +.Cr \-e +option is present, then +.I rc +will exit if the exit status of a command is false (nonzero). +.I rc +will not exit, however, if a conditional fails, e.g., an +.Cr if() +command. +.TP +.Cr \-i +If the +.Cr \-i +option is present or if the input to +.I rc +is from a terminal (as determined by +.IR isatty (3)) +then +.I rc +will be in +.I interactive +mode. +That is, a prompt (from +.Cr $prompt(1)\^ ) +will be printed before an +input line is taken, and +.I rc +will ignore the signals +.Cr SIGINT +and +.Cr SIGQUIT . +.TP +.Cr \-x +This option will make +.I rc +print every command on standard error before it is executed. +It can be useful for debugging +.I rc +scripts. +.TP +.Cr \-v +This option will echo input to +.I rc +on standard error as it is read. +.TP +.Cr \-l +If the +.Cr \-l +option is present, or if +.IR rc 's +.Cr argv[0][0] +is a dash +.Rc ( \- ), +then +.I rc +will behave as a login shell. +That is, it will try to run commands present in +.Cr $home/.rcrc , +if this file exists, before reading any other input. +.TP +.Cr \-d +This flag causes +.I rc +not to ignore +.Cr SIGQUIT +or +.Cr SIGTERM . +Thus +.I rc +can be made to dump core if sent +.Cr SIGQUIT . +This option is only useful for debugging +.IR rc . +.TP +.Cr \-n +This flag causes +.I rc +to read its input and parse it, but not to execute any commands. +This is useful for syntax checking on scripts. +If used in combination with the +.Cr \-x +option, +.I rc +will print each command as it is parsed in a form similar to the one +used for exporting functions into the environment. +.TP +.Cr \-p +This flag prevents +.I rc +from initializing shell functions from the environment. +This allows +.I rc +to run in a protected mode, whereby it becomes more difficult for +an +.I rc +script to be subverted by placing false commands in the environment. +(Note that this presence of this option does NOT mean that it is safe to +run setuid +.I rc +scripts; the usual caveats about the setuid bit still apply.) +.TP +.Cr \-o +This flag prevents the usual practice of trying to open +.Cr /dev/null +on file descriptors 0, 1, and 2, if any of those descriptors +are inherited closed. +.TP +.Cr \-c +If +.Cr \-c +is present, commands are executed from the immediately following +argument. +Any further arguments to +.I rc +are placed in +.Cr $* . +.PP +.SH COMMANDS +A simple command is a sequence of words, separated by white space +(space and tab) characters that ends with a newline, semicolon +.Rc ( ; ), +or ampersand +.Rc ( & ). +The first word of a command is the name of that command. +If the name begins with +.Cr / , +.Cr ./ , +or +.Cr ../ , +then the name is used as an absolute path +name referring to an executable file. +Otherwise, the name of the command is looked up in a table +of shell functions, builtin commands, +or as a file in the directories named by +.Cr $path . +.SS "Background Tasks" +A command ending with a +.Cr & +is run in the background; that is, +the shell returns immediately rather than waiting for the command to +complete. +Background commands have +.Cr /dev/null +connected to their standard input unless an explicit redirection for +standard input is used. +.SS "Subshells" +A command prefixed with an at-sign +.Rc ( @ ) +is executed in a subshell. +This insulates the parent shell from the effects +of state changing operations such as a +.B cd +or a variable assignment. +For example: +.Ds +.Cr "@ {cd ..; make}" +.De +.PP +will run +.IR make (1) +in the parent directory +.Rc ( .. ), +but leaves the shell running in the current directory. +.SS "Line continuation" +A long logical line may be continued over several physical lines by +terminating each line (except the last) with a backslash +.Rc ( \e ). +The backslash-newline sequence is treated as a space. +A backslash is not otherwise special to +.IR rc . +(In addition, +inside quotes a backslash loses its special meaning +even when it is followed by a newline.) +.SS Quoting +.IR rc +interprets several characters specially; special characters +automatically terminate words. +The following characters are special: +.Ds +.Cr "# ; & | ^ $ = \` ' { } ( ) < >" +.De +.PP +The single quote +.Rc ( ' ) +prevents special treatment of any character other than itself. +All characters, including control characters, newlines, +and backslashes between two quote characters are treated as an +uninterpreted string. +A quote character itself may be quoted by placing two quotes in a row. +The minimal sequence needed to enter the quote character is +.Cr '''' . +The empty string is represented by +.Cr '' . +Thus: +.Ds +.Cr "echo 'What''s the plan, Stan?'" +.De +.PP +prints out +.Ds +.Cr "What's the plan, Stan?" +.De +.PP +The number sign +.Rc ( # ) +begins a comment in +.IR rc . +All characters up to but not including the next newline are ignored. +Note that backslash continuation does not work inside a comment, +i.e., +the backslash is ignored along with everything else. +.SS Grouping +Zero or more commands may be grouped within braces +.Rc (`` { '' +and +.Rc `` } ''), +and are then treated as one command. +Braces do not otherwise define scope; +they are used only for command grouping. +In particular, be wary of the command: +.Ds +.Cr "for (i) {" +.Cr " command" +.Cr "} | command" +.De +.PP +Since pipe binds tighter than +.Cr for , +this command does not perform what the user expects it to. +Instead, enclose the whole +.Cr for +statement in braces: +.Ds +.Cr "{for (i) command} | command" +.De +.PP +Fortunately, +.IR rc 's +grammar is simple enough that a (confident) user can +understand it by examining the skeletal +.IR yacc (1) +grammar +at the end of this man page (see the section entitled +.BR GRAMMAR ). +.SS "Input and output" +.PP +The standard output may be redirected to a file with +.Ds +.Cr "command > file" +.De +.PP +and the standard input may be taken from a file with +.Ds +.Cr "command < file" +.De +.PP +File descriptors other than 0 and 1 may be specified also. +For example, to redirect standard error to a file, use: +.Ds +.Cr "command >[2] file" +.De +.PP +In order to duplicate a file descriptor, use +.Ci >[ n = m ]\fR. +Thus to redirect both standard output and standard error +to the same file, use +.Ds +.Cr "command > file >[2=1]" +.De +.PP +To close a file descriptor that may be open, use +.Ci >[ n =]\fR. +For example, to +close file descriptor 7: +.Ds +.Cr "command >[7=]" +.De +.PP +In order to place the output of a command at the end of an already +existing file, use: +.Ds +.Cr "command >> file" +.De +.PP +If the file does not exist, then it is created. +.PP +``Here documents'' are supported as in +.I sh +with the use of +.Ds +.Cr "command << 'eof-marker'" +.De +.PP +If the end-of-file marker is enclosed in quotes, +then no variable substitution occurs inside the here document. +Otherwise, every variable is substituted +by its space-separated-list value (see +.BR "Flat Lists" , +below), +and if a +.Cr ^ +character follows a variable name, it is deleted. +This allows the unambiguous use of variables adjacent to text, as in +.Ds +.Cr $variable^follow +.De +To include a literal +.Cr $ +in a here document when an unquoted end-of-file marker is being used, +enter it as +.Cr $$ . +.PP +Additionally, +.I rc +supports ``here strings'', which are like here documents, +except that input is taken directly from a string on the command line. +Its use is illustrated here: +.Ds +.Cr "cat <<< 'this is a here string' | wc" +.De +.PP +(This feature enables +.I rc +to export functions using here documents into the environment; +the author does not expect users to find this feature useful.) +.SS Pipes +Two or more commands may be combined in a pipeline by placing the +vertical bar +.Rc ( \||\| ) +between them. +The standard output (file descriptor 1) +of the command on the left is tied to the standard input (file +descriptor 0) of the command on the right. +The notation +.Ci |[ n = m ] +indicates that file descriptor +.I n +of the left process is connected to +file descriptor +.I m +of the right process. +.Ci |[ n ] +is a shorthand for +.Ci |[ n =0]\fR. +As an example, to pipe the standard error of a command to +.IR wc (1), +use: +.Ds +.Cr "command |[2] wc" +.De +.PP +The exit status of a pipeline is considered true if and only if every +command in the pipeline exits true. +.SS "Commands as Arguments" +Some commands, like +.IR cmp (1) +or +.IR diff (1), +take their arguments on the command +line, and do not read input from standard input. +It is convenient +sometimes to build nonlinear pipelines so that a command like +.I cmp +can read the output of two other commands at once. +.I rc +does it like this: +.Ds +.Cr "cmp <{command} <{command}" +.De +.PP +compares the output of the two commands in braces. +A note: since this form of +redirection is implemented with some kind of pipe, and since one cannot +.IR lseek (2) +on a pipe, commands that use +.IR lseek (2) +will hang. +For example, +most versions of +.IR diff (1) +use +.IR lseek (2) +on their inputs. +.PP +Data can be sent down a pipe to several commands using +.IR tee (1) +and the output version of this notation: +.Ds +.Cr "echo hi there | tee >{sed 's/^/p1 /'} >{sed 's/^/p2 /'}" +.De +.SH "CONTROL STRUCTURES" +The following may be used for control flow in +.IR rc : +.SS "If-else Statements" +.PD 0 +.sp +.Ci "if (" test ") {" +.br +.I " cmd" +.br +.TP +.Ci "} else " cmd +The +.I test +is executed, and if its return status is zero, the first +command is executed, otherwise the second is. +Braces are not mandatory around the commands. +However, an +.Cr else +statement is valid only if it +follows a close-brace on the same line. +Otherwise, the +.Cr if +is taken to be a simple-if: +.Ds +.Cr "if (test)" +.Cr " command" +.De +.PD +.SS "While and For Loops" +.TP +.Ci "while (" test ) " cmd" +.I rc +executes the +.I test +and performs the command as long as the +.I test +is true. +.TP +.Ci "for (" var " in" " list" ) " cmd" +.I rc +sets +.I var +to each element of +.I list +(which may contain variables and backquote substitutions) and runs +.IR cmd . +If +.Rc `` in +.IR list '' +is omitted, then +.I rc +will set +.I var +to each element of +.Cr $* +(excluding +.Cr $0 ). +For example: +.Ds +.Cr "for (i in \`{ls -F | grep '\e*$' | sed 's/\e*$//'}) { commands }" +.De +.TP +\& +will set +.Cr $i +to the name of each file in the current directory that is +executable. +.SS "Switch" +.TP +.Ci "switch (" list ") { case" " ..." " }" +.I rc +looks inside the braces after a +.Cr switch +for statements beginning with the word +.Cr case . +If any of the patterns following +.Cr case +match the list supplied to +.Cr switch , +then the commands up until the next +.Cr case +statement are executed. +The metacharacters +.Cr "*" , +.Cr [ +or +.Cr ? +should not be quoted; +matching is performed only against the strings in +.IR list , +not against file names. +(Matching for case statements is the same as for the +.Cr ~ +command.) +.SS "Logical Operators" +There are a number of operators in +.I rc +which depend on the exit status of a command. +.Ds +.Cr "command && command" +.De +.PP +executes the first command and then executes the second command if and only if +the first command exits with a zero exit status (``true'' in Unix). +.Ds +.Cr "command || command" +.De +.PP +executes the first command executing the second command if and only if +the second command exits with a nonzero exit status (``false'' in Unix). +.Ds +.Cr "! command" +.De +.PP +negates the exit status of a command. +.SH "PATTERN MATCHING" +There are two forms of pattern matching in +.IR rc . +One is traditional shell globbing. +This occurs in matching for file names in argument lists: +.Ds +.Cr "command argument argument ..." +.De +.PP +When the characters +.Cr "*" , +.Cr [ +or +.Cr ? +occur in an argument or command, +.I rc +looks at the +argument as a pattern for matching against files. +(Contrary to the behavior other shells exhibit, +.I rc +will only perform pattern matching if a metacharacter occurs unquoted and +literally in the input. +Thus, +.Ds +.Cr "foo='*'" +.Cr "echo $foo" +.De +.PP +will always echo just a star. +In order for non-literal metacharacters to be expanded, an +.Cr eval +statement must be used in order to rescan the input.) +Pattern matching occurs according to the following rules: a +.Cr * +matches any number (including zero) of +characters. +A +.Cr ? +matches any single character, and a +.Cr [ +followed by a +number of characters followed by a +.Cr ] +matches a single character in that +class. +The rules for character class matching are the same as those for +.IR ed (1), +with the exception that character class negation is achieved +with the tilde +.Rc ( ~ ), +not the caret +.Rc ( ^ ), +since the caret already means +something else in +.IR rc . +.PP +.I rc +also matches patterns against strings with the +.Cr ~ +command: +.Ds +.Cr "~ subject pattern pattern ..." +.De +.PP +.Cr ~ +sets +.Cr $status +to zero if and only if a supplied pattern matches any +single element of the subject list. +Thus +.Ds +.Cr "~ foo f*" +.De +.PP +sets status to zero, while +.Ds +.Cr "~ (bar baz) f*" +.De +.PP +sets status to one. +The null list is matched by the null list, so +.Ds +.Cr "~ $foo ()" +.De +.PP +checks to see whether +.Cr $foo +is empty or not. +This may also be achieved +by the test +.Ds +.Cr "~ $#foo 0" +.De +.PP +Note that inside a +.Cr ~ +command +.I rc +does not match patterns against file +names, so it is not necessary to quote the characters +.Cr "*" , +.Cr [ +and +.Cr "?" . +However, +.I rc +does expand the glob the subject against filenames if it contains +metacharacters. +Thus, the command +.Ds +.Cr "~ * ?" +.De +.PP +returns true if any of the files in the current directory have a +single-character name. +(Note that if the +.Cr ~ +command is given a list as its first +argument, then a successful match against any of the elements of that +list will cause +.Cr ~ +to return true. +For example: +.Ds +.Cr "~ (foo goo zoo) z*" +.De +.PP +is true.) +.SH "LISTS AND VARIABLES" +The primary data structure in +.IR rc +is the list, which is a sequence of words. +Parentheses are used to group lists. +The empty list is represented by +.Cr "()" . +Lists have no hierarchical structure; +a list inside another list is expanded so the +outer list contains all the elements of the inner list. +Thus, the following are all equivalent +.Ds +.Cr "one two three" + +.Cr "(one two three)" + +.Cr "((one) () ((two three)))" +.De +.PP +Note that the null string, +.Cr "''" , +and the null list, +.Cr "()" , +are two very +different things. +Assigning the null string to variable is a valid +operation, but it does not remove its definition. +For example, +if +.Cr $a +is set to +.Cr "''" , +then +.Cr "$#a" , +returns a 1. +.SS "List Concatenation" +Two lists may be joined by the concatenation operator +.Rc ( ^ ). +A single word is treated as a list of length one, so +.Ds +.Cr "echo foo^bar" +.De +.PP +produces the output +.Ds +.Cr foobar +.De +.PP +For lists of more than one element, +concatenation works according to the following rules: +if the two lists have the same number of elements, +then concatenation is pairwise: +.Ds +.Cr "echo (a\- b\- c\-)^(1 2 3)" +.De +.PP +produces the output +.Ds +.Cr "a\-1 b\-2 c\-3" +.De +.PP +Otherwise, one of the lists must have a single element, +and then the concatenation is distributive: +.Ds +.Cr "cc \-^(O g c) (malloc alloca)^.c" +.De +.PP +has the effect of performing the command +.Ds +.Cr "cc \-O \-g \-c malloc.c alloca.c" +.De +.SS "Free Carets" +.I rc +inserts carets (concatenation operators) for free in certain situations, +in order to save some typing on the user's behalf. +For +example, the above example could also be typed in as: +.Ds +.Cr "opts=(O g c) files=(malloc alloca) cc \-$opts $files.c" +.De +.PP +.I rc +takes care to insert a free-caret between the +.Rc `` \- '' +and +.Cr "$opts" , +as well +as between +.Cr $files +and +.Cr ".c" . +The rule for free carets is as follows: if +a word or keyword is immediately +followed by another word, keyword, dollar-sign or +backquote, then +.I rc +inserts a caret between them. +.SS "Variables" +A list may be assigned to a variable, using the notation: +.Ds +.Ic var " = " list +.De +.PP +Any sequence of non-special characters, except a sequence including +only digits, may be used as a variable name. +All user-defined variables are exported into the environment. +.PP +The value of a variable is referenced with the notation: +.Ds +.Ci $ var +.De +.PP +Any variable which has not been assigned a value returns the null list, +.Cr "()" , +when referenced. +In addition, multiple references are allowed: +.Ds +.Cr a=foo +.Cr b=a +.Cr "echo $$b" +.De +.PP +prints +.Ds +.Cr foo +.De +.PP +A variable's definition may also be removed by +assigning the null list to a variable: +.Ds +.Ic var =() +.De +.PP +For ``free careting'' to work correctly, +.I rc +must make certain assumptions +about what characters may appear in a variable name. +.I rc +assumes that a variable name consists only of alphanumeric characters, +underscore +.Rc ( \|_\| ) +and star +.Rc ( * ). +To reference a variable with other +characters in its name, quote the variable name. +Thus: +.Ds +.Cr "echo $'we$Ird\Variab!le'" +.De +.SS "Local Variables" +Any number of variable assignments may be made local to a single +command by typing: +.Ds +.Cr "a=foo b=bar ... command" +.De +.PP +The command may be a compound command, so for example: +.Ds +.Cr "path=. ifs=() {" +.Cr " " ... +.Cr } +.De +.PP +sets +.Cr path +to +.Cr . +and removes +.Cr ifs +for the duration of one long compound command. +.SS "Variable Subscripts" +Variables may be subscripted with the notation +.Ds +.Ci $var( n ) +.De +.PP +where +.I n +is a list of integers (origin 1). +The list of subscripts need +not be in order or even unique. +Thus, if +.Ds +.Cr "a=(one two three)" +.De +.PP +then +.Ds +.Cr "echo $a(3 3 3)" +.De +.PP +prints +.Ds +.Cr "three three three" +.De +.PP +If +.I n +references a nonexistent element, then +.Ci $var( n ) +returns the null list. +The notation +.Ci "$" n\fR, +where +.I n +is an integer, is a shorthand for +.Ci $*( n )\fR. +Thus, +.IR rc 's +arguments may be referred to as +.Cr "$1" , +.Cr "$2" , +and so on. +.PP +Note also that the list of subscripts may be given by any of +.IR rc 's +list operations: +.Ds +.Cr "$var(\`{awk 'BEGIN{for(i=1;i<=10;i++)print i;exit; }'})" +.De +.PP +returns the first 10 elements of +.Cr $var . +.PP +To count the number of elements in a variable, use +.Ds +.Cr $#var +.De +.PP +This returns a single-element list, with the number of elements in +.Cr $var . +.SS "Flat Lists" +In order to create a single-element list from a multi-element list, +with the components space-separated, use +.Ds +.Cr $^var +.De +.PP +This is useful when the normal list concatenation rules need to be +bypassed. +For example, to append a single period at the end of +.Cr $path , +use: +.Ds +.Cr "echo $^path." +.De +.SS "Backquote Substitution" +A list may be formed from the output of a command by using backquote +substitution: +.Ds +.Cr "\`{ command }" +.De +.PP +returns a list formed from the standard output of the command in braces. +.Cr $ifs +is used to split the output into list elements. +By default, +.Cr $ifs +has the value space-tab-newline. +The braces may be omitted if the command is a single word. +Thus +.Cr \`ls +may be used instead of +.Cr "\`{ls}" . +This last feature is useful when defining functions that expand +to useful argument lists. +A frequent use is: +.Ds +.Cr "fn src { echo *.[chy] }" +.De +.PP +followed by +.Ds +.Cr "wc \`src" +.De +.PP +(This will print out a word-count of all C source files in the current +directory.) +.PP +In order to override the value of +.Cr $ifs +for a single backquote +substitution, use: +.Ds +.Cr "\`\` (ifs-list) { command }" +.De +.PP +.Cr $ifs +will be temporarily ignored and the command's output will be split as specified by +the list following the double backquote. +For example: +.Ds +.Cr "\`\` ($nl :) {cat /etc/passwd}" +.De +.PP +splits up +.Cr /etc/passwd +into fields, assuming that +.Cr $nl +contains a newline +as its value. +.SH "SPECIAL VARIABLES" +Several variables are known to +.I rc +and are treated specially. +.TP +.Cr * +The argument list of +.IR rc . +.Cr "$1, $2," +etc. are the same as +.Cr $*(1) , +.Cr $*(2) , +etc. +The variable +.Cr $0 +holds the value of +.Cr argv[0] +with which +.I rc +was invoked. +Additionally, +.Cr $0 +is set to the name of a function for the duration of +the execution of that function, and +.Cr $0 +is also set to the name of the +file being interpreted for the duration of a +.Cr . +command. +.TP +.Cr apid +The process ID of the last process started in the background. +.TP +.Cr apids +The process IDs of any background processes which are outstanding +or which have died and have not been waited for yet. +.TP +.Cr cdpath +A list of directories to search for the target of a +.B cd +command. +The empty string stands for the current directory. +Note that if the +.Cr $cdpath +variable does not contain the current directory, then the current +directory will not be searched; this allows directory searching to +begin in a directory other than the current directory. +Note also that an assignment to +.Cr $cdpath +causes an automatic assignment to +.Cr $CDPATH , +and vice-versa. +.TP +.Cr history +.Cr $history +contains the name of a file to which commands are appended as +.I rc +reads them. +This facilitates the use of a stand-alone history program +(such as +.IR history (1)) +which parses the contents of the history file and presents them to +.I rc +for reinterpretation. +If +.Cr $history +is not set, then +.I rc +does not append commands to any file. +.TP +.Cr home +The default directory for the builtin +.B cd +command and is the directory +in which +.I rc +looks to find its initialization file, +.Cr .rcrc , +if +.I rc +has been started up as a login shell. +Like +.Cr $cdpath +and +.Cr $CDPATH , +.Cr $home +and +.Cr $HOME +are aliased to each other. +.TP +.Cr ifs +The internal field separator, used for splitting up the output of +backquote commands for digestion as a list. +.TP +.Cr path +This is a list of directories to search in for commands. +The empty string stands for the current directory. +Note that like +.Cr $cdpath +and +.Cr $CDPATH , +.Cr $path +and +.Cr $PATH +are aliased to each other. +If +.Cr $path +or +.Cr $PATH +is not set at startup time, +.Cr $path +assumes a default value suitable for your system. +This is typically +.Cr "(/usr/ucb /usr/bin /bin .)" +.TP +.Cr pid +The process ID of the currently running +.IR rc . +.TP +.Cr prompt +This variable holds the two prompts (in list form, of course) that +.I rc +prints. +.Cr $prompt(1) +is printed before each command is read, and +.Cr $prompt(2) +is printed when input is expected to continue on the next +line. +.I rc +sets +.Cr $prompt +to +.Cr "('; ' '')" +by default. +The reason for this is that it enables an +.I rc +user to grab commands from previous lines using a +mouse, and to present them to +.I rc +for re-interpretation; the semicolon +prompt is simply ignored by +.IR rc . +The null +.Cr $prompt(2) +also has its +justification: an +.I rc +script, when typed interactively, will not leave +.Cr $prompt(2) 's +on the screen, +and can therefore be grabbed by a mouse and placed +directly into a file for use as a shell script, without further editing +being necessary. +.TP +.Cr prompt " (function)" +If this function is set, then it gets executed every time +.I rc +is about to print +.Cr "$prompt(1)" . +.TP +.Cr status +The exit status of the last command. +If the command exited with a numeric value, +that number is the status. +If the died with a signal, +the status is the name of that signal; if a core file +was created, the string +.Rc `` +core '' +is appended. +The value of +.Cr $status +for a pipeline is a list, with one entry, +as above, for each process in the pipeline. +For example, the command +.Ds +.Cr "ls | wc" +.De +.TP +\& +usually sets +.Cr $status +to +.Cr "(0 0)" . +.PP +The values of +.Cr "$path" , +.Cr "$cdpath" , +and +.Cr $home +are derived from the environment +values of +.Cr "$PATH" , +.Cr "$CDPATH" , +and +.Cr "$HOME" . +Otherwise, they are derived from +the environment values of +.Cr $path , +.Cr $cdpath +and +.Cr $home . +This is for compatibility with other Unix programs, like +.IR sh (1). +.Cr $PATH +and +.Cr $CDPATH +are assumed to be colon-separated lists. +.SH FUNCTIONS +.I rc +functions are identical to +.I rc +scripts, except that they are stored +in memory and are automatically exported into the environment. +A shell function is declared as: +.Ds +.Cr "fn name { commands }" +.De +.PP +.I rc +scans the definition until the close-brace, so the function can +span more than one line. +The function definition may be removed by typing +.Ds +.Cr "fn name" +.De +.PP +(One or more names may be specified. +With an accompanying definition, all names receive the same definition. +This is sometimes useful +for assigning the same signal handler to many signals. +Without a definition, all named functions are deleted.) +When a function is executed, +.Cr $* +is set to the arguments to that +function for the duration of the command. +Thus a reasonable definition for +.Cr "l" , +a shorthand for +.IR ls (1), +could be: +.Ds +.Cr "fn l { ls -FC $* }" +.De +.PP +but not +.Ds +.Cr "fn l { ls -FC }" +.De +.SH "INTERRUPTS AND SIGNALS" +.I rc +recognizes a number of signals, and allows the user to define shell +functions which act as signal handlers. +.I rc +by default traps +.Cr SIGINT +when it is in interactive mode. +.Cr SIGQUIT +and +.Cr SIGTERM +are ignored, unless +.I rc +has been invoked with the +.Cr \-d +flag. +However, user-defined signal handlers may be written for these and +all other signals. +The way to define a signal handler is to +write a function by the name of the signal in lower case. +Thus: +.Ds +.Cr "fn sighup { echo hangup; rm /tmp/rc$pid.*; exit }" +.De +.PP +In addition to Unix signals, +.I rc +recognizes the artificial signal +.Cr SIGEXIT +which occurs as +.I rc +is about to exit. +.PP +In order to remove a signal handler's definition, +remove it as though it were a regular function. +For example: +.Ds +.Cr "fn sigint" +.De +.PP +returns the handler of +.Cr SIGINT +to the default value. +In order to ignore a signal, set the signal handler's value to +.Cr "{}" . +Thus: +.Ds +.Cr "fn sigint {}" +.De +.PP +causes SIGINT to be ignored by the shell. +Only signals that are being ignored are passed on to programs run by +.IR rc ; +signal functions are not exported. +.PP +On System V-based Unix systems, +.I rc +will not allow you to trap +.Cr SIGCLD . +.SH "BUILTIN COMMANDS" +Builtin commands execute in the context of the shell, but otherwise +behave exactly like other commands. +Although +.BR ! , +.B ~ +and +.B @ +are not strictly speaking builtin commands, +they can usually be used as such. +.TP +\&\fB.\fR [\fB\-i\fR] \fIfile \fR[\fIarg ...\fR] +Reads +.I file +as input to +.IR rc +and executes its contents. +With a +.Cr \-i +flag, input is interactive. +Thus from within a shell script, +.Ds +.Cr ". \-i /dev/tty" +.De +.TP +\& +does the ``right'' thing. +.TP +.B break +Breaks from the innermost +.Cr for +or +.Cr while , +as in C. +It is an error to invoke +.B break +outside of a loop. +(Note that there is no +.B break +keyword between commands in +.Cr switch +statements, unlike C.) +.TP +\fBbuiltin \fIcommand \fR[\fIarg ...\fR] +Executes the command ignoring any function definition of the +same name. +This command is present to allow functions with the +same names as builtins to use the underlying builtin or binary. +.TP +\fBcd \fR[\fIdirectory\fR] +Changes the current directory to +.IR directory . +The variable +.Cr $cdpath +is searched for possible locations of +.IR directory , +analogous to the searching of +.Cr $path +for executable files. +With no argument, +.B cd +changes the current directory to +.Cr "$home" . +.TP +\fBecho \fR[\fB\-n\fR] [\fB\-\|\-\fR] [\fIarg ...\fR] +Prints its arguments to standard output, terminated by a newline. +Arguments are separated by spaces. +If the first argument is +.Cr "\-n" +no final newline is printed. +If the first argument is +.Cr "\-\|\-" , +then all other arguments are echoed literally. +This is used for echoing a literal +.Cr "\-n" . +.TP +\fBeval \fR[\fIlist\fR] +Concatenates the elements of +.I list +with spaces and feeds the resulting string to +.I rc +for re-scanning. +This is the only time input is rescanned in +.IR rc . +.TP +\fBexec \fR[\fIarg ...\fR] +Replaces +.I rc +with the given command. +If the exec contains only redirections, +then these redirections apply to the current shell +and the shell does not exit. +For example, +.Ds +.Cr "exec >[2] err.out" +.De +.TP +\& +places further output to standard error in the file +.IR err.out . +.TP +\fBexit \fR[\fIstatus\fR] +Cause the current shell to exit with the given exit +.IR status . +If no argument is given, the current value of +.Cr $status +is used. +.TP +\fBlimit \fR[\fB\-h\fR] [\fIresource \fR[\fIvalue\fR]] +Similar to the +.IR csh (1) +.B limit +builtin, this command operates upon the +BSD-style limits of a process. +The +.Cr \-h +flag displays/alters the hard +limits. +The resources which can be shown or altered are +.BR cputime , +.BR filesize , +.BR datasize , +.BR stacksize , +.B coredumpsize +and +.BR memoryuse . +For +example: +.Ds +.Cr "limit coredumpsize 0" +.De +.TP +\& +disables core dumps. +.TP +.B newpgrp +Puts +.I rc +into a new process group. +This builtin is useful for making +.I rc +behave like a job-control shell in a hostile environment. +One example is the NeXT Terminal program, which implicitly assumes +that each shell it forks will put itself into a new process group. +.TP +\fBreturn \fR[\fIn\fR] +Returns from the current function, with status +.IR n , +where +.IR n +is a single value or a list of possible exit statuses. +Thus it is legal to have +.Ds +.Cr "return (sigpipe 1 2 3)" +.De +.TP +\& +(This is commonly used to allow a function to return with the exit status +of a previously executed pipeline of commands.) +If +.IR n +is omitted, then +.Cr $status +is left unchanged. +It is an error to invoke +.B return +when not inside a function. +.TP +\fBshift \fR[\fIn\fR] +Deletes +.I n +elements from the beginning of +.Cr $* +and shifts the other +elements down by +.IR n . +.I n +defaults to 1. +(Note that +.Cr $0 +is not affected by +.BR shift .) +.TP +\fBumask \fR[\fImask\fR] +Sets the current umask (see +.IR umask (2)) +to the octal +.IR mask . +If no argument is present, the current mask value is printed. +.TP +\fBwait \fR[\fIpid\fR] +Waits for the specified +.IR pid , +which must have been started by +.IR rc . +If no +.I pid +is specified, +.I rc +waits for any child process to exit. +.TP +\fBwhatis \fR[\fB\-s\fR] [\fB\-\|\-\fR] [\fIname ...\fR] +Prints a definition of the named objects. +For variables, their values +are printed; for functions, their definitions are; and for executable +files, path names are printed. +Without arguments, +.B whatis +prints the values of all shell variables and functions. +With a +.Cr \-s +argument, +.B whatis +also prints out a list of available signals and their handlers (if any). +Note that +.B whatis +output is suitable for input to +.IR rc ; +by saving the output of +.B whatis +in a file, it should be possible to recreate the state of +.I rc +by sourcing this file with a +.Cr . +command. +Another note: +.Cr "whatis -s > file" +cannot be used to store the state of +.IR rc 's +signal handlers in a file, because builtins with redirections +are run in a subshell, and +.I rc +always restores signal handlers to their default value after a +.Cr fork() . +.TP +\& +Since +.B whatis +uses +.IR getopt (3) +to parse its arguments, you can use the special argument +.Cr "\-\|\-" +to terminate its options. +This allows you to use names beginning with a dash, such as +the +.IR history (1) +commands. +For example, +.Ds +.Cr "whatis \-\|\- \-p" +.De +.SH GRAMMAR +Here is +.IR rc 's +grammar, edited to remove semantic actions. +.Ds +.ft \*(Cf +%term ANDAND BACKBACK BANG CASE COUNT DUP ELSE END FLAT FN FOR IF IN +%term OROR PIPE REDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH + +%left WHILE ')' ELSE +%left ANDAND OROR '\en' +%left BANG SUBSHELL +%left PIPE +%right '$' +%left SUB + +%start rc + +%% + +rc: line end + | error end + +end: END /* EOF */ | '\en' + +cmdsa: cmd ';' | cmd '&' + +line: cmd | cmdsa line + +body: cmd | cmdsan body + +cmdsan: cmdsa | cmd '\en' + +brace: '{' body '}' + +paren: '(' body ')' + +assign: first '=' word + +epilog: /* empty */ | redir epilog + +redir: DUP | REDIR word + +case: CASE words ';' | CASE words '\en' + +cbody: cmd | case cbody | cmdsan cbody + +iftail: cmd %prec ELSE + | brace ELSE optnl cmd + +cmd : /* empty */ %prec WHILE + | simple + | brace epilog + | IF paren optnl iftail + | FOR '(' word IN words ')' optnl cmd + | FOR '(' word ')' optnl cmd + | WHILE paren optnl cmd + | SWITCH '(' word ')' optnl '{' cbody '}' + | TWIDDLE optcaret word words + | cmd ANDAND optnl cmd + | cmd OROR optnl cmd + | cmd PIPE optnl cmd + | redir cmd %prec BANG + | assign cmd %prec BANG + | BANG optcaret cmd + | SUBSHELL optcaret cmd + | FN words brace + | FN words + +optcaret: /* empty */ | '^' + +simple: first | simple word | simple redir + +first: comword | first '^' sword + +sword: comword | keyword + +word: sword | word '^' sword + +comword: '$' sword + | '$' sword SUB words ')' + | COUNT sword + | FLAT sword + | '`' sword + | '`' brace + | BACKBACK word brace | BACKBACK word sword + | '(' words ')' + | REDIR brace + | WORD + +keyword: FOR | IN | WHILE | IF | SWITCH + | FN | ELSE | CASE | TWIDDLE | BANG | SUBSHELL + +words: /* empty */ | words word + +optnl: /* empty */ | optnl '\en' +.ft R +.De +.SH FILES +.Cr $HOME/.rcrc , +.Cr /tmp/rc* , +.Cr /dev/null +.SH CREDITS +.I rc +was written by Byron Rakitzis, with valuable help +from Paul Haahr, Hugh Redelmeier and David Sanderson. +The design of this shell has been copied from the +.I rc +that Tom Duff wrote at Bell Labs. +.SH BUGS +On systems that support +.Cr /dev/fd , +.Cr <{foo} +style redirection is implemented that way. +However, on other systems it is implemented with named pipes, +and it is sometimes +possible to foil +.I rc +into removing the FIFO it places in +.Cr /tmp +prematurely, or it is even possible to cause +.I rc +to hang. +.PP +The functionality of +.B shift +should be available for variables other than +.Cr "$*" . +.PP +.B echo +is built in only for performance reasons, which is a bad idea. +.PP +There should be a way to avoid exporting a variable. +.PP +The +.Cr $^var +notation for flattening should allow for using an arbitrary +separating character, not just space. +.PP +Bug reports should be mailed to +.Cr "byron@archone.tamu.edu" . +.SH INCOMPATIBILITIES +Here is a list of features which distinguish this incarnation of +.I rc +from the one described in the Bell Labs manual pages: +.PP +The treatment of +.Cr if - else +is different in the v10 +.IR rc : +that version uses an +.Cr "if not" +clause which gets executed +if the preceding +.Cr if +test does not succeed. +.PP +Backquotes are slightly different in v10 +.IR rc : +a backquote must always be followed by a left-brace. +This restriction is not present for single-word commands in this +.IR rc . +.PP +The following are all new with this version of +.IR rc : +The +.Cr \-n +option, +the list flattening operator, +here strings (they facilitate exporting of functions +with here documents into the environment), +the +.B return +and +.B break +keywords, +the +.B echo +builtin, +the support for the GNU +.IR readline (3) +library and +the support for the +.Cr prompt +function. +This +.I rc +also sets +.Cr $0 +to the name of a function being executed/file +being sourced. +.SH "SEE ALSO" +``rc \(em A Shell for Plan 9 and UNIX Systems'', +Unix Research System, +10th Edition, +vol. 2. (Saunders College Publishing) +(This paper is also distributed with this +.I rc +in PostScript form.) +.PP +.IR history (1) diff --git a/rc.h b/rc.h new file mode 100644 index 0000000..9e38d8b --- /dev/null +++ b/rc.h @@ -0,0 +1,380 @@ +#include "config.h" +#include "proto.h" + +/* datatypes */ + +/* braindamaged IBM header files #define true and false */ +#undef FALSE +#undef TRUE + +#include + +typedef void builtin_t(char **); +typedef struct Block Block; +typedef struct Dup Dup; +typedef struct Estack Estack; +typedef struct Function Function; +typedef struct Hq Hq; +typedef struct Htab Htab; +typedef struct Jbwrap Jbwrap; +typedef struct List List; +typedef struct Node Node; +typedef struct Pipe Pipe; +typedef struct Redir Redir; +typedef struct Rq Rq; +typedef struct Variable Variable; +typedef struct Word Word; +typedef struct Format Format; +typedef union Edata Edata; + +typedef enum nodetype { + nAndalso, nAssign, nBackq, nBang, nBody, nCbody, nNowait, nBrace, nConcat, + nCount, nElse, nFlat, nDup, nEpilog, nNewfn, nForin, nIf, nQword, + nOrelse, nPipe, nPre, nRedir, nRmfn, nArgs, nSubshell, nCase, + nSwitch, nMatch, nVar, nVarsub, nWhile, nWord, nLappend, nNmpipe +} nodetype; + +typedef enum ecodes { + eError, eBreak, eReturn, eVarstack, eArena, eFifo, eFd +} ecodes; + +typedef enum bool { + FALSE, TRUE +} bool; + +typedef enum inputtype { + iFd, iString +} inputtype; + +typedef enum redirtype { + rFrom, rCreate, rAppend, rHeredoc, rHerestring +} redirtype; + +typedef bool (*Conv)(Format *, int); + +union Edata { + Jbwrap *jb; + Block *b; + char *name; + int fd; +}; + +struct Estack { + ecodes e; + bool interactive; + Edata data; + Estack *prev; +}; + +struct List { + char *w, *m; + List *n; +}; + +struct Node { + nodetype type; + union { + char *s; + int i; + Node *p; + } u[4]; +}; + +struct Pipe { + int left, right; +}; + +struct Dup { + redirtype type; + int left, right; +}; + +struct Redir { + redirtype type; + int fd; +}; + +struct Word { + char *w, *m; +}; + +struct Rq { + Node *r; + struct Rq *n; +}; + +struct Function { + Node *def; + char *extdef; +}; + +struct Variable { + List *def; + char *extdef; + Variable *n; +}; + +struct Htab { + char *name; + void *p; +}; + +struct Format { + /* for the formatting routines */ + va_list args; + long flags, f1, f2; + /* for the buffer maintainence routines */ + char *buf, *bufbegin, *bufend; + int flushed; + void (*grow)(Format *, SIZE_T); + union { int n; void *p; } u; +}; + +/* Format->flags values */ +enum { + FMT_long = 1, /* %l */ + FMT_short = 2, /* %h */ + FMT_unsigned = 4, /* %u */ + FMT_zeropad = 8, /* %0 */ + FMT_leftside = 16, /* %- */ + FMT_altform = 32, /* %# */ + FMT_f1set = 64, /* % */ + FMT_f2set = 128 /* %. */ +}; + +/* macros */ +#define EOF (-1) +#ifndef NULL +#define NULL 0 +#endif +#define a2u(x) n2u(x, 10) +#define o2u(x) n2u(x, 8) +#define arraysize(a) ((int)(sizeof(a)/sizeof(*a))) +#define enew(x) ((x *) ealloc(sizeof(x))) +#define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1), x) +#define lookup_fn(s) ((Function *) lookup(s, fp)) +#define lookup_var(s) ((Variable *) lookup(s, vp)) +#define nnew(x) ((x *) nalloc(sizeof(x))) +#define ncpy(x) (strcpy((char *) nalloc(strlen(x) + 1), x)) +#ifndef offsetof +#define offsetof(t, m) ((SIZE_T) (((char *) &((t *) 0)->m) - (char *)0)) +#endif +#define streq(x, y) (*(x) == *(y) && strcmp(x, y) == 0) +#define conststrlen(x) (sizeof (x) - 1) + +/* rc prototypes */ + +/* main.c */ +extern char *prompt, *prompt2; +extern Rq *redirq; +extern bool dashdee, dashee, dashvee, dashex, dashell, + dasheye, dashen, dashpee, interactive; +extern int rc_pid; +extern int lineno; + +/* builtins.c */ +extern builtin_t *isbuiltin(char *); +extern void b_exec(char **), funcall(char **), b_dot(char **), b_builtin(char **); +extern char *which(char *, bool); + +/* except.c */ +extern bool nl_on_intr; +extern bool outstanding_cmdarg(void); +extern void pop_cmdarg(bool); +extern void rc_raise(ecodes); +extern void except(ecodes, Edata, Estack *); +extern void unexcept(void); +extern void rc_error(char *); +extern void sigint(int); + +/* exec.c */ +extern void exec(List *, bool); +extern void doredirs(void); + +/* footobar.c */ +extern char *fun2str(char *, Node *); +extern char *list2str(char *, List *); +extern char **list2array(List *, bool); +extern char *get_name(char *); +extern List *parse_var(char *, char *); +extern Node *parse_fn(char *, char *); +extern void initprint(void); +extern void rc_exit(int); /* here for odd reasons; user-defined signal handlers are kept in fn.c */ + +/* getopt.c */ +extern int rc_getopt(int, char **, char *); + +extern int rc_optind, rc_opterr, rc_optopt; +extern char *rc_optarg; + +/* glob.c */ +extern bool lmatch(List *, List *); +extern List *glob(List *); + +/* glom.c */ +extern void assign(List *, List *, bool); +extern void qredir(Node *); +extern List *append(List *, List*); +extern List *flatten(List *); +extern List *glom(Node *); +extern List *concat(List *, List *); +extern List *varsub(List *, List *); +extern List *word(char *, char *); + +/* hash.c */ +extern Htab *fp, *vp; +extern void *lookup(char *, Htab *); +extern Function *get_fn_place(char *); +extern List *varlookup(char *); +extern Node *fnlookup(char *); +extern Variable *get_var_place(char *, bool); +extern bool varassign_string(char *); +extern char **makeenv(void); +extern char *fnlookup_string(char *); +extern char *varlookup_string(char *); +extern void alias(char *, List *, bool); +extern void starassign(char *, char **, bool); +extern void delete_fn(char *); +extern void delete_var(char *, bool); +extern void fnassign(char *, Node *); +extern void fnassign_string(char *); +extern void fnrm(char *); +extern void initenv(char **); +extern void inithash(void); +extern void setsigdefaults(bool); +extern void inithandler(void); +extern void varassign(char *, List *, bool); +extern void varrm(char *, bool); +extern void whatare_all_vars(void); +extern void whatare_all_signals(void); +extern void prettyprint_var(int, char *, List *); +extern void prettyprint_fn(int, char *, Node *); + +/* heredoc.c */ +extern int heredoc(int); +extern int qdoc(Node *, Node *); +extern Hq *hq; + +/* input.c */ +extern void initinput(void); +extern Node *parseline(char *); +extern int gchar(void); +extern void ugchar(int); +extern Node *doit(bool); +extern void flushu(void); +extern void pushfd(int); +extern void pushstring(char **, bool); +extern void popinput(void); +extern void closefds(void); +extern int last; +extern bool rcrc; + +/* lex.c */ +extern int yylex(void); +extern void inityy(void); +extern void yyerror(const char *); +extern void scanerror(char *); +extern void print_prompt2(void); +extern const char nw[], dnw[]; + +/* list.c */ +extern void listfree(List *); +extern List *listcpy(List *, void *(*)(SIZE_T)); +extern SIZE_T listlen(List *); +extern int listnel(List *); + +/* match.c */ +extern bool match(char *, char *, char *); + +/* alloc.c */ +extern void *ealloc(SIZE_T); +extern void *erealloc(void *, SIZE_T); +extern void efree(void *); +extern Block *newblock(void); +extern void *nalloc(SIZE_T); +extern void nfree(void); +extern void restoreblock(Block *); + +/* open.c */ +extern int rc_open(const char *, redirtype); + +/* print.c */ +/* + The following prototype should be: +extern Conv fmtinstall(int, Conv); + but this freaks out SGI's compiler under IRIX3.3.2 +*/ +extern bool (*fmtinstall(int, bool (*)(Format *, int)))(Format *, int); +extern int printfmt(Format *, const char *); +extern int fmtprint(Format *, const char *,...); +extern void fmtappend(Format *, const char *, SIZE_T); +extern void fmtcat(Format *, const char *); +extern int fprint(int fd, const char *fmt,...); +extern char *mprint(const char *fmt,...); +extern char *nprint(const char *fmt,...); +/* + the following macro should by rights be coded as an expression, not + a statement, but certain compilers (notably DEC) have trouble with + void expressions inside the ?: operator. (sheesh, give me a break!) +*/ +#define fmtputc(f, c) {\ + if ((f)->buf >= (f)->bufend)\ + (*(f)->grow)((f), (SIZE_T)1);\ + *(f)->buf++ = (c);\ +} + +/* y.tab.c (parse.y) */ +extern Node *parsetree; +extern int yyparse(void); +extern void initparse(void); + +/* redir.c */ +extern void doredirs(void); + +/* signal.c */ +extern void initsignal(void); +extern void catcher(int); +extern void sigchk(void); +extern void (*rc_signal(int, void (*)(int)))(int); +extern void (*sighandlers[])(int); +extern volatile SIG_ATOMIC_T slow, interrupt_happened; +#define SIGCHK sigchk() + +/* status.c */ +extern int istrue(void); +extern int getstatus(void); +extern void set(bool); +extern void setstatus(int, int); +extern List *sgetstatus(void); +extern void setpipestatus(int [], int); +extern void statprint(int, int); +extern void ssetstatus(char **); + +/* tree.c */ +extern Node *mk(int /*nodetype*/,...); +extern Node *treecpy(Node *, void *(*)(SIZE_T)); +extern void treefree(Node *); + +/* utils.c */ +extern bool isabsolute(char *); +extern int n2u(char *, unsigned int); +extern int rc_read(int, char *, SIZE_T); +extern int mvfd(int, int); +extern int starstrcmp(const void *, const void *); +extern void pr_error(char *); +extern char *clear(char *, SIZE_T); +extern void panic(char *); +extern void uerror(char *); +extern void writeall(int, char *, SIZE_T); + +/* wait.c */ +extern int rc_fork(void); +extern int rc_wait4(int, int *, bool); +extern List *sgetapids(void); +extern void waitforall(void); +extern bool forked; + +/* walk.c */ +extern bool walk(Node *, bool); +extern bool cond; + diff --git a/redir.c b/redir.c new file mode 100644 index 0000000..b582341 --- /dev/null +++ b/redir.c @@ -0,0 +1,77 @@ +/* redir.c: code for opening files and piping heredocs after fork but before exec. */ + +#include "rc.h" + +/* + Walk the redirection queue, and open files and dup2 to them. Also, + here-documents are treated here by dumping them down a pipe. (this + should make here-documents fast on systems with lots of memory which + do pipes right. Under sh, a file is copied to /tmp, and then read + out of /tmp again. I'm interested in knowing how much faster, say, + shar runs when unpacking when invoked with rc instead of sh. On my + sun4/280, it runs in about 60-75% of the time of sh for unpacking + the rc source distribution.) +*/ + +extern void doredirs() { + List *fname; + int fd, p[2]; + Rq *r; + for (r = redirq; r != NULL; r = r->n) { + switch(r->r->type) { + default: + panic("unexpected node in doredirs"); + /* NOTREACHED */ + case nRedir: + if (r->r->u[0].i == rHerestring) { + fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */ + if (pipe(p) < 0) { + uerror("pipe"); + rc_error(NULL); + } + if (rc_fork() == 0) { /* child writes to pipe */ + setsigdefaults(FALSE); + close(p[0]); + if (fname != NULL) + writeall(p[1], fname->w, strlen(fname->w)); + exit(0); + } else { + close(p[1]); + if (mvfd(p[0], r->r->u[1].i) < 0) + rc_error(NULL); + } + } else { + fname = glob(glom(r->r->u[2].p)); + if (fname == NULL) + rc_error("null filename in redirection"); + if (fname->n != NULL) + rc_error("multi-word filename in redirection"); + switch (r->r->u[0].i) { + default: + panic("unexpected node in doredirs"); + /* NOTREACHED */ + case rCreate: case rAppend: case rFrom: + fd = rc_open(fname->w, r->r->u[0].i); + break; + } + if (fd < 0) { + uerror(fname->w); + rc_error(NULL); + } + if (mvfd(fd, r->r->u[1].i) < 0) + rc_error(NULL); + } + break; + case nDup: + if (r->r->u[2].i == -1) + close(r->r->u[1].i); + else if (r->r->u[2].i != r->r->u[1].i) { + if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) { + uerror("dup2"); + rc_error(NULL); + } + } + } + } + redirq = NULL; +} diff --git a/signal.c b/signal.c new file mode 100644 index 0000000..645fb36 --- /dev/null +++ b/signal.c @@ -0,0 +1,75 @@ +/* signal.c: a Hugh-approved signal handler. */ + +#include +#include +#include "rc.h" +#include "sigmsgs.h" +#include "jbwrap.h" + +Jbwrap slowbuf; +volatile SIG_ATOMIC_T slow, interrupt_happened; +void (*sighandlers[NUMOFSIGNALS])(int); + +static volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS]; + +extern void catcher(int s) { + if (forked) + exit(1); /* exit unconditionally on a signal in a child process */ + if (caught[s] == 0) { + sigcount++; + caught[s] = 1; + } + signal(s, catcher); + interrupt_happened = TRUE; +#ifndef SVSIGS + if (slow) + longjmp(slowbuf.j, 1); +#endif +} + +extern void sigchk() { + void (*h)(int); + int s, i; + if (sigcount == 0) + return; /* ho hum; life as usual */ + if (forked) + exit(1); /* exit unconditionally on a signal in a child process */ + for (i = 0, s = -1; i < NUMOFSIGNALS; i++) + if (caught[i] != 0) { + s = i; + --sigcount; + caught[s] = 0; + break; + } + if (s == -1) + panic("all-zero sig vector with nonzero sigcount"); + if ((h = sighandlers[s]) == SIG_DFL) + panic("caught signal set to SIG_DFL"); + if (h == SIG_IGN) + panic("caught signal set to SIG_IGN"); + (*h)(s); +} + +extern void (*rc_signal(int s, void (*h)(int)))(int) { + void (*old)(int); + SIGCHK; + old = sighandlers[s]; + if (h == SIG_DFL || h == SIG_IGN) { + signal(s, h); + sighandlers[s] = h; + } else { + sighandlers[s] = h; + signal(s, catcher); + } + return old; +} + +extern void initsignal() { + void (*h)(int); + int i; + for (i = 1; i < NUMOFSIGNALS; i++) { + if ((h = signal(i, SIG_DFL)) != SIG_DFL) + signal(i, h); + sighandlers[i] = h; + } +} diff --git a/status.c b/status.c new file mode 100644 index 0000000..1b6325b --- /dev/null +++ b/status.c @@ -0,0 +1,139 @@ +/* status.c: functions for printing fancy status messages in rc */ + +#include "rc.h" +#include "sigmsgs.h" + +/* status == the wait() value of the last command in the pipeline, or the last command */ + +static int statuses[512]; +static int pipelength = 1; + +/* + Test to see if rc's status is true. According to td, status is true + if and only if every pipe-member has an exit status of zero. +*/ + +extern int istrue() { + int i; + for (i = 0; i < pipelength; i++) + if (statuses[i] != 0) + return FALSE; + return TRUE; +} + +/* + Return the status as an integer. A status which has low-bits set is + a signal number, whereas a status with high bits set is a value set + from exit(). The presence of a signal just sets status to 1. Also, + a pipeline with nonzero exit statuses in it just sets status to 1. +*/ + +extern int getstatus() { + int s; + if (pipelength > 1) + return !istrue(); + s = statuses[0]; + return (s&0xff) ? 1 : (s >> 8) & 0xff; +} + +extern void set(bool code) { + setstatus(-1, (!code) << 8); /* exit status 1 == 0x100 */ +} + +/* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */ + +extern void setpipestatus(int stats[], int num) { + int i; + for (i = 0; i < (pipelength = num); i++) { + statprint(-1, stats[i]); + statuses[i] = stats[i]; + } +} + +/* set a simple status, as opposed to a pipeline */ + +extern void setstatus(int pid, int i) { + pipelength = 1; + statuses[0] = i; + statprint(pid, i); +} + +/* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */ + +extern void statprint(int pid, int i) { + if (i & 0xff) { + char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f].msg : ""); + if (pid != -1) + fprint(2, "%d: ", pid); + if (i & 0x80) { + if (*msg == '\0') + fprint(2, "core dumped\n"); + else + fprint(2, "%s--core dumped\n", msg); + } else if (*msg != '\0') + fprint(2, "%s\n", msg); + } + if (i != 0 && dashee && !cond) + rc_exit(getstatus()); +} + +/* prepare a list to be passed back. Used whenever $status is dereferenced */ + +extern List *sgetstatus() { + List *r; + int i; + for (r = NULL, i = 0; i < pipelength; i++) { + List *q = nnew(List); + int s = statuses[i]; + int t; + q->n = r; + r = q; + if ((t = s & 0x7f) != 0) { + const char *core = (s & 0x80) ? "+core" : ""; + if (t < NUMOFSIGNALS && *signals[t].name != '\0') + r->w = nprint("%s%s", signals[t].name, core); + else + r->w = nprint("-%d%s", t, core); /* unknown signals are negated */ + } else + r->w = nprint("%d", (s >> 8) & 0xff); + r->m = NULL; + } + return r; +} + +extern void ssetstatus(char **av) { + int i, j, k, l; + bool found; + for (l = 0; av[l] != NULL; l++) + ; /* count up array length */ + --l; + for (i = 0; av[i] != NULL; i++) { + j = a2u(av[i]); + if (j >= 0) { + statuses[l - i] = j << 8; + continue; + } + found = FALSE; + for (k = 0; k < NUMOFSIGNALS; k++) { + if (streq(signals[k].name, av[i])) { + statuses[l - i] = k; + found = TRUE; + break; + } + else { + SIZE_T len = strlen(signals[k].name); + if (strncmp(signals[k].name, av[i], len) == 0 && streq(av[i] + len, "+core")) { + statuses[l - i] = k + 0x80; + found = TRUE; + break; + } + } + } + if (!found) { + fprint(2, "bad status\n"); + set(FALSE); + return; + } + } + pipelength = i; +} diff --git a/tree.c b/tree.c new file mode 100644 index 0000000..6ce1ee8 --- /dev/null +++ b/tree.c @@ -0,0 +1,172 @@ +/* tree.c: functions for manipulating parse-trees. (create, copy, delete) */ + +#include "rc.h" + +/* make a new node, pass it back to yyparse. Used to generate the parsetree. */ + +extern Node *mk(int /*nodetype*/ t,...) { + va_list ap; + Node *n; + va_start(ap, t); + switch (t) { + default: + panic("unexpected node in mk"); + /* NOTREACHED */ + case nDup: + n = nalloc(offsetof(Node, u[3])); + n->u[0].i = va_arg(ap, int); + n->u[1].i = va_arg(ap, int); + n->u[2].i = va_arg(ap, int); + break; + case nWord: case nQword: + n = nalloc(offsetof(Node, u[2])); + n->u[0].s = va_arg(ap, char *); + n->u[1].s = va_arg(ap, char *); + break; + case nBang: case nNowait: + case nCount: case nFlat: case nRmfn: case nSubshell: + case nVar: case nCase: + n = nalloc(offsetof(Node, u[1])); + n->u[0].p = va_arg(ap, Node *); + break; + case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat: + case nElse: case nEpilog: case nIf: case nNewfn: case nCbody: + case nOrelse: case nPre: case nArgs: case nSwitch: + case nMatch: case nVarsub: case nWhile: case nLappend: + n = nalloc(offsetof(Node, u[2])); + n->u[0].p = va_arg(ap, Node *); + n->u[1].p = va_arg(ap, Node *); + break; + case nForin: + n = nalloc(offsetof(Node, u[3])); + n->u[0].p = va_arg(ap, Node *); + n->u[1].p = va_arg(ap, Node *); + n->u[2].p = va_arg(ap, Node *); + break; + case nPipe: + n = nalloc(offsetof(Node, u[4])); + n->u[0].i = va_arg(ap, int); + n->u[1].i = va_arg(ap, int); + n->u[2].p = va_arg(ap, Node *); + n->u[3].p = va_arg(ap, Node *); + break; + case nRedir: + case nNmpipe: + n = nalloc(offsetof(Node, u[3])); + n->u[0].i = va_arg(ap, int); + n->u[1].i = va_arg(ap, int); + n->u[2].p = va_arg(ap, Node *); + break; + } + n->type = t; + va_end(ap); + return n; +} + +/* copy a tree to malloc space. Used when storing the definition of a function */ + +extern Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) { + Node *n; + if (s == NULL) + return NULL; + switch (s->type) { + default: + panic("unexpected node in treecpy"); + /* NOTREACHED */ + case nDup: + n = (*alloc)(offsetof(Node, u[3])); + n->u[0].i = s->u[0].i; + n->u[1].i = s->u[1].i; + n->u[2].i = s->u[2].i; + break; + case nWord: case nQword: + n = (*alloc)(offsetof(Node, u[2])); + n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s); + if (s->u[1].s != NULL) { + SIZE_T i = strlen(s->u[0].s); + n->u[1].s = (*alloc)(i); + memcpy(n->u[1].s, s->u[1].s, i); + } else + n->u[1].s = NULL; + break; + case nBang: case nNowait: case nCase: + case nCount: case nFlat: case nRmfn: case nSubshell: case nVar: + n = (*alloc)(offsetof(Node, u[1])); + n->u[0].p = treecpy(s->u[0].p, alloc); + break; + case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat: + case nElse: case nEpilog: case nIf: case nNewfn: case nCbody: + case nOrelse: case nPre: case nArgs: case nSwitch: + case nMatch: case nVarsub: case nWhile: case nLappend: + n = (*alloc)(offsetof(Node, u[2])); + n->u[0].p = treecpy(s->u[0].p, alloc); + n->u[1].p = treecpy(s->u[1].p, alloc); + break; + case nForin: + n = (*alloc)(offsetof(Node, u[3])); + n->u[0].p = treecpy(s->u[0].p, alloc); + n->u[1].p = treecpy(s->u[1].p, alloc); + n->u[2].p = treecpy(s->u[2].p, alloc); + break; + case nPipe: + n = (*alloc)(offsetof(Node, u[4])); + n->u[0].i = s->u[0].i; + n->u[1].i = s->u[1].i; + n->u[2].p = treecpy(s->u[2].p, alloc); + n->u[3].p = treecpy(s->u[3].p, alloc); + break; + case nRedir: + case nNmpipe: + n = (*alloc)(offsetof(Node, u[3])); + n->u[0].i = s->u[0].i; + n->u[1].i = s->u[1].i; + n->u[2].p = treecpy(s->u[2].p, alloc); + break; + } + n->type = s->type; + return n; +} + +/* free a function definition that is no longer needed */ + +extern void treefree(Node *s) { + if (s == NULL) + return; + switch (s->type) { + default: + panic("unexpected node in treefree"); + /* NOTREACHED */ + case nDup: + break; + case nWord: case nQword: + efree(s->u[0].s); + efree(s->u[1].s); + break; + case nBang: case nNowait: + case nCount: case nFlat: case nRmfn: + case nSubshell: case nVar: case nCase: + treefree(s->u[0].p); + break; + case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat: + case nElse: case nEpilog: case nIf: case nNewfn: + case nOrelse: case nPre: case nArgs: case nCbody: + case nSwitch: case nMatch: case nVarsub: case nWhile: + case nLappend: + treefree(s->u[1].p); + treefree(s->u[0].p); + break; + case nForin: + treefree(s->u[2].p); + treefree(s->u[1].p); + treefree(s->u[0].p); + break; + case nPipe: + treefree(s->u[2].p); + treefree(s->u[3].p); + break; + case nRedir: + case nNmpipe: + treefree(s->u[2].p); + } + efree(s); +} diff --git a/trip.rc b/trip.rc new file mode 100644 index 0000000..ba38207 Binary files /dev/null and b/trip.rc differ diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..6ab303c --- /dev/null +++ b/utils.c @@ -0,0 +1,125 @@ +/* utils.c: functions of general utility */ + +#include +#include +#include "rc.h" +#include "jbwrap.h" + +/* print error with line number on noninteractive shells (i.e., scripts) */ + +extern void pr_error(char *s) { + if (s != NULL) { + if (interactive) + fprint(2, "%s\n", s); + else + fprint(2, "line %d: %s\n", lineno - 1, s); + } +} + +/* our perror */ + +extern void uerror(char *s) { + extern int sys_nerr; + extern char *sys_errlist[]; + if (errno > sys_nerr) + return; + if (s != NULL) + fprint(2, "%s: %s\n", s, sys_errlist[errno]); + else + fprint(2, "%s\n", sys_errlist[errno]); +} + +/* Die horribly. This should never get called. Please let me know if it does. */ + +#define PANICMSG "rc panic: " + +extern void panic(char *s) { + write(2, PANICMSG, conststrlen(PANICMSG)); + write(2, s, strlen(s)); + write(2, "!\n", 2); + exit(1); +} + +/* ascii -> unsigned conversion routines. -1 indicates conversion error. */ + +extern int n2u(char *s, unsigned int base) { + unsigned int i; + for (i = 0; *s != '\0'; s++) { + unsigned int j = (unsigned int) *s - '0'; + if (j >= base) /* small hack with unsigned ints -- one compare for range test */ + return -1; + i = i * base + j; + } + return (int) i; +} + +/* The last word in portable ANSI: a strcmp wrapper for qsort */ + +extern int starstrcmp(const void *s1, const void *s2) { + return strcmp(*(char **)s1, *(char **)s2); +} + +/* tests to see if pathname begins with "/", "./", or "../" */ + +extern bool isabsolute(char *path) { + return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/'))); +} + +/* signal-safe read and write (for BSD slow devices). writeall also allows partial writes */ + +extern void writeall(int fd, char *buf, SIZE_T remain) { + int i; + for (i = 0; remain > 0; buf += i, remain -= i) { + interrupt_happened = FALSE; + if (!setjmp(slowbuf.j)) { + slow = TRUE; + if (interrupt_happened) + break; + else if ((i = write(fd, buf, remain)) <= 0) + break; /* abort silently on errors in write() */ + } else + break; + slow = FALSE; + } + slow = FALSE; + SIGCHK; +} + +extern int rc_read(int fd, char *buf, SIZE_T n) { + long /*ssize_t*/ r; + interrupt_happened = FALSE; + if (!setjmp(slowbuf.j)) { + slow = TRUE; + if (!interrupt_happened) + r = read(fd, buf, n); + else + r = -2; + } else + r = -2; + slow = FALSE; + if (r == -2) { + errno = EINTR; + r = -1; + } + SIGCHK; + return r; +} + +/* clear out z bytes from character string s */ + +extern char *clear(char *s, SIZE_T z) { + while (z != 0) + s[--z] = 0; + return s; +} + +/* duplicate a fd and close the old one only if necessary */ + +extern int mvfd(int i, int j) { + if (i != j) { + int s = dup2(i, j); + close(i); + return s; + } + return 0; +} diff --git a/var.c b/var.c new file mode 100644 index 0000000..ef780b3 --- /dev/null +++ b/var.c @@ -0,0 +1,226 @@ +/* var.c: provide "public" functions for adding and removing variables from the symbol table */ + +#include "rc.h" + +static void colonassign(char *, List *, bool); +static void listassign(char *, List *, bool); +static int hasalias(char *); + +static char *const aliases[] = { + "home", "HOME", "path", "PATH", "cdpath", "CDPATH" +}; + +/* assign a variable in List form to a name, stacking if appropriate */ + +extern void varassign(char *name, List *def, bool stack) { + Variable *new; + List *newdef = listcpy(def, ealloc); /* important to do the listcpy first; get_var_place() frees old values */ + new = get_var_place(name, stack); + new->def = newdef; + new->extdef = NULL; +#ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */ + if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) { + extern void rl_reset_terminal(char *); + rl_reset_terminal(NULL); + } +#endif +} + +/* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */ + +extern bool varassign_string(char *extdef) { + static bool aliasset[arraysize(aliases)] = { + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE + }; + char *name = get_name(extdef); + Variable *new; + int i; + if (name == NULL) + return FALSE; /* add it to bozo env */ + if ((i = hasalias(name)) != -1) { + aliasset[i] = TRUE; + i ^= 1; /* set i to the "opposite" case subscript and */ + if (i&1 && aliasset[i]) /* don't alias variables that are already set in upper case */ + return TRUE; + } + new = get_var_place(name, FALSE); + new->def = NULL; + new->extdef = ealloc(strlen(extdef) + 1); + strcpy(new->extdef, extdef); + if (i != -1) + alias(name, varlookup(name), FALSE); + return TRUE; +} + +/* + Return a List based on a name lookup. If the list is in external (string) form, + convert it to internal (List) form. Treat $n (n is an integer) specially as $*(n). + Also check to see if $status is being dereferenced. (we lazily evaluate the List + associated with $status) +*/ + +extern List *varlookup(char *name) { + Variable *look; + List *ret, *l; + int sub; + if (streq(name, "status")) + return sgetstatus(); + if (streq(name, "apids")) + return sgetapids(); + if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */ + for (l = varlookup("*"); l != NULL && sub != 0; --sub) + l = l->n; + if (l == NULL) + return NULL; + ret = nnew(List); + ret->w = l->w; + ret->m = NULL; + ret->n = NULL; + return ret; + } + look = lookup_var(name); + if (look == NULL) + return NULL; /* not found */ + if (look->def != NULL) + return look->def; + if (look->extdef == NULL) + return NULL; /* variable was set to null, e.g., a=() echo foo */ + ret = parse_var(name, look->extdef); + if (ret == NULL) { + look->extdef = NULL; + return NULL; + } + return look->def = ret; +} + +/* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */ + +extern char *varlookup_string(char *name) { + Variable *look; + look = lookup_var(name); + if (look == NULL) + return NULL; + if (look->extdef != NULL) + return look->extdef; + if (look->def == NULL) + return NULL; + return look->extdef = list2str(name, look->def); +} + +/* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */ + +extern void varrm(char *name, bool stack) { + int i = hasalias(name); + if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */ + varassign("*", varlookup("0"), FALSE); + return; + } + delete_var(name, stack); + if (i != -1) + delete_var(aliases[i^1], stack); +} + +/* assign a value (List) to a variable, using array "a" as input. Used to assign $* */ + +extern void starassign(char *dollarzero, char **a, bool stack) { + List *s, *var; + var = nnew(List); + var->w = dollarzero; + if (*a == NULL) { + var->n = NULL; + varassign("*", var, stack); + return; + } + var->n = s = nnew(List); + while (1) { + s->w = *a++; + if (*a == NULL) { + s->n = NULL; + break; + } else + s = s->n = nnew(List); + } + varassign("*", var, stack); +} + +/* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */ + +static void colonassign(char *name, List *def, bool stack) { + List dud; + if (def == NULL) { + varassign(name, NULL, stack); + return; + } + dud.w = nprint("%-L", def, ":"); + dud.n = NULL; + varassign(name, &dud, stack); +} + +/* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */ + +static void listassign(char *name, List *def, bool stack) { + List *val, *r; + char *v, *w; + if (def == NULL) { + varassign(name, NULL, stack); + return; + } + v = def->w; + r = val = enew(List); + while ((w = strchr(v, ':')) != NULL) { + *w = '\0'; + r->w = ecpy(v); + *w = ':'; + v = w + 1; + r->n = enew(List); + r = r->n; + } + r->w = ecpy(v); + r->n = NULL; + varassign(name, val, stack); +} + +/* check to see if a particular variable is aliased; return -1 on failure, or the index */ + +static int hasalias(char *name) { + int i; + for (i = 0; i < arraysize(aliases); i++) + if (streq(name, aliases[i])) + return i; + return -1; +} + +/* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */ + +extern void alias(char *name, List *s, bool stack) { + static void (*vectors[])(char *, List *, bool) = { + varassign, varassign, colonassign, listassign, colonassign, listassign + }; + int i = hasalias(name); + if (i != -1) + (*vectors[i])(aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */ +} + +extern void prettyprint_var(int fd, char *name, List *s) { + int i; + static const char * const keywords[] = { + "if", "in", "fn", "for", "else", "switch", "while", "case" + }; + if (s == NULL) { + fprint(fd, "%S=()\n", name); + return; + } + if (streq(name, "*")) { + s = s->n; + if (s == NULL) + return; /* Don't print $0, and if $* is not set, skip it */ + } + for (i = 0; i < arraysize(keywords); i++) + if (streq(keywords[i], name)) { + fprint(fd, "%#S=", name); + goto value; + } + fprint(fd, "%S=", name); +value: + fprint(fd, s->n == NULL ? "%L\n" : "(%L)\n", s, " "); +} diff --git a/version.c b/version.c new file mode 100644 index 0000000..0cdc517 --- /dev/null +++ b/version.c @@ -0,0 +1 @@ +const char id[] = "@(#)rc version 1.4, 5/26/92."; diff --git a/wait.c b/wait.c new file mode 100644 index 0000000..a70acee --- /dev/null +++ b/wait.c @@ -0,0 +1,124 @@ +#include +#include +#include "rc.h" +#include "jbwrap.h" + +bool forked = FALSE; + +static int rc_wait(int *); + +typedef struct Pid Pid; + +static struct Pid { + int pid, stat; + bool alive; + Pid *n; +} *plist = NULL; + +extern int rc_fork() { + Pid *new = enew(Pid); + int pid = fork(); + switch (pid) { + case -1: + uerror("fork"); + rc_error(NULL); + /* NOTREACHED */ + case 0: + forked = TRUE; + SIGCHK; + return 0; + default: + new->pid = pid; + new->alive = TRUE; + new->n = plist; + plist = new; + return pid; + } +} + +extern int rc_wait4(int pid, int *stat, bool nointr) { + Pid *r, *prev; + int ret; + /* first look for a child which may already have exited */ +again: for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n) + if (r->pid == pid) + break; + if (r == NULL) { + errno = ECHILD; /* no children */ + uerror("wait"); + *stat = 0x100; /* exit(1) */ + return -1; + } + if (r->alive) { + while (pid != (ret = rc_wait(stat))) { + Pid *q; + if (ret < 0) { + if (nointr) + goto again; + return ret; + } + for (q = plist; q != NULL; q = q->n) + if (q->pid == ret) { + q->alive = FALSE; + q->stat = *stat; + break; + } + } + } else + *stat = r->stat; + if (prev == NULL) + plist = r->n; /* remove element from head of list */ + else + prev->n = r->n; + efree(r); + return pid; +} + +extern List *sgetapids() { + List *r; + Pid *p; + for (r = NULL, p = plist; p != NULL; p = p->n) { + List *q; + if (!p->alive) + continue; + q = nnew(List); + q->w = nprint("%d", p->pid); + q->m = NULL; + q->n = r; + r = q; + } + return r; +} + +extern void waitforall() { + int stat; + while (plist != NULL) { + int pid = rc_wait4(plist->pid, &stat, FALSE); + if (pid > 0) + setstatus(pid, stat); + else + set(FALSE); + SIGCHK; + } +} + +/* + rc_wait: a wait() wrapper that interfaces wait() w/rc signals. + Note that the signal queue is not checked in this fn; someone + may want to resume the wait() without delivering any signals. +*/ + +static int rc_wait(int *stat) { + int r; + interrupt_happened = FALSE; + if (!setjmp(slowbuf.j)) { + slow = TRUE; + if (!interrupt_happened) + r = wait(stat); + else + r = -1; + } else + r = -1; + slow = FALSE; + return r; +} diff --git a/walk.c b/walk.c new file mode 100644 index 0000000..c18921c --- /dev/null +++ b/walk.c @@ -0,0 +1,344 @@ +/* walk.c: walks the parse tree. */ + +#include +#include +#include "rc.h" +#include "jbwrap.h" + +/* + global which indicates whether rc is executing a test; + used by rc -e so that if (false) does not exit. +*/ +bool cond = FALSE; + +static bool isallpre(Node *); +static bool dofork(bool); +static void dopipe(Node *); + +/* Tail-recursive version of walk() */ + +#define WALK(x, y) { n = x; parent = y; goto top; } + +/* walk the parse-tree. "obvious". */ + +extern bool walk(Node *n, bool parent) { +top: SIGCHK; + if (n == NULL) { + if (!parent) + exit(0); + set(TRUE); + return TRUE; + } + switch (n->type) { + case nArgs: case nBackq: case nConcat: case nCount: + case nFlat: case nLappend: case nRedir: case nVar: + case nVarsub: case nWord: case nQword: + exec(glob(glom(n)), parent); /* simple command */ + break; + case nBody: + walk(n->u[0].p, TRUE); + WALK(n->u[1].p, parent); + /* WALK doesn't fall through */ + case nNowait: { + int pid; + if ((pid = rc_fork()) == 0) { +#if !defined(NOJOB) && defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP) + setsigdefaults(FALSE); + rc_signal(SIGTTOU, SIG_IGN); /* Berkeleyized version: put it in a new pgroup. */ + rc_signal(SIGTTIN, SIG_IGN); + rc_signal(SIGTSTP, SIG_IGN); + setpgrp(0, getpid()); +#else + setsigdefaults(TRUE); /* ignore SIGINT, SIGQUIT, SIGTERM */ +#endif + mvfd(rc_open("/dev/null", rFrom), 0); + walk(n->u[0].p, FALSE); + exit(getstatus()); + } + if (interactive) + fprint(2, "%d\n", pid); + varassign("apid", word(nprint("%d", pid), NULL), FALSE); + redirq = NULL; /* kill pre-redir queue */ + break; + } + case nAndalso: { + bool oldcond = cond; + cond = TRUE; + if (walk(n->u[0].p, TRUE)) { + cond = oldcond; + WALK(n->u[1].p, parent); + } else + cond = oldcond; + break; + } + case nOrelse: { + bool oldcond = cond; + cond = TRUE; + if (!walk(n->u[0].p, TRUE)) { + cond = oldcond; + WALK(n->u[1].p, parent); + } else + cond = oldcond; + break; + } + case nBang: + set(!walk(n->u[0].p, TRUE)); + break; + case nIf: { + bool oldcond = cond; + Node *true_cmd = n->u[1].p, *false_cmd = NULL; + if (true_cmd != NULL && true_cmd->type == nElse) { + false_cmd = true_cmd->u[1].p; + true_cmd = true_cmd->u[0].p; + } + cond = TRUE; + if (!walk(n->u[0].p, TRUE)) + true_cmd = false_cmd; /* run the else clause */ + cond = oldcond; + WALK(true_cmd, parent); + } + case nWhile: { + Jbwrap j; + Edata jbreak; + Estack e1, e2; + bool testtrue, oldcond = cond; + cond = TRUE; + if (!walk(n->u[0].p, TRUE)) { /* prevent spurious breaks inside test */ + cond = oldcond; + break; + } + if (setjmp(j.j)) + break; + jbreak.jb = &j; + except(eBreak, jbreak, &e1); + do { + Edata block; + block.b = newblock(); + cond = oldcond; + except(eArena, block, &e2); + walk(n->u[1].p, TRUE); + testtrue = walk(n->u[0].p, TRUE); + unexcept(); /* eArena */ + cond = TRUE; + } while (testtrue); + cond = oldcond; + unexcept(); /* eBreak */ + break; + } + case nForin: { + List *l, *var = glom(n->u[0].p); + Jbwrap j; + Estack e1, e2; + Edata jbreak; + if (setjmp(j.j)) + break; + jbreak.jb = &j; + except(eBreak, jbreak, &e1); + for (l = listcpy(glob(glom(n->u[1].p)), nalloc); l != NULL; l = l->n) { + Edata block; + assign(var, word(l->w, NULL), FALSE); + block.b = newblock(); + except(eArena, block, &e2); + walk(n->u[2].p, TRUE); + unexcept(); /* eArena */ + } + unexcept(); /* eBreak */ + break; + } + case nSubshell: + if (dofork(TRUE)) { + setsigdefaults(FALSE); + walk(n->u[0].p, FALSE); + rc_exit(getstatus()); + } + break; + case nAssign: + if (n->u[0].p == NULL) + rc_error("null variable name"); + assign(glom(n->u[0].p), glob(glom(n->u[1].p)), FALSE); + set(TRUE); + break; + case nPipe: + dopipe(n); + break; + case nNewfn: { + List *l = glom(n->u[0].p); + if (l == NULL) + rc_error("null function name"); + while (l != NULL) { + if (dashex) + prettyprint_fn(2, l->w, n->u[1].p); + fnassign(l->w, n->u[1].p); + l = l->n; + } + set(TRUE); + break; + } + case nRmfn: { + List *l = glom(n->u[0].p); + while (l != NULL) { + if (dashex) + fprint(2, "fn %S\n", l->w); + fnrm(l->w); + l = l->n; + } + set(TRUE); + break; + } + case nDup: + redirq = NULL; + break; /* Null command */ + case nMatch: { + List *a = glob(glom(n->u[0].p)), *b = glom(n->u[1].p); + if (dashex) + fprint(2, (a != NULL && a->n != NULL) ? "~ (%L) %L\n" : "~ %L %L\n", a, " ", b, " "); + set(lmatch(a, b)); + break; + } + case nSwitch: { + List *v = glom(n->u[0].p); + while (1) { + do { + n = n->u[1].p; + if (n == NULL) + return istrue(); + } while (n->u[0].p == NULL || n->u[0].p->type != nCase); + if (lmatch(v, glom(n->u[0].p->u[0].p))) { + for (n = n->u[1].p; n != NULL && (n->u[0].p == NULL || n->u[0].p->type != nCase); n = n->u[1].p) + walk(n->u[0].p, TRUE); + break; + } + } + break; + } + case nPre: { + List *v; + if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) { + qredir(n->u[0].p); + walk(n->u[1].p, parent); + } else if (n->u[0].p->type == nAssign) { + if (isallpre(n->u[1].p)) { + walk(n->u[0].p, TRUE); + WALK(n->u[1].p, parent); + } else { + Estack e; + Edata var; + v = glom(n->u[0].p->u[0].p); + assign(v, glob(glom(n->u[0].p->u[1].p)), TRUE); + var.name = v->w; + except(eVarstack, var, &e); + walk(n->u[1].p, parent); + varrm(v->w, TRUE); + unexcept(); /* eVarstack */ + } + } else + panic("unexpected node in preredir section of walk"); + break; + } + case nBrace: + if (n->u[1].p == NULL) { + WALK(n->u[0].p, parent); + } else if (dofork(parent)) { + setsigdefaults(FALSE); + walk(n->u[1].p, TRUE); /* Do redirections */ + redirq = NULL; /* Reset redirection queue */ + walk(n->u[0].p, FALSE); /* Do commands */ + rc_exit(getstatus()); + /* NOTREACHED */ + } + break; + case nEpilog: + qredir(n->u[0].p); + if (n->u[1].p != NULL) { + WALK(n->u[1].p, parent); /* Do more redirections. */ + } else { + doredirs(); /* Okay, we hit the bottom. */ + } + break; + case nNmpipe: + rc_error("named pipes cannot be executed as commands"); + /* NOTREACHED */ + default: + panic("unknown node in walk"); + /* NOTREACHED */ + } + return istrue(); +} + +/* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */ + +static bool isallpre(Node *n) { + while (n != NULL && n->type == nPre) + n = n->u[1].p; + return n == NULL || n->type == nRedir || n->type == nAssign || n->type == nDup; +} + +/* + A code-saver. Forks, child returns (for further processing in walk()), and the parent + waits for the child to finish, setting $status appropriately. +*/ + +static bool dofork(bool parent) { + int pid, sp; + + if (!parent || (pid = rc_fork()) == 0) + return TRUE; + redirq = NULL; /* clear out the pre-redirection queue in the parent */ + rc_wait4(pid, &sp, TRUE); + setstatus(-1, sp); + SIGCHK; + return FALSE; +} + +static void dopipe(Node *n) { + int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2]; + bool intr; + Node *r; + + fd_prev = fd_out = 1; + for (r = n, i = 0; r != NULL && r->type == nPipe; r = r->u[2].p, i++) { + if (i > 500) /* the only hard-wired limit in rc? */ + rc_error("pipe too long"); + if (pipe(p) < 0) { + uerror("pipe"); + rc_error(NULL); + } + if ((pid = rc_fork()) == 0) { + setsigdefaults(FALSE); + redirq = NULL; /* clear preredir queue */ + mvfd(p[0], r->u[1].i); + if (fd_prev != 1) + mvfd(fd_prev, fd_out); + close(p[1]); + walk(r->u[3].p, FALSE); + exit(getstatus()); + } + if (fd_prev != 1) + close(fd_prev); /* parent must close all pipe fd's */ + pids[i] = pid; + fd_prev = p[1]; + fd_out = r->u[0].i; + close(p[0]); + } + if ((pid = rc_fork()) == 0) { + setsigdefaults(FALSE); + mvfd(fd_prev, fd_out); + walk(r, FALSE); + exit(getstatus()); + /* NOTREACHED */ + } + redirq = NULL; /* clear preredir queue */ + close(fd_prev); + pids[i++] = pid; + + /* collect statuses */ + + intr = FALSE; + for (j = 0; j < i; j++) { + rc_wait4(pids[j], &sp, TRUE); + stats[j] = sp; + intr |= (sp == SIGINT); + } + setpipestatus(stats, i); + SIGCHK; +} diff --git a/which.c b/which.c new file mode 100644 index 0000000..a9e2f65 --- /dev/null +++ b/which.c @@ -0,0 +1,114 @@ +/* which.c: check to see if a file is executable. + + This function was originally written with Maarten Litmaath's which.c as + a template, but was changed in order to accomodate the possibility of + rc's running setuid or the possibility of executing files not in the + primary group. Much of this file has been re-vamped by Paul Haahr. + I re-re-vamped the functions that Paul supplied to correct minor bugs + and to strip out unneeded functionality. +*/ + +#include +#include +#include +#include +#include "rc.h" + +#define X_USR 0100 +#define X_GRP 0010 +#define X_OTH 0001 +#define X_ALL (X_USR|X_GRP|X_OTH) + +extern int stat(const char *, struct stat *); + +static bool initialized = FALSE; +static int uid, gid; + +#ifdef NGROUPS +static int ngroups, gidset[NGROUPS]; + +/* determine whether gid lies in gidset */ + +static int ingidset(int g) { + int i; + for (i = 0; i < ngroups; i++) + if (g == gidset[i]) + return 1; + return 0; +} +#endif + +/* + A home-grown access/stat. Does the right thing for group-executable files. + Returns a bool instead of this -1 nonsense. +*/ + +static bool rc_access(char *path, bool verbose) { + struct stat st; + int mask; + if (stat(path, &st) != 0) { + if (verbose) /* verbose flag only set for absolute pathname */ + uerror(path); + return FALSE; + } + if (uid == 0) + mask = X_ALL; + else if (uid == st.st_uid) + mask = X_USR; +#ifdef NGROUPS + else if (gid == st.st_gid || ingidset(st.st_gid)) +#else + else if (gid == st.st_gid) +#endif + mask = X_GRP; + else + mask = X_OTH; + if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask)) + return TRUE; + errno = EACCES; + if (verbose) + uerror(path); + return FALSE; +} + +/* return a full pathname by searching $path, and by checking the status of the file */ + +extern char *which(char *name, bool verbose) { + static char *test = NULL; + static SIZE_T testlen = 0; + List *path; + int len; + if (name == NULL) /* no filename? can happen with "> foo" as a command */ + return NULL; + if (!initialized) { + initialized = TRUE; + uid = geteuid(); + gid = getegid(); +#ifdef NGROUPS + ngroups = getgroups(NGROUPS, gidset); +#endif + } + if (isabsolute(name)) /* absolute pathname? */ + return rc_access(name, verbose) ? name : NULL; + len = strlen(name); + for (path = varlookup("path"); path != NULL; path = path->n) { + SIZE_T need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */ + if (testlen < need) { + efree(test); + test = ealloc(testlen = need); + } + if (*path->w == '\0') { + strcpy(test, name); + } else { + strcpy(test, path->w); + if (!streq(test, "/")) /* "//" is special to POSIX */ + strcat(test, "/"); + strcat(test, name); + } + if (rc_access(test, FALSE)) + return test; + } + if (verbose) + fprint(2, "%s not found\n", name); + return NULL; +} -- cgit v1.2.3 From a076248389c82276e079756bee26c011b03f70f2 Mon Sep 17 00:00:00 2001 From: Byron Rakitzis Date: Mon, 7 Mar 1994 00:00:01 +0000 Subject: beta: rc-1.5betadev1 --- CHANGES | 92 ++++++++++++++++++++++++++++ Makefile | 2 +- README | 13 +++- builtins.c | 60 +++++++++++++------ except.c | 2 +- exec.c | 13 +++- fn.c | 33 ++++------ footobar.c | 175 ++++++++++++++++++++++-------------------------------- glob.c | 50 ++++++++++++---- glom.c | 20 ++++--- hash.c | 16 ++--- history/history.c | 12 +++- input.c | 83 +++++++++++--------------- lex.c | 5 +- main.c | 18 ++++-- nalloc.c | 2 + print.c | 20 +++++-- proto.h | 1 + rc.1 | 7 ++- rc.h | 8 +-- signal.c | 4 +- status.c | 34 +++++++---- trip.rc | Bin 14684 -> 14684 bytes utils.c | 11 +--- var.c | 11 ++-- version.c | 2 +- wait.c | 7 ++- walk.c | 30 +++++++--- 28 files changed, 446 insertions(+), 285 deletions(-) diff --git a/CHANGES b/CHANGES index 8456cd5..767bd08 100644 --- a/CHANGES +++ b/CHANGES @@ -169,3 +169,95 @@ on. A memory leak in treefree() was plugged up --- the root node of a function was not getting freed. + +Changes since rc-1.4: + +General changes: + + Some small memory leaks/uninit references revealed by Purify. + + $bqstatus for querying the exit status of a backquote. + + Globbing through unreadable directories. + + More options to whatis. + + History append which always re-opens the file (avoids + inconsistencies over multiple NFS-mounted accesses to + $history). + + Support "rc -s". + +--------- + +Makefile: Added comment referring to README for yacc/malloc problem. + +uiltins.c: Added more options to whatis, protected rlimit prototypes + with #ifndef SYSVR4, renamed SIGCHK to sigchk. + +except.c: Patched nl_on_intr printing to happen only in interactive + shells. + +exec.c: Added comment explaining nl_on_intr variable, renamed SIGCHK + to sigchk. + +fn.c: Replaced by-hand consing of exception stack etc. for signal + handler execution with call to funcall(). Replaced fun2str + call with call on print routines. + +footobar.c: Got rid of memory leak in get_name(), parenthesize count, + flat and var nodes for correctness in unparsing, removed + list2str, made get_name use nalloc space, merge in a + better parse_var from es. + +glob.c: Split out a test so that closedir is called correctly, renamed + SIGCHK to sigchk. + +glom.c: Added bqstatus, renamed SIGCHK to sigchk, removed spurious + setsigdefaults, patched uninit memory reference, rename + "clear" to "memzero", wait for bq subproc to finish on EINTR. + +hash.c: Added options to function/variable print code. + +history/history.c: Added '@' to the list of chars which can precede an + ignored '-'. + +input.c: Got rid of tiny memory leak in closefds, got rid of uninit + memory reference in popinput, moved nul ignored check into + realgchar(), changed history append to always reopen the + history file, replaced SIGCHK with sigchk. Freed memory + returned by call to readline(). + +lex.c: Corrected typo in comment, moved nul character ignore code + to input routines. + +main.c: Added -s flag. + +nalloc.c: Added convenience feature to erealloc. (Allow NULL parameter) + +print.c: Changed use of va_start so broken compilers can compile + print code. + +proto.h: Added fake memset. + +rc.h: Replaced clear() function prototype with a macro call on + memset(), removed SIGCHK, fixed prototypes. + +signal.c: Removed unconditional exit in catcher code, renamed SIGCHK + to sigchk. + +status.c: Rewrite sgetstatus breaking out strstatus so that bqstatus + can be set from glom routines. + +utils.c: Got rid of clear() (use memset from C library), rename SIGCHK + to sigchk. + +var.c: Got rid of memory leak in listassign(), converted list2str() + call to something using the print routines. + +version.c: New version string. + +wait.c: Got rid of memory leak in rc_fork, renamed SIGCHK to sigchk. + +walk.c: Fixed pre-redirection bug, removed spurious setsigdefaults(), + renamed SIGCHK to sigchk. diff --git a/Makefile b/Makefile index 7306f36..477ff76 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ CFLAGS= LDFLAGS= # You may substitute "bison -y" for yacc. (You want to choose the one that -# makes a smaller y.tab.c.) +# makes a smaller y.tab.c. Also see the README about Sun's yacc.) YACC=yacc OBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \ diff --git a/README b/README index 401fa8f..bbb1c9e 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is release 1.4 of rc. +This is release 1.5 of rc. Read COPYRIGHT for copying information. All files are @@ -63,6 +63,17 @@ to get rc to work in a reasonable fashion on a real (i.e., commercial, non-Labs) UNIX system; a few were changes motivated by concern about some inadequacies in the original design. +YACC + +The yacc that Sun ships with SunOS 4.1.1 calls malloc() to allocate +space for the state stack, and requires a call to YYACCEPT or YYABORT +to free this memory. This means that if rc takes an interrupt while +parsing a command (say, if ^C is typed), yacc will leak away this +memory. The solution is to use a yacc which statically allocates +this array, such as the yacc in the BSD distribution. Berkeley yacc- +generated y.tab.c and y.tab.h are shipped with rc in case you cannot +get hold of Berkeley yacc. + OLD C If you need to convert rc's source into K&R C, you need to run the diff --git a/builtins.c b/builtins.c index d9b2e2e..77f75df 100644 --- a/builtins.c +++ b/builtins.c @@ -12,6 +12,7 @@ #include #include "rc.h" #include "jbwrap.h" +#include "sigmsgs.h" #ifndef NOLIMITS #include #include @@ -266,7 +267,7 @@ static void b_wait(char **av) { setstatus(pid, stat); else set(FALSE); - SIGCHK; + sigchk(); } /* @@ -274,46 +275,69 @@ static void b_wait(char **av) { is defined as a variable, function or pathname. */ +#define not(b) ((b)^TRUE) +#define show(b) (not(eff|vee|pee|bee|ess)|(b)) + +static bool issig(char *s) { + int i; + for (i = 0; i < NUMOFSIGNALS; i++) + if (streq(s, signals[i].name)) + return TRUE; + return FALSE; +} + static void b_whatis(char **av) { + bool ess, eff, vee, pee, bee; bool f, found; - bool ess = FALSE; int i, ac, c; List *s; Node *n; char *e; for (rc_optind = ac = 0; av[ac] != NULL; ac++) ; /* count the arguments for getopt */ - while ((c = rc_getopt(ac, av, "s")) == 's') - ess = TRUE; - if (c != -1) { - set(FALSE); - return; - } + ess = eff = vee = pee = bee = FALSE; + while ((c = rc_getopt(ac, av, "sfvpb")) != -1) + switch (c) { + default: set(FALSE); return; + case 's': ess = TRUE; break; + case 'f': eff = TRUE; break; + case 'v': vee = TRUE; break; + case 'p': pee = TRUE; break; + case 'b': bee = TRUE; break; + } av += rc_optind; - if (*av == NULL && !ess) { - whatare_all_vars(); + if (*av == NULL) { + if (vee|eff) + whatare_all_vars(eff, vee); + if (ess) + whatare_all_signals(); + if (bee) + for (i = 0; i < arraysize(builtins); i++) + fprint(1, "builtin %s\n", builtins[i].name); + if (pee) + fprint(2, "whatis -p: must specify argument\n"); + if (show(FALSE)) /* no options? */ + whatare_all_vars(TRUE, TRUE); set(TRUE); return; } - if (ess) - whatare_all_signals(); found = TRUE; for (i = 0; av[i] != NULL; i++) { f = FALSE; errno = ENOENT; - if ((s = varlookup(av[i])) != NULL) { + if (show(vee) && (s = varlookup(av[i])) != NULL) { f = TRUE; prettyprint_var(1, av[i], s); } - if ((n = fnlookup(av[i])) != NULL) { + if (((show(ess)&&issig(av[i])) || show(eff)) && (n = fnlookup(av[i])) != NULL) { f = TRUE; prettyprint_fn(1, av[i], n); - } else if (isbuiltin(av[i]) != NULL) { + } else if (show(bee) && isbuiltin(av[i]) != NULL) { f = TRUE; fprint(1, "builtin %s\n", av[i]); - } else if ((e = which(av[i], FALSE)) != NULL) { + } else if (show(pee) && (e = which(av[i], FALSE)) != NULL) { f = TRUE; - fprint(1, "%s\n", e); + fprint(1, "%S\n", e); } if (!f) { found = FALSE; @@ -440,8 +464,10 @@ static const Limit limits[] = { { NULL, 0, NULL } }; +#ifndef SYSVR4 extern int getrlimit(int, struct rlimit *); extern int setrlimit(int, struct rlimit *); +#endif static void printlimit(const Limit *limit, bool hard) { struct rlimit rlim; diff --git a/except.c b/except.c index 48ea008..241d887 100644 --- a/except.c +++ b/except.c @@ -131,7 +131,7 @@ extern void sigint(int s) { if (s != SIGINT) panic("s != SIGINT in sigint catcher"); /* this is the newline you see when you hit ^C while typing a command */ - if (nl_on_intr) + if (interactive && nl_on_intr) fprint(2, "\n"); nl_on_intr = TRUE; redirq = NULL; diff --git a/exec.c b/exec.c index 38d627c..8ed8ead 100644 --- a/exec.c +++ b/exec.c @@ -110,9 +110,20 @@ extern void exec(List *s, bool parent) { redirq = NULL; rc_wait4(pid, &stat, TRUE); setstatus(-1, stat); + /* + There is a very good reason for having this weird + nl_on_intr variable: when rc and its child both + process a SIGINT, (i.e., the child has a SIGINT + catcher installed) then you don't want rc to print + a newline when the child finally exits. Here's an + example: ed, , . rc does not + and should not print a newline before the next + prompt, even though there's a SIGINT in its signal + vector. + */ if ((stat & 0xff) == 0) nl_on_intr = FALSE; - SIGCHK; + sigchk(); nl_on_intr = TRUE; pop_cmdarg(TRUE); } diff --git a/fn.c b/fn.c index 02de02b..56c5e86 100644 --- a/fn.c +++ b/fn.c @@ -12,9 +12,9 @@ static void fn_handler(int), dud_handler(int); static bool runexit = FALSE; static Node *handlers[NUMOFSIGNALS], null; -static void (*def_sigint)(int) = SIG_DFL, - (*def_sigquit)(int) = SIG_DFL, - (*def_sigterm)(int) = SIG_DFL; +static void (*def_sigint)(int) = SIG_DFL; +static void (*def_sigquit)(int) = SIG_DFL; +static void (*def_sigterm)(int) = SIG_DFL; /* Set signals to default values for rc. This means that interactive @@ -106,13 +106,12 @@ extern void setsigdefaults(bool sysvbackground) { /* rc's exit. if runexit is set, run the sigexit function. */ extern void rc_exit(int stat) { - static char *sigexit[2] = { - "sigexit", - NULL - }; if (runexit) { + char *sig[2]; + sig[0] = "sigexit"; + sig[1] = NULL; runexit = FALSE; - funcall(sigexit); + funcall(sig); stat = getstatus(); } exit(stat); @@ -121,22 +120,14 @@ extern void rc_exit(int stat) { /* The signal handler for all functions. calls walk() */ static void fn_handler(int s) { - List *dollarzero; - Estack e; - Edata star; + char *sig[2]; int olderrno; if (s < 1 || s >= NUMOFSIGNALS) panic("unknown signal"); olderrno = errno; - dollarzero = nnew(List); - dollarzero->w = signals[s].name; - dollarzero->n = NULL; - varassign("*", dollarzero, TRUE); - star.name = "*"; - except(eVarstack, star, &e); - walk(handlers[s], TRUE); - varrm("*", TRUE); - unexcept(); /* eVarstack */ + sig[0] = signals[s].name; + sig[1] = NULL; + funcall(sig); errno = olderrno; } @@ -217,7 +208,7 @@ extern char *fnlookup_string(char *name) { return NULL; if (look->extdef != NULL) return look->extdef; - return look->extdef = fun2str(name, look->def); + return look->extdef = mprint("fn_%F={%T}", name, look->def); } /* diff --git a/footobar.c b/footobar.c index f50db3c..2440f5a 100644 --- a/footobar.c +++ b/footobar.c @@ -5,15 +5,12 @@ #include "rc.h" -#define FSCHAR '\1' -#define FSSTRING "\1" - -static char *getenvw(char *, bool); +/* protect an exported name from brain-dead shells */ #ifdef PROTECT_ENV -static bool Fconv(Format *f, int ignore) { /* protect an exported name from brain-dead shells */ - int c; +static bool Fconv(Format *f, int ignore) { unsigned const char *s = va_arg(f->args, unsigned const char *); + int c; while ((c = *s++) != '\0') if (dnw[c] || c == '*' || (c == '_' && *s == '_')) @@ -24,12 +21,6 @@ static bool Fconv(Format *f, int ignore) { /* protect an exported name from brai } #endif -/* used to turn a function in Node * form into something we can export to the environment */ - -extern char *fun2str(char *name, Node *n) { - return mprint("fn_%F={%T}", name, n); -} - /* convert a redirection to a printable form */ static bool Dconv(Format *f, int ignore) { @@ -63,14 +54,11 @@ static bool Tconv(Format *f, int ignore) { switch (n->type) { case nWord: fmtprint(f, "%S", n->u[0].s); break; case nQword: fmtprint(f, "%#S", n->u[0].s); break; - case nBang: fmtprint(f, "! %T", n->u[0].p); break; + case nBang: fmtprint(f, "!%T", n->u[0].p); break; case nCase: fmtprint(f, "case %T", n->u[0].p); break; case nNowait: fmtprint(f, "%T&", n->u[0].p); break; - case nCount: fmtprint(f, "$#%T", n->u[0].p); break; - case nFlat: fmtprint(f, "$^%T", n->u[0].p); break; case nRmfn: fmtprint(f, "fn %T", n->u[0].p); break; case nSubshell: fmtprint(f, "@ %T", n->u[0].p); break; - case nVar: fmtprint(f, "$%T", n->u[0].p); break; case nAndalso: fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p); break; case nAssign: fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p); break; case nConcat: fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p); break; @@ -81,10 +69,25 @@ static bool Tconv(Format *f, int ignore) { case nArgs: fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); break; case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break; case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break; - case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break; case nLappend: fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); break; case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break; + case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; + case nCount: case nFlat: case nVar: { + char *lp = "", *rp = ""; + Node *n0 = n->u[0].p; + + if (n0->type != nWord && n0->type != nQword) + lp = "(", rp = ")"; + + switch (n->type) { + default: panic("this can't happen"); break; + case nCount: fmtprint(f, "$#%s%T%s", lp, n0, rp); break; + case nFlat: fmtprint(f, "$^%s%T%s", lp, n0, rp); break; + case nVar: fmtprint(f, "$%s%T%s", lp, n0, rp); break; + } + break; + } case nDup: if (n->u[2].i != -1) fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i); @@ -154,65 +157,41 @@ static bool Tconv(Format *f, int ignore) { return FALSE; } -/* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */ - -extern char *list2str(char *name, List *s) { - SIZE_T size, step; - List *t; - char *w, *x; - name = nprint("%F", name); - size = strlen(name) + listlen(s); - w = ealloc(size + 2); - t = s; - x = w; - strcpy(x, name); - strcpy(x += strlen(name), "="); - strcpy(x += conststrlen("="), t->w); - for (x += strlen(t->w), s = s->n; s != NULL; s = s->n) { - memcpy(x, FSSTRING, step = conststrlen(FSSTRING)); - x += step; - memcpy(x, s->w, step = strlen(s->w)); - x += step; - } - *x = '\0'; - return w; -} - /* convert a List to an array, for execve() */ extern char **list2array(List *s, bool print) { - char **av; - int i; + char **argv, **av; - /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */ - av = nalloc((listnel(s) + 4) * sizeof (char *)); - av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */ if (print) fprint(2, "%L\n", s, " "); - for (i = 0; s != NULL; i++) { - av[i] = s->w; + /* + Allocate 3 extra spots (2 for the fake execve & 1 for defaulting to + sh) and hide these from exec(). + */ + argv = av = (char **) nalloc((listnel(s) + 4) * sizeof *av) + 3; + while (s != NULL) { + *av++ = s->w; s = s->n; } - av[i] = NULL; - return av; + *av = NULL; + return argv; } -/* figure out the name of a variable given an environment string. copy this into malloc space */ +/* figure out the name of a variable given an environment string. */ extern char *get_name(char *s) { + char *eq = strchr(s, '='); + char *r, *result; int c; - SIZE_T i; - char *r, *namebuf; - for (i = 0; s[i] != '\0' && s[i] != '='; i++) - ; - if (s[i] == '\0') + + if (eq == NULL) return NULL; - r = namebuf = ealloc(i + 1); + r = result = nalloc(eq - s + 1); while (1) switch (c = *s++) { case '=': *r++ = '\0'; - return namebuf; + return result; #ifdef PROTECT_ENV case '_': if (*s == '_') { @@ -233,55 +212,45 @@ extern char *get_name(char *s) { } } -/* get the next word from a variable's value as represented in the environment. */ - -static char *getenvw(char *s, bool saw_alpha) { - SIZE_T i; - char *r; - for (i = 0; s[i] != '\0' && s[i] != FSCHAR; i++) - ; - if (i == 0) { - if (s[i] == '\0' && !saw_alpha) - return NULL; - else - return clear(enew(char), (SIZE_T) 1); - } - r = strncpy(ealloc(i + 1), s, i); - r[i] = '\0'; - return r; -} +/* + Hacky routine to split a ^A-separated environment variable. Scans + backwards. Be VERY CAREFUL with the loop boundary conditions. e.g., + notice what happens when there is no ^A in the extdef. (It does + the right thing, of course :-) +*/ -/* take an environment entry for a variable (elements ^A separated) and turn it into a List */ +#define skipleft(p) do --p; while (*p != '\0' && *p != '\001'); extern List *parse_var(char *name, char *extdef) { - List *r, *top; - char *f; - bool saw_alpha; - top = r = enew(List); - extdef = strchr(extdef, '=') + 1; - if ((f = getenvw(extdef, FALSE)) == NULL) { - r->w = ""; - r->m = NULL; - r->n = NULL; - } else { - while (1) { - r->w = f; - r->m = NULL; - extdef += strlen(f); - if (*extdef == FSCHAR) { - extdef++; - saw_alpha = TRUE; - } else { - saw_alpha = FALSE; - } - if ((f = getenvw(extdef, saw_alpha)) == NULL) { - r->n = NULL; - break; - } - r = r->n = enew(List); - } + char *endp, *realend, *sepp; + List *tailp, *new; + + extdef = strchr(extdef, '='); + *extdef++ = '\0'; /* null "initiate" the string for rtol scanning */ + + sepp = realend = strchr(extdef, '\0'); + tailp = NULL; + + while (1) { + endp = sepp; /* set endp to end of current mebmer */ + skipleft(sepp); /* advance sepp to the previous \1, */ + *endp = '\0'; /* and null terminate the member. */ + + new = enew(List); + new->w = ecpy(sepp+1); + new->m = NULL; + new->n = tailp; + tailp = new; + + if (sepp < extdef) /* break when sepp hits the null "initiator" */ + break; + if (endp != realend) /* else restore the \1 in between members */ + *endp = '\001'; } - return top; + if (endp != realend) + *endp = '\001'; + *--extdef = '='; /* restore extdef '=' */ + return tailp; } /* get an environment entry for a function and have rc parse it. */ diff --git a/glob.c b/glob.c index 1b0121b..bdd3b6c 100644 --- a/glob.c +++ b/glob.c @@ -94,11 +94,39 @@ static List *dmatch(char *d, char *p, char *m) { extern DIR *opendir(const char *); extern struct dirent *readdir(DIR *); /*extern int closedir(DIR *);*/ + int i; + + /* + return a match if there are no metacharacters; allows globbing through + directories with no read permission. make sure the file exists, though. + */ + matched = TRUE; + if (m != NULL) + for (i = 0; p[i] != '\0'; i++) + if (m[i]) { + matched = FALSE; + break; + } + + if (matched) { + char *path = nprint("%s/%s", d, p); + if (stat(path, &s) < 0) + return NULL; + r = nnew(List); + r->w = ncpy(p); + r->m = NULL; + r->n = NULL; + return r; + } top = r = NULL; + if ((dirp = opendir(d)) == NULL) + return NULL; /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */ - if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR || (dirp = opendir(d)) == NULL) + if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR) { + closedir(dirp); return NULL; + } while ((dp = readdir(dirp)) != NULL) if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */ matched = TRUE; @@ -125,15 +153,17 @@ static List *dmatch(char *d, char *p, char *m) { static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) { List *q, *r, *top, foo; - static List slash; - static SIZE_T slashsize = 0; - if (slashcount + 1 > slashsize) { - slash.w = ealloc(slashcount + 1); - slashsize = slashcount; + static struct { + List l; + SIZE_T size; + } slash; + if (slashcount+1 > slash.size) { + slash.size = 2*(slashcount+1); + slash.l.w = erealloc(slash.l.w, slash.size); } - slash.w[slashcount] = '\0'; + slash.l.w[slashcount] = '\0'; while (slashcount > 0) - slash.w[--slashcount] = '/'; + slash.l.w[--slashcount] = '/'; for (top = r = NULL; s != NULL; s = s->n) { q = dmatch(s->w, p, m); if (q != NULL) { @@ -141,7 +171,7 @@ static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) { foo.m = NULL; foo.n = NULL; if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */ - q = concat(&slash, q); /* dir/name with slash */ + q = concat(&slash.l, q); /* dir/name with slash */ q = concat(&foo, q); if (r == NULL) top = r = q; @@ -209,7 +239,7 @@ static List *doglob(char *w, char *m) { } do { SIZE_T slashcount; - SIGCHK; + sigchk(); for (slashcount = 0; *s == '/'; s++, m++) slashcount++; /* skip slashes */ while (*s != '/' && *s != '\0') diff --git a/glom.c b/glom.c index a82183c..d0b1705 100644 --- a/glom.c +++ b/glom.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "rc.h" #if !defined(S_IFIFO) && !defined(DEVFD) #define NOCMDARG @@ -68,11 +69,11 @@ extern List *concat(List *s1, List *s2) { } else { r->m = nalloc(z); if (s1->m == NULL) - clear(r->m, x); + memzero(r->m, x); else memcpy(r->m, s1->m, x); if (s2->m == NULL) - clear(&r->m[x], y); + memzero(&r->m[x], y); else memcpy(&r->m[x], s2->m, y); r->m[z] = 0; @@ -183,7 +184,7 @@ static List *bqinput(List *ifs, int fd) { char isifs[256]; int n, state; /* a simple FSA is used to read in data */ - clear(isifs, sizeof isifs); + memzero(isifs, sizeof isifs); for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n) for (s = ifs->w; *s != '\0'; s++) isifs[*(unsigned char *)s] = TRUE; @@ -209,8 +210,12 @@ static List *bqinput(List *ifs, int fd) { if ((n = rc_read(fd, end, remain)) <= 0) { if (n == 0) /* break */ break; - uerror("backquote read"); - rc_error(NULL); + else if (errno == EINTR) + return NULL; /* interrupted, wait for subproc */ + else { + uerror("backquote read"); + rc_error(NULL); + } } remain -= n; for (bufend = &end[n]; end < bufend; end++) @@ -218,6 +223,7 @@ static List *bqinput(List *ifs, int fd) { if (!isifs[*(unsigned char *)end]) { state = 1; r->w = end; + r->m = NULL; } } else { if (isifs[*(unsigned char *)end]) { @@ -252,7 +258,6 @@ static List *backq(Node *ifs, Node *n) { rc_error(NULL); } if ((pid = rc_fork()) == 0) { - setsigdefaults(FALSE); mvfd(p[1], 1); close(p[0]); redirq = NULL; @@ -264,7 +269,8 @@ static List *backq(Node *ifs, Node *n) { close(p[0]); rc_wait4(pid, &sp, TRUE); statprint(-1, sp); - SIGCHK; + varassign("bqstatus", word(strstatus(sp), NULL), FALSE); + sigchk(); return bq; } diff --git a/hash.c b/hash.c index 9397218..2c8acd5 100644 --- a/hash.c +++ b/hash.c @@ -279,15 +279,17 @@ extern char **makeenv() { return env; } -extern void whatare_all_vars() { +extern void whatare_all_vars(bool showfn, bool showvar) { int i; List *s; - for (i = 0; i < vsize; i++) - if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL) - prettyprint_var(1, vp[i].name, s); - for (i = 0; i < fsize; i++) - if (fp[i].name != NULL && fp[i].name != dead) - prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name)); + if (showvar) + for (i = 0; i < vsize; i++) + if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL) + prettyprint_var(1, vp[i].name, s); + if (showfn) + for (i = 0; i < fsize; i++) + if (fp[i].name != NULL && fp[i].name != dead) + prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name)); } /* fake getenv() for readline() follows: */ diff --git a/history/history.c b/history/history.c index 5f2cece..e6aa29d 100644 --- a/history/history.c +++ b/history/history.c @@ -246,7 +246,7 @@ again: s = last; /* * if the command contains the "me" character at the start of the line - * or after any of [`{|()] then try again + * or after any of [`{|()@] then try again */ for (t = s; *t != '\0'; t++) @@ -254,8 +254,16 @@ again: s = last; char *u = t - 1; while (u >= s && (*u == ' ' || *u == '\t')) --u; - if (u < s || *u == '`' || *u == '{' || *u == '|' || *u == '(' || *u == ')') + if (u < s) goto again; + switch (*u) { + case '`': case '@': + case '(': case ')': + case '{': case '|': + goto again; + default: + break; + } } return s; } diff --git a/input.c b/input.c index 9018a54..24e0070 100644 --- a/input.c +++ b/input.c @@ -40,8 +40,6 @@ static char *inbuf; static SIZE_T istacksize, chars_out, chars_in; static bool eofread = FALSE, save_lineno = TRUE; static Input *istack, *itop; -static char *histstr; -static int histfd; static int (*realgchar)(void); static void (*realugchar)(int); @@ -49,11 +47,17 @@ static void (*realugchar)(int); int last; extern int gchar() { + int c; + if (eofread) { eofread = FALSE; return last = EOF; } - return (*realgchar)(); + + while ((c = (*realgchar)()) == '\0') + pr_error("warning: null character ignored"); + + return c; } extern void ugchar(int c) { @@ -99,7 +103,7 @@ static char *rc_readline(char *prompt) { slow = FALSE; if (r == NULL) errno = EINTR; - SIGCHK; + sigchk(); return r; } #else @@ -128,14 +132,14 @@ static int fdgchar() { inbuf = ealloc(chars_in + 3); strcpy(inbuf+2, rlinebuf); strcat(inbuf+2, "\n"); + efree(rlinebuf); } } else #endif { long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE); + sigchk(); if (r < 0) { - if (errno == EINTR) - continue; /* Suppose it was interrupted by a signal */ uerror("read"); rc_exit(1); } @@ -214,7 +218,7 @@ extern void popinput() { efree(inbuf); --istack; realgchar = (istack->t == iString ? stringgchar : fdgchar); - if (istack->fd == -1) { /* top of input stack */ + if (istack->t == iFd && istack->fd == -1) { /* top of input stack */ realgchar = dead; realugchar = ugdead; } @@ -258,7 +262,7 @@ extern Node *doit(bool execit) { Edata block; block.b = newblock(); except(eArena, block, &e2); - SIGCHK; + sigchk(); if (dashell) { char *fname[3]; fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w; @@ -314,57 +318,42 @@ extern Node *parseline(char *extdef) { return fun; } -/* write last command out to a file. Check to see if $history has changed, also */ +/* write last command out to a file if interactive && $history is set */ static void history() { - List *histlist; + List *hist; SIZE_T a; - if (!interactive) - return; - if ((histlist = varlookup("history")) == NULL) { - if (histstr != NULL) { - efree(histstr); - close(histfd); - histstr = NULL; - } + + if (!interactive || (hist = varlookup("history")) == NULL) return; - } - if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */ - if (histstr != NULL) { - efree(histstr); - close(histfd); - } - histstr = ecpy(histlist->w); - histfd = rc_open(histstr, rAppend); - if (histfd < 0) { - uerror(histstr); - efree(histstr); - histstr = NULL; - varrm("history", FALSE); - } - } - /* - Small unix hack: since read() reads only up to a newline - from a terminal, then presumably this write() will write at - most only one input line at a time. - */ - for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */ - if (inbuf[a] == '#' || inbuf[a] == '\n') - return; - if (inbuf[a] != ' ' && inbuf[a] != '\t') + + for (a = 0; a < chars_in; a++) { + char c = inbuf[a+2]; + + /* skip empty lines and comments */ + if (c == '#' || c == '\n') break; + + /* line matches [ \t]*[^#\n] so it's ok to write out */ + if (c != ' ' && c != '\t') { + char *name = hist->w; + int fd = rc_open(name, rAppend); + if (fd < 0) { + uerror(name); + varrm(name, TRUE); + } else { + writeall(fd, inbuf + 2, chars_in); + close(fd); + } + break; + } } - writeall(histfd, inbuf + 2, chars_in); } /* close file descriptors after a fork() */ extern void closefds() { Input *i; - if (histstr != NULL) { /* Close an open history file */ - close(histfd); - histstr = NULL; /* But prevent re-closing of the same file-descriptor */ - } for (i = istack; i != itop; --i) /* close open scripts */ if (i->t == iFd && i->fd > 2) { close(i->fd); diff --git a/lex.c b/lex.c index 90be65d..a4e4106 100644 --- a/lex.c +++ b/lex.c @@ -10,7 +10,7 @@ The lexical analyzer is fairly straightforward. The only really unclean part concerns backslash continuation and "double backslashes". A backslash followed by a newline is treated as a - space, otherwise backslash is not a special characeter (i.e., + space, otherwise backslash is not a special character (i.e., it can be part of a word). This introduces a host of unwanted special cases. In our case, \ cannot be a word character, since we wish to read in all word characters in a tight loop. @@ -155,9 +155,6 @@ top: while ((c = gchar()) == ' ' || c == '\t') w = KW; } switch (c) { - case '\0': - pr_error("warning: null character ignored"); - goto top; case '!': return BANG; case '@': diff --git a/main.c b/main.c index 0b65adf..20b3221 100644 --- a/main.c +++ b/main.c @@ -3,7 +3,7 @@ #include "rc.h" bool dashdee, dashee, dashvee, dashex, dashell, dasheye, - dashen, dashpee, interactive; + dashen, dashpee, dashess, interactive; int rc_pid; static bool dashoh; @@ -19,7 +19,7 @@ extern void main(int argc, char *argv[], char *envp[]) { dollarzero = argv[0]; rc_pid = getpid(); dashell = (*argv[0] == '-'); /* Unix tradition */ - while ((c = rc_getopt(argc, argv, "nolpeivdxc:")) != -1) + while ((c = rc_getopt(argc, argv, "nolpeivdxsc:")) != -1) switch (c) { case 'l': dashell = TRUE; @@ -39,6 +39,9 @@ extern void main(int argc, char *argv[], char *envp[]) { case 'd': dashdee = TRUE; break; + case 's': + dashess = dasheye = interactive = TRUE; + break; case 'c': dashsee[0] = rc_optarg; goto quitopts; @@ -56,8 +59,8 @@ extern void main(int argc, char *argv[], char *envp[]) { } quitopts: argv += rc_optind; - /* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */ - if (!dasheye && dashsee[0] == NULL && *argv == NULL) + /* use isatty() iff -i is not set, and iff the input is not from a script or -c or -s flags */ + if (!dasheye && !dashess && dashsee[0] == NULL && *argv == NULL) interactive = isatty(0); if (!dashoh) { checkfd(0, rFrom); @@ -78,10 +81,13 @@ quitopts: null[0] = NULL; starassign(dollarzero, null, FALSE); /* assign $0 to $* */ inithandler(); - if (dashsee[0] != NULL) { /* input from the -c flag? */ + if (dashsee[0] != NULL || dashess) { /* input from -c or -s? */ if (*argv != NULL) starassign(dollarzero, argv, FALSE); - pushstring(dashsee, TRUE); + if (dashess) + pushfd(0); + else + pushstring(dashsee, TRUE); } else if (*argv != NULL) { /* else from a file? */ b_dot(--argv); rc_exit(getstatus()); diff --git a/nalloc.c b/nalloc.c index 5498e38..d600e4e 100644 --- a/nalloc.c +++ b/nalloc.c @@ -122,6 +122,8 @@ extern void *ealloc(SIZE_T n) { extern void *erealloc(void *p, SIZE_T n) { extern void *realloc(void *, SIZE_T); + if (p == NULL) /* convenience feature */ + return ealloc(n); if ((p = realloc(p, n)) == NULL) { uerror("realloc"); rc_exit(1); diff --git a/print.c b/print.c index 36fefb5..a5cf25f 100644 --- a/print.c +++ b/print.c @@ -270,9 +270,11 @@ extern int printfmt(Format *format, const char *fmt) { extern int fmtprint(Format *format, const char *fmt,...) { int n = -format->flushed; - va_list saveargs = format->args; + va_list ap, saveargs; - va_start(format->args, fmt); + va_start(ap, fmt); + saveargs = format->args; + format->args = ap; n += printfmt(format, fmt); va_end(format->args); format->args = saveargs; @@ -292,6 +294,7 @@ static void fprint_flush(Format *format, SIZE_T more) { extern int fprint(int fd, const char *fmt,...) { char buf[1024]; Format format; + va_list ap; format.buf = buf; format.bufbegin = buf; @@ -300,7 +303,8 @@ extern int fprint(int fd, const char *fmt,...) { format.flushed = 0; format.u.n = fd; - va_start(format.args, fmt); + va_start(ap, fmt); + format.args = ap; printfmt(&format, fmt); va_end(format.args); @@ -340,8 +344,11 @@ static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) { extern char *mprint(const char *fmt,...) { Format format; char *result; + va_list ap; + format.u.n = 1; - va_start(format.args, fmt); + va_start(ap, fmt); + format.args = ap; result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; @@ -350,8 +357,11 @@ extern char *mprint(const char *fmt,...) { extern char *nprint(const char *fmt,...) { Format format; char *result; + va_list ap; + format.u.n = 0; - va_start(format.args, fmt); + va_start(ap, fmt); + format.args = ap; result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; diff --git a/proto.h b/proto.h index a599537..2dc51a1 100644 --- a/proto.h +++ b/proto.h @@ -47,6 +47,7 @@ extern char *strncpy(char *, const char *, SIZE_T); extern char *strcat(char *, const char *); extern char *strncat(char *, const char *, SIZE_T); extern void *memcpy(void *, const void *, SIZE_T); +extern void *memset(void *, int, SIZE_T); /* fake unistd.h */ diff --git a/rc.1 b/rc.1 index c9f9e08..140eb66 100644 --- a/rc.1 +++ b/rc.1 @@ -490,6 +490,7 @@ This allows the unambiguous use of variables adjacent to text, as in .Ds .Cr $variable^follow .De +.PP To include a literal .Cr $ in a here document when an unquoted end-of-file marker is being used, @@ -683,8 +684,8 @@ the first command exits with a zero exit status (``true'' in Unix). .Cr "command || command" .De .PP -executes the first command executing the second command if and only if -the second command exits with a nonzero exit status (``false'' in Unix). +executes the first command and then executes the second command if and only if +the first command exits with a nonzero exit status (``false'' in Unix). .Ds .Cr "! command" .De @@ -1625,7 +1626,7 @@ If no .I pid is specified, .I rc -waits for any child process to exit. +waits for all child processes to exit. .TP \fBwhatis \fR[\fB\-s\fR] [\fB\-\|\-\fR] [\fIname ...\fR] Prints a definition of the named objects. diff --git a/rc.h b/rc.h index 9e38d8b..04e37a2 100644 --- a/rc.h +++ b/rc.h @@ -150,6 +150,7 @@ enum { #define a2u(x) n2u(x, 10) #define o2u(x) n2u(x, 8) #define arraysize(a) ((int)(sizeof(a)/sizeof(*a))) +#define memzero(s, n) memset(s, 0, n) #define enew(x) ((x *) ealloc(sizeof(x))) #define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1), x) #define lookup_fn(s) ((Function *) lookup(s, fp)) @@ -192,8 +193,6 @@ extern void exec(List *, bool); extern void doredirs(void); /* footobar.c */ -extern char *fun2str(char *, Node *); -extern char *list2str(char *, List *); extern char **list2array(List *, bool); extern char *get_name(char *); extern List *parse_var(char *, char *); @@ -245,7 +244,7 @@ extern void setsigdefaults(bool); extern void inithandler(void); extern void varassign(char *, List *, bool); extern void varrm(char *, bool); -extern void whatare_all_vars(void); +extern void whatare_all_vars(bool, bool); extern void whatare_all_signals(void); extern void prettyprint_var(int, char *, List *); extern void prettyprint_fn(int, char *, Node *); @@ -338,7 +337,6 @@ extern void sigchk(void); extern void (*rc_signal(int, void (*)(int)))(int); extern void (*sighandlers[])(int); extern volatile SIG_ATOMIC_T slow, interrupt_happened; -#define SIGCHK sigchk() /* status.c */ extern int istrue(void); @@ -349,6 +347,7 @@ extern List *sgetstatus(void); extern void setpipestatus(int [], int); extern void statprint(int, int); extern void ssetstatus(char **); +extern char *strstatus(int s); /* tree.c */ extern Node *mk(int /*nodetype*/,...); @@ -362,7 +361,6 @@ extern int rc_read(int, char *, SIZE_T); extern int mvfd(int, int); extern int starstrcmp(const void *, const void *); extern void pr_error(char *); -extern char *clear(char *, SIZE_T); extern void panic(char *); extern void uerror(char *); extern void writeall(int, char *, SIZE_T); diff --git a/signal.c b/signal.c index 645fb36..6bca945 100644 --- a/signal.c +++ b/signal.c @@ -13,8 +13,6 @@ void (*sighandlers[NUMOFSIGNALS])(int); static volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS]; extern void catcher(int s) { - if (forked) - exit(1); /* exit unconditionally on a signal in a child process */ if (caught[s] == 0) { sigcount++; caught[s] = 1; @@ -52,7 +50,7 @@ extern void sigchk() { extern void (*rc_signal(int s, void (*h)(int)))(int) { void (*old)(int); - SIGCHK; + sigchk(); old = sighandlers[s]; if (h == SIG_DFL || h == SIG_IGN) { signal(s, h); diff --git a/status.c b/status.c index 1b6325b..91252b0 100644 --- a/status.c +++ b/status.c @@ -80,27 +80,35 @@ extern void statprint(int pid, int i) { /* prepare a list to be passed back. Used whenever $status is dereferenced */ extern List *sgetstatus() { - List *r; + List *r = NULL; int i; - for (r = NULL, i = 0; i < pipelength; i++) { + + for (i = 0; i < pipelength; i++) { List *q = nnew(List); - int s = statuses[i]; - int t; + q->w = strstatus(statuses[i]); + q->m = NULL; q->n = r; r = q; - if ((t = s & 0x7f) != 0) { - const char *core = (s & 0x80) ? "+core" : ""; - if (t < NUMOFSIGNALS && *signals[t].name != '\0') - r->w = nprint("%s%s", signals[t].name, core); - else - r->w = nprint("-%d%s", t, core); /* unknown signals are negated */ - } else - r->w = nprint("%d", (s >> 8) & 0xff); - r->m = NULL; } + return r; } +/* return status as a string (used above and for bqstatus) */ + +extern char *strstatus(int s) { + int t = s & 0x7f; + + if (t != 0) { + const char *core = (s & 0x80) ? "+core" : ""; + if (t < NUMOFSIGNALS && *signals[t].name != '\0') + return nprint("%s%s", signals[t].name, core); + else + return nprint("-%d%s", t, core); /* unknown signals are negated */ + } else + return nprint("%d", (s >> 8) & 0xff); +} + extern void ssetstatus(char **av) { int i, j, k, l; bool found; diff --git a/trip.rc b/trip.rc index ba38207..64d660f 100644 Binary files a/trip.rc and b/trip.rc differ diff --git a/utils.c b/utils.c index 6ab303c..67b146b 100644 --- a/utils.c +++ b/utils.c @@ -82,7 +82,7 @@ extern void writeall(int fd, char *buf, SIZE_T remain) { slow = FALSE; } slow = FALSE; - SIGCHK; + sigchk(); } extern int rc_read(int fd, char *buf, SIZE_T n) { @@ -101,18 +101,9 @@ extern int rc_read(int fd, char *buf, SIZE_T n) { errno = EINTR; r = -1; } - SIGCHK; return r; } -/* clear out z bytes from character string s */ - -extern char *clear(char *s, SIZE_T z) { - while (z != 0) - s[--z] = 0; - return s; -} - /* duplicate a fd and close the old one only if necessary */ extern int mvfd(int i, int j) { diff --git a/var.c b/var.c index ef780b3..6a3e7c8 100644 --- a/var.c +++ b/var.c @@ -104,7 +104,7 @@ extern char *varlookup_string(char *name) { return look->extdef; if (look->def == NULL) return NULL; - return look->extdef = list2str(name, look->def); + return look->extdef = mprint("%F=%-L", name, look->def, "\001"); } /* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */ @@ -166,16 +166,15 @@ static void listassign(char *name, List *def, bool stack) { return; } v = def->w; - r = val = enew(List); + r = val = nnew(List); while ((w = strchr(v, ':')) != NULL) { *w = '\0'; - r->w = ecpy(v); + r->w = ncpy(v); *w = ':'; v = w + 1; - r->n = enew(List); - r = r->n; + r = r->n = nnew(List); } - r->w = ecpy(v); + r->w = ncpy(v); r->n = NULL; varassign(name, val, stack); } diff --git a/version.c b/version.c index 0cdc517..b3dcba5 100644 --- a/version.c +++ b/version.c @@ -1 +1 @@ -const char id[] = "@(#)rc version 1.4, 5/26/92."; +const char id[] = "@(#)rc version 1.5betadev-1, 1/9/94."; diff --git a/wait.c b/wait.c index a70acee..3756985 100644 --- a/wait.c +++ b/wait.c @@ -16,7 +16,7 @@ static struct Pid { } *plist = NULL; extern int rc_fork() { - Pid *new = enew(Pid); + Pid *new; int pid = fork(); switch (pid) { case -1: @@ -25,9 +25,10 @@ extern int rc_fork() { /* NOTREACHED */ case 0: forked = TRUE; - SIGCHK; + sigchk(); return 0; default: + new = enew(Pid); new->pid = pid; new->alive = TRUE; new->n = plist; @@ -98,7 +99,7 @@ extern void waitforall() { setstatus(pid, stat); else set(FALSE); - SIGCHK; + sigchk(); } } diff --git a/walk.c b/walk.c index c18921c..e57de0d 100644 --- a/walk.c +++ b/walk.c @@ -11,6 +11,7 @@ */ bool cond = FALSE; +static bool haspreredir(Node *); static bool isallpre(Node *); static bool dofork(bool); static void dopipe(Node *); @@ -22,7 +23,7 @@ static void dopipe(Node *); /* walk the parse-tree. "obvious". */ extern bool walk(Node *n, bool parent) { -top: SIGCHK; +top: sigchk(); if (n == NULL) { if (!parent) exit(0); @@ -147,7 +148,6 @@ top: SIGCHK; } case nSubshell: if (dofork(TRUE)) { - setsigdefaults(FALSE); walk(n->u[0].p, FALSE); rc_exit(getstatus()); } @@ -214,8 +214,14 @@ top: SIGCHK; case nPre: { List *v; if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) { + if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */ + break; qredir(n->u[0].p); - walk(n->u[1].p, parent); + if (!haspreredir(n->u[1].p)) + doredirs(); /* no more preredirs, empty queue */ + walk(n->u[1].p, FALSE); + rc_exit(getstatus()); + /* NOTREACHED */ } else if (n->u[0].p->type == nAssign) { if (isallpre(n->u[1].p)) { walk(n->u[0].p, TRUE); @@ -239,7 +245,6 @@ top: SIGCHK; if (n->u[1].p == NULL) { WALK(n->u[0].p, parent); } else if (dofork(parent)) { - setsigdefaults(FALSE); walk(n->u[1].p, TRUE); /* Do redirections */ redirq = NULL; /* Reset redirection queue */ walk(n->u[0].p, FALSE); /* Do commands */ @@ -265,6 +270,17 @@ top: SIGCHK; return istrue(); } +/* checks to see whether there are any pre-redirections left in the tree */ + +static bool haspreredir(Node *n) { + while (n != NULL && n->type == nPre) { + if (n->u[0].p->type == nDup || n->u[0].p->type == nRedir) + return TRUE; + n = n->u[1].p; + } + return FALSE; +} + /* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */ static bool isallpre(Node *n) { @@ -286,7 +302,7 @@ static bool dofork(bool parent) { redirq = NULL; /* clear out the pre-redirection queue in the parent */ rc_wait4(pid, &sp, TRUE); setstatus(-1, sp); - SIGCHK; + sigchk(); return FALSE; } @@ -304,7 +320,6 @@ static void dopipe(Node *n) { rc_error(NULL); } if ((pid = rc_fork()) == 0) { - setsigdefaults(FALSE); redirq = NULL; /* clear preredir queue */ mvfd(p[0], r->u[1].i); if (fd_prev != 1) @@ -321,7 +336,6 @@ static void dopipe(Node *n) { close(p[0]); } if ((pid = rc_fork()) == 0) { - setsigdefaults(FALSE); mvfd(fd_prev, fd_out); walk(r, FALSE); exit(getstatus()); @@ -340,5 +354,5 @@ static void dopipe(Node *n) { intr |= (sp == SIGINT); } setpipestatus(stats, i); - SIGCHK; + sigchk(); } -- cgit v1.2.3 From 671e1e2d1599aa8c5f1010b3fe75c151c56a7403 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Mon, 7 Jul 1997 00:00:01 +0100 Subject: beta: rc-1.5b2 --- CHANGES | 15 + Makefile | 65 -- Makefile.in | 80 ++ README | 236 +++-- builtins.c | 44 +- config.h-dist | 204 ----- config.h.in | 44 + configure | 2541 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ configure.in | 287 ++++++ exec.c | 12 +- fn.c | 4 +- footobar.c | 6 +- glob.c | 38 +- glom.c | 97 ++- group.h | 9 + hash.c | 4 +- heredoc.c | 8 +- history/Makefile | 6 - input.c | 25 +- install-sh | 250 ++++++ jbwrap.h | 5 +- lex.c | 8 +- list.c | 6 +- main.c | 2 +- mksignal | 3 +- nalloc.c | 22 +- open.c | 4 - print.c | 50 +- proto.h | 82 +- rc.h | 78 +- rlimit.h | 42 + signal.c | 9 +- status.c | 8 +- tree.c | 4 +- utils.c | 4 +- var.c | 2 +- version.c | 2 +- wait.c | 18 +- walk.c | 4 +- which.c | 35 +- y.tab.c | 1070 +++++++++++++++++++++++ y.tab.h | 33 + 42 files changed, 4838 insertions(+), 628 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.in delete mode 100644 config.h-dist create mode 100644 config.h.in create mode 100755 configure create mode 100644 configure.in create mode 100644 group.h delete mode 100644 history/Makefile create mode 100755 install-sh create mode 100644 rlimit.h create mode 100644 y.tab.c create mode 100644 y.tab.h diff --git a/CHANGES b/CHANGES index 767bd08..0543c11 100644 --- a/CHANGES +++ b/CHANGES @@ -261,3 +261,18 @@ wait.c: Got rid of memory leak in rc_fork, renamed SIGCHK to sigchk. walk.c: Fixed pre-redirection bug, removed spurious setsigdefaults(), renamed SIGCHK to sigchk. + + +Changes since rc-1.5beta1 + + Configuration: rc now uses GNU autoconf. + + Portability: mksignal works on HPUX 10. + + Portability: resources can be (quad_t). + + Bug: if rc was started with SIGCLD == SIG_IGN (e.g. by Solaris's + rshd) it would loop. Fixed by resetting SIGCLD to SIG_DFL if it + was SIG_IGN when rc was started. + + Portability: POSIXish systems don't have NGROUPS. diff --git a/Makefile b/Makefile deleted file mode 100644 index 477ff76..0000000 --- a/Makefile +++ /dev/null @@ -1,65 +0,0 @@ -# Makefile for rc. - -# Please check the configuration parameters in config.h (and if you want -# to make sure, the definitions in proto.h) to make sure they are correct -# for your system. - -SHELL=/bin/sh - -# Uncomment this line if you have defined the NOEXECVE macro in config.h -#EXECVE=execve.o - -# Define this macro if you wish to extend rc via locally-defined builtins. -# An interface is provided in addon.[ch]. Note that the author does not -# endorse any such extensions, rather hopes that this way rc will become -# useful to more people. -#ADDON=addon.o - -# Use an ANSI compiler (or at least one that groks prototypes and void *): -CC=gcc -g -O -CFLAGS= -LDFLAGS= - -# You may substitute "bison -y" for yacc. (You want to choose the one that -# makes a smaller y.tab.c. Also see the README about Sun's yacc.) -YACC=yacc - -OBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \ - glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \ - nalloc.o open.o print.o redir.o sigmsgs.o signal.o status.o tree.o \ - utils.o var.o version.o wait.o walk.o which.o y.tab.o - -# If rc is compiled with READLINE defined, you must supply the correct -# arguments to ld on this line. Typically this would be something like: -# -# $(CC) -o $@ $(OBJS) -lreadline -ltermcap - -rc: $(OBJS) - $(CC) -o $@ $(OBJS) $(LDFLAGS) - -sigmsgs.c: mksignal - sh mksignal /usr/include/sys/signal.h - -y.tab.c: parse.y - $(YACC) -d parse.y - -config.h: config.h-dist - cp config.h-dist config.h - -trip: rc - ./rc -p < trip.rc - -clean: force - rm -f *.o *.tab.* sigmsgs.* - -history: force - cd history; make CC="$(CC)" $(HISTORYMAKEFLAGS) - -force: - -# dependencies: - -$(OBJS): config.h -sigmsgs.h: sigmsgs.c -lex.o y.tab.o: y.tab.c -builtins.c fn.c status.c hash.c: sigmsgs.h diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..ed89d84 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,80 @@ +# Makefile.in for rc. + +SHELL=/bin/sh + +bindir=@bindir@ +exec_prefix=@exec_prefix@ +mandir=@mandir@ +prefix=@prefix@ + +CC=@CC@ +CFLAGS=@CFLAGS@ +LDFLAGS=@CFLAGS@ +LIBS=@LIBS@ + +INSTALL=@INSTALL@ +INSTALL_DATA=@INSTALL_DATA@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +LN=@LN@ +YACC=@YACC@ + +HISTORY=@HISTORY@ + +OBJS=@ADDON@ builtins.o except.o exec.o @EXECVE@ fn.o footobar.o getopt.o \ + glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \ + nalloc.o open.o print.o redir.o sigmsgs.o signal.o status.o tree.o \ + utils.o var.o version.o wait.o walk.o which.o y.tab.o + +all: rc $(HISTORY) + +rc: $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LIBS) + +sigmsgs.c: mksignal + sh mksignal @SIGNAL_H@ + +y.tab.c: parse.y + $(YACC) -d parse.y + +trip: rc + ./rc -p < trip.rc + +clean: force + rm -f rc $(HISTORY) - *.o *.tab.* sigmsgs.* config.cache config.log + +cleaner: clean + rm -f config.status config.h Makefile + +cleanest: cleaner + rm -f configure + +history: force + cd history; make CC="$(CC)" $(HISTORYMAKEFLAGS) + +install: all + $(INSTALL_PROGRAM) rc $(bindir) + $(INSTALL_DATA) rc.1 $(mandir)/man1/rc.1 + case "x$(HISTORY)" in \ + x) \ + ;; \ + *) \ + $(LN) $(HISTORY) - ;\ + $(INSTALL_PROGRAM) - $(bindir) ;\ + $(LN) $(bindir)/- $(bindir)/-- ;\ + $(LN) $(bindir)/- $(bindir)/-p ;\ + $(LN) $(bindir)/- $(bindir)/--p ;\ + $(INSTALL_DATA) history/history.1 $(mandir)/man1/history.1 \ + ;; \ + esac + +force: + +# dependencies: + +$(OBJS): config.h proto.h rc.h +sigmsgs.h: sigmsgs.c +lex.o y.tab.o: y.tab.c + +builtins.o except.o exec.o input.o signal.o utils.o wait.o walk.o: jbwrap.h +builtins.o: rlimit.h +builtins.o fn.o hash.o signal.o status.o: sigmsgs.h diff --git a/README b/README index bbb1c9e..30e9f9a 100644 --- a/README +++ b/README @@ -1,111 +1,197 @@ -This is release 1.5 of rc. +This is release 1.5b2 of rc. -Read COPYRIGHT for copying information. All files are +Read COPYRIGHT for copying information. All files are -Copyright 1991, Byron Rakitzis. + Copyright 1991, 1997 Byron Rakitzis. COMPILING -rc was written in portable ANSI C. If you don't have an ANSI compiler +rc was written in portable ANSI C. If you don't have an ANSI compiler like gcc or something close (e.g., sgi's cc) read further down on how to convert rc's source to old C. -Please read the Makefile, and copy config.h-dist to config.h and -examine the parameters in there; they let you customize rc to your -Unix. For example, some Unices support /dev/fd, or some have FIFOs. -If you do not perform this step then the Makefile will automatically -copy config.h-dist to config.h and proceed assuming that everything -is ok. Note that config.h-dist supplies default parameter configurations -for SunOS, NeXT-OS, Irix, Ultrix and some others. Finally, if you're -having trouble you may want to look at proto.h and see if everything -in there jibes with your system. +The following commands are all you need to configure, build, +test, and install rc. -After you've built rc, you may wish to run it through a test script -to see that everything is ok. Type "make trip" for this. This will -produce some output, and end with "trip is complete". If the trip -ends with "trip took a wrong turn..." then drop me a line. + $ sh configure + $ make + $ make trip + # make install + +There are lots of options you can give to configure to modify rc's +behaviour. You can also select a command line history library to link +against. For a summary of all options, run `sh configure --help'. + +You can specify Makefile variables by setting the corresponding +environment variables. For example, you might want to set `CC=cc', to +prevent configure looking for gcc, or set an initial value for `LIBS', +as in the example below. + +Here are the configure options you may want to use, in approximately +descending order of usefulness. + + --with-editline + + This option tells rc to use Simmule Turner's and Rich $alz's editline + package, which you can get from the following location. This is + essentially a lightweight version of GNU readline, providing EMACS + style command line editing and history. + + ftp://ftp.pipex.net/people/tim/editline.tar.gz + + If the editline library is not installed in a standard place, you + can tell configure where to find it by setting the environment + variable LIBS. For example, the maintainer builds rc by copying + libedit.a into the rc directory and then running this configure + command. + + LIBS=-L. sh configure --with-editline + + --with-readline + + This option tells rc to use the GNU readline package, which is similar + to editline, but has many more features. The readline package is over + 6 times the size of editline (whether you count lines of code, or the + library itself). You probably need to tell the compiler to link with + the termcap library if you're using readline. For example, here is + the configure command the maintainer uses to build rc with readline. + + LIBS=-ltermcap sh configure --with-readline + + --enable-history + + Use this option if you want to build and install the programs that + support a crude history mechanism. + +You can't use `--with-editline' and `--with-readline' together, of course, +and if you have either of those you probably don't want to bother with +`--enable-history'. -To compile the history program, go into the history subdirectory -and type "make". This will create a binary called "history". However, -in order for it to work as advertised it must be installed into -your bin as four files named -, --, -p and --p. (these can be soft -or hard links to the same file) + --prefix=/path -rc may also be linked with either GNU readline (10,000+ lines of -code!) or a supplied readline-like system by Simmule Turner (1,000+ -lines of code). See the Makefile on how to do this. + By default, `prefix' is /usr/local, which means that `make install' + installs rc (and possibly the history programs) in /usr/local/bin, and + man pages in /usr/local/man/man1. Use this option to change where + `make install' puts things. + + --disable-builtin-echo + + By default, the `echo' command is builtin to rc for efficiency reasons. + It is the only builtin which is not essential, and purists may wish + to omit it. + + --disable-def-interp + --enable-def-interp=/bin/foo + + By default, a program that fails with "Exec format error" is handed to + /bin/sh. This does the Right Thing for scripts that start with `:' to + indicate that they are sh scripts. You can disable this behaviour + entirely, or specify a different default interpreter. + + --disable-def-path + --enable-def-path="/usr/local/bin","/usr/bin" + + By default, if rc is started with no PATH, it uses a default path. + The default path is constructed at configure time, and consists + of each of the following directories that exist, in order. + + /usr/local/bin /usr/bin /usr/ucb /bin . + + You can disable this, or specify a different default path. Note + that the quote marks (") must be seen by configure; you will + probably need to quote them to your shell. (Not if it's already + rc, but then you will need to quote the `='.) + + --disable-job + + By default, rc puts backgrounded processes into a new process group, + as though it were a job control shell (it isn't). This is usually + needed to work around bugs in application programs which install + signal handlers for the keyboard signals without checking whether the + signal was being ignored. This option disables the default behaviour, + making rc behave like a traditional sh. You are unlikely to want this + option on any Unix system. + + --disable-protect-env + + By default, rc encodes special characters in environment variables. + This is necessary on all known Unix systems to prevent sh either + dying or discarding the variables. This option disables the default + behaviour. You are unlikely to want this option on any Unix system. + +After you've built rc, you may wish to run it through a test script +to see that everything is ok. Type `make trip' for this. This will +produce some output, and end with "trip is complete". If the trip ends +with "trip took a wrong turn..." please contact the maintainer. (If +you've built in either of the command line history libraries, the trip +will fail near the end with `trip took a wrong turn: dot -i'.) BUGS -Send bug reports to byron@archone.tamu.edu. If a core dump is -generated, sending me a backtrace will help me out a great deal. You -can get a backtrace like this: +Send bug reports to ( after +1997-07-27). If a core dump is generated, sending a backtrace will +help a great deal. You can get a backtrace like this. ; gdb rc core (gdb) where <<>> (gdb) -Also, always report the machine, compiler and OS used to make rc. It's -possible I may have access to a machine of that type, in which case it -becomes much easier for me to track the bug down. - -If you are using gcc, please make sure that you have a recent version of -the compiler (1.39 and up) before you send me a note; I have found that -older versions of gcc choke over rc and generate bad code on several -architectures. (this is especially relevant for the the MIPS architecture) +Also, always report the machine, OS (`uname -a'), and compiler used to +make rc; this information is extremely valuable. FEEPING CREATURISM See the end of the man page, under "INCOMPATABILITIES" for (known?) -differences from the "real" rc. Most of these changes were necessary -to get rc to work in a reasonable fashion on a real (i.e., commercial, -non-Labs) UNIX system; a few were changes motivated by concern -about some inadequacies in the original design. +differences from the "real" rc. Most of these changes were necessary +to get rc to work in a reasonable fashion on a real (i.e. commercial, +non-Labs) Unix system; a few were changes motivated by concern about +some inadequacies in the original design. YACC The yacc that Sun ships with SunOS 4.1.1 calls malloc() to allocate -space for the state stack, and requires a call to YYACCEPT or YYABORT -to free this memory. This means that if rc takes an interrupt while -parsing a command (say, if ^C is typed), yacc will leak away this -memory. The solution is to use a yacc which statically allocates -this array, such as the yacc in the BSD distribution. Berkeley yacc- -generated y.tab.c and y.tab.h are shipped with rc in case you cannot -get hold of Berkeley yacc. +space for the state stack, and requires a call to YYACCEPT or YYABORT to +free this memory. This means that if rc takes an interrupt while parsing +a command (say, if ^C is typed), yacc will leak away this memory. The +solution is to use a yacc which statically allocates this array, such +as the yacc in the BSD distribution. Berkeley yacc-generated y.tab.c +and y.tab.h are shipped with rc in case you cannot get hold of Berkeley +yacc. OLD C If you need to convert rc's source into K&R C, you need to run the source through a filter called "unproto", posted in comp.sources.misc. -A sample "cpp" shell script that I used to run unproto under SunOS -is supplied with rc. +A sample "cpp" shell script that I used to run unproto under SunOS is +supplied with rc. CREDITS -This shell was written by me, Byron Rakitzis, but kudos go to Paul -Haahr for letting me know what a shell should do and for contributing -certain bits and pieces to rc (notably the limits code, print.c, -most of which.c and the backquote redirection code), and to Hugh -Redelmeier for running rc through his fussy ANSI compiler and -thereby provoking interesting discussions about portability, and -also for providing many valuable suggestions for improving rc's -code in general. Finally, many thanks go to David Sanderson, for -reworking the man page to format well with troff, and for providing -many suggestions both for rc and its man page. - -Thanks to Boyd Roberts for the original history.c, and to Hugh -again for re-working parts of that code. - -Of course, without Tom Duff's design of the original rc, I could -not have written this shell (though I probably would have written -*a* shell). Almost of all of the features, with minor exceptions, -have been implemented as described in the Unix v10 manuals. Hats -off to td for designing a C-like, minimal but very useful shell. - -Tom Duff has kindly given permission for the paper he wrote for -UKUUG to be distributed with this version of rc (called "plan9.ps" -in the same ftp directory as the shell). Please read this paper -bearing in mind that it describes a program that was written at -AT&T and that the version of rc presented here differs in some -respects. +This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr +for letting me know what a shell should do and for contributing certain +bits and pieces to rc (notably the limits code, print.c, most of which.c +and the backquote redirection code), and to Hugh Redelmeier for running +rc through his fussy ANSI compiler and thereby provoking interesting +discussions about portability, and also for providing many valuable +suggestions for improving rc's code in general. Finally, many thanks +go to David Sanderson, for reworking the man page to format well with +troff, and for providing many suggestions both for rc and its man page. + +Thanks to Boyd Roberts for the original history.c, and to Hugh again for +re-working parts of that code. + +Of course, without Tom Duff's design of the original rc, I could not +have written this shell (though I probably would have written *a* +shell). Almost of all of the features, with minor exceptions, have been +implemented as described in the Unix v10 manuals. Hats off to td for +designing a C-like, minimal but very useful shell. + +Tom Duff has kindly given permission for the paper he wrote for UKUUG to +be distributed with this version of rc (called "plan9.ps" in the same +ftp directory as the shell). Please read this paper bearing in mind that +it describes a program that was written at AT&T and that the version of +rc presented here differs in some respects. + +The current maintainer of rc is Tim Goodwin, +( after 1997-07-27). diff --git a/builtins.c b/builtins.c index 77f75df..1f9b56e 100644 --- a/builtins.c +++ b/builtins.c @@ -7,17 +7,16 @@ because of a bad umask. */ +#include "rc.h" + #include #include #include -#include "rc.h" + #include "jbwrap.h" #include "sigmsgs.h" -#ifndef NOLIMITS -#include -#include -#endif #include "addon.h" +#include "rlimit.h" extern int umask(int); @@ -25,10 +24,11 @@ static void b_break(char **), b_cd(char **), b_eval(char **), b_exit(char **), b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **), b_wait(char **), b_whatis(char **); -#ifndef NOLIMITS +#if HAVE_SETRLIMIT static void b_limit(char **); #endif -#ifndef NOECHO + +#if RC_ECHO static void b_echo(char **); #endif @@ -39,13 +39,13 @@ static struct { { b_break, "break" }, { b_builtin, "builtin" }, { b_cd, "cd" }, -#ifndef NOECHO +#if RC_ECHO { b_echo, "echo" }, #endif { b_eval, "eval" }, { b_exec, "exec" }, { b_exit, "exit" }, -#ifndef NOLIMITS +#if HAVE_SETRLIMIT { b_limit, "limit" }, #endif { b_newpgrp, "newpgrp" }, @@ -100,7 +100,7 @@ static void badnum(char *num) { extern void b_exec(char **av) { } -#ifndef NOECHO +#if RC_ECHO /* echo -n omits a newline. echo -- -n echos '-n' */ static void b_echo(char **av) { @@ -121,7 +121,7 @@ static void b_echo(char **av) { static void b_cd(char **av) { List *s, nil; char *path = NULL; - SIZE_T t, pathlen = 0; + size_t t, pathlen = 0; if (*++av == NULL) { s = varlookup("home"); *av = (s == NULL) ? "/" : s->w; @@ -250,7 +250,8 @@ extern void b_builtin(char **av) { /* wait for a given process, or all outstanding processes */ static void b_wait(char **av) { - int stat, pid; + int stat; + pid_t pid; if (av[1] == NULL) { waitforall(); return; @@ -414,15 +415,13 @@ static void b_newpgrp(char **av) { arg_count("newpgrp"); return; } - setpgrp(rc_pid, rc_pid); -#ifdef TIOCSPGRP - ioctl(2, TIOCSPGRP, &rc_pid); -#endif + setpgid(rc_pid, rc_pid); /* XXX check return value */ + tcsetpgrp(2, rc_pid); /* XXX check return value */ } /* Berkeley limit support was cleaned up by Paul Haahr. */ -#ifndef NOLIMITS +#if HAVE_SETRLIMIT typedef struct Suffix Suffix; struct Suffix { const Suffix *next; @@ -464,14 +463,9 @@ static const Limit limits[] = { { NULL, 0, NULL } }; -#ifndef SYSVR4 -extern int getrlimit(int, struct rlimit *); -extern int setrlimit(int, struct rlimit *); -#endif - static void printlimit(const Limit *limit, bool hard) { struct rlimit rlim; - long lim; + rlim_t lim; getrlimit(limit->flag, &rlim); if (hard) lim = rlim.rlim_max; @@ -486,11 +480,11 @@ static void printlimit(const Limit *limit, bool hard) { lim /= suf->amount; break; } - fprint(1, "%s \t%d%s\n", limit->name, lim, (suf == NULL || lim == 0) ? "" : suf->name); + fprint(1, RLIM_FMT, limit->name, (RLIM_CONV)lim, (suf == NULL || lim == 0) ? "" : suf->name); } } -static long parselimit(const Limit *limit, char *s) { +static rlim_t parselimit(const Limit *limit, char *s) { char *t; int len = strlen(s); long lim = 1; diff --git a/config.h-dist b/config.h-dist deleted file mode 100644 index 5be81eb..0000000 --- a/config.h-dist +++ /dev/null @@ -1,204 +0,0 @@ -/* Copy config.h-dist to config.h and edit config.h, don't edit this file */ - -/* - * Configuration parameters for rc. Suggested defaults are at the bottom - * of this file (you should probably look at those first to see if your - * system matches one of them; you can search for the beginning of the - * defaults section by looking for the string "#ifndef CUSTOM"). If you - * want to override the suggested defaults, define the macro CUSTOM. -#define CUSTOM - */ - -/* - * (Note that certain default settings redefine this macro) - * DEFAULTPATH the default search path that rc uses when it is started - * without either a $PATH or $path environment variable. You must pick - * something sensible for your system if you don't like the path shown - * below. - */ -#define DEFAULTPATH "/usr/ucb", "/usr/bin", "/bin", "." - -/* - * Define the macro NODIRENT if your system has but not - * . (e.g., NeXT-OS and RISCos) -#define NODIRENT - */ - -/* - * Define the macro SVSIGS if your system has System V signal semantics, - * i.e., if "slow" system calls are interrupted rather than resumed - * after returning from an interrupt handler. (If you are not sure what - * this means, see the man page for signal(2). In any case, it is probably - * safe to leave this macro undefined.) -#define SVSIGS - */ - -/* - * Define the macro NOCMDARG if you do not have /dev/fd or fifos on your - * system. You may also want to define this if you have broken fifos. -#define NOCMDARG - */ - -/* - * Define TMPDIR if you need to have rc create its fifos in a directory - * other than /tmp. For example, if you have a Sun with /tmp mounted - * as a ramdisk (type "tmpfs") then you cannot use fifos in /tmp (sigh). -#define TMPDIR "/var/tmp" - */ - -/* - * Define the macro DEVFD if your system supports /dev/fd. -#define DEVFD - */ - -/* - * Define the macro NOLIMITS if your system does not support Berkeley - * limits. -#define NOLIMITS - */ - -/* - * Define the macro NOSIGCLD if your system uses SIGCLD in the System - * V way. (e.g., sgi's Irix) -#define NOSIGCLD - */ - -/* - * Define the macro READLINE if you want rc to call GNU readline - * instead of read(2) on interactive shells. -#define READLINE - */ - -/* - * Define the macro NOEXECVE if your Unix does not interpret #! in the - * kernel, and uncomment the EXECVE variable in the Makefile. -#define NOEXECVE - */ - -/* - * If you want rc to default to some interpreter for files which don't - * have a legal #! on the first line, define the macro DEFAULTINTERP. -#define DEFAULTINTERP "/bin/sh" - */ - -/* - * If your /bin/sh (or another program you care about) rejects environment - * variables with special characters in them (such as ':' or '-'), rc can - * put out ugly variable names using [_0-9a-zA-Z] that encode the real name; - * define PROTECT_ENV for this hack. (Known offenders: every sh I have tried; - * SunOS (silently discards), NeXT (aborts with error), SGI (aborts with - * error), Ultrix (sh seems to work, sh5 aborts with error)) -#define PROTECT_ENV - */ - -/* - * Define the macro NOECHO if you wish to omit rc's echo builtin from the - * compile. -#define NOECHO - */ - -/* - * Define the NOJOB if you do *not* wish rc to perform backgrounding - * as if it were a job-control shell; that is, if you do *not* wish - * it to put a command spawned in the background into a new process - * group. Since most systems support job control and since there are - * many broken programs that do not behave correctly when backgrounded - * in a v7 non-job-control fashion, rc by default performs a job- - * control-like backgrounding. -#define NOJOB - */ - -/* Beginning of defaults section: */ - -#ifndef CUSTOM - -/* - * Suggested settings for Sun, NeXT and sgi (machines here at TAMU): - */ - -#ifdef NeXT /* Used on NextOS 2.1 */ -#define NODIRENT -#define PROTECT_ENV -#define NOCMDARG -#endif - -#ifdef sgi /* Used on Irix 3.3.[12] */ -#define SVSIGS -#define NOSIGCLD -#define PROTECT_ENV -#undef DEFAULTPATH -#define DEFAULTPATH "/usr/bsd", "/usr/sbin", "/usr/bin", "/bin", "." -#endif - -#ifdef sun /* Used on SunOS 4.1.1 */ -#define PROTECT_ENV -#undef DEFAULTPATH -#define DEFAULTPATH "/usr/ucb", "/usr/bin", "." -#endif - -/* - * Suggested settings for HP300 running 4.3BSD-utah (DWS): - */ - -#if defined(hp300) && !defined(hpux) -#define NODIRENT -#define NOCMDARG -#define DEFAULTINTERP "/bin/sh" -#define PROTECT_ENV -#endif - -/* - * Suggested settings for Ultrix - */ - -#ifdef ultrix -#define PROTECT_ENV -#define DEFAULTINTERP "/bin/sh" /* so /bin/true can work */ -#endif - -/* - * Suggested settings for RISCos 4.52 - */ - -/* - This doesn't work without interfering with other MIPS-based - systems' configuration. Please do it by hand. -*/ - -#if defined(host_mips) && defined(MIPSEB) && defined(SYSTYPE_BSD43) -#define NODIRENT -#define PROTECT_ENV -#endif - -/* - * Suggested settings for AIX - */ - -#ifdef _AIX -#define PROTECT_ENV -#endif - -/* - * Suggested settings for OSF/1 1.0 - */ - -#ifdef OSF1 -#define PROTECT_ENV -#endif - -/* - * Suggested settings for Unicos XXX - */ - -#ifdef cray -#define PROTECT_ENV -#define NOLIMITS -#define word _word -#define DEFAULTINTERP "/bin/sh" -#endif - -#endif /* CUSTOM */ - -#ifndef TMPDIR -#define TMPDIR "/tmp" -#endif diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..3c8bde8 --- /dev/null +++ b/config.h.in @@ -0,0 +1,44 @@ +/* Header files */ +#undef STDC_HEADERS + +#undef HAVE_SYS_RESOURCE_H +#undef RLIMIT_NEEDS_KERNEL +#undef HAVE_SYS_TIME_H +#undef HAVE_UNISTD_H + +#undef HAVE_DIRENT_H +#undef HAVE_SYS_NDIR_H +#undef HAVE_SYS_DIR_H +#undef HAVE_NDIR_H + +/* Functions */ +#undef HAVE_GETGROUPS +#undef HAVE_SETPGRP +#undef HAVE_SETRLIMIT + +/* Types */ +#undef HAVE_GID_T +#undef HAVE_RLIM_T +#undef HAVE_QUAD_T +#undef RLIM_T_IS_QUAD_T +#undef GETGROUPS_T +#undef gid_t +#undef pid_t +#undef size_t +#undef uid_t + +/* OS features */ +#undef HASH_BANG +#undef HAVE_DEV_FD +#undef HAVE_FIFO +#undef HAVE_PROC_SELF_FD +#undef HAVE_RESTARTABLE_SYSCALLS +#undef SETPGRP_VOID + +/* rc features */ +#undef DEFAULTINTERP +#undef DEFAULTPATH +#undef RC_ECHO +#undef RC_JOB +#undef PROTECT_ENV +#undef READLINE diff --git a/configure b/configure new file mode 100755 index 0000000..9460c76 --- /dev/null +++ b/configure @@ -0,0 +1,2541 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --disable-builtin-echo Don't include \`echo' as a builtin" +ac_help="$ac_help + --disable-job Don't do job-control-style backgrounding" +ac_help="$ac_help + --disable-protect-env Don't protect environment names" +ac_help="$ac_help + --enable-def-interp=/bin/foo + Use /bin/foo as default interpreter [/bin/sh]" +ac_help="$ac_help + --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" + Default path [All of these that exist + (/usr/local/bin /usr/bin /usr/ucb /bin .)]" +ac_help="$ac_help + --enable-history Build history subprograms" +ac_help="$ac_help + --with-addon Extra builtins, from addon.c " +ac_help="$ac_help + --with-editline Simmule Turner's line editing" +ac_help="$ac_help + --with-readline Bloated GNU line editing" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=rc.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:549: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:578: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:626: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:660: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:665: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:689: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +case "x$GCC" in +xyes) + CFLAGS="-Wall $CFLAGS" + ;; +esac + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:752: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:806: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +for ac_prog in ln cp +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:840: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LN"; then + ac_cv_prog_LN="$LN" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LN="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LN="$ac_cv_prog_LN" +if test -n "$LN"; then + echo "$ac_t""$LN" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LN" && break +done + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:870: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:891: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:908: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in sys/resource.h sys/time.h sys/types.h unistd.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:934: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:944: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:975: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:988: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:1013: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:1054: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1096: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1109: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + + +echo $ac_n "checking for signal names in ""... $ac_c" 1>&6 +echo "configure:1201: checking for signal names in " >&5 +if eval "test \"`echo '$''{'rc_cv_sys_signal_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if grep SIGINT /usr/include/sys/signal.h >/dev/null 2>&1; then + rc_cv_sys_signal_h=yes + else + rc_cv_sys_signal_h=no + fi +fi + +echo "$ac_t""$rc_cv_sys_signal_h" 1>&6 + +case "x$rc_cv_sys_signal_h" in +xyes) + SIGNAL_H=/usr/include/sys/signal.h + ;; +xno) + echo $ac_n "checking for signal names in ""... $ac_c" 1>&6 +echo "configure:1220: checking for signal names in " >&5 +if eval "test \"`echo '$''{'rc_cv_asm_signal_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if grep SIGINT /usr/include/asm/signal.h >/dev/null 2>&1; then + rc_cv_asm_signal_h=yes + else + rc_cv_asm_signal_h=no + fi +fi + +echo "$ac_t""$rc_cv_asm_signal_h" 1>&6 + + case "x$rc_cv_asm_signal_h" in + xyes) + SIGNAL_H=/usr/include/asm/signal.h + ;; + xno) + { echo "configure: error: Can't find signal names in or " 1>&2; exit 1; } + ;; + esac + ;; +esac + + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:1246: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 +echo "configure:1280: checking type of array argument to getgroups" >&5 +if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_type_getgroups=cross +else + cat > conftest.$ac_ext < +#define NGID 256 +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +main() +{ + gid_t gidset[NGID]; + int i, n; + union { gid_t gval; long lval; } val; + + val.lval = -1; + for (i = 0; i < NGID; i++) + gidset[i] = val.gval; + n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, + gidset); + /* Exit non-zero if getgroups seems to require an array of ints. This + happens when gid_t is short but getgroups modifies an array of ints. */ + exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); +} + +EOF +if { (eval echo configure:1313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_type_getgroups=gid_t +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_type_getgroups=int +fi +rm -fr conftest* +fi + +if test $ac_cv_type_getgroups = cross; then + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "getgroups.*int.*gid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_getgroups=gid_t +else + rm -rf conftest* + ac_cv_type_getgroups=int +fi +rm -f conftest* + +fi +fi + +echo "$ac_t""$ac_cv_type_getgroups" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1351: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:1384: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:1417: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + + +for ac_func in getgroups setpgrp setrlimit +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1454: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1482: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 +echo "configure:1508: checking whether setpgrp takes no argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setpgrp_void=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setpgrp_void=yes +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6 +if test $ac_cv_func_setpgrp_void = yes; then + cat >> confdefs.h <<\EOF +#define SETPGRP_VOID 1 +EOF + +fi + + +echo $ac_n "checking if _KERNEL is required for RLIMIT defines""... $ac_c" 1>&6 +echo "configure:1557: checking if _KERNEL is required for RLIMIT defines" >&5 +if eval "test \"`echo '$''{'rc_cv_kernel_rlimit'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include + +int main() { + +int f; +f = RLIMIT_DATA; + +; return 0; } +EOF +if { (eval echo configure:1575: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + rc_cv_kernel_rlimit=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat > conftest.$ac_ext < +#define _KERNEL +#include +#undef _KERNEL + +int main() { + +int f; +f = RLIMIT_DATA; + +; return 0; } +EOF +if { (eval echo configure:1598: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + rc_cv_kernel_rlimit=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + rc_cv_kernel_rlimit=no +fi +rm -f conftest* +fi +rm -f conftest* +fi + +echo "$ac_t""$rc_cv_kernel_rlimit" 1>&6 +case "x$rc_cv_kernel_rlimit" in +xyes) + cat >> confdefs.h <<\EOF +#define RLIMIT_NEEDS_KERNEL 1 +EOF + + ;; +esac + +echo $ac_n "checking for rlim_t""... $ac_c" 1>&6 +echo "configure:1623: checking for rlim_t" >&5 +if eval "test \"`echo '$''{'rc_cv_have_rlim_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "rlim_t" >/dev/null 2>&1; then + rm -rf conftest* + rc_cv_have_rlim_t=yes +else + rm -rf conftest* + rc_cv_have_rlim_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$rc_cv_have_rlim_t" 1>&6 + +case "x$rc_cv_have_rlim_t" in +xyes) + cat >> confdefs.h <<\EOF +#define HAVE_RLIM_T 1 +EOF + + ;; +xno) + echo $ac_n "checking for native quad_t""... $ac_c" 1>&6 +echo "configure:1661: checking for native quad_t" >&5 +if eval "test \"`echo '$''{'rc_cv_have_quad_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() { + quad_t q; + q = 0; + exit((int) q); +} + +EOF +if { (eval echo configure:1680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + rc_cv_have_quad_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + rc_cv_have_quad_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$rc_cv_have_quad_t" 1>&6 + + case "x$rc_cv_have_quad_t" in + xyes) + cat >> confdefs.h <<\EOF +#define HAVE_QUAD_T 1 +EOF + + + echo $ac_n "checking if rlimit values are quad_t""... $ac_c" 1>&6 +echo "configure:1704: checking if rlimit values are quad_t" >&5 +if eval "test \"`echo '$''{'rc_cv_rlim_t_is_quad_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + $ac_cv_type_quad_t +else + cat > conftest.$ac_ext < +#include +#include +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include +#if RLIMIT_NEEDS_KERNEL +#undef _KERNEL +#endif +main(){ + struct rlimit rl; + exit(sizeof rl.rlim_cur != sizeof(quad_t)); +} + +EOF +if { (eval echo configure:1731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + rc_cv_rlim_t_is_quad_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + rc_cv_rlim_t_is_quad_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$rc_cv_rlim_t_is_quad_t" 1>&6 + + case "x$rc_cv_rlim_t_is_quad_t" in + xyes) + cat >> confdefs.h <<\EOF +#define RLIM_T_IS_QUAD_T 1 +EOF + + ;; + esac + ;; + esac + ;; +esac + +echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6 +echo "configure:1761: checking for restartable system calls" >&5 +if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +ucatch (isig) { } +main () { + int i = fork (), status; + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + signal (SIGINT, ucatch); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +} + +EOF +if { (eval echo configure:1787: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sys_restartable_syscalls=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sys_restartable_syscalls=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_sys_restartable_syscalls" 1>&6 +if test $ac_cv_sys_restartable_syscalls = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_RESTARTABLE_SYSCALLS 1 +EOF + +fi + + +# Pull the hash mark out of the macro call to avoid m4 problems. +ac_msg="whether #! works in shell scripts" +echo $ac_n "checking $ac_msg""... $ac_c" 1>&6 +echo "configure:1813: checking $ac_msg" >&5 +if eval "test \"`echo '$''{'ac_cv_sys_interpreter'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo '#! /bin/cat +exit 69 +' > conftest +chmod u+x conftest +(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null) +if test $? -ne 69; then + ac_cv_sys_interpreter=yes +else + ac_cv_sys_interpreter=no +fi +rm -f conftest +fi + +echo "$ac_t""$ac_cv_sys_interpreter" 1>&6 + +case "x$ac_cv_sys_interpreter" in +xyes) + cat >> confdefs.h <<\EOF +#define HASH_BANG 1 +EOF + + EXECVE='' + ;; +xno) + EXECVE=execve.o +esac + + +echo $ac_n "checking for /dev/fd""... $ac_c" 1>&6 +echo "configure:1846: checking for /dev/fd" >&5 +if eval "test \"`echo '$''{'rc_cv_sys_dev_fd'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -d /dev/fd && test -r /dev/fd/0; then + rc_cv_sys_dev_fd=yes + elif test -d /proc/self/fd && test -r /proc/self/fd/0; then + rc_cv_sys_dev_fd=odd + else + rc_cv_sys_dev_fd=no + fi +fi + +echo "$ac_t""$rc_cv_sys_dev_fd" 1>&6 + +case "x$rc_cv_sys_dev_fd" in +xyes) + cat >> confdefs.h <<\EOF +#define HAVE_DEV_FD 1 +EOF + + ;; +xodd) + cat >> confdefs.h <<\EOF +#define HAVE_PROC_SELF_FD 1 +EOF + + ;; +xno) + echo $ac_n "checking for named pipes""... $ac_c" 1>&6 +echo "configure:1876: checking for named pipes" >&5 +if eval "test \"`echo '$''{'rc_cv_sys_fifo'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat >> confdefs.h < conftest.$ac_ext < +#include + +main() { + exit(mknod(TMPNAM, S_IFIFO | 0666, 0) != 0); +} + +EOF +if { (eval echo configure:1899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + rc_cv_sys_fifo=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + rc_cv_sys_fifo=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$rc_cv_sys_fifo" 1>&6 + case "x$rc_cv_sys_fifo" in + xyes) + cat >> confdefs.h <<\EOF +#define HAVE_FIFO 1 +EOF + + ;; + esac +esac + +# Check whether --enable-builtin-echo or --disable-builtin-echo was given. +if test "${enable_builtin_echo+set}" = set; then + enableval="$enable_builtin_echo" + test "x$enableval" != "xno" && cat >> confdefs.h <<\EOF +#define RC_ECHO 1 +EOF + +else + cat >> confdefs.h <<\EOF +#define RC_ECHO 1 +EOF + +fi + + +# Check whether --enable-job or --disable-job was given. +if test "${enable_job+set}" = set; then + enableval="$enable_job" + test "x$enableval" != "xno" && cat >> confdefs.h <<\EOF +#define RC_JOB 1 +EOF + +else + cat >> confdefs.h <<\EOF +#define RC_JOB 1 +EOF + +fi + + +# Check whether --enable-protect-env or --disable-protect-env was given. +if test "${enable_protect_env+set}" = set; then + enableval="$enable_protect_env" + test "x$enableval" != "xno" && cat >> confdefs.h <<\EOF +#define PROTECT_ENV 1 +EOF + +else + cat >> confdefs.h <<\EOF +#define PROTECT_ENV 1 +EOF + +fi + + +# Check whether --enable-def-interp or --disable-def-interp was given. +if test "${enable_def_interp+set}" = set; then + enableval="$enable_def_interp" + + case "x$enableval" in + xno) + ;; + xyes) + cat >> confdefs.h <<\EOF +#define DEFAULTINTERP "/bin/sh" +EOF + + ;; + *) + cat >> confdefs.h <> confdefs.h <<\EOF +#define DEFAULTINTERP "/bin/sh" +EOF + +fi + + +# Check whether --enable-def-path or --disable-def-path was given. +if test "${enable_def_path+set}" = set; then + enableval="$enable_def_path" + + case "x$enableval" in + xno|xyes) + ;; + *) + cat >> confdefs.h <&6 +echo "configure:2019: checking extant directories for default path" >&5 +if eval "test \"`echo '$''{'rc_cv_def_path'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + rc_cv_def_path='' + for i in /usr/local/bin /usr/bin /usr/ucb /bin .; do + if test -d $i; then + case "x$rc_cv_def_path" in + x) + rc_cv_def_path=\"$i\" + ;; + *) + rc_cv_def_path=$rc_cv_def_path,\"$i\" + ;; + esac + fi + done + cat >> confdefs.h <&6 + ;; +esac + +# Check whether --enable-history or --disable-history was given. +if test "${enable_history+set}" = set; then + enableval="$enable_history" + test "x$enableval" != "xno" && rc_history=yes +else + rc_history=no +fi + +case "x$rc_history" in +xyes) + HISTORY=history/history + ;; +esac + + +# Check whether --with-addon or --without-addon was given. +if test "${with_addon+set}" = set; then + withval="$with_addon" + + case "x$withval" in + xyes) + ADDON=addon.o + ;; + xno) + ADDON='' + ;; + *) + ADDON=$withval + ;; + esac + +fi + + + +# Check whether --with-editline or --without-editline was given. +if test "${with_editline+set}" = set; then + withval="$with_editline" + echo $ac_n "checking for readline in -ledit""... $ac_c" 1>&6 +echo "configure:2087: checking for readline in -ledit" >&5 +ac_lib_var=`echo edit'_'readline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ledit $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define READLINE 1 +EOF + LIBS="$LIBS -ledit" +else + echo "$ac_t""no" 1>&6 +echo "configure: warning: editline library not found" 1>&2 +fi + +fi + + +# Check whether --with-readline or --without-readline was given. +if test "${with_readline+set}" = set; then + withval="$with_readline" + echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 +echo "configure:2137: checking for readline in -lreadline" >&5 +ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lreadline $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define READLINE 1 +EOF + LIBS="$LIBS -lreadline -ltermcap" +else + echo "$ac_t""no" 1>&6 +echo "configure: warning: readline library not found" 1>&2 +fi + +fi + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@CC@%$CC%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@YACC@%$YACC%g +s%@LN@%$LN%g +s%@CPP@%$CPP%g +s%@SIGNAL_H@%$SIGNAL_H%g +s%@EXECVE@%$EXECVE%g +s%@HISTORY@%$HISTORY%g +s%@ADDON@%$ADDON%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..86a97bb --- /dev/null +++ b/configure.in @@ -0,0 +1,287 @@ +AC_INIT(rc.h) + +AC_CONFIG_HEADER(config.h) + +AC_PROG_CC +case "x$GCC" in +xyes) + CFLAGS="-Wall $CFLAGS" + ;; +esac + +AC_PROG_INSTALL +AC_PROG_YACC +AC_CHECK_PROGS(LN, ln cp) + +AC_CHECK_HEADERS(sys/resource.h sys/time.h sys/types.h unistd.h) +AC_HEADER_DIRENT +AC_HEADER_STDC + +dnl Linux puts real signal names in /usr/include/asm/signal.h. +AC_CACHE_CHECK(for signal names in , rc_cv_sys_signal_h, + if grep SIGINT /usr/include/sys/signal.h >/dev/null 2>&1; then + rc_cv_sys_signal_h=yes + else + rc_cv_sys_signal_h=no + fi) + +case "x$rc_cv_sys_signal_h" in +xyes) + SIGNAL_H=/usr/include/sys/signal.h + ;; +xno) + AC_CACHE_CHECK(for signal names in , rc_cv_asm_signal_h, + if grep SIGINT /usr/include/asm/signal.h >/dev/null 2>&1; then + rc_cv_asm_signal_h=yes + else + rc_cv_asm_signal_h=no + fi) + + case "x$rc_cv_asm_signal_h" in + xyes) + SIGNAL_H=/usr/include/asm/signal.h + ;; + xno) + AC_MSG_ERROR(Can't find signal names in or ) + ;; + esac + ;; +esac +AC_SUBST(SIGNAL_H) + +AC_TYPE_GETGROUPS +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UID_T + +AC_CHECK_FUNCS(getgroups setpgrp setrlimit) + +AC_FUNC_SETPGRP + +dnl HPUX needs _KERNEL defined to pick up RLIMIT_foo defines. (Why?) +AC_CACHE_CHECK(if _KERNEL is required for RLIMIT defines, rc_cv_kernel_rlimit, + AC_TRY_COMPILE([ +#include +#include + ], [ +int f; +f = RLIMIT_DATA; + ], rc_cv_kernel_rlimit=no, [ AC_TRY_COMPILE([ +#include +#define _KERNEL +#include +#undef _KERNEL + ], [ +int f; +f = RLIMIT_DATA; + ], rc_cv_kernel_rlimit=yes, rc_cv_kernel_rlimit=no)])) +case "x$rc_cv_kernel_rlimit" in +xyes) + AC_DEFINE(RLIMIT_NEEDS_KERNEL) + ;; +esac + +dnl Look for rlim_t in sys/types.h and sys/resource.h +AC_CACHE_CHECK(for rlim_t, rc_cv_have_rlim_t, + AC_EGREP_CPP(rlim_t, [ +#include +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include + ], rc_cv_have_rlim_t=yes, rc_cv_have_rlim_t=no)) + +case "x$rc_cv_have_rlim_t" in +xyes) + AC_DEFINE(HAVE_RLIM_T) + ;; +xno) + AC_CACHE_CHECK(for native quad_t, rc_cv_have_quad_t, + AC_TRY_RUN([ +#include +main() { + quad_t q; + q = 0; + exit((int) q); +} + ], rc_cv_have_quad_t=yes, rc_cv_have_quad_t=no)) + + case "x$rc_cv_have_quad_t" in + xyes) + AC_DEFINE(HAVE_QUAD_T) + + AC_CACHE_CHECK(if rlimit values are quad_t, rc_cv_rlim_t_is_quad_t, + AC_TRY_RUN([ +#include +#include +#include +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include +#if RLIMIT_NEEDS_KERNEL +#undef _KERNEL +#endif +main(){ + struct rlimit rl; + exit(sizeof rl.rlim_cur != sizeof(quad_t)); +} + ], rc_cv_rlim_t_is_quad_t=yes, rc_cv_rlim_t_is_quad_t=no, $ac_cv_type_quad_t)) + + case "x$rc_cv_rlim_t_is_quad_t" in + xyes) + AC_DEFINE(RLIM_T_IS_QUAD_T) + ;; + esac + ;; + esac + ;; +esac + +AC_SYS_RESTARTABLE_SYSCALLS + +dnl Does the kernel handle `#! /interpreter'? +AC_SYS_INTERPRETER +case "x$ac_cv_sys_interpreter" in +xyes) + AC_DEFINE(HASH_BANG) + EXECVE='' + ;; +xno) + EXECVE=execve.o +esac +AC_SUBST(EXECVE) + +AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd, + if test -d /dev/fd && test -r /dev/fd/0; then + rc_cv_sys_dev_fd=yes + elif test -d /proc/self/fd && test -r /proc/self/fd/0; then + rc_cv_sys_dev_fd=odd + else + rc_cv_sys_dev_fd=no + fi) + +case "x$rc_cv_sys_dev_fd" in +xyes) + AC_DEFINE(HAVE_DEV_FD) + ;; +xodd) + AC_DEFINE(HAVE_PROC_SELF_FD) + ;; +xno) + AC_CACHE_CHECK(for named pipes, rc_cv_sys_fifo, + AC_DEFINE_UNQUOTED(TMPNAM, "/tmp/rc$$.0") + AC_TRY_RUN([ +#include +#include + +main() { + exit(mknod(TMPNAM, S_IFIFO | 0666, 0) != 0); +} + ], rc_cv_sys_fifo=yes, rc_cv_sys_fifo=no, rc_cv_sys_fifo=no)) + case "x$rc_cv_sys_fifo" in + xyes) + AC_DEFINE(HAVE_FIFO) + ;; + esac +esac + +AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], + test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO), + AC_DEFINE(RC_ECHO)) + +AC_ARG_ENABLE(job, [ --disable-job Don't do job-control-style backgrounding], + test "x$enableval" != "xno" && AC_DEFINE(RC_JOB), + AC_DEFINE(RC_JOB)) + +AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment names], + test "x$enableval" != "xno" && AC_DEFINE(PROTECT_ENV), + AC_DEFINE(PROTECT_ENV)) + +AC_ARG_ENABLE(def-interp, +[ --enable-def-interp=/bin/foo + Use /bin/foo as default interpreter [/bin/sh]], +[ + case "x$enableval" in + xno) + ;; + xyes) + AC_DEFINE(DEFAULTINTERP, "/bin/sh") + ;; + *) + AC_DEFINE_UNQUOTED(DEFAULTINTERP, "$enableval") + esac +], + AC_DEFINE(DEFAULTINTERP, "/bin/sh")) + +AC_ARG_ENABLE(def-path, +[ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" + Default path [All of these that exist + (/usr/local/bin /usr/bin /usr/ucb /bin .)]], +[ + case "x$enableval" in + xno|xyes) + ;; + *) + AC_DEFINE_UNQUOTED(DEFAULTPATH, $enableval) + esac +], + enable_def_path=yes) + +case "x$enable_def_path" in +xyes) + AC_CACHE_CHECK(extant directories for default path, rc_cv_def_path,[ + rc_cv_def_path='' + for i in /usr/local/bin /usr/bin /usr/ucb /bin .; do + if test -d $i; then + case "x$rc_cv_def_path" in + x) + rc_cv_def_path=\"$i\" + ;; + *) + rc_cv_def_path=$rc_cv_def_path,\"$i\" + ;; + esac + fi + done + AC_DEFINE_UNQUOTED(DEFAULTPATH, $rc_cv_def_path) + ]) + ;; +esac + +AC_ARG_ENABLE(history, [ --enable-history Build history subprograms], + test "x$enableval" != "xno" && rc_history=yes, + rc_history=no) +case "x$rc_history" in +xyes) + HISTORY=history/history + ;; +esac +AC_SUBST(HISTORY) + +AC_ARG_WITH(addon, [ --with-addon Extra builtins, from addon.c ],[ + case "x$withval" in + xyes) + ADDON=addon.o + ;; + xno) + ADDON='' + ;; + *) + ADDON=$withval + ;; + esac + ]) +AC_SUBST(ADDON) + +AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], + AC_CHECK_LIB(edit, readline, + AC_DEFINE(READLINE) LIBS="$LIBS -ledit", + AC_MSG_WARN(editline library not found))) + +AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], + AC_CHECK_LIB(readline, readline, + AC_DEFINE(READLINE) LIBS="$LIBS -lreadline -ltermcap", + AC_MSG_WARN(readline library not found))) + +AC_OUTPUT(Makefile) diff --git a/exec.c b/exec.c index 8ed8ead..6a0082e 100644 --- a/exec.c +++ b/exec.c @@ -12,7 +12,8 @@ extern void exec(List *s, bool parent) { char **av, **ev = NULL; - int pid, stat; + int stat; + pid_t pid; builtin_t *b; char *path = NULL; bool didfork, returning, saw_exec, saw_builtin; @@ -91,16 +92,17 @@ extern void exec(List *s, bool parent) { return; rc_exit(getstatus()); } -#ifdef NOEXECVE - my_execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */ +#if HASH_BANG + execve(path, (char * const *) av, (char * const *) ev); #else - execve(path, (const char **) av, (const char **) ev); + my_execve(path, (char * const *) av, (char * const *) ev); /* bogus, huh? */ #endif + #ifdef DEFAULTINTERP if (errno == ENOEXEC) { *av = path; *--av = DEFAULTINTERP; - execve(*av, (const char **) av, (const char **) ev); + execve(*av, (char * const *) av, (char * const *) ev); } #endif uerror(*av); diff --git a/fn.c b/fn.c index 56c5e86..053ed89 100644 --- a/fn.c +++ b/fn.c @@ -26,7 +26,7 @@ extern void inithandler() { null.type = nBody; null.u[0].p = null.u[1].p = NULL; for (i = 1; i < NUMOFSIGNALS; i++) -#ifdef NOSIGCLD +#ifndef HAVE_RESTARTABLE_SYSCALLS if (i != SIGCLD) #endif if (sighandlers[i] == SIG_IGN) @@ -148,7 +148,7 @@ extern void fnassign(char *name, Node *def) { new->def = newdef; new->extdef = NULL; if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */ -#ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */ +#ifndef HAVE_RESTARTABLE_SYSCALLS /* System V machines treat SIGCLD very specially */ if (streq(name, "sigcld")) rc_error("can't trap SIGCLD"); #endif diff --git a/footobar.c b/footobar.c index 2440f5a..27955ba 100644 --- a/footobar.c +++ b/footobar.c @@ -7,7 +7,7 @@ /* protect an exported name from brain-dead shells */ -#ifdef PROTECT_ENV +#if PROTECT_ENV static bool Fconv(Format *f, int ignore) { unsigned const char *s = va_arg(f->args, unsigned const char *); int c; @@ -192,7 +192,7 @@ extern char *get_name(char *s) { case '=': *r++ = '\0'; return result; -#ifdef PROTECT_ENV +#if PROTECT_ENV case '_': if (*s == '_') { static const char hexchar[] = "0123456789abcdef"; @@ -329,7 +329,7 @@ void initprint(void) { fmtinstall('S', Sconv); fmtinstall('T', Tconv); fmtinstall('D', Dconv); -#ifdef PROTECT_ENV +#if PROTECT_ENV fmtinstall('F', Fconv); #else fmtinstall('F', fmtinstall('s', NULL)); diff --git a/glob.c b/glob.c index bdd3b6c..043f767 100644 --- a/glob.c +++ b/glob.c @@ -3,16 +3,28 @@ #include #include #include "rc.h" -#ifdef NODIRENT -#include -#define dirent direct /* need to get the struct declaraction right */ + +/* Lifted from autoconf documentation.*/ +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) #else -#include +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif #endif static List *dmatch(char *, char *, char *); static List *doglob(char *, char *); -static List *lglob(List *, char *, char *, SIZE_T); +static List *lglob(List *, char *, char *, size_t); static List *sort(List *); /* @@ -90,10 +102,6 @@ static List *dmatch(char *d, char *p, char *m) { static DIR *dirp; static struct dirent *dp; static struct stat s; - /* prototypes for XXXdir functions. comment out if necessary */ - extern DIR *opendir(const char *); - extern struct dirent *readdir(DIR *); - /*extern int closedir(DIR *);*/ int i; /* @@ -151,11 +159,11 @@ static List *dmatch(char *d, char *p, char *m) { matched name. e.g., for matching ////tmp/////foo* */ -static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) { +static List *lglob(List *s, char *p, char *m, size_t slashcount) { List *q, *r, *top, foo; static struct { List l; - SIZE_T size; + size_t size; } slash; if (slashcount+1 > slash.size) { slash.size = 2*(slashcount+1); @@ -191,9 +199,9 @@ static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) { static List *doglob(char *w, char *m) { static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL; - static SIZE_T dsize = 0; + static size_t dsize = 0; char *d, *p, *md, *mp; - SIZE_T psize; + size_t psize; char *s = w; List firstdir; List *matched; @@ -238,7 +246,7 @@ static List *doglob(char *w, char *m) { matched = dmatch(".", dir, metadir); } do { - SIZE_T slashcount; + size_t slashcount; sigchk(); for (slashcount = 0; *s == '/'; s++, m++) slashcount++; /* skip slashes */ @@ -258,7 +266,7 @@ end: if (matched == NULL) { } static List *sort(List *s) { - SIZE_T nel = listnel(s); + size_t nel = listnel(s); if (nel > 1) { char **a; List *t; diff --git a/glom.c b/glom.c index d0b1705..e835ed2 100644 --- a/glom.c +++ b/glom.c @@ -5,9 +5,6 @@ #include #include #include "rc.h" -#if !defined(S_IFIFO) && !defined(DEVFD) -#define NOCMDARG -#endif static List *backq(Node *, Node *); static List *bqinput(List *, int); @@ -58,9 +55,9 @@ extern List *concat(List *s1, List *s2) { if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1) rc_error("bad concatenation"); for (r = top = nnew(List); 1; r = r->n = nnew(List)) { - SIZE_T x = strlen(s1->w); - SIZE_T y = strlen(s2->w); - SIZE_T z = x + y + 1; + size_t x = strlen(s1->w); + size_t y = strlen(s2->w); + size_t z = x + y + 1; r->w = nalloc(z); strcpy(r->w, s1->w); strcat(r->w, s2->w); @@ -115,7 +112,7 @@ extern List *varsub(List *var, List *subs) { extern List *flatten(List *s) { List *r; - SIZE_T step; + size_t step; char *f; if (s == NULL || s->n == NULL) return s; @@ -175,12 +172,12 @@ extern void assign(List *s1, List *s2, bool stack) { who could not stand the incompetence of my own backquote implementation. */ -#define BUFSIZE ((SIZE_T) 1000) +#define BUFSIZE ((size_t) 1000) static List *bqinput(List *ifs, int fd) { char *end, *bufend, *s; List *r, *top, *prev; - SIZE_T remain, bufsize; + size_t remain, bufsize; char isifs[256]; int n, state; /* a simple FSA is used to read in data */ @@ -197,7 +194,7 @@ static List *bqinput(List *ifs, int fd) { while (1) { if (remain == 0) { /* is the string bigger than the buffer? */ - SIZE_T m = end - r->w; + size_t m = end - r->w; char *buf; while (bufsize < m + BUFSIZE) bufsize *= 2; @@ -249,7 +246,8 @@ static List *bqinput(List *ifs, int fd) { } static List *backq(Node *ifs, Node *n) { - int p[2], pid, sp; + int p[2], sp; + pid_t pid; List *bq; if (n == NULL) return NULL; @@ -288,13 +286,44 @@ extern void qredir(Node *n) { next->n = NULL; } -#ifdef NOCMDARG +#if HAVE_DEV_FD || HAVE_PROC_SELF_FD static List *mkcmdarg(Node *n) { - rc_error("named pipes are not supported"); - return NULL; -} + char *name; + List *ret = nnew(List); + Estack *e = nnew(Estack); + Edata efd; + int p[2]; + if (pipe(p) < 0) { + uerror("pipe"); + return NULL; + } + if (rc_fork() == 0) { + setsigdefaults(FALSE); + if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */ + exit(1); + close(p[n->u[0].i != rFrom]); + redirq = NULL; + walk(n->u[2].p, FALSE); + exit(getstatus()); + } + +#if HAVE_DEV_FD + name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]); #else -#ifndef DEVFD + name = nprint("/proc/self/fd/%d", p[n->u[0].i != rFrom]); +#endif + + efd.fd = p[n->u[0].i != rFrom]; + except(eFd, efd, e); + close(p[n->u[0].i == rFrom]); + ret->w = name; + ret->m = NULL; + ret->n = NULL; + return ret; +} + +#elif HAVE_FIFO + static List *mkcmdarg(Node *n) { int fd; char *name; @@ -302,7 +331,7 @@ static List *mkcmdarg(Node *n) { Estack *e = enew(Estack); List *ret = nnew(List); static int fifonumber = 0; - name = nprint("%s/rc%d.%d", TMPDIR, getpid(), fifonumber++); + name = nprint("/tmp/rc%d.%d", getpid(), fifonumber++); if (mknod(name, S_IFIFO | 0666, 0) < 0) { uerror("mknod"); return NULL; @@ -327,37 +356,15 @@ static List *mkcmdarg(Node *n) { ret->n = NULL; return ret; } + #else + static List *mkcmdarg(Node *n) { - char *name; - List *ret = nnew(List); - Estack *e = nnew(Estack); - Edata efd; - int p[2]; - if (pipe(p) < 0) { - uerror("pipe"); - return NULL; - } - if (rc_fork() == 0) { - setsigdefaults(FALSE); - if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */ - exit(1); - close(p[n->u[0].i != rFrom]); - redirq = NULL; - walk(n->u[2].p, FALSE); - exit(getstatus()); - } - name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]); - efd.fd = p[n->u[0].i != rFrom]; - except(eFd, efd, e); - close(p[n->u[0].i == rFrom]); - ret->w = name; - ret->m = NULL; - ret->n = NULL; - return ret; + rc_error("named pipes are not supported"); + return NULL; } -#endif /* DEVFD */ -#endif /* !NOCMDARG */ + +#endif extern List *glom(Node *n) { List *v, *head, *tail; diff --git a/group.h b/group.h new file mode 100644 index 0000000..8e78468 --- /dev/null +++ b/group.h @@ -0,0 +1,9 @@ +/* Solaris / `gcc -ansi' only defines NGROUPS_MAX in if +_POSIX_C_SOURCE is defined. */ +#define _POSIX_C_SOURCE 1 +#include +#undef _POSIX_C_SOURCE + +#if defined(NGROUPS) && !defined(NGROUPS_MAX) +#define NGROUPS_MAX NGROUPS +#endif diff --git a/hash.c b/hash.c index 2c8acd5..9f75b6c 100644 --- a/hash.c +++ b/hash.c @@ -275,7 +275,7 @@ extern char **makeenv() { env[ep++] = fnlookup_string(fp[i].name); } env[ep] = NULL; - qsort(env, (SIZE_T) ep, sizeof(char *), starstrcmp); + qsort(env, (size_t) ep, sizeof(char *), starstrcmp); return env; } @@ -294,7 +294,7 @@ extern void whatare_all_vars(bool showfn, bool showvar) { /* fake getenv() for readline() follows: */ -#ifdef READLINE +#if READLINE extern char *getenv(const char *name) { List *s; if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL) diff --git a/heredoc.c b/heredoc.c index 3930d9e..ba4fd3a 100644 --- a/heredoc.c +++ b/heredoc.c @@ -26,7 +26,7 @@ static char *readheredoc(char *eof) { int c; char *t, *buf, *bufend; unsigned char *s; - SIZE_T bufsize; + size_t bufsize; t = buf = nalloc(bufsize = 512); bufend = &buf[bufsize]; dead = FALSE; @@ -34,7 +34,7 @@ static char *readheredoc(char *eof) { char *nbuf; \ bufsize = bufsize * 2 + extra; \ nbuf = nalloc(bufsize); \ - memcpy(nbuf, buf, (SIZE_T) (t - buf)); \ + memcpy(nbuf, buf, (size_t) (t - buf)); \ t = nbuf + (t - buf); \ buf = nbuf; \ bufend = &buf[bufsize]; \ @@ -48,7 +48,7 @@ static char *readheredoc(char *eof) { return buf; } if (s != (unsigned char *) eof) { - SIZE_T len = s - (unsigned char *) eof; + size_t len = s - (unsigned char *) eof; if (t + len >= bufend) RESIZE(len); memcpy(t, eof, len); @@ -92,7 +92,7 @@ static Node *parseheredoc(char *s) { node = mk(nQword, "$", NULL); c = *s; } else { - SIZE_T len = 0; + size_t len = 0; do len++; while (!dnw[c = *(unsigned char *) s++]); diff --git a/history/Makefile b/history/Makefile deleted file mode 100644 index 4655947..0000000 --- a/history/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -CC=gcc -g -O - -history: history.c - $(CC) -o history history.c - @echo 'Now install "history" as -, --, -p and --p in your bin directory' - @echo '(for example, by making them links to the same file)' diff --git a/input.c b/input.c index 24e0070..3b60677 100644 --- a/input.c +++ b/input.c @@ -18,9 +18,9 @@ typedef struct Input { bool saved, eofread; } Input; -#define BUFSIZE ((SIZE_T) 256) +#define BUFSIZE ((size_t) 256) -#ifdef READLINE +#if READLINE extern char *readline(char *); extern void add_history(char *); static char *rlinebuf; @@ -37,7 +37,7 @@ static void ugdead(int); static void pushcommon(void); static char *inbuf; -static SIZE_T istacksize, chars_out, chars_in; +static size_t istacksize, chars_out, chars_in; static bool eofread = FALSE, save_lineno = TRUE; static Input *istack, *itop; @@ -87,8 +87,8 @@ static int stringgchar() { /* signal-safe readline wrapper */ -#ifdef READLINE -#ifndef SVSIGS +#if READLINE +#ifndef HAVE_RESTARTABLE_SYSCALLS static char *rc_readline(char *prompt) { char *r; interrupt_happened = FALSE; @@ -108,7 +108,7 @@ static char *rc_readline(char *prompt) { } #else #define rc_readline readline -#endif /* SVSIGS */ +#endif /* HAVE_RESTARTABLE_SYSCALLS */ #endif /* READLINE */ /* @@ -119,9 +119,9 @@ static char *rc_readline(char *prompt) { static int fdgchar() { if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */ while (1) { -#ifdef READLINE +#if READLINE if (interactive && istack->fd == 0) { - rlinebuf = readline(prompt); + rlinebuf = rc_readline(prompt); if (rlinebuf == NULL) { chars_in = 0; } else { @@ -143,7 +143,7 @@ static int fdgchar() { uerror("read"); rc_exit(1); } - chars_in = (SIZE_T) r; + chars_in = (size_t) r; } break; } @@ -169,7 +169,7 @@ extern void initinput() { /* push an input source onto the stack. set up a new input buffer, and set gchar() */ static void pushcommon() { - SIZE_T idiff; + size_t idiff; istack->index = chars_out; istack->read = chars_in; istack->ibuf = inbuf; @@ -253,6 +253,7 @@ extern Node *doit(bool execit) { Jbwrap j; Estack e1, e2; Edata jerror; + if (dashen) execit = FALSE; setjmp(j.j); @@ -278,7 +279,7 @@ extern Node *doit(bool execit) { funcall(arglist); } if ((s = varlookup("prompt")) != NULL) { -#ifdef READLINE +#if READLINE prompt = s->w; #else fprint(2, "%s", s->w); @@ -322,7 +323,7 @@ extern Node *parseline(char *extdef) { static void history() { List *hist; - SIZE_T a; + size_t a; if (!interactive || (hist = varlookup("history")) == NULL) return; diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..ebc6691 --- /dev/null +++ b/install-sh @@ -0,0 +1,250 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/jbwrap.h b/jbwrap.h index a31ef19..7d0358b 100644 --- a/jbwrap.h +++ b/jbwrap.h @@ -1,3 +1,5 @@ +#include + /* certain braindamaged environments don't define jmp_buf as an array, so... */ struct Jbwrap { @@ -5,6 +7,3 @@ struct Jbwrap { }; extern Jbwrap slowbuf; /* for getting out of interrupts while performing slow i/o on BSD */ - -extern int setjmp(jmp_buf); -extern void longjmp(jmp_buf, int); diff --git a/lex.c b/lex.c index a4e4106..a763ce4 100644 --- a/lex.c +++ b/lex.c @@ -20,7 +20,7 @@ it declared in rc.h) */ -#define BUFSIZE ((SIZE_T) 1000) /* malloc hates power of 2 buffers? */ +#define BUFSIZE ((size_t) 1000) /* malloc hates power of 2 buffers? */ #define BUFMAX (8 * BUFSIZE) /* How big the buffer can get before we re-allocate the space at BUFSIZE again. Premature optimization? Maybe. */ @@ -55,7 +55,7 @@ const char dnw[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; -static SIZE_T bufsize = BUFSIZE; +static size_t bufsize = BUFSIZE; static char *realbuf = NULL; static bool newline = FALSE; static bool errset = FALSE; @@ -73,7 +73,7 @@ extern int yylex() { static bool dollar = FALSE; bool saw_meta = FALSE; int c; - SIZE_T i; /* The purpose of all these local assignments is to */ + size_t i; /* The purpose of all these local assignments is to */ const char *meta; /* allow optimizing compilers like gcc to load these */ char *buf = realbuf; /* values into registers. On a sparc this is a */ YYSTYPE *y = &yylval; /* win, in code size *and* execution time */ @@ -338,7 +338,7 @@ extern void inityy() { extern void print_prompt2() { lineno++; -#ifdef READLINE +#if READLINE prompt = prompt2; #else if (interactive) diff --git a/list.c b/list.c index f795485..fba6f6a 100644 --- a/list.c +++ b/list.c @@ -22,7 +22,7 @@ extern void listfree(List *p) { /* Copy list into malloc space (for storing a variable) */ -extern List *listcpy(List *s, void *(*alloc)(SIZE_T)) { +extern List *listcpy(List *s, void *(*alloc)(size_t)) { List *top, *r; for (top = r = NULL; s != NULL; s = s->n) { if (top == NULL) @@ -40,8 +40,8 @@ extern List *listcpy(List *s, void *(*alloc)(SIZE_T)) { /* Length of list */ -extern SIZE_T listlen(List *s) { - SIZE_T size; +extern size_t listlen(List *s) { + size_t size; for (size = 0; s != NULL; s = s->n) size += strlen(s->w) + 1; return size; diff --git a/main.c b/main.c index 20b3221..68624d7 100644 --- a/main.c +++ b/main.c @@ -4,7 +4,7 @@ bool dashdee, dashee, dashvee, dashex, dashell, dasheye, dashen, dashpee, dashess, interactive; -int rc_pid; +pid_t rc_pid; static bool dashoh; diff --git a/mksignal b/mksignal index 9a9b968..9902ed8 100755 --- a/mksignal +++ b/mksignal @@ -12,7 +12,8 @@ sed ' s/\/\*[ ]*// s/([@*+!]) // s/[ ]*([a-zA-Z,->& ]*)[ ]*// s/^[ ]*\#[ ]*define/\#define/ - s/[ ]*signal$//' $1 | + s/[ ]*signal$// + s/_SIG/SIG/g' $1 | awk ' BEGIN { # assign to nomesg["SIGNAME"] to suppress a long message diff --git a/nalloc.c b/nalloc.c index d600e4e..a809504 100644 --- a/nalloc.c +++ b/nalloc.c @@ -2,18 +2,18 @@ #include "rc.h" static struct Block { - SIZE_T used, size; + size_t used, size; char *mem; Block *n; } *fl, *ul; /* alignto() works only with power of 2 blocks and assumes 2's complement arithmetic */ #define alignto(m, n) ((m + n - 1) & ~(n - 1)) -#define BLOCKSIZE ((SIZE_T) 4096) +#define BLOCKSIZE ((size_t) 4096) /* Allocate a block from the free list or malloc one if none in the fl fit */ -static void getblock(SIZE_T n) { +static void getblock(size_t n) { Block *r, *p; for (r = fl, p = NULL; r != NULL; p = r, r = r->n) if (n <= r->size) @@ -41,10 +41,10 @@ static void getblock(SIZE_T n) { address of a global in a register) */ -extern void *nalloc(SIZE_T n) { - SIZE_T base; +extern void *nalloc(size_t n) { + size_t base; Block *ulp; - n = alignto(n, sizeof (ALIGN_T)); + n = alignto(n, sizeof(align_t)); ulp = ul; if (ulp != NULL && n + (base = ulp->used) < ulp->size) { ulp->used = base + n; @@ -65,7 +65,7 @@ extern void *nalloc(SIZE_T n) { #define MAXMEM 500000 extern void nfree() { - SIZE_T count; + size_t count; Block *r; if (ul == NULL) return; @@ -110,8 +110,8 @@ extern void restoreblock(Block *old) { /* generic memory allocation functions */ -extern void *ealloc(SIZE_T n) { - extern void *malloc(SIZE_T); +extern void *ealloc(size_t n) { + extern void *malloc(size_t); void *p = malloc(n); if (p == NULL) { uerror("malloc"); @@ -120,8 +120,8 @@ extern void *ealloc(SIZE_T n) { return p; } -extern void *erealloc(void *p, SIZE_T n) { - extern void *realloc(void *, SIZE_T); +extern void *erealloc(void *p, size_t n) { + extern void *realloc(void *, size_t); if (p == NULL) /* convenience feature */ return ealloc(n); if ((p = realloc(p, n)) == NULL) { diff --git a/open.c b/open.c index 7287e0e..2b6ee75 100644 --- a/open.c +++ b/open.c @@ -3,10 +3,6 @@ #include #include "rc.h" -/* prototype for open() follows. comment out if necessary */ - -/*extern int open(const char *, int,...);*/ - /* Opens a file with the necessary flags. Assumes the following declaration for redirtype: diff --git a/print.c b/print.c index a5cf25f..e0dba12 100644 --- a/print.c +++ b/print.c @@ -3,8 +3,8 @@ #include "rc.h" #include -#define PRINT_ALLOCSIZE ((SIZE_T)64) -#define SPRINT_BUFSIZ ((SIZE_T)1024) +#define PRINT_ALLOCSIZE ((size_t)64) +#define SPRINT_BUFSIZ ((size_t)1024) #define MAXCONV 256 @@ -22,6 +22,11 @@ static bool name(Format *format, int c) { \ Flag(uconv, FMT_unsigned) Flag(hconv, FMT_short) Flag(lconv, FMT_long) + +#if HAVE_QUAD_T +Flag(qconv, FMT_quad) +#endif + Flag(altconv, FMT_altform) Flag(leftconv, FMT_leftside) Flag(dotconv, FMT_f2set) @@ -43,7 +48,7 @@ static bool zeroconv(Format *format, int c) { return TRUE; } -static void pad(Format *format, SIZE_T len, int c) { +static void pad(Format *format, size_t len, int c) { while (len-- != 0) fmtputc(format, c); } @@ -53,7 +58,7 @@ static bool sconv(Format *format, int c) { if ((format->flags & FMT_f1set) == 0) fmtcat(format, s); else { - SIZE_T len = strlen(s), width = format->f1 - len; + size_t len = strlen(s), width = format->f1 - len; if (format->flags & FMT_leftside) { fmtappend(format, s, len); pad(format, width, ' '); @@ -80,7 +85,7 @@ static void intconv(Format *format, unsigned int radix, int upper, const char *a "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", }; char padchar; - SIZE_T len, pre, zeroes, padding, width; + size_t len, pre, zeroes, padding, width; long n, flags; unsigned long u; char number[64], prefix[20]; @@ -89,6 +94,13 @@ static void intconv(Format *format, unsigned int radix, int upper, const char *a return; flags = format->flags; + +#if HAVE_QUAD_T + if (flags & FMT_quad) + n = va_arg(format->args, quad_t); + else +#endif + if (flags & FMT_long) n = va_arg(format->args, long); else if (flags & FMT_short) @@ -109,13 +121,13 @@ static void intconv(Format *format, unsigned int radix, int upper, const char *a prefix[pre++] = *altform++; len = utoa(u, number, radix, table[upper]) - number; - if ((flags & FMT_f2set) && (SIZE_T) format->f2 > len) + if ((flags & FMT_f2set) && (size_t) format->f2 > len) zeroes = format->f2 - len; else zeroes = 0; width = pre + zeroes + len; - if ((flags & FMT_f1set) && (SIZE_T) format->f1 > width) { + if ((flags & FMT_f1set) && (size_t) format->f1 > width) { padding = format->f1 - width; } else padding = 0; @@ -196,6 +208,10 @@ static void inittab(void) { fmttab['-'] = leftconv; fmttab['.'] = dotconv; +#if HAVE_QUAD_T + fmttab['q'] = qconv; +#endif + fmttab['0'] = zeroconv; for (i = '1'; i <= '9'; i++) fmttab[i] = digitconv; @@ -218,9 +234,9 @@ extern bool (*fmtinstall(int c, bool (*f)(Format *, int)))(Format *, int) { * functions for inserting strings in the format buffer */ -extern void fmtappend(Format *format, const char *s, SIZE_T len) { +extern void fmtappend(Format *format, const char *s, size_t len) { while (format->buf + len > format->bufend) { - SIZE_T split = format->bufend - format->buf; + size_t split = format->bufend - format->buf; memcpy(format->buf, s, split); format->buf += split; s += split; @@ -282,8 +298,8 @@ extern int fmtprint(Format *format, const char *fmt,...) { return n + format->flushed; } -static void fprint_flush(Format *format, SIZE_T more) { - SIZE_T n = format->buf - format->bufbegin; +static void fprint_flush(Format *format, size_t more) { + size_t n = format->buf - format->bufbegin; char *buf = format->bufbegin; format->flushed += n; @@ -308,20 +324,20 @@ extern int fprint(int fd, const char *fmt,...) { printfmt(&format, fmt); va_end(format.args); - fprint_flush(&format, (SIZE_T) 0); + fprint_flush(&format, 0); return format.flushed; } -static void memprint_grow(Format *format, SIZE_T more) { +static void memprint_grow(Format *format, size_t more) { char *buf; - SIZE_T len = format->bufend - format->bufbegin + 1; + size_t len = format->bufend - format->bufbegin + 1; len = (len >= more) ? len * 2 : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1); if (format->u.n) buf = erealloc(format->bufbegin, len); else { - SIZE_T used = format->buf - format->bufbegin; + size_t used = format->buf - format->bufbegin; buf = nalloc(len); memcpy(buf, format->bufbegin, used); } @@ -330,7 +346,7 @@ static void memprint_grow(Format *format, SIZE_T more) { format->bufend = buf + len - 1; } -static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) { +static char *memprint(Format *format, const char *fmt, char *buf, size_t len) { format->buf = buf; format->bufbegin = buf; format->bufend = buf + len - 1; @@ -410,7 +426,7 @@ extern int eprint(const char *fmt,...) { return format.flushed; } -static void snprint_grow(Format *format, SIZE_T more) { +static void snprint_grow(Format *format, size_t more) { longjmp(format->u.p, 1); } diff --git a/proto.h b/proto.h index 2dc51a1..4e0fb5a 100644 --- a/proto.h +++ b/proto.h @@ -1,82 +1,40 @@ -/* proto.h - This file provides a definition for size_t and align_t that - should work for your system. If it does not, it is up to you to - make it the right thing. The problem is that I cannot rely upon - to do the right thing on machines which don't - yet have ansi header files. Note that on many RISC machines, - align_t must be at least 32 bits wide, and sparc doubles are - aligned on 64 bit boundaries, but of course rc does not use - doubles in its code, so the "typedef long ALIGN_T" is good - enough in the sparc's case. Also for performance reasons on a - VAX one would probably want align_t to be 32 bits wide. - - You can override these definitions with compile-line definitions - of the same macros. -*/ - -#ifndef ALIGN_T -typedef long ALIGN_T; -#endif -#ifndef SIZE_T -typedef unsigned int SIZE_T; -#endif -#ifndef MODE_T -typedef short int MODE_T; -#endif -#ifndef PID_T -typedef int PID_T; +#if HAVE_QUAD_T +typedef quad_t align_t; +#else +typedef long align_t; #endif + +/* If you need to change this, please let the maintainer know. */ #ifndef SIG_ATOMIC_T typedef int SIG_ATOMIC_T; #endif +#if STDC_HEADERS +#include +#else /* fake stdlib.h */ - extern void exit(int); -extern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *)); +extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); +#endif +#if STDC_HEADERS +#include +#else /* fake string.h */ - -extern int strncmp(const char *, const char *, SIZE_T); +extern int strncmp(const char *, const char *, size_t); extern int strcmp(const char *, const char *); -extern SIZE_T strlen(const char *); +extern size_t strlen(const char *); extern char *strchr(const char *, int); extern char *strrchr(const char *, int); extern char *strcpy(char *, const char *); -extern char *strncpy(char *, const char *, SIZE_T); +extern char *strncpy(char *, const char *, size_t); extern char *strcat(char *, const char *); -extern char *strncat(char *, const char *, SIZE_T); -extern void *memcpy(void *, const void *, SIZE_T); -extern void *memset(void *, int, SIZE_T); - -/* fake unistd.h */ - -extern PID_T fork(void); -extern PID_T getpid(void); -extern char *getenv(const char *); -extern int chdir(const char *); -extern int close(int); -extern int dup(int); -extern int dup2(int, int); -extern int execve(const char *, const char **, const char **); -extern int execl(const char *,...); -extern int getegid(void); -extern int geteuid(void); -extern int getgroups(int, int *); -/*extern int ioctl(int, long,...);*/ /* too much trouble leaving this uncommented */ -extern int isatty(int); -#ifndef SYSVR4 /* declares AND defines this in sys/stat.h!! */ -extern int mknod(const char *, int, int); +extern char *strncat(char *, const char *, size_t); +extern void *memcpy(void *, const void *, size_t); +extern void *memset(void *, int, size_t); #endif -extern int pipe(int *); -extern int read(int, void *, unsigned int); -extern int setpgrp(int, PID_T); -extern int unlink(const char *); -extern int wait(int *); -extern int write(int, const void *, unsigned int); /* fake errno.h for mips (which doesn't declare errno in errno.h!?!?) */ - #ifdef host_mips extern int errno; #endif diff --git a/rc.h b/rc.h index 04e37a2..e540117 100644 --- a/rc.h +++ b/rc.h @@ -1,4 +1,13 @@ #include "config.h" + +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_UNISTD_H +#include +#endif + #include "proto.h" /* datatypes */ @@ -9,6 +18,24 @@ #include +#if HAVE_SETPGRP + +#if SETPGRP_VOID +/* Smells like POSIX: should all be ok. */ +#else +/* BSD: fake it. */ +#define setpgid(pid, pgrp) setpgrp(pid, pgrp) +#define tcsetpgrp(fd, pgrp) ioctl((fd), TIOCSPGRP, &(pgrp)) +#endif + +#else /* HAVE_SETPGRP */ + +/* Nothing doing. */ +#define setpgid +#define tcsetpgrp + +#endif /*HAVE_SETPGRP */ + typedef void builtin_t(char **); typedef struct Block Block; typedef struct Dup Dup; @@ -126,20 +153,21 @@ struct Format { /* for the buffer maintainence routines */ char *buf, *bufbegin, *bufend; int flushed; - void (*grow)(Format *, SIZE_T); + void (*grow)(Format *, size_t); union { int n; void *p; } u; }; /* Format->flags values */ enum { - FMT_long = 1, /* %l */ - FMT_short = 2, /* %h */ - FMT_unsigned = 4, /* %u */ - FMT_zeropad = 8, /* %0 */ - FMT_leftside = 16, /* %- */ - FMT_altform = 32, /* %# */ - FMT_f1set = 64, /* % */ - FMT_f2set = 128 /* %. */ + FMT_quad = 1, /* %q */ + FMT_long = 2, /* %l */ + FMT_short = 4, /* %h */ + FMT_unsigned = 8, /* %u */ + FMT_zeropad = 16, /* %0 */ + FMT_leftside = 32, /* %- */ + FMT_altform = 64, /* %# */ + FMT_f1set = 128, /* % */ + FMT_f2set = 256 /* %. */ }; /* macros */ @@ -158,7 +186,7 @@ enum { #define nnew(x) ((x *) nalloc(sizeof(x))) #define ncpy(x) (strcpy((char *) nalloc(strlen(x) + 1), x)) #ifndef offsetof -#define offsetof(t, m) ((SIZE_T) (((char *) &((t *) 0)->m) - (char *)0)) +#define offsetof(t, m) ((size_t) (((char *) &((t *) 0)->m) - (char *)0)) #endif #define streq(x, y) (*(x) == *(y) && strcmp(x, y) == 0) #define conststrlen(x) (sizeof (x) - 1) @@ -170,7 +198,7 @@ extern char *prompt, *prompt2; extern Rq *redirq; extern bool dashdee, dashee, dashvee, dashex, dashell, dasheye, dashen, dashpee, interactive; -extern int rc_pid; +extern pid_t rc_pid; extern int lineno; /* builtins.c */ @@ -278,19 +306,19 @@ extern const char nw[], dnw[]; /* list.c */ extern void listfree(List *); -extern List *listcpy(List *, void *(*)(SIZE_T)); -extern SIZE_T listlen(List *); +extern List *listcpy(List *, void *(*)(size_t)); +extern size_t listlen(List *); extern int listnel(List *); /* match.c */ extern bool match(char *, char *, char *); /* alloc.c */ -extern void *ealloc(SIZE_T); -extern void *erealloc(void *, SIZE_T); +extern void *ealloc(size_t); +extern void *erealloc(void *, size_t); extern void efree(void *); extern Block *newblock(void); -extern void *nalloc(SIZE_T); +extern void *nalloc(size_t); extern void nfree(void); extern void restoreblock(Block *); @@ -306,7 +334,7 @@ extern Conv fmtinstall(int, Conv); extern bool (*fmtinstall(int, bool (*)(Format *, int)))(Format *, int); extern int printfmt(Format *, const char *); extern int fmtprint(Format *, const char *,...); -extern void fmtappend(Format *, const char *, SIZE_T); +extern void fmtappend(Format *, const char *, size_t); extern void fmtcat(Format *, const char *); extern int fprint(int fd, const char *fmt,...); extern char *mprint(const char *fmt,...); @@ -318,7 +346,7 @@ extern char *nprint(const char *fmt,...); */ #define fmtputc(f, c) {\ if ((f)->buf >= (f)->bufend)\ - (*(f)->grow)((f), (SIZE_T)1);\ + (*(f)->grow)((f), (size_t)1);\ *(f)->buf++ = (c);\ } @@ -342,32 +370,32 @@ extern volatile SIG_ATOMIC_T slow, interrupt_happened; extern int istrue(void); extern int getstatus(void); extern void set(bool); -extern void setstatus(int, int); +extern void setstatus(pid_t, int); extern List *sgetstatus(void); extern void setpipestatus(int [], int); -extern void statprint(int, int); +extern void statprint(pid_t, int); extern void ssetstatus(char **); extern char *strstatus(int s); /* tree.c */ extern Node *mk(int /*nodetype*/,...); -extern Node *treecpy(Node *, void *(*)(SIZE_T)); +extern Node *treecpy(Node *, void *(*)(size_t)); extern void treefree(Node *); /* utils.c */ extern bool isabsolute(char *); extern int n2u(char *, unsigned int); -extern int rc_read(int, char *, SIZE_T); +extern int rc_read(int, char *, size_t); extern int mvfd(int, int); extern int starstrcmp(const void *, const void *); extern void pr_error(char *); extern void panic(char *); extern void uerror(char *); -extern void writeall(int, char *, SIZE_T); +extern void writeall(int, char *, size_t); /* wait.c */ -extern int rc_fork(void); -extern int rc_wait4(int, int *, bool); +extern pid_t rc_fork(void); +extern pid_t rc_wait4(pid_t, int *, bool); extern List *sgetapids(void); extern void waitforall(void); extern bool forked; diff --git a/rlimit.h b/rlimit.h new file mode 100644 index 0000000..f6e179b --- /dev/null +++ b/rlimit.h @@ -0,0 +1,42 @@ +/* What a mess. This file attempts to straighten everything out. */ + +#if HAVE_SETRLIMIT + +#if HAVE_SYS_RESOURCE_H +# include +# if RLIMIT_NEEDS_KERNEL +# define _KERNEL +# endif +# include +# if RLIMIT_NEEDS_KERNEL +# undef _KERNEL +# endif +#else +# include +#endif + +#if HAVE_LIMITS_H +# include +#endif + +#ifndef HAVE_RLIM_T +# if RLIM_T_IS_QUAD_T +typedef quad_t rlim_t; +# else +typedef long rlim_t; +# endif +#endif + +#if HAVE_QUAD_T +# define RLIM_CONV quad_t +# define RLIM_FMT "%s \t%qd%s\n" +#else +# define RLIM_CONV long +# define RLIM_FMT "%s \t%ld%s\n" +#endif + +#if defined(RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) +# define RLIMIT_NOFILE RLIMIT_OFILE +#endif + +#endif /* HAVE_SETRLIMIT */ diff --git a/signal.c b/signal.c index 6bca945..1c3f812 100644 --- a/signal.c +++ b/signal.c @@ -19,7 +19,7 @@ extern void catcher(int s) { } signal(s, catcher); interrupt_happened = TRUE; -#ifndef SVSIGS +#ifndef HAVE_RESTARTABLE_SYSCALLS if (slow) longjmp(slowbuf.j, 1); #endif @@ -70,4 +70,11 @@ extern void initsignal() { signal(i, h); sighandlers[i] = h; } + +#ifdef SIGCLD + /* Ensure that SIGCLD is not SIG_IGN. Solaris's rshd does this. :-( */ + h = signal(SIGCLD, SIG_DFL); + if (h != SIG_IGN) + signal(SIGCLD, h); +#endif } diff --git a/status.c b/status.c index 91252b0..428e414 100644 --- a/status.c +++ b/status.c @@ -52,7 +52,7 @@ extern void setpipestatus(int stats[], int num) { /* set a simple status, as opposed to a pipeline */ -extern void setstatus(int pid, int i) { +extern void setstatus(pid_t pid, int i) { pipelength = 1; statuses[0] = i; statprint(pid, i); @@ -60,11 +60,11 @@ extern void setstatus(int pid, int i) { /* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */ -extern void statprint(int pid, int i) { +extern void statprint(pid_t pid, int i) { if (i & 0xff) { char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f].msg : ""); if (pid != -1) - fprint(2, "%d: ", pid); + fprint(2, "%ld: ", (long)pid); if (i & 0x80) { if (*msg == '\0') fprint(2, "core dumped\n"); @@ -129,7 +129,7 @@ extern void ssetstatus(char **av) { break; } else { - SIZE_T len = strlen(signals[k].name); + size_t len = strlen(signals[k].name); if (strncmp(signals[k].name, av[i], len) == 0 && streq(av[i] + len, "+core")) { statuses[l - i] = k + 0x80; found = TRUE; diff --git a/tree.c b/tree.c index 6ce1ee8..aaea645 100644 --- a/tree.c +++ b/tree.c @@ -65,7 +65,7 @@ extern Node *mk(int /*nodetype*/ t,...) { /* copy a tree to malloc space. Used when storing the definition of a function */ -extern Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) { +extern Node *treecpy(Node *s, void *(*alloc)(size_t)) { Node *n; if (s == NULL) return NULL; @@ -83,7 +83,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) { n = (*alloc)(offsetof(Node, u[2])); n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s); if (s->u[1].s != NULL) { - SIZE_T i = strlen(s->u[0].s); + size_t i = strlen(s->u[0].s); n->u[1].s = (*alloc)(i); memcpy(n->u[1].s, s->u[1].s, i); } else diff --git a/utils.c b/utils.c index 67b146b..71ef61b 100644 --- a/utils.c +++ b/utils.c @@ -67,7 +67,7 @@ extern bool isabsolute(char *path) { /* signal-safe read and write (for BSD slow devices). writeall also allows partial writes */ -extern void writeall(int fd, char *buf, SIZE_T remain) { +extern void writeall(int fd, char *buf, size_t remain) { int i; for (i = 0; remain > 0; buf += i, remain -= i) { interrupt_happened = FALSE; @@ -85,7 +85,7 @@ extern void writeall(int fd, char *buf, SIZE_T remain) { sigchk(); } -extern int rc_read(int fd, char *buf, SIZE_T n) { +extern int rc_read(int fd, char *buf, size_t n) { long /*ssize_t*/ r; interrupt_happened = FALSE; if (!setjmp(slowbuf.j)) { diff --git a/var.c b/var.c index 6a3e7c8..b0bc60b 100644 --- a/var.c +++ b/var.c @@ -18,7 +18,7 @@ extern void varassign(char *name, List *def, bool stack) { new = get_var_place(name, stack); new->def = newdef; new->extdef = NULL; -#ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */ +#if READLINE /* need to reset readline() every time TERM or TERMCAP changes */ if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) { extern void rl_reset_terminal(char *); rl_reset_terminal(NULL); diff --git a/version.c b/version.c index b3dcba5..68b5dc1 100644 --- a/version.c +++ b/version.c @@ -1 +1 @@ -const char id[] = "@(#)rc version 1.5betadev-1, 1/9/94."; +const char id[] = "@(#)rc version 1.5b2, 1997-07-01."; diff --git a/wait.c b/wait.c index 3756985..171d97e 100644 --- a/wait.c +++ b/wait.c @@ -1,23 +1,27 @@ +#include "rc.h" + #include #include -#include "rc.h" +#include + #include "jbwrap.h" bool forked = FALSE; -static int rc_wait(int *); +static pid_t rc_wait(int *); typedef struct Pid Pid; static struct Pid { - int pid, stat; + pid_t pid; + int stat; bool alive; Pid *n; } *plist = NULL; -extern int rc_fork() { +extern pid_t rc_fork() { Pid *new; - int pid = fork(); + pid_t pid = fork(); switch (pid) { case -1: uerror("fork"); @@ -37,7 +41,7 @@ extern int rc_fork() { } } -extern int rc_wait4(int pid, int *stat, bool nointr) { +extern pid_t rc_wait4(pid_t pid, int *stat, bool nointr) { Pid *r, *prev; int ret; /* first look for a child which may already have exited */ @@ -109,7 +113,7 @@ extern void waitforall() { may want to resume the wait() without delivering any signals. */ -static int rc_wait(int *stat) { +static pid_t rc_wait(int *stat) { int r; interrupt_happened = FALSE; if (!setjmp(slowbuf.j)) { diff --git a/walk.c b/walk.c index e57de0d..ed9f965 100644 --- a/walk.c +++ b/walk.c @@ -43,12 +43,12 @@ top: sigchk(); case nNowait: { int pid; if ((pid = rc_fork()) == 0) { -#if !defined(NOJOB) && defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP) +#if defined(RC_JOB) && defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP) setsigdefaults(FALSE); rc_signal(SIGTTOU, SIG_IGN); /* Berkeleyized version: put it in a new pgroup. */ rc_signal(SIGTTIN, SIG_IGN); rc_signal(SIGTSTP, SIG_IGN); - setpgrp(0, getpid()); + setpgid(0, getpid()); #else setsigdefaults(TRUE); /* ignore SIGINT, SIGQUIT, SIGTERM */ #endif diff --git a/which.c b/which.c index a9e2f65..372cc92 100644 --- a/which.c +++ b/which.c @@ -8,11 +8,11 @@ and to strip out unneeded functionality. */ +#include "rc.h" +#include #include #include -#include -#include -#include "rc.h" +#include #define X_USR 0100 #define X_GRP 0010 @@ -22,16 +22,18 @@ extern int stat(const char *, struct stat *); static bool initialized = FALSE; -static int uid, gid; +static uid_t uid; +static gid_t gid; -#ifdef NGROUPS -static int ngroups, gidset[NGROUPS]; +#if HAVE_GETGROUPS +static int ngroups; +static GETGROUPS_T *gidset; /* determine whether gid lies in gidset */ -static int ingidset(int g) { - int i; - for (i = 0; i < ngroups; i++) +static int ingidset(gid_t g) { + gid_t i; + for (i = 0; i < ngroups; ++i) if (g == gidset[i]) return 1; return 0; @@ -55,7 +57,7 @@ static bool rc_access(char *path, bool verbose) { mask = X_ALL; else if (uid == st.st_uid) mask = X_USR; -#ifdef NGROUPS +#if HAVE_GETGROUPS else if (gid == st.st_gid || ingidset(st.st_gid)) #else else if (gid == st.st_gid) @@ -75,7 +77,7 @@ static bool rc_access(char *path, bool verbose) { extern char *which(char *name, bool verbose) { static char *test = NULL; - static SIZE_T testlen = 0; + static size_t testlen = 0; List *path; int len; if (name == NULL) /* no filename? can happen with "> foo" as a command */ @@ -84,15 +86,20 @@ extern char *which(char *name, bool verbose) { initialized = TRUE; uid = geteuid(); gid = getegid(); -#ifdef NGROUPS - ngroups = getgroups(NGROUPS, gidset); +#if HAVE_GETGROUPS + ngroups = getgroups(0, (gid_t *)0); + gidset = malloc(ngroups * sizeof(gid_t)); + if (!gidset) + uerror("malloc"); + else + getgroups(ngroups, gidset); #endif } if (isabsolute(name)) /* absolute pathname? */ return rc_access(name, verbose) ? name : NULL; len = strlen(name); for (path = varlookup("path"); path != NULL; path = path->n) { - SIZE_T need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */ + size_t need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */ if (testlen < need) { efree(test); test = ealloc(testlen = need); diff --git a/y.tab.c b/y.tab.c new file mode 100644 index 0000000..4538689 --- /dev/null +++ b/y.tab.c @@ -0,0 +1,1070 @@ +#ifndef lint +static char const yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif +#ifdef __cplusplus +extern "C" { char *getenv(const char *); } +#else +extern char *getenv(); +extern int yylex(); +extern int yyparse(); +#endif +#define YYPREFIX "yy" +#line 8 "parse.y" +#include "rc.h" +#ifndef lint +#define lint /* hush up gcc -Wall, leave out the dumb sccsid's. */ +#endif +static Node *star, *nolist; +Node *parsetree; /* not using yylval because bison declares it as an auto */ +#line 28 "parse.y" +typedef union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} YYSTYPE; +#line 43 "y.tab.c" +#define ANDAND 257 +#define BACKBACK 258 +#define BANG 259 +#define CASE 260 +#define COUNT 261 +#define DUP 262 +#define ELSE 263 +#define END 264 +#define FLAT 265 +#define FN 266 +#define FOR 267 +#define IF 268 +#define IN 269 +#define OROR 270 +#define PIPE 271 +#define REDIR 272 +#define SREDIR 273 +#define SUB 274 +#define SUBSHELL 275 +#define SWITCH 276 +#define TWIDDLE 277 +#define WHILE 278 +#define WORD 279 +#define HUH 280 +#define YYERRCODE 256 +const short yylhs[] = { -1, + 0, 0, 22, 22, 8, 8, 13, 13, 3, 3, + 9, 9, 4, 15, 2, 11, 11, 16, 16, 16, + 5, 5, 6, 6, 6, 19, 19, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 24, 24, 18, 18, 18, + 12, 12, 17, 17, 20, 20, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 21, 21, + 14, 14, 14, 23, 23, +}; +const short yylen[] = { 2, + 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, + 1, 2, 3, 3, 3, 0, 2, 1, 2, 2, + 3, 3, 1, 2, 2, 1, 4, 0, 1, 2, + 4, 8, 6, 4, 8, 4, 4, 4, 4, 2, + 2, 3, 3, 3, 2, 0, 1, 1, 2, 2, + 1, 3, 1, 1, 1, 3, 2, 5, 2, 2, + 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, + 0, 2, 2, 0, 2, +}; +const short yydefred[] = { 0, + 0, 0, 0, 0, 18, 0, 79, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 0, 0, 81, 0, + 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, + 3, 4, 2, 77, 75, 74, 73, 68, 71, 69, + 0, 78, 72, 76, 70, 54, 53, 55, 0, 47, + 0, 59, 60, 0, 0, 0, 84, 66, 0, 0, + 0, 0, 0, 84, 0, 0, 0, 11, 0, 0, + 62, 61, 0, 0, 30, 0, 84, 84, 84, 5, + 6, 8, 0, 0, 1, 0, 50, 0, 0, 63, + 64, 0, 44, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 13, 12, 10, 65, 82, 0, 17, 0, + 0, 0, 0, 52, 56, 79, 84, 14, 85, 0, + 0, 31, 84, 0, 0, 0, 0, 0, 39, 0, + 0, 84, 0, 58, 84, 0, 0, 0, 0, 0, + 79, 0, 0, 0, 0, 0, 0, 24, 35, 25, + 22, 21, +}; +const short yydgoto[] = { 21, + 46, 22, 66, 23, 142, 143, 67, 68, 69, 47, + 75, 27, 28, 70, 57, 29, 48, 30, 122, 94, + 54, 33, 97, 51, +}; +const short yysindex[] = { 874, + 24, 1001, -82, 1001, 0, 1001, 0, -27, -26, 900, + 1001, -82, -20, -82, -26, 0, 1001, 1134, 0, 900, + 0, 1134, -203, -30, 1134, 0, -55, 24, 1134, 826, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -66, 0, 0, 0, 0, 0, 0, 0, 849, 0, + 1134, 0, 0, 900, 1001, 1134, 0, 0, -52, -52, + 1134, 1001, 1001, 0, -212, -58, 154, 0, 1134, 426, + 0, 0, -196, 1001, 0, -203, 0, 0, 0, 0, + 0, 0, 1001, 1001, 0, -196, 0, -52, 1001, 0, + 0, -196, 0, -52, -38, 36, 502, -196, -36, -52, + 502, 0, 0, 0, 0, 0, 0, -52, 0, 502, + 502, 502, -52, 0, 0, 0, 0, 0, 0, -97, + -234, 0, 0, 1001, -234, 922, -196, -196, 0, 944, + 502, 0, -9, 0, 0, -234, 502, 967, 502, -234, + 0, 967, -45, 154, 967, -234, 448, 0, 0, 0, + 0, 0, +}; +const short yyrindex[] = { 134, + 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, + 0, 356, 0, 1024, 0, 0, 0, 571, 0, 0, + 0, 487, 529, 54, 134, 0, 62, 0, 487, 548, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 487, 0, 0, 712, 0, 142, 0, 0, 14, 38, + 487, 0, 0, 0, -10, 0, -32, 0, 744, 0, + 0, 0, 749, 0, 0, 529, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 763, 0, 86, 0, 0, + 0, 779, 0, 110, 0, 0, -34, 788, 0, 380, + -34, 0, 0, 0, 0, 0, 0, 470, 0, -34, + -34, -34, 404, 0, 0, 0, 0, 0, 0, 529, + 6, 0, 0, 724, 30, 0, 805, 813, 0, 0, + -34, 0, 0, 0, 0, 119, -34, 571, -34, 187, + 0, 571, 0, -44, 571, 396, 0, 0, 0, 0, + 0, 0, +}; +const short yygindex[] = { 0, + 0, 0, -23, 12, 0, -104, 1319, 2, -127, 1307, + 7, 0, 57, 0, 70, -13, 84, 0, 0, 420, + -81, 59, 369, 31, +}; +#define YYTABLESIZE 1464 +const short yytable[] = { 57, + 119, 25, 117, 28, 123, 83, 28, 81, 9, 76, + 145, 50, 55, 56, 145, 26, 87, 145, 124, 62, + 126, 58, 77, 19, 28, 57, 25, 57, 80, 57, + 57, 71, 96, 32, 130, 78, 79, 148, 84, 34, + 150, 89, 61, 26, 63, 105, 26, 20, 57, 19, + 57, 19, 58, 19, 19, 89, 18, 89, 5, 147, + 90, 102, 76, 7, 26, 93, 103, 34, 74, 11, + 34, 48, 19, 20, 79, 20, 118, 20, 20, 149, + 23, 82, 109, 57, 64, 57, 85, 52, 34, 53, + 28, 0, 9, 0, 0, 49, 20, 48, 0, 48, + 65, 48, 48, 72, 0, 0, 76, 0, 120, 19, + 0, 0, 57, 138, 57, 0, 0, 0, 0, 80, + 48, 49, 0, 49, 0, 49, 49, 0, 33, 0, + 26, 0, 91, 20, 0, 0, 19, 0, 19, 0, + 0, 0, 0, 28, 49, 80, 0, 80, 0, 80, + 80, 28, 0, 0, 34, 0, 33, 48, 0, 33, + 20, 0, 20, 104, 5, 132, 0, 114, 80, 0, + 0, 28, 115, 0, 74, 11, 0, 33, 0, 28, + 0, 49, 28, 0, 0, 0, 48, 0, 0, 0, + 0, 81, 28, 0, 0, 0, 27, 0, 0, 0, + 28, 0, 0, 0, 0, 80, 0, 0, 0, 0, + 49, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 28, 0, 27, 0, 77, 27, 0, 28, + 116, 0, 80, 0, 80, 28, 28, 0, 0, 78, + 79, 0, 0, 33, 0, 27, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 0, 57, 57, 57, 57, 57, 26, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 31, 19, 19, + 19, 19, 19, 34, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 27, 20, 20, 20, 20, 20, 7, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, + 48, 0, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, + 49, 49, 49, 49, 49, 46, 80, 80, 80, 80, + 80, 0, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 33, 0, 80, 80, 80, 80, 80, 79, + 28, 46, 0, 46, 0, 46, 46, 28, 28, 0, + 0, 0, 0, 28, 28, 32, 0, 0, 0, 0, + 77, 28, 28, 15, 46, 79, 0, 79, 0, 79, + 79, 49, 0, 78, 79, 0, 0, 0, 0, 59, + 60, 0, 101, 32, 0, 107, 32, 0, 79, 15, + 0, 15, 0, 15, 15, 110, 111, 112, 0, 88, + 27, 46, 0, 0, 32, 0, 0, 151, 0, 0, + 0, 17, 15, 0, 0, 19, 106, 0, 0, 0, + 0, 0, 0, 0, 95, 79, 0, 0, 46, 83, + 46, 99, 100, 17, 0, 131, 0, 19, 0, 108, + 0, 133, 0, 59, 0, 0, 28, 0, 0, 15, + 137, 0, 113, 139, 79, 83, 152, 0, 0, 83, + 83, 119, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 20, 0, 0, 28, 0, 15, 28, 15, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 16, 0, + 0, 19, 0, 20, 0, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 83, 16, 0, 0, 16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 28, 0, 0, 0, 0, 29, 0, 16, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 0, 28, 0, + 0, 28, 46, 46, 46, 0, 46, 46, 0, 46, + 46, 46, 46, 46, 18, 46, 46, 46, 46, 28, + 46, 46, 46, 46, 46, 0, 79, 79, 79, 79, + 79, 0, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 0, 16, 79, 79, 79, 79, 79, 32, + 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, + 15, 15, 29, 15, 15, 15, 15, 0, 15, 15, + 15, 15, 15, 2, 34, 35, 4, 0, 36, 0, + 6, 37, 38, 39, 40, 28, 0, 41, 0, 0, + 42, 43, 44, 45, 16, 2, 34, 35, 4, 0, + 36, 0, 6, 37, 38, 39, 40, 0, 0, 41, + 0, 45, 42, 43, 44, 45, 16, 83, 83, 83, + 83, 0, 83, 36, 83, 83, 83, 83, 83, 0, + 0, 83, 0, 28, 83, 83, 83, 83, 83, 45, + 28, 0, 45, 28, 0, 0, 28, 28, 41, 2, + 3, 36, 4, 5, 36, 0, 6, 7, 8, 9, + 45, 0, 40, 10, 11, 0, 12, 13, 14, 15, + 16, 28, 36, 0, 28, 16, 41, 0, 42, 41, + 0, 0, 16, 0, 0, 0, 0, 43, 16, 16, + 40, 0, 28, 40, 29, 0, 0, 41, 0, 0, + 0, 29, 0, 0, 37, 0, 42, 29, 29, 42, + 0, 40, 38, 0, 0, 43, 0, 28, 43, 0, + 0, 0, 0, 0, 0, 0, 45, 42, 0, 0, + 28, 28, 37, 0, 0, 37, 43, 0, 36, 0, + 38, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 37, 0, 19, 0, 0, 28, 0, + 0, 38, 0, 41, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 40, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42, 0, 0, 0, 0, 0, 17, + 0, 0, 43, 19, 0, 0, 0, 0, 0, 0, + 0, 20, 0, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 0, 0, 17, 0, 38, 0, 19, + 0, 0, 89, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, + 0, 19, 134, 0, 0, 0, 0, 0, 45, 20, + 0, 18, 0, 0, 0, 45, 0, 0, 0, 17, + 36, 45, 45, 19, 135, 0, 0, 36, 0, 0, + 0, 0, 0, 36, 36, 20, 18, 0, 0, 0, + 28, 0, 17, 0, 0, 41, 19, 0, 0, 0, + 0, 0, 41, 28, 28, 0, 0, 20, 41, 40, + 0, 0, 18, 0, 0, 0, 40, 0, 0, 0, + 0, 0, 40, 0, 0, 42, 17, 0, 0, 20, + 19, 0, 42, 0, 43, 0, 0, 0, 42, 0, + 0, 43, 0, 0, 0, 0, 0, 43, 0, 46, + 0, 37, 20, 46, 0, 0, 0, 0, 37, 38, + 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, + 0, 0, 38, 2, 34, 35, 4, 5, 36, 18, + 6, 37, 38, 39, 40, 0, 20, 10, 11, 0, + 42, 43, 44, 45, 16, 0, 2, 34, 35, 4, + 0, 36, 0, 6, 37, 38, 39, 40, 0, 46, + 41, 0, 0, 42, 43, 44, 45, 16, 0, 1, + 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, + 8, 9, 0, 0, 0, 10, 11, 0, 12, 13, + 14, 15, 16, 0, 0, 0, 0, 2, 34, 35, + 4, 0, 36, 0, 6, 37, 38, 39, 40, 17, + 0, 41, 0, 19, 42, 43, 44, 45, 16, 2, + 34, 35, 4, 0, 36, 0, 6, 37, 38, 39, + 40, 0, 0, 41, 0, 0, 42, 43, 44, 45, + 16, 2, 34, 35, 4, 0, 36, 0, 6, 37, + 38, 39, 40, 0, 0, 41, 0, 0, 42, 43, + 44, 45, 16, 0, 2, 3, 141, 4, 5, 20, + 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, + 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 0, 2, 34, + 35, 4, 0, 36, 0, 6, 37, 38, 39, 40, + 0, 0, 41, 0, 0, 42, 43, 44, 45, 16, + 0, 46, 46, 46, 46, 0, 46, 0, 46, 46, + 46, 46, 46, 0, 0, 46, 0, 0, 46, 46, + 46, 46, 46, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, + 0, 0, 0, 0, 26, 0, 0, 0, 26, 0, + 0, 26, 0, 0, 0, 26, 0, 0, 0, 0, + 73, 0, 0, 24, 0, 0, 0, 86, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, + 0, 0, 26, 0, 0, 0, 0, 26, 0, 92, + 0, 0, 0, 0, 0, 26, 0, 0, 0, 98, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, + 8, 9, 0, 26, 0, 10, 11, 26, 12, 13, + 14, 15, 16, 0, 0, 121, 26, 26, 26, 125, + 0, 0, 0, 0, 0, 0, 0, 0, 127, 128, + 129, 0, 0, 0, 0, 0, 0, 26, 0, 0, + 0, 0, 0, 26, 26, 26, 0, 0, 26, 136, + 0, 26, 0, 0, 0, 140, 144, 146, 0, 0, + 144, 0, 0, 144, +}; +const short yycheck[] = { 10, + 10, 0, 41, 38, 41, 61, 41, 38, 41, 23, + 138, 94, 40, 40, 142, 10, 30, 145, 100, 40, + 102, 10, 257, 10, 59, 36, 25, 38, 59, 40, + 41, 20, 56, 10, 116, 270, 271, 142, 94, 10, + 145, 94, 12, 38, 14, 69, 41, 10, 59, 36, + 61, 38, 41, 40, 41, 94, 123, 94, 262, 141, + 49, 274, 76, 10, 59, 54, 125, 38, 272, 273, + 41, 10, 59, 36, 271, 38, 41, 40, 41, 125, + 125, 25, 76, 94, 15, 96, 28, 4, 59, 6, + 125, -1, 125, -1, -1, 10, 59, 36, -1, 38, + 17, 40, 41, 20, -1, -1, 120, -1, 97, 96, + -1, -1, 123, 123, 125, -1, -1, -1, -1, 10, + 59, 36, -1, 38, -1, 40, 41, -1, 10, -1, + 125, -1, 49, 96, -1, -1, 123, -1, 125, -1, + -1, -1, -1, 10, 59, 36, -1, 38, -1, 40, + 41, 10, -1, -1, 125, -1, 38, 96, -1, 41, + 123, -1, 125, 10, 262, 263, -1, 84, 59, -1, + -1, 38, 89, -1, 272, 273, -1, 59, -1, 38, + -1, 96, 41, -1, -1, -1, 125, -1, -1, -1, + -1, 38, 59, -1, -1, -1, 10, -1, -1, -1, + 59, -1, -1, -1, -1, 96, -1, -1, -1, -1, + 125, -1, 59, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 257, -1, 38, -1, 257, 41, -1, 264, + 269, -1, 123, -1, 125, 270, 271, -1, -1, 270, + 271, -1, -1, 125, -1, 59, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, -1, 275, 276, 277, 278, 279, 264, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 264, 275, 276, + 277, 278, 279, 264, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 125, 275, 276, 277, 278, 279, 264, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, -1, 275, 276, 277, 278, + 279, -1, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, -1, + 275, 276, 277, 278, 279, 10, 257, 258, 259, 260, + 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 264, -1, 275, 276, 277, 278, 279, 10, + 257, 36, -1, 38, -1, 40, 41, 264, 257, -1, + -1, -1, -1, 270, 271, 10, -1, -1, -1, -1, + 257, 270, 271, 10, 59, 36, -1, 38, -1, 40, + 41, 2, -1, 270, 271, -1, -1, -1, -1, 10, + 11, -1, 64, 38, -1, 10, 41, -1, 59, 36, + -1, 38, -1, 40, 41, 77, 78, 79, -1, 30, + 264, 96, -1, -1, 59, -1, -1, 10, -1, -1, + -1, 36, 59, -1, -1, 40, 41, -1, -1, -1, + -1, -1, -1, -1, 55, 96, -1, -1, 123, 10, + 125, 62, 63, 36, -1, 117, -1, 40, -1, 70, + -1, 123, -1, 74, -1, -1, 10, -1, -1, 96, + 132, -1, 83, 135, 125, 36, 59, -1, -1, 40, + 41, 10, -1, -1, -1, -1, -1, -1, -1, -1, + 125, 96, -1, -1, 38, -1, 123, 41, 125, -1, + -1, -1, -1, -1, -1, -1, -1, 36, 10, -1, + -1, 40, -1, 96, -1, 59, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, + -1, -1, -1, -1, -1, 96, 38, -1, -1, 41, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, -1, -1, -1, -1, 38, -1, 59, 41, -1, + -1, -1, -1, -1, -1, -1, -1, 96, -1, -1, + -1, -1, -1, -1, -1, -1, 59, -1, 38, -1, + -1, 125, 257, 258, 259, -1, 261, 262, -1, 264, + 265, 266, 267, 268, 123, 270, 271, 272, 273, 59, + 275, 276, 277, 278, 279, -1, 257, 258, 259, 260, + 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, -1, 125, 275, 276, 277, 278, 279, 264, + 257, 258, 259, -1, 261, 262, -1, 264, 265, 266, + 267, 268, 125, 270, 271, 272, 273, -1, 275, 276, + 277, 278, 279, 258, 259, 260, 261, -1, 263, -1, + 265, 266, 267, 268, 269, 125, -1, 272, -1, -1, + 275, 276, 277, 278, 279, 258, 259, 260, 261, -1, + 263, -1, 265, 266, 267, 268, 269, -1, -1, 272, + -1, 10, 275, 276, 277, 278, 279, 258, 259, 260, + 261, -1, 263, 10, 265, 266, 267, 268, 269, -1, + -1, 272, -1, 257, 275, 276, 277, 278, 279, 38, + 264, -1, 41, 10, -1, -1, 270, 271, 10, 258, + 259, 38, 261, 262, 41, -1, 265, 266, 267, 268, + 59, -1, 10, 272, 273, -1, 275, 276, 277, 278, + 279, 38, 59, -1, 41, 257, 38, -1, 10, 41, + -1, -1, 264, -1, -1, -1, -1, 10, 270, 271, + 38, -1, 59, 41, 257, -1, -1, 59, -1, -1, + -1, 264, -1, -1, 10, -1, 38, 270, 271, 41, + -1, 59, 10, -1, -1, 38, -1, 257, 41, -1, + -1, -1, -1, -1, -1, -1, 125, 59, -1, -1, + 270, 271, 38, -1, -1, 41, 59, -1, 125, -1, + 38, -1, -1, 41, -1, -1, -1, -1, -1, -1, + -1, 36, -1, 59, -1, 40, -1, -1, 125, -1, + -1, 59, -1, 125, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, 125, 40, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 125, -1, -1, -1, -1, -1, 36, + -1, -1, 125, 40, -1, -1, -1, -1, -1, -1, + -1, 96, -1, -1, -1, -1, -1, -1, -1, 125, + -1, -1, -1, -1, -1, 36, -1, 125, -1, 40, + -1, -1, 94, -1, 96, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, + -1, 40, 41, -1, -1, -1, -1, -1, 257, 96, + -1, 123, -1, -1, -1, 264, -1, -1, -1, 36, + 257, 270, 271, 40, 41, -1, -1, 264, -1, -1, + -1, -1, -1, 270, 271, 96, 123, -1, -1, -1, + 257, -1, 36, -1, -1, 257, 40, -1, -1, -1, + -1, -1, 264, 270, 271, -1, -1, 96, 270, 257, + -1, -1, 123, -1, -1, -1, 264, -1, -1, -1, + -1, -1, 270, -1, -1, 257, 36, -1, -1, 96, + 40, -1, 264, -1, 257, -1, -1, -1, 270, -1, + -1, 264, -1, -1, -1, -1, -1, 270, -1, 36, + -1, 257, 96, 40, -1, -1, -1, -1, 264, 257, + -1, -1, -1, -1, 270, -1, 264, -1, -1, -1, + -1, -1, 270, 258, 259, 260, 261, 262, 263, 123, + 265, 266, 267, 268, 269, -1, 96, 272, 273, -1, + 275, 276, 277, 278, 279, -1, 258, 259, 260, 261, + -1, 263, -1, 265, 266, 267, 268, 269, -1, 96, + 272, -1, -1, 275, 276, 277, 278, 279, -1, 256, + -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, + 267, 268, -1, -1, -1, 272, 273, -1, 275, 276, + 277, 278, 279, -1, -1, -1, -1, 258, 259, 260, + 261, -1, 263, -1, 265, 266, 267, 268, 269, 36, + -1, 272, -1, 40, 275, 276, 277, 278, 279, 258, + 259, 260, 261, -1, 263, -1, 265, 266, 267, 268, + 269, -1, -1, 272, -1, -1, 275, 276, 277, 278, + 279, 258, 259, 260, 261, -1, 263, -1, 265, 266, + 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, + 277, 278, 279, -1, 258, 259, 260, 261, 262, 96, + -1, 265, 266, 267, 268, -1, -1, -1, 272, 273, + -1, 275, 276, 277, 278, 279, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 123, -1, 258, 259, + 260, 261, -1, 263, -1, 265, 266, 267, 268, 269, + -1, -1, 272, -1, -1, 275, 276, 277, 278, 279, + -1, 258, 259, 260, 261, -1, 263, -1, 265, 266, + 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, + 277, 278, 279, -1, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, + -1, -1, -1, -1, 18, -1, -1, -1, 22, -1, + -1, 25, -1, -1, -1, 29, -1, -1, -1, -1, + 22, -1, -1, 25, -1, -1, -1, 29, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, + -1, -1, 56, -1, -1, -1, -1, 61, -1, 51, + -1, -1, -1, -1, -1, 69, -1, -1, -1, 61, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, + 267, 268, -1, 97, -1, 272, 273, 101, 275, 276, + 277, 278, 279, -1, -1, 97, 110, 111, 112, 101, + -1, -1, -1, -1, -1, -1, -1, -1, 110, 111, + 112, -1, -1, -1, -1, -1, -1, 131, -1, -1, + -1, -1, -1, 137, 138, 139, -1, -1, 142, 131, + -1, 145, -1, -1, -1, 137, 138, 139, -1, -1, + 142, -1, -1, 145, +}; +#define YYFINAL 21 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 280 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,"'$'",0,"'&'",0,"'('","')'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0, +"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'^'",0, +"'`'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,"ANDAND","BACKBACK","BANG","CASE","COUNT","DUP","ELSE","END", +"FLAT","FN","FOR","IF","IN","OROR","PIPE","REDIR","SREDIR","SUB","SUBSHELL", +"SWITCH","TWIDDLE","WHILE","WORD","HUH", +}; +const char * const yyrule[] = { +"$accept : rc", +"rc : line end", +"rc : error end", +"end : END", +"end : '\\n'", +"cmdsa : cmd ';'", +"cmdsa : cmd '&'", +"line : cmd", +"line : cmdsa line", +"body : cmd", +"body : cmdsan body", +"cmdsan : cmdsa", +"cmdsan : cmd '\\n'", +"brace : '{' body '}'", +"paren : '(' body ')'", +"assign : first '=' word", +"epilog :", +"epilog : redir epilog", +"redir : DUP", +"redir : REDIR word", +"redir : SREDIR word", +"case : CASE words ';'", +"case : CASE words '\\n'", +"cbody : cmd", +"cbody : case cbody", +"cbody : cmdsan cbody", +"iftail : cmd", +"iftail : brace ELSE optnl cmd", +"cmd :", +"cmd : simple", +"cmd : brace epilog", +"cmd : IF paren optnl iftail", +"cmd : FOR '(' word IN words ')' optnl cmd", +"cmd : FOR '(' word ')' optnl cmd", +"cmd : WHILE paren optnl cmd", +"cmd : SWITCH '(' word ')' optnl '{' cbody '}'", +"cmd : TWIDDLE optcaret word words", +"cmd : cmd ANDAND optnl cmd", +"cmd : cmd OROR optnl cmd", +"cmd : cmd PIPE optnl cmd", +"cmd : redir cmd", +"cmd : assign cmd", +"cmd : BANG optcaret cmd", +"cmd : SUBSHELL optcaret cmd", +"cmd : FN words brace", +"cmd : FN words", +"optcaret :", +"optcaret : '^'", +"simple : first", +"simple : simple word", +"simple : simple redir", +"first : comword", +"first : first '^' sword", +"sword : comword", +"sword : keyword", +"word : sword", +"word : word '^' sword", +"comword : '$' sword", +"comword : '$' sword SUB words ')'", +"comword : COUNT sword", +"comword : FLAT sword", +"comword : '`' sword", +"comword : '`' brace", +"comword : BACKBACK word brace", +"comword : BACKBACK word sword", +"comword : '(' nlwords ')'", +"comword : REDIR brace", +"comword : WORD", +"keyword : FOR", +"keyword : IN", +"keyword : WHILE", +"keyword : IF", +"keyword : SWITCH", +"keyword : FN", +"keyword : ELSE", +"keyword : CASE", +"keyword : TWIDDLE", +"keyword : BANG", +"keyword : SUBSHELL", +"words :", +"words : words word", +"nlwords :", +"nlwords : nlwords '\\n'", +"nlwords : nlwords word", +"optnl :", +"optnl : optnl '\\n'", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 169 "parse.y" + +void initparse() { + star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc); + nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc); +} + +#line 590 "y.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate])) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 49 "parse.y" +{ parsetree = yyvsp[-1].node; YYACCEPT; } +break; +case 2: +#line 50 "parse.y" +{ yyerrok; parsetree = NULL; YYABORT; } +break; +case 3: +#line 53 "parse.y" +{ if (!heredoc(1)) YYABORT; } +break; +case 4: +#line 54 "parse.y" +{ if (!heredoc(0)) YYABORT; } +break; +case 6: +#line 58 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? mk(nNowait,yyvsp[-1].node) : yyvsp[-1].node); } +break; +case 8: +#line 62 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? mk(nBody,yyvsp[-1].node,yyvsp[0].node) : yyvsp[0].node); } +break; +case 10: +#line 66 "parse.y" +{ yyval.node = (yyvsp[-1].node == NULL ? yyvsp[0].node : yyvsp[0].node == NULL ? yyvsp[-1].node : mk(nBody,yyvsp[-1].node,yyvsp[0].node)); } +break; +case 12: +#line 69 "parse.y" +{ yyval.node = yyvsp[-1].node; if (!heredoc(0)) YYABORT; } +break; +case 13: +#line 71 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 14: +#line 73 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 15: +#line 75 "parse.y" +{ yyval.node = mk(nAssign,yyvsp[-2].node,yyvsp[0].node); } +break; +case 16: +#line 77 "parse.y" +{ yyval.node = NULL; } +break; +case 17: +#line 78 "parse.y" +{ yyval.node = mk(nEpilog,yyvsp[-1].node,yyvsp[0].node); } +break; +case 18: +#line 81 "parse.y" +{ yyval.node = mk(nDup,yyvsp[0].dup.type,yyvsp[0].dup.left,yyvsp[0].dup.right); } +break; +case 19: +#line 82 "parse.y" +{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); + if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ + } +break; +case 20: +#line 85 "parse.y" +{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); + if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ + } +break; +case 21: +#line 89 "parse.y" +{ yyval.node = mk(nCase, yyvsp[-1].node); } +break; +case 22: +#line 90 "parse.y" +{ yyval.node = mk(nCase, yyvsp[-1].node); } +break; +case 23: +#line 92 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[0].node, NULL); } +break; +case 24: +#line 93 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } +break; +case 25: +#line 94 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } +break; +case 27: +#line 97 "parse.y" +{ yyval.node = mk(nElse,yyvsp[-3].node,yyvsp[0].node); } +break; +case 28: +#line 99 "parse.y" +{ yyval.node = NULL; } +break; +case 30: +#line 101 "parse.y" +{ yyval.node = mk(nBrace,yyvsp[-1].node,yyvsp[0].node); } +break; +case 31: +#line 102 "parse.y" +{ yyval.node = mk(nIf,yyvsp[-2].node,yyvsp[0].node); } +break; +case 32: +#line 103 "parse.y" +{ yyval.node = mk(nForin,yyvsp[-5].node,yyvsp[-3].node,yyvsp[0].node); } +break; +case 33: +#line 104 "parse.y" +{ yyval.node = mk(nForin,yyvsp[-3].node,star,yyvsp[0].node); } +break; +case 34: +#line 105 "parse.y" +{ yyval.node = mk(nWhile,yyvsp[-2].node,yyvsp[0].node); } +break; +case 35: +#line 106 "parse.y" +{ yyval.node = mk(nSwitch,yyvsp[-5].node,yyvsp[-1].node); } +break; +case 36: +#line 107 "parse.y" +{ yyval.node = mk(nMatch,yyvsp[-1].node,yyvsp[0].node); } +break; +case 37: +#line 108 "parse.y" +{ yyval.node = mk(nAndalso,yyvsp[-3].node,yyvsp[0].node); } +break; +case 38: +#line 109 "parse.y" +{ yyval.node = mk(nOrelse,yyvsp[-3].node,yyvsp[0].node); } +break; +case 39: +#line 110 "parse.y" +{ yyval.node = mk(nPipe,yyvsp[-2].pipe.left,yyvsp[-2].pipe.right,yyvsp[-3].node,yyvsp[0].node); } +break; +case 40: +#line 111 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 41: +#line 112 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 42: +#line 113 "parse.y" +{ yyval.node = mk(nBang,yyvsp[0].node); } +break; +case 43: +#line 114 "parse.y" +{ yyval.node = mk(nSubshell,yyvsp[0].node); } +break; +case 44: +#line 115 "parse.y" +{ yyval.node = mk(nNewfn,yyvsp[-1].node,yyvsp[0].node); } +break; +case 45: +#line 116 "parse.y" +{ yyval.node = mk(nRmfn,yyvsp[0].node); } +break; +case 49: +#line 122 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nArgs,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 50: +#line 123 "parse.y" +{ yyval.node = mk(nArgs,yyvsp[-1].node,yyvsp[0].node); } +break; +case 52: +#line 126 "parse.y" +{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } +break; +case 54: +#line 129 "parse.y" +{ yyval.node = mk(nWord,yyvsp[0].keyword, NULL); } +break; +case 56: +#line 132 "parse.y" +{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } +break; +case 57: +#line 134 "parse.y" +{ yyval.node = mk(nVar,yyvsp[0].node); } +break; +case 58: +#line 135 "parse.y" +{ yyval.node = mk(nVarsub,yyvsp[-3].node,yyvsp[-1].node); } +break; +case 59: +#line 136 "parse.y" +{ yyval.node = mk(nCount,yyvsp[0].node); } +break; +case 60: +#line 137 "parse.y" +{ yyval.node = mk(nFlat, yyvsp[0].node); } +break; +case 61: +#line 138 "parse.y" +{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } +break; +case 62: +#line 139 "parse.y" +{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } +break; +case 63: +#line 140 "parse.y" +{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } +break; +case 64: +#line 141 "parse.y" +{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } +break; +case 65: +#line 142 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 66: +#line 143 "parse.y" +{ yyval.node = mk(nNmpipe,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); } +break; +case 67: +#line 144 "parse.y" +{ yyval.node = (yyvsp[0].word.w[0] == '\'') ? mk(nQword, yyvsp[0].word.w+1, NULL) : mk(nWord,yyvsp[0].word.w, yyvsp[0].word.m); } +break; +case 68: +#line 146 "parse.y" +{ yyval.keyword = "for"; } +break; +case 69: +#line 147 "parse.y" +{ yyval.keyword = "in"; } +break; +case 70: +#line 148 "parse.y" +{ yyval.keyword = "while"; } +break; +case 71: +#line 149 "parse.y" +{ yyval.keyword = "if"; } +break; +case 72: +#line 150 "parse.y" +{ yyval.keyword = "switch"; } +break; +case 73: +#line 151 "parse.y" +{ yyval.keyword = "fn"; } +break; +case 74: +#line 152 "parse.y" +{ yyval.keyword = "else"; } +break; +case 75: +#line 153 "parse.y" +{ yyval.keyword = "case"; } +break; +case 76: +#line 154 "parse.y" +{ yyval.keyword = "~"; } +break; +case 77: +#line 155 "parse.y" +{ yyval.keyword = "!"; } +break; +case 78: +#line 156 "parse.y" +{ yyval.keyword = "@"; } +break; +case 79: +#line 158 "parse.y" +{ yyval.node = NULL; } +break; +case 80: +#line 159 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } +break; +case 81: +#line 161 "parse.y" +{ yyval.node = NULL; } +break; +case 83: +#line 163 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } +break; +#line 1015 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/y.tab.h b/y.tab.h new file mode 100644 index 0000000..76f8b74 --- /dev/null +++ b/y.tab.h @@ -0,0 +1,33 @@ +#define ANDAND 257 +#define BACKBACK 258 +#define BANG 259 +#define CASE 260 +#define COUNT 261 +#define DUP 262 +#define ELSE 263 +#define END 264 +#define FLAT 265 +#define FN 266 +#define FOR 267 +#define IF 268 +#define IN 269 +#define OROR 270 +#define PIPE 271 +#define REDIR 272 +#define SREDIR 273 +#define SUB 274 +#define SUBSHELL 275 +#define SWITCH 276 +#define TWIDDLE 277 +#define WHILE 278 +#define WORD 279 +#define HUH 280 +typedef union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} YYSTYPE; +extern YYSTYPE yylval; -- cgit v1.2.3 From e11c7df86144bed383ac6bbeaecc3017d18b37db Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Mon, 11 Jan 1999 10:55:18 +0000 Subject: beta: rc-1.5b4 --- AUTHORS | 34 + CHANGES | 278 ------ COPYING | 26 + COPYRIGHT | 26 - ChangeLog | 531 +++++++++++ INSTALL | 167 ++++ Makefile.am | 69 ++ Makefile.in | 80 -- NEWS | 50 ++ README | 191 +--- acconfig.h | 80 ++ acinclude.m4 | 206 +++++ addon.c | 33 +- addon.h | 49 +- builtins.c | 15 +- config.h-dist | 204 +++++ config.h.in | 44 - configure | 2541 ----------------------------------------------------- configure.ac | 200 +++++ configure.in | 287 ------ cpp | 38 - except.c | 4 +- exec.c | 16 +- execve.c | 6 +- fn.c | 19 +- footobar.c | 10 +- getgroups.h | 10 + getopt.c | 73 +- glob.c | 3 +- glom.c | 17 +- group.h | 9 - hash.c | 10 +- history.1 | 243 +++++ history.c | 339 +++++++ history/history.1 | 234 ----- history/history.c | 341 ------- input.c | 99 ++- install-sh | 250 ------ jbwrap.h | 22 +- lex.c | 12 +- main.c | 10 +- mksignal | 76 -- mksignal.c | 238 +++++ nalloc.c | 7 +- open.c | 22 +- parse.y | 4 +- print.c | 141 +-- proto.h | 70 +- rc.1 | 61 +- rc.h | 114 ++- rlimit.h | 36 +- signal.c | 53 +- status.c | 23 +- system-bsd.c | 60 ++ system.c | 10 + trip.rc | Bin 14684 -> 15120 bytes tripping.c | 33 + utils.c | 42 +- var.c | 8 +- version.c | 1 - version.c.in | 1 + wait.c | 94 +- wait.h | 23 + walk.c | 5 +- which.c | 26 +- y.tab.c | 1070 ---------------------- y.tab.h | 33 - 67 files changed, 3104 insertions(+), 6023 deletions(-) create mode 100644 AUTHORS delete mode 100644 CHANGES create mode 100644 COPYING delete mode 100644 COPYRIGHT create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am delete mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 acconfig.h create mode 100644 acinclude.m4 create mode 100644 config.h-dist delete mode 100644 config.h.in delete mode 100755 configure create mode 100644 configure.ac delete mode 100644 configure.in delete mode 100644 cpp create mode 100644 getgroups.h delete mode 100644 group.h create mode 100644 history.1 create mode 100644 history.c delete mode 100644 history/history.1 delete mode 100644 history/history.c delete mode 100755 install-sh delete mode 100755 mksignal create mode 100644 mksignal.c create mode 100644 system-bsd.c create mode 100644 system.c create mode 100644 tripping.c delete mode 100644 version.c create mode 100644 version.c.in create mode 100644 wait.h delete mode 100644 y.tab.c delete mode 100644 y.tab.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..4075191 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,34 @@ +The current maintainer of rc is Tim Goodwin . Please +send all bug reports to him. + +This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr +for letting me know what a shell should do and for contributing certain +bits and pieces to rc (notably the limits code, print.c, most of which.c +and the backquote redirection code), and to Hugh Redelmeier for running +rc through his fussy ANSI compiler and thereby provoking interesting +discussions about portability, and also for providing many valuable +suggestions for improving rc's code in general. Finally, many thanks +go to David Sanderson, for reworking the man page to format well with +troff, and for providing many suggestions both for rc and its man page. + +Thanks to Boyd Roberts for the original history.c, and to Hugh again for +re-working parts of that code. + +Of course, without Tom Duff's design of the original rc, I could not +have written this shell (though I probably would have written *a* +shell). Almost all of the features, with minor exceptions, have been +implemented as described in the Unix v10 manuals. Hats off to td for +designing a C-like, minimal but very useful shell. + +Tom Duff has kindly given permission for the paper he wrote for UKUUG to +be distributed with this version of rc (called "plan9.ps" in the same +FTP or HTTP directory as the shell). Please read this paper bearing in +mind that it describes a program that was written at AT&T and that the +version of rc presented here differs in some respects. + +Tim would like to thank these people for their contributions since he +took over maintenance of rc. Arvid Requate, Bengt Kleberg, Brynjulv +Hauksson, Byron Rakitzis, Chris Siebenmann, David Swasey, Gert-Jan Vons, +Ian Lance Taylor, Jeremy Fitzhardinge, Marc Moorcroft, Mark K Gardner, +Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, +Tom Culliton, Tom Tromey, Vincent Broman. diff --git a/CHANGES b/CHANGES deleted file mode 100644 index 0543c11..0000000 --- a/CHANGES +++ /dev/null @@ -1,278 +0,0 @@ -Changes since 1.2: (Too many to count!) - -A memory stomping bug was fixed (provoked by assigning a variable -to its old value plus something else). - -Better signal handling; a real signal handler which manages a queue -of pending signals was added. - -rc now ignores SIGQUIT and traps SIGINT even in non-interactive -mode. Thus, - - rc ed.sh - -will not do mysterious things if the shell script "ed.sh" calls a -command like "ed" and then you hit ^C. - -rc now opens 0, 1, 2 on /dev/null if they are inherited closed. -rc -o prevents this. - -A couple of stupid O(n^2) string appends were replaced with O(n) -loops. This should make foo=`{cat /etc/termcap} bar=$^foo a little -faster :-) - -Returning a list of signals from a function is now legal, so "return -$status" should always work. - -The code has been revised, new printing routines have been added. - -rc no longer uses redundant braces when exporting functions. - -A first stab at a verification suite has been added (trip.rc). -(someone, please help me make this comprehensive!) - -rc -p now does not initialize functions from the environment. This -should make it easier to write shell scripts that don't need to -assume anything about the environment. - -Inherited ignored signals are now ignored in the current shell and -passed on ignored to the child processes. whatis -s also reflects -this information. - -A file descriptor leak in the /dev/fd implementation of >{} was -fixed. - -A variable set to '' was not imported from the environment; this -has been fixed. - -Changes since 1.3beta: - -New Makefile/config.h setup. - -builtin echo may now be conditionally included out, to use a Goldwynism. - -builtin exit takes any legal exit status. If the status is not all zeros, -rc exits with 1. (having "exit sigiot" produce a core dump would be going -a little far, I think.) - -limit does not append a unit after a zero limit; 0g was too confusing. - -exec > /nonexistentfile does not cause rc to exit any more. - -If a noninteractive rc is started with sigint ignored, rc does not install -its own signal handler. - -error messages produced by rc in a subshell were cleaned up. (rc erroneously -reset the 'interactive' flag after a fork) - -print.c was cleaned up a little; no functionality was changed, but should -be more portable now. - -a bug in rc-1.3beta (not previous versions) was fixed: setting the first -element of $path to '' caused PATH to be exported as '':etc.. - -getopt's "illegal option" message was gratuitously changed to something -less abrupt. - -some dead code was removed from input.c - -%term was changed to %token in parse.y; apparently newer yacc's don't grok -%term any more. - -a race condition in the signal handler was fixed. - -the variable in for() was getting evaluated each time through the loop -(e.g., for (`{echo i;date>[1=2]} in 1 2 3)echo $i would print the date -three times). This was cleaned up. - -a redundant fork() was removed from walk.c; this showed up when running -a braced command with a redirection in the background. e.g., {a;b}>c& - -man pages for history and rc were cleaned up by david (thanks). - -rc set SIGQUIT and SIGTERM to SIG_DFL on background jobs---even when -trying to do old-style backgrounding (i.e., don't use process groups, -just ignore SIGINT & SIGQUIT & SIGTERM). - -$0 is now changed to the name of the signal when entering a signal -handler. Thus it's possible to write code like - - fn sigint sigterm sigquit { - switch ($0) { - case sigint - ... - case sigterm - ... - -wait with no arguments now prints the pid of any and all children -that died with a signal. e.g., - - ; wait - 25321: terminated - 25325: terminated - -as opposed to - - ; wait - terminated - -An error saving/restoring state in the input stream code would -cause rc to exit with the (erroneous) command: - - eval '|[a' - -FIFO's were not removed in a backgrounded command, e.g., - - cat <{echo hi}& - -Changes since rc-1.4beta: - -getopt was renamed to rc_getopt to avoid libc collisions. - -$cdpath with a / in it caused a cd to sometimes have two //'s at the -front of the path. This is reserved by POSIX, so I changed it to skip -one of the /'s. - -signal handling now emulates sh in the way I described in a previous -message: the race condition present in older rc's whereby some SIGINTs -got lost is now gone; any SIGINT received during a wait() is acted upon -at the end of the wait(), unless of course SIGINT is being deliberately -ignored. - -getopt was renamed to avoid naming conflicts with libc. Also a sound -move since rc_getopt is no longer quite libc-getopt compatible; I had -to add in a mechanism for resetting getopt. - -signal handler code in fn.c was cleaned up; there were several bugs -in rc-1.4beta, notably the shell sometimes spawned background jobs -with SIGTERM ignored. I took the opportunity to make things a little -cleaner here. - -a quasi-memory leak in the code for while() was fixed: a long-running -while that had rc commands allocating memory in it could cause the -shell to grow without bounds. I fixed this by placing the while loop -(*and* test!) inside a new allocation arena each time through the loop. - -A new configuration parameter, NOJOB, was added to allow you to force -v7-style backgrounding (no setpgrp, ignore SIGINT and SIGTERM). - -The FIFO code was reworked a little. It should be more robust now--- -FIFOs get removed at the end of the command of the argument list -that they were on: - - fn foo {echo $*; cat $*} - foo<{echo hi} - -now works as expected. Also FIFO names are pushed onto the exception -stack so that their removal occurs in the face of exceptions and so -on. - -A memory leak in treefree() was plugged up --- the root node of a -function was not getting freed. - -Changes since rc-1.4: - -General changes: - - Some small memory leaks/uninit references revealed by Purify. - - $bqstatus for querying the exit status of a backquote. - - Globbing through unreadable directories. - - More options to whatis. - - History append which always re-opens the file (avoids - inconsistencies over multiple NFS-mounted accesses to - $history). - - Support "rc -s". - ---------- - -Makefile: Added comment referring to README for yacc/malloc problem. - -uiltins.c: Added more options to whatis, protected rlimit prototypes - with #ifndef SYSVR4, renamed SIGCHK to sigchk. - -except.c: Patched nl_on_intr printing to happen only in interactive - shells. - -exec.c: Added comment explaining nl_on_intr variable, renamed SIGCHK - to sigchk. - -fn.c: Replaced by-hand consing of exception stack etc. for signal - handler execution with call to funcall(). Replaced fun2str - call with call on print routines. - -footobar.c: Got rid of memory leak in get_name(), parenthesize count, - flat and var nodes for correctness in unparsing, removed - list2str, made get_name use nalloc space, merge in a - better parse_var from es. - -glob.c: Split out a test so that closedir is called correctly, renamed - SIGCHK to sigchk. - -glom.c: Added bqstatus, renamed SIGCHK to sigchk, removed spurious - setsigdefaults, patched uninit memory reference, rename - "clear" to "memzero", wait for bq subproc to finish on EINTR. - -hash.c: Added options to function/variable print code. - -history/history.c: Added '@' to the list of chars which can precede an - ignored '-'. - -input.c: Got rid of tiny memory leak in closefds, got rid of uninit - memory reference in popinput, moved nul ignored check into - realgchar(), changed history append to always reopen the - history file, replaced SIGCHK with sigchk. Freed memory - returned by call to readline(). - -lex.c: Corrected typo in comment, moved nul character ignore code - to input routines. - -main.c: Added -s flag. - -nalloc.c: Added convenience feature to erealloc. (Allow NULL parameter) - -print.c: Changed use of va_start so broken compilers can compile - print code. - -proto.h: Added fake memset. - -rc.h: Replaced clear() function prototype with a macro call on - memset(), removed SIGCHK, fixed prototypes. - -signal.c: Removed unconditional exit in catcher code, renamed SIGCHK - to sigchk. - -status.c: Rewrite sgetstatus breaking out strstatus so that bqstatus - can be set from glom routines. - -utils.c: Got rid of clear() (use memset from C library), rename SIGCHK - to sigchk. - -var.c: Got rid of memory leak in listassign(), converted list2str() - call to something using the print routines. - -version.c: New version string. - -wait.c: Got rid of memory leak in rc_fork, renamed SIGCHK to sigchk. - -walk.c: Fixed pre-redirection bug, removed spurious setsigdefaults(), - renamed SIGCHK to sigchk. - - -Changes since rc-1.5beta1 - - Configuration: rc now uses GNU autoconf. - - Portability: mksignal works on HPUX 10. - - Portability: resources can be (quad_t). - - Bug: if rc was started with SIGCLD == SIG_IGN (e.g. by Solaris's - rshd) it would loop. Fixed by resetting SIGCLD to SIG_DFL if it - was SIG_IGN when rc was started. - - Portability: POSIXish systems don't have NGROUPS. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..8ce4998 --- /dev/null +++ b/COPYING @@ -0,0 +1,26 @@ +/* + * Copyright 1991, 1999 Byron Rakitzis. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * + * 4. This notice may not be removed or altered. + * + * [this copyright notice is adapted from Henry Spencer's + * "awf" copyright notice.] + */ diff --git a/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index 279f66c..0000000 --- a/COPYRIGHT +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 1991 Byron Rakitzis. All rights reserved. - * - * This software is not subject to any license of the American Telephone - * and Telegraph Company or of the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on - * any computer system, and to alter it and redistribute it freely, subject - * to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits must appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits must appear in the documentation. - * - * 4. This notice may not be removed or altered. - * - * [this copyright notice is adapted from Henry Spencer's - * "awf" copyright notice.] - */ diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..d997a6d --- /dev/null +++ b/ChangeLog @@ -0,0 +1,531 @@ +Changes since 1.2: (Too many to count!) + +A memory stomping bug was fixed (provoked by assigning a variable +to its old value plus something else). + +Better signal handling; a real signal handler which manages a queue +of pending signals was added. + +rc now ignores SIGQUIT and traps SIGINT even in non-interactive +mode. Thus, + + rc ed.sh + +will not do mysterious things if the shell script "ed.sh" calls a +command like "ed" and then you hit ^C. + +rc now opens 0, 1, 2 on /dev/null if they are inherited closed. +rc -o prevents this. + +A couple of stupid O(n^2) string appends were replaced with O(n) +loops. This should make foo=`{cat /etc/termcap} bar=$^foo a little +faster :-) + +Returning a list of signals from a function is now legal, so "return +$status" should always work. + +The code has been revised, new printing routines have been added. + +rc no longer uses redundant braces when exporting functions. + +A first stab at a verification suite has been added (trip.rc). +(someone, please help me make this comprehensive!) + +rc -p now does not initialize functions from the environment. This +should make it easier to write shell scripts that don't need to +assume anything about the environment. + +Inherited ignored signals are now ignored in the current shell and +passed on ignored to the child processes. whatis -s also reflects +this information. + +A file descriptor leak in the /dev/fd implementation of >{} was +fixed. + +A variable set to '' was not imported from the environment; this +has been fixed. + +Changes since 1.3beta: + +New Makefile/config.h setup. + +builtin echo may now be conditionally included out, to use a Goldwynism. + +builtin exit takes any legal exit status. If the status is not all zeros, +rc exits with 1. (having "exit sigiot" produce a core dump would be going +a little far, I think.) + +limit does not append a unit after a zero limit; 0g was too confusing. + +exec > /nonexistentfile does not cause rc to exit any more. + +If a noninteractive rc is started with sigint ignored, rc does not install +its own signal handler. + +error messages produced by rc in a subshell were cleaned up. (rc erroneously +reset the 'interactive' flag after a fork) + +print.c was cleaned up a little; no functionality was changed, but should +be more portable now. + +a bug in rc-1.3beta (not previous versions) was fixed: setting the first +element of $path to '' caused PATH to be exported as '':etc.. + +getopt's "illegal option" message was gratuitously changed to something +less abrupt. + +some dead code was removed from input.c + +%term was changed to %token in parse.y; apparently newer yacc's don't grok +%term any more. + +a race condition in the signal handler was fixed. + +the variable in for() was getting evaluated each time through the loop +(e.g., for (`{echo i;date>[1=2]} in 1 2 3)echo $i would print the date +three times). This was cleaned up. + +a redundant fork() was removed from walk.c; this showed up when running +a braced command with a redirection in the background. e.g., {a;b}>c& + +man pages for history and rc were cleaned up by david (thanks). + +rc set SIGQUIT and SIGTERM to SIG_DFL on background jobs---even when +trying to do old-style backgrounding (i.e., don't use process groups, +just ignore SIGINT & SIGQUIT & SIGTERM). + +$0 is now changed to the name of the signal when entering a signal +handler. Thus it's possible to write code like + + fn sigint sigterm sigquit { + switch ($0) { + case sigint + ... + case sigterm + ... + +wait with no arguments now prints the pid of any and all children +that died with a signal. e.g., + + ; wait + 25321: terminated + 25325: terminated + +as opposed to + + ; wait + terminated + +An error saving/restoring state in the input stream code would +cause rc to exit with the (erroneous) command: + + eval '|[a' + +FIFO's were not removed in a backgrounded command, e.g., + + cat <{echo hi}& + +Changes since rc-1.4beta: + +getopt was renamed to rc_getopt to avoid libc collisions. + +$cdpath with a / in it caused a cd to sometimes have two //'s at the +front of the path. This is reserved by POSIX, so I changed it to skip +one of the /'s. + +signal handling now emulates sh in the way I described in a previous +message: the race condition present in older rc's whereby some SIGINTs +got lost is now gone; any SIGINT received during a wait() is acted upon +at the end of the wait(), unless of course SIGINT is being deliberately +ignored. + +getopt was renamed to avoid naming conflicts with libc. Also a sound +move since rc_getopt is no longer quite libc-getopt compatible; I had +to add in a mechanism for resetting getopt. + +signal handler code in fn.c was cleaned up; there were several bugs +in rc-1.4beta, notably the shell sometimes spawned background jobs +with SIGTERM ignored. I took the opportunity to make things a little +cleaner here. + +a quasi-memory leak in the code for while() was fixed: a long-running +while that had rc commands allocating memory in it could cause the +shell to grow without bounds. I fixed this by placing the while loop +(*and* test!) inside a new allocation arena each time through the loop. + +A new configuration parameter, NOJOB, was added to allow you to force +v7-style backgrounding (no setpgrp, ignore SIGINT and SIGTERM). + +The FIFO code was reworked a little. It should be more robust now--- +FIFOs get removed at the end of the command of the argument list +that they were on: + + fn foo {echo $*; cat $*} + foo<{echo hi} + +now works as expected. Also FIFO names are pushed onto the exception +stack so that their removal occurs in the face of exceptions and so +on. + +A memory leak in treefree() was plugged up --- the root node of a +function was not getting freed. + +Changes since rc-1.4: + +General changes: + + Some small memory leaks/uninit references revealed by Purify. + + $bqstatus for querying the exit status of a backquote. + + Globbing through unreadable directories. + + More options to whatis. + + History append which always re-opens the file (avoids + inconsistencies over multiple NFS-mounted accesses to + $history). + + Support "rc -s". + +--------- + +Makefile: Added comment referring to README for yacc/malloc problem. + +uiltins.c: Added more options to whatis, protected rlimit prototypes + with #ifndef SYSVR4, renamed SIGCHK to sigchk. + +except.c: Patched nl_on_intr printing to happen only in interactive + shells. + +exec.c: Added comment explaining nl_on_intr variable, renamed SIGCHK + to sigchk. + +fn.c: Replaced by-hand consing of exception stack etc. for signal + handler execution with call to funcall(). Replaced fun2str + call with call on print routines. + +footobar.c: Got rid of memory leak in get_name(), parenthesize count, + flat and var nodes for correctness in unparsing, removed + list2str, made get_name use nalloc space, merge in a + better parse_var from es. + +glob.c: Split out a test so that closedir is called correctly, renamed + SIGCHK to sigchk. + +glom.c: Added bqstatus, renamed SIGCHK to sigchk, removed spurious + setsigdefaults, patched uninit memory reference, rename + "clear" to "memzero", wait for bq subproc to finish on EINTR. + +hash.c: Added options to function/variable print code. + +history/history.c: Added '@' to the list of chars which can precede an + ignored '-'. + +input.c: Got rid of tiny memory leak in closefds, got rid of uninit + memory reference in popinput, moved nul ignored check into + realgchar(), changed history append to always reopen the + history file, replaced SIGCHK with sigchk. Freed memory + returned by call to readline(). + +lex.c: Corrected typo in comment, moved nul character ignore code + to input routines. + +main.c: Added -s flag. + +nalloc.c: Added convenience feature to erealloc. (Allow NULL parameter) + +print.c: Changed use of va_start so broken compilers can compile + print code. + +proto.h: Added fake memset. + +rc.h: Replaced clear() function prototype with a macro call on + memset(), removed SIGCHK, fixed prototypes. + +signal.c: Removed unconditional exit in catcher code, renamed SIGCHK + to sigchk. + +status.c: Rewrite sgetstatus breaking out strstatus so that bqstatus + can be set from glom routines. + +utils.c: Got rid of clear() (use memset from C library), rename SIGCHK + to sigchk. + +var.c: Got rid of memory leak in listassign(), converted list2str() + call to something using the print routines. + +version.c: New version string. + +wait.c: Got rid of memory leak in rc_fork, renamed SIGCHK to sigchk. + +walk.c: Fixed pre-redirection bug, removed spurious setsigdefaults(), + renamed SIGCHK to sigchk. + + +Changes since rc-1.5beta1 + + Configuration: rc now uses GNU autoconf. + + Portability: mksignal works on HPUX 10. + + Portability: resources can be (quad_t). + + Bug: if rc was started with SIGCLD == SIG_IGN (e.g. by Solaris's + rshd) it would loop. Fixed by resetting SIGCLD to SIG_DFL if it + was SIG_IGN when rc was started. + + Portability: POSIXish systems don't have NGROUPS. + +Changes since rc-1.5b2 + + Configuration: rc now uses GNU automake. + + Portability: use sigsetjmp() when available. + + Portability: improve tests for quad_t. + + Configuration: don't leave FIFOs in /tmp when configuring. + + Configuration: let configure find `-ltermcap' when using readline. + + Configuration: pick up default path from config.cache. + + Bug: sense of most HAVE_RESTARTABLE_SYSCALLS tests was wrong. + + Bug: print prompts with `-i', even with editline / readline. + + Testing: just say `false' (not `/bin/false'). + + Bug: confusion over gid_t versus GETGROUPS_T in which.c. + + Feature: `-V' option added to report version number. + + Configuration: remove version.c; `id' is defined in main.c now. + + Bug: clear list of living children after fork(); `{ ls & wait } |cat' + no longer hangs or panics. + + Testing: add regression test for above. + + Tidiness: all the system call wrappers to prevent calls being + restarted now live in system-bsd.c. The configure script decides + whether to build system.c or system-bsd.c. Also, signal.c is more + careful to only declare slowbuf if it will be needed. + + Tidiness: similarly, configure decides whether to build execve.c or + not. + + Portability: test for ssize_t and use it where available; use long if + there's no ssize_t. + + Portability: use sigsetjmp where it's available and appropriate. If + no sigsetjmp, just use sigjmp; this probably fails in a traditional + SysV environment. + + Portability: test explicitly for SysV SIGCLD semantics. Main (and + dubious) benefit is that you can now define a function called `sigcld' + on systems where there is no signal called SIGCLD! + + Bug: rc has its own memory allocator; don't use malloc directly. + + Bug: the rc_wait() wrapper is only needed on systems which restart + system calls. On Linux, in particular, the wrapper leads to a race + which causes rc to hang (or panic in later versions). Other systems + apparently don't exercise this race. + + Bug: waitforall() must return if rc_wait4() returns with errno == + EINTR. Otherwise, the rc builtin `wait' cannot be interrupted if + there are background processes (although apparently only if there is a + handler for SIGINT). + + Portability: dreadful hack to track down the real locations of + signal.h to find signal names. rc now builds under CygWin32! + + Portability: replace above dreadful hack with mksignal.c, contributed + by Vincent Broman. + + Portability: use POSIX wait() macros (WIFEXITED and friends). + Unfortunately, POSIX omitted to supply WIFDUMPED, so this doesn't buy + a great deal. + + Distribution: remove the dependencies of y.tab.[ch] on parse.y from + Makefile.am. The justification for this is that, unless you're + hacking on rc's grammar, there's no reason to use anything other + than the distributed files (which were generated with byacc and very + lightly edited to silence a few gcc warnings). + + Enhancement: the example in addon.c wasn't very useful, since it + depended on files which weren't included with the distribution. There + is now a working, if trivial, example. + + Tidiness: the code was compiled with as many gcc warnings enabled as + I could find. Very few problems turned up. Some unused function + arguments were removed. Where unused arguments could not be removed + (because the function is one of a set that must all have the same + prototype), they were renamed to `ignore'. + + Portability: some versions of readline define the name `Function', + which rc also uses. Its use in rc has been renamed to `rc_Function'. + + Documentation: the `history' man page didn't explain what end of line + does in editing mode. It now does. + + Bug: the interaction with readline was broken, particularly with + respect to signal handling. I've incorporated some changes from Tom + Culliton which should sort this out. Unfortunately, we now have 3 + different code paths for readline 2.1, readline 2.2, and editline :-(. + + Configuration: if you say `--with-readline' or `--with-editline' it is + now an error if the appropriate library is not found. + + Bug: rc didn't work on RedHat 5 systems. This is because of + peculiarities in the handling of signals and system calls on this + system (the C library attempts to fake restartable system calls). + The fix involves testing at configure time for sigaction() and + SA_INTERRUPT: if both exist, we set up sys_signal() to be an "always + interrupt" wrapper around sigaction(). (If we don't have sigaction(), + we use signal() and check for restartable system calls as usual.) + + Portability: on AIX, lconv is defined by the system header files. + Rename lconv in print.c to avoid the clash. + + Testing: add a test that `cd' prints the new directory if we are + interactive and the directory was found via $cdpath. + +1998-07-23 + + Testing: fix silly typo in above test. + + Configuration: `--with-vrl' added to support Gert-Jan Vons's readline + library. + +1998-07-24 + + Portability: the autoconf macro AC_FUNC_SETPGRP doesn't work on OSF1: that + system supports arguments to setpgrp(), but also has a prototype in + to say that it is void. Fix this by defining our own + RC_FUNC_SETPGRP for now. + + Bug: was included twice in some source files. + + Configuration: automake wants `make distclean' to remove *.tab.c. + Rename y.tab.[ch] to parse.[ch] to avoid this. + +1998-07-27 + + Portability: on Ultrix, `make trip' fails with `malloc: Invalid + argument'. Problem is that getgroups(0, NULL) in which.c returns -1. + Add new configure test to check for POSIX getgroups() and fall back to + NGROUPS if it's not available. The magic is done by "getgroups.h". + + Tidiness: extract magic into "wait.h". + +1998-10-20 + + Tidiness: include prototype for add_history() when doing editline. + + Documentation: document the `-V' flag and mention Linux's + /proc/self/fd as alternative to /dev/fd. + +1998-10-21 + + Bug: shells need to be prepared for bogus applications to have set + their input file descriptor to non-blocking, and set it back. + + Tidiness: is in "proto.h", so nothing else needs to + include it explicitly. + + Documentation: document the ^A bug. + +1998-10-22 + + Tidiness: makenonblock() was a rather poor choice of name for + a function which makes a file descriptor *not* nonblocking :-). + +1998-10-26 + + Portability: apparently some systems declare `char *basename(const + char *)' in system header files. Changing our basename() (in + history.c) to match this prototype allows it to be compiled on such + systems, and is harmless. (Harmless, that is, if no system declares + `char *basename(char *)'.) + +1998-10-28 + + Bug: system-bsd.c needs to include "wait.h". + + Warnings: some versions of gcc warn about "ambiguous" `else' clauses. + + Portability: assigning va_list objects doesn't work everywhere (Linux + on the PowerPC, specifically). Use the C 9x invention va_copy() + instead, if it exists, otherwise fall back to assignment. + + Documentation: help HP-UX users by mentioning that you need `cc -Ae'. + Also, HP-UX make will build rc in a separate directory. + + Tidiness: remove unused functions from print.c. Anybody wanting to + use this library in another project should follow the pointer in the + documentation to an improved version. + +1998-10-29 + + Bug: the "null character ignored" warning was printed with the wrong + line number. Fix by adding an offset argument to pr_error. + + Portability: work around readline's broken treatment of a non-blocking + input file descriptor. + + Testing: add `testing' auxiliary program; use `testing' to generate + null character on the fly (since it's a nuisance having a literal + null character in trip.rc); reset sigexit in `fn fail'; add test for + nonblocking input file descriptor; fix test for cdpath. + + Portability: include before . + +1998-10-30 + + Portability: rename basename() to rc_basename(), since the former is + quite widespread, and has a variety of different definitions (none of + them, of course, static). + + Portability: work around i386 GCC 2.7.2.3 optimization bug triggered + by a (really quite simple) expression in history.c. + +1998-12-04 + + Bug: a debugging statement was left in history.c by mistake. + + Bug: `history' needs to check for `me' character preceded by `/', as + well as all the other options. An invocation like ../rc-1.5/- no + longer loops. + + Documentation: it seems better to have but a single URL in the README + file, which indirects to the other places of interest. + +1998-12-08 + + Portability: use AM_PROG_CC_STDC. This obviates the need for a + special hack on HP-UX. + + Documentation: document all the flags to `whatis'. + +1998-12-09 + + Tidiness: latest autoconf version has fixed AC_FUNC_SETPGRP, so we + no longer need to supply our own. + + Portability: test for va_copy() needs to include . + +1998-12-10 + + Tidiness: move most of the configure.in nastiness into acinclude.m4. + +1998-12-11 + + Tidiness: the release date now only needs to be changed in one place. + +1999-01-05 + + Documentation: the Bell Labs rc now has the list flattening operator, + but spelt $"foo. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..f99c34e --- /dev/null +++ b/INSTALL @@ -0,0 +1,167 @@ +COMPILING + +rc uses GNU autoconf and automake. The following commands are all you +need to configure, build, test, and install rc. + + $ sh configure + $ make + $ make trip + # make install + +This will build rc in the source directory (see below for details on how +to build rc in a different directory). + +BUILD AND CONFIGURATION OPTIONS + +There are lots of options you can give to configure to modify rc's +behaviour. You can also select a command line history library to +link against---see the README file for details of where to find these +libraries. For a summary of all options, run `sh configure --help'. + +You can specify Makefile variables by setting the corresponding +environment variables. For example, you might want to set `CC=cc', to +prevent configure looking for gcc, or set an initial value for `LIBS', +as in the example below. It is a good idea to specify static linking +(unless you are linking against a dynamic readline library)---if you are +using gcc, you can do this by setting `CFLAGS=-static'. + +Here are the configure options you may want to use, in approximately +descending order of usefulness. + + --with-editline + + This option tells rc to use the editline package (see the README file + for details) to provide EMACS style command line editing and history. + If the editline library is not installed in a standard place, you can + tell configure where to find it by setting the environment variable + LIBS. For example, the maintainer builds rc by copying libedit.a into + the rc build directory and then running this configure command. + + LIBS=-L. sh ../rc-1.5b3/configure --with-editline + + --with-vrl + + This option tells rc to use the vrl package (see the README file for + details) to provide EMACS style command line editing and history. As + for `--with-editline', you may need to set the environment variable + LIBS appropriately. + + --with-readline + + This option tells rc to use the GNU readline package, which is similar + to editline or vrl, but has many more features. The readline package + is over 6 times the size of editline (whether you count lines of code, + or the library itself). As for editline, you can set the environment + variable LIBS if your readline library is not installed in a standard + place. + + LIBS=-L/usr/gnu/lib sh configure --with-readline + + --with-history + + Use this option if you want to build and install the programs that + support a crude history mechanism. + +You can't use more than one of `--with-editline', `--with-vrl', and +`--with-readline' at the same time. If you have any of these you +probably don't want to bother with `--with-history'. + + --prefix /path + + By default, `prefix' is /usr/local, which means that `make install' + installs rc (and possibly the history programs) in /usr/local/bin, and + man pages in /usr/local/man/man1. Use this option to change where + `make install' puts things. + + --disable-builtin-echo + + By default, the `echo' command is builtin to rc for reasons of + efficiency and portability (of rc scripts). It is the only builtin + which is not essential, and purists may wish to omit it. Note that + `make trip' will fail if you disable builtin echo and your system's + `echo' does not understand `-n' to suppress newline. + + --with-addon + --with-addon=foo.c + + On the other hand, non-purists may wish to add extra builtin commands. + An example is included in the files addon.c and addon.h, which will + only be built if you specify `--with-addon'. If your addons are + in another file, you can specify that instead (but beware that the + interface file is still addon.h). + + --disable-def-interp + --enable-def-interp=/bin/foo + + By default, a program that fails with "Exec format error" is handed to + /bin/sh. This does the Right Thing for scripts that start with `:' to + indicate that they are sh scripts. You can disable this behaviour + entirely, or specify a different default interpreter. + + --disable-def-path + --enable-def-path "/usr/local/bin","/usr/bin" + + By default, if rc is started with no PATH, it uses a default path. + The default path is constructed at configure time, and consists + of each of the following directories that exist, in order. + + /usr/local/bin /usr/bin /usr/ucb /bin . + + You can disable this, or specify a different default path. Note that + the quote marks (") must be seen by configure; unless you are already + using rc, you will probably need to quote them to your shell. + + --disable-job + + By default, rc puts backgrounded processes into a new process group, + as though it were a job control shell (it isn't). This is usually + needed to work around bugs in application programs which install + signal handlers for the keyboard signals without checking whether the + signal was being ignored. This option disables the default behaviour, + making rc behave like a traditional sh. You are unlikely to want this + option on any Unix system. + + --disable-protect-env + + By default, rc encodes special characters in environment variables. + This is necessary on all known Unix systems to prevent sh either + dying or discarding the variables. This option disables the default + behaviour. You are unlikely to want this option on any Unix system. + +After you've built rc, I recommend that you run it through a test script +to gain some confidence that all is working well. Type `make trip' to +do this. This will produce some output, and should end with "trip is +complete". If the trip instead ends with "trip took a wrong turn..." +please contact the maintainer. + +BUILDING IN ANOTHER DIRECTORY + +If you have a suitable `make', you can build rc in a different directory +from where the sources are held. This is particularly useful if you +are building rc for multiple architectures. All you need do is specify +the path to the configure script in the first step. Suitable `make's +include GNU, HP-UX, and SunOS, but not Irix, nor Ultrix, nor UnixWare. + +COMPILATION WARNINGS + +If your C compiler is gcc, the option `-Wall' is turned on. This may +produce a few warnings. + +Warnings about "implicit declaration" of system functions may occur if +your system's include files are deficient---they are usually harmless. + +There is a warning about "variable `n' might be clobbered" in walk.c. +I'm not sure how serious this warning is, nor how to eliminate it. + +On some systems there are warnings about "passing arg 2 of `getgroups' +from incompatible pointer type" in which.c. I believe this is due to an +incorrect declaration of `getgroups()' in those systems' header files. + +Any other warnings should be reported to the maintainer. + +OLD C + +rc needs an ISO C (89) compiler, or at least one that has a reasonable +understanding of function prototypes, `', `void', and +`volatile'. If you really need to compile rc with an ancient C +compiler, please contact the maintainer. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6433f0c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,69 @@ +## Process this file with automake to produce Makefile.in + +if AMC_ADDON +ADDON = @ADDON@ +endif + +if AMC_HISTORY +man_MANS = rc.1 history.1 +HISTORY = history +else +man_MANS = rc.1 +endif + +if AMC_NO_HASHBANG +EXECVE = execve.o +endif + +if AMC_READLINE +READLINE = readline.o +endif + +if AMC_RESTART +SYSTEM = system-bsd.o +else +SYSTEM = system.o +endif + +bin_PROGRAMS = rc +noinst_PROGRAMS = mksignal tripping $(HISTORY) + +rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c hash.c heredoc.c input.c lex.c list.c main.c match.c nalloc.c open.c parse.c print.c redir.c signal.c status.c tree.c utils.c var.c wait.c walk.c which.c + +EXTRA_rc_SOURCES = addon.c execve.c readline.c system.c system-bsd.c + +rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) +rc_LDADD = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) + +noinst_HEADERS = getgroups.h jbwrap.h parse.h proto.h rc.h rlimit.h wait.h + +BUILT_SOURCES = sigmsgs.c + +EXTRA_DIST = EXAMPLES RELDATE addon.c addon.h history.1 parse.y rc.1 trip.rc + +sigmsgs.c sigmsgs.h: mksignal + ./mksignal + +CONFIGURE_DEPENDENCIES = RELDATE + +# Of course, parse.c and parse.h depend on parse.y. However, unless +# you're hacking on rc's grammar, it's not useful to have this +# dependency expressed, since the distributed parse.[ch] (generated with +# byacc, and lightly edited to remove a couple of gcc warnings) are +# portable (I hope). +#parse.c parse.h: $(srcdir)/parse.y +# $(YACC) -d $(srcdir)/parse.y +# mv y.tab.c parse.c +# mv y.tab.h parse.h + +trip: rc tripping + ./rc -p < $(srcdir)/trip.rc + +install-exec-hook: +if AMC_HISTORY + $(LN) history - ;\ + $(INSTALL_PROGRAM) - $(bindir) ;\ + rm -f $(bindir)/--; $(LN) $(bindir)/- $(bindir)/-- ;\ + rm -f $(bindir)/-p; $(LN) $(bindir)/- $(bindir)/-p ;\ + rm -f $(bindir)/--p; $(LN) $(bindir)/- $(bindir)/--p +endif diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index ed89d84..0000000 --- a/Makefile.in +++ /dev/null @@ -1,80 +0,0 @@ -# Makefile.in for rc. - -SHELL=/bin/sh - -bindir=@bindir@ -exec_prefix=@exec_prefix@ -mandir=@mandir@ -prefix=@prefix@ - -CC=@CC@ -CFLAGS=@CFLAGS@ -LDFLAGS=@CFLAGS@ -LIBS=@LIBS@ - -INSTALL=@INSTALL@ -INSTALL_DATA=@INSTALL_DATA@ -INSTALL_PROGRAM=@INSTALL_PROGRAM@ -LN=@LN@ -YACC=@YACC@ - -HISTORY=@HISTORY@ - -OBJS=@ADDON@ builtins.o except.o exec.o @EXECVE@ fn.o footobar.o getopt.o \ - glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \ - nalloc.o open.o print.o redir.o sigmsgs.o signal.o status.o tree.o \ - utils.o var.o version.o wait.o walk.o which.o y.tab.o - -all: rc $(HISTORY) - -rc: $(OBJS) - $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LIBS) - -sigmsgs.c: mksignal - sh mksignal @SIGNAL_H@ - -y.tab.c: parse.y - $(YACC) -d parse.y - -trip: rc - ./rc -p < trip.rc - -clean: force - rm -f rc $(HISTORY) - *.o *.tab.* sigmsgs.* config.cache config.log - -cleaner: clean - rm -f config.status config.h Makefile - -cleanest: cleaner - rm -f configure - -history: force - cd history; make CC="$(CC)" $(HISTORYMAKEFLAGS) - -install: all - $(INSTALL_PROGRAM) rc $(bindir) - $(INSTALL_DATA) rc.1 $(mandir)/man1/rc.1 - case "x$(HISTORY)" in \ - x) \ - ;; \ - *) \ - $(LN) $(HISTORY) - ;\ - $(INSTALL_PROGRAM) - $(bindir) ;\ - $(LN) $(bindir)/- $(bindir)/-- ;\ - $(LN) $(bindir)/- $(bindir)/-p ;\ - $(LN) $(bindir)/- $(bindir)/--p ;\ - $(INSTALL_DATA) history/history.1 $(mandir)/man1/history.1 \ - ;; \ - esac - -force: - -# dependencies: - -$(OBJS): config.h proto.h rc.h -sigmsgs.h: sigmsgs.c -lex.o y.tab.o: y.tab.c - -builtins.o except.o exec.o input.o signal.o utils.o wait.o walk.o: jbwrap.h -builtins.o: rlimit.h -builtins.o fn.o hash.o signal.o status.o: sigmsgs.h diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..ec827a6 --- /dev/null +++ b/NEWS @@ -0,0 +1,50 @@ +Since rc-1.5b2 was released, many fixes have been made to the +autoconfiguration code, some of them critical. One problem (which I +introduced) was found in minutes with ElectricFence: I had spent several +hours failing to find it with other tools. + +Two bugs in rc itself, one of them trivial, were fixed. + +rc now uses GNU automake. Although I feel that automake is sticking +plaster to mend a broken leg, it has made my job as maintainer easier. +(Errm, apart from tracking down bugs in automake itself, and Perl, that +is.) For people building rc, it's now possible (depending on your +flavour of `make') to build in a separate directory from the source. + +Creeping featurism: rc now has a `-V' switch to report its version +number. + +The detection of signal names has been completely revised. Vincent +Broman suggested this, and contributed mksignal.c. + +The interaction with readline has been redone, principally to work +around bugs in the readline library. Tom Culliton persuaded me of +the need for this, and his patches to an earlier version of rc became +readline.c. + +I rewrote addon.[ch] to provide a more useful example of adding extra +builtins. + +The rc build system no longer considers running `yacc': parse.y is for +information only. The supplied y.tab.[ch] were built with Berkeley +`yacc', and lightly edited to remove a few gcc warnings. This idea was +suggested by Gert-Jan Vons. + +Binaries of rc-1.5b4 are typically a few kilobytes smaller than 1.5b2. +I believe this is due to improved autoconfiguration: we are now much +more careful only to include code that will be used. + +Support for vrl (another lightweight "readline"-style library) was +added. + +rc can now deal with a bogus application that sets its stdin to +non-blocking mode. + +See ChangeLog for more details. + +What happened to rc-1.5b3? There were a couple of releases to people +who'd found bugs in rc-1.5b2 that were called b3. To avoid any +possibility of confusion, I have named this beta release rc-1.5b4. + +Tim Goodwin +1999-01-11 diff --git a/README b/README index 30e9f9a..f750d18 100644 --- a/README +++ b/README @@ -1,136 +1,18 @@ -This is release 1.5b2 of rc. +This is a snapshot release of rc-1.5. The file RELDATE identifies the +date of the snapshot. -Read COPYRIGHT for copying information. All files are +See COPYING for copying information. All files are - Copyright 1991, 1997 Byron Rakitzis. + Copyright 1991, 1999 Byron Rakitzis. -COMPILING +See INSTALL for build and installation information. -rc was written in portable ANSI C. If you don't have an ANSI compiler -like gcc or something close (e.g., sgi's cc) read further down on -how to convert rc's source to old C. - -The following commands are all you need to configure, build, -test, and install rc. - - $ sh configure - $ make - $ make trip - # make install - -There are lots of options you can give to configure to modify rc's -behaviour. You can also select a command line history library to link -against. For a summary of all options, run `sh configure --help'. - -You can specify Makefile variables by setting the corresponding -environment variables. For example, you might want to set `CC=cc', to -prevent configure looking for gcc, or set an initial value for `LIBS', -as in the example below. - -Here are the configure options you may want to use, in approximately -descending order of usefulness. - - --with-editline - - This option tells rc to use Simmule Turner's and Rich $alz's editline - package, which you can get from the following location. This is - essentially a lightweight version of GNU readline, providing EMACS - style command line editing and history. - - ftp://ftp.pipex.net/people/tim/editline.tar.gz - - If the editline library is not installed in a standard place, you - can tell configure where to find it by setting the environment - variable LIBS. For example, the maintainer builds rc by copying - libedit.a into the rc directory and then running this configure - command. - - LIBS=-L. sh configure --with-editline - - --with-readline - - This option tells rc to use the GNU readline package, which is similar - to editline, but has many more features. The readline package is over - 6 times the size of editline (whether you count lines of code, or the - library itself). You probably need to tell the compiler to link with - the termcap library if you're using readline. For example, here is - the configure command the maintainer uses to build rc with readline. - - LIBS=-ltermcap sh configure --with-readline - - --enable-history - - Use this option if you want to build and install the programs that - support a crude history mechanism. - -You can't use `--with-editline' and `--with-readline' together, of course, -and if you have either of those you probably don't want to bother with -`--enable-history'. - - --prefix=/path - - By default, `prefix' is /usr/local, which means that `make install' - installs rc (and possibly the history programs) in /usr/local/bin, and - man pages in /usr/local/man/man1. Use this option to change where - `make install' puts things. - - --disable-builtin-echo - - By default, the `echo' command is builtin to rc for efficiency reasons. - It is the only builtin which is not essential, and purists may wish - to omit it. - - --disable-def-interp - --enable-def-interp=/bin/foo - - By default, a program that fails with "Exec format error" is handed to - /bin/sh. This does the Right Thing for scripts that start with `:' to - indicate that they are sh scripts. You can disable this behaviour - entirely, or specify a different default interpreter. - - --disable-def-path - --enable-def-path="/usr/local/bin","/usr/bin" - - By default, if rc is started with no PATH, it uses a default path. - The default path is constructed at configure time, and consists - of each of the following directories that exist, in order. - - /usr/local/bin /usr/bin /usr/ucb /bin . - - You can disable this, or specify a different default path. Note - that the quote marks (") must be seen by configure; you will - probably need to quote them to your shell. (Not if it's already - rc, but then you will need to quote the `='.) - - --disable-job - - By default, rc puts backgrounded processes into a new process group, - as though it were a job control shell (it isn't). This is usually - needed to work around bugs in application programs which install - signal handlers for the keyboard signals without checking whether the - signal was being ignored. This option disables the default behaviour, - making rc behave like a traditional sh. You are unlikely to want this - option on any Unix system. - - --disable-protect-env - - By default, rc encodes special characters in environment variables. - This is necessary on all known Unix systems to prevent sh either - dying or discarding the variables. This option disables the default - behaviour. You are unlikely to want this option on any Unix system. - -After you've built rc, you may wish to run it through a test script -to see that everything is ok. Type `make trip' for this. This will -produce some output, and end with "trip is complete". If the trip ends -with "trip took a wrong turn..." please contact the maintainer. (If -you've built in either of the command line history libraries, the trip -will fail near the end with `trip took a wrong turn: dot -i'.) BUGS -Send bug reports to ( after -1997-07-27). If a core dump is generated, sending a backtrace will -help a great deal. You can get a backtrace like this. +Send bug reports to . If a core dump is generated, +sending a backtrace will help a great deal. You can get a backtrace +like this. ; gdb rc core (gdb) where @@ -140,58 +22,19 @@ help a great deal. You can get a backtrace like this. Also, always report the machine, OS (`uname -a'), and compiler used to make rc; this information is extremely valuable. + FEEPING CREATURISM See the end of the man page, under "INCOMPATABILITIES" for (known?) differences from the "real" rc. Most of these changes were necessary -to get rc to work in a reasonable fashion on a real (i.e. commercial, +to get rc to work in a reasonable fashion on a real (i.e. commercial, non-Labs) Unix system; a few were changes motivated by concern about some inadequacies in the original design. -YACC - -The yacc that Sun ships with SunOS 4.1.1 calls malloc() to allocate -space for the state stack, and requires a call to YYACCEPT or YYABORT to -free this memory. This means that if rc takes an interrupt while parsing -a command (say, if ^C is typed), yacc will leak away this memory. The -solution is to use a yacc which statically allocates this array, such -as the yacc in the BSD distribution. Berkeley yacc-generated y.tab.c -and y.tab.h are shipped with rc in case you cannot get hold of Berkeley -yacc. - -OLD C - -If you need to convert rc's source into K&R C, you need to run the -source through a filter called "unproto", posted in comp.sources.misc. -A sample "cpp" shell script that I used to run unproto under SunOS is -supplied with rc. - -CREDITS - -This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr -for letting me know what a shell should do and for contributing certain -bits and pieces to rc (notably the limits code, print.c, most of which.c -and the backquote redirection code), and to Hugh Redelmeier for running -rc through his fussy ANSI compiler and thereby provoking interesting -discussions about portability, and also for providing many valuable -suggestions for improving rc's code in general. Finally, many thanks -go to David Sanderson, for reworking the man page to format well with -troff, and for providing many suggestions both for rc and its man page. - -Thanks to Boyd Roberts for the original history.c, and to Hugh again for -re-working parts of that code. - -Of course, without Tom Duff's design of the original rc, I could not -have written this shell (though I probably would have written *a* -shell). Almost of all of the features, with minor exceptions, have been -implemented as described in the Unix v10 manuals. Hats off to td for -designing a C-like, minimal but very useful shell. - -Tom Duff has kindly given permission for the paper he wrote for UKUUG to -be distributed with this version of rc (called "plan9.ps" in the same -ftp directory as the shell). Please read this paper bearing in mind that -it describes a program that was written at AT&T and that the version of -rc presented here differs in some respects. - -The current maintainer of rc is Tim Goodwin, -( after 1997-07-27). + +WWW + +More information on releases of rc can be found at this web page. + + http://www.star.le.ac.uk/~tjg/rc/ + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..8e8c0e7 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,80 @@ +/* Define to a suitable ssize_t. */ +#undef ssize_t + +/* Define to a suitable sig_atomic_t. */ +#undef sig_atomic_t + +/* Define if you want rc to hand off exec errors to (e.g.) /bin/sh. */ +#undef DEFAULTINTERP + +/* Define to the default path used if $PATH is empty when rc starts. */ +#undef DEFAULTPATH + +/* Define if your kernel has SysV special SIGCLD semantics. */ +#undef HAVE_SYSV_SIGCLD + +/* Define if your kernel supports `#!' magic numbers. */ +#undef HASH_BANG + +/* Define if you have /dev/fd. */ +#undef HAVE_DEV_FD + +/* Define if you have /proc/self/fd. */ +#undef HAVE_PROC_SELF_FD + +/* Define if you have named pipes. */ +#undef HAVE_FIFO + +/* Define if quad_t is a native type. */ +#undef HAVE_QUAD_T + +/* Define if you have rlim_t. */ +#undef HAVE_RLIM_T + +/* Define if you have sigsetjmp(). */ +#undef HAVE_SIGSETJMP + +/* Define if you want rc to encode strange characters in the environment. */ +#undef PROTECT_ENV + +/* Define if you have extra builtins. */ +#undef RC_ADDON + +/* Define if you want echo as a builtin. */ +#undef RC_ECHO + +/* Define if you want rc to support broken apps, like a job control shell. */ +#undef RC_JOB + +/* Define if you want to use editline. */ +#undef EDITLINE + +/* Define if you want to use GNU readline. */ +#undef READLINE + +/* Define if you have the older readline, with rl_deprep_terminal. */ +#undef READLINE_OLD + +/* Define if RLIMIT_foo defines need _KERNEL. */ +#undef RLIMIT_NEEDS_KERNEL + +/* Define if rlim_t is quad_t. */ +#undef RLIM_T_IS_QUAD_T + +/* Define to package name. */ +#undef PACKAGE + +/* Define to version. */ +#undef VERSION + +/* Define to release date. */ +#undef RELDATE + +/* Define if you have SA_INTERRUPT (and sigaction()). */ +#undef HAVE_SA_INTERRUPT + +/* Define if you have POSIX getgroups(). */ +#undef HAVE_POSIX_GETGROUPS + +/* Define if you have va_copy(). */ +#undef HAVE_VA_COPY diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..3516928 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,206 @@ +dnl This macro sets HAVE_POSIX_GETGROUPS if the +dnl getgroups() function accepts a zero first argument. +AC_DEFUN(RC_FUNC_GETGROUPS, [ + AC_CACHE_CHECK(for POSIX getgroups, rc_cv_func_posix_getgroups, AC_TRY_RUN([ +#include +#include +int main(void) { + return getgroups(0, (void *)0) == -1; +} + ], rc_cv_func_posix_getgroups=yes, rc_cv_func_posix_getgroups=no, rc_cv_func_posix_getgroups=yes)) + case "$rc_cv_func_posix_getgroups" in + yes) AC_DEFINE(HAVE_POSIX_GETGROUPS) ;; + esac +]) + + +dnl Check for va_copy() in . This is new in C 9x. +AC_DEFUN(RC_HAVE_VA_COPY, [ + AC_CACHE_CHECK(for va_copy(), rc_cv_have_va_copy, AC_EGREP_CPP(yes, [ +#include +#ifdef va_copy +yes +#endif +], rc_cv_have_va_copy=yes, rc_cv_have_va_copy=no)) + case "$rc_cv_have_va_copy" in + yes) AC_DEFINE(HAVE_VA_COPY) ;; + esac +]) + + +dnl We can't use AC_CHECK_FUNCS for sigsetjmp(), since it's a macro in +dnl some places. +AC_DEFUN(RC_FUNC_SIGSETJMP, [ + AC_CACHE_CHECK(for sigsetjmp, rc_cv_sigsetjmp, + AC_TRY_LINK([ +#include + ], [ +sigjmp_buf e; +sigsetjmp(e, 1); + ], rc_cv_sigsetjmp=yes, rc_cv_sigsetjmp=no)) + case "$rc_cv_sigsetjmp" in + yes) AC_DEFINE(HAVE_SIGSETJMP) ;; + esac +]) + +dnl HPUX needs _KERNEL defined to pick up RLIMIT_foo defines. (Why?) +AC_DEFUN(RC_NEED_KERNEL, [ + AC_CACHE_CHECK(if _KERNEL is required for RLIMIT defines, rc_cv_kernel_rlimit, + AC_TRY_COMPILE([ +#include +#include + ], [ +int f; +f = RLIMIT_DATA; + ], rc_cv_kernel_rlimit=no, [ AC_TRY_COMPILE([ +#include +#define _KERNEL +#include +#undef _KERNEL + ], [ +int f; +f = RLIMIT_DATA; + ], rc_cv_kernel_rlimit=yes, rc_cv_kernel_rlimit=no)])) + case "$rc_cv_kernel_rlimit" in + yes) AC_DEFINE(RLIMIT_NEEDS_KERNEL) ;; + esac +]) + +dnl Look for rlim_t in sys/types.h and sys/resource.h +AC_DEFUN(RC_TYPE_RLIM_T, [ + AC_CACHE_CHECK(for rlim_t, rc_cv_have_rlim_t, + AC_EGREP_CPP(rlim_t, [ +#include +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include + ], rc_cv_have_rlim_t=yes, rc_cv_have_rlim_t=no)) + + case "$rc_cv_have_rlim_t" in + yes) AC_DEFINE(HAVE_RLIM_T) ;; + no) AC_CACHE_CHECK(for native quad_t, rc_cv_have_quad_t, + AC_TRY_COMPILE([ +#include + ], [ +typedef quad_t align_t; +align_t a; +a = (quad_t)0; + ], rc_cv_have_quad_t=yes, rc_cv_have_quad_t=no)) + + case "$rc_cv_have_quad_t" in + yes) AC_DEFINE(HAVE_QUAD_T) + AC_CACHE_CHECK(if rlimit values are quad_t, rc_cv_rlim_t_is_quad_t, + AC_TRY_RUN([ +#include +#include +#include +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include +#if RLIMIT_NEEDS_KERNEL +#undef _KERNEL +#endif +main(){ + struct rlimit rl; + exit(sizeof rl.rlim_cur != sizeof(quad_t)); +} + ], rc_cv_rlim_t_is_quad_t=yes, rc_cv_rlim_t_is_quad_t=no, $ac_cv_type_quad_t)) + + case "$rc_cv_rlim_t_is_quad_t" in + yes) AC_DEFINE(RLIM_T_IS_QUAD_T) ;; + esac + ;; + esac + ;; + esac +]) + + +dnl Check type of sig_atomic_t. +AC_DEFUN(RC_TYPE_SIG_ATOMIC_T, [ + AC_CACHE_CHECK(for sig_atomic_t, rc_cv_sig_atomic_t, + AC_EGREP_HEADER(sig_atomic_t, signal.h, + rc_cv_sig_atomic_t=yes, rc_cv_sig_atomic_t=no)) + case "$rc_cv_sig_atomic_t" in + no) AC_DEFINE(sig_atomic_t, int) ;; + esac +]) + + +dnl Check for sigaction and SA_INTERRUPT +AC_DEFUN(RC_FUNC_SIGACTION, [ + AC_CACHE_CHECK(for sigaction and SA_INTERRUPT, rc_cv_sa_int, + AC_TRY_COMPILE([ +#include + ], [ +struct sigaction foo; +foo.sa_flags = SA_INTERRUPT; +sigaction(SIGINT, 0, 0); + ], rc_cv_sa_int=yes, rc_cv_sa_int=no + ) + ) +]) + + +dnl Do we have SysV SIGCLD semantics? In other words, if we set the +dnl action for SIGCLD to SIG_IGN does wait() always say ECHILD? +AC_DEFUN(RC_SYS_V_SIGCLD, [ + AC_CACHE_CHECK(for SysV SIGCLD semantics, rc_cv_sysv_sigcld, + AC_TRY_RUN([ +#include +#include +#include +#include +#include +int main(void) { + int i; + sigset(SIGCLD, SIG_IGN); + switch (fork()) { + case -1: + return 1; + case 0: + return 0; + default: + if (wait(&i) == -1 && errno == ECHILD) return 0; + else return 1; + } +} + ], rc_cv_sysv_sigcld=yes, rc_cv_sysv_sigcld=no, rc_cv_sysv_sigcld=yes)) + case "$rc_cv_sysv_sigcld" in + yes) AC_DEFINE(HAVE_SYSV_SIGCLD) ;; + esac +]) + + +dnl Do we have /dev/fd or /proc/self/fd? +AC_DEFUN(RC_SYS_DEV_FD, [ + AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd, + if test -d /dev/fd && test -r /dev/fd/0; then + rc_cv_sys_dev_fd=yes + elif test -d /proc/self/fd && test -r /proc/self/fd/0; then + rc_cv_sys_dev_fd=odd + else + rc_cv_sys_dev_fd=no + fi + ) +]) + + +dnl Can mknod make FIFOs? +AC_DEFUN(RC_SYS_MKNOD_FIFO, [ + AC_CACHE_CHECK(for mknod FIFOs, rc_cv_sys_fifo, + AC_TRY_RUN([ +#include +#include + +main() { + exit(mknod("/tmp/rc$$.0", S_IFIFO | 0666, 0) != 0); +} + ], rc_cv_sys_fifo=yes, rc_cv_sys_fifo=no, rc_cv_sys_fifo=no)) + rm -f /tmp/rc$$.0 + case "$rc_cv_sys_fifo" in + yes) AC_DEFINE(HAVE_FIFO) ;; + esac +]) diff --git a/addon.c b/addon.c index df3fcd7..6e6c232 100644 --- a/addon.c +++ b/addon.c @@ -1,22 +1,25 @@ /* - This file contains the implementations of any locally defined - builtins. + This file is NOT BUILT by default. Together with addon.h, it + provides an example of how to add new builtins to rc. */ -#ifdef DWS - -/* - This is what DaviD Sanderson (dws@cs.wisc.edu) uses. -*/ +#include "rc.h" +#include "addon.h" -#include -#include -#include +void b_sum(char **av) { + long sum = 0; -#include "rc.h" /* for bool TRUE, FALSE */ -#include "addon.h" + while (*++av) + sum += atol(*av); + fprint(1, "%ld\n", sum); + set(TRUE); +} -#include "addon/access.c" -#include "addon/test.c" +void b_prod(char **av) { + long sum = 1; -#endif + while (*++av) + sum *= atol(*av); + fprint(1, "%ld\n", sum); + set(TRUE); +} diff --git a/addon.h b/addon.h index 25f2312..4a69375 100644 --- a/addon.h +++ b/addon.h @@ -1,38 +1,31 @@ /* - This file is the interface to the rest of rc for any locally - defined addon builtins. By default there are none. - The interface consists of the following macro. - - ADDONS A comma-separated list of pairs of function pointers - and string literals. - - The addon functions must also have proper prototypes in this file. - The builtins all have the form: - + This file is NOT BUILT by default. Together with addon.c, it + provides an example of how to add new builtins to rc. + + To define a new builtin, it must appear in the macro ADDONS, which + is a comma-separated list of pairs of function pointers (the + implementation of the new builtin) and string literals (the name of + the new builtin). + + Any new builtin functions must also have proper prototypes in this + file. This is always of the same form. + void b_NAME(char **av); - - Builtins report their exit status using set(TRUE) or set(FALSE). - - Example: - - #define ADDONS { b_test, "test" }, - extern void b_test(char **av); -*/ -#define ADDONS /* no addons by default */ + The first argument, av[0], is the name of the builtin. The last + argument is followed by a NULL pointer. -#ifdef DWS + Builtins report their exit status using set(TRUE) or set(FALSE). -/* - This is what DaviD Sanderson (dws@cs.wisc.edu) uses. */ -#undef ADDONS -#define ADDONS { b_access, "access" },\ - { b_test, "test" },\ - { b_test, "[" }, +#if RC_ADDON + +#define ADDONS \ + { b_sum, "+" }, \ + { b_prod, "x" }, -extern void b_access(char **av); -extern void b_test(char **av); +extern void b_sum(char **av); +extern void b_prod(char **av); #endif diff --git a/builtins.c b/builtins.c index 1f9b56e..dcea06d 100644 --- a/builtins.c +++ b/builtins.c @@ -10,15 +10,14 @@ #include "rc.h" #include +#include #include #include -#include "jbwrap.h" -#include "sigmsgs.h" #include "addon.h" +#include "jbwrap.h" #include "rlimit.h" - -extern int umask(int); +#include "sigmsgs.h" static void b_break(char **), b_cd(char **), b_eval(char **), b_exit(char **), b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **), @@ -55,7 +54,9 @@ static struct { { b_wait, "wait" }, { b_whatis, "whatis" }, { b_dot, "." }, +#ifdef ADDONS ADDONS +#endif }; extern builtin_t *isbuiltin(char *s) { @@ -72,7 +73,7 @@ extern void funcall(char **av) { Jbwrap j; Estack e1, e2; Edata jreturn, star; - if (setjmp(j.j)) + if (sigsetjmp(j.j, 1)) return; starassign(*av, av+1, TRUE); jreturn.jb = &j; @@ -97,7 +98,7 @@ static void badnum(char *num) { /* a dummy command. (exec() performs "exec" simply by not forking) */ -extern void b_exec(char **av) { +extern void b_exec(char **ignore) { } #if RC_ECHO @@ -244,7 +245,7 @@ static void b_shift(char **av) { /* dud function */ -extern void b_builtin(char **av) { +extern void b_builtin(char **ignore) { } /* wait for a given process, or all outstanding processes */ diff --git a/config.h-dist b/config.h-dist new file mode 100644 index 0000000..5be81eb --- /dev/null +++ b/config.h-dist @@ -0,0 +1,204 @@ +/* Copy config.h-dist to config.h and edit config.h, don't edit this file */ + +/* + * Configuration parameters for rc. Suggested defaults are at the bottom + * of this file (you should probably look at those first to see if your + * system matches one of them; you can search for the beginning of the + * defaults section by looking for the string "#ifndef CUSTOM"). If you + * want to override the suggested defaults, define the macro CUSTOM. +#define CUSTOM + */ + +/* + * (Note that certain default settings redefine this macro) + * DEFAULTPATH the default search path that rc uses when it is started + * without either a $PATH or $path environment variable. You must pick + * something sensible for your system if you don't like the path shown + * below. + */ +#define DEFAULTPATH "/usr/ucb", "/usr/bin", "/bin", "." + +/* + * Define the macro NODIRENT if your system has but not + * . (e.g., NeXT-OS and RISCos) +#define NODIRENT + */ + +/* + * Define the macro SVSIGS if your system has System V signal semantics, + * i.e., if "slow" system calls are interrupted rather than resumed + * after returning from an interrupt handler. (If you are not sure what + * this means, see the man page for signal(2). In any case, it is probably + * safe to leave this macro undefined.) +#define SVSIGS + */ + +/* + * Define the macro NOCMDARG if you do not have /dev/fd or fifos on your + * system. You may also want to define this if you have broken fifos. +#define NOCMDARG + */ + +/* + * Define TMPDIR if you need to have rc create its fifos in a directory + * other than /tmp. For example, if you have a Sun with /tmp mounted + * as a ramdisk (type "tmpfs") then you cannot use fifos in /tmp (sigh). +#define TMPDIR "/var/tmp" + */ + +/* + * Define the macro DEVFD if your system supports /dev/fd. +#define DEVFD + */ + +/* + * Define the macro NOLIMITS if your system does not support Berkeley + * limits. +#define NOLIMITS + */ + +/* + * Define the macro NOSIGCLD if your system uses SIGCLD in the System + * V way. (e.g., sgi's Irix) +#define NOSIGCLD + */ + +/* + * Define the macro READLINE if you want rc to call GNU readline + * instead of read(2) on interactive shells. +#define READLINE + */ + +/* + * Define the macro NOEXECVE if your Unix does not interpret #! in the + * kernel, and uncomment the EXECVE variable in the Makefile. +#define NOEXECVE + */ + +/* + * If you want rc to default to some interpreter for files which don't + * have a legal #! on the first line, define the macro DEFAULTINTERP. +#define DEFAULTINTERP "/bin/sh" + */ + +/* + * If your /bin/sh (or another program you care about) rejects environment + * variables with special characters in them (such as ':' or '-'), rc can + * put out ugly variable names using [_0-9a-zA-Z] that encode the real name; + * define PROTECT_ENV for this hack. (Known offenders: every sh I have tried; + * SunOS (silently discards), NeXT (aborts with error), SGI (aborts with + * error), Ultrix (sh seems to work, sh5 aborts with error)) +#define PROTECT_ENV + */ + +/* + * Define the macro NOECHO if you wish to omit rc's echo builtin from the + * compile. +#define NOECHO + */ + +/* + * Define the NOJOB if you do *not* wish rc to perform backgrounding + * as if it were a job-control shell; that is, if you do *not* wish + * it to put a command spawned in the background into a new process + * group. Since most systems support job control and since there are + * many broken programs that do not behave correctly when backgrounded + * in a v7 non-job-control fashion, rc by default performs a job- + * control-like backgrounding. +#define NOJOB + */ + +/* Beginning of defaults section: */ + +#ifndef CUSTOM + +/* + * Suggested settings for Sun, NeXT and sgi (machines here at TAMU): + */ + +#ifdef NeXT /* Used on NextOS 2.1 */ +#define NODIRENT +#define PROTECT_ENV +#define NOCMDARG +#endif + +#ifdef sgi /* Used on Irix 3.3.[12] */ +#define SVSIGS +#define NOSIGCLD +#define PROTECT_ENV +#undef DEFAULTPATH +#define DEFAULTPATH "/usr/bsd", "/usr/sbin", "/usr/bin", "/bin", "." +#endif + +#ifdef sun /* Used on SunOS 4.1.1 */ +#define PROTECT_ENV +#undef DEFAULTPATH +#define DEFAULTPATH "/usr/ucb", "/usr/bin", "." +#endif + +/* + * Suggested settings for HP300 running 4.3BSD-utah (DWS): + */ + +#if defined(hp300) && !defined(hpux) +#define NODIRENT +#define NOCMDARG +#define DEFAULTINTERP "/bin/sh" +#define PROTECT_ENV +#endif + +/* + * Suggested settings for Ultrix + */ + +#ifdef ultrix +#define PROTECT_ENV +#define DEFAULTINTERP "/bin/sh" /* so /bin/true can work */ +#endif + +/* + * Suggested settings for RISCos 4.52 + */ + +/* + This doesn't work without interfering with other MIPS-based + systems' configuration. Please do it by hand. +*/ + +#if defined(host_mips) && defined(MIPSEB) && defined(SYSTYPE_BSD43) +#define NODIRENT +#define PROTECT_ENV +#endif + +/* + * Suggested settings for AIX + */ + +#ifdef _AIX +#define PROTECT_ENV +#endif + +/* + * Suggested settings for OSF/1 1.0 + */ + +#ifdef OSF1 +#define PROTECT_ENV +#endif + +/* + * Suggested settings for Unicos XXX + */ + +#ifdef cray +#define PROTECT_ENV +#define NOLIMITS +#define word _word +#define DEFAULTINTERP "/bin/sh" +#endif + +#endif /* CUSTOM */ + +#ifndef TMPDIR +#define TMPDIR "/tmp" +#endif diff --git a/config.h.in b/config.h.in deleted file mode 100644 index 3c8bde8..0000000 --- a/config.h.in +++ /dev/null @@ -1,44 +0,0 @@ -/* Header files */ -#undef STDC_HEADERS - -#undef HAVE_SYS_RESOURCE_H -#undef RLIMIT_NEEDS_KERNEL -#undef HAVE_SYS_TIME_H -#undef HAVE_UNISTD_H - -#undef HAVE_DIRENT_H -#undef HAVE_SYS_NDIR_H -#undef HAVE_SYS_DIR_H -#undef HAVE_NDIR_H - -/* Functions */ -#undef HAVE_GETGROUPS -#undef HAVE_SETPGRP -#undef HAVE_SETRLIMIT - -/* Types */ -#undef HAVE_GID_T -#undef HAVE_RLIM_T -#undef HAVE_QUAD_T -#undef RLIM_T_IS_QUAD_T -#undef GETGROUPS_T -#undef gid_t -#undef pid_t -#undef size_t -#undef uid_t - -/* OS features */ -#undef HASH_BANG -#undef HAVE_DEV_FD -#undef HAVE_FIFO -#undef HAVE_PROC_SELF_FD -#undef HAVE_RESTARTABLE_SYSCALLS -#undef SETPGRP_VOID - -/* rc features */ -#undef DEFAULTINTERP -#undef DEFAULTPATH -#undef RC_ECHO -#undef RC_JOB -#undef PROTECT_ENV -#undef READLINE diff --git a/configure b/configure deleted file mode 100755 index 9460c76..0000000 --- a/configure +++ /dev/null @@ -1,2541 +0,0 @@ -#! /bin/sh - -# Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.12 -# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. - -# Defaults: -ac_help= -ac_default_prefix=/usr/local -# Any additions from configure.in: -ac_help="$ac_help - --disable-builtin-echo Don't include \`echo' as a builtin" -ac_help="$ac_help - --disable-job Don't do job-control-style backgrounding" -ac_help="$ac_help - --disable-protect-env Don't protect environment names" -ac_help="$ac_help - --enable-def-interp=/bin/foo - Use /bin/foo as default interpreter [/bin/sh]" -ac_help="$ac_help - --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" - Default path [All of these that exist - (/usr/local/bin /usr/bin /usr/ucb /bin .)]" -ac_help="$ac_help - --enable-history Build history subprograms" -ac_help="$ac_help - --with-addon Extra builtins, from addon.c " -ac_help="$ac_help - --with-editline Simmule Turner's line editing" -ac_help="$ac_help - --with-readline Bloated GNU line editing" - -# Initialize some variables set by options. -# The variables have the same names as the options, with -# dashes changed to underlines. -build=NONE -cache_file=./config.cache -exec_prefix=NONE -host=NONE -no_create= -nonopt=NONE -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -target=NONE -verbose= -x_includes=NONE -x_libraries=NONE -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datadir='${prefix}/share' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -libdir='${exec_prefix}/lib' -includedir='${prefix}/include' -oldincludedir='/usr/include' -infodir='${prefix}/info' -mandir='${prefix}/man' - -# Initialize some other variables. -subdirs= -MFLAGS= MAKEFLAGS= -# Maximum number of lines to put in a shell here document. -ac_max_here_lines=12 - -ac_prev= -for ac_option -do - - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval "$ac_prev=\$ac_option" - ac_prev= - continue - fi - - case "$ac_option" in - -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) ac_optarg= ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case "$ac_option" in - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir="$ac_optarg" ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build="$ac_optarg" ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file="$ac_optarg" ;; - - -datadir | --datadir | --datadi | --datad | --data | --dat | --da) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ - | --da=*) - datadir="$ac_optarg" ;; - - -disable-* | --disable-*) - ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - eval "enable_${ac_feature}=no" ;; - - -enable-* | --enable-*) - ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "enable_${ac_feature}='$ac_optarg'" ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix="$ac_optarg" ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he) - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat << EOF -Usage: configure [options] [host] -Options: [defaults in brackets after descriptions] -Configuration: - --cache-file=FILE cache test results in FILE - --help print this message - --no-create do not create output files - --quiet, --silent do not print \`checking...' messages - --version print the version of autoconf that created configure -Directory and file names: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [same as prefix] - --bindir=DIR user executables in DIR [EPREFIX/bin] - --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] - --libexecdir=DIR program executables in DIR [EPREFIX/libexec] - --datadir=DIR read-only architecture-independent data in DIR - [PREFIX/share] - --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data in DIR - [PREFIX/com] - --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] - --libdir=DIR object code libraries in DIR [EPREFIX/lib] - --includedir=DIR C header files in DIR [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] - --infodir=DIR info documentation in DIR [PREFIX/info] - --mandir=DIR man documentation in DIR [PREFIX/man] - --srcdir=DIR find the sources in DIR [configure dir or ..] - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM - run sed PROGRAM on installed program names -EOF - cat << EOF -Host type: - --build=BUILD configure for building on BUILD [BUILD=HOST] - --host=HOST configure for HOST [guessed] - --target=TARGET configure for TARGET [TARGET=HOST] -Features and packages: - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --x-includes=DIR X include files are in DIR - --x-libraries=DIR X library files are in DIR -EOF - if test -n "$ac_help"; then - echo "--enable and --with options recognized:$ac_help" - fi - exit 0 ;; - - -host | --host | --hos | --ho) - ac_prev=host ;; - -host=* | --host=* | --hos=* | --ho=*) - host="$ac_optarg" ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir="$ac_optarg" ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir="$ac_optarg" ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir="$ac_optarg" ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir="$ac_optarg" ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst \ - | --locals | --local | --loca | --loc | --lo) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* \ - | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) - localstatedir="$ac_optarg" ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir="$ac_optarg" ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir="$ac_optarg" ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix="$ac_optarg" ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix="$ac_optarg" ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix="$ac_optarg" ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name="$ac_optarg" ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir="$ac_optarg" ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir="$ac_optarg" ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site="$ac_optarg" ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir="$ac_optarg" ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir="$ac_optarg" ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target="$ac_optarg" ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.12" - exit 0 ;; - - -with-* | --with-*) - ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "with_${ac_package}='$ac_optarg'" ;; - - -without-* | --without-*) - ac_package=`echo $ac_option|sed -e 's/-*without-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - eval "with_${ac_package}=no" ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes="$ac_optarg" ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries="$ac_optarg" ;; - - -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } - ;; - - *) - if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then - echo "configure: warning: $ac_option: invalid host type" 1>&2 - fi - if test "x$nonopt" != xNONE; then - { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } - fi - nonopt="$ac_option" - ;; - - esac -done - -if test -n "$ac_prev"; then - { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } -fi - -trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 - -# File descriptor usage: -# 0 standard input -# 1 file creation -# 2 errors and warnings -# 3 some systems may open it to /dev/tty -# 4 used on the Kubota Titan -# 6 checking for... messages and results -# 5 compiler messages saved in config.log -if test "$silent" = yes; then - exec 6>/dev/null -else - exec 6>&1 -fi -exec 5>./config.log - -echo "\ -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. -" 1>&5 - -# Strip out --no-create and --no-recursion so they do not pile up. -# Also quote any args containing shell metacharacters. -ac_configure_args= -for ac_arg -do - case "$ac_arg" in - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) ;; - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) - ac_configure_args="$ac_configure_args '$ac_arg'" ;; - *) ac_configure_args="$ac_configure_args $ac_arg" ;; - esac -done - -# NLS nuisances. -# Only set these to C if already set. These must not be set unconditionally -# because not all systems understand e.g. LANG=C (notably SCO). -# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! -# Non-C LC_CTYPE values break the ctype check. -if test "${LANG+set}" = set; then LANG=C; export LANG; fi -if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi -if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi -if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -rf conftest* confdefs.h -# AIX cpp loses on an empty file, so make sure it contains at least a newline. -echo > confdefs.h - -# A filename unique to this package, relative to the directory that -# configure is in, which we can look for to find out if srcdir is correct. -ac_unique_file=rc.h - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then its parent. - ac_prog=$0 - ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` - test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. - srcdir=$ac_confdir - if test ! -r $srcdir/$ac_unique_file; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r $srcdir/$ac_unique_file; then - if test "$ac_srcdir_defaulted" = yes; then - { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } - else - { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } - fi -fi -srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` - -# Prefer explicitly selected file to automatically selected ones. -if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" - fi -fi -for ac_site_file in $CONFIG_SITE; do - if test -r "$ac_site_file"; then - echo "loading site script $ac_site_file" - . "$ac_site_file" - fi -done - -if test -r "$cache_file"; then - echo "loading cache $cache_file" - . $cache_file -else - echo "creating cache $cache_file" - > $cache_file -fi - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then - # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. - if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then - ac_n= ac_c=' -' ac_t=' ' - else - ac_n=-n ac_c= ac_t= - fi -else - ac_n= ac_c='\c' ac_t= -fi - - - - - -# Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:549: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CC="gcc" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:578: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - ac_prog_rejected=no - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - break - fi - done - IFS="$ac_save_ifs" -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# -gt 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - set dummy "$ac_dir/$ac_word" "$@" - shift - ac_cv_prog_CC="$@" - fi -fi -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } -fi - -echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:626: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then - ac_cv_prog_cc_works=yes - # If we can't run a trivial program, we are probably using a cross compiler. - if (./conftest; exit) 2>/dev/null; then - ac_cv_prog_cc_cross=no - else - ac_cv_prog_cc_cross=yes - fi -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_prog_cc_works=no -fi -rm -fr conftest* - -echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 -if test $ac_cv_prog_cc_works = no; then - { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } -fi -echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:660: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 -echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 -cross_compiling=$ac_cv_prog_cc_cross - -echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:665: checking whether we are using GNU C" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then - ac_cv_prog_gcc=yes -else - ac_cv_prog_gcc=no -fi -fi - -echo "$ac_t""$ac_cv_prog_gcc" 1>&6 - -if test $ac_cv_prog_gcc = yes; then - GCC=yes - ac_test_CFLAGS="${CFLAGS+set}" - ac_save_CFLAGS="$CFLAGS" - CFLAGS= - echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:689: checking whether ${CC-cc} accepts -g" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - echo 'void f(){}' > conftest.c -if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then - ac_cv_prog_cc_g=yes -else - ac_cv_prog_cc_g=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 - if test "$ac_test_CFLAGS" = set; then - CFLAGS="$ac_save_CFLAGS" - elif test $ac_cv_prog_cc_g = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-O2" - fi -else - GCC= - test "${CFLAGS+set}" = set || CFLAGS="-g" -fi - -case "x$GCC" in -xyes) - CFLAGS="-Wall $CFLAGS" - ;; -esac - -ac_aux_dir= -for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do - if test -f $ac_dir/install-sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f $ac_dir/install.sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - fi -done -if test -z "$ac_aux_dir"; then - { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } -fi -ac_config_guess=$ac_aux_dir/config.guess -ac_config_sub=$ac_aux_dir/config.sub -ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# ./install, which can be erroneously created by make from ./install.sh. -echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:752: checking for a BSD compatible install" >&5 -if test -z "$INSTALL"; then -if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - # Account for people who put trailing slashes in PATH elements. - case "$ac_dir/" in - /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - for ac_prog in ginstall installbsd scoinst install; do - if test -f $ac_dir/$ac_prog; then - if test $ac_prog = install && - grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - # OSF/1 installbsd also uses dspmsg, but is usable. - : - else - ac_cv_path_install="$ac_dir/$ac_prog -c" - break 2 - fi - fi - done - ;; - esac - done - IFS="$ac_save_IFS" - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL="$ac_cv_path_install" - else - # As a last resort, use the slow shell script. We don't cache a - # path for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the path is relative. - INSTALL="$ac_install_sh" - fi -fi -echo "$ac_t""$INSTALL" 1>&6 - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -for ac_prog in 'bison -y' byacc -do -# Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:806: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$YACC"; then - ac_cv_prog_YACC="$YACC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_YACC="$ac_prog" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -YACC="$ac_cv_prog_YACC" -if test -n "$YACC"; then - echo "$ac_t""$YACC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -test -n "$YACC" && break -done -test -n "$YACC" || YACC="yacc" - -for ac_prog in ln cp -do -# Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:840: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_LN'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$LN"; then - ac_cv_prog_LN="$LN" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_LN="$ac_prog" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -LN="$ac_cv_prog_LN" -if test -n "$LN"; then - echo "$ac_t""$LN" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -test -n "$LN" && break -done - - -echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:870: checking how to run the C preprocessor" >&5 -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then -if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - # This must be in double quotes, not single quotes, because CPP may get - # substituted into the Makefile and "${CC-cc}" will confuse make. - CPP="${CC-cc} -E" - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. - cat > conftest.$ac_ext < -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:891: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP="${CC-cc} -E -traditional-cpp" - cat > conftest.$ac_ext < -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:908: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP=/lib/cpp -fi -rm -f conftest* -fi -rm -f conftest* - ac_cv_prog_CPP="$CPP" -fi - CPP="$ac_cv_prog_CPP" -else - ac_cv_prog_CPP="$CPP" -fi -echo "$ac_t""$CPP" 1>&6 - -for ac_hdr in sys/resource.h sys/time.h sys/types.h unistd.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:934: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:944: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <&6 -fi -done - -ac_header_dirent=no -for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 -echo "configure:975: checking for $ac_hdr that defines DIR" >&5 -if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#include <$ac_hdr> -int main() { -DIR *dirp = 0; -; return 0; } -EOF -if { (eval echo configure:988: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - eval "ac_cv_header_dirent_$ac_safe=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_dirent_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <&6 -fi -done -# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. -if test $ac_header_dirent = dirent.h; then -echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 -echo "configure:1013: checking for opendir in -ldir" >&5 -ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldir $LIBS" -cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - LIBS="$LIBS -ldir" -else - echo "$ac_t""no" 1>&6 -fi - -else -echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 -echo "configure:1054: checking for opendir in -lx" >&5 -ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lx $LIBS" -cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - LIBS="$LIBS -lx" -else - echo "$ac_t""no" 1>&6 -fi - -fi - -echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:1096: checking for ANSI C header files" >&5 -if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#include -#include -#include -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1109: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - rm -rf conftest* - ac_cv_header_stdc=yes -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. -cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "memchr" >/dev/null 2>&1; then - : -else - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. -cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "free" >/dev/null 2>&1; then - : -else - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. -if test "$cross_compiling" = yes; then - : -else - cat > conftest.$ac_ext < -#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int main () { int i; for (i = 0; i < 256; i++) -if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); -exit (0); } - -EOF -if { (eval echo configure:1176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - : -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_header_stdc=no -fi -rm -fr conftest* -fi - -fi -fi - -echo "$ac_t""$ac_cv_header_stdc" 1>&6 -if test $ac_cv_header_stdc = yes; then - cat >> confdefs.h <<\EOF -#define STDC_HEADERS 1 -EOF - -fi - - -echo $ac_n "checking for signal names in ""... $ac_c" 1>&6 -echo "configure:1201: checking for signal names in " >&5 -if eval "test \"`echo '$''{'rc_cv_sys_signal_h'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if grep SIGINT /usr/include/sys/signal.h >/dev/null 2>&1; then - rc_cv_sys_signal_h=yes - else - rc_cv_sys_signal_h=no - fi -fi - -echo "$ac_t""$rc_cv_sys_signal_h" 1>&6 - -case "x$rc_cv_sys_signal_h" in -xyes) - SIGNAL_H=/usr/include/sys/signal.h - ;; -xno) - echo $ac_n "checking for signal names in ""... $ac_c" 1>&6 -echo "configure:1220: checking for signal names in " >&5 -if eval "test \"`echo '$''{'rc_cv_asm_signal_h'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if grep SIGINT /usr/include/asm/signal.h >/dev/null 2>&1; then - rc_cv_asm_signal_h=yes - else - rc_cv_asm_signal_h=no - fi -fi - -echo "$ac_t""$rc_cv_asm_signal_h" 1>&6 - - case "x$rc_cv_asm_signal_h" in - xyes) - SIGNAL_H=/usr/include/asm/signal.h - ;; - xno) - { echo "configure: error: Can't find signal names in or " 1>&2; exit 1; } - ;; - esac - ;; -esac - - -echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:1246: checking for uid_t in sys/types.h" >&5 -if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "uid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_uid_t=yes -else - rm -rf conftest* - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_type_uid_t" 1>&6 -if test $ac_cv_type_uid_t = no; then - cat >> confdefs.h <<\EOF -#define uid_t int -EOF - - cat >> confdefs.h <<\EOF -#define gid_t int -EOF - -fi - -echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 -echo "configure:1280: checking type of array argument to getgroups" >&5 -if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - ac_cv_type_getgroups=cross -else - cat > conftest.$ac_ext < -#define NGID 256 -#undef MAX -#define MAX(x, y) ((x) > (y) ? (x) : (y)) -main() -{ - gid_t gidset[NGID]; - int i, n; - union { gid_t gval; long lval; } val; - - val.lval = -1; - for (i = 0; i < NGID; i++) - gidset[i] = val.gval; - n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, - gidset); - /* Exit non-zero if getgroups seems to require an array of ints. This - happens when gid_t is short but getgroups modifies an array of ints. */ - exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); -} - -EOF -if { (eval echo configure:1313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_type_getgroups=gid_t -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_type_getgroups=int -fi -rm -fr conftest* -fi - -if test $ac_cv_type_getgroups = cross; then - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "getgroups.*int.*gid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_getgroups=gid_t -else - rm -rf conftest* - ac_cv_type_getgroups=int -fi -rm -f conftest* - -fi -fi - -echo "$ac_t""$ac_cv_type_getgroups" 1>&6 -cat >> confdefs.h <&6 -echo "configure:1351: checking for pid_t" >&5 -if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#if STDC_HEADERS -#include -#include -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_pid_t=yes -else - rm -rf conftest* - ac_cv_type_pid_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_pid_t" 1>&6 -if test $ac_cv_type_pid_t = no; then - cat >> confdefs.h <<\EOF -#define pid_t int -EOF - -fi - -echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:1384: checking for size_t" >&5 -if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#if STDC_HEADERS -#include -#include -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_size_t=yes -else - rm -rf conftest* - ac_cv_type_size_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_size_t" 1>&6 -if test $ac_cv_type_size_t = no; then - cat >> confdefs.h <<\EOF -#define size_t unsigned -EOF - -fi - -echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:1417: checking for uid_t in sys/types.h" >&5 -if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "uid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_uid_t=yes -else - rm -rf conftest* - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_type_uid_t" 1>&6 -if test $ac_cv_type_uid_t = no; then - cat >> confdefs.h <<\EOF -#define uid_t int -EOF - - cat >> confdefs.h <<\EOF -#define gid_t int -EOF - -fi - - -for ac_func in getgroups setpgrp setrlimit -do -echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1454: checking for $ac_func" >&5 -if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char $ac_func(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_$ac_func) || defined (__stub___$ac_func) -choke me -#else -$ac_func(); -#endif - -; return 0; } -EOF -if { (eval echo configure:1482: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then - rm -rf conftest* - eval "ac_cv_func_$ac_func=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func_$ac_func=no" -fi -rm -f conftest* -fi - -if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - cat >> confdefs.h <&6 -fi -done - - -echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 -echo "configure:1508: checking whether setpgrp takes no argument" >&5 -if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } -else - cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_func_setpgrp_void=no -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_func_setpgrp_void=yes -fi -rm -fr conftest* -fi - - -fi - -echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6 -if test $ac_cv_func_setpgrp_void = yes; then - cat >> confdefs.h <<\EOF -#define SETPGRP_VOID 1 -EOF - -fi - - -echo $ac_n "checking if _KERNEL is required for RLIMIT defines""... $ac_c" 1>&6 -echo "configure:1557: checking if _KERNEL is required for RLIMIT defines" >&5 -if eval "test \"`echo '$''{'rc_cv_kernel_rlimit'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#include - -int main() { - -int f; -f = RLIMIT_DATA; - -; return 0; } -EOF -if { (eval echo configure:1575: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - rc_cv_kernel_rlimit=no -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - cat > conftest.$ac_ext < -#define _KERNEL -#include -#undef _KERNEL - -int main() { - -int f; -f = RLIMIT_DATA; - -; return 0; } -EOF -if { (eval echo configure:1598: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - rc_cv_kernel_rlimit=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - rc_cv_kernel_rlimit=no -fi -rm -f conftest* -fi -rm -f conftest* -fi - -echo "$ac_t""$rc_cv_kernel_rlimit" 1>&6 -case "x$rc_cv_kernel_rlimit" in -xyes) - cat >> confdefs.h <<\EOF -#define RLIMIT_NEEDS_KERNEL 1 -EOF - - ;; -esac - -echo $ac_n "checking for rlim_t""... $ac_c" 1>&6 -echo "configure:1623: checking for rlim_t" >&5 -if eval "test \"`echo '$''{'rc_cv_have_rlim_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#if RLIMIT_NEEDS_KERNEL -#define _KERNEL -#endif -#include - -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "rlim_t" >/dev/null 2>&1; then - rm -rf conftest* - rc_cv_have_rlim_t=yes -else - rm -rf conftest* - rc_cv_have_rlim_t=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$rc_cv_have_rlim_t" 1>&6 - -case "x$rc_cv_have_rlim_t" in -xyes) - cat >> confdefs.h <<\EOF -#define HAVE_RLIM_T 1 -EOF - - ;; -xno) - echo $ac_n "checking for native quad_t""... $ac_c" 1>&6 -echo "configure:1661: checking for native quad_t" >&5 -if eval "test \"`echo '$''{'rc_cv_have_quad_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else - cat > conftest.$ac_ext < -main() { - quad_t q; - q = 0; - exit((int) q); -} - -EOF -if { (eval echo configure:1680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - rc_cv_have_quad_t=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - rc_cv_have_quad_t=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$rc_cv_have_quad_t" 1>&6 - - case "x$rc_cv_have_quad_t" in - xyes) - cat >> confdefs.h <<\EOF -#define HAVE_QUAD_T 1 -EOF - - - echo $ac_n "checking if rlimit values are quad_t""... $ac_c" 1>&6 -echo "configure:1704: checking if rlimit values are quad_t" >&5 -if eval "test \"`echo '$''{'rc_cv_rlim_t_is_quad_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - $ac_cv_type_quad_t -else - cat > conftest.$ac_ext < -#include -#include -#if RLIMIT_NEEDS_KERNEL -#define _KERNEL -#endif -#include -#if RLIMIT_NEEDS_KERNEL -#undef _KERNEL -#endif -main(){ - struct rlimit rl; - exit(sizeof rl.rlim_cur != sizeof(quad_t)); -} - -EOF -if { (eval echo configure:1731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - rc_cv_rlim_t_is_quad_t=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - rc_cv_rlim_t_is_quad_t=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$rc_cv_rlim_t_is_quad_t" 1>&6 - - case "x$rc_cv_rlim_t_is_quad_t" in - xyes) - cat >> confdefs.h <<\EOF -#define RLIM_T_IS_QUAD_T 1 -EOF - - ;; - esac - ;; - esac - ;; -esac - -echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6 -echo "configure:1761: checking for restartable system calls" >&5 -if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else - cat > conftest.$ac_ext < -#include -ucatch (isig) { } -main () { - int i = fork (), status; - if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } - signal (SIGINT, ucatch); - status = wait(&i); - if (status == -1) wait(&i); - exit (status == -1); -} - -EOF -if { (eval echo configure:1787: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_sys_restartable_syscalls=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_sys_restartable_syscalls=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$ac_cv_sys_restartable_syscalls" 1>&6 -if test $ac_cv_sys_restartable_syscalls = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_RESTARTABLE_SYSCALLS 1 -EOF - -fi - - -# Pull the hash mark out of the macro call to avoid m4 problems. -ac_msg="whether #! works in shell scripts" -echo $ac_n "checking $ac_msg""... $ac_c" 1>&6 -echo "configure:1813: checking $ac_msg" >&5 -if eval "test \"`echo '$''{'ac_cv_sys_interpreter'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - echo '#! /bin/cat -exit 69 -' > conftest -chmod u+x conftest -(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null) -if test $? -ne 69; then - ac_cv_sys_interpreter=yes -else - ac_cv_sys_interpreter=no -fi -rm -f conftest -fi - -echo "$ac_t""$ac_cv_sys_interpreter" 1>&6 - -case "x$ac_cv_sys_interpreter" in -xyes) - cat >> confdefs.h <<\EOF -#define HASH_BANG 1 -EOF - - EXECVE='' - ;; -xno) - EXECVE=execve.o -esac - - -echo $ac_n "checking for /dev/fd""... $ac_c" 1>&6 -echo "configure:1846: checking for /dev/fd" >&5 -if eval "test \"`echo '$''{'rc_cv_sys_dev_fd'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -d /dev/fd && test -r /dev/fd/0; then - rc_cv_sys_dev_fd=yes - elif test -d /proc/self/fd && test -r /proc/self/fd/0; then - rc_cv_sys_dev_fd=odd - else - rc_cv_sys_dev_fd=no - fi -fi - -echo "$ac_t""$rc_cv_sys_dev_fd" 1>&6 - -case "x$rc_cv_sys_dev_fd" in -xyes) - cat >> confdefs.h <<\EOF -#define HAVE_DEV_FD 1 -EOF - - ;; -xodd) - cat >> confdefs.h <<\EOF -#define HAVE_PROC_SELF_FD 1 -EOF - - ;; -xno) - echo $ac_n "checking for named pipes""... $ac_c" 1>&6 -echo "configure:1876: checking for named pipes" >&5 -if eval "test \"`echo '$''{'rc_cv_sys_fifo'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat >> confdefs.h < conftest.$ac_ext < -#include - -main() { - exit(mknod(TMPNAM, S_IFIFO | 0666, 0) != 0); -} - -EOF -if { (eval echo configure:1899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - rc_cv_sys_fifo=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - rc_cv_sys_fifo=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$rc_cv_sys_fifo" 1>&6 - case "x$rc_cv_sys_fifo" in - xyes) - cat >> confdefs.h <<\EOF -#define HAVE_FIFO 1 -EOF - - ;; - esac -esac - -# Check whether --enable-builtin-echo or --disable-builtin-echo was given. -if test "${enable_builtin_echo+set}" = set; then - enableval="$enable_builtin_echo" - test "x$enableval" != "xno" && cat >> confdefs.h <<\EOF -#define RC_ECHO 1 -EOF - -else - cat >> confdefs.h <<\EOF -#define RC_ECHO 1 -EOF - -fi - - -# Check whether --enable-job or --disable-job was given. -if test "${enable_job+set}" = set; then - enableval="$enable_job" - test "x$enableval" != "xno" && cat >> confdefs.h <<\EOF -#define RC_JOB 1 -EOF - -else - cat >> confdefs.h <<\EOF -#define RC_JOB 1 -EOF - -fi - - -# Check whether --enable-protect-env or --disable-protect-env was given. -if test "${enable_protect_env+set}" = set; then - enableval="$enable_protect_env" - test "x$enableval" != "xno" && cat >> confdefs.h <<\EOF -#define PROTECT_ENV 1 -EOF - -else - cat >> confdefs.h <<\EOF -#define PROTECT_ENV 1 -EOF - -fi - - -# Check whether --enable-def-interp or --disable-def-interp was given. -if test "${enable_def_interp+set}" = set; then - enableval="$enable_def_interp" - - case "x$enableval" in - xno) - ;; - xyes) - cat >> confdefs.h <<\EOF -#define DEFAULTINTERP "/bin/sh" -EOF - - ;; - *) - cat >> confdefs.h <> confdefs.h <<\EOF -#define DEFAULTINTERP "/bin/sh" -EOF - -fi - - -# Check whether --enable-def-path or --disable-def-path was given. -if test "${enable_def_path+set}" = set; then - enableval="$enable_def_path" - - case "x$enableval" in - xno|xyes) - ;; - *) - cat >> confdefs.h <&6 -echo "configure:2019: checking extant directories for default path" >&5 -if eval "test \"`echo '$''{'rc_cv_def_path'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - - rc_cv_def_path='' - for i in /usr/local/bin /usr/bin /usr/ucb /bin .; do - if test -d $i; then - case "x$rc_cv_def_path" in - x) - rc_cv_def_path=\"$i\" - ;; - *) - rc_cv_def_path=$rc_cv_def_path,\"$i\" - ;; - esac - fi - done - cat >> confdefs.h <&6 - ;; -esac - -# Check whether --enable-history or --disable-history was given. -if test "${enable_history+set}" = set; then - enableval="$enable_history" - test "x$enableval" != "xno" && rc_history=yes -else - rc_history=no -fi - -case "x$rc_history" in -xyes) - HISTORY=history/history - ;; -esac - - -# Check whether --with-addon or --without-addon was given. -if test "${with_addon+set}" = set; then - withval="$with_addon" - - case "x$withval" in - xyes) - ADDON=addon.o - ;; - xno) - ADDON='' - ;; - *) - ADDON=$withval - ;; - esac - -fi - - - -# Check whether --with-editline or --without-editline was given. -if test "${with_editline+set}" = set; then - withval="$with_editline" - echo $ac_n "checking for readline in -ledit""... $ac_c" 1>&6 -echo "configure:2087: checking for readline in -ledit" >&5 -ac_lib_var=`echo edit'_'readline | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ledit $LIBS" -cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - cat >> confdefs.h <<\EOF -#define READLINE 1 -EOF - LIBS="$LIBS -ledit" -else - echo "$ac_t""no" 1>&6 -echo "configure: warning: editline library not found" 1>&2 -fi - -fi - - -# Check whether --with-readline or --without-readline was given. -if test "${with_readline+set}" = set; then - withval="$with_readline" - echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 -echo "configure:2137: checking for readline in -lreadline" >&5 -ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lreadline $LIBS" -cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - cat >> confdefs.h <<\EOF -#define READLINE 1 -EOF - LIBS="$LIBS -lreadline -ltermcap" -else - echo "$ac_t""no" 1>&6 -echo "configure: warning: readline library not found" 1>&2 -fi - -fi - - -trap '' 1 2 15 -cat > confcache <<\EOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs. It is not useful on other systems. -# If it contains results you don't want to keep, you may remove or edit it. -# -# By default, configure uses ./config.cache as the cache file, -# creating it if it does not exist already. You can give configure -# the --cache-file=FILE option to use a different cache file; that is -# what configure does when it calls configure scripts in -# subdirectories, so they share the cache. -# Giving --cache-file=/dev/null disables caching, for debugging configure. -# config.status only pays attention to the cache file if you give it the -# --recheck option to rerun configure. -# -EOF -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, don't put newlines in cache variables' values. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -(set) 2>&1 | - case `(ac_space=' '; set) 2>&1` in - *ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote substitution - # turns \\\\ into \\, and sed turns \\ into \). - sed -n \ - -e "s/'/'\\\\''/g" \ - -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" - ;; - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' - ;; - esac >> confcache -if cmp -s $cache_file confcache; then - : -else - if test -w $cache_file; then - echo "updating cache $cache_file" - cat confcache > $cache_file - else - echo "not updating unwritable cache $cache_file" - fi -fi -rm -f confcache - -trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Any assignment to VPATH causes Sun make to only execute -# the first set of double-colon rules, so remove it if not needed. -# If there is a colon in the path, we need to keep it. -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' -fi - -trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 - -DEFS=-DHAVE_CONFIG_H - -# Without the "./", some shells look in PATH for config.status. -: ${CONFIG_STATUS=./config.status} - -echo creating $CONFIG_STATUS -rm -f $CONFIG_STATUS -cat > $CONFIG_STATUS </dev/null | sed 1q`: -# -# $0 $ac_configure_args -# -# Compiler output produced by configure, useful for debugging -# configure, is in ./config.log if it exists. - -ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" -for ac_option -do - case "\$ac_option" in - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" - exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; - -version | --version | --versio | --versi | --vers | --ver | --ve | --v) - echo "$CONFIG_STATUS generated by autoconf version 2.12" - exit 0 ;; - -help | --help | --hel | --he | --h) - echo "\$ac_cs_usage"; exit 0 ;; - *) echo "\$ac_cs_usage"; exit 1 ;; - esac -done - -ac_given_srcdir=$srcdir -ac_given_INSTALL="$INSTALL" - -trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 -EOF -cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF -$ac_vpsub -$extrasub -s%@CFLAGS@%$CFLAGS%g -s%@CPPFLAGS@%$CPPFLAGS%g -s%@CXXFLAGS@%$CXXFLAGS%g -s%@DEFS@%$DEFS%g -s%@LDFLAGS@%$LDFLAGS%g -s%@LIBS@%$LIBS%g -s%@exec_prefix@%$exec_prefix%g -s%@prefix@%$prefix%g -s%@program_transform_name@%$program_transform_name%g -s%@bindir@%$bindir%g -s%@sbindir@%$sbindir%g -s%@libexecdir@%$libexecdir%g -s%@datadir@%$datadir%g -s%@sysconfdir@%$sysconfdir%g -s%@sharedstatedir@%$sharedstatedir%g -s%@localstatedir@%$localstatedir%g -s%@libdir@%$libdir%g -s%@includedir@%$includedir%g -s%@oldincludedir@%$oldincludedir%g -s%@infodir@%$infodir%g -s%@mandir@%$mandir%g -s%@CC@%$CC%g -s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g -s%@INSTALL_DATA@%$INSTALL_DATA%g -s%@YACC@%$YACC%g -s%@LN@%$LN%g -s%@CPP@%$CPP%g -s%@SIGNAL_H@%$SIGNAL_H%g -s%@EXECVE@%$EXECVE%g -s%@HISTORY@%$HISTORY%g -s%@ADDON@%$ADDON%g - -CEOF -EOF - -cat >> $CONFIG_STATUS <<\EOF - -# Split the substitutions into bite-sized pieces for seds with -# small command number limits, like on Digital OSF/1 and HP-UX. -ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. -ac_file=1 # Number of current file. -ac_beg=1 # First line for current file. -ac_end=$ac_max_sed_cmds # Line after last line for current file. -ac_more_lines=: -ac_sed_cmds="" -while $ac_more_lines; do - if test $ac_beg -gt 1; then - sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file - else - sed "${ac_end}q" conftest.subs > conftest.s$ac_file - fi - if test ! -s conftest.s$ac_file; then - ac_more_lines=false - rm -f conftest.s$ac_file - else - if test -z "$ac_sed_cmds"; then - ac_sed_cmds="sed -f conftest.s$ac_file" - else - ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" - fi - ac_file=`expr $ac_file + 1` - ac_beg=$ac_end - ac_end=`expr $ac_end + $ac_max_sed_cmds` - fi -done -if test -z "$ac_sed_cmds"; then - ac_sed_cmds=cat -fi -EOF - -cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF -for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. - - # Remove last slash and all that follows it. Not all systems have dirname. - ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` - if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then - # The file is in a subdirectory. - test ! -d "$ac_dir" && mkdir "$ac_dir" - ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" - # A "../" for each directory in $ac_dir_suffix. - ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` - else - ac_dir_suffix= ac_dots= - fi - - case "$ac_given_srcdir" in - .) srcdir=. - if test -z "$ac_dots"; then top_srcdir=. - else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; - /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; - *) # Relative path. - srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" - top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - - case "$ac_given_INSTALL" in - [/$]*) INSTALL="$ac_given_INSTALL" ;; - *) INSTALL="$ac_dots$ac_given_INSTALL" ;; - esac - - echo creating "$ac_file" - rm -f "$ac_file" - configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." - case "$ac_file" in - *Makefile*) ac_comsub="1i\\ -# $configure_input" ;; - *) ac_comsub= ;; - esac - - ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` - sed -e "$ac_comsub -s%@configure_input@%$configure_input%g -s%@srcdir@%$srcdir%g -s%@top_srcdir@%$top_srcdir%g -s%@INSTALL@%$INSTALL%g -" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file -fi; done -rm -f conftest.s* - -# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where -# NAME is the cpp macro being defined and VALUE is the value it is being given. -# -# ac_d sets the value in "#define NAME VALUE" lines. -ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' -ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' -ac_dC='\3' -ac_dD='%g' -# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". -ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_uB='\([ ]\)%\1#\2define\3' -ac_uC=' ' -ac_uD='\4%g' -# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". -ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_eB='$%\1#\2define\3' -ac_eC=' ' -ac_eD='%g' - -if test "${CONFIG_HEADERS+set}" != set; then -EOF -cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF -fi -for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - echo creating $ac_file - - rm -f conftest.frag conftest.in conftest.out - ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` - cat $ac_file_inputs > conftest.in - -EOF - -# Transform confdefs.h into a sed script conftest.vals that substitutes -# the proper values into config.h.in to produce config.h. And first: -# Protect against being on the right side of a sed subst in config.status. -# Protect against being in an unquoted here document in config.status. -rm -f conftest.vals -cat > conftest.hdr <<\EOF -s/[\\&%]/\\&/g -s%[\\$`]%\\&%g -s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp -s%ac_d%ac_u%gp -s%ac_u%ac_e%gp -EOF -sed -n -f conftest.hdr confdefs.h > conftest.vals -rm -f conftest.hdr - -# This sed command replaces #undef with comments. This is necessary, for -# example, in the case of _POSIX_SOURCE, which is predefined and required -# on some systems where configure will not decide to define it. -cat >> conftest.vals <<\EOF -s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% -EOF - -# Break up conftest.vals because some shells have a limit on -# the size of here documents, and old seds have small limits too. - -rm -f conftest.tail -while : -do - ac_lines=`grep -c . conftest.vals` - # grep -c gives empty output for an empty file on some AIX systems. - if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi - # Write a limited-size here document to conftest.frag. - echo ' cat > conftest.frag <> $CONFIG_STATUS - sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS - echo 'CEOF - sed -f conftest.frag conftest.in > conftest.out - rm -f conftest.in - mv conftest.out conftest.in -' >> $CONFIG_STATUS - sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail - rm -f conftest.vals - mv conftest.tail conftest.vals -done -rm -f conftest.vals - -cat >> $CONFIG_STATUS <<\EOF - rm -f conftest.frag conftest.h - echo "/* $ac_file. Generated automatically by configure. */" > conftest.h - cat conftest.in >> conftest.h - rm -f conftest.in - if cmp -s $ac_file conftest.h 2>/dev/null; then - echo "$ac_file is unchanged" - rm -f conftest.h - else - # Remove last slash and all that follows it. Not all systems have dirname. - ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` - if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then - # The file is in a subdirectory. - test ! -d "$ac_dir" && mkdir "$ac_dir" - fi - rm -f $ac_file - mv conftest.h $ac_file - fi -fi; done - -EOF -cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF - -exit 0 -EOF -chmod +x $CONFIG_STATUS -rm -fr confdefs* $ac_clean_files -test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 - diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..dd460aa --- /dev/null +++ b/configure.ac @@ -0,0 +1,200 @@ +dnl Get things going... +AC_INIT(rc.h) + +RELDATE=`cat $srcdir/RELDATE` +AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE") + +dnl Automake stuff. +dnl Use this one for snapshots... +dnl AM_INIT_AUTOMAKE(rc, 1.5s`echo $RELDATE |sed 's/-//g'`) +dnl ...and this one for releases +AM_INIT_AUTOMAKE(rc, 1.5b4) + +AM_CONFIG_HEADER(config.h) + +dnl Anybody using name transformations? +AC_ARG_PROGRAM + +dnl Find a standard C compiler +AC_PROG_CC +AM_PROG_CC_STDC + +dnl If we're using gcc, specify `-Wall'. I've also checked the code +dnl with `-pedantic -W -Wall -Wpointer-arith -Wstrict-prototypes +dnl -Wmissing-prototypes', and checked that all the warnings generated +dnl are harmless. +case "$GCC" in +yes) CFLAGS="-Wall $CFLAGS" ;; +esac + +AC_PROG_CPP +AC_PROG_INSTALL +AC_CHECK_PROGS(LN, ln cp) + +AC_CHECK_HEADERS(sys/resource.h sys/time.h sys/types.h unistd.h) +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT + +AC_TYPE_GETGROUPS +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UID_T +AC_CHECK_TYPE(ssize_t, long) + +AC_CHECK_FUNCS(getgroups setpgrp setrlimit) +RC_FUNC_GETGROUPS + +RC_FUNC_SIGSETJMP + +AC_FUNC_SETPGRP + +RC_NEED_KERNEL + +RC_TYPE_RLIM_T + +RC_TYPE_SIG_ATOMIC_T + +dnl We prefer system calls that don't restart. If we have sigaction() and +dnl SA_INTERRUPT, we'll use 'em. Otherwise, we check whether +dnl good ol' signal() produces interruptible system calls. +RC_FUNC_SIGACTION +case "$rc_cv_sa_int" in +yes) AC_DEFINE(HAVE_SA_INTERRUPT) ;; +no) AC_SYS_RESTARTABLE_SYSCALLS ;; +esac +AM_CONDITIONAL(AMC_RESTART, test "$ac_cv_sys_restartable_syscalls" = yes) + +RC_SYS_V_SIGCLD + +dnl Does the kernel handle `#! /interpreter'? +AC_SYS_INTERPRETER +case "$ac_cv_sys_interpreter" in +yes) AC_DEFINE(HASH_BANG) ;; +esac +AM_CONDITIONAL(AMC_NO_HASHBANG, test "$ac_cv_sys_interpreter" = no) + + +dnl What do we do for command arguments? We want /dev/fd or Linux's +dnl /proc/self/fd. Failing that, we'll try for POSIX mkfifo(), or a +dnl mknod() that makes FIFOs. +RC_SYS_DEV_FD +case "$rc_cv_sys_dev_fd" in +yes) AC_DEFINE(HAVE_DEV_FD) ;; +odd) AC_DEFINE(HAVE_PROC_SELF_FD) ;; +no) AC_CHECK_FUNCS(mkfifo) ;; +esac + +case "$ac_cv_func_mkfifo" in +yes) AC_DEFINE(HAVE_FIFO) ;; +no) RC_SYS_MKNOD_FIFO ;; +esac + +RC_HAVE_VA_COPY + +dnl Now handle arguments. +AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], + test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO), + AC_DEFINE(RC_ECHO)) + +AC_ARG_ENABLE(job, [ --disable-job Don't do job-control-style backgrounding], + test "x$enableval" != "xno" && AC_DEFINE(RC_JOB), + AC_DEFINE(RC_JOB)) + +AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment names], + test "x$enableval" != "xno" && AC_DEFINE(PROTECT_ENV), + AC_DEFINE(PROTECT_ENV)) + +AC_ARG_ENABLE(def-interp, +[ --enable-def-interp=/bin/foo + Use /bin/foo as default interpreter [/bin/sh]], +[ + case "$enableval" in + no) + ;; + yes) + AC_DEFINE(DEFAULTINTERP, "/bin/sh") + ;; + *) + AC_DEFINE_UNQUOTED(DEFAULTINTERP, "$enableval") + esac +], + AC_DEFINE(DEFAULTINTERP, "/bin/sh")) + +AC_ARG_ENABLE(def-path, +[ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" + Default path [All of these that exist + (/usr/local/bin /usr/bin /usr/ucb /bin .)]], +[ + case "$enableval" in + no|yes) ;; + *) AC_DEFINE_UNQUOTED(DEFAULTPATH, $enableval) ;; + esac +], + enable_def_path=yes) + +case "$enable_def_path" in +yes) AC_CACHE_CHECK(extant directories for default path, rc_cv_def_path,[ + rc_cv_def_path='' + for i in /usr/local/bin /usr/bin /usr/ucb /bin .; do + if test -d $i; then + case "$rc_cv_def_path" in + '') rc_cv_def_path=\"$i\" ;; + *) rc_cv_def_path=$rc_cv_def_path,\"$i\" ;; + esac + fi + done + ]) + AC_DEFINE_UNQUOTED(DEFAULTPATH, $rc_cv_def_path) + ;; +esac + +AC_ARG_WITH(history, + [ --with-history Build history subprograms],[ + case "$withval" in + yes) rc_history=yes ;; + *) rc_history=no ;; + esac + ], rc_history=no) +AM_CONDITIONAL(AMC_HISTORY, test "$rc_history" = yes) + + +AC_ARG_WITH(addon, [ --with-addon[=foo.c] Extra builtins, from addon.c by default ],[ + case "$withval" in + yes) ADDON=addon.o ;; + no) ADDON='' ;; + *) ADDON=`echo $withval |sed 's/\.c$/\.o/'` ;; + esac +]) +AM_CONDITIONAL(AMC_ADDON, test "$ADDON" != "") +case "$ADDON" in +?*) AC_DEFINE(RC_ADDON) ;; +esac +AC_SUBST(ADDON) + + +AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], + AC_CHECK_LIB(edit, readline, + AC_DEFINE(EDITLINE) LIBS="$LIBS -ledit", + AC_MSG_ERROR(editline library not found))) + +AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing], + AC_CHECK_LIB(vrl, readline, + AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl -ltermcap", + AC_MSG_ERROR(vrl library not found), -ltermcap)) + +dnl There are (at least) two incompatible versions of readline, and we +dnl need to know which one we are using. We don't support readline 2.0. +AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ + AC_CHECK_LIB(readline, readline, [ + AC_DEFINE(READLINE) + LIBS="$LIBS -lreadline -ltermcap" + AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD), -ltermcap) + ], AC_MSG_ERROR(readline library not found), -ltermcap) +]) +AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) + +dnl For some reason CPPFLAGS doesn't get propagated. +AC_SUBST(CPPFLAGS) + +AC_OUTPUT(Makefile) diff --git a/configure.in b/configure.in deleted file mode 100644 index 86a97bb..0000000 --- a/configure.in +++ /dev/null @@ -1,287 +0,0 @@ -AC_INIT(rc.h) - -AC_CONFIG_HEADER(config.h) - -AC_PROG_CC -case "x$GCC" in -xyes) - CFLAGS="-Wall $CFLAGS" - ;; -esac - -AC_PROG_INSTALL -AC_PROG_YACC -AC_CHECK_PROGS(LN, ln cp) - -AC_CHECK_HEADERS(sys/resource.h sys/time.h sys/types.h unistd.h) -AC_HEADER_DIRENT -AC_HEADER_STDC - -dnl Linux puts real signal names in /usr/include/asm/signal.h. -AC_CACHE_CHECK(for signal names in , rc_cv_sys_signal_h, - if grep SIGINT /usr/include/sys/signal.h >/dev/null 2>&1; then - rc_cv_sys_signal_h=yes - else - rc_cv_sys_signal_h=no - fi) - -case "x$rc_cv_sys_signal_h" in -xyes) - SIGNAL_H=/usr/include/sys/signal.h - ;; -xno) - AC_CACHE_CHECK(for signal names in , rc_cv_asm_signal_h, - if grep SIGINT /usr/include/asm/signal.h >/dev/null 2>&1; then - rc_cv_asm_signal_h=yes - else - rc_cv_asm_signal_h=no - fi) - - case "x$rc_cv_asm_signal_h" in - xyes) - SIGNAL_H=/usr/include/asm/signal.h - ;; - xno) - AC_MSG_ERROR(Can't find signal names in or ) - ;; - esac - ;; -esac -AC_SUBST(SIGNAL_H) - -AC_TYPE_GETGROUPS -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_TYPE_UID_T - -AC_CHECK_FUNCS(getgroups setpgrp setrlimit) - -AC_FUNC_SETPGRP - -dnl HPUX needs _KERNEL defined to pick up RLIMIT_foo defines. (Why?) -AC_CACHE_CHECK(if _KERNEL is required for RLIMIT defines, rc_cv_kernel_rlimit, - AC_TRY_COMPILE([ -#include -#include - ], [ -int f; -f = RLIMIT_DATA; - ], rc_cv_kernel_rlimit=no, [ AC_TRY_COMPILE([ -#include -#define _KERNEL -#include -#undef _KERNEL - ], [ -int f; -f = RLIMIT_DATA; - ], rc_cv_kernel_rlimit=yes, rc_cv_kernel_rlimit=no)])) -case "x$rc_cv_kernel_rlimit" in -xyes) - AC_DEFINE(RLIMIT_NEEDS_KERNEL) - ;; -esac - -dnl Look for rlim_t in sys/types.h and sys/resource.h -AC_CACHE_CHECK(for rlim_t, rc_cv_have_rlim_t, - AC_EGREP_CPP(rlim_t, [ -#include -#if RLIMIT_NEEDS_KERNEL -#define _KERNEL -#endif -#include - ], rc_cv_have_rlim_t=yes, rc_cv_have_rlim_t=no)) - -case "x$rc_cv_have_rlim_t" in -xyes) - AC_DEFINE(HAVE_RLIM_T) - ;; -xno) - AC_CACHE_CHECK(for native quad_t, rc_cv_have_quad_t, - AC_TRY_RUN([ -#include -main() { - quad_t q; - q = 0; - exit((int) q); -} - ], rc_cv_have_quad_t=yes, rc_cv_have_quad_t=no)) - - case "x$rc_cv_have_quad_t" in - xyes) - AC_DEFINE(HAVE_QUAD_T) - - AC_CACHE_CHECK(if rlimit values are quad_t, rc_cv_rlim_t_is_quad_t, - AC_TRY_RUN([ -#include -#include -#include -#if RLIMIT_NEEDS_KERNEL -#define _KERNEL -#endif -#include -#if RLIMIT_NEEDS_KERNEL -#undef _KERNEL -#endif -main(){ - struct rlimit rl; - exit(sizeof rl.rlim_cur != sizeof(quad_t)); -} - ], rc_cv_rlim_t_is_quad_t=yes, rc_cv_rlim_t_is_quad_t=no, $ac_cv_type_quad_t)) - - case "x$rc_cv_rlim_t_is_quad_t" in - xyes) - AC_DEFINE(RLIM_T_IS_QUAD_T) - ;; - esac - ;; - esac - ;; -esac - -AC_SYS_RESTARTABLE_SYSCALLS - -dnl Does the kernel handle `#! /interpreter'? -AC_SYS_INTERPRETER -case "x$ac_cv_sys_interpreter" in -xyes) - AC_DEFINE(HASH_BANG) - EXECVE='' - ;; -xno) - EXECVE=execve.o -esac -AC_SUBST(EXECVE) - -AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd, - if test -d /dev/fd && test -r /dev/fd/0; then - rc_cv_sys_dev_fd=yes - elif test -d /proc/self/fd && test -r /proc/self/fd/0; then - rc_cv_sys_dev_fd=odd - else - rc_cv_sys_dev_fd=no - fi) - -case "x$rc_cv_sys_dev_fd" in -xyes) - AC_DEFINE(HAVE_DEV_FD) - ;; -xodd) - AC_DEFINE(HAVE_PROC_SELF_FD) - ;; -xno) - AC_CACHE_CHECK(for named pipes, rc_cv_sys_fifo, - AC_DEFINE_UNQUOTED(TMPNAM, "/tmp/rc$$.0") - AC_TRY_RUN([ -#include -#include - -main() { - exit(mknod(TMPNAM, S_IFIFO | 0666, 0) != 0); -} - ], rc_cv_sys_fifo=yes, rc_cv_sys_fifo=no, rc_cv_sys_fifo=no)) - case "x$rc_cv_sys_fifo" in - xyes) - AC_DEFINE(HAVE_FIFO) - ;; - esac -esac - -AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], - test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO), - AC_DEFINE(RC_ECHO)) - -AC_ARG_ENABLE(job, [ --disable-job Don't do job-control-style backgrounding], - test "x$enableval" != "xno" && AC_DEFINE(RC_JOB), - AC_DEFINE(RC_JOB)) - -AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment names], - test "x$enableval" != "xno" && AC_DEFINE(PROTECT_ENV), - AC_DEFINE(PROTECT_ENV)) - -AC_ARG_ENABLE(def-interp, -[ --enable-def-interp=/bin/foo - Use /bin/foo as default interpreter [/bin/sh]], -[ - case "x$enableval" in - xno) - ;; - xyes) - AC_DEFINE(DEFAULTINTERP, "/bin/sh") - ;; - *) - AC_DEFINE_UNQUOTED(DEFAULTINTERP, "$enableval") - esac -], - AC_DEFINE(DEFAULTINTERP, "/bin/sh")) - -AC_ARG_ENABLE(def-path, -[ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" - Default path [All of these that exist - (/usr/local/bin /usr/bin /usr/ucb /bin .)]], -[ - case "x$enableval" in - xno|xyes) - ;; - *) - AC_DEFINE_UNQUOTED(DEFAULTPATH, $enableval) - esac -], - enable_def_path=yes) - -case "x$enable_def_path" in -xyes) - AC_CACHE_CHECK(extant directories for default path, rc_cv_def_path,[ - rc_cv_def_path='' - for i in /usr/local/bin /usr/bin /usr/ucb /bin .; do - if test -d $i; then - case "x$rc_cv_def_path" in - x) - rc_cv_def_path=\"$i\" - ;; - *) - rc_cv_def_path=$rc_cv_def_path,\"$i\" - ;; - esac - fi - done - AC_DEFINE_UNQUOTED(DEFAULTPATH, $rc_cv_def_path) - ]) - ;; -esac - -AC_ARG_ENABLE(history, [ --enable-history Build history subprograms], - test "x$enableval" != "xno" && rc_history=yes, - rc_history=no) -case "x$rc_history" in -xyes) - HISTORY=history/history - ;; -esac -AC_SUBST(HISTORY) - -AC_ARG_WITH(addon, [ --with-addon Extra builtins, from addon.c ],[ - case "x$withval" in - xyes) - ADDON=addon.o - ;; - xno) - ADDON='' - ;; - *) - ADDON=$withval - ;; - esac - ]) -AC_SUBST(ADDON) - -AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], - AC_CHECK_LIB(edit, readline, - AC_DEFINE(READLINE) LIBS="$LIBS -ledit", - AC_MSG_WARN(editline library not found))) - -AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], - AC_CHECK_LIB(readline, readline, - AC_DEFINE(READLINE) LIBS="$LIBS -lreadline -ltermcap", - AC_MSG_WARN(readline library not found))) - -AC_OUTPUT(Makefile) diff --git a/cpp b/cpp deleted file mode 100644 index e3ac656..0000000 --- a/cpp +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# @(#) cpp.sh 1.3 92/01/15 21:53:22 - -# Unprototypeing preprocessor for pre-ANSI C compilers. On some systems, -# this script can be as simple as: -# -# /lib/cpp "$@" | unproto -# -# However, some cc(1) drivers specify output file names on the -# preprocessor command line, so this shell script must be prepared to -# intercept them. Depending on the driver program, the cpp options may -# even go before or after the file name argument(s). The script below -# tries to tackle all these cases. -# -# You may want to add -Ipath_to_stdarg.h_file, -Dvoid=, -Dvolatile=, -# and even -D__STDC__. - -## (This is what I used while testing with the SunOS C compiler. -## Also, I added "-Qpath ." to CFLAGS so that cpp would be -## run out of the current directory. --- Byron) -cpp_args="-I/u/byron/lib/sun4 -Dconst= -Dvolatile=" - -while : -do - case $1 in - "") break;; - -*) cpp_args="$cpp_args $1";; - *) cpp_args="$cpp_args $1" - case $2 in - ""|-*) ;; - *) exec 1> $2 || exit 1; shift;; - esac;; - esac - shift -done - -/lib/cpp $cpp_args | unproto diff --git a/except.c b/except.c index 241d887..af30e71 100644 --- a/except.c +++ b/except.c @@ -91,7 +91,7 @@ extern void rc_raise(ecodes e) { interactive = estack->interactive; estack = estack->prev; - longjmp(j->j, 1); + siglongjmp(j->j, 1); } } rc_exit(1); /* top of exception stack */ @@ -120,7 +120,7 @@ extern void pop_cmdarg(bool remove) { /* exception handlers */ extern void rc_error(char *s) { - pr_error(s); + pr_error(s, -1); set(FALSE); redirq = NULL; cond = FALSE; /* no longer inside conditional */ diff --git a/exec.c b/exec.c index 6a0082e..a0ba8d4 100644 --- a/exec.c +++ b/exec.c @@ -1,10 +1,9 @@ /* exec.c */ -#include #include -#include -#include "rc.h" -#include "jbwrap.h" +#include +#include "rc.h" +#include "wait.h" /* Takes an argument list and does the appropriate thing (calls a builtin, calls a function, etc.) @@ -92,11 +91,7 @@ extern void exec(List *s, bool parent) { return; rc_exit(getstatus()); } -#if HASH_BANG - execve(path, (char * const *) av, (char * const *) ev); -#else - my_execve(path, (char * const *) av, (char * const *) ev); /* bogus, huh? */ -#endif + rc_execve(path, (char * const *) av, (char * const *) ev); #ifdef DEFAULTINTERP if (errno == ENOEXEC) { @@ -105,6 +100,7 @@ extern void exec(List *s, bool parent) { execve(*av, (char * const *) av, (char * const *) ev); } #endif + uerror(*av); rc_exit(1); /* NOTREACHED */ @@ -123,7 +119,7 @@ extern void exec(List *s, bool parent) { prompt, even though there's a SIGINT in its signal vector. */ - if ((stat & 0xff) == 0) + if (WIFEXITED(stat)) nl_on_intr = FALSE; sigchk(); nl_on_intr = TRUE; diff --git a/execve.c b/execve.c index b21b30c..3fb5cc1 100644 --- a/execve.c +++ b/execve.c @@ -1,8 +1,8 @@ /* execve.c: an execve() for geriatric unices without #! */ /* - NOTE: this file depends on a hack in footobar.c which places two free spots before - av[][] so that execve does not have to call malloc. + NOTE: this file depends on a hack in footobar.c which places two free + spots before av[][] so that execve does not have to call malloc. */ #include @@ -10,7 +10,7 @@ #define giveupif(x) { if (x) goto fail; } -extern int my_execve(const char *path, const char **av, const char **ev) { +extern int rc_execve(char *path, char **av, char **ev) { int fd, len, fst, snd, end; bool noarg; char pb[256]; /* arbitrary but generous limit */ diff --git a/fn.c b/fn.c index 053ed89..e82e832 100644 --- a/fn.c +++ b/fn.c @@ -26,7 +26,7 @@ extern void inithandler() { null.type = nBody; null.u[0].p = null.u[1].p = NULL; for (i = 1; i < NUMOFSIGNALS; i++) -#ifndef HAVE_RESTARTABLE_SYSCALLS +#if HAVE_SYSV_SIGCLD if (i != SIGCLD) #endif if (sighandlers[i] == SIG_IGN) @@ -133,7 +133,7 @@ static void fn_handler(int s) { /* A dud signal handler for SIGQUIT and SIGTERM */ -static void dud_handler(int s) { +static void dud_handler(int ignore) { } /* @@ -143,12 +143,12 @@ static void dud_handler(int s) { extern void fnassign(char *name, Node *def) { Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */ - Function *new = get_fn_place(name); + rc_Function *new = get_fn_place(name); int i; new->def = newdef; new->extdef = NULL; if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */ -#ifndef HAVE_RESTARTABLE_SYSCALLS /* System V machines treat SIGCLD very specially */ +#if HAVE_SYSV_SIGCLD /* System V machines treat SIGCLD very specially */ if (streq(name, "sigcld")) rc_error("can't trap SIGCLD"); #endif @@ -170,7 +170,7 @@ extern void fnassign(char *name, Node *def) { extern void fnassign_string(char *extdef) { char *name = get_name(extdef+3); /* +3 to skip over "fn_" */ - Function *new; + rc_Function *new; if (name == NULL) return; new = get_fn_place(name); @@ -181,7 +181,7 @@ extern void fnassign_string(char *extdef) { /* Return a function in Node form, evaluating an entry from the environment if necessary */ extern Node *fnlookup(char *name) { - Function *look = lookup_fn(name); + rc_Function *look = lookup_fn(name); Node *ret; if (look == NULL) return NULL; /* not found */ @@ -189,7 +189,7 @@ extern Node *fnlookup(char *name) { return look->def; if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */ return &null; - ret = parse_fn(name, look->extdef); + ret = parse_fn(look->extdef); if (ret == NULL) { efree(look->extdef); look->extdef = NULL; @@ -202,7 +202,7 @@ extern Node *fnlookup(char *name) { /* Return a function in string form (used by makeenv) */ extern char *fnlookup_string(char *name) { - Function *look = lookup_fn(name); + rc_Function *look = lookup_fn(name); if (look == NULL) return NULL; @@ -243,13 +243,14 @@ extern void fnrm(char *name) { extern void whatare_all_signals() { int i; for (i = 1; i < NUMOFSIGNALS; i++) - if (*signals[i].name != '\0') + if (*signals[i].name != '\0') { if (sighandlers[i] == SIG_IGN) fprint(1, "fn %s {}\n", signals[i].name); else if (sighandlers[i] == fn_handler) fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]); else fprint(1, "fn %s\n", signals[i].name); + } } extern void prettyprint_fn(int fd, char *name, Node *n) { diff --git a/footobar.c b/footobar.c index 27955ba..43a44d9 100644 --- a/footobar.c +++ b/footobar.c @@ -39,7 +39,7 @@ static bool Dconv(Format *f, int ignore) { /* defaultfd -- return the default fd for a given redirection operation */ -extern int defaultfd(int op) { +static int defaultfd(int op) { return (op == rCreate || op == rAppend) ? 1 : 0; } @@ -221,7 +221,7 @@ extern char *get_name(char *s) { #define skipleft(p) do --p; while (*p != '\0' && *p != '\001'); -extern List *parse_var(char *name, char *extdef) { +extern List *parse_var(char *extdef) { char *endp, *realend, *sepp; List *tailp, *new; @@ -257,7 +257,7 @@ extern List *parse_var(char *name, char *extdef) { #define PREFIX "fn x" #define PRELEN conststrlen(PREFIX) -extern Node *parse_fn(char *name, char *extdef) { +extern Node *parse_fn(char *extdef) { Node *def; char *s, old[PRELEN]; if ((s = strchr(extdef, '=')) == NULL) @@ -269,7 +269,7 @@ extern Node *parse_fn(char *name, char *extdef) { return (def == NULL || def->type != nNewfn) ? NULL : def->u[1].p; } -static bool Aconv(Format *f, int c) { +static bool Aconv(Format *f, int ignore) { char **a = va_arg(f->args, char **); if (*a != NULL) { fmtcat(f, *a); @@ -279,7 +279,7 @@ static bool Aconv(Format *f, int c) { return FALSE; } -static bool Lconv(Format *f, int c) { +static bool Lconv(Format *f, int ignore) { List *l = va_arg(f->args, List *); char *sep = va_arg(f->args, char *); char *fmt = (f->flags & FMT_leftside) ? "%s%s" : "%-S%s"; diff --git a/getgroups.h b/getgroups.h new file mode 100644 index 0000000..982dfa0 --- /dev/null +++ b/getgroups.h @@ -0,0 +1,10 @@ +#if HAVE_GETGROUPS +#if HAVE_POSIX_GETGROUPS +/* We love POSIX. */ +#else +/* OK, so you've got getgroups, but you don't have the POSIX semantics +of a zero first argument. The conclusion is that you're on a reasonably +pure BSD system, and we can include for NGROUPS. */ +#include +#endif +#endif diff --git a/getopt.c b/getopt.c index 423b84a..3c54f53 100644 --- a/getopt.c +++ b/getopt.c @@ -9,42 +9,43 @@ char *rc_optarg; extern int rc_getopt(int argc, char **argv, char *opts) { static int sp = 1; - int c; - char *cp; + int c; + char *cp; if (rc_optind == 0) /* reset rc_getopt() */ rc_optind = sp = 1; - if (sp == 1) - if (rc_optind >= argc || argv[rc_optind][0] != '-' || argv[rc_optind][1] == '\0') { - return -1; - } else if (strcmp(argv[rc_optind], "--") == 0) { - rc_optind++; - return -1; - } - rc_optopt = c = argv[rc_optind][sp]; - if (c == ':' || (cp=strchr(opts, c)) == 0) { - fprint(2, "%s: bad option: -%c\n", argv[0], c); - if (argv[rc_optind][++sp] == '\0') { - rc_optind++; - sp = 1; - } - return '?'; - } - if (*++cp == ':') { - if (argv[rc_optind][sp+1] != '\0') { - rc_optarg = &argv[rc_optind++][sp+1]; - } else if (++rc_optind >= argc) { - fprint(2, "%s: option requires an argument -- %c\n", argv[0], c); - sp = 1; - return '?'; - } else - rc_optarg = argv[rc_optind++]; - sp = 1; - } else { - if (argv[rc_optind][++sp] == '\0') { - sp = 1; - rc_optind++; - } - rc_optarg = NULL; - } - return c; + if (sp == 1) { + if (rc_optind >= argc || argv[rc_optind][0] != '-' || argv[rc_optind][1] == '\0') { + return -1; + } else if (strcmp(argv[rc_optind], "--") == 0) { + rc_optind++; + return -1; + } + } + rc_optopt = c = argv[rc_optind][sp]; + if (c == ':' || (cp=strchr(opts, c)) == 0) { + fprint(2, "%s: bad option: -%c\n", argv[0], c); + if (argv[rc_optind][++sp] == '\0') { + rc_optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') { + if (argv[rc_optind][sp+1] != '\0') { + rc_optarg = &argv[rc_optind++][sp+1]; + } else if (++rc_optind >= argc) { + fprint(2, "%s: option requires an argument -- %c\n", argv[0], c); + sp = 1; + return '?'; + } else + rc_optarg = argv[rc_optind++]; + sp = 1; + } else { + if (argv[rc_optind][++sp] == '\0') { + sp = 1; + rc_optind++; + } + rc_optarg = NULL; + } + return c; } diff --git a/glob.c b/glob.c index 043f767..419a096 100644 --- a/glob.c +++ b/glob.c @@ -1,8 +1,7 @@ /* glob.c: rc's (ugly) globber. This code is not elegant, but it works */ -#include -#include #include "rc.h" +#include /* Lifted from autoconf documentation.*/ #if HAVE_DIRENT_H diff --git a/glom.c b/glom.c index e835ed2..ea6b432 100644 --- a/glom.c +++ b/glom.c @@ -1,10 +1,10 @@ /* glom.c: builds an argument list out of words, variables, etc. */ -#include +#include "rc.h" + #include #include #include -#include "rc.h" static List *backq(Node *, Node *); static List *bqinput(List *, int); @@ -324,6 +324,12 @@ static List *mkcmdarg(Node *n) { #elif HAVE_FIFO +#if HAVE_MKFIFO +/* Have POSIX mkfifo(). */ +#else +#define mkfifo(n,m) mknod(n, S_IFIFO | m, 0) +#endif + static List *mkcmdarg(Node *n) { int fd; char *name; @@ -331,9 +337,10 @@ static List *mkcmdarg(Node *n) { Estack *e = enew(Estack); List *ret = nnew(List); static int fifonumber = 0; + name = nprint("/tmp/rc%d.%d", getpid(), fifonumber++); - if (mknod(name, S_IFIFO | 0666, 0) < 0) { - uerror("mknod"); + if (mkfifo(name, 0666) < 0) { + uerror("mkfifo"); return NULL; } if (rc_fork() == 0) { @@ -360,7 +367,7 @@ static List *mkcmdarg(Node *n) { #else static List *mkcmdarg(Node *n) { - rc_error("named pipes are not supported"); + rc_error("command arguments are not supported"); return NULL; } diff --git a/group.h b/group.h deleted file mode 100644 index 8e78468..0000000 --- a/group.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Solaris / `gcc -ansi' only defines NGROUPS_MAX in if -_POSIX_C_SOURCE is defined. */ -#define _POSIX_C_SOURCE 1 -#include -#undef _POSIX_C_SOURCE - -#if defined(NGROUPS) && !defined(NGROUPS_MAX) -#define NGROUPS_MAX NGROUPS -#endif diff --git a/hash.c b/hash.c index 9f75b6c..408d0f2 100644 --- a/hash.c +++ b/hash.c @@ -15,7 +15,7 @@ static bool var_exportable(char *); static bool fn_exportable(char *); static int hash(char *, int); static int find(char *, Htab *, int); -static void free_fn(Function *); +static void free_fn(rc_Function *); Htab *fp; Htab *vp; @@ -118,7 +118,7 @@ extern void *lookup(char *s, Htab *ht) { return (ht[h].name == NULL) ? NULL : ht[h].p; } -extern Function *get_fn_place(char *s) { +extern rc_Function *get_fn_place(char *s) { int h = fnfind(s); env_dirty = TRUE; if (fp[h].name == NULL) { @@ -126,7 +126,7 @@ extern Function *get_fn_place(char *s) { h = fnfind(s); fused++; fp[h].name = ecpy(s); - fp[h].p = enew(Function); + fp[h].p = enew(rc_Function); } else free_fn(fp[h].p); return fp[h].p; @@ -205,7 +205,7 @@ extern void delete_var(char *s, bool stack) { } } -static void free_fn(Function *f) { +static void free_fn(rc_Function *f) { treefree(f->def); efree(f->extdef); } @@ -294,7 +294,7 @@ extern void whatare_all_vars(bool showfn, bool showvar) { /* fake getenv() for readline() follows: */ -#if READLINE +#if EDITLINE || READLINE extern char *getenv(const char *name) { List *s; if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL) diff --git a/history.1 b/history.1 new file mode 100644 index 0000000..5530654 --- /dev/null +++ b/history.1 @@ -0,0 +1,243 @@ +.\" history.1 +.\"------- +.\" See rc.1 for man page portability notes. +.\"------- +.\" Dd distance to space vertically before a "display" +.\" These are what n/troff use for interparagraph distance +.\"------- +.if t .nr Dd .4v +.if n .nr Dd 1v +.\"------- +.\" Ds begin a display, indented .5 inches from the surrounding text. +.\" +.\" Note that uses of Ds and De may NOT be nested. +.\"------- +.de Ds +.\" .RS \\$1 +.sp \\n(Ddu +.in +0.5i +.nf +.. +.\"------- +.\" De end a display (no trailing vertical spacing) +.\"------- +.de De +.fi +.in +.\" .RE +.. +.\"------- +.\" I stole the Xf macro from the -man macros on my machine (originally +.\" "}S", I renamed it so that it won't conflict). +.\"------- +.\" Set Cf to the name of the constant width font. +.\" It will be "C" or "(CW", typically. +.\" NOTEZ BIEN the lines defining Cf must have no trailing white space: +.\"------- +.if t .ds Cf C +.if n .ds Cf R +.\"------- +.\" Rc - Alternate Roman and Courier +.\"------- +.de Rc +.Xf R \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Ic - Alternate Italic and Courier +.\"------- +.de Ic +.Xf I \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Bc - Alternate Bold and Courier +.\"------- +.de Bc +.Xf B \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Cr - Alternate Courier and Roman +.\"------- +.de Cr +.Xf \\*(Cf R \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Ci - Alternate Courier and Italic +.\"------- +.de Ci +.Xf \\*(Cf I \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Cb - Alternate Courier and Bold +.\"------- +.de Cb +.Xf \\*(Cf B \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.\"------- +.\" Xf - Alternate fonts +.\" +.\" \$1 - first font +.\" \$2 - second font +.\" \$3 - desired word with embedded font changes, built up by recursion +.\" \$4 - text for first font +.\" \$5 - \$9 - remaining args +.\" +.\" Every time we are called: +.\" +.\" If there is something in \$4 +.\" then Call ourself with the fonts switched, +.\" with a new word made of the current word (\$3) and \$4 +.\" rendered in the first font, +.\" and with the remaining args following \$4. +.\" else We are done recursing. \$3 holds the desired output +.\" word. We emit \$3, change to Roman font, and restore +.\" the point size to the default. +.\" fi +.\" +.\" Use Xi to add a little bit of space after italic text. +.\"------- +.de Xf +.ds Xi +.\"------- +.\" I used to test for the italic font both by its font position +.\" and its name. Now just test by its name. +.\" +.\" .if "\\$1"2" .if !"\\$5"" .ds Xi \^ +.\"------- +.if "\\$1"I" .if !"\\$5"" .ds Xi \^ +.\"------- +.\" This is my original code to deal with the recursion. +.\" Evidently some nroffs can't deal with it. +.\"------- +.\" .ie !"\\$4"" \{\ +.\" . Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" +.\" .\} +.\" .el \{\\$3 +.\" . ft R \" Restore the default font, since we don't know +.\" . \" what the last font change was. +.\" . ps 10 \" Restore the default point size, since it might +.\" . \" have been changed by an argument to this macro. +.\" .\} +.\"------- +.\" Here is more portable (though less pretty) code to deal with +.\" the recursion. +.\"------- +.if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" +.if "\\$4"" \\$3\fR\s10 +.. +.TH HISTORY 1 "30 July 1991" +.SH NAME +\-, \-\|\-, \-p, \-\|\-p \- shell history programs +.SH SYNOPSIS +.B \- +.RI [ pattern ...] +.RI [ substitution ...] +.SH DESCRIPTION +This set of programs provides a crude history mechanism for the shell +.IR rc (1). +It is based on the v8 UNIX programs +.IR = , +.IR == , +etc. +.PP +The program +.RI `` \- '' +runs the shell on the command it is requested to find. +The program +.RI `` \-\|\- '' +edits that command first. +The programs +.RI `` \-p '' +and +.RI `` \-\|\-p '' +are similar, except that they print the final command on their standard +output instead of running the shell. +.PP +The commands work by looking for a file +named by the environment variable +.Cr $history , +and by searching for previous commands in this file. +Old commands can be edited, +or simply re-executed according to the rules below: +.PP +A command is searched for by examining the lines in +.Cr $history +in reverse order. +Lines which contain a previous invocation of the history +program itself are ignored. +If one or more +.I pattern +is supplied on the command line, +then the patterns are used as a means of +limiting the search. +Patterns match any substring of a previous command, +and if more than one pattern is present then all patterns must be +matched before a command is selected. +.PP +Substitutions may also be specified on the command line. +These have the syntax: +.Ds +.Ic old : new +.De +.PP +(Note that the +.I old +pattern is used as a search-limiting pattern also.) +Substitutions happen on the first match. +.PP +Finally, if the program was invoked as +.RI `` -- '' +or +.RI `` --p '', +a command may be edited in a crude line-mode fashion. The line to be +edited is printed out, and below it the user supplies modifications to +the command. +.TP +.B any character except those below +Replaces the character above. +.TP +.B space or tab +Skips over the above character(s). +.TP +.B # +Deletes one character. +.TP +.B % +Replaces one character with a space. +.TP +.B ^ +Inserts the rest of the typed line just before the character. +.TP +.B $ +Deletes the rest of the line from that character on, and replaces +it with the rest of the typed line. +.TP +.B + +Appends the rest of the typed line. +.TP +.B \- +Backs up to a previous command satisfying the same matching +constraints. +.TP +.B end of line +If any changes have been made, the command is printed out again for +further editing. If no changes have been made, the command is executed +or printed, and the program exits. +.TP +.B end of file +If an end-of-file is read from the keyboard by the editor, +it aborts with exit status 1 and does not produce any output. +.SH EXAMPLES +The history programs work best when their output is reinterpreted by +the shell using an +.Cr eval +command. +This can be achieved by writing a shell function to perform the +reinterpretation: +.Ds +.Cr "fn - -- {" +.Cr " comm = \`{$0^p $*}" +.Cr " if (! ~ $#comm 0) {" +.Cr " echo $comm >[1=2]" +.Cr " eval $comm" +.Cr " }" +.Cr "}" diff --git a/history.c b/history.c new file mode 100644 index 0000000..629751d --- /dev/null +++ b/history.c @@ -0,0 +1,339 @@ +/* + history.c -- primitive history mechanism + + Paul Haahr & Byron Rakitzis, July 1991. + + This program mimics the att v8 = and == history programs. + The edit() algorithm was adapted from a similar program + that Boyd Roberts wrote, but otherwise all the code has + been written from scratch. + + edit() was subsequently redone by Hugh Redelmeier in order + to correctly deal with tab characters in the source line. + + BUGS: + There is an implicit assumption that commands are no + more than 1k characters long. +*/ + +#include "rc.h" + +#include + +static const char id[] = "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $"; + +#define CHUNKSIZE 65536 + +static struct { + char *old, *new; +} *replace; + +static char **search, *progname, *history; +static char me; /* typically ':' or '-' */ +static bool editit = FALSE, printit = FALSE; +static int nreplace = 0, nsearch = 0; +static FILE *histfile; + +void *ealloc(size_t n) { + void *p = (void *) malloc(n); + if (p == NULL) { + perror("malloc"); + exit(1); + } + return p; +} + +void *erealloc(void *p, size_t n) { + p = (void *) realloc(p, n); + if (p == NULL) { + perror("realloc"); + exit(1); + } + return p; +} + +static char *newstr() { + return ealloc((size_t)1024); +} + +static char *rc_basename(char *s) { + char *t = strrchr(s, '/'); + return (t == NULL) ? s : t + 1; +} + +/* stupid O(n^2) substring matching routine */ + +static char *isin(char *target, char *pattern) { + size_t plen = strlen(pattern); + size_t tlen = strlen(target); + for (; tlen >= plen; target++, --tlen) + if (strncmp(target, pattern, plen) == 0) + return target; + return NULL; +} + +/* replace the first match in the string with "new" */ +static char *sub(char *s, char *old, char *new) { + char *t, *u; + + t = isin(s, old); + u = newstr(); + + *t = '\0'; + while (*old != '\0') + old++, t++; + strcpy(u, s); + strcat(u, new); + strcat(u, t); + return u; +} + +static char *edit(char *s) { + char *final, *f, *end; + int col; + bool ins; + +start: + fprintf(stderr, "%s\n", s); + f = final = newstr(); + end = s + strlen(s); + col = 0; + ins = FALSE; + + for (;; col++) { + int c = getchar(); + + if (c == me && col == 0) { + int peekc = getchar(); + if (peekc == '\n') + return NULL; + ungetc(peekc, stdin); + } + if (c == '\n') { + if (col == 0) + return s; + + while (s < end) /* copy remainder of string */ + *f++ = *s++; + *f = '\0'; + s = final; + goto start; + } else if (ins || s>=end) { + /* col need not be accurate -- tabs need not be interpreted */ + *f++ = c; + } else { + switch (c) { + case '+': + while (s < end) + *f++ = *s++; + *f = '\0'; + continue; + case '%': + c = ' '; + /* FALLTHROUGH */ + default: + *f++ = c; + break; + case EOF: + exit(1); + /* NOTREACHED */ + case ' ': + if (*s == '\t') { + int oldcol = col; + + for (;; col++) { + int peekc; + + if ((col&07) == 07) { + *f++ = '\t'; /* we spaced past a tab */ + break; + } + peekc = getchar(); + if (peekc != ' ') { + ungetc(peekc, stdin); + if (peekc != '\n') { + /* we spaced partially into a tab */ + do { + *f++ = ' '; + oldcol++; + } while (oldcol <= col); + } + break; + } + } + } else { + *f++ = *s; + } + break; + case '#': + break; + case '$': + end = s; /* truncate s */ + continue; /* skip incrementing s */ + case '^': + ins = TRUE; + continue; /* skip incrementing s */ + case '\t': + for (;; col++) { + *f = s 0) { + count += nread; + if (size - count == 0) + buf = erealloc(buf, size *= 4); + } + if (nread == -1) { + perror(history); + exit(1); + } + *last = buf + count; + return buf; +} + +static char *getcommand() { + char *s, *t; + static char *hist = NULL, *last; + + if (hist == NULL) { + hist = readhistoryfile(&last); + *--last = '\0'; /* trim final newline */ + } + +again: s = last; + if (s < hist) + return NULL; + while (*--s != '\n') + if (s <= hist) { + last = hist - 1; + return hist; + } + *s = '\0'; + last = s++; + + /* + * if the command contains the "me" character at the start of the line + * or after any of [`{|()@] then try again + */ + + for (t = s; *t != '\0'; t++) + if (*t == me) { + char *u = t - 1; + while (u >= s && (*u == ' ' || *u == '\t')) + --u; + if (u < s) + goto again; + switch (*u) { + case '`': case '@': + case '(': case ')': + case '{': case '|': + case '/': + goto again; + default: + break; + } + } + return s; +} + +int main(int argc, char **argv) { + int i; + char *s; + + s = progname = rc_basename(argv[0]); + me = *s++; + if (*s == me) { + s++; + editit = TRUE; + } + if (*s == 'p') { + s++; + printit = TRUE; + } +/* Nahh... + if (*s != '\0') { + fprintf(stderr, "\"%s\": bad name for history program\n", progname); + exit(1); + } +*/ + + if (argc > 1) { + replace = ealloc((argc - 1) * sizeof *replace); + search = ealloc((argc - 1) * sizeof *search); + } + for (i = 1; i < argc; i++) + if ((s = strchr(argv[i], ':')) == NULL) + search[nsearch++] = argv[i]; + else { + *(char *)s = '\0'; /* do we confuse ps too much? */ + replace[nreplace].old = argv[i]; + replace[nreplace].new = s + 1; + nreplace++; + } + +next: s = getcommand(); + if (s == NULL) { + fprintf(stderr, "command not matched\n"); + return 1; + } + for (i = 0; i < nsearch; i++) + if (!isin(s, search[i])) + goto next; + for (i = 0; i < nreplace; i++) + if (!isin(s, replace[i].old)) + goto next; + else + s = sub(s, replace[i].old, replace[i].new); + if (editit) { + s = edit(s); + if (s == NULL) + goto next; + } + fseek(histfile, 0, 2); /* 2 == end of file. i.e., append command to $history */ + fprintf(histfile, "%s\n", s); + fclose(histfile); + if (printit) + printf("%s\n", s); + else { + char *shell = getenv("SHELL"); + + if (!editit) + fprintf(stderr, "%s\n", s); + if (shell == NULL) + shell = "/bin/sh"; + execl(shell, rc_basename(shell), "-c", s, NULL); + perror(shell); + exit(1); + } + return 0; +} diff --git a/history/history.1 b/history/history.1 deleted file mode 100644 index 18ed28f..0000000 --- a/history/history.1 +++ /dev/null @@ -1,234 +0,0 @@ -.\" history.1 -.\"------- -.\" See rc.1 for man page portability notes. -.\"------- -.\" Dd distance to space vertically before a "display" -.\" These are what n/troff use for interparagraph distance -.\"------- -.if t .nr Dd .4v -.if n .nr Dd 1v -.\"------- -.\" Ds begin a display, indented .5 inches from the surrounding text. -.\" -.\" Note that uses of Ds and De may NOT be nested. -.\"------- -.de Ds -.\" .RS \\$1 -.sp \\n(Ddu -.in +0.5i -.nf -.. -.\"------- -.\" De end a display (no trailing vertical spacing) -.\"------- -.de De -.fi -.in -.\" .RE -.. -.\"------- -.\" I stole the Xf macro from the -man macros on my machine (originally -.\" "}S", I renamed it so that it won't conflict). -.\"------- -.\" Set Cf to the name of the constant width font. -.\" It will be "C" or "(CW", typically. -.\" NOTEZ BIEN the lines defining Cf must have no trailing white space: -.\"------- -.if t .ds Cf C -.if n .ds Cf R -.\"------- -.\" Rc - Alternate Roman and Courier -.\"------- -.de Rc -.Xf R \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" -.. -.\"------- -.\" Ic - Alternate Italic and Courier -.\"------- -.de Ic -.Xf I \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" -.. -.\"------- -.\" Bc - Alternate Bold and Courier -.\"------- -.de Bc -.Xf B \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" -.. -.\"------- -.\" Cr - Alternate Courier and Roman -.\"------- -.de Cr -.Xf \\*(Cf R \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" -.. -.\"------- -.\" Ci - Alternate Courier and Italic -.\"------- -.de Ci -.Xf \\*(Cf I \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" -.. -.\"------- -.\" Cb - Alternate Courier and Bold -.\"------- -.de Cb -.Xf \\*(Cf B \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" -.. -.\"------- -.\" Xf - Alternate fonts -.\" -.\" \$1 - first font -.\" \$2 - second font -.\" \$3 - desired word with embedded font changes, built up by recursion -.\" \$4 - text for first font -.\" \$5 - \$9 - remaining args -.\" -.\" Every time we are called: -.\" -.\" If there is something in \$4 -.\" then Call ourself with the fonts switched, -.\" with a new word made of the current word (\$3) and \$4 -.\" rendered in the first font, -.\" and with the remaining args following \$4. -.\" else We are done recursing. \$3 holds the desired output -.\" word. We emit \$3, change to Roman font, and restore -.\" the point size to the default. -.\" fi -.\" -.\" Use Xi to add a little bit of space after italic text. -.\"------- -.de Xf -.ds Xi -.\"------- -.\" I used to test for the italic font both by its font position -.\" and its name. Now just test by its name. -.\" -.\" .if "\\$1"2" .if !"\\$5"" .ds Xi \^ -.\"------- -.if "\\$1"I" .if !"\\$5"" .ds Xi \^ -.\"------- -.\" This is my original code to deal with the recursion. -.\" Evidently some nroffs can't deal with it. -.\"------- -.\" .ie !"\\$4"" \{\ -.\" . Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" -.\" .\} -.\" .el \{\\$3 -.\" . ft R \" Restore the default font, since we don't know -.\" . \" what the last font change was. -.\" . ps 10 \" Restore the default point size, since it might -.\" . \" have been changed by an argument to this macro. -.\" .\} -.\"------- -.\" Here is more portable (though less pretty) code to deal with -.\" the recursion. -.\"------- -.if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" -.if "\\$4"" \\$3\fR\s10 -.. -.TH HISTORY 1 "30 July 1991" -.SH NAME -\-, \-\|\-, \-p, \-\|\-p \- shell history programs -.SH SYNOPSIS -.B \- -.RI [ pattern ...] -.RI [ substitution ...] -.SH DESCRIPTION -This set of programs provides a crude history mechanism for the shell -.IR rc (1). -It is based on the v8 UNIX programs -.IR = , -.IR == , -etc. -.PP -The program -.RI `` \- '' -runs the shell on the command it is requested to find. -The program -.RI `` \-\|\- '' -edits that command first. -The programs -.RI `` \-p '' -and -.RI `` \-\|\-p '' -are similar, except that they print the final command on their standard -output instead of running the shell. -.PP -The commands work by looking for a file -named by the environment variable -.Cr $history , -and by searching for previous commands in this file. -Old commands can be edited, -or simply re-executed according to the rules below: -.PP -A command is searched for by examining the lines in -.Cr $history -in reverse order. -Lines which contain a previous invocation of the history -program itself are ignored. -If one or more -.I pattern -is supplied on the command line, -then the patterns are used as a means of -limiting the search. -Patterns match any substring of a previous command, -and if more than one pattern is present then all patterns must be -matched before a command is selected. -.PP -Substitutions may also be specified on the command line. -These have the syntax: -.Ds -.Ic old : new -.De -.PP -(Note that the -.I old -pattern is used as a search-limiting pattern also.) -Substitutions happen on the first match. -.PP -Finally, a command may be edited in a crude line-mode fashion: -The line to be edited is printed out, and below it the user -supplies modifications to the command: -.TP -.B any character -Replaces the character above. -.TP -.B space or tab -Skips over the above character(s). -.TP -.B # -Deletes one character. -.TP -.B % -Replaces one character with a space. -.TP -.B ^ -Inserts the rest of the typed line just before the character. -.TP -.B $ -Deletes the rest of the line from that character on, and replaces -it with the rest of the typed line. -.TP -.B + -Appends the rest of the typed line. -.TP -.B \- -Backs up to a previous command satisfying the same matching -constraints. -.TP -.B end of file -If an end-of-file is read from the keyboard by the editor, -it aborts with exit status 1 and does not produce any output. -.SH EXAMPLES -The history programs work best when their output is reinterpreted by -the shell using an -.Cr eval -command. -This can be achieved by writing a shell function to perform the -reinterpretation: -.Ds -.Cr "fn - -- {" -.Cr " comm = \`{$0^p $*}" -.Cr " if (! ~ $#comm 0) {" -.Cr " echo $comm >[1=2]" -.Cr " eval $comm" -.Cr " }" -.Cr "}" diff --git a/history/history.c b/history/history.c deleted file mode 100644 index e6aa29d..0000000 --- a/history/history.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - history.c -- primitive history mechanism - - Paul Haahr & Byron Rakitzis, July 1991. - - This program mimics the att v8 = and == history programs. - The edit() algorithm was adapted from a similar program - that Boyd Roberts wrote, but otherwise all the code has - been written from scratch. - - edit() was subsequently redone by Hugh Redelmeier in order - to correctly deal with tab characters in the source line. - - BUGS: - There is an implicit assumption that commands are no - more than 1k characters long. -*/ - -#include -#include -#include - -static char *id = "@(#) history.c 8/91"; - -#undef FALSE -#undef TRUE -typedef enum { FALSE, TRUE } bool; - -#define CHUNKSIZE 65536 - -static struct { - char *old, *new; -} *replace; - -static char **search, *progname, *history; -static char me; /* typically ':' or '-' */ -static bool editit = FALSE, printit = FALSE; -static int nreplace = 0, nsearch = 0; -static FILE *fp; - -static void *ealloc(size_t n) { - void *p = (void *) malloc(n); - if (p == NULL) { - perror("malloc"); - exit(1); - } - return p; -} - -static void *erealloc(void *p, size_t n) { - p = (void *) realloc(p, n); - if (p == NULL) { - perror("realloc"); - exit(1); - } - return p; -} - -static char *newstr() { - return ealloc((size_t)1024); -} - -static char *basename(char *s) { - char *t = strrchr(s, '/'); - return (t == NULL) ? s : t + 1; -} - -/* stupid O(n^2) substring matching routine */ - -static char *isin(char *target, char *pattern) { - size_t plen = strlen(pattern); - size_t tlen = strlen(target); - for (; tlen >= plen; target++, --tlen) - if (strncmp(target, pattern, plen) == 0) - return target; - return NULL; -} - -/* replace the first match in the string with "new" */ -static char *sub(char *s, char *old, char *new) { - char *t, *u; - - t = isin(s, old); - u = newstr(); - - *t = '\0'; - while (*old != '\0') - old++, t++; - strcpy(u, s); - strcat(u, new); - strcat(u, t); - return u; -} - -static char *edit(char *s) { - char *final, *f, *end; - int col; - bool ins; - -start: - fprintf(stderr, "%s\n", s); - f = final = newstr(); - end = s + strlen(s); - col = 0; - ins = FALSE; - - for (;; col++) { - int c = getchar(); - - if (c == me && col == 0) { - int peekc = getchar(); - if (peekc == '\n') - return NULL; - ungetc(peekc, stdin); - } - if (c == '\n') { - if (col == 0) - return s; - - while (s < end) /* copy remainder of string */ - *f++ = *s++; - *f = '\0'; - s = final; - goto start; - } else if (ins || s>=end) { - /* col need not be accurate -- tabs need not be interpreted */ - *f++ = c; - } else { - switch (c) { - case '+': - while (s < end) - *f++ = *s++; - *f = '\0'; - continue; - case '%': - c = ' '; - /* FALLTHROUGH */ - default: - *f++ = c; - break; - case EOF: - exit(1); - /* NOTREACHED */ - case ' ': - if (*s == '\t') { - int oldcol = col; - - for (;; col++) { - int peekc; - - if ((col&07) == 07) { - *f++ = '\t'; /* we spaced past a tab */ - break; - } - peekc = getchar(); - if (peekc != ' ') { - ungetc(peekc, stdin); - if (peekc != '\n') { - /* we spaced partially into a tab */ - do { - *f++ = ' '; - oldcol++; - } while (oldcol <= col); - } - break; - } - } - } else { - *f++ = *s; - } - break; - case '#': - break; - case '$': - end = s; /* truncate s */ - continue; /* skip incrementing s */ - case '^': - ins = TRUE; - continue; /* skip incrementing s */ - case '\t': - for (;; col++) { - if ((*f++ = s 0) { - count += nread; - if (size - count == 0) - buf = erealloc(buf, size *= 4); - } - if (nread == -1) { - perror(history); - exit(1); - } - *last = buf + count; - return buf; -} - -static char *getcommand() { - char *s, *t; - static char *hist = NULL, *last; - - if (hist == NULL) { - hist = readhistoryfile(&last); - *--last = '\0'; /* trim final newline */ - } - -again: s = last; - if (s < hist) - return NULL; - while (*--s != '\n') - if (s <= hist) { - last = hist - 1; - return hist; - } - *s = '\0'; - last = s++; - - /* - * if the command contains the "me" character at the start of the line - * or after any of [`{|()@] then try again - */ - - for (t = s; *t != '\0'; t++) - if (*t == me) { - char *u = t - 1; - while (u >= s && (*u == ' ' || *u == '\t')) - --u; - if (u < s) - goto again; - switch (*u) { - case '`': case '@': - case '(': case ')': - case '{': case '|': - goto again; - default: - break; - } - } - return s; -} - -int main(int argc, char **argv) { - int i; - char *s; - - s = progname = basename(argv[0]); - me = *s++; - if (*s == me) { - s++; - editit = TRUE; - } - if (*s == 'p') { - s++; - printit = TRUE; - } -/* Nahh... - if (*s != '\0') { - fprintf(stderr, "\"%s\": bad name for history program\n", progname); - exit(1); - } -*/ - - if (argc > 1) { - replace = ealloc((argc - 1) * sizeof *replace); - search = ealloc((argc - 1) * sizeof *search); - } - for (i = 1; i < argc; i++) - if ((s = strchr(argv[i], ':')) == NULL) - search[nsearch++] = argv[i]; - else { - *(char *)s = '\0'; /* do we confuse ps too much? */ - replace[nreplace].old = argv[i]; - replace[nreplace].new = s + 1; - nreplace++; - } - -next: s = getcommand(); - if (s == NULL) { - fprintf(stderr, "command not matched\n"); - return 1; - } - for (i = 0; i < nsearch; i++) - if (!isin(s, search[i])) - goto next; - for (i = 0; i < nreplace; i++) - if (!isin(s, replace[i].old)) - goto next; - else - s = sub(s, replace[i].old, replace[i].new); - if (editit) { - s = edit(s); - if (s == NULL) - goto next; - } - fseek(fp, 0, 2); /* 2 == end of file. i.e., append command to $history */ - fprintf(fp, "%s\n", s); - fclose(fp); - if (printit) - printf("%s\n", s); - else { - char *shell = getenv("SHELL"); - - if (!editit) - fprintf(stderr, "%s\n", s); - if (shell == NULL) - shell = "/bin/sh"; - execl(shell, basename(shell), "-c", s, NULL); - perror(shell); - exit(1); - } - return 0; -} diff --git a/input.c b/input.c index 3b60677..83bd60b 100644 --- a/input.c +++ b/input.c @@ -1,7 +1,7 @@ /* input.c: i/o routines for files and pseudo-files (strings) */ #include -#include + #include "rc.h" #include "jbwrap.h" @@ -20,13 +20,7 @@ typedef struct Input { #define BUFSIZE ((size_t) 256) -#if READLINE -extern char *readline(char *); -extern void add_history(char *); -static char *rlinebuf; -#endif - -char *prompt, *prompt2; +static char *prompt2; bool rcrc; static int dead(void); @@ -46,6 +40,10 @@ static void (*realugchar)(int); int last; +#if EDITLINE || READLINE +static char *rlinebuf, *prompt; +#endif + extern int gchar() { int c; @@ -55,7 +53,7 @@ extern int gchar() { } while ((c = (*realgchar)()) == '\0') - pr_error("warning: null character ignored"); + pr_error("warning: null character ignored", 0); return c; } @@ -68,7 +66,7 @@ static int dead() { return last = EOF; } -static void ugdead(int c) { +static void ugdead(int ignore) { return; } @@ -85,42 +83,20 @@ static int stringgchar() { return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); } -/* signal-safe readline wrapper */ - -#if READLINE -#ifndef HAVE_RESTARTABLE_SYSCALLS -static char *rc_readline(char *prompt) { - char *r; - interrupt_happened = FALSE; - if (!setjmp(slowbuf.j)) { - slow = TRUE; - if (!interrupt_happened) - r = readline(prompt); - else - r = NULL; - } else - r = NULL; - slow = FALSE; - if (r == NULL) - errno = EINTR; - sigchk(); - return r; -} -#else -#define rc_readline readline -#endif /* HAVE_RESTARTABLE_SYSCALLS */ -#endif /* READLINE */ - /* - read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor - the buffer to look like a regular fdgchar buffer. + read a character from a file-descriptor. If GNU readline is defined, + add a newline and doctor the buffer to look like a regular fdgchar + buffer. */ static int fdgchar() { + if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */ while (1) { -#if READLINE - if (interactive && istack->fd == 0) { +#if EDITLINE || READLINE + if (interactive && istack->fd == 0 && isatty(0)) { + /* The readline library doesn't handle read() returning EAGAIN. */ + makeblocking(istack->fd); rlinebuf = rc_readline(prompt); if (rlinebuf == NULL) { chars_in = 0; @@ -136,9 +112,17 @@ static int fdgchar() { } } else #endif - { - long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE); - sigchk(); + { + ssize_t r; + do { + r = rc_read(istack->fd, inbuf + 2, BUFSIZE); + sigchk(); + if (errno == EAGAIN) { + if (!makeblocking(istack->fd)) + panic("not O_NONBLOCK"); + errno = EINTR; + } + } while (r < 0 && errno == EINTR); if (r < 0) { uerror("read"); rc_exit(1); @@ -248,15 +232,17 @@ extern void flushu() { /* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */ -extern Node *doit(bool execit) { +extern Node *doit(bool clobberexecit) { bool eof; + bool execit ; Jbwrap j; Estack e1, e2; Edata jerror; if (dashen) - execit = FALSE; - setjmp(j.j); + clobberexecit = FALSE; + execit = clobberexecit; + sigsetjmp(j.j, 1); jerror.jb = &j; except(eError, jerror, &e1); for (eof = FALSE; !eof;) { @@ -279,11 +265,12 @@ extern Node *doit(bool execit) { funcall(arglist); } if ((s = varlookup("prompt")) != NULL) { -#if READLINE - prompt = s->w; -#else - fprint(2, "%s", s->w); +#if EDITLINE || READLINE + if (istack->t == iFd && istack->fd == 0 && isatty(0)) + prompt = s->w; + else #endif + fprint(2, "%s", s->w); prompt2 = (s->n == NULL ? "" : s->n->w); } } @@ -361,3 +348,15 @@ extern void closefds() { i->fd = -1; } } + +extern void print_prompt2() { + lineno++; + if (interactive) { +#if EDITLINE || READLINE + if (istack->t == iFd && istack->fd == 0 && isatty(0)) + prompt = prompt2; + else +#endif + fprint(2, "%s", prompt2); + } +} diff --git a/install-sh b/install-sh deleted file mode 100755 index ebc6691..0000000 --- a/install-sh +++ /dev/null @@ -1,250 +0,0 @@ -#! /bin/sh -# -# install - install a program, script, or datafile -# This comes from X11R5 (mit/util/scripts/install.sh). -# -# Copyright 1991 by the Massachusetts Institute of Technology -# -# Permission to use, copy, modify, distribute, and sell this software and its -# documentation for any purpose is hereby granted without fee, provided that -# the above copyright notice appear in all copies and that both that -# copyright notice and this permission notice appear in supporting -# documentation, and that the name of M.I.T. not be used in advertising or -# publicity pertaining to distribution of the software without specific, -# written prior permission. M.I.T. makes no representations about the -# suitability of this software for any purpose. It is provided "as is" -# without express or implied warranty. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. It can only install one file at a time, a restriction -# shared with many OS's install programs. - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -transformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" - -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift - - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi - - pathcomp="${pathcomp}/" -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi - -# Make a temp file name in the proper directory. - - dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - - $doit $instcmd $src $dsttmp && - - trap "rm -f ${dsttmp}" 0 && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && - -# Now rename the file to the real destination. - - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile - -fi && - - -exit 0 diff --git a/jbwrap.h b/jbwrap.h index 7d0358b..4b3ea86 100644 --- a/jbwrap.h +++ b/jbwrap.h @@ -1,9 +1,23 @@ #include -/* certain braindamaged environments don't define jmp_buf as an array, so... */ +/* If we have POSIX sigjmp_buf and friends, use them. If we don't, just +use a jmp_buf. This probably fails on a traditional SysV machine, where +jmp_bufs don't preserve signal masks. I'm not worrying about this till +someone reports it as a bug :-). */ + +#if HAVE_SIGSETJMP +#else +#define sigjmp_buf jmp_buf +#define sigsetjmp(x,y) setjmp(x) +#define siglongjmp longjmp +#endif /* HAVE_SIGSETJMP */ + + +/* Certain braindamaged environments don't define jmp_buf as an array, +so wrap it in a structure. Potentially, we could use configure to do +this only where it needs to be done, but the effort is probably not +worth it. */ struct Jbwrap { - jmp_buf j; + sigjmp_buf j; }; - -extern Jbwrap slowbuf; /* for getting out of interrupts while performing slow i/o on BSD */ diff --git a/lex.c b/lex.c index a763ce4..7e35cdd 100644 --- a/lex.c +++ b/lex.c @@ -1,7 +1,7 @@ /* lex.c: rc's lexical analyzer */ #include "rc.h" -#include "y.tab.h" +#include "parse.h" /* Special characters (i.e., "non-word") in rc: @@ -336,16 +336,6 @@ extern void inityy() { realbuf = ealloc(bufsize); } -extern void print_prompt2() { - lineno++; -#if READLINE - prompt = prompt2; -#else - if (interactive) - fprint(2, "%s", prompt2); -#endif -} - /* Scan in a pair of integers for redirections like >[2=1]. CLOSED represents a closed file descriptor (i.e., >[2=]) and UNSET represents an undesignated file descriptor (e.g., diff --git a/main.c b/main.c index 68624d7..55649fe 100644 --- a/main.c +++ b/main.c @@ -11,7 +11,9 @@ static bool dashoh; static void assigndefault(char *,...); static void checkfd(int, enum redirtype); -extern void main(int argc, char *argv[], char *envp[]) { +static const char id[] = "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $"; + +extern int main(int argc, char *argv[], char *envp[]) { char *dashsee[2], *dollarzero, *null[1]; int c; initprint(); @@ -19,7 +21,7 @@ extern void main(int argc, char *argv[], char *envp[]) { dollarzero = argv[0]; rc_pid = getpid(); dashell = (*argv[0] == '-'); /* Unix tradition */ - while ((c = rc_getopt(argc, argv, "nolpeivdxsc:")) != -1) + while ((c = rc_getopt(argc, argv, "Vnolpeivdxsc:")) != -1) switch (c) { case 'l': dashell = TRUE; @@ -54,6 +56,9 @@ extern void main(int argc, char *argv[], char *envp[]) { case 'o': dashoh = TRUE; break; + case 'V': + fprint(1, "%s\n", id); + exit(0); case '?': exit(1); } @@ -97,6 +102,7 @@ quitopts: dasheye = FALSE; doit(TRUE); rc_exit(getstatus()); + return 0; /* Never really reached. */ } static void assigndefault(char *name,...) { diff --git a/mksignal b/mksignal deleted file mode 100755 index 9902ed8..0000000 --- a/mksignal +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh -# generate rc's internal signal table from signal.h - -exec > sigmsgs.c - -echo '#include "sigmsgs.h"' -echo -echo 'Sigmsgs signals[] = {' - -sed ' s/\/\*[ ]*// - s/[ ]*\*\/// - s/([@*+!]) // - s/[ ]*([a-zA-Z,->& ]*)[ ]*// - s/^[ ]*\#[ ]*define/\#define/ - s/[ ]*signal$// - s/_SIG/SIG/g' $1 | -awk ' - BEGIN { - # assign to nomesg["SIGNAME"] to suppress a long message - nomesg["SIGINT"] = 1 - nomesg["SIGPIPE"] = 1 - # assign to mesg["SIGNAME"] to override a message - mesg["SIGHUP"] = "hangup" - mesg["SIGKILL"] = "killed" - mesg["SIGQUIT"] = "quit" - mesg["SIGTERM"] = "terminated" - mesg["SIGURG"] = "urgent condition on i/o channel" - mesg["SIGSTOP"] = "stop signal not from tty" - mesg["SIGTSTP"] = "stopped" - mesg["SIGCONT"] = "continue" - mesg["SIGCHLD"] = "child stop or exit" - mesg["SIGTTIN"] = "background tty read" - mesg["SIGTTOU"] = "background tty write" - # assign to ignore["SIGNAME"] to explicitly ignore a named signal - ignore["SIGMAX"] = 1 - } - $1 == "#define" && $2 == "NSIG" && $3 ~ /^[0-9]+$/ { nsig = $3 } - $1 == "#define" && $2 ~ /^SIG/ && $3 ~ /^[0-9]+$/ && sig[$3] == "" && ignore[$2] == 0 { - sig[$3] = $2 - if ($3 > max) - max = $3 - if (mesg[$2] == "" && nomesg[$2] == 0) { - str = $4 - for (i = 5; i <= NF; i++) - str = str " " $i - mesg[$2] = str - } - } - END { - if (nsig == 0) - nsig = max + 1 - printf " {!!, !!},\n" - for (i = 1; i < nsig; i++) { - if (sig[i] == "") - printf " {!!, !!},\n" - else - printf " {!%s!, !%s!},\n", sig[i], mesg[sig[i]] - } - } -' | -tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!' 'abcdefghijklmnopqrstuvwxyz"' - -echo '};' - -exec > sigmsgs.h - -echo 'typedef struct {' -echo ' char *name, *msg;' -echo '} Sigmsgs;' -echo 'extern Sigmsgs signals[];' - -grep '^ ' sigmsgs.c | # the thing in quotes is ^ -awk ' - { sum = sum + 1; } - END { print "#define NUMOFSIGNALS", sum } -' diff --git a/mksignal.c b/mksignal.c new file mode 100644 index 0000000..5677271 --- /dev/null +++ b/mksignal.c @@ -0,0 +1,238 @@ +#include +#include + +#ifdef NSIG +#define NUMSIG NSIG +#else +#define NUMSIG 1 +#endif + +typedef struct { + int signo; + char *signame; + char *sigmsg; +} signaming; + +static signaming signamings[] = { +#ifdef SIGABRT + { SIGABRT, "sigabrt", "abort"}, +#endif +#ifdef SIGALRM + { SIGALRM, "sigalrm", "alarm clock"}, +#endif +#ifdef SIGBREAK + { SIGBREAK, "sigbreak", "break"}, +#endif +#ifdef SIGBUS + { SIGBUS, "sigbus", "bus error"}, +#endif +#ifdef SIGCANCEL + { SIGCANCEL, "sigcancel", "thread cancellation"}, +#endif +#ifdef SIGCHLD + { SIGCHLD, "sigchld", "child stop or exit"}, +#endif +#ifdef SIGCLD + { SIGCLD, "sigcld", "child stop or exit"}, +#endif +#ifdef SIGCONT + { SIGCONT, "sigcont", "continue"}, +#endif +#ifdef SIGDIL + { SIGDIL, "sigdil", "dil signal"}, +#endif +#ifdef SIGEMT + { SIGEMT, "sigemt", "emt instruction"}, +#endif +#ifdef SIGFPE + { SIGFPE, "sigfpe", "floating point error"}, +#endif +#ifdef SIGFREEZE + { SIGFREEZE, "sigfreeze", "cpr freeze"}, +#endif +#ifdef SIGHUP + { SIGHUP, "sighup", "hangup"}, +#endif +#ifdef SIGILL + { SIGILL, "sigill", "illegal instruction"}, +#endif + +/* We don't want a default message for SIGINT. */ +#ifdef SIGINT + { SIGINT, "sigint", ""}, +#endif + +#ifdef SIGIO + { SIGIO, "sigio", "socket i/o possible"}, +#endif +#ifdef SIGIOT + { SIGIOT, "sigiot", "iot instruction"}, +#endif +#ifdef SIGKILL + { SIGKILL, "sigkill", "killed"}, +#endif +#ifdef SIGLOST + { SIGLOST, "siglost", "resource lost"}, +#endif +#ifdef SIGLWP + { SIGLWP, "siglwp", "thread library signal"}, +#endif + +/* By default, SIGPIPEs are silent. */ +#ifdef SIGPIPE + { SIGPIPE, "sigpipe", ""}, +#endif + +#ifdef SIGPOLL + { SIGPOLL, "sigpoll", "pollable event occurred"}, +#endif +#ifdef SIGPROF + { SIGPROF, "sigprof", "profiling timer alarm"}, +#endif +#ifdef SIGPWR + { SIGPWR, "sigpwr", "power-fail restart"}, +#endif +#ifdef SIGQUIT + { SIGQUIT, "sigquit", "quit"}, +#endif +#ifdef SIGSEGV + { SIGSEGV, "sigsegv", "segmentation violation"}, +#endif +#ifdef SIGSTKFLT + { SIGSTKFLT, "sigstkflt", "stack fault"}, +#endif +#ifdef SIGSTOP + { SIGSTOP, "sigstop", "stopped by program"}, +#endif +#ifdef SIGSYS + { SIGSYS, "sigsys", "invalid argument to system call"}, +#endif +#ifdef SIGTERM + { SIGTERM, "sigterm", "terminated"}, +#endif +#ifdef SIGTHAW + { SIGTHAW, "sigthaw", "cpr thaw"}, +#endif +#ifdef SIGTRAP + { SIGTRAP, "sigtrap", "trace trap"}, +#endif +#ifdef SIGTSTP + { SIGTSTP, "sigtstp", "stopped"}, +#endif +#ifdef SIGTTIN + { SIGTTIN, "sigttin", "background tty read"}, +#endif +#ifdef SIGTTOU + { SIGTTOU, "sigttou", "background tty write"}, +#endif +#ifdef SIGURG + { SIGURG, "sigurg", "urgent condition on i/o channel"}, +#endif +#ifdef SIGUSR1 + { SIGUSR1, "sigusr1", "user defined signal 1"}, +#endif +#ifdef SIGUSR2 + { SIGUSR2, "sigusr2", "user defined signal 2"}, +#endif +#ifdef SIGVTALRM + { SIGVTALRM, "sigvtalrm", "virtual timer alarm"}, +#endif +#ifdef SIGWAITING + { SIGWAITING, "sigwaiting", "lwps blocked"}, +#endif +#ifdef SIGWINCH + { SIGWINCH, "sigwinch", "window size change"}, +#endif +#ifdef SIGWINDOW + { SIGWINDOW, "sigwindow", "window size change"}, +#endif +#ifdef SIGXCPU + { SIGXCPU, "sigxcpu", "exceeded cpu time limit"}, +#endif +#ifdef SIGXFSZ + { SIGXFSZ, "sigxfsz", "exceeded file size limit"}, +#endif +#ifdef SIGSAK + { SIGSAK, "sigsak", "secure attention key"}, +#endif +#ifdef SIGSOUND + { SIGSOUND, "sigsound", "hft sound sequence completed"}, +#endif +#ifdef SIGRETRACT + { SIGRETRACT, "sigretract", "hft monitor mode retracted"}, +#endif +#ifdef SIGKAP + { SIGKAP, "sigkap", "keep alive poll"}, +#endif +#ifdef SIGGRANT + { SIGGRANT, "siggrant", "hft monitor mode granted"}, +#endif +#ifdef SIGALRM1 + { SIGALRM1, "sigalrm1", "m:n condition alarm"}, +#endif +#ifdef SIGVIRT + { SIGVIRT, "sigvirt", "virtual time alarm"}, +#endif +#ifdef SIGPRE + { SIGPRE, "sigpre", "programming error"}, +#endif +#ifdef SIGMIGRATE + { SIGMIGRATE, "sigmigrate", "migrate process"}, +#endif +#ifdef SIGDANGER + { SIGDANGER, "sigdanger", "system crash imminent"}, +#endif +#ifdef SIGMSG + { SIGMSG, "sigmsg", "hft input data pending"}, +#endif +#ifdef SIGINFO + { SIGINFO, "siginfo", "information request"}, +#endif + { 0, 0, 0} +}; + +static void barf(char *msg) { + fprintf(stderr, "mksignals: %s\n", msg); + exit(1); +} + +int main(void) { + int maxsig = NUMSIG-1; + int s; + signaming *snp; + FILE *outf; + + for (snp = signamings; snp->signo; ++snp) + if (snp->signo > maxsig) + maxsig = snp->signo; + + outf = fopen("sigmsgs.h", "w"); + if (!outf) barf("could not open sigmsgs.h for writing"); + fprintf(outf, "typedef struct {\n"); + fprintf(outf, "\tchar *name, *msg;\n"); + fprintf(outf, "} Sigmsgs;\n"); + fprintf(outf, "extern Sigmsgs signals[];\n"); + fprintf(outf, "#define NUMOFSIGNALS %d\n", maxsig+1); + if (fclose(outf) == EOF) barf("could not fclose sigmsgs.h after writing"); + + outf = fopen("sigmsgs.c", "w"); + if (!outf) barf("could not open sigmsgs.c for writing"); + fprintf(outf, "#include \"sigmsgs.h\"\n\n"); + fprintf(outf, "Sigmsgs signals[] = {\n"); + fprintf(outf, "\t{\"\",\t\"\"},\n"); + + /* yes, we could avoid the quadratic searching with an aux array. fap. */ + for (s = 1; s <= maxsig; ++s) { + for (snp = signamings; snp->signo && snp->signo != s; ++snp) + /* */; + if (snp->signo) + fprintf(outf, "\t{\"%s\",\t\"%s\"},\n", + snp->signame, snp->sigmsg); + else + fprintf(outf, "\t{\"sigunknown%d\",\t\"unknown signal %d\"},\n", + s, s); + } + fprintf(outf, "};\n"); + if (fclose(outf) == EOF) barf("could not fclose sigmsgs.c after writing"); + return 0; +} diff --git a/nalloc.c b/nalloc.c index a809504..25e75a1 100644 --- a/nalloc.c +++ b/nalloc.c @@ -111,8 +111,8 @@ extern void restoreblock(Block *old) { /* generic memory allocation functions */ extern void *ealloc(size_t n) { - extern void *malloc(size_t); void *p = malloc(n); + if (p == NULL) { uerror("malloc"); rc_exit(1); @@ -121,8 +121,7 @@ extern void *ealloc(size_t n) { } extern void *erealloc(void *p, size_t n) { - extern void *realloc(void *, size_t); - if (p == NULL) /* convenience feature */ + if (p == NULL) /* erealloc() has POSIX realloc() semantics */ return ealloc(n); if ((p = realloc(p, n)) == NULL) { uerror("realloc"); @@ -132,8 +131,6 @@ extern void *erealloc(void *p, size_t n) { } extern void efree(void *p) { - extern void free(void *); if (p != NULL) free(p); } - diff --git a/open.c b/open.c index 2b6ee75..bac9f2c 100644 --- a/open.c +++ b/open.c @@ -1,7 +1,7 @@ /* open.c: to insulate from the rest of rc. */ -#include #include "rc.h" +#include /* Opens a file with the necessary flags. Assumes the following @@ -23,3 +23,23 @@ extern int rc_open(const char *name, redirtype m) { panic("bad mode passed to rc_open"); return open(name, mode_masks[m], 0666); } + +/* make a file descriptor blocking. return value indicates whether +the desciptor was previously set to non-blocking. */ + +extern bool makeblocking(int fd) { + int flags; + + if ((flags = fcntl(fd, F_GETFL)) == -1) { + uerror("fcntl"); + rc_error(NULL); + } + if (! (flags & O_NONBLOCK)) + return FALSE; + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, (long) flags) == -1) { + uerror("fcntl"); + rc_error(NULL); + } + return TRUE; +} diff --git a/parse.y b/parse.y index f1f5526..b1bcf85 100644 --- a/parse.y +++ b/parse.y @@ -6,9 +6,7 @@ %{ #include "rc.h" -#ifndef lint -#define lint /* hush up gcc -Wall, leave out the dumb sccsid's. */ -#endif + static Node *star, *nolist; Node *parsetree; /* not using yylval because bison declares it as an auto */ %} diff --git a/print.c b/print.c index e0dba12..9ccccc4 100644 --- a/print.c +++ b/print.c @@ -14,14 +14,14 @@ */ #define Flag(name, flag) \ -static bool name(Format *format, int c) { \ +static bool name(Format *format, int ignore) { \ format->flags |= flag; \ return TRUE; \ } Flag(uconv, FMT_unsigned) Flag(hconv, FMT_short) -Flag(lconv, FMT_long) +Flag(rc_lconv, FMT_long) #if HAVE_QUAD_T Flag(qconv, FMT_quad) @@ -41,7 +41,7 @@ static bool digitconv(Format *format, int c) { return TRUE; } -static bool zeroconv(Format *format, int c) { +static bool zeroconv(Format *format, int ignore) { if (format->flags & (FMT_f1set | FMT_f2set)) return digitconv(format, '0'); format->flags |= FMT_zeropad; @@ -53,7 +53,7 @@ static void pad(Format *format, size_t len, int c) { fmtputc(format, c); } -static bool sconv(Format *format, int c) { +static bool sconv(Format *format, int ignore) { char *s = va_arg(format->args, char *); if ((format->flags & FMT_f1set) == 0) fmtcat(format, s); @@ -151,32 +151,32 @@ static void intconv(Format *format, unsigned int radix, int upper, const char *a pad(format, padding, padchar); } -static bool cconv(Format *format, int c) { +static bool cconv(Format *format, int ignore) { fmtputc(format, va_arg(format->args, int)); return FALSE; } -static bool dconv(Format *format, int c) { +static bool dconv(Format *format, int ignore) { intconv(format, 10, 0, ""); return FALSE; } -static bool oconv(Format *format, int c) { +static bool oconv(Format *format, int ignore) { intconv(format, 8, 0, "0"); return FALSE; } -static bool xconv(Format *format, int c) { +static bool xconv(Format *format, int ignore) { intconv(format, 16, 0, "0x"); return FALSE; } -static bool pctconv(Format *format, int c) { +static bool pctconv(Format *format, int ignore) { fmtputc(format, '%'); return FALSE; } -static bool badconv(Format *format, int c) { +static bool badconv(Format *ignore, int ign0re) { panic("bad conversion character in printfmt"); /* NOTREACHED */ return FALSE; /* hush up gcc -Wall */ @@ -203,7 +203,7 @@ static void inittab(void) { fmttab['u'] = uconv; fmttab['h'] = hconv; - fmttab['l'] = lconv; + fmttab['l'] = rc_lconv; fmttab['#'] = altconv; fmttab['-'] = leftconv; fmttab['.'] = dotconv; @@ -289,16 +289,16 @@ extern int fmtprint(Format *format, const char *fmt,...) { va_list ap, saveargs; va_start(ap, fmt); - saveargs = format->args; - format->args = ap; + va_copy(saveargs, format->args); + va_copy(format->args, ap); n += printfmt(format, fmt); va_end(format->args); - format->args = saveargs; + va_copy(format->args, saveargs); return n + format->flushed; } -static void fprint_flush(Format *format, size_t more) { +static void fprint_flush(Format *format, size_t ignore) { size_t n = format->buf - format->bufbegin; char *buf = format->bufbegin; @@ -320,7 +320,7 @@ extern int fprint(int fd, const char *fmt,...) { format.u.n = fd; va_start(ap, fmt); - format.args = ap; + va_copy(format.args, ap); printfmt(&format, fmt); va_end(format.args); @@ -331,19 +331,20 @@ extern int fprint(int fd, const char *fmt,...) { static void memprint_grow(Format *format, size_t more) { char *buf; size_t len = format->bufend - format->bufbegin + 1; + size_t used = format->buf - format->bufbegin; + len = (len >= more) ? len * 2 : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1); if (format->u.n) buf = erealloc(format->bufbegin, len); else { - size_t used = format->buf - format->bufbegin; buf = nalloc(len); memcpy(buf, format->bufbegin, used); } - format->buf = buf + (format->buf - format->bufbegin); + format->buf = buf + used; format->bufbegin = buf; - format->bufend = buf + len - 1; + format->bufend = buf + len - 1; } static char *memprint(Format *format, const char *fmt, char *buf, size_t len) { @@ -364,7 +365,7 @@ extern char *mprint(const char *fmt,...) { format.u.n = 1; va_start(ap, fmt); - format.args = ap; + va_copy(format.args, ap); result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; @@ -377,106 +378,8 @@ extern char *nprint(const char *fmt,...) { format.u.n = 0; va_start(ap, fmt); - format.args = ap; + va_copy(format.args, ap); result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; } - - -/* THESE ARE UNUSED IN rc */ - -#if 0 - -extern int print(const char *fmt,...) { - char buf[1024]; - Format format; - - format.buf = buf; - format.bufbegin = buf; - format.bufend = buf + sizeof buf; - format.grow = fprint_flush; - format.flushed = 0; - format.u.n = 1; - - va_start(format.args, fmt); - printfmt(&format, fmt); - va_end(format.args); - - fprint_flush(&format, 0); - return format.flushed; -} - -extern int eprint(const char *fmt,...) { - char buf[1024]; - Format format; - - format.buf = buf; - format.bufbegin = buf; - format.bufend = buf + sizeof buf; - format.grow = fprint_flush; - format.flushed = 0; - format.u.n = 2; - - va_start(format.args, fmt); - printfmt(&format, fmt); - va_end(format.args); - - fprint_flush(&format, 0); - return format.flushed; -} - -static void snprint_grow(Format *format, size_t more) { - longjmp(format->u.p, 1); -} - -extern int snprint(char *buf, int buflen, const char *fmt,...) { - int n; - jmp_buf jbuf; - Format format; - - if (setjmp(jbuf)) { - *format.buf = '\0'; - return format.buf - format.bufbegin; - } - - format.buf = buf; - format.bufbegin = buf; - format.bufend = buf + buflen - 1; - format.grow = snprint_grow; - format.flushed = 0; - format.u.p = jbuf; - - va_start(format.args, fmt); - n = printfmt(&format, fmt); - va_end(format.args); - - *format.buf = '\0'; - return n; -} - -extern int sprint(char *buf, const char *fmt,...) { - int n; - jmp_buf jbuf; - Format format; - - if (setjmp(jbuf)) { - *format.buf = '\0'; - return format.buf - format.bufbegin; - } - - format.buf = buf; - format.bufbegin = buf; - format.bufend = buf + SPRINT_BUFSIZ - 1; - format.grow = snprint_grow; - format.flushed = 0; - format.u.p = jbuf; - - va_start(format.args, fmt); - n = printfmt(&format, fmt); - va_end(format.args); - - *format.buf = '\0'; - return n; -} -#endif diff --git a/proto.h b/proto.h index 4e0fb5a..82e5cb7 100644 --- a/proto.h +++ b/proto.h @@ -1,25 +1,42 @@ +/* + The idea of this file is to include prototypes for all external + functions that rc uses, either by including the appropriate header + file, or---for older systems---declaring the functions directly. +*/ + +#if HAVE_SYS_TYPES_H +#include +#endif + +#include + #if HAVE_QUAD_T typedef quad_t align_t; #else typedef long align_t; #endif -/* If you need to change this, please let the maintainer know. */ -#ifndef SIG_ATOMIC_T -typedef int SIG_ATOMIC_T; -#endif +/* + We need . If you really need to build rc on a system which + doesn't have it, please contact the maintainer. +*/ -#if STDC_HEADERS -#include -#else -/* fake stdlib.h */ -extern void exit(int); -extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); +#include + +/* C 9x specifies a va_copy() macro which should be used for copying +objects of type va_list. Of course, most places don't have this yet, +but where it does exist we need to use it. */ +#ifndef va_copy +#define va_copy(x,y) (x)=(y) #endif #if STDC_HEADERS + +#include #include -#else + +#else /* STDC_HEADERS */ + /* fake string.h */ extern int strncmp(const char *, const char *, size_t); extern int strcmp(const char *, const char *); @@ -32,8 +49,39 @@ extern char *strcat(char *, const char *); extern char *strncat(char *, const char *, size_t); extern void *memcpy(void *, const void *, size_t); extern void *memset(void *, int, size_t); + +/* fake stdlib.h */ +extern void exit(int); +extern void free(void *); +extern void *malloc(size_t); +extern void *realloc(void *, size_t); +extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); + +#endif /* STDC_HEADERS */ + +#if HAVE_UNISTD_H +#include #endif +#if HAVE_SETPGRP + +#if SETPGRP_VOID +/* Smells like POSIX: should all be ok. */ +#else +/* BSD: fake it. */ +#define setpgid(pid, pgrp) setpgrp(pid, pgrp) +#define tcsetpgrp(fd, pgrp) ioctl((fd), TIOCSPGRP, &(pgrp)) +#endif + +#else /* HAVE_SETPGRP */ + +/* Nothing doing. */ +#define setpgid() +#define tcsetpgrp() + +#endif /*HAVE_SETPGRP */ + + /* fake errno.h for mips (which doesn't declare errno in errno.h!?!?) */ #ifdef host_mips extern int errno; diff --git a/rc.1 b/rc.1 index 140eb66..8353340 100644 --- a/rc.1 +++ b/rc.1 @@ -35,7 +35,7 @@ .\" troff will supply the correct intersentence spacing, but only if .\" the sentences end at the end of a line. Explicit spaces, if given, .\" are apparently honored and the normal intersentence spacing is -.\" supressed. +.\" suppressed. .\" .\" DaviD W. Sanderson .\"------- @@ -166,7 +166,7 @@ rc \- shell .SH SYNOPSIS .B rc -.RB [ \-eixvldnpo ] +.RB [ \-eixvldnpoV ] .RB [ \-c .IR command ] .RI [ arguments ] @@ -300,6 +300,11 @@ Any further arguments to .I rc are placed in .Cr $* . +.TP +.Cr \-V +This flag causes +.I rc +to print a version string to stdout, and exit immediately. .PP .SH COMMANDS A simple command is a sequence of words, separated by white space @@ -1628,19 +1633,28 @@ is specified, .I rc waits for all child processes to exit. .TP -\fBwhatis \fR[\fB\-s\fR] [\fB\-\|\-\fR] [\fIname ...\fR] +\fBwhatis \fR[\fB\-b\fR] \fR[\fB\-f\fR] \fR[\fB\-p\fR] \fR[\fB\-s\fR] \fR[\fB\-v\fR] [\fB\-\|\-\fR] [\fIname ...\fR] Prints a definition of the named objects. -For variables, their values -are printed; for functions, their definitions are; and for executable -files, path names are printed. +For builtins, +.B builtin +.I foo +is printed; for functions, including signal handlers, their definitions +are printed; for executable files, path names are printed; and for +variables, their values are printed. +The options restrict output to builtins, functions, executable +programs, signal handlers, and variables, respectively. If no +.IR name s +are specified, +.I rc +lists all objects of that type. (This is not permitted for +.BR -p .) Without arguments, .B whatis -prints the values of all shell variables and functions. -With a -.Cr \-s -argument, -.B whatis -also prints out a list of available signals and their handlers (if any). +is equivalent to +.BR "whatis -fv" , +and prints the values of all shell variables and functions. +.TP +\& Note that .B whatis output is suitable for input to @@ -1788,8 +1802,16 @@ The design of this shell has been copied from the .I rc that Tom Duff wrote at Bell Labs. .SH BUGS -On systems that support -.Cr /dev/fd , +Environment variables that contain the ASCII character SOH (also known +as '\\001', or CTRL-A) will be split into lists at that character in +descendant +.IR rc +processes. +.PP +On modern systems that support +.Cr /dev/fd +or +.Cr /proc/self/fd , .Cr <{foo} style redirection is implemented that way. However, on other systems it is implemented with named pipes, @@ -1818,7 +1840,7 @@ notation for flattening should allow for using an arbitrary separating character, not just space. .PP Bug reports should be mailed to -.Cr "byron@archone.tamu.edu" . +.Cr "" . .SH INCOMPATIBILITIES Here is a list of features which distinguish this incarnation of .I rc @@ -1841,12 +1863,19 @@ a backquote must always be followed by a left-brace. This restriction is not present for single-word commands in this .IR rc . .PP +The list flattening operator, +.Cr $^foo , +is spelt +.Cr $"foo +in those versions of the Bell Labs +.IR rc +which have it. +.PP The following are all new with this version of .IR rc : The .Cr \-n option, -the list flattening operator, here strings (they facilitate exporting of functions with here documents into the environment), the diff --git a/rc.h b/rc.h index e540117..f582bd4 100644 --- a/rc.h +++ b/rc.h @@ -1,13 +1,4 @@ #include "config.h" - -#if HAVE_SYS_TYPES_H -#include -#endif - -#if HAVE_UNISTD_H -#include -#endif - #include "proto.h" /* datatypes */ @@ -16,31 +7,12 @@ #undef FALSE #undef TRUE -#include - -#if HAVE_SETPGRP - -#if SETPGRP_VOID -/* Smells like POSIX: should all be ok. */ -#else -/* BSD: fake it. */ -#define setpgid(pid, pgrp) setpgrp(pid, pgrp) -#define tcsetpgrp(fd, pgrp) ioctl((fd), TIOCSPGRP, &(pgrp)) -#endif - -#else /* HAVE_SETPGRP */ - -/* Nothing doing. */ -#define setpgid -#define tcsetpgrp - -#endif /*HAVE_SETPGRP */ typedef void builtin_t(char **); typedef struct Block Block; typedef struct Dup Dup; typedef struct Estack Estack; -typedef struct Function Function; +typedef struct rc_Function rc_Function; typedef struct Hq Hq; typedef struct Htab Htab; typedef struct Jbwrap Jbwrap; @@ -130,7 +102,7 @@ struct Rq { struct Rq *n; }; -struct Function { +struct rc_Function { Node *def; char *extdef; }; @@ -181,7 +153,7 @@ enum { #define memzero(s, n) memset(s, 0, n) #define enew(x) ((x *) ealloc(sizeof(x))) #define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1), x) -#define lookup_fn(s) ((Function *) lookup(s, fp)) +#define lookup_fn(s) ((rc_Function *) lookup(s, fp)) #define lookup_var(s) ((Variable *) lookup(s, vp)) #define nnew(x) ((x *) nalloc(sizeof(x))) #define ncpy(x) (strcpy((char *) nalloc(strlen(x) + 1), x)) @@ -194,7 +166,6 @@ enum { /* rc prototypes */ /* main.c */ -extern char *prompt, *prompt2; extern Rq *redirq; extern bool dashdee, dashee, dashvee, dashex, dashell, dasheye, dashen, dashpee, interactive; @@ -220,11 +191,18 @@ extern void sigint(int); extern void exec(List *, bool); extern void doredirs(void); +#if HASH_BANG +#define rc_execve execve +#else +/* execve.c */ +extern int my_execve(char *, char **, char **); +#endif + /* footobar.c */ extern char **list2array(List *, bool); extern char *get_name(char *); -extern List *parse_var(char *, char *); -extern Node *parse_fn(char *, char *); +extern List *parse_var(char *); +extern Node *parse_fn(char *); extern void initprint(void); extern void rc_exit(int); /* here for odd reasons; user-defined signal handlers are kept in fn.c */ @@ -251,7 +229,7 @@ extern List *word(char *, char *); /* hash.c */ extern Htab *fp, *vp; extern void *lookup(char *, Htab *); -extern Function *get_fn_place(char *); +extern rc_Function *get_fn_place(char *); extern List *varlookup(char *); extern Node *fnlookup(char *); extern Variable *get_var_place(char *, bool); @@ -282,6 +260,7 @@ extern int heredoc(int); extern int qdoc(Node *, Node *); extern Hq *hq; + /* input.c */ extern void initinput(void); extern Node *parseline(char *); @@ -289,6 +268,7 @@ extern int gchar(void); extern void ugchar(int); extern Node *doit(bool); extern void flushu(void); +extern void print_prompt2(void); extern void pushfd(int); extern void pushstring(char **, bool); extern void popinput(void); @@ -296,12 +276,12 @@ extern void closefds(void); extern int last; extern bool rcrc; + /* lex.c */ extern int yylex(void); extern void inityy(void); extern void yyerror(const char *); extern void scanerror(char *); -extern void print_prompt2(void); extern const char nw[], dnw[]; /* list.c */ @@ -324,6 +304,7 @@ extern void restoreblock(Block *); /* open.c */ extern int rc_open(const char *, redirtype); +extern bool makeblocking(int); /* print.c */ /* @@ -350,21 +331,56 @@ extern char *nprint(const char *fmt,...); *(f)->buf++ = (c);\ } -/* y.tab.c (parse.y) */ +/* parse.c (parse.y) */ extern Node *parsetree; extern int yyparse(void); extern void initparse(void); +/* readline */ + +#if READLINE + +/* Including the real readline .h files is too complicated, so we just +declare what we actually use. */ + +extern void add_history(char *); +extern char *readline(char *); +extern int rl_clear_signals(void); +extern int rl_pending_input; +extern int rl_reset_terminal(char *); + +#if READLINE_OLD +extern void rl_clean_up_for_exit(void); +extern void rl_deprep_terminal(void); +#else +extern void _rl_clean_up_for_exit(void); +extern void (*rl_deprep_term_function)(void); +#endif + +extern char *rc_readline(char *); + +extern volatile sig_atomic_t rl_active; +extern struct Jbwrap rl_buf; +#endif + +#if EDITLINE +extern char *readline(char *); +extern void add_history(char *); +#define rc_readline readline +#endif + + /* redir.c */ extern void doredirs(void); + /* signal.c */ extern void initsignal(void); extern void catcher(int); extern void sigchk(void); extern void (*rc_signal(int, void (*)(int)))(int); extern void (*sighandlers[])(int); -extern volatile SIG_ATOMIC_T slow, interrupt_happened; + /* status.c */ extern int istrue(void); @@ -377,6 +393,23 @@ extern void statprint(pid_t, int); extern void ssetstatus(char **); extern char *strstatus(int s); + +/* system.c or system-bsd.c */ +extern void writeall(int, char *, size_t); + +#if HAVE_RESTARTABLE_SYSCALLS +extern int rc_read(int, char *, size_t); +extern pid_t rc_wait(int *); +extern Jbwrap slowbuf; +extern volatile sig_atomic_t slow; + +#else /* HAVE_RESTARTABLE_SYSCALLS */ + +#define rc_read read +#define rc_wait wait +#endif /* HAVE_RESTARTABLE_SYSCALLS */ + + /* tree.c */ extern Node *mk(int /*nodetype*/,...); extern Node *treecpy(Node *, void *(*)(size_t)); @@ -385,13 +418,11 @@ extern void treefree(Node *); /* utils.c */ extern bool isabsolute(char *); extern int n2u(char *, unsigned int); -extern int rc_read(int, char *, size_t); extern int mvfd(int, int); extern int starstrcmp(const void *, const void *); -extern void pr_error(char *); +extern void pr_error(char *, int); extern void panic(char *); extern void uerror(char *); -extern void writeall(int, char *, size_t); /* wait.c */ extern pid_t rc_fork(void); @@ -403,4 +434,3 @@ extern bool forked; /* walk.c */ extern bool walk(Node *, bool); extern bool cond; - diff --git a/rlimit.h b/rlimit.h index f6e179b..f3c2e3d 100644 --- a/rlimit.h +++ b/rlimit.h @@ -3,40 +3,40 @@ #if HAVE_SETRLIMIT #if HAVE_SYS_RESOURCE_H -# include -# if RLIMIT_NEEDS_KERNEL -# define _KERNEL -# endif -# include -# if RLIMIT_NEEDS_KERNEL -# undef _KERNEL -# endif +#include +#if RLIMIT_NEEDS_KERNEL +#define _KERNEL +#endif +#include +#if RLIMIT_NEEDS_KERNEL +#undef _KERNEL +#endif #else -# include +#include #endif #if HAVE_LIMITS_H -# include +#include #endif #ifndef HAVE_RLIM_T -# if RLIM_T_IS_QUAD_T +#if RLIM_T_IS_QUAD_T typedef quad_t rlim_t; -# else +#else typedef long rlim_t; -# endif +#endif #endif #if HAVE_QUAD_T -# define RLIM_CONV quad_t -# define RLIM_FMT "%s \t%qd%s\n" +#define RLIM_CONV quad_t +#define RLIM_FMT "%s \t%qd%s\n" #else -# define RLIM_CONV long -# define RLIM_FMT "%s \t%ld%s\n" +#define RLIM_CONV long +#define RLIM_FMT "%s \t%ld%s\n" #endif #if defined(RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) -# define RLIMIT_NOFILE RLIMIT_OFILE +#define RLIMIT_NOFILE RLIMIT_OFILE #endif #endif /* HAVE_SETRLIMIT */ diff --git a/signal.c b/signal.c index 1c3f812..1c59746 100644 --- a/signal.c +++ b/signal.c @@ -2,32 +2,51 @@ #include #include + #include "rc.h" #include "sigmsgs.h" #include "jbwrap.h" -Jbwrap slowbuf; -volatile SIG_ATOMIC_T slow, interrupt_happened; +#if HAVE_SA_INTERRUPT +static void (*sys_signal(int signum, void (*handler)(int)))(int) { + struct sigaction new, old; + + new.sa_handler = handler; + new.sa_flags = SA_INTERRUPT; + sigaction(signum, &new, &old); + return old.sa_handler; +} +#else +#define sys_signal signal +#endif + void (*sighandlers[NUMOFSIGNALS])(int); -static volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS]; +static volatile sig_atomic_t sigcount, caught[NUMOFSIGNALS]; extern void catcher(int s) { if (caught[s] == 0) { sigcount++; caught[s] = 1; } - signal(s, catcher); - interrupt_happened = TRUE; -#ifndef HAVE_RESTARTABLE_SYSCALLS - if (slow) - longjmp(slowbuf.j, 1); + sys_signal(s, catcher); + +#if READLINE + if (rl_active) + siglongjmp(rl_buf.j, s); +#endif /* READLINE */ + +#if HAVE_RESTARTABLE_SYSCALLS + if (slow) { + siglongjmp(slowbuf.j, s); +} #endif } extern void sigchk() { void (*h)(int); int s, i; + if (sigcount == 0) return; /* ho hum; life as usual */ if (forked) @@ -53,11 +72,11 @@ extern void (*rc_signal(int s, void (*h)(int)))(int) { sigchk(); old = sighandlers[s]; if (h == SIG_DFL || h == SIG_IGN) { - signal(s, h); sighandlers[s] = h; + sys_signal(s, h); } else { sighandlers[s] = h; - signal(s, catcher); + sys_signal(s, catcher); } return old; } @@ -65,16 +84,18 @@ extern void (*rc_signal(int s, void (*h)(int)))(int) { extern void initsignal() { void (*h)(int); int i; + for (i = 1; i < NUMOFSIGNALS; i++) { - if ((h = signal(i, SIG_DFL)) != SIG_DFL) - signal(i, h); + h = sys_signal(i, SIG_DFL); + if (h != SIG_DFL && h != SIG_ERR) + sys_signal(i, h); sighandlers[i] = h; } -#ifdef SIGCLD +#if HAVE_SYSV_SIGCLD /* Ensure that SIGCLD is not SIG_IGN. Solaris's rshd does this. :-( */ - h = signal(SIGCLD, SIG_DFL); - if (h != SIG_IGN) - signal(SIGCLD, h); + h = sys_signal(SIGCLD, SIG_DFL); + if (h != SIG_IGN && h != SIG_ERR) + sys_signal(SIGCLD, h); #endif } diff --git a/status.c b/status.c index 428e414..b594e4b 100644 --- a/status.c +++ b/status.c @@ -2,6 +2,7 @@ #include "rc.h" #include "sigmsgs.h" +#include "wait.h" /* status == the wait() value of the last command in the pipeline, or the last command */ @@ -33,7 +34,9 @@ extern int getstatus() { if (pipelength > 1) return !istrue(); s = statuses[0]; - return (s&0xff) ? 1 : (s >> 8) & 0xff; + if (WIFSIGNALED(s)) + return 1; + return WEXITSTATUS(s); } extern void set(bool code) { @@ -61,11 +64,12 @@ extern void setstatus(pid_t pid, int i) { /* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */ extern void statprint(pid_t pid, int i) { - if (i & 0xff) { - char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f].msg : ""); + if (WIFSIGNALED(i)) { + int t = WTERMSIG(i); + char *msg = ((t > 0) && (t < NUMOFSIGNALS) ? signals[WTERMSIG(i)].msg : ""); if (pid != -1) fprint(2, "%ld: ", (long)pid); - if (i & 0x80) { + if (myWIFDUMPED(i)) { if (*msg == '\0') fprint(2, "core dumped\n"); else @@ -97,16 +101,15 @@ extern List *sgetstatus() { /* return status as a string (used above and for bqstatus) */ extern char *strstatus(int s) { - int t = s & 0x7f; - - if (t != 0) { - const char *core = (s & 0x80) ? "+core" : ""; - if (t < NUMOFSIGNALS && *signals[t].name != '\0') + if (WIFSIGNALED(s)) { + int t = WTERMSIG(s); + const char *core = myWIFDUMPED(s) ? "+core" : ""; + if ((t > 0) && (t < NUMOFSIGNALS) && *signals[t].name != '\0') return nprint("%s%s", signals[t].name, core); else return nprint("-%d%s", t, core); /* unknown signals are negated */ } else - return nprint("%d", (s >> 8) & 0xff); + return nprint("%d", WEXITSTATUS(s)); } extern void ssetstatus(char **av) { diff --git a/system-bsd.c b/system-bsd.c new file mode 100644 index 0000000..3babaea --- /dev/null +++ b/system-bsd.c @@ -0,0 +1,60 @@ +/* signal-safe read and write (for BSD slow devices). writeall() also +allows partial writes */ + +#include + +#include "rc.h" +#include "jbwrap.h" +#include "wait.h" + +Jbwrap slowbuf; +volatile sig_atomic_t slow; + +static char *safe_buf; +static size_t safe_remain; + +extern void writeall(int fd, char *buf, size_t remain) { + int i; + + safe_buf = buf; + safe_remain = remain; + for (i = 0; safe_remain > 0; buf += i, safe_remain -= i) { + if (sigsetjmp(slowbuf.j, 1) == 0) { + slow = TRUE; + if ((i = write(fd, safe_buf, safe_remain)) <= 0) + break; /* abort silently on errors in write() */ + } else + break; + } + slow = FALSE; + sigchk(); +} + +extern int rc_read(int fd, char *buf, size_t n) { + ssize_t r; + + if (sigsetjmp(slowbuf.j, 1) == 0) { + slow = TRUE; + r = read(fd, buf, n); + } else { + errno = EINTR; + r = -1; + } + slow = FALSE; + + return r; +} + +static int r = -1; +extern pid_t rc_wait(int *stat) { + if (sigsetjmp(slowbuf.j, 1) == 0) { + slow = TRUE; + r = wait(stat); + } else { + errno = EINTR; + r = -1; + } + slow = FALSE; + + return r; +} diff --git a/system.c b/system.c new file mode 100644 index 0000000..edc0e0f --- /dev/null +++ b/system.c @@ -0,0 +1,10 @@ +#include "rc.h" + +extern void writeall(int fd, char *buf, size_t remain) { + int i; + + for (i = 0; remain > 0; buf += i, remain -= i) + if ((i = write(fd, buf, remain)) <= 0) + break; /* abort silently on errors in write() */ + sigchk(); +} diff --git a/trip.rc b/trip.rc index 64d660f..717b0a2 100644 Binary files a/trip.rc and b/trip.rc differ diff --git a/tripping.c b/tripping.c new file mode 100644 index 0000000..911d229 --- /dev/null +++ b/tripping.c @@ -0,0 +1,33 @@ +/* This is an auxiliary test program for rc. */ + +#include +#include + +void out0(void) { + putchar('t'); putchar('r'); + putchar('\0'); + putchar('u'); putchar('e'); + putchar('\n'); +} + +void makenonblock(void) { + int flags; + + if ((flags = fcntl(0, F_GETFL)) == -1) + perror("fcntl 1"); + flags |= O_NONBLOCK; + if (fcntl(0, F_SETFL, (long) flags) == -1) + perror("fcntl 2"); +} + +int main(int argc, char **argv) { + switch(argv[1][0]) { + case '0': + out0(); + break; + case 'n': + makenonblock(); + break; + } + return 0; +} diff --git a/utils.c b/utils.c index 71ef61b..ded0c03 100644 --- a/utils.c +++ b/utils.c @@ -7,12 +7,12 @@ /* print error with line number on noninteractive shells (i.e., scripts) */ -extern void pr_error(char *s) { +extern void pr_error(char *s, int offset) { if (s != NULL) { if (interactive) fprint(2, "%s\n", s); else - fprint(2, "line %d: %s\n", lineno - 1, s); + fprint(2, "line %d: %s\n", lineno + offset, s); } } @@ -65,44 +65,6 @@ extern bool isabsolute(char *path) { return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/'))); } -/* signal-safe read and write (for BSD slow devices). writeall also allows partial writes */ - -extern void writeall(int fd, char *buf, size_t remain) { - int i; - for (i = 0; remain > 0; buf += i, remain -= i) { - interrupt_happened = FALSE; - if (!setjmp(slowbuf.j)) { - slow = TRUE; - if (interrupt_happened) - break; - else if ((i = write(fd, buf, remain)) <= 0) - break; /* abort silently on errors in write() */ - } else - break; - slow = FALSE; - } - slow = FALSE; - sigchk(); -} - -extern int rc_read(int fd, char *buf, size_t n) { - long /*ssize_t*/ r; - interrupt_happened = FALSE; - if (!setjmp(slowbuf.j)) { - slow = TRUE; - if (!interrupt_happened) - r = read(fd, buf, n); - else - r = -2; - } else - r = -2; - slow = FALSE; - if (r == -2) { - errno = EINTR; - r = -1; - } - return r; -} /* duplicate a fd and close the old one only if necessary */ diff --git a/var.c b/var.c index b0bc60b..8ef453b 100644 --- a/var.c +++ b/var.c @@ -18,11 +18,9 @@ extern void varassign(char *name, List *def, bool stack) { new = get_var_place(name, stack); new->def = newdef; new->extdef = NULL; -#if READLINE /* need to reset readline() every time TERM or TERMCAP changes */ - if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) { - extern void rl_reset_terminal(char *); +#if READLINE + if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) rl_reset_terminal(NULL); - } #endif } @@ -85,7 +83,7 @@ extern List *varlookup(char *name) { return look->def; if (look->extdef == NULL) return NULL; /* variable was set to null, e.g., a=() echo foo */ - ret = parse_var(name, look->extdef); + ret = parse_var(look->extdef); if (ret == NULL) { look->extdef = NULL; return NULL; diff --git a/version.c b/version.c deleted file mode 100644 index 68b5dc1..0000000 --- a/version.c +++ /dev/null @@ -1 +0,0 @@ -const char id[] = "@(#)rc version 1.5b2, 1997-07-01."; diff --git a/version.c.in b/version.c.in new file mode 100644 index 0000000..967f0eb --- /dev/null +++ b/version.c.in @@ -0,0 +1 @@ +const char id[] = "@(#)@PACKAGE@ version @VERSION@, @RELDATE@."; diff --git a/wait.c b/wait.c index 171d97e..66c5097 100644 --- a/wait.c +++ b/wait.c @@ -1,15 +1,10 @@ -#include "rc.h" - #include -#include -#include -#include "jbwrap.h" +#include "rc.h" +#include "wait.h" bool forked = FALSE; -static pid_t rc_wait(int *); - typedef struct Pid Pid; static struct Pid { @@ -21,7 +16,9 @@ static struct Pid { extern pid_t rc_fork() { Pid *new; + struct Pid *p, *q; pid_t pid = fork(); + switch (pid) { case -1: uerror("fork"); @@ -30,6 +27,14 @@ extern pid_t rc_fork() { case 0: forked = TRUE; sigchk(); + p = plist; q = 0; + while (p) { + if (q) efree(q); + q = p; + p = p->n; + } + if (q) efree(q); + plist = 0; return 0; default: new = enew(Pid); @@ -43,34 +48,44 @@ extern pid_t rc_fork() { extern pid_t rc_wait4(pid_t pid, int *stat, bool nointr) { Pid *r, *prev; - int ret; - /* first look for a child which may already have exited */ -again: for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n) + + /* Find the child on the list. */ + for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n) if (r->pid == pid) break; + + /* Uh-oh, not there. */ if (r == NULL) { errno = ECHILD; /* no children */ uerror("wait"); *stat = 0x100; /* exit(1) */ return -1; } - if (r->alive) { - while (pid != (ret = rc_wait(stat))) { - Pid *q; - if (ret < 0) { - if (nointr) - goto again; + + /* If it's still alive, wait() for it. */ + while (r->alive) { + int ret; + Pid *q; + + ret = rc_wait(stat); + + if (ret < 0) { + if (errno == ECHILD) + panic("lost child"); + if (nointr) + continue; + else return ret; - } - for (q = plist; q != NULL; q = q->n) - if (q->pid == ret) { - q->alive = FALSE; - q->stat = *stat; - break; - } } - } else - *stat = r->stat; + + for (q = plist; q != NULL; q = q->n) + if (q->pid == ret) { + q->alive = FALSE; + q->stat = *stat; + break; + } + } + *stat = r->stat; if (prev == NULL) plist = r->n; /* remove element from head of list */ else @@ -97,33 +112,16 @@ extern List *sgetapids() { extern void waitforall() { int stat; + while (plist != NULL) { - int pid = rc_wait4(plist->pid, &stat, FALSE); + pid_t pid = rc_wait4(plist->pid, &stat, FALSE); if (pid > 0) setstatus(pid, stat); - else + else { set(FALSE); + if (errno == EINTR) + return; + } sigchk(); } } - -/* - rc_wait: a wait() wrapper that interfaces wait() w/rc signals. - Note that the signal queue is not checked in this fn; someone - may want to resume the wait() without delivering any signals. -*/ - -static pid_t rc_wait(int *stat) { - int r; - interrupt_happened = FALSE; - if (!setjmp(slowbuf.j)) { - slow = TRUE; - if (!interrupt_happened) - r = wait(stat); - else - r = -1; - } else - r = -1; - slow = FALSE; - return r; -} diff --git a/wait.h b/wait.h new file mode 100644 index 0000000..e54ae45 --- /dev/null +++ b/wait.h @@ -0,0 +1,23 @@ +#if HAVE_SYS_WAIT_H +#include +#endif + +/* Fake the POSIX wait() macros if we don't have them. */ +#ifndef WIFEXITED +#define WIFEXITED(s) (((s) & 0xFF) == 0) +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(s) (((unsigned)(s) >> 8) && 0xFF) +#endif +#ifndef WIFSIGNALED +#define WIFSIGNALED(s) (((s) & 0xFF) != 0) +#endif +#ifndef WTERMSIG +#define WTERMSIG(s) ((s) & 0x7F) +#endif + +/* These don't exist in POSIX. */ +#define myWIFDUMPED(s) (((s) & 0x80) != 0) + + + diff --git a/walk.c b/walk.c index ed9f965..2f725d6 100644 --- a/walk.c +++ b/walk.c @@ -108,7 +108,7 @@ top: sigchk(); cond = oldcond; break; } - if (setjmp(j.j)) + if (sigsetjmp(j.j, 1)) break; jbreak.jb = &j; except(eBreak, jbreak, &e1); @@ -131,7 +131,7 @@ top: sigchk(); Jbwrap j; Estack e1, e2; Edata jbreak; - if (setjmp(j.j)) + if (sigsetjmp(j.j, 1)) break; jbreak.jb = &j; except(eBreak, jbreak, &e1); @@ -148,6 +148,7 @@ top: sigchk(); } case nSubshell: if (dofork(TRUE)) { + setsigdefaults(FALSE); walk(n->u[0].p, FALSE); rc_exit(getstatus()); } diff --git a/which.c b/which.c index 372cc92..9a6e1bb 100644 --- a/which.c +++ b/which.c @@ -9,18 +9,17 @@ */ #include "rc.h" + #include -#include #include -#include + +#include "getgroups.h" #define X_USR 0100 #define X_GRP 0010 #define X_OTH 0001 #define X_ALL (X_USR|X_GRP|X_OTH) -extern int stat(const char *, struct stat *); - static bool initialized = FALSE; static uid_t uid; static gid_t gid; @@ -32,7 +31,7 @@ static GETGROUPS_T *gidset; /* determine whether gid lies in gidset */ static int ingidset(gid_t g) { - gid_t i; + int i; for (i = 0; i < ngroups; ++i) if (g == gidset[i]) return 1; @@ -87,12 +86,17 @@ extern char *which(char *name, bool verbose) { uid = geteuid(); gid = getegid(); #if HAVE_GETGROUPS - ngroups = getgroups(0, (gid_t *)0); - gidset = malloc(ngroups * sizeof(gid_t)); - if (!gidset) - uerror("malloc"); - else - getgroups(ngroups, gidset); +#if HAVE_POSIX_GETGROUPS + ngroups = getgroups(0, (GETGROUPS_T *)0); + if (ngroups < 0) { + uerror("getgroups"); + rc_exit(1); + } +#else + ngroups = NGROUPS; +#endif + gidset = ealloc(ngroups * sizeof(GETGROUPS_T)); + getgroups(ngroups, gidset); #endif } if (isabsolute(name)) /* absolute pathname? */ diff --git a/y.tab.c b/y.tab.c deleted file mode 100644 index 4538689..0000000 --- a/y.tab.c +++ /dev/null @@ -1,1070 +0,0 @@ -#ifndef lint -static char const yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; -#endif -#define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define YYLEX yylex() -#define YYEMPTY -1 -#define yyclearin (yychar=(YYEMPTY)) -#define yyerrok (yyerrflag=0) -#define YYRECOVERING (yyerrflag!=0) -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif -#ifdef __cplusplus -extern "C" { char *getenv(const char *); } -#else -extern char *getenv(); -extern int yylex(); -extern int yyparse(); -#endif -#define YYPREFIX "yy" -#line 8 "parse.y" -#include "rc.h" -#ifndef lint -#define lint /* hush up gcc -Wall, leave out the dumb sccsid's. */ -#endif -static Node *star, *nolist; -Node *parsetree; /* not using yylval because bison declares it as an auto */ -#line 28 "parse.y" -typedef union { - struct Node *node; - struct Redir redir; - struct Pipe pipe; - struct Dup dup; - struct Word word; - char *keyword; -} YYSTYPE; -#line 43 "y.tab.c" -#define ANDAND 257 -#define BACKBACK 258 -#define BANG 259 -#define CASE 260 -#define COUNT 261 -#define DUP 262 -#define ELSE 263 -#define END 264 -#define FLAT 265 -#define FN 266 -#define FOR 267 -#define IF 268 -#define IN 269 -#define OROR 270 -#define PIPE 271 -#define REDIR 272 -#define SREDIR 273 -#define SUB 274 -#define SUBSHELL 275 -#define SWITCH 276 -#define TWIDDLE 277 -#define WHILE 278 -#define WORD 279 -#define HUH 280 -#define YYERRCODE 256 -const short yylhs[] = { -1, - 0, 0, 22, 22, 8, 8, 13, 13, 3, 3, - 9, 9, 4, 15, 2, 11, 11, 16, 16, 16, - 5, 5, 6, 6, 6, 19, 19, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 24, 24, 18, 18, 18, - 12, 12, 17, 17, 20, 20, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 21, 21, - 14, 14, 14, 23, 23, -}; -const short yylen[] = { 2, - 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, - 1, 2, 3, 3, 3, 0, 2, 1, 2, 2, - 3, 3, 1, 2, 2, 1, 4, 0, 1, 2, - 4, 8, 6, 4, 8, 4, 4, 4, 4, 2, - 2, 3, 3, 3, 2, 0, 1, 1, 2, 2, - 1, 3, 1, 1, 1, 3, 2, 5, 2, 2, - 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, - 0, 2, 2, 0, 2, -}; -const short yydefred[] = { 0, - 0, 0, 0, 0, 18, 0, 79, 0, 0, 0, - 0, 0, 0, 0, 0, 67, 0, 0, 81, 0, - 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, - 3, 4, 2, 77, 75, 74, 73, 68, 71, 69, - 0, 78, 72, 76, 70, 54, 53, 55, 0, 47, - 0, 59, 60, 0, 0, 0, 84, 66, 0, 0, - 0, 0, 0, 84, 0, 0, 0, 11, 0, 0, - 62, 61, 0, 0, 30, 0, 84, 84, 84, 5, - 6, 8, 0, 0, 1, 0, 50, 0, 0, 63, - 64, 0, 44, 0, 0, 0, 0, 0, 0, 0, - 0, 79, 13, 12, 10, 65, 82, 0, 17, 0, - 0, 0, 0, 52, 56, 79, 84, 14, 85, 0, - 0, 31, 84, 0, 0, 0, 0, 0, 39, 0, - 0, 84, 0, 58, 84, 0, 0, 0, 0, 0, - 79, 0, 0, 0, 0, 0, 0, 24, 35, 25, - 22, 21, -}; -const short yydgoto[] = { 21, - 46, 22, 66, 23, 142, 143, 67, 68, 69, 47, - 75, 27, 28, 70, 57, 29, 48, 30, 122, 94, - 54, 33, 97, 51, -}; -const short yysindex[] = { 874, - 24, 1001, -82, 1001, 0, 1001, 0, -27, -26, 900, - 1001, -82, -20, -82, -26, 0, 1001, 1134, 0, 900, - 0, 1134, -203, -30, 1134, 0, -55, 24, 1134, 826, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -66, 0, 0, 0, 0, 0, 0, 0, 849, 0, - 1134, 0, 0, 900, 1001, 1134, 0, 0, -52, -52, - 1134, 1001, 1001, 0, -212, -58, 154, 0, 1134, 426, - 0, 0, -196, 1001, 0, -203, 0, 0, 0, 0, - 0, 0, 1001, 1001, 0, -196, 0, -52, 1001, 0, - 0, -196, 0, -52, -38, 36, 502, -196, -36, -52, - 502, 0, 0, 0, 0, 0, 0, -52, 0, 502, - 502, 502, -52, 0, 0, 0, 0, 0, 0, -97, - -234, 0, 0, 1001, -234, 922, -196, -196, 0, 944, - 502, 0, -9, 0, 0, -234, 502, 967, 502, -234, - 0, 967, -45, 154, 967, -234, 448, 0, 0, 0, - 0, 0, -}; -const short yyrindex[] = { 134, - 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, - 0, 356, 0, 1024, 0, 0, 0, 571, 0, 0, - 0, 487, 529, 54, 134, 0, 62, 0, 487, 548, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 487, 0, 0, 712, 0, 142, 0, 0, 14, 38, - 487, 0, 0, 0, -10, 0, -32, 0, 744, 0, - 0, 0, 749, 0, 0, 529, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 763, 0, 86, 0, 0, - 0, 779, 0, 110, 0, 0, -34, 788, 0, 380, - -34, 0, 0, 0, 0, 0, 0, 470, 0, -34, - -34, -34, 404, 0, 0, 0, 0, 0, 0, 529, - 6, 0, 0, 724, 30, 0, 805, 813, 0, 0, - -34, 0, 0, 0, 0, 119, -34, 571, -34, 187, - 0, 571, 0, -44, 571, 396, 0, 0, 0, 0, - 0, 0, -}; -const short yygindex[] = { 0, - 0, 0, -23, 12, 0, -104, 1319, 2, -127, 1307, - 7, 0, 57, 0, 70, -13, 84, 0, 0, 420, - -81, 59, 369, 31, -}; -#define YYTABLESIZE 1464 -const short yytable[] = { 57, - 119, 25, 117, 28, 123, 83, 28, 81, 9, 76, - 145, 50, 55, 56, 145, 26, 87, 145, 124, 62, - 126, 58, 77, 19, 28, 57, 25, 57, 80, 57, - 57, 71, 96, 32, 130, 78, 79, 148, 84, 34, - 150, 89, 61, 26, 63, 105, 26, 20, 57, 19, - 57, 19, 58, 19, 19, 89, 18, 89, 5, 147, - 90, 102, 76, 7, 26, 93, 103, 34, 74, 11, - 34, 48, 19, 20, 79, 20, 118, 20, 20, 149, - 23, 82, 109, 57, 64, 57, 85, 52, 34, 53, - 28, 0, 9, 0, 0, 49, 20, 48, 0, 48, - 65, 48, 48, 72, 0, 0, 76, 0, 120, 19, - 0, 0, 57, 138, 57, 0, 0, 0, 0, 80, - 48, 49, 0, 49, 0, 49, 49, 0, 33, 0, - 26, 0, 91, 20, 0, 0, 19, 0, 19, 0, - 0, 0, 0, 28, 49, 80, 0, 80, 0, 80, - 80, 28, 0, 0, 34, 0, 33, 48, 0, 33, - 20, 0, 20, 104, 5, 132, 0, 114, 80, 0, - 0, 28, 115, 0, 74, 11, 0, 33, 0, 28, - 0, 49, 28, 0, 0, 0, 48, 0, 0, 0, - 0, 81, 28, 0, 0, 0, 27, 0, 0, 0, - 28, 0, 0, 0, 0, 80, 0, 0, 0, 0, - 49, 0, 80, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 28, 0, 27, 0, 77, 27, 0, 28, - 116, 0, 80, 0, 80, 28, 28, 0, 0, 78, - 79, 0, 0, 33, 0, 27, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 0, 57, 57, 57, 57, 57, 26, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 31, 19, 19, - 19, 19, 19, 34, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 27, 20, 20, 20, 20, 20, 7, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, - 48, 0, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, - 49, 49, 49, 49, 49, 46, 80, 80, 80, 80, - 80, 0, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 33, 0, 80, 80, 80, 80, 80, 79, - 28, 46, 0, 46, 0, 46, 46, 28, 28, 0, - 0, 0, 0, 28, 28, 32, 0, 0, 0, 0, - 77, 28, 28, 15, 46, 79, 0, 79, 0, 79, - 79, 49, 0, 78, 79, 0, 0, 0, 0, 59, - 60, 0, 101, 32, 0, 107, 32, 0, 79, 15, - 0, 15, 0, 15, 15, 110, 111, 112, 0, 88, - 27, 46, 0, 0, 32, 0, 0, 151, 0, 0, - 0, 17, 15, 0, 0, 19, 106, 0, 0, 0, - 0, 0, 0, 0, 95, 79, 0, 0, 46, 83, - 46, 99, 100, 17, 0, 131, 0, 19, 0, 108, - 0, 133, 0, 59, 0, 0, 28, 0, 0, 15, - 137, 0, 113, 139, 79, 83, 152, 0, 0, 83, - 83, 119, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 20, 0, 0, 28, 0, 15, 28, 15, 0, - 0, 0, 0, 0, 0, 0, 0, 17, 16, 0, - 0, 19, 0, 20, 0, 28, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, - 0, 0, 0, 0, 0, 83, 16, 0, 0, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 28, 0, 0, 0, 0, 29, 0, 16, 29, 0, - 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, - 0, 0, 0, 0, 0, 0, 29, 0, 28, 0, - 0, 28, 46, 46, 46, 0, 46, 46, 0, 46, - 46, 46, 46, 46, 18, 46, 46, 46, 46, 28, - 46, 46, 46, 46, 46, 0, 79, 79, 79, 79, - 79, 0, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 0, 16, 79, 79, 79, 79, 79, 32, - 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, - 15, 15, 29, 15, 15, 15, 15, 0, 15, 15, - 15, 15, 15, 2, 34, 35, 4, 0, 36, 0, - 6, 37, 38, 39, 40, 28, 0, 41, 0, 0, - 42, 43, 44, 45, 16, 2, 34, 35, 4, 0, - 36, 0, 6, 37, 38, 39, 40, 0, 0, 41, - 0, 45, 42, 43, 44, 45, 16, 83, 83, 83, - 83, 0, 83, 36, 83, 83, 83, 83, 83, 0, - 0, 83, 0, 28, 83, 83, 83, 83, 83, 45, - 28, 0, 45, 28, 0, 0, 28, 28, 41, 2, - 3, 36, 4, 5, 36, 0, 6, 7, 8, 9, - 45, 0, 40, 10, 11, 0, 12, 13, 14, 15, - 16, 28, 36, 0, 28, 16, 41, 0, 42, 41, - 0, 0, 16, 0, 0, 0, 0, 43, 16, 16, - 40, 0, 28, 40, 29, 0, 0, 41, 0, 0, - 0, 29, 0, 0, 37, 0, 42, 29, 29, 42, - 0, 40, 38, 0, 0, 43, 0, 28, 43, 0, - 0, 0, 0, 0, 0, 0, 45, 42, 0, 0, - 28, 28, 37, 0, 0, 37, 43, 0, 36, 0, - 38, 0, 0, 38, 0, 0, 0, 0, 0, 0, - 0, 17, 0, 37, 0, 19, 0, 0, 28, 0, - 0, 38, 0, 41, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 17, 0, 0, 40, 19, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 42, 0, 0, 0, 0, 0, 17, - 0, 0, 43, 19, 0, 0, 0, 0, 0, 0, - 0, 20, 0, 0, 0, 0, 0, 0, 0, 37, - 0, 0, 0, 0, 0, 17, 0, 38, 0, 19, - 0, 0, 89, 0, 20, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, - 0, 19, 134, 0, 0, 0, 0, 0, 45, 20, - 0, 18, 0, 0, 0, 45, 0, 0, 0, 17, - 36, 45, 45, 19, 135, 0, 0, 36, 0, 0, - 0, 0, 0, 36, 36, 20, 18, 0, 0, 0, - 28, 0, 17, 0, 0, 41, 19, 0, 0, 0, - 0, 0, 41, 28, 28, 0, 0, 20, 41, 40, - 0, 0, 18, 0, 0, 0, 40, 0, 0, 0, - 0, 0, 40, 0, 0, 42, 17, 0, 0, 20, - 19, 0, 42, 0, 43, 0, 0, 0, 42, 0, - 0, 43, 0, 0, 0, 0, 0, 43, 0, 46, - 0, 37, 20, 46, 0, 0, 0, 0, 37, 38, - 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, - 0, 0, 38, 2, 34, 35, 4, 5, 36, 18, - 6, 37, 38, 39, 40, 0, 20, 10, 11, 0, - 42, 43, 44, 45, 16, 0, 2, 34, 35, 4, - 0, 36, 0, 6, 37, 38, 39, 40, 0, 46, - 41, 0, 0, 42, 43, 44, 45, 16, 0, 1, - 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, - 8, 9, 0, 0, 0, 10, 11, 0, 12, 13, - 14, 15, 16, 0, 0, 0, 0, 2, 34, 35, - 4, 0, 36, 0, 6, 37, 38, 39, 40, 17, - 0, 41, 0, 19, 42, 43, 44, 45, 16, 2, - 34, 35, 4, 0, 36, 0, 6, 37, 38, 39, - 40, 0, 0, 41, 0, 0, 42, 43, 44, 45, - 16, 2, 34, 35, 4, 0, 36, 0, 6, 37, - 38, 39, 40, 0, 0, 41, 0, 0, 42, 43, - 44, 45, 16, 0, 2, 3, 141, 4, 5, 20, - 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, - 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 18, 0, 2, 34, - 35, 4, 0, 36, 0, 6, 37, 38, 39, 40, - 0, 0, 41, 0, 0, 42, 43, 44, 45, 16, - 0, 46, 46, 46, 46, 0, 46, 0, 46, 46, - 46, 46, 46, 0, 0, 46, 0, 0, 46, 46, - 46, 46, 46, 0, 0, 0, 26, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, - 0, 0, 0, 0, 26, 0, 0, 0, 26, 0, - 0, 26, 0, 0, 0, 26, 0, 0, 0, 0, - 73, 0, 0, 24, 0, 0, 0, 86, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, - 0, 0, 26, 0, 0, 0, 0, 26, 0, 92, - 0, 0, 0, 0, 0, 26, 0, 0, 0, 98, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, - 8, 9, 0, 26, 0, 10, 11, 26, 12, 13, - 14, 15, 16, 0, 0, 121, 26, 26, 26, 125, - 0, 0, 0, 0, 0, 0, 0, 0, 127, 128, - 129, 0, 0, 0, 0, 0, 0, 26, 0, 0, - 0, 0, 0, 26, 26, 26, 0, 0, 26, 136, - 0, 26, 0, 0, 0, 140, 144, 146, 0, 0, - 144, 0, 0, 144, -}; -const short yycheck[] = { 10, - 10, 0, 41, 38, 41, 61, 41, 38, 41, 23, - 138, 94, 40, 40, 142, 10, 30, 145, 100, 40, - 102, 10, 257, 10, 59, 36, 25, 38, 59, 40, - 41, 20, 56, 10, 116, 270, 271, 142, 94, 10, - 145, 94, 12, 38, 14, 69, 41, 10, 59, 36, - 61, 38, 41, 40, 41, 94, 123, 94, 262, 141, - 49, 274, 76, 10, 59, 54, 125, 38, 272, 273, - 41, 10, 59, 36, 271, 38, 41, 40, 41, 125, - 125, 25, 76, 94, 15, 96, 28, 4, 59, 6, - 125, -1, 125, -1, -1, 10, 59, 36, -1, 38, - 17, 40, 41, 20, -1, -1, 120, -1, 97, 96, - -1, -1, 123, 123, 125, -1, -1, -1, -1, 10, - 59, 36, -1, 38, -1, 40, 41, -1, 10, -1, - 125, -1, 49, 96, -1, -1, 123, -1, 125, -1, - -1, -1, -1, 10, 59, 36, -1, 38, -1, 40, - 41, 10, -1, -1, 125, -1, 38, 96, -1, 41, - 123, -1, 125, 10, 262, 263, -1, 84, 59, -1, - -1, 38, 89, -1, 272, 273, -1, 59, -1, 38, - -1, 96, 41, -1, -1, -1, 125, -1, -1, -1, - -1, 38, 59, -1, -1, -1, 10, -1, -1, -1, - 59, -1, -1, -1, -1, 96, -1, -1, -1, -1, - 125, -1, 59, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 257, -1, 38, -1, 257, 41, -1, 264, - 269, -1, 123, -1, 125, 270, 271, -1, -1, 270, - 271, -1, -1, 125, -1, 59, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, -1, 275, 276, 277, 278, 279, 264, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 264, 275, 276, - 277, 278, 279, 264, 257, 258, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, - 273, 125, 275, 276, 277, 278, 279, 264, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, -1, 275, 276, 277, 278, - 279, -1, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, -1, - 275, 276, 277, 278, 279, 10, 257, 258, 259, 260, - 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 264, -1, 275, 276, 277, 278, 279, 10, - 257, 36, -1, 38, -1, 40, 41, 264, 257, -1, - -1, -1, -1, 270, 271, 10, -1, -1, -1, -1, - 257, 270, 271, 10, 59, 36, -1, 38, -1, 40, - 41, 2, -1, 270, 271, -1, -1, -1, -1, 10, - 11, -1, 64, 38, -1, 10, 41, -1, 59, 36, - -1, 38, -1, 40, 41, 77, 78, 79, -1, 30, - 264, 96, -1, -1, 59, -1, -1, 10, -1, -1, - -1, 36, 59, -1, -1, 40, 41, -1, -1, -1, - -1, -1, -1, -1, 55, 96, -1, -1, 123, 10, - 125, 62, 63, 36, -1, 117, -1, 40, -1, 70, - -1, 123, -1, 74, -1, -1, 10, -1, -1, 96, - 132, -1, 83, 135, 125, 36, 59, -1, -1, 40, - 41, 10, -1, -1, -1, -1, -1, -1, -1, -1, - 125, 96, -1, -1, 38, -1, 123, 41, 125, -1, - -1, -1, -1, -1, -1, -1, -1, 36, 10, -1, - -1, 40, -1, 96, -1, 59, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, - -1, -1, -1, -1, -1, 96, 38, -1, -1, 41, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 10, -1, -1, -1, -1, 38, -1, 59, 41, -1, - -1, -1, -1, -1, -1, -1, -1, 96, -1, -1, - -1, -1, -1, -1, -1, -1, 59, -1, 38, -1, - -1, 125, 257, 258, 259, -1, 261, 262, -1, 264, - 265, 266, 267, 268, 123, 270, 271, 272, 273, 59, - 275, 276, 277, 278, 279, -1, 257, 258, 259, 260, - 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, -1, 125, 275, 276, 277, 278, 279, 264, - 257, 258, 259, -1, 261, 262, -1, 264, 265, 266, - 267, 268, 125, 270, 271, 272, 273, -1, 275, 276, - 277, 278, 279, 258, 259, 260, 261, -1, 263, -1, - 265, 266, 267, 268, 269, 125, -1, 272, -1, -1, - 275, 276, 277, 278, 279, 258, 259, 260, 261, -1, - 263, -1, 265, 266, 267, 268, 269, -1, -1, 272, - -1, 10, 275, 276, 277, 278, 279, 258, 259, 260, - 261, -1, 263, 10, 265, 266, 267, 268, 269, -1, - -1, 272, -1, 257, 275, 276, 277, 278, 279, 38, - 264, -1, 41, 10, -1, -1, 270, 271, 10, 258, - 259, 38, 261, 262, 41, -1, 265, 266, 267, 268, - 59, -1, 10, 272, 273, -1, 275, 276, 277, 278, - 279, 38, 59, -1, 41, 257, 38, -1, 10, 41, - -1, -1, 264, -1, -1, -1, -1, 10, 270, 271, - 38, -1, 59, 41, 257, -1, -1, 59, -1, -1, - -1, 264, -1, -1, 10, -1, 38, 270, 271, 41, - -1, 59, 10, -1, -1, 38, -1, 257, 41, -1, - -1, -1, -1, -1, -1, -1, 125, 59, -1, -1, - 270, 271, 38, -1, -1, 41, 59, -1, 125, -1, - 38, -1, -1, 41, -1, -1, -1, -1, -1, -1, - -1, 36, -1, 59, -1, 40, -1, -1, 125, -1, - -1, 59, -1, 125, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 36, -1, -1, 125, 40, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 125, -1, -1, -1, -1, -1, 36, - -1, -1, 125, 40, -1, -1, -1, -1, -1, -1, - -1, 96, -1, -1, -1, -1, -1, -1, -1, 125, - -1, -1, -1, -1, -1, 36, -1, 125, -1, 40, - -1, -1, 94, -1, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, - -1, 40, 41, -1, -1, -1, -1, -1, 257, 96, - -1, 123, -1, -1, -1, 264, -1, -1, -1, 36, - 257, 270, 271, 40, 41, -1, -1, 264, -1, -1, - -1, -1, -1, 270, 271, 96, 123, -1, -1, -1, - 257, -1, 36, -1, -1, 257, 40, -1, -1, -1, - -1, -1, 264, 270, 271, -1, -1, 96, 270, 257, - -1, -1, 123, -1, -1, -1, 264, -1, -1, -1, - -1, -1, 270, -1, -1, 257, 36, -1, -1, 96, - 40, -1, 264, -1, 257, -1, -1, -1, 270, -1, - -1, 264, -1, -1, -1, -1, -1, 270, -1, 36, - -1, 257, 96, 40, -1, -1, -1, -1, 264, 257, - -1, -1, -1, -1, 270, -1, 264, -1, -1, -1, - -1, -1, 270, 258, 259, 260, 261, 262, 263, 123, - 265, 266, 267, 268, 269, -1, 96, 272, 273, -1, - 275, 276, 277, 278, 279, -1, 258, 259, 260, 261, - -1, 263, -1, 265, 266, 267, 268, 269, -1, 96, - 272, -1, -1, 275, 276, 277, 278, 279, -1, 256, - -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, - 267, 268, -1, -1, -1, 272, 273, -1, 275, 276, - 277, 278, 279, -1, -1, -1, -1, 258, 259, 260, - 261, -1, 263, -1, 265, 266, 267, 268, 269, 36, - -1, 272, -1, 40, 275, 276, 277, 278, 279, 258, - 259, 260, 261, -1, 263, -1, 265, 266, 267, 268, - 269, -1, -1, 272, -1, -1, 275, 276, 277, 278, - 279, 258, 259, 260, 261, -1, 263, -1, 265, 266, - 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, - 277, 278, 279, -1, 258, 259, 260, 261, 262, 96, - -1, 265, 266, 267, 268, -1, -1, -1, 272, 273, - -1, 275, 276, 277, 278, 279, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 123, -1, 258, 259, - 260, 261, -1, 263, -1, 265, 266, 267, 268, 269, - -1, -1, 272, -1, -1, 275, 276, 277, 278, 279, - -1, 258, 259, 260, 261, -1, 263, -1, 265, 266, - 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, - 277, 278, 279, -1, -1, -1, 0, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, - -1, -1, -1, -1, 18, -1, -1, -1, 22, -1, - -1, 25, -1, -1, -1, 29, -1, -1, -1, -1, - 22, -1, -1, 25, -1, -1, -1, 29, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, - -1, -1, 56, -1, -1, -1, -1, 61, -1, 51, - -1, -1, -1, -1, -1, 69, -1, -1, -1, 61, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, - 267, 268, -1, 97, -1, 272, 273, 101, 275, 276, - 277, 278, 279, -1, -1, 97, 110, 111, 112, 101, - -1, -1, -1, -1, -1, -1, -1, -1, 110, 111, - 112, -1, -1, -1, -1, -1, -1, 131, -1, -1, - -1, -1, -1, 137, 138, 139, -1, -1, 142, 131, - -1, 145, -1, -1, -1, 137, 138, 139, -1, -1, - 142, -1, -1, 145, -}; -#define YYFINAL 21 -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif -#define YYMAXTOKEN 280 -#if YYDEBUG -char *yyname[] = { -"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,"'$'",0,"'&'",0,"'('","')'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0, -"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'^'",0, -"'`'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,"ANDAND","BACKBACK","BANG","CASE","COUNT","DUP","ELSE","END", -"FLAT","FN","FOR","IF","IN","OROR","PIPE","REDIR","SREDIR","SUB","SUBSHELL", -"SWITCH","TWIDDLE","WHILE","WORD","HUH", -}; -const char * const yyrule[] = { -"$accept : rc", -"rc : line end", -"rc : error end", -"end : END", -"end : '\\n'", -"cmdsa : cmd ';'", -"cmdsa : cmd '&'", -"line : cmd", -"line : cmdsa line", -"body : cmd", -"body : cmdsan body", -"cmdsan : cmdsa", -"cmdsan : cmd '\\n'", -"brace : '{' body '}'", -"paren : '(' body ')'", -"assign : first '=' word", -"epilog :", -"epilog : redir epilog", -"redir : DUP", -"redir : REDIR word", -"redir : SREDIR word", -"case : CASE words ';'", -"case : CASE words '\\n'", -"cbody : cmd", -"cbody : case cbody", -"cbody : cmdsan cbody", -"iftail : cmd", -"iftail : brace ELSE optnl cmd", -"cmd :", -"cmd : simple", -"cmd : brace epilog", -"cmd : IF paren optnl iftail", -"cmd : FOR '(' word IN words ')' optnl cmd", -"cmd : FOR '(' word ')' optnl cmd", -"cmd : WHILE paren optnl cmd", -"cmd : SWITCH '(' word ')' optnl '{' cbody '}'", -"cmd : TWIDDLE optcaret word words", -"cmd : cmd ANDAND optnl cmd", -"cmd : cmd OROR optnl cmd", -"cmd : cmd PIPE optnl cmd", -"cmd : redir cmd", -"cmd : assign cmd", -"cmd : BANG optcaret cmd", -"cmd : SUBSHELL optcaret cmd", -"cmd : FN words brace", -"cmd : FN words", -"optcaret :", -"optcaret : '^'", -"simple : first", -"simple : simple word", -"simple : simple redir", -"first : comword", -"first : first '^' sword", -"sword : comword", -"sword : keyword", -"word : sword", -"word : word '^' sword", -"comword : '$' sword", -"comword : '$' sword SUB words ')'", -"comword : COUNT sword", -"comword : FLAT sword", -"comword : '`' sword", -"comword : '`' brace", -"comword : BACKBACK word brace", -"comword : BACKBACK word sword", -"comword : '(' nlwords ')'", -"comword : REDIR brace", -"comword : WORD", -"keyword : FOR", -"keyword : IN", -"keyword : WHILE", -"keyword : IF", -"keyword : SWITCH", -"keyword : FN", -"keyword : ELSE", -"keyword : CASE", -"keyword : TWIDDLE", -"keyword : BANG", -"keyword : SUBSHELL", -"words :", -"words : words word", -"nlwords :", -"nlwords : nlwords '\\n'", -"nlwords : nlwords word", -"optnl :", -"optnl : optnl '\\n'", -}; -#endif -#ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE -#else -#ifdef YYMAXDEPTH -#define YYSTACKSIZE YYMAXDEPTH -#else -#define YYSTACKSIZE 500 -#define YYMAXDEPTH 500 -#endif -#endif -int yydebug; -int yynerrs; -int yyerrflag; -int yychar; -short *yyssp; -YYSTYPE *yyvsp; -YYSTYPE yyval; -YYSTYPE yylval; -short yyss[YYSTACKSIZE]; -YYSTYPE yyvs[YYSTACKSIZE]; -#define yystacksize YYSTACKSIZE -#line 169 "parse.y" - -void initparse() { - star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc); - nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc); -} - -#line 590 "y.tab.c" -#define YYABORT goto yyabort -#define YYREJECT goto yyabort -#define YYACCEPT goto yyaccept -#define YYERROR goto yyerrlab - -int -yyparse() -{ - register int yym, yyn, yystate; -#if YYDEBUG - register char *yys; - - if ((yys = getenv("YYDEBUG"))) - { - yyn = *yys; - if (yyn >= '0' && yyn <= '9') - yydebug = yyn - '0'; - } -#endif - - yynerrs = 0; - yyerrflag = 0; - yychar = (-1); - - yyssp = yyss; - yyvsp = yyvs; - *yyssp = yystate = 0; - -yyloop: - if ((yyn = yydefred[yystate])) goto yyreduce; - if (yychar < 0) - { - if ((yychar = yylex()) < 0) yychar = 0; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - } - if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, yystate, yytable[yyn]); -#endif - if (yyssp >= yyss + yystacksize - 1) - { - goto yyoverflow; - } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; - yychar = (-1); - if (yyerrflag > 0) --yyerrflag; - goto yyloop; - } - if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { - yyn = yytable[yyn]; - goto yyreduce; - } - if (yyerrflag) goto yyinrecovery; -#if defined(lint) || defined(__GNUC__) - goto yynewerror; -#endif -yynewerror: - yyerror("syntax error"); -#if defined(lint) || defined(__GNUC__) - goto yyerrlab; -#endif -yyerrlab: - ++yynerrs; -yyinrecovery: - if (yyerrflag < 3) - { - yyerrflag = 3; - for (;;) - { - if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); -#endif - if (yyssp >= yyss + yystacksize - 1) - { - goto yyoverflow; - } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; - goto yyloop; - } - else - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *yyssp); -#endif - if (yyssp <= yyss) goto yyabort; - --yyssp; - --yyvsp; - } - } - } - else - { - if (yychar == 0) goto yyabort; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - yychar = (-1); - goto yyloop; - } -yyreduce: -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, yystate, yyn, yyrule[yyn]); -#endif - yym = yylen[yyn]; - yyval = yyvsp[1-yym]; - switch (yyn) - { -case 1: -#line 49 "parse.y" -{ parsetree = yyvsp[-1].node; YYACCEPT; } -break; -case 2: -#line 50 "parse.y" -{ yyerrok; parsetree = NULL; YYABORT; } -break; -case 3: -#line 53 "parse.y" -{ if (!heredoc(1)) YYABORT; } -break; -case 4: -#line 54 "parse.y" -{ if (!heredoc(0)) YYABORT; } -break; -case 6: -#line 58 "parse.y" -{ yyval.node = (yyvsp[-1].node != NULL ? mk(nNowait,yyvsp[-1].node) : yyvsp[-1].node); } -break; -case 8: -#line 62 "parse.y" -{ yyval.node = (yyvsp[-1].node != NULL ? mk(nBody,yyvsp[-1].node,yyvsp[0].node) : yyvsp[0].node); } -break; -case 10: -#line 66 "parse.y" -{ yyval.node = (yyvsp[-1].node == NULL ? yyvsp[0].node : yyvsp[0].node == NULL ? yyvsp[-1].node : mk(nBody,yyvsp[-1].node,yyvsp[0].node)); } -break; -case 12: -#line 69 "parse.y" -{ yyval.node = yyvsp[-1].node; if (!heredoc(0)) YYABORT; } -break; -case 13: -#line 71 "parse.y" -{ yyval.node = yyvsp[-1].node; } -break; -case 14: -#line 73 "parse.y" -{ yyval.node = yyvsp[-1].node; } -break; -case 15: -#line 75 "parse.y" -{ yyval.node = mk(nAssign,yyvsp[-2].node,yyvsp[0].node); } -break; -case 16: -#line 77 "parse.y" -{ yyval.node = NULL; } -break; -case 17: -#line 78 "parse.y" -{ yyval.node = mk(nEpilog,yyvsp[-1].node,yyvsp[0].node); } -break; -case 18: -#line 81 "parse.y" -{ yyval.node = mk(nDup,yyvsp[0].dup.type,yyvsp[0].dup.left,yyvsp[0].dup.right); } -break; -case 19: -#line 82 "parse.y" -{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); - if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ - } -break; -case 20: -#line 85 "parse.y" -{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); - if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ - } -break; -case 21: -#line 89 "parse.y" -{ yyval.node = mk(nCase, yyvsp[-1].node); } -break; -case 22: -#line 90 "parse.y" -{ yyval.node = mk(nCase, yyvsp[-1].node); } -break; -case 23: -#line 92 "parse.y" -{ yyval.node = mk(nCbody, yyvsp[0].node, NULL); } -break; -case 24: -#line 93 "parse.y" -{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } -break; -case 25: -#line 94 "parse.y" -{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } -break; -case 27: -#line 97 "parse.y" -{ yyval.node = mk(nElse,yyvsp[-3].node,yyvsp[0].node); } -break; -case 28: -#line 99 "parse.y" -{ yyval.node = NULL; } -break; -case 30: -#line 101 "parse.y" -{ yyval.node = mk(nBrace,yyvsp[-1].node,yyvsp[0].node); } -break; -case 31: -#line 102 "parse.y" -{ yyval.node = mk(nIf,yyvsp[-2].node,yyvsp[0].node); } -break; -case 32: -#line 103 "parse.y" -{ yyval.node = mk(nForin,yyvsp[-5].node,yyvsp[-3].node,yyvsp[0].node); } -break; -case 33: -#line 104 "parse.y" -{ yyval.node = mk(nForin,yyvsp[-3].node,star,yyvsp[0].node); } -break; -case 34: -#line 105 "parse.y" -{ yyval.node = mk(nWhile,yyvsp[-2].node,yyvsp[0].node); } -break; -case 35: -#line 106 "parse.y" -{ yyval.node = mk(nSwitch,yyvsp[-5].node,yyvsp[-1].node); } -break; -case 36: -#line 107 "parse.y" -{ yyval.node = mk(nMatch,yyvsp[-1].node,yyvsp[0].node); } -break; -case 37: -#line 108 "parse.y" -{ yyval.node = mk(nAndalso,yyvsp[-3].node,yyvsp[0].node); } -break; -case 38: -#line 109 "parse.y" -{ yyval.node = mk(nOrelse,yyvsp[-3].node,yyvsp[0].node); } -break; -case 39: -#line 110 "parse.y" -{ yyval.node = mk(nPipe,yyvsp[-2].pipe.left,yyvsp[-2].pipe.right,yyvsp[-3].node,yyvsp[0].node); } -break; -case 40: -#line 111 "parse.y" -{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } -break; -case 41: -#line 112 "parse.y" -{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } -break; -case 42: -#line 113 "parse.y" -{ yyval.node = mk(nBang,yyvsp[0].node); } -break; -case 43: -#line 114 "parse.y" -{ yyval.node = mk(nSubshell,yyvsp[0].node); } -break; -case 44: -#line 115 "parse.y" -{ yyval.node = mk(nNewfn,yyvsp[-1].node,yyvsp[0].node); } -break; -case 45: -#line 116 "parse.y" -{ yyval.node = mk(nRmfn,yyvsp[0].node); } -break; -case 49: -#line 122 "parse.y" -{ yyval.node = (yyvsp[0].node != NULL ? mk(nArgs,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } -break; -case 50: -#line 123 "parse.y" -{ yyval.node = mk(nArgs,yyvsp[-1].node,yyvsp[0].node); } -break; -case 52: -#line 126 "parse.y" -{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } -break; -case 54: -#line 129 "parse.y" -{ yyval.node = mk(nWord,yyvsp[0].keyword, NULL); } -break; -case 56: -#line 132 "parse.y" -{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } -break; -case 57: -#line 134 "parse.y" -{ yyval.node = mk(nVar,yyvsp[0].node); } -break; -case 58: -#line 135 "parse.y" -{ yyval.node = mk(nVarsub,yyvsp[-3].node,yyvsp[-1].node); } -break; -case 59: -#line 136 "parse.y" -{ yyval.node = mk(nCount,yyvsp[0].node); } -break; -case 60: -#line 137 "parse.y" -{ yyval.node = mk(nFlat, yyvsp[0].node); } -break; -case 61: -#line 138 "parse.y" -{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } -break; -case 62: -#line 139 "parse.y" -{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } -break; -case 63: -#line 140 "parse.y" -{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } -break; -case 64: -#line 141 "parse.y" -{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } -break; -case 65: -#line 142 "parse.y" -{ yyval.node = yyvsp[-1].node; } -break; -case 66: -#line 143 "parse.y" -{ yyval.node = mk(nNmpipe,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); } -break; -case 67: -#line 144 "parse.y" -{ yyval.node = (yyvsp[0].word.w[0] == '\'') ? mk(nQword, yyvsp[0].word.w+1, NULL) : mk(nWord,yyvsp[0].word.w, yyvsp[0].word.m); } -break; -case 68: -#line 146 "parse.y" -{ yyval.keyword = "for"; } -break; -case 69: -#line 147 "parse.y" -{ yyval.keyword = "in"; } -break; -case 70: -#line 148 "parse.y" -{ yyval.keyword = "while"; } -break; -case 71: -#line 149 "parse.y" -{ yyval.keyword = "if"; } -break; -case 72: -#line 150 "parse.y" -{ yyval.keyword = "switch"; } -break; -case 73: -#line 151 "parse.y" -{ yyval.keyword = "fn"; } -break; -case 74: -#line 152 "parse.y" -{ yyval.keyword = "else"; } -break; -case 75: -#line 153 "parse.y" -{ yyval.keyword = "case"; } -break; -case 76: -#line 154 "parse.y" -{ yyval.keyword = "~"; } -break; -case 77: -#line 155 "parse.y" -{ yyval.keyword = "!"; } -break; -case 78: -#line 156 "parse.y" -{ yyval.keyword = "@"; } -break; -case 79: -#line 158 "parse.y" -{ yyval.node = NULL; } -break; -case 80: -#line 159 "parse.y" -{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } -break; -case 81: -#line 161 "parse.y" -{ yyval.node = NULL; } -break; -case 83: -#line 163 "parse.y" -{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } -break; -#line 1015 "y.tab.c" - } - yyssp -= yym; - yystate = *yyssp; - yyvsp -= yym; - yym = yylhs[yyn]; - if (yystate == 0 && yym == 0) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); -#endif - yystate = YYFINAL; - *++yyssp = YYFINAL; - *++yyvsp = yyval; - if (yychar < 0) - { - if ((yychar = yylex()) < 0) yychar = 0; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, yychar, yys); - } -#endif - } - if (yychar == 0) goto yyaccept; - goto yyloop; - } - if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yystate) - yystate = yytable[yyn]; - else - yystate = yydgoto[yym]; -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *yyssp, yystate); -#endif - if (yyssp >= yyss + yystacksize - 1) - { - goto yyoverflow; - } - *++yyssp = yystate; - *++yyvsp = yyval; - goto yyloop; -yyoverflow: - yyerror("yacc stack overflow"); -yyabort: - return (1); -yyaccept: - return (0); -} diff --git a/y.tab.h b/y.tab.h deleted file mode 100644 index 76f8b74..0000000 --- a/y.tab.h +++ /dev/null @@ -1,33 +0,0 @@ -#define ANDAND 257 -#define BACKBACK 258 -#define BANG 259 -#define CASE 260 -#define COUNT 261 -#define DUP 262 -#define ELSE 263 -#define END 264 -#define FLAT 265 -#define FN 266 -#define FOR 267 -#define IF 268 -#define IN 269 -#define OROR 270 -#define PIPE 271 -#define REDIR 272 -#define SREDIR 273 -#define SUB 274 -#define SUBSHELL 275 -#define SWITCH 276 -#define TWIDDLE 277 -#define WHILE 278 -#define WORD 279 -#define HUH 280 -typedef union { - struct Node *node; - struct Redir redir; - struct Pipe pipe; - struct Dup dup; - struct Word word; - char *keyword; -} YYSTYPE; -extern YYSTYPE yylval; -- cgit v1.2.3 From f983e502ce8fc8d1d0289b8feb269218a70618e6 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 27 Jan 1999 14:01:36 +0000 Subject: beta: rc-1.5b5 --- AUTHORS | 9 ++-- ChangeLog | 25 +++++++++++ Makefile.am | 3 +- NEWS | 10 ++--- README | 4 +- configure.ac | 2 +- main.c | 42 +++++++++--------- rc.1 | 137 ++++++++++++++++++++++++++++++++++------------------------- trip.rc | 6 +++ 9 files changed, 142 insertions(+), 96 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4075191..65916d4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,7 +28,8 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Arvid Requate, Bengt Kleberg, Brynjulv -Hauksson, Byron Rakitzis, Chris Siebenmann, David Swasey, Gert-Jan Vons, -Ian Lance Taylor, Jeremy Fitzhardinge, Marc Moorcroft, Mark K Gardner, -Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, -Tom Culliton, Tom Tromey, Vincent Broman. +Hauksson, Byron Rakitzis, Chris Siebenmann, David Swasey, Gerry +Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc +Moorcroft, Mark K Gardner, Raymond Venneker, Rich $alz, Rob Savoye, +Scott Schwartz, Stefan Dalibor, Tom Culliton, Tom Tromey, Vincent +Broman. diff --git a/ChangeLog b/ChangeLog index d997a6d..c840afa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -529,3 +529,28 @@ Changes since rc-1.5b2 Documentation: the Bell Labs rc now has the list flattening operator, but spelt $"foo. + +1999-01-11 + + Release: rc-1.5b4. + +1999-01-19 + + Documentation: document the `-s' option. Also, arrange the option + documentation in alphabetical order. + + Tidiness: just install `history' to `$(bindir)/-'; don't create an + extra link (which `make clean' failed to remove). + +1999-01-22 + + Bug: `-s' should not imply `-i'. + + Testing: add regression test for `-s' behaviour. + +1999-01-27 + + Documentation: default path was out of date; minor consistency + improvements. + + Release: rc-1.5b5. diff --git a/Makefile.am b/Makefile.am index 6433f0c..b06518b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,8 +61,7 @@ trip: rc tripping install-exec-hook: if AMC_HISTORY - $(LN) history - ;\ - $(INSTALL_PROGRAM) - $(bindir) ;\ + $(INSTALL_PROGRAM) history $(bindir)/- ;\ rm -f $(bindir)/--; $(LN) $(bindir)/- $(bindir)/-- ;\ rm -f $(bindir)/-p; $(LN) $(bindir)/- $(bindir)/-p ;\ rm -f $(bindir)/--p; $(LN) $(bindir)/- $(bindir)/--p diff --git a/NEWS b/NEWS index ec827a6..deb5dab 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,7 @@ autoconfiguration code, some of them critical. One problem (which I introduced) was found in minutes with ElectricFence: I had spent several hours failing to find it with other tools. -Two bugs in rc itself, one of them trivial, were fixed. +Three bugs in rc itself, one of them trivial, were fixed. rc now uses GNU automake. Although I feel that automake is sticking plaster to mend a broken leg, it has made my job as maintainer easier. @@ -30,7 +30,7 @@ information only. The supplied y.tab.[ch] were built with Berkeley `yacc', and lightly edited to remove a few gcc warnings. This idea was suggested by Gert-Jan Vons. -Binaries of rc-1.5b4 are typically a few kilobytes smaller than 1.5b2. +Binaries of rc-1.5b5 are typically a few kilobytes smaller than 1.5b2. I believe this is due to improved autoconfiguration: we are now much more careful only to include code that will be used. @@ -42,9 +42,5 @@ non-blocking mode. See ChangeLog for more details. -What happened to rc-1.5b3? There were a couple of releases to people -who'd found bugs in rc-1.5b2 that were called b3. To avoid any -possibility of confusion, I have named this beta release rc-1.5b4. - Tim Goodwin -1999-01-11 +1999-01-27 diff --git a/README b/README index f750d18..8ee9aeb 100644 --- a/README +++ b/README @@ -1,5 +1,4 @@ -This is a snapshot release of rc-1.5. The file RELDATE identifies the -date of the snapshot. +This is a beta release, rc-1.5b5. See COPYING for copying information. All files are @@ -37,4 +36,3 @@ WWW More information on releases of rc can be found at this web page. http://www.star.le.ac.uk/~tjg/rc/ - diff --git a/configure.ac b/configure.ac index dd460aa..6ed8149 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.5s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.5b4) +AM_INIT_AUTOMAKE(rc, 1.5b5) AM_CONFIG_HEADER(config.h) diff --git a/main.c b/main.c index 55649fe..0c4b602 100644 --- a/main.c +++ b/main.c @@ -21,10 +21,13 @@ extern int main(int argc, char *argv[], char *envp[]) { dollarzero = argv[0]; rc_pid = getpid(); dashell = (*argv[0] == '-'); /* Unix tradition */ - while ((c = rc_getopt(argc, argv, "Vnolpeivdxsc:")) != -1) + while ((c = rc_getopt(argc, argv, "c:deilnopsVvx")) != -1) switch (c) { - case 'l': - dashell = TRUE; + case 'c': + dashsee[0] = rc_optarg; + goto quitopts; + case 'd': + dashdee = TRUE; break; case 'e': dashee = TRUE; @@ -32,40 +35,37 @@ extern int main(int argc, char *argv[], char *envp[]) { case 'i': dasheye = interactive = TRUE; break; - case 'v': - dashvee = TRUE; - break; - case 'x': - dashex = TRUE; - break; - case 'd': - dashdee = TRUE; - break; - case 's': - dashess = dasheye = interactive = TRUE; + case 'l': + dashell = TRUE; break; - case 'c': - dashsee[0] = rc_optarg; - goto quitopts; case 'n': dashen = TRUE; break; + case 'o': + dashoh = TRUE; + break; case 'p': dashpee = TRUE; break; - case 'o': - dashoh = TRUE; + case 's': + dashess = TRUE; break; case 'V': fprint(1, "%s\n", id); exit(0); + case 'v': + dashvee = TRUE; + break; + case 'x': + dashex = TRUE; + break; case '?': exit(1); } quitopts: argv += rc_optind; - /* use isatty() iff -i is not set, and iff the input is not from a script or -c or -s flags */ - if (!dasheye && !dashess && dashsee[0] == NULL && *argv == NULL) + /* use isatty() iff -i is not set, and iff the input is not from a script or -c flags */ + if (!dasheye && dashsee[0] == NULL && (dashess || *argv == NULL)) interactive = isatty(0); if (!dashoh) { checkfd(0, rFrom); diff --git a/rc.1 b/rc.1 index 8353340..526fecf 100644 --- a/rc.1 +++ b/rc.1 @@ -166,7 +166,7 @@ rc \- shell .SH SYNOPSIS .B rc -.RB [ \-eixvldnpoV ] +.RB [ \-deilnopsVvx ] .RB [ \-c .IR command ] .RI [ arguments ] @@ -183,10 +183,44 @@ Its use is intended to be interactive, but the language lends itself well to scripts. .SH OPTIONS .TP +.Cr \-c +If +.Cr \-c +is present, commands are executed from the immediately following +argument. +Any further arguments to +.I rc +are placed in +.Cr $* . +Thus: +.Ds +.Cr "rc -c 'echo $*' 1 2 3" +.De +.TP +\& +prints out +.Ds +.Cr "1 2 3" +.De +.TP +.Cr \-d +This flag causes +.I rc +not to ignore +.Cr SIGQUIT +or +.Cr SIGTERM . +Thus +.I rc +can be made to dump core if sent +.Cr SIGQUIT . +This flag is only useful for debugging +.IR rc . +.TP .Cr \-e If the .Cr \-e -option is present, then +flag is present, then .I rc will exit if the exit status of a command is false (nonzero). .I rc @@ -197,7 +231,7 @@ command. .Cr \-i If the .Cr \-i -option is present or if the input to +flag is present or if the input to .I rc is from a terminal (as determined by .IR isatty (3)) @@ -216,23 +250,10 @@ will ignore the signals and .Cr SIGQUIT . .TP -.Cr \-x -This option will make -.I rc -print every command on standard error before it is executed. -It can be useful for debugging -.I rc -scripts. -.TP -.Cr \-v -This option will echo input to -.I rc -on standard error as it is read. -.TP .Cr \-l If the .Cr \-l -option is present, or if +flag is present, or if .IR rc 's .Cr argv[0][0] is a dash @@ -244,20 +265,6 @@ That is, it will try to run commands present in .Cr $home/.rcrc , if this file exists, before reading any other input. .TP -.Cr \-d -This flag causes -.I rc -not to ignore -.Cr SIGQUIT -or -.Cr SIGTERM . -Thus -.I rc -can be made to dump core if sent -.Cr SIGQUIT . -This option is only useful for debugging -.IR rc . -.TP .Cr \-n This flag causes .I rc @@ -265,11 +272,17 @@ to read its input and parse it, but not to execute any commands. This is useful for syntax checking on scripts. If used in combination with the .Cr \-x -option, +flag, .I rc will print each command as it is parsed in a form similar to the one used for exporting functions into the environment. .TP +.Cr \-o +This flag prevents the usual practice of trying to open +.Cr /dev/null +on file descriptors 0, 1, and 2, if any of those descriptors +are inherited closed. +.TP .Cr \-p This flag prevents .I rc @@ -280,31 +293,36 @@ to run in a protected mode, whereby it becomes more difficult for an .I rc script to be subverted by placing false commands in the environment. -(Note that this presence of this option does NOT mean that it is safe to +(Note that this presence of this flag does NOT mean that it is safe to run setuid .I rc scripts; the usual caveats about the setuid bit still apply.) .TP -.Cr \-o -This flag prevents the usual practice of trying to open -.Cr /dev/null -on file descriptors 0, 1, and 2, if any of those descriptors -are inherited closed. -.TP -.Cr \-c -If -.Cr \-c -is present, commands are executed from the immediately following -argument. -Any further arguments to +.Cr \- s +This flag causes .I rc -are placed in +to read from standard input. Any arguments are +placed in .Cr $* . .TP .Cr \-V This flag causes .I rc to print a version string to stdout, and exit immediately. +.TP +.Cr \-v +This flag causes +.I rc +to echo its input +to standard error as it is read. +.TP +.Cr \-x +This flag causes +.I rc +to print every command on standard error before it is executed. +It can be useful for debugging +.I rc +scripts. .PP .SH COMMANDS A simple command is a sequence of words, separated by white space @@ -1238,7 +1256,7 @@ is not set at startup time, .Cr $path assumes a default value suitable for your system. This is typically -.Cr "(/usr/ucb /usr/bin /bin .)" +.Cr "(/usr/local/bin /usr/bin /usr/ucb /bin .)" .TP .Cr pid The process ID of the currently running @@ -1641,7 +1659,7 @@ For builtins, is printed; for functions, including signal handlers, their definitions are printed; for executable files, path names are printed; and for variables, their values are printed. -The options restrict output to builtins, functions, executable +The flags restrict output to builtins, functions, executable programs, signal handlers, and variables, respectively. If no .IR name s are specified, @@ -1683,7 +1701,7 @@ uses .IR getopt (3) to parse its arguments, you can use the special argument .Cr "\-\|\-" -to terminate its options. +to terminate its flags. This allows you to use names beginning with a dash, such as the .IR history (1) @@ -1846,15 +1864,18 @@ Here is a list of features which distinguish this incarnation of .I rc from the one described in the Bell Labs manual pages: .PP -The treatment of -.Cr if - else -is different in the v10 -.IR rc : -that version uses an -.Cr "if not" -clause which gets executed +The v10 +.I rc +does not have the +.B else +keyword. Instead, +.B if +is optionally followed by +an +.B "if not" +clause which is executed if the preceding -.Cr if +.B if test does not succeed. .PP Backquotes are slightly different in v10 @@ -1875,7 +1896,7 @@ The following are all new with this version of .IR rc : The .Cr \-n -option, +flag, here strings (they facilitate exporting of functions with here documents into the environment), the diff --git a/trip.rc b/trip.rc index 717b0a2..a0d5677 100644 --- a/trip.rc +++ b/trip.rc @@ -559,3 +559,9 @@ expect date x=`{ { sleep 1; echo echo foo } | { ./tripping n; $rc >[2=1] } } if (!~ foo $x) fail input file descriptor nonblocking + +# `rc -s' reads from stdin, but should not imply `-i' +expect foo bar qux +$rc -s foo bar qux <<'eof' +echo $* +eof -- cgit v1.2.3 From 2c998c165268f24f038e02f103e07a967b343c3f Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 12 May 1999 16:47:55 +0100 Subject: beta: rc-1.5b6 --- AUTHORS | 12 +++++----- ChangeLog | 35 +++++++++++++++++++++++++++ EXAMPLES | 16 ++++++------- README | 2 +- acinclude.m4 | 21 ++++++++++++++-- configure.ac | 20 ++++++++-------- rc.1 | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- signal.c | 2 ++ 8 files changed, 147 insertions(+), 39 deletions(-) diff --git a/AUTHORS b/AUTHORS index 65916d4..7544cb2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,9 +27,9 @@ mind that it describes a program that was written at AT&T and that the version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he -took over maintenance of rc. Arvid Requate, Bengt Kleberg, Brynjulv -Hauksson, Byron Rakitzis, Chris Siebenmann, David Swasey, Gerry -Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc -Moorcroft, Mark K Gardner, Raymond Venneker, Rich $alz, Rob Savoye, -Scott Schwartz, Stefan Dalibor, Tom Culliton, Tom Tromey, Vincent -Broman. +took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt +Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, David +Swasey, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy +Fitzhardinge, Marc Moorcroft, Mark K Gardner, Raymond Venneker, Rich +$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Tom Culliton, Tom +Tromey, Vincent Broman, Wolfgang Zekoll. diff --git a/ChangeLog b/ChangeLog index c840afa..e296f2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -554,3 +554,38 @@ Changes since rc-1.5b2 improvements. Release: rc-1.5b5. + +1999-02-15 + + Portability: AM_INIT_AUTOMAKE calls AC_ARG_PROGRAM and + AC_PROG_INSTALL. Don't do it explicitly. For once, the configure + script gets smaller! Program name transformations work right now. + + Documentation: note that rc has no `set' builtin; fix weird variable + name example; any character except `=' may be used in a variable name; + document bqstatus; document rc's exit status; other tidying. + +1999-03-01 + + Documentation: document the yacc-imposed limit on ; separated commands + in a line. + +1999-05-06 + + Portability: tgetent() might be in -lncurses instead of -ltermcap. + +1999-05-10 + + Portability: Linux *almost* has SysV SIGCLD semantics, and we need to + detect them. + + Bug: if we reset SIGCLD to SIG_DFL, we need to record the fact in the + sighandlers[] array. + +1999-05-12 + + Documentation: note that `$(a.b)' syntax only mostly works, and that + list definitions in exported functions are noisier than they need to + be. + + Release: rc-1.5b6. diff --git a/EXAMPLES b/EXAMPLES index 90bd8df..9f4b5c8 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -1,6 +1,6 @@ -There is no repository for useful rc code snippets as yet, so I'm including -a (short) file in the distribution with some helpful/intriguing pieces of -rc code. +There is no repository for useful rc code snippets as yet, so +I'm including a (short) file in the distribution with some +helpful/intriguing pieces of rc code. A sample .rcrc -------------- @@ -624,7 +624,7 @@ Status: RO Use trimhist [-#lines] -trims your history file back; useful for folks with dis quota's :-) +trims your history file back; useful for folks with disk quota's :-) fn trimhist { p1=-100 { cp $history $history^'~' ~ $#* 1 && p1=$1 @@ -742,8 +742,8 @@ fn pathprefix { p1=() i=() j=() { home=/user/users/rsalz z=/usr/users -pathprefix /usr/users/rsalz home usr # --> $home -pathprefix /usr/users/rsalz z # --> $z/rsalz -pathprefix /usr/users/rsalz/foo z home # --> $z/rsalz/foo -pathprefix /usr/users/rsalz/foo home # --> $home/foo +pathprefix /usr/users/rsalz home usr # --> $home +pathprefix /usr/users/rsalz z # --> $z/rsalz +pathprefix /usr/users/rsalz/foo z home # --> $z/rsalz/foo +pathprefix /usr/users/rsalz/foo home # --> $home/foo diff --git a/README b/README index 8ee9aeb..fb106f9 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is a beta release, rc-1.5b5. +This is a beta release, rc-1.5b6. See COPYING for copying information. All files are diff --git a/acinclude.m4 b/acinclude.m4 index 3516928..32fa6f2 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -145,7 +145,12 @@ sigaction(SIGINT, 0, 0); dnl Do we have SysV SIGCLD semantics? In other words, if we set the -dnl action for SIGCLD to SIG_IGN does wait() always say ECHILD? +dnl action for SIGCLD to SIG_IGN does wait() always say ECHILD? Linux, +dnl of course, is bizarre here. It basically implements the SysV +dnl semantics, but if the parent calls wait() before the child calls +dnl exit(), wait() returns with the PID of the child as normal. (Real +dnl SysV waits for all children to exit, then returns with ECHILD.) +dnl Anyway, this is why the `sleep(1)' is there. AC_DEFUN(RC_SYS_V_SIGCLD, [ AC_CACHE_CHECK(for SysV SIGCLD semantics, rc_cv_sysv_sigcld, AC_TRY_RUN([ @@ -156,13 +161,14 @@ AC_DEFUN(RC_SYS_V_SIGCLD, [ #include int main(void) { int i; - sigset(SIGCLD, SIG_IGN); + signal(SIGCLD, SIG_IGN); switch (fork()) { case -1: return 1; case 0: return 0; default: + sleep(1); if (wait(&i) == -1 && errno == ECHILD) return 0; else return 1; } @@ -204,3 +210,14 @@ main() { yes) AC_DEFINE(HAVE_FIFO) ;; esac ]) + +dnl Where is tgetent()? +AC_DEFUN(RC_LIB_TGETENT, [ + AC_CHECK_LIB(termcap, tgetent, + rc_lib_tgetent=-ltermcap, + AC_CHECK_LIB(ncurses, tgetent, + rc_lib_tgetent=-lncurses, + AC_MSG_ERROR(tgetent not found) + ) + ) +]) diff --git a/configure.ac b/configure.ac index 6ed8149..76b0fea 100644 --- a/configure.ac +++ b/configure.ac @@ -8,13 +8,10 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.5s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.5b5) +AM_INIT_AUTOMAKE(rc, 1.5b6) AM_CONFIG_HEADER(config.h) -dnl Anybody using name transformations? -AC_ARG_PROGRAM - dnl Find a standard C compiler AC_PROG_CC AM_PROG_CC_STDC @@ -28,7 +25,6 @@ yes) CFLAGS="-Wall $CFLAGS" ;; esac AC_PROG_CPP -AC_PROG_INSTALL AC_CHECK_PROGS(LN, ln cp) AC_CHECK_HEADERS(sys/resource.h sys/time.h sys/types.h unistd.h) @@ -178,19 +174,23 @@ AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], AC_DEFINE(EDITLINE) LIBS="$LIBS -ledit", AC_MSG_ERROR(editline library not found))) +if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then + RC_LIB_TGETENT +fi + AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing], AC_CHECK_LIB(vrl, readline, - AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl -ltermcap", - AC_MSG_ERROR(vrl library not found), -ltermcap)) + AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent", + AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent)) dnl There are (at least) two incompatible versions of readline, and we dnl need to know which one we are using. We don't support readline 2.0. AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ AC_CHECK_LIB(readline, readline, [ AC_DEFINE(READLINE) - LIBS="$LIBS -lreadline -ltermcap" - AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD), -ltermcap) - ], AC_MSG_ERROR(readline library not found), -ltermcap) + LIBS="$LIBS -lreadline $rc_lib_tgetent" + AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD), $rc_lib_tgetent) + ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) ]) AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) diff --git a/rc.1 b/rc.1 index 526fecf..d85099f 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "28 April 1991" +.TH RC 1 "1999-05-12" .SH NAME rc \- shell .SH SYNOPSIS @@ -298,7 +298,7 @@ run setuid .I rc scripts; the usual caveats about the setuid bit still apply.) .TP -.Cr \- s +.Cr \-s This flag causes .I rc to read from standard input. Any arguments are @@ -601,7 +601,7 @@ and the output version of this notation: .SH "CONTROL STRUCTURES" The following may be used for control flow in .IR rc : -.SS "If-else Statements" +.SS "If-Else Statements" .PD 0 .sp .Ci "if (" test ") {" @@ -820,7 +820,7 @@ and .Cr "?" . However, .I rc -does expand the glob the subject against filenames if it contains +does expand the subject against filenames if it contains metacharacters. Thus, the command .Ds @@ -945,8 +945,18 @@ A list may be assigned to a variable, using the notation: .Ic var " = " list .De .PP -Any sequence of non-special characters, except a sequence including -only digits, may be used as a variable name. +The special variable +.Cr * +may be assigned to using this notation; +.I rc +has no +.B set +builtin. +.PP +Any non-empty sequence of characters, except a sequence including only +digits, may be used as a variable name. Any character except +.Cr = +may be used, but special characters must be quoted. All user-defined variables are exported into the environment. .PP The value of a variable is referenced with the notation: @@ -989,7 +999,7 @@ To reference a variable with other characters in its name, quote the variable name. Thus: .Ds -.Cr "echo $'we$Ird\Variab!le'" +.Cr "echo $'we$Ird:Variab!le'" .De .SS "Local Variables" Any number of variable assignments may be made local to a single @@ -1180,6 +1190,11 @@ The process ID of the last process started in the background. The process IDs of any background processes which are outstanding or which have died and have not been waited for yet. .TP +.Cr bqstatus +The exit status of the +.I rc +forked to execute the most recent backquote substitution. +.TP .Cr cdpath A list of directories to search for the target of a .B cd @@ -1654,7 +1669,7 @@ waits for all child processes to exit. \fBwhatis \fR[\fB\-b\fR] \fR[\fB\-f\fR] \fR[\fB\-p\fR] \fR[\fB\-s\fR] \fR[\fB\-v\fR] [\fB\-\|\-\fR] [\fIname ...\fR] Prints a definition of the named objects. For builtins, -.B builtin +.Cr builtin .I foo is printed; for functions, including signal handlers, their definitions are printed; for executable files, path names are printed; and for @@ -1665,11 +1680,11 @@ programs, signal handlers, and variables, respectively. If no are specified, .I rc lists all objects of that type. (This is not permitted for -.BR -p .) +.Cr \-p .) Without arguments, -.B whatis +.Cr whatis is equivalent to -.BR "whatis -fv" , +.Cr "whatis -fv" , and prints the values of all shell variables and functions. .TP \& @@ -1710,6 +1725,24 @@ For example, .Ds .Cr "whatis \-\|\- \-p" .De +.SH "EXIT STATUS" +The exit status of +.I rc +is normally the same as that of the +last command executed. If the last +command was a pipeline, +.I rc +exits +.Cr 0 +if every command in the pipeline did; +otherwise it exits +.Cr 1 . +.PP +.I rc +can be made to exit with a particular +status using the +.B exit +builtin. .SH GRAMMAR Here is .IR rc 's @@ -1816,7 +1849,7 @@ optnl: /* empty */ | optnl '\en' .I rc was written by Byron Rakitzis, with valuable help from Paul Haahr, Hugh Redelmeier and David Sanderson. -The design of this shell has been copied from the +The design of this shell was copied from the .I rc that Tom Duff wrote at Bell Labs. .SH BUGS @@ -1826,6 +1859,14 @@ descendant .IR rc processes. .PP +There is a compile-time limit on the number of +.Cr ; +separated commands in a line: usually 500. +This is sometimes a problem for automatically generated scripts: +substituting the newline character for +.Cr ; +avoids the limit. +.PP On modern systems that support .Cr /dev/fd or @@ -1857,6 +1898,19 @@ The notation for flattening should allow for using an arbitrary separating character, not just space. .PP +It is usually possible to use parentheses to defeat +free caret insertion; that is, to use +.Cr $(x.y) +as a synonym for +.Cr $'x.y' . +However, the former syntax is not correctly handled in functions +exported to the environment: a function defined using this syntax will +not work properly in descendant +.I rc +processes. +.PP +List definitions in exported functions are "noisier" than they need to be. +.PP Bug reports should be mailed to .Cr "" . .SH INCOMPATIBILITIES diff --git a/signal.c b/signal.c index 1c59746..8535eab 100644 --- a/signal.c +++ b/signal.c @@ -97,5 +97,7 @@ extern void initsignal() { h = sys_signal(SIGCLD, SIG_DFL); if (h != SIG_IGN && h != SIG_ERR) sys_signal(SIGCLD, h); + else + sighandlers[SIGCLD] = SIG_DFL; #endif } -- cgit v1.2.3 From 3815ffb98e9db3d593219cead05284f983eb6d71 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Fri, 28 May 1999 10:38:44 +0100 Subject: release: rc-1.6 --- AUTHORS | 8 +++---- ChangeLog | 12 ++++++++++ Makefile.am | 2 ++ NEWS | 71 +++++++++++++++++++++++------------------------------------- README | 2 +- configure.ac | 2 +- rc.1 | 51 ++++++++++++++++++++++++++++++++++++++----- 7 files changed, 92 insertions(+), 56 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7544cb2..3395148 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,8 +28,8 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt -Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, David -Swasey, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy -Fitzhardinge, Marc Moorcroft, Mark K Gardner, Raymond Venneker, Rich -$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Tom Culliton, Tom +Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, Dale +Scheetz, David Swasey, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, +Jeremy Fitzhardinge, Marc Moorcroft, Mark K Gardner, Raymond Venneker, +Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang Zekoll. diff --git a/ChangeLog b/ChangeLog index e296f2c..3031a91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -589,3 +589,15 @@ Changes since rc-1.5b2 be. Release: rc-1.5b6. + +1999-05-19 + + Documentation: minor fixes to man page. + +1999-05-26 + + Tidiness: `make distclean' now removes sigmsgs.[ch]. + +1995-05-28 + + Release: rc-1.6. diff --git a/Makefile.am b/Makefile.am index b06518b..ccd990b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,6 +46,8 @@ sigmsgs.c sigmsgs.h: mksignal CONFIGURE_DEPENDENCIES = RELDATE +DISTCLEANFILES = sigmsgs.c sigmsgs.h + # Of course, parse.c and parse.h depend on parse.y. However, unless # you're hacking on rc's grammar, it's not useful to have this # dependency expressed, since the distributed parse.[ch] (generated with diff --git a/NEWS b/NEWS index deb5dab..320ad47 100644 --- a/NEWS +++ b/NEWS @@ -1,46 +1,29 @@ -Since rc-1.5b2 was released, many fixes have been made to the -autoconfiguration code, some of them critical. One problem (which I -introduced) was found in minutes with ElectricFence: I had spent several -hours failing to find it with other tools. - -Three bugs in rc itself, one of them trivial, were fixed. - -rc now uses GNU automake. Although I feel that automake is sticking -plaster to mend a broken leg, it has made my job as maintainer easier. -(Errm, apart from tracking down bugs in automake itself, and Perl, that -is.) For people building rc, it's now possible (depending on your -flavour of `make') to build in a separate directory from the source. - -Creeping featurism: rc now has a `-V' switch to report its version -number. - -The detection of signal names has been completely revised. Vincent -Broman suggested this, and contributed mksignal.c. - -The interaction with readline has been redone, principally to work -around bugs in the readline library. Tom Culliton persuaded me of -the need for this, and his patches to an earlier version of rc became -readline.c. - -I rewrote addon.[ch] to provide a more useful example of adding extra -builtins. - -The rc build system no longer considers running `yacc': parse.y is for -information only. The supplied y.tab.[ch] were built with Berkeley -`yacc', and lightly edited to remove a few gcc warnings. This idea was -suggested by Gert-Jan Vons. - -Binaries of rc-1.5b5 are typically a few kilobytes smaller than 1.5b2. -I believe this is due to improved autoconfiguration: we are now much -more careful only to include code that will be used. - -Support for vrl (another lightweight "readline"-style library) was -added. - -rc can now deal with a bogus application that sets its stdin to -non-blocking mode. - -See ChangeLog for more details. +Highlights of changes since rc-1.4. See ChangeLog for further details. + +Portability. The major change since the last full release is that rc +now uses GNU autoconf and automake. Other parts of the build process +have been tidied up too, so that building rc should now be painless. It +has been tested on a wide variety of Unix-like systems. + +Bug fixes. The following bugs have been fixed: the interaction with +readline was not always correct; SIGCLD set to SIG_IGN could cause a +hang; some obscure pipeline incantations could cause a hang; the `wait' +builtin could become uninterruptible; an application could crash rc +by making stdin nonblocking; the `-i' flag didn't work with readline; +$history didn't work properly over NFS; a few memory leaks; and an off +by one bug in reporting line numbers of errors. + +New features. The following features are new: the `-s' flag, which +causes rc to read from stdin even if arguments are present; the `-V' +flag, which prints a version string; $bqstatus which holds the exit +status of the last backquote command; additional options to the `whatis' +builtin; and support for vrl, another lightweight readline-style +library. + +What happened to rc-1.5? A number of beta releases were made with names +like rc-1.5b2, which might suggest improvements over rc-1.5. To avoid +any possibility of confusion, I decided to name this release rc-1.6 +instead. Tim Goodwin -1999-01-27 +1999-05-26 diff --git a/README b/README index fb106f9..4074da7 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is a beta release, rc-1.5b6. +This is a full release, rc-1.6. See COPYING for copying information. All files are diff --git a/configure.ac b/configure.ac index 76b0fea..ba9c78a 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.5s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.5b6) +AM_INIT_AUTOMAKE(rc, 1.6) AM_CONFIG_HEADER(config.h) diff --git a/rc.1 b/rc.1 index d85099f..2df377a 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "1999-05-12" +.TH RC 1 "1999-05-28" .SH NAME rc \- shell .SH SYNOPSIS @@ -293,8 +293,9 @@ to run in a protected mode, whereby it becomes more difficult for an .I rc script to be subverted by placing false commands in the environment. -(Note that this presence of this flag does NOT mean that it is safe to -run setuid +(Note that the presence of this flag does +.I not +mean that it is safe to run setuid .I rc scripts; the usual caveats about the setuid bit still apply.) .TP @@ -308,7 +309,7 @@ placed in .Cr \-V This flag causes .I rc -to print a version string to stdout, and exit immediately. +to print a version string to standard output, and exit immediately. .TP .Cr \-v This flag causes @@ -463,6 +464,16 @@ and the standard input may be taken from a file with .Cr "command < file" .De .PP +Redirections can appear anywhere in the line: the word +following the redirection symbol is the filename and must be +quoted if it contains spaces or other special characters. +These are all equivalent. +.Ds +.Cr "echo 1 2 3 > foo" +.Cr "> foo echo 1 2 3" +.Cr "echo 1 2 > foo 3" +.De +.PP File descriptors other than 0 and 1 may be specified also. For example, to redirect standard error to a file, use: .Ds @@ -477,6 +488,17 @@ to the same file, use .Cr "command > file >[2=1]" .De .PP +As in +.IR sh , +redirections are processed from left to right. Thus this sequence +.Ds +.Cr "command >[2=1] > file" +.De +.PP +is usually a mistake. It first duplicates standard error to standard +output; then redirects standard output to a file, leaving standard error +wherever standard output originally was. +.PP To close a file descriptor that may be open, use .Ci >[ n =]\fR. For example, to @@ -485,6 +507,14 @@ close file descriptor 7: .Cr "command >[7=]" .De .PP +Note that no spaces may appear in these constructs: +.Ds +.Cr "command > [2] file" +.De +would send the output of the command to a file named +.Cr [2] , +with the intended filename appearing in the command's argument list. +.PP In order to place the output of a command at the end of an already existing file, use: .Ds @@ -500,6 +530,12 @@ with the use of .Cr "command << 'eof-marker'" .De .PP +Subsequent lines form the standard input of +the command, till a line containing just the +marker, in this case +.Cr eof-marker , +is encountered. +.PP If the end-of-file marker is enclosed in quotes, then no variable substitution occurs inside the here document. Otherwise, every variable is substituted @@ -524,7 +560,7 @@ Additionally, .I rc supports ``here strings'', which are like here documents, except that input is taken directly from a string on the command line. -Its use is illustrated here: +Their use is illustrated here: .Ds .Cr "cat <<< 'this is a here string' | wc" .De @@ -559,6 +595,9 @@ use: .Cr "command |[2] wc" .De .PP +As with file redirections, no spaces may occur in the construct specifying +numbered file descriptors. +.PP The exit status of a pipeline is considered true if and only if every command in the pipeline exits true. .SS "Commands as Arguments" @@ -579,7 +618,7 @@ does it like this: .De .PP compares the output of the two commands in braces. -A note: since this form of +Note: since this form of redirection is implemented with some kind of pipe, and since one cannot .IR lseek (2) on a pipe, commands that use -- cgit v1.2.3 From 3e9e4d3f8f518f8f467066593ae6f270d97f6d60 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 10 Nov 1999 14:55:51 +0000 Subject: beta: rc-1.6b1 --- AUTHORS | 9 +++++---- ChangeLog | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- INSTALL | 16 ++++++++-------- Makefile.am | 7 +++++-- README | 2 +- acinclude.m4 | 14 -------------- configure.ac | 18 ++++++++---------- glob.c | 8 ++------ hash.c | 2 +- input.c | 2 +- main.c | 7 +------ print.c | 12 ++++++------ proto.h | 15 ++++++++++++--- rc.1 | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- status.c | 3 ++- trip.rc | 2 +- utils.c | 15 ++++++++------- var.c | 9 +++++++-- 18 files changed, 165 insertions(+), 85 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3395148..b8d18e0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,7 +29,8 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, Dale -Scheetz, David Swasey, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, -Jeremy Fitzhardinge, Marc Moorcroft, Mark K Gardner, Raymond Venneker, -Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Tom Culliton, Tom -Tromey, Vincent Broman, Wolfgang Zekoll. +Scheetz, David Luyer, David Swasey, Donn Cave, Gerry Tomlinson, Gert-Jan +Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc Moorcroft, Mark H +Wilkinson, Mark K Gardner, Raymond Venneker, Rich $alz, Rob Savoye, +Scott Schwartz, Stefan Dalibor, Steve Simon, Tom Culliton, Tom Tromey, +Vincent Broman, Wolfgang Zekoll. diff --git a/ChangeLog b/ChangeLog index 3031a91..b93ccad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -598,6 +598,57 @@ Changes since rc-1.5b2 Tidiness: `make distclean' now removes sigmsgs.[ch]. -1995-05-28 +1999-05-28 Release: rc-1.6. + +1999-08-19 + + Portability: the proposed C 9x __va_copy() macro is called that, not + va_copy(), as I thought. Furthermore, it is defined to be a macro, so + we don't need to use autoconf to check for it. + +1999-10-11 + + Bug: absolute globs don't need special case in doglob(). Avoids + creating path names like `//tmp', which is a UNC path under CygWin. + +1999-10-12 + + Portability: status.c assumes traditional Unix layout of 0 and 1 exit + statuses in the parent, which is not shared by BeOS. Add mkstatval.c. + +1999-10-13 + + Bug: a read(2) error in fdgchar() should call rc_raise(), not + rc_exit(). This bug is easily tickled on systems (like Linux) which + allow you to open(2) but not read(2) directories: `. /tmp'. In all + previous versions of rc, this caused the shell to exit. + + Portability: use POSIX strerror() where it's available; fake it with + sys_errlist[] where not. + + Feature: replace `-V' with `version' variable. + +1999-10-14 + + Portability: exporting `path' causes indigestion in CygWin. Since + it's virtually impossible for a child `rc' process to inherit `path' + (which I consider a bug, but it's not going to be fixed now), simply + don't export `path'. + + Portability: add /usr/bsd to default default path. + + Documentation: failing to search $path for a `.' command is at least + an incompatibility with Tenth Edition rc, and probably a bug. + +1999-11-10 + + Feature: make `version' a list. + +1999-11-11 + + Documentation: when running configure, you need to set LDFLAGS for + `-L' options, not LIBS. + + Release: rc-1.6b1. diff --git a/INSTALL b/INSTALL index f99c34e..63a11fe 100644 --- a/INSTALL +++ b/INSTALL @@ -34,17 +34,17 @@ descending order of usefulness. for details) to provide EMACS style command line editing and history. If the editline library is not installed in a standard place, you can tell configure where to find it by setting the environment variable - LIBS. For example, the maintainer builds rc by copying libedit.a into - the rc build directory and then running this configure command. + LDFLAGS. For example, the maintainer builds rc by copying libedit.a + into the rc build directory and then running this configure command. - LIBS=-L. sh ../rc-1.5b3/configure --with-editline + LDFLAGS=-L. sh ../rc-1.5b3/configure --with-editline --with-vrl This option tells rc to use the vrl package (see the README file for details) to provide EMACS style command line editing and history. As for `--with-editline', you may need to set the environment variable - LIBS appropriately. + LDFLAGS appropriately. --with-readline @@ -52,10 +52,10 @@ descending order of usefulness. to editline or vrl, but has many more features. The readline package is over 6 times the size of editline (whether you count lines of code, or the library itself). As for editline, you can set the environment - variable LIBS if your readline library is not installed in a standard - place. + variable LDFLAGS if your readline library is not installed in a + standard place. - LIBS=-L/usr/gnu/lib sh configure --with-readline + LDFLAGS=-L/usr/gnu/lib sh configure --with-readline --with-history @@ -105,7 +105,7 @@ probably don't want to bother with `--with-history'. The default path is constructed at configure time, and consists of each of the following directories that exist, in order. - /usr/local/bin /usr/bin /usr/ucb /bin . + /usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin . You can disable this, or specify a different default path. Note that the quote marks (") must be seen by configure; unless you are already diff --git a/Makefile.am b/Makefile.am index ccd990b..76b3514 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,7 @@ SYSTEM = system.o endif bin_PROGRAMS = rc -noinst_PROGRAMS = mksignal tripping $(HISTORY) +noinst_PROGRAMS = mksignal mkstatval tripping $(HISTORY) rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c hash.c heredoc.c input.c lex.c list.c main.c match.c nalloc.c open.c parse.c print.c redir.c signal.c status.c tree.c utils.c var.c wait.c walk.c which.c @@ -44,9 +44,12 @@ EXTRA_DIST = EXAMPLES RELDATE addon.c addon.h history.1 parse.y rc.1 trip.rc sigmsgs.c sigmsgs.h: mksignal ./mksignal +statval.h: mkstatval + ./mkstatval > statval.h + CONFIGURE_DEPENDENCIES = RELDATE -DISTCLEANFILES = sigmsgs.c sigmsgs.h +DISTCLEANFILES = sigmsgs.c sigmsgs.h statval.h # Of course, parse.c and parse.h depend on parse.y. However, unless # you're hacking on rc's grammar, it's not useful to have this diff --git a/README b/README index 4074da7..8c0d641 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is a full release, rc-1.6. +This is beta release rc-1.6b1. See COPYING for copying information. All files are diff --git a/acinclude.m4 b/acinclude.m4 index 32fa6f2..697b326 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -14,20 +14,6 @@ int main(void) { ]) -dnl Check for va_copy() in . This is new in C 9x. -AC_DEFUN(RC_HAVE_VA_COPY, [ - AC_CACHE_CHECK(for va_copy(), rc_cv_have_va_copy, AC_EGREP_CPP(yes, [ -#include -#ifdef va_copy -yes -#endif -], rc_cv_have_va_copy=yes, rc_cv_have_va_copy=no)) - case "$rc_cv_have_va_copy" in - yes) AC_DEFINE(HAVE_VA_COPY) ;; - esac -]) - - dnl We can't use AC_CHECK_FUNCS for sigsetjmp(), since it's a macro in dnl some places. AC_DEFUN(RC_FUNC_SIGSETJMP, [ diff --git a/configure.ac b/configure.ac index ba9c78a..c192496 100644 --- a/configure.ac +++ b/configure.ac @@ -6,9 +6,9 @@ AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE") dnl Automake stuff. dnl Use this one for snapshots... -dnl AM_INIT_AUTOMAKE(rc, 1.5s`echo $RELDATE |sed 's/-//g'`) +dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6) +AM_INIT_AUTOMAKE(rc, 1.6b1) AM_CONFIG_HEADER(config.h) @@ -38,7 +38,7 @@ AC_TYPE_SIZE_T AC_TYPE_UID_T AC_CHECK_TYPE(ssize_t, long) -AC_CHECK_FUNCS(getgroups setpgrp setrlimit) +AC_CHECK_FUNCS(getgroups setpgrp setrlimit strerror) RC_FUNC_GETGROUPS RC_FUNC_SIGSETJMP @@ -51,9 +51,9 @@ RC_TYPE_RLIM_T RC_TYPE_SIG_ATOMIC_T -dnl We prefer system calls that don't restart. If we have sigaction() and -dnl SA_INTERRUPT, we'll use 'em. Otherwise, we check whether -dnl good ol' signal() produces interruptible system calls. +dnl We prefer system calls that don't restart. If we have sigaction() +dnl and SA_INTERRUPT, we'll use 'em. Otherwise, we check whether good +dnl ol' signal() produces interruptible system calls. RC_FUNC_SIGACTION case "$rc_cv_sa_int" in yes) AC_DEFINE(HAVE_SA_INTERRUPT) ;; @@ -86,8 +86,6 @@ yes) AC_DEFINE(HAVE_FIFO) ;; no) RC_SYS_MKNOD_FIFO ;; esac -RC_HAVE_VA_COPY - dnl Now handle arguments. AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO), @@ -120,7 +118,7 @@ AC_ARG_ENABLE(def-interp, AC_ARG_ENABLE(def-path, [ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" Default path [All of these that exist - (/usr/local/bin /usr/bin /usr/ucb /bin .)]], + (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]], [ case "$enableval" in no|yes) ;; @@ -132,7 +130,7 @@ AC_ARG_ENABLE(def-path, case "$enable_def_path" in yes) AC_CACHE_CHECK(extant directories for default path, rc_cv_def_path,[ rc_cv_def_path='' - for i in /usr/local/bin /usr/bin /usr/ucb /bin .; do + for i in /usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .; do if test -d $i; then case "$rc_cv_def_path" in '') rc_cv_def_path=\"$i\" ;; diff --git a/glob.c b/glob.c index 419a096..03d8a42 100644 --- a/glob.c +++ b/glob.c @@ -216,12 +216,8 @@ static List *doglob(char *w, char *m) { p = pattern; md = metadir; mp = metapattern; - if (*s == '/') - while (*s == '/') - *d++ = *s++, *md++ = *m++; - else - while (*s != '/' && *s != '\0') - *d++ = *s++, *md++ = *m++; /* get first directory component */ + while (*s != '/' && *s != '\0') + *d++ = *s++, *md++ = *m++; /* get first directory component */ *d = '\0'; /* Special case: no slashes in the pattern, i.e., open the current directory. diff --git a/hash.c b/hash.c index 408d0f2..fd182cc 100644 --- a/hash.c +++ b/hash.c @@ -230,7 +230,7 @@ extern void initenv(char **envp) { static bool var_exportable(char *s) { static char *notforexport[] = { - "apid", "pid", "apids", "*", "ifs" + "apid", "apids", "ifs", "path", "pid", "version", "*" }; int i; for (i = 0; i < arraysize(notforexport); i++) diff --git a/input.c b/input.c index 83bd60b..8daa6e2 100644 --- a/input.c +++ b/input.c @@ -125,7 +125,7 @@ static int fdgchar() { } while (r < 0 && errno == EINTR); if (r < 0) { uerror("read"); - rc_exit(1); + rc_raise(eError); } chars_in = (size_t) r; } diff --git a/main.c b/main.c index 0c4b602..d526bd1 100644 --- a/main.c +++ b/main.c @@ -11,8 +11,6 @@ static bool dashoh; static void assigndefault(char *,...); static void checkfd(int, enum redirtype); -static const char id[] = "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $"; - extern int main(int argc, char *argv[], char *envp[]) { char *dashsee[2], *dollarzero, *null[1]; int c; @@ -21,7 +19,7 @@ extern int main(int argc, char *argv[], char *envp[]) { dollarzero = argv[0]; rc_pid = getpid(); dashell = (*argv[0] == '-'); /* Unix tradition */ - while ((c = rc_getopt(argc, argv, "c:deilnopsVvx")) != -1) + while ((c = rc_getopt(argc, argv, "c:deilnopsvx")) != -1) switch (c) { case 'c': dashsee[0] = rc_optarg; @@ -50,9 +48,6 @@ extern int main(int argc, char *argv[], char *envp[]) { case 's': dashess = TRUE; break; - case 'V': - fprint(1, "%s\n", id); - exit(0); case 'v': dashvee = TRUE; break; diff --git a/print.c b/print.c index 9ccccc4..f0f7728 100644 --- a/print.c +++ b/print.c @@ -289,11 +289,11 @@ extern int fmtprint(Format *format, const char *fmt,...) { va_list ap, saveargs; va_start(ap, fmt); - va_copy(saveargs, format->args); - va_copy(format->args, ap); + __va_copy(saveargs, format->args); + __va_copy(format->args, ap); n += printfmt(format, fmt); va_end(format->args); - va_copy(format->args, saveargs); + __va_copy(format->args, saveargs); return n + format->flushed; } @@ -320,7 +320,7 @@ extern int fprint(int fd, const char *fmt,...) { format.u.n = fd; va_start(ap, fmt); - va_copy(format.args, ap); + __va_copy(format.args, ap); printfmt(&format, fmt); va_end(format.args); @@ -365,7 +365,7 @@ extern char *mprint(const char *fmt,...) { format.u.n = 1; va_start(ap, fmt); - va_copy(format.args, ap); + __va_copy(format.args, ap); result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; @@ -378,7 +378,7 @@ extern char *nprint(const char *fmt,...) { format.u.n = 0; va_start(ap, fmt); - va_copy(format.args, ap); + __va_copy(format.args, ap); result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; diff --git a/proto.h b/proto.h index 82e5cb7..7d2fe2a 100644 --- a/proto.h +++ b/proto.h @@ -23,11 +23,11 @@ typedef long align_t; #include -/* C 9x specifies a va_copy() macro which should be used for copying +/* C 9x specifies a __va_copy() macro which should be used for copying objects of type va_list. Of course, most places don't have this yet, but where it does exist we need to use it. */ -#ifndef va_copy -#define va_copy(x,y) (x)=(y) +#ifndef __va_copy +#define __va_copy(x,y) (x)=(y) #endif #if STDC_HEADERS @@ -59,6 +59,15 @@ extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); #endif /* STDC_HEADERS */ +#if HAVE_STRERROR +/* Smells like POSIX. */ +#else +/* Assume BSD-style sys_errlist[]. */ +extern int sys_nerr; +extern char *sys_errlist[]; +#define strerror(x) ((0 <= (x)) && (errno < (x)) ? sys_errlist[x] : (char *)0) +#endif + #if HAVE_UNISTD_H #include #endif diff --git a/rc.1 b/rc.1 index 2df377a..0150e53 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "1999-05-28" +.TH RC 1 "1999-11-11" .SH NAME rc \- shell .SH SYNOPSIS @@ -306,11 +306,6 @@ to read from standard input. Any arguments are placed in .Cr $* . .TP -.Cr \-V -This flag causes -.I rc -to print a version string to standard output, and exit immediately. -.TP .Cr \-v This flag causes .I rc @@ -1195,7 +1190,9 @@ as its value. .SH "SPECIAL VARIABLES" Several variables are known to .I rc -and are treated specially. +and are treated specially. In the following list, +``(read only)'' indicates that an attempt to set the +variable will silently have no effect. .TP .Cr * The argument list of @@ -1225,7 +1222,7 @@ command. .Cr apid The process ID of the last process started in the background. .TP -.Cr apids +.Cr apids " (read only)" The process IDs of any background processes which are outstanding or which have died and have not been waited for yet. .TP @@ -1357,7 +1354,7 @@ If this function is set, then it gets executed every time is about to print .Cr "$prompt(1)" . .TP -.Cr status +.Cr status " (read only)" The exit status of the last command. If the command exited with a numeric value, that number is the status. @@ -1380,6 +1377,11 @@ usually sets .Cr $status to .Cr "(0 0)" . +.TP +.Cr version " (read only)" +This variable contains a string which identifies this +version of +.IR rc . .PP The values of .Cr "$path" , @@ -1950,6 +1952,25 @@ processes. .PP List definitions in exported functions are "noisier" than they need to be. .PP +If both +.Cr $PATH +and +.Cr $path +are set, +.I rc +believes the former. Arguably this is a bug: +.I rc +can quite happily deal with path elements that contain +.Cr : , +but such elements will be split at the colon in descendant +.I rc +processes. +.PP +The +.Cr . +command should search +.Cr $path . +.PP Bug reports should be mailed to .Cr "" . .SH INCOMPATIBILITIES @@ -1957,7 +1978,7 @@ Here is a list of features which distinguish this incarnation of .I rc from the one described in the Bell Labs manual pages: .PP -The v10 +The Tenth Edition .I rc does not have the .B else @@ -1971,12 +1992,25 @@ if the preceding .B if test does not succeed. .PP -Backquotes are slightly different in v10 +Backquotes are slightly different in Tenth Edition .IR rc : a backquote must always be followed by a left-brace. This restriction is not present for single-word commands in this .IR rc . .PP +For +.Cr . +.IR file , +the Tenth Edition +.IR rc +searches +.Cr $path +for +.IR file . +This +.I rc +does not; this is a bug. +.PP The list flattening operator, .Cr $^foo , is spelt diff --git a/status.c b/status.c index b594e4b..5b37aa5 100644 --- a/status.c +++ b/status.c @@ -2,6 +2,7 @@ #include "rc.h" #include "sigmsgs.h" +#include "statval.h" #include "wait.h" /* status == the wait() value of the last command in the pipeline, or the last command */ @@ -40,7 +41,7 @@ extern int getstatus() { } extern void set(bool code) { - setstatus(-1, (!code) << 8); /* exit status 1 == 0x100 */ + setstatus(-1, code ? STATUS0 : STATUS1); } /* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */ diff --git a/trip.rc b/trip.rc index a0d5677..0b9ca0f 100644 --- a/trip.rc +++ b/trip.rc @@ -2,7 +2,7 @@ # Invoke as "path-to-new-rc < trip.rc" rc=$0 -echo tripping $rc +echo tripping $rc $version fn fail { echo >[1=2] trip took a wrong turn: $* diff --git a/utils.c b/utils.c index ded0c03..00be28b 100644 --- a/utils.c +++ b/utils.c @@ -19,14 +19,15 @@ extern void pr_error(char *s, int offset) { /* our perror */ extern void uerror(char *s) { - extern int sys_nerr; - extern char *sys_errlist[]; - if (errno > sys_nerr) - return; - if (s != NULL) - fprint(2, "%s: %s\n", s, sys_errlist[errno]); + char *err; + + err = strerror(errno); + if (!err) err = "unknown error"; + + if (s) + fprint(2, "%s: %s\n", s, err); else - fprint(2, "%s\n", sys_errlist[errno]); + fprint(2, "%s\n", err); } /* Die horribly. This should never get called. Please let me know if it does. */ diff --git a/var.c b/var.c index 8ef453b..e7161de 100644 --- a/var.c +++ b/var.c @@ -57,14 +57,19 @@ extern bool varassign_string(char *extdef) { associated with $status) */ +static List id2 = { "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $", 0, 0 }; +static List id1 = { VERSION, 0, &id2 }; + extern List *varlookup(char *name) { Variable *look; List *ret, *l; int sub; - if (streq(name, "status")) - return sgetstatus(); if (streq(name, "apids")) return sgetapids(); + if (streq(name, "status")) + return sgetstatus(); + if (streq(name, "version")) + return &id1; if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */ for (l = varlookup("*"); l != NULL && sub != 0; --sub) l = l->n; -- cgit v1.2.3 From 14106ccc3b2cb03c8b9a1df1a1b3e3953aaee2f8 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Fri, 10 Dec 1999 11:55:04 +0000 Subject: beta: rc-1.6b2 --- ChangeLog | 13 +++++++++++++ README | 2 +- configure.ac | 2 +- glob.c | 7 +++++-- rc.1 | 23 +++++++++++++++++------ signal.c | 18 +++++++++--------- trip.rc | 4 ++++ 7 files changed, 50 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index b93ccad..d778b29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -652,3 +652,16 @@ Changes since rc-1.5b2 `-L' options, not LIBS. Release: rc-1.6b1. + +1999-12-10 + + Bug: absolute globs do still need a special case. `/*' works again now, but + we still avoid creating names like `//tmp/foo'. + + Bug: avoid a putative race condition in signal.c. + + Documentation: extra parentheses around `~' and `!' expressions are + forbidden. Tom Duff's paper is not distributed with rc, but is + available on the web. + + Release: rc-1.6b2. diff --git a/README b/README index 8c0d641..22c1da8 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is beta release rc-1.6b1. +This is beta release rc-1.6b2. See COPYING for copying information. All files are diff --git a/configure.ac b/configure.ac index c192496..f4950c2 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6b1) +AM_INIT_AUTOMAKE(rc, 1.6b2) AM_CONFIG_HEADER(config.h) diff --git a/glob.c b/glob.c index 03d8a42..cd62d65 100644 --- a/glob.c +++ b/glob.c @@ -127,6 +127,7 @@ static List *dmatch(char *d, char *p, char *m) { } top = r = NULL; + if (*d == '\0') d = "/"; if ((dirp = opendir(d)) == NULL) return NULL; /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */ @@ -216,8 +217,10 @@ static List *doglob(char *w, char *m) { p = pattern; md = metadir; mp = metapattern; - while (*s != '/' && *s != '\0') - *d++ = *s++, *md++ = *m++; /* get first directory component */ + while (*s != '/' && *s != '\0') { + *d++ = *s++; /* get first directory component */ + *md++ = *m++; + } *d = '\0'; /* Special case: no slashes in the pattern, i.e., open the current directory. diff --git a/rc.1 b/rc.1 index 0150e53..325374e 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "1999-11-11" +.TH RC 1 "1999-12-10" .SH NAME rc \- shell .SH SYNOPSIS @@ -1971,6 +1971,17 @@ The command should search .Cr $path . .PP +Extra parentheses around a +.Cr ~ +expression or a +.Cr ! +expression are a syntax error. Thus, this +code is illegal. +.Ds +.Cr "while ((~ $1 -*) && (! ~ $1 --)) { ..." +.De +The redundant inner parentheses must be omitted. +.PP Bug reports should be mailed to .Cr "" . .SH INCOMPATIBILITIES @@ -2049,10 +2060,10 @@ being sourced. .SH "SEE ALSO" ``rc \(em A Shell for Plan 9 and UNIX Systems'', Unix Research System, -10th Edition, -vol. 2. (Saunders College Publishing) -(This paper is also distributed with this -.I rc -in PostScript form.) +Tenth Edition, +Volume 2. (Saunders College Publishing) +.PP +.Cr http://www.star.le.ac.uk/~tjg/rc/misc/td.html , +an updated version of the above paper. .PP .IR history (1) diff --git a/signal.c b/signal.c index 8535eab..ca34dfa 100644 --- a/signal.c +++ b/signal.c @@ -85,19 +85,19 @@ extern void initsignal() { void (*h)(int); int i; - for (i = 1; i < NUMOFSIGNALS; i++) { - h = sys_signal(i, SIG_DFL); - if (h != SIG_DFL && h != SIG_ERR) - sys_signal(i, h); - sighandlers[i] = h; - } - #if HAVE_SYSV_SIGCLD /* Ensure that SIGCLD is not SIG_IGN. Solaris's rshd does this. :-( */ - h = sys_signal(SIGCLD, SIG_DFL); + h = sys_signal(SIGCLD, SIG_IGN); if (h != SIG_IGN && h != SIG_ERR) sys_signal(SIGCLD, h); else - sighandlers[SIGCLD] = SIG_DFL; + sys_signal(SIGCLD, SIG_DFL); #endif + + for (i = 1; i < NUMOFSIGNALS; i++) { + h = sys_signal(i, SIG_IGN); + if (h != SIG_IGN && h != SIG_ERR) + sys_signal(i, h); + sighandlers[i] = h; + } } diff --git a/trip.rc b/trip.rc index 0b9ca0f..a381db4 100644 --- a/trip.rc +++ b/trip.rc @@ -565,3 +565,7 @@ expect foo bar qux $rc -s foo bar qux <<'eof' echo $* eof + +# Believe it or not, I broke root directory globbing in rc-1.6b1. +x=/* +~ '/*' $^x && fail root directory globbing -- cgit v1.2.3 From 609a278bf6e301ea9a021793de314ddcadb806ba Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Fri, 12 Oct 2001 10:25:58 +0100 Subject: beta: rc-1.6b3 --- AUTHORS | 10 +-- COPYING | 2 +- ChangeLog | 58 +++++++++++++++ Futures | 12 ++++ INSTALL | 7 +- Makefile.am | 2 + NEWS | 41 +++++------ README | 6 +- acconfig.h | 3 + acinclude.m4 | 13 ++++ builtins.c | 6 +- configure.ac | 6 +- footobar.c | 141 ++++++++++++++++++++++++------------ glob.c | 18 ++--- glom.c | 3 +- hash.c | 3 +- heredoc.c | 10 +-- input.c | 53 +++++++++----- lex.c | 27 +++++-- main.c | 12 ++-- mksignal.c | 17 ++--- nalloc.c | 3 +- open.c | 18 +++++ parse.y | 8 +-- print.c | 4 -- proto.h | 5 +- rc.1 | 231 +++++++++++++++++++++++++++++++++++------------------------ rc.h | 17 +++-- tree.c | 9 +-- trip.rc | 41 +++++++---- tripping.c | 11 ++- utils.c | 2 +- var.c | 2 +- walk.c | 6 +- 34 files changed, 536 insertions(+), 271 deletions(-) create mode 100644 Futures diff --git a/AUTHORS b/AUTHORS index b8d18e0..bde6a37 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,8 +29,8 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, Dale -Scheetz, David Luyer, David Swasey, Donn Cave, Gerry Tomlinson, Gert-Jan -Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc Moorcroft, Mark H -Wilkinson, Mark K Gardner, Raymond Venneker, Rich $alz, Rob Savoye, -Scott Schwartz, Stefan Dalibor, Steve Simon, Tom Culliton, Tom Tromey, -Vincent Broman, Wolfgang Zekoll. +Scheetz, David Luyer, David Swasey, Decklin Foster, Donn Cave, Gerry +Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc +Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond Venneker, Rich +$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve Simon, Thomas +Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang Zekoll. diff --git a/COPYING b/COPYING index 8ce4998..03ca62d 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ /* - * Copyright 1991, 1999 Byron Rakitzis. All rights reserved. + * Copyright 1991, 2001 Byron Rakitzis. All rights reserved. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. diff --git a/ChangeLog b/ChangeLog index d778b29..40f3aad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -665,3 +665,61 @@ Changes since rc-1.5b2 available on the web. Release: rc-1.6b2. + +2000-04-19 + + Bug: isatty() tests in input.c are relevant to any fd, not just 0. + Now `. -i /dev/tty' works right. + + Bug: fn sigexit wasn't always cleared in child shells. + + Bug: `~ () '*'' dumped core. + +2000-05-25 + + Portability: need special runes for read() returning EIO under job + control systems. + +2000-06-20 + + Feature: add `-I' flag (definitively not interactive) for + compatibility with Plan 9 rc. + +2000-11-27 + + Portability: configure fails to detect strerror() on NetBSD; we need + to include . + +2001-06-18 + + Bug: you can't pass a short to a stdargs function! + +2001-09-27 + + Documentation: we don't consider that `.' failing to search path is + a bug. + + Feature: ^A in lists is now handled transparently. + +2001-10-01 + + Bug: it's no longer possible to use parentheses to sneak a word that + needs quoting past the "quoting detector", so `fn x { echo $(x.y) }' + now works both in the current rc and its descendants. + + Documentation: mention the catastrophic effects of a semantic error + in fn prompt. + +2001-10-03 + + Feature: exported lists no longer use redundant parentheses. + +2001-10-04 + + Bug: semantic errors in `fn prompt' no longer throw rc into a tailspin. + + Feature: don't export $cdpath or $home (the lower-case versions). + +2001-10-12 + + Release: rc-1.6b3. diff --git a/Futures b/Futures new file mode 100644 index 0000000..9188087 --- /dev/null +++ b/Futures @@ -0,0 +1,12 @@ +I18N. + +Offer more control over what rc prints about commands (e.g. a way to +allow EPIPE to generate an error). + +Faster; smaller; cheaper. + +Dynamically load readline and friends. + +Make --disable-def-interp the default. + +Allow builtin wait more than one argument. diff --git a/INSTALL b/INSTALL index 63a11fe..cf80210 100644 --- a/INSTALL +++ b/INSTALL @@ -150,8 +150,11 @@ produce a few warnings. Warnings about "implicit declaration" of system functions may occur if your system's include files are deficient---they are usually harmless. -There is a warning about "variable `n' might be clobbered" in walk.c. -I'm not sure how serious this warning is, nor how to eliminate it. +Some older versions of gcc warn about "variable `n' might be +clobbered" in walk.c. As far as I can tell, this is gcc telling you +that it might not be compiling the code correctly! I don't know how +to eliminate the warning, but it doesn't appear to cause any problems +in practice. On some systems there are warnings about "passing arg 2 of `getgroups' from incompatible pointer type" in which.c. I believe this is due to an diff --git a/Makefile.am b/Makefile.am index 76b3514..6de407a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,6 +61,8 @@ DISTCLEANFILES = sigmsgs.c sigmsgs.h statval.h # mv y.tab.c parse.c # mv y.tab.h parse.h +check: trip + trip: rc tripping ./rc -p < $(srcdir)/trip.rc diff --git a/NEWS b/NEWS index 320ad47..34b7d6d 100644 --- a/NEWS +++ b/NEWS @@ -1,29 +1,24 @@ -Highlights of changes since rc-1.4. See ChangeLog for further details. +Highlights of changes since rc-1.6. See ChangeLog for further details. -Portability. The major change since the last full release is that rc -now uses GNU autoconf and automake. Other parts of the build process -have been tidied up too, so that building rc should now be painless. It -has been tested on a wide variety of Unix-like systems. +Portability. Many minor tweaks, including fixes for BeOS, CygWin, and +gcc-3. -Bug fixes. The following bugs have been fixed: the interaction with -readline was not always correct; SIGCLD set to SIG_IGN could cause a -hang; some obscure pipeline incantations could cause a hang; the `wait' -builtin could become uninterruptible; an application could crash rc -by making stdin nonblocking; the `-i' flag didn't work with readline; -$history didn't work properly over NFS; a few memory leaks; and an off -by one bug in reporting line numbers of errors. +Bug fixes. A number of bugs have been fixed. The serious ones were: +a core dump, triggered by `~ () '*''; premature exit, triggered by +sourcing a file which could be open()ed but not read() (such as a +directory on many systems); uninterruptible looping, triggered by +semantic errors in `fn prompt'. -New features. The following features are new: the `-s' flag, which -causes rc to read from stdin even if arguments are present; the `-V' -flag, which prints a version string; $bqstatus which holds the exit -status of the last backquote command; additional options to the `whatis' -builtin; and support for vrl, another lightweight readline-style -library. +New features. The following features are new: the `$version' variable +replaces the `-V' flag; the `-I' flag (definitively not interactive) +was added for compatibility with the Plan 9 rc; ASCII SOH (^A) is now +handled transparently. -What happened to rc-1.5? A number of beta releases were made with names -like rc-1.5b2, which might suggest improvements over rc-1.5. To avoid -any possibility of confusion, I decided to name this release rc-1.6 -instead. +Documentation. Distributions of this rc used to include a PostScript +paper given by Tom Duff to the UKUUG, describing the Plan 9 rc. This +paper is no longer distributed with rc, but instead is available on +the web, both in its original PostScript version, and an updated HTML +version. Tim Goodwin -1999-05-26 +2001-10-05 diff --git a/README b/README index 22c1da8..6b6c181 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -This is beta release rc-1.6b2. +This is beta release rc-1.6b3. See COPYING for copying information. All files are - Copyright 1991, 1999 Byron Rakitzis. + Copyright 1991, 2001 Byron Rakitzis. See INSTALL for build and installation information. @@ -24,7 +24,7 @@ make rc; this information is extremely valuable. FEEPING CREATURISM -See the end of the man page, under "INCOMPATABILITIES" for (known?) +See the end of the man page, under "INCOMPATIBILITIES" for (known?) differences from the "real" rc. Most of these changes were necessary to get rc to work in a reasonable fashion on a real (i.e. commercial, non-Labs) Unix system; a few were changes motivated by concern about diff --git a/acconfig.h b/acconfig.h index 8e8c0e7..c5b9bcf 100644 --- a/acconfig.h +++ b/acconfig.h @@ -34,6 +34,9 @@ /* Define if you have sigsetjmp(). */ #undef HAVE_SIGSETJMP +/* Define in you have strerror(). */ +#undef HAVE_STRERROR + /* Define if you want rc to encode strange characters in the environment. */ #undef PROTECT_ENV diff --git a/acinclude.m4 b/acinclude.m4 index 697b326..7fbc6aa 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -29,6 +29,19 @@ sigsetjmp(e, 1); esac ]) +dnl Similarly, AC_CHECK_FUNCS doesn't find strerror() on NetBSD. +AC_DEFUN(RC_FUNC_STRERROR, [ + AC_CACHE_CHECK(for strerror, rc_cv_strerror, + AC_TRY_LINK([ +#include + ], [ +strerror(0); + ], rc_cv_strerror=yes, rc_cv_strerror=no)) + case "$rc_cv_strerror" in + yes) AC_DEFINE(HAVE_STRERROR) ;; + esac +]) + dnl HPUX needs _KERNEL defined to pick up RLIMIT_foo defines. (Why?) AC_DEFUN(RC_NEED_KERNEL, [ AC_CACHE_CHECK(if _KERNEL is required for RLIMIT defines, rc_cv_kernel_rlimit, diff --git a/builtins.c b/builtins.c index dcea06d..283d2fa 100644 --- a/builtins.c +++ b/builtins.c @@ -251,7 +251,7 @@ extern void b_builtin(char **ignore) { /* wait for a given process, or all outstanding processes */ static void b_wait(char **av) { - int stat; + int status; pid_t pid; if (av[1] == NULL) { waitforall(); @@ -265,8 +265,8 @@ static void b_wait(char **av) { badnum(av[1]); return; } - if (rc_wait4(pid, &stat, FALSE) > 0) - setstatus(pid, stat); + if (rc_wait4(pid, &status, FALSE) > 0) + setstatus(pid, status); else set(FALSE); sigchk(); diff --git a/configure.ac b/configure.ac index f4950c2..6792d85 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6b2) +AM_INIT_AUTOMAKE(rc, 1.6b3) AM_CONFIG_HEADER(config.h) @@ -38,13 +38,15 @@ AC_TYPE_SIZE_T AC_TYPE_UID_T AC_CHECK_TYPE(ssize_t, long) -AC_CHECK_FUNCS(getgroups setpgrp setrlimit strerror) +AC_CHECK_FUNCS(getgroups setpgrp setrlimit) RC_FUNC_GETGROUPS RC_FUNC_SIGSETJMP AC_FUNC_SETPGRP +RC_FUNC_STRERROR + RC_NEED_KERNEL RC_TYPE_RLIM_T diff --git a/footobar.c b/footobar.c index 43a44d9..4430c05 100644 --- a/footobar.c +++ b/footobar.c @@ -46,14 +46,14 @@ static int defaultfd(int op) { /* convert a function in Node * form into something rc can parse (and humans can read?) */ static bool Tconv(Format *f, int ignore) { + bool dollar = f->flags & FMT_altform; Node *n = va_arg(f->args, Node *); + if (n == NULL) { fmtprint(f, "()"); return FALSE; } switch (n->type) { - case nWord: fmtprint(f, "%S", n->u[0].s); break; - case nQword: fmtprint(f, "%#S", n->u[0].s); break; case nBang: fmtprint(f, "!%T", n->u[0].p); break; case nCase: fmtprint(f, "case %T", n->u[0].p); break; case nNowait: fmtprint(f, "%T&", n->u[0].p); break; @@ -70,21 +70,34 @@ static bool Tconv(Format *f, int ignore) { case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break; case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break; case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break; - case nLappend: fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); break; case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break; case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; + case nWord: + fmtprint(f, quotep(n->u[0].s, dollar) ? "%#S" : "%S", n->u[0].s); + break; + case nLappend: { + static bool inlist; + if (!inlist) { + inlist = TRUE; + fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); + inlist = FALSE; + } else { + fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); + } + break; + } case nCount: case nFlat: case nVar: { char *lp = "", *rp = ""; Node *n0 = n->u[0].p; - if (n0->type != nWord && n0->type != nQword) + if (n0->type != nWord) lp = "(", rp = ")"; switch (n->type) { default: panic("this can't happen"); break; - case nCount: fmtprint(f, "$#%s%T%s", lp, n0, rp); break; - case nFlat: fmtprint(f, "$^%s%T%s", lp, n0, rp); break; - case nVar: fmtprint(f, "$%s%T%s", lp, n0, rp); break; + case nCount: fmtprint(f, "$#%s%#T%s", lp, n0, rp); break; + case nFlat: fmtprint(f, "$^%s%#T%s", lp, n0, rp); break; + case nVar: fmtprint(f, "$%s%#T%s", lp, n0, rp); break; } break; } @@ -212,45 +225,52 @@ extern char *get_name(char *s) { } } -/* - Hacky routine to split a ^A-separated environment variable. Scans - backwards. Be VERY CAREFUL with the loop boundary conditions. e.g., - notice what happens when there is no ^A in the extdef. (It does - the right thing, of course :-) -*/ - -#define skipleft(p) do --p; while (*p != '\0' && *p != '\001'); +/* interpret a variable from environment. ^A separates list elements; + ^B escapes a literal ^A or ^B. For minimal surprise, ^B followed + by anything other than ^A or ^B is preserved. */ extern List *parse_var(char *extdef) { - char *endp, *realend, *sepp; - List *tailp, *new; - - extdef = strchr(extdef, '='); - *extdef++ = '\0'; /* null "initiate" the string for rtol scanning */ - - sepp = realend = strchr(extdef, '\0'); - tailp = NULL; - - while (1) { - endp = sepp; /* set endp to end of current mebmer */ - skipleft(sepp); /* advance sepp to the previous \1, */ - *endp = '\0'; /* and null terminate the member. */ - + char *begin, *end, *from, *to; + int len; + List *first, *last, *new; + + first = last = NULL; + begin = strchr(extdef, '='); + assert(begin); /* guaranteed by initenv() */ + while (*begin) { + ++begin; + end = begin; + len = 0; + while (*end != ENV_SEP && *end != '\0') { + if (*end == ENV_ESC) { + ++end; + if (*end != ENV_SEP && *end != ENV_ESC) --end; + } + ++end; ++len; + } new = enew(List); - new->w = ecpy(sepp+1); + if (last) + last->n = new; + else + first = new; + last = new; + new->w = ealloc(len + 1); new->m = NULL; - new->n = tailp; - tailp = new; - - if (sepp < extdef) /* break when sepp hits the null "initiator" */ - break; - if (endp != realend) /* else restore the \1 in between members */ - *endp = '\001'; + new->n = NULL; + to = new->w; + for (from = begin; from < end; ++from) { + if (*from == ENV_ESC) { + ++from; + if (*from != ENV_SEP && *from != ENV_ESC) + --from; + } + *to = *from; + ++to; + } + *to = '\0'; + begin = end; } - if (endp != realend) - *endp = '\001'; - *--extdef = '='; /* restore extdef '=' */ - return tailp; + return first; } /* get an environment entry for a function and have rc parse it. */ @@ -279,16 +299,42 @@ static bool Aconv(Format *f, int ignore) { return FALSE; } +/* %L -- print a list */ static bool Lconv(Format *f, int ignore) { - List *l = va_arg(f->args, List *); - char *sep = va_arg(f->args, char *); - char *fmt = (f->flags & FMT_leftside) ? "%s%s" : "%-S%s"; + bool plain; + char *sep; + List *l, *n; + + plain = f->flags & FMT_leftside; + l = va_arg(f->args, List *); + sep = va_arg(f->args, char *); if (l == NULL && (f->flags & FMT_leftside) == 0) fmtprint(f, "()"); else { - List *s; - for (s = l; s != NULL; s = s->n) - fmtprint(f, fmt, s->w, s->n == NULL ? "" : sep); + for (; l != NULL; l = n) { + n = l->n; + fmtprint(f, plain ? "%s" : "%-S", l->w); + if (n != NULL) fmtputc(f, *sep); + } + } + return FALSE; +} + +/* %W -- print a list for exporting */ +static bool Wconv(Format *f, int ignore) { + List *l, *n; + + l = va_arg(f->args, List *); + for (; l != NULL; l = n) { + char c, *s; + + for (s = l->w; (c = *s) != '\0'; ++s) { + if (c == ENV_SEP || c == ENV_ESC) + fmtputc(f, ENV_ESC); + fmtputc(f, c); + } + n = l->n; + if (n != NULL) fmtputc(f, ENV_SEP); } return FALSE; } @@ -329,6 +375,7 @@ void initprint(void) { fmtinstall('S', Sconv); fmtinstall('T', Tconv); fmtinstall('D', Dconv); + fmtinstall('W', Wconv); #if PROTECT_ENV fmtinstall('F', Fconv); #else diff --git a/glob.c b/glob.c index cd62d65..ac26203 100644 --- a/glob.c +++ b/glob.c @@ -34,23 +34,13 @@ static List *sort(List *); extern bool lmatch(List *s, List *p) { List *q; - int i; - bool okay; if (s == NULL) { if (p == NULL) /* null matches null */ return TRUE; - for (; p != NULL; p = p->n) { /* one or more stars match null */ - if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */ - okay = TRUE; - for (i = 0; p->w[i] != '\0'; i++) - if (p->w[i] != '*' || p->m[i] != 1) { - okay = FALSE; - break; - } - if (okay) - return TRUE; - } - } + for (; p != NULL; p = p->n) /* one or more stars match null */ + if (strspn(p->w, "*") == strlen(p->w) && + p->m != NULL && strlen(p->m) == strlen(p->w)) + return TRUE; return FALSE; } for (; s != NULL; s = s->n) diff --git a/glom.c b/glom.c index ea6b432..c44f0d5 100644 --- a/glom.c +++ b/glom.c @@ -384,7 +384,7 @@ extern List *glom(Node *n) { words = n->u[0].p; tail = NULL; while (words != NULL && (words->type == nArgs || words->type == nLappend)) { - if (words->u[1].p != NULL && words->u[1].p->type != nWord && words->u[1].p->type != nQword) + if (words->u[1].p != NULL && words->u[1].p->type != nWord) break; head = glom(words->u[1].p); if (head != NULL) { @@ -405,7 +405,6 @@ extern List *glom(Node *n) { qredir(n); return NULL; case nWord: - case nQword: return word(n->u[0].s, n->u[1].s); case nNmpipe: return mkcmdarg(n); diff --git a/hash.c b/hash.c index fd182cc..16971ef 100644 --- a/hash.c +++ b/hash.c @@ -230,7 +230,8 @@ extern void initenv(char **envp) { static bool var_exportable(char *s) { static char *notforexport[] = { - "apid", "apids", "ifs", "path", "pid", "version", "*" + "apid", "apids", "cdpath", "home", "ifs", + "path", "pid", "version", "*" }; int i; for (i = 0; i < arraysize(notforexport); i++) diff --git a/heredoc.c b/heredoc.c index ba4fd3a..922fc12 100644 --- a/heredoc.c +++ b/heredoc.c @@ -82,14 +82,14 @@ static Node *parseheredoc(char *s) { while ((c = *s++) != '\0' && c != '$') ; *--s = '\0'; - node = mk(nQword, begin, NULL); + node = mk(nWord, begin, NULL); break; } case '$': { char *begin = ++s, *var; c = *s++; if (c == '$') { - node = mk(nQword, "$", NULL); + node = mk(nWord, "$", NULL); c = *s; } else { size_t len = 0; @@ -129,7 +129,7 @@ extern int heredoc(int end) { char *s = readheredoc(here->name); if (dead) return FALSE; - n->u[2].p = here->quoted ? mk(nQword, s, NULL) : parseheredoc(s); + n->u[2].p = here->quoted ? mk(nWord, s, NULL, FALSE) : parseheredoc(s); n->u[0].i = rHerestring; } while ((here = here->n) != NULL); } @@ -140,7 +140,7 @@ extern int heredoc(int end) { extern int qdoc(Node *name, Node *n) { Hq *new, **prev; - if (name->type != nWord && name->type != nQword) { + if (name->type != nWord) { yyerror("eof-marker not a single literal word"); flushu(); return FALSE; @@ -149,7 +149,7 @@ extern int qdoc(Node *name, Node *n) { ; *prev = new = nnew(Hq); new->name = name->u[0].s; - new->quoted = (name->type == nQword); + new->quoted = name->u[2].i; new->doc = n; new->n = NULL; return TRUE; diff --git a/input.c b/input.c index 8daa6e2..7c0dde7 100644 --- a/input.c +++ b/input.c @@ -38,7 +38,11 @@ static Input *istack, *itop; static int (*realgchar)(void); static void (*realugchar)(int); -int last; +int lastchar; + +#if EDITLINE || READLINE +static char *rlinebuf, *prompt; +#endif #if EDITLINE || READLINE static char *rlinebuf, *prompt; @@ -49,7 +53,7 @@ extern int gchar() { if (eofread) { eofread = FALSE; - return last = EOF; + return lastchar = EOF; } while ((c = (*realgchar)()) == '\0') @@ -63,7 +67,7 @@ extern void ugchar(int c) { } static int dead() { - return last = EOF; + return lastchar = EOF; } static void ugdead(int ignore) { @@ -80,7 +84,7 @@ static void ugalive(int c) { /* get the next character from a string. */ static int stringgchar() { - return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); + return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); } /* @@ -94,7 +98,7 @@ static int fdgchar() { if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */ while (1) { #if EDITLINE || READLINE - if (interactive && istack->fd == 0 && isatty(0)) { + if (interactive && istack->t == iFd && isatty(istack->fd)) { /* The readline library doesn't handle read() returning EAGAIN. */ makeblocking(istack->fd); rlinebuf = rc_readline(prompt); @@ -117,10 +121,18 @@ static int fdgchar() { do { r = rc_read(istack->fd, inbuf + 2, BUFSIZE); sigchk(); - if (errno == EAGAIN) { + switch (errno) { + case EAGAIN: if (!makeblocking(istack->fd)) panic("not O_NONBLOCK"); errno = EINTR; + break; + case EIO: + if (makesamepgrp(istack->fd)) + errno = EINTR; + else + errno = EIO; + break; } } while (r < 0 && errno == EINTR); if (r < 0) { @@ -132,13 +144,13 @@ static int fdgchar() { break; } if (chars_in == 0) - return last = EOF; + return lastchar = EOF; chars_out = 2; if (dashvee) writeall(2, inbuf + 2, chars_in); history(); } - return last = inbuf[chars_out++]; + return lastchar = inbuf[chars_out++]; } /* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */ @@ -159,7 +171,7 @@ static void pushcommon() { istack->ibuf = inbuf; istack->lineno = lineno; istack->saved = save_lineno; - istack->last = last; + istack->last = lastchar; istack->eofread = eofread; istack++; idiff = istack - itop; @@ -206,7 +218,7 @@ extern void popinput() { realgchar = dead; realugchar = ugdead; } - last = istack->last; + lastchar = istack->last; eofread = istack->eofread; inbuf = istack->ibuf; chars_out = istack->index; @@ -222,7 +234,7 @@ extern void popinput() { extern void flushu() { int c; - if (last == '\n' || last == EOF) + if (lastchar == '\n' || lastchar == EOF) return; while ((c = gchar()) != '\n' && c != EOF) ; /* skip to newline */ @@ -234,9 +246,9 @@ extern void flushu() { extern Node *doit(bool clobberexecit) { bool eof; - bool execit ; + bool execit; Jbwrap j; - Estack e1, e2; + Estack e1; Edata jerror; if (dashen) @@ -247,6 +259,7 @@ extern Node *doit(bool clobberexecit) { except(eError, jerror, &e1); for (eof = FALSE; !eof;) { Edata block; + Estack e2; block.b = newblock(); except(eArena, block, &e2); sigchk(); @@ -261,12 +274,18 @@ extern Node *doit(bool clobberexecit) { if (interactive) { List *s; if (!dashen && fnlookup("prompt") != NULL) { + static bool died = FALSE; static char *arglist[] = { "prompt", NULL }; - funcall(arglist); + + if (!died) { + died = TRUE; + funcall(arglist); + } + died = FALSE; } if ((s = varlookup("prompt")) != NULL) { #if EDITLINE || READLINE - if (istack->t == iFd && istack->fd == 0 && isatty(0)) + if (istack->t == iFd && isatty(istack->fd)) prompt = s->w; else #endif @@ -277,7 +296,7 @@ extern Node *doit(bool clobberexecit) { inityy(); if (yyparse() == 1 && execit) rc_raise(eError); - eof = (last == EOF); /* "last" can be clobbered during a walk() */ + eof = (lastchar == EOF); /* "lastchar" can be clobbered during a walk() */ if (parsetree != NULL) { if (execit) walk(parsetree, TRUE); @@ -353,7 +372,7 @@ extern void print_prompt2() { lineno++; if (interactive) { #if EDITLINE || READLINE - if (istack->t == iFd && istack->fd == 0 && isatty(0)) + if (istack->t == iFd && isatty(istack->fd)) prompt = prompt2; else #endif diff --git a/lex.c b/lex.c index 7e35cdd..6bc92da 100644 --- a/lex.c +++ b/lex.c @@ -69,6 +69,18 @@ enum filedescriptors { UNSET = -9, CLOSED = -1 }; +/* does this string require quoting? */ +extern bool quotep(char *s, bool dollar) { + unsigned char c; + const char *meta; + + meta = dollar ? dnw : nw; + while ((c = *s++)) + if (meta[c]) + return TRUE; + return FALSE; +} + extern int yylex() { static bool dollar = FALSE; bool saw_meta = FALSE; @@ -147,6 +159,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') } else { y->word.m = NULL; } + y->word.q = FALSE; return WORD; } if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') { @@ -179,7 +192,8 @@ top: while ((c = gchar()) == ' ' || c == '\t') case '\'': w = RW; i = 0; - do { + /* double ' to quote it, like this: 'how''s it going?' */ + while ((c = gchar()) != '\'' || (c = gchar()) == '\'') { buf[i++] = c; if (c == '\n') print_prompt2(); @@ -190,11 +204,12 @@ top: while ((c = gchar()) == ' ' || c == '\t') } if (i >= bufsize) buf = realbuf = erealloc(buf, bufsize *= 2); - } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */ + } ugchar(c); buf[i] = '\0'; y->word.w = ncpy(buf); y->word.m = NULL; + y->word.q = TRUE; return WORD; case '\\': if ((c = gchar()) == '\n') { @@ -306,13 +321,13 @@ extern void yyerror(const char *s) { if (!interactive) { if (w != NW) tok = realbuf; - else if (last == EOF) + else if (lastchar == EOF) tok = "eof"; - else if (last == '\n') + else if (lastchar == '\n') tok = "end of line"; else - tok = nprint((last < 32 || last > 126) ? "(decimal %d)" : "'%c'", last); - fprint(2, "line %d: %s near %s\n", lineno - (last == '\n'), s, tok); + tok = nprint((lastchar < 32 || lastchar > 126) ? "(decimal %d)" : "'%c'", lastchar); + fprint(2, "line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok); } else fprint(2, "%s\n", s); } diff --git a/main.c b/main.c index d526bd1..57a79c3 100644 --- a/main.c +++ b/main.c @@ -2,7 +2,7 @@ #include "rc.h" -bool dashdee, dashee, dashvee, dashex, dashell, dasheye, +bool dashdee, dashee, dashvee, dashex, dashell, dashEYE, dasheye, dashen, dashpee, dashess, interactive; pid_t rc_pid; @@ -19,7 +19,7 @@ extern int main(int argc, char *argv[], char *envp[]) { dollarzero = argv[0]; rc_pid = getpid(); dashell = (*argv[0] == '-'); /* Unix tradition */ - while ((c = rc_getopt(argc, argv, "c:deilnopsvx")) != -1) + while ((c = rc_getopt(argc, argv, "c:deiIlnopsvx")) != -1) switch (c) { case 'c': dashsee[0] = rc_optarg; @@ -30,6 +30,10 @@ extern int main(int argc, char *argv[], char *envp[]) { case 'e': dashee = TRUE; break; + case 'I': + dashEYE = TRUE; + interactive = FALSE; + break; case 'i': dasheye = interactive = TRUE; break; @@ -59,8 +63,8 @@ extern int main(int argc, char *argv[], char *envp[]) { } quitopts: argv += rc_optind; - /* use isatty() iff -i is not set, and iff the input is not from a script or -c flags */ - if (!dasheye && dashsee[0] == NULL && (dashess || *argv == NULL)) + /* use isatty() iff neither -i nor -I is set, and iff the input is not from a script or -c flags */ + if (!dasheye && !dashEYE && dashsee[0] == NULL && (dashess || *argv == NULL)) interactive = isatty(0); if (!dashoh) { checkfd(0, rFrom); diff --git a/mksignal.c b/mksignal.c index 5677271..c66ad49 100644 --- a/mksignal.c +++ b/mksignal.c @@ -1,5 +1,6 @@ -#include #include +#include +#include #ifdef NSIG #define NUMSIG NSIG @@ -7,13 +8,13 @@ #define NUMSIG 1 #endif -typedef struct { +struct signaming { int signo; - char *signame; - char *sigmsg; -} signaming; + const char *signame; + const char *sigmsg; +}; -static signaming signamings[] = { +static struct signaming signamings[] = { #ifdef SIGABRT { SIGABRT, "sigabrt", "abort"}, #endif @@ -191,7 +192,7 @@ static signaming signamings[] = { { 0, 0, 0} }; -static void barf(char *msg) { +static void barf(const char *msg) { fprintf(stderr, "mksignals: %s\n", msg); exit(1); } @@ -199,7 +200,7 @@ static void barf(char *msg) { int main(void) { int maxsig = NUMSIG-1; int s; - signaming *snp; + struct signaming *snp; FILE *outf; for (snp = signamings; snp->signo; ++snp) diff --git a/nalloc.c b/nalloc.c index 25e75a1..eb621e0 100644 --- a/nalloc.c +++ b/nalloc.c @@ -50,7 +50,8 @@ extern void *nalloc(size_t n) { ulp->used = base + n; return &ulp->mem[base]; } else { - getblock(n); /* assert(ul->used) == 0 */ + getblock(n); + assert(ul->used == 0); (ulp = ul)->used = n; return &ulp->mem[0]; } diff --git a/open.c b/open.c index bac9f2c..60555b0 100644 --- a/open.c +++ b/open.c @@ -43,3 +43,21 @@ extern bool makeblocking(int fd) { } return TRUE; } + +/* make a file descriptor the same pgrp as us. Returns TRUE if +it changes anything. */ + +extern bool makesamepgrp(int fd) { + pid_t grp; + + grp = getpgrp(); + + if (tcgetpgrp(fd) == grp) + return FALSE; + + if (tcsetpgrp(fd, grp) < 0) { + uerror("tcsetgrp"); + return FALSE; + } + return TRUE; +} diff --git a/parse.y b/parse.y index b1bcf85..f83e673 100644 --- a/parse.y +++ b/parse.y @@ -124,7 +124,7 @@ first : comword | first '^' sword { $$ = mk(nConcat,$1,$3); } sword : comword - | keyword { $$ = mk(nWord,$1, NULL); } + | keyword { $$ = mk(nWord, $1, NULL, FALSE); } word : sword | word '^' sword { $$ = mk(nConcat,$1,$3); } @@ -139,7 +139,7 @@ comword : '$' sword { $$ = mk(nVar,$2); } | BACKBACK word sword { $$ = mk(nBackq,$2,$3); } | '(' nlwords ')' { $$ = $2; } | REDIR brace { $$ = mk(nNmpipe,$1.type,$1.fd,$2); } - | WORD { $$ = ($1.w[0] == '\'') ? mk(nQword, $1.w+1, NULL) : mk(nWord,$1.w, $1.m); } + | WORD { $$ = mk(nWord, $1.w, $1.m, $1.q); } keyword : FOR { $$ = "for"; } | IN { $$ = "in"; } @@ -166,7 +166,7 @@ optnl : /* empty */ %% void initparse() { - star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc); - nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc); + star = treecpy(mk(nVar, mk(nWord,"*", NULL, FALSE)), ealloc); + nolist = treecpy(mk(nVar, mk(nWord,"ifs", NULL, FALSE)), ealloc); } diff --git a/print.c b/print.c index f0f7728..ad939a0 100644 --- a/print.c +++ b/print.c @@ -20,7 +20,6 @@ static bool name(Format *format, int ignore) { \ } Flag(uconv, FMT_unsigned) -Flag(hconv, FMT_short) Flag(rc_lconv, FMT_long) #if HAVE_QUAD_T @@ -103,8 +102,6 @@ static void intconv(Format *format, unsigned int radix, int upper, const char *a if (flags & FMT_long) n = va_arg(format->args, long); - else if (flags & FMT_short) - n = va_arg(format->args, short); else n = va_arg(format->args, int); @@ -202,7 +199,6 @@ static void inittab(void) { fmttab['%'] = pctconv; fmttab['u'] = uconv; - fmttab['h'] = hconv; fmttab['l'] = rc_lconv; fmttab['#'] = altconv; fmttab['-'] = leftconv; diff --git a/proto.h b/proto.h index 7d2fe2a..3f1e05b 100644 --- a/proto.h +++ b/proto.h @@ -77,8 +77,10 @@ extern char *sys_errlist[]; #if SETPGRP_VOID /* Smells like POSIX: should all be ok. */ #else -/* BSD: fake it. */ +/* Old BSD: fake it. */ #define setpgid(pid, pgrp) setpgrp(pid, pgrp) +#include +#define tcgetpgrp(fd) ioctl((fd), TIOCGPGRP) #define tcsetpgrp(fd, pgrp) ioctl((fd), TIOCSPGRP, &(pgrp)) #endif @@ -86,6 +88,7 @@ extern char *sys_errlist[]; /* Nothing doing. */ #define setpgid() +#define tcgetpgrp() #define tcsetpgrp() #endif /*HAVE_SETPGRP */ diff --git a/rc.1 b/rc.1 index 325374e..d0992b6 100644 --- a/rc.1 +++ b/rc.1 @@ -161,12 +161,12 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "1999-12-10" +.TH RC 1 "2001-10-12" .SH NAME rc \- shell .SH SYNOPSIS .B rc -.RB [ \-deilnopsVvx ] +.RB [ \-deiIlnopsvx ] .RB [ \-c .IR command ] .RI [ arguments ] @@ -242,13 +242,23 @@ will be in mode. That is, a prompt (from .Cr $prompt(1)\^ ) -will be printed before an -input line is taken, and +will be printed before an input line is taken, and .I rc -will ignore the signals +will ignore +.Cr SIGINT . +.TP +.Cr \-I +If the +.Cr \-I +flag is present, or if the input to +.I rc +is not from a terminal, then +.I rc +will not be in interactive mode. No prompts will be printed, and .Cr SIGINT -and -.Cr SIGQUIT . +will cause +.I rc +to exit. .TP .Cr \-l If the @@ -261,7 +271,7 @@ is a dash then .I rc will behave as a login shell. -That is, it will try to run commands present in +That is, it will run commands from .Cr $home/.rcrc , if this file exists, before reading any other input. .TP @@ -339,7 +349,7 @@ of shell functions, builtin commands, or as a file in the directories named by .Cr $path . .SS "Background Tasks" -A command ending with a +A command ending with .Cr & is run in the background; that is, the shell returns immediately rather than waiting for the command to @@ -506,6 +516,7 @@ Note that no spaces may appear in these constructs: .Ds .Cr "command > [2] file" .De +.PP would send the output of the command to a file named .Cr [2] , with the intended filename appearing in the command's argument list. @@ -618,9 +629,7 @@ redirection is implemented with some kind of pipe, and since one cannot .IR lseek (2) on a pipe, commands that use .IR lseek (2) -will hang. -For example, -most versions of +will hang. For example, some versions of .IR diff (1) use .IR lseek (2) @@ -671,7 +680,7 @@ and performs the command as long as the .I test is true. .TP -.Ci "for (" var " in" " list" ) " cmd" +.Ci "for (" var " in " list ) " cmd" .I rc sets .I var @@ -899,18 +908,16 @@ Note that the null string, .Cr "''" , and the null list, .Cr "()" , -are two very -different things. -Assigning the null string to variable is a valid -operation, but it does not remove its definition. -For example, -if -.Cr $a -is set to -.Cr "''" , -then -.Cr "$#a" , -returns a 1. +are two very different things. Assigning the null string to a +variable is a valid operation, but it does not remove its definition. +.Ds +.Cr "null = '' empty = () echo $#null $#empty" +.De +.PP +produces the output +.Ds +.Cr "1 0" +.De .SS "List Concatenation" Two lists may be joined by the concatenation operator .Rc ( ^ ). @@ -981,7 +988,7 @@ A list may be assigned to a variable, using the notation: .PP The special variable .Cr * -may be assigned to using this notation; +may also be assigned to using this notation; .I rc has no .B set @@ -993,19 +1000,20 @@ digits, may be used as a variable name. Any character except may be used, but special characters must be quoted. All user-defined variables are exported into the environment. .PP -The value of a variable is referenced with the notation: +The value of a variable is referenced with the dollar +.Rc ( $ ) +operator: .Ds .Ci $ var .De .PP Any variable which has not been assigned a value returns the null list, .Cr "()" , -when referenced. -In addition, multiple references are allowed: +when referenced. Multiple references are allowed: .Ds -.Cr a=foo -.Cr b=a -.Cr "echo $$b" +.Cr "a = foo" +.Cr "b = a" +.Cr "echo $ $ b" .De .PP prints @@ -1064,16 +1072,11 @@ Variables may be subscripted with the notation .PP where .I n -is a list of integers (origin 1). -The list of subscripts need -not be in order or even unique. -Thus, if +is a list of integers (origin 1). The opening parenthesis must +immediately follow the variable name. The list of subscripts need not +be in order or even unique. Thus, .Ds .Cr "a=(one two three)" -.De -.PP -then -.Ds .Cr "echo $a(3 3 3)" .De .PP @@ -1119,14 +1122,15 @@ This returns a single-element list, with the number of elements in .Cr $var . .SS "Flat Lists" In order to create a single-element list from a multi-element list, -with the components space-separated, use +with the components space-separated, use the dollar-caret +.Rc ( $^ ) +operator: .Ds .Cr $^var .De .PP This is useful when the normal list concatenation rules need to be -bypassed. -For example, to append a single period at the end of +bypassed. For example, to append a single period at the end of .Cr $path , use: .Ds @@ -1245,7 +1249,9 @@ Note also that an assignment to .Cr $cdpath causes an automatic assignment to .Cr $CDPATH , -and vice-versa. +and vice-versa. Only +.Cr $CDPATH +is exported into the environment. .TP .Cr history .Cr $history @@ -1299,11 +1305,11 @@ and and .Cr $PATH are aliased to each other. -If -.Cr $path -or +If neither .Cr $PATH -is not set at startup time, +nor +.Cr $path +is set at startup time, .Cr $path assumes a default value suitable for your system. This is typically @@ -1355,19 +1361,15 @@ is about to print .Cr "$prompt(1)" . .TP .Cr status " (read only)" -The exit status of the last command. -If the command exited with a numeric value, -that number is the status. -If the died with a signal, -the status is the name of that signal; if a core file -was created, the string +The exit status of the last command. If the command exited with a +numeric value, that number is the status. If the command died with a +signal, the status is the name of that signal; if a core file was +created, the string .Rc `` +core '' -is appended. -The value of +is appended. The value of .Cr $status -for a pipeline is a list, with one entry, -as above, for each process in the pipeline. -For example, the command +for a pipeline is a list, with one entry, as above, for each process +in the pipeline. For example, the command .Ds .Cr "ls | wc" .De @@ -1497,7 +1499,9 @@ Thus: .Cr "fn sigint {}" .De .PP -causes SIGINT to be ignored by the shell. +causes +.Cr SIGINT +to be ignored by the shell. Only signals that are being ignored are passed on to programs run by .IR rc ; signal functions are not exported. @@ -1629,9 +1633,10 @@ The resources which can be shown or altered are .BR filesize , .BR datasize , .BR stacksize , -.B coredumpsize -and -.BR memoryuse . +.BR coredumpsize , +.BR memoryuse , +and, where supported, +.BR descriptors . For example: .Ds @@ -1766,22 +1771,66 @@ For example, .Ds .Cr "whatis \-\|\- \-p" .De +.SH EXAMPLES +The +.B shift +builtin only shifts +.Cr "$*" . +This function can shift any variable (except +.Cr "$lshift" ). +.Ds +.Cr "fn lshift { lshift=$*; *=$$1; shift $lshift(2); $lshift(1)=$* }" +.De +.PP +With this definition in place, +.Ds +.Cr "walrus = (shoes ships sealing-wax cabbages kings)" +.Cr "lshift walrus 3" +.Cr "whatis walrus" +.De +.PP +prints +.Ds +.Cr "walrus=(cabbages kings)" +.De +.PP +The +.Cr $^var +operator flattens a list by separating each element with a space. +This function allows the separator to be an arbitrary string. +.Ds +.Cr "fn lflat {" +.Cr " lflat=$*; *=$$1" +.Cr " while () {" +.Cr " echo -n $1; shift" +.Cr " ~ $#* 0 && break" +.Cr " echo -n $lflat(2)" +.Cr "}" +.De +.PP +With this definition in place, +.Ds +.Cr "hops=(uunet mcvax ukc tlg)" +.Cr lflat hops ! +.De +.PP +prints (with no final newline) +.Ds +.Cr uunet!mcvax!ukc!tlg +.De .SH "EXIT STATUS" The exit status of .I rc -is normally the same as that of the -last command executed. If the last -command was a pipeline, +is normally the same as that of the last command executed. If the +last command was a pipeline, .I rc exits .Cr 0 -if every command in the pipeline did; -otherwise it exits +if every command in the pipeline did; otherwise it exits .Cr 1 . .PP .I rc -can be made to exit with a particular -status using the +can be made to exit with a particular status using the .B exit builtin. .SH GRAMMAR @@ -1894,12 +1943,6 @@ The design of this shell was copied from the .I rc that Tom Duff wrote at Bell Labs. .SH BUGS -Environment variables that contain the ASCII character SOH (also known -as '\\001', or CTRL-A) will be split into lists at that character in -descendant -.IR rc -processes. -.PP There is a compile-time limit on the number of .Cr ; separated commands in a line: usually 500. @@ -1913,31 +1956,35 @@ On modern systems that support or .Cr /proc/self/fd , .Cr <{foo} -style redirection is implemented that way. -However, on other systems it is implemented with named pipes, -and it is sometimes +style redirection is implemented that way. However, on older systems +it is implemented with named pipes. Allegedly, it is sometimes possible to foil .I rc into removing the FIFO it places in .Cr /tmp prematurely, or it is even possible to cause .I rc -to hang. -.PP -The functionality of -.B shift -should be available for variables other than -.Cr "$*" . +to hang. (The current maintainer has never seen this, but then he +doesn't use systems which lack +.Cr /dev/fd +any more. If anybody can reproduce this problem, please let the +maintainer know.) .PP .B echo is built in only for performance reasons, which is a bad idea. .PP There should be a way to avoid exporting a variable. .PP -The -.Cr $^var -notation for flattening should allow for using an arbitrary -separating character, not just space. +Extra parentheses around a +.Cr ~ +expression or a +.Cr ! +expression are a syntax error. Thus, this code is illegal. +.Ds +.Cr "while ((~ $1 -*) && (! ~ $1 --)) { ..." +.De +.TP +The redundant inner parentheses must be omitted. .PP It is usually possible to use parentheses to defeat free caret insertion; that is, to use @@ -2020,12 +2067,12 @@ for .IR file . This .I rc -does not; this is a bug. +does not, since it is not considered useful. .PP The list flattening operator, .Cr $^foo , is spelt -.Cr $"foo +.Cr "$\"foo" in those versions of the Bell Labs .IR rc which have it. @@ -2063,7 +2110,7 @@ Unix Research System, Tenth Edition, Volume 2. (Saunders College Publishing) .PP -.Cr http://www.star.le.ac.uk/~tjg/rc/misc/td.html , +.Cr http://www.star.le.ac.uk/~tjg/rc/misc/td , an updated version of the above paper. .PP .IR history (1) diff --git a/rc.h b/rc.h index f582bd4..abbbf6b 100644 --- a/rc.h +++ b/rc.h @@ -1,13 +1,18 @@ +#define NDEBUG 1 +#include + #include "config.h" #include "proto.h" /* datatypes */ +#define ENV_SEP '\001' +#define ENV_ESC '\002' + /* braindamaged IBM header files #define true and false */ #undef FALSE #undef TRUE - typedef void builtin_t(char **); typedef struct Block Block; typedef struct Dup Dup; @@ -27,8 +32,8 @@ typedef struct Format Format; typedef union Edata Edata; typedef enum nodetype { - nAndalso, nAssign, nBackq, nBang, nBody, nCbody, nNowait, nBrace, nConcat, - nCount, nElse, nFlat, nDup, nEpilog, nNewfn, nForin, nIf, nQword, + nAndalso, nAssign, nBackq, nBang, nBody, nCbody, nNowait, nBrace, + nConcat, nCount, nElse, nFlat, nDup, nEpilog, nNewfn, nForin, nIf, nOrelse, nPipe, nPre, nRedir, nRmfn, nArgs, nSubshell, nCase, nSwitch, nMatch, nVar, nVarsub, nWhile, nWord, nLappend, nNmpipe } nodetype; @@ -95,6 +100,7 @@ struct Redir { struct Word { char *w, *m; + bool q; }; struct Rq { @@ -133,7 +139,6 @@ struct Format { enum { FMT_quad = 1, /* %q */ FMT_long = 2, /* %l */ - FMT_short = 4, /* %h */ FMT_unsigned = 8, /* %u */ FMT_zeropad = 16, /* %0 */ FMT_leftside = 32, /* %- */ @@ -273,11 +278,12 @@ extern void pushfd(int); extern void pushstring(char **, bool); extern void popinput(void); extern void closefds(void); -extern int last; +extern int lastchar; extern bool rcrc; /* lex.c */ +extern bool quotep(char *, bool); extern int yylex(void); extern void inityy(void); extern void yyerror(const char *); @@ -305,6 +311,7 @@ extern void restoreblock(Block *); /* open.c */ extern int rc_open(const char *, redirtype); extern bool makeblocking(int); +extern bool makesamepgrp(int); /* print.c */ /* diff --git a/tree.c b/tree.c index aaea645..37db4cd 100644 --- a/tree.c +++ b/tree.c @@ -18,10 +18,11 @@ extern Node *mk(int /*nodetype*/ t,...) { n->u[1].i = va_arg(ap, int); n->u[2].i = va_arg(ap, int); break; - case nWord: case nQword: - n = nalloc(offsetof(Node, u[2])); + case nWord: + n = nalloc(offsetof(Node, u[3])); n->u[0].s = va_arg(ap, char *); n->u[1].s = va_arg(ap, char *); + n->u[2].i = va_arg(ap, int); break; case nBang: case nNowait: case nCount: case nFlat: case nRmfn: case nSubshell: @@ -79,7 +80,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(size_t)) { n->u[1].i = s->u[1].i; n->u[2].i = s->u[2].i; break; - case nWord: case nQword: + case nWord: n = (*alloc)(offsetof(Node, u[2])); n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s); if (s->u[1].s != NULL) { @@ -138,7 +139,7 @@ extern void treefree(Node *s) { /* NOTREACHED */ case nDup: break; - case nWord: case nQword: + case nWord: efree(s->u[0].s); efree(s->u[1].s); break; diff --git a/trip.rc b/trip.rc index a381db4..20e7624 100644 --- a/trip.rc +++ b/trip.rc @@ -318,7 +318,7 @@ submatch 'cdpath='''' cd frobnatz' 'couldn''t cd to frobnatz' 'cd to frobnatz su submatch 'wait 1 2 3' 'too many arguments to wait' 'arg count' $rc -c 'wait 1' >[2]/dev/null && fail wait 1 -sleep 5& +sleep 3& expect $apid echo $apids wait @@ -329,7 +329,6 @@ if (~ `` '' {wait} ?) # # matching # - touch /tmp/abc.$pid /tmp/bbc.$pid mkdir /tmp/dir.$pid /tmp/dip.$pid touch /tmp/dir.$pid/^(a b c) /tmp/dip.$pid/^(a b c) @@ -369,7 +368,6 @@ rm -rf /tmp/dir.$pid /tmp/dip.$pid # # signals # - fn sigint {eval} kill -2 $pid fn sigint @@ -377,7 +375,6 @@ fn sigint # # path searching # - $rc -c /frobnatz >[2]/dev/null && fail 'search error' touch /tmp/noexec.$pid @@ -427,15 +424,13 @@ $rc -c '. /frobnatz' >[2]/dev/null && fail 'dot of a nonexistent file' # # stdin # - if (!~ `{echo echo hi | $rc} hi) fail piping stdin to rc # # functions, variables & environment # - -fn --- {for(i)a|[2=3]b>>c<<<'e'&f>[2=1]} +fn --- {for(i)a|[2=3]b>>c<<[2=1]} if (whatis printenv >/dev/null>[2=1]) { printenv=printenv @@ -444,7 +439,7 @@ if (whatis printenv >/dev/null>[2=1]) { } else printenv=() -if (~ $#printenv 1 && !~ `` $nl {$printenv | grep fn___2d__2d__2d} 'fn___2d__2d__2d={for(i in $*)a|[2=3]b >>c <<<''e''&f >[2=1]}') +if (~ $#printenv 1 && !~ `` $nl {$printenv | grep fn___2d__2d__2d} 'fn___2d__2d__2d={for(i in $*)a|[2=3]b >>c <<[2=1]}') fail protect_env fn --- {replace} @@ -470,7 +465,6 @@ fn_ff='{' prompt='' if (!~ `` $nl {$rc -cff>[2=1]} 'line 1: '*' error near eof') # # statuses # - ~ `{$rc -ec 'sleep 10&kill -9 $apid;wait'>[2=1]} killed || fail status diagnostic @@ -481,7 +475,6 @@ submatch 'exit foo' 'bad status' 'exit diagnostic' # # control structures # - if (!~ `{false || echo hi} hi) fail '||' if (!~ `{true && echo hi} hi) @@ -522,7 +515,6 @@ submatch 'fn () {eval}' 'null function name' 'assigning null function name' # # prompt # - fn prompt {echo hi} prompt=() if (!~ `{$rc -i /dev/null>[2]/dev/null} hi) fail fn prompt fn prompt @@ -530,7 +522,6 @@ fn prompt # # history # - history=/tmp/hist.$pid prompt='' echo 'history=()' | $rc -i if (!~ `{cat /tmp/hist.$pid} 'history=()') @@ -569,3 +560,29 @@ eof # Believe it or not, I broke root directory globbing in rc-1.6b1. x=/* ~ '/*' $^x && fail root directory globbing + +# fn sigexit should be cleared in children + +x = () +expect nonesuch not found +x = `{true | nonesuch}; if (~ $x trip) fail sigexit in children +x = `{ < /dev/null wc |grep xxx }; if (~ $x trip) fail sigexit in children +x = `{{ wc | wc } < /dev/null }; if (~ $x trip) fail sigexit in children + +# core dumps in glob.c +~ () '*' && fail globber problem +~ () '**' && fail globber problem + +# check for ctrl-a bug +x=`{./tripping a} +# ~ `{$rc -c 'echo $x'} $x || fail ctrl-a bug detected + +# check for hilarious quoting bug introduced while fixing ctrl-a +x=('#' '#' '#') +eval z^`{whatis -v x} +~ $#zx 3 || fail hilarious quoting bug + +# parens bypass quote detector bug +fn x {echo x.y $(x.y)} +~ ``''{whatis -f x} 'fn x {echo x.y $''x.y''} +' || fail sneaky parens bug diff --git a/tripping.c b/tripping.c index 911d229..aff7927 100644 --- a/tripping.c +++ b/tripping.c @@ -3,14 +3,18 @@ #include #include -void out0(void) { +static void out0(void) { putchar('t'); putchar('r'); putchar('\0'); putchar('u'); putchar('e'); putchar('\n'); } -void makenonblock(void) { +static void ctrl_a(void) { + puts("a\001ab\002b"); +} + +static void makenonblock(void) { int flags; if ((flags = fcntl(0, F_GETFL)) == -1) @@ -25,6 +29,9 @@ int main(int argc, char **argv) { case '0': out0(); break; + case 'a': + ctrl_a(); + break; case 'n': makenonblock(); break; diff --git a/utils.c b/utils.c index 00be28b..b36f5f6 100644 --- a/utils.c +++ b/utils.c @@ -57,7 +57,7 @@ extern int n2u(char *s, unsigned int base) { /* The last word in portable ANSI: a strcmp wrapper for qsort */ extern int starstrcmp(const void *s1, const void *s2) { - return strcmp(*(char **)s1, *(char **)s2); + return strcmp(*(char * const *)s1, *(char * const *)s2); } /* tests to see if pathname begins with "/", "./", or "../" */ diff --git a/var.c b/var.c index e7161de..1c30fba 100644 --- a/var.c +++ b/var.c @@ -107,7 +107,7 @@ extern char *varlookup_string(char *name) { return look->extdef; if (look->def == NULL) return NULL; - return look->extdef = mprint("%F=%-L", name, look->def, "\001"); + return look->extdef = mprint("%F=%W", name, look->def); } /* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */ diff --git a/walk.c b/walk.c index 2f725d6..177e56e 100644 --- a/walk.c +++ b/walk.c @@ -33,7 +33,7 @@ top: sigchk(); switch (n->type) { case nArgs: case nBackq: case nConcat: case nCount: case nFlat: case nLappend: case nRedir: case nVar: - case nVarsub: case nWord: case nQword: + case nVarsub: case nWord: exec(glob(glom(n)), parent); /* simple command */ break; case nBody: @@ -217,6 +217,7 @@ top: sigchk(); if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) { if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */ break; + setsigdefaults(FALSE); qredir(n->u[0].p); if (!haspreredir(n->u[1].p)) doredirs(); /* no more preredirs, empty queue */ @@ -246,6 +247,7 @@ top: sigchk(); if (n->u[1].p == NULL) { WALK(n->u[0].p, parent); } else if (dofork(parent)) { + setsigdefaults(FALSE); walk(n->u[1].p, TRUE); /* Do redirections */ redirq = NULL; /* Reset redirection queue */ walk(n->u[0].p, FALSE); /* Do commands */ @@ -321,6 +323,7 @@ static void dopipe(Node *n) { rc_error(NULL); } if ((pid = rc_fork()) == 0) { + setsigdefaults(FALSE); redirq = NULL; /* clear preredir queue */ mvfd(p[0], r->u[1].i); if (fd_prev != 1) @@ -337,6 +340,7 @@ static void dopipe(Node *n) { close(p[0]); } if ((pid = rc_fork()) == 0) { + setsigdefaults(FALSE); mvfd(fd_prev, fd_out); walk(r, FALSE); exit(getstatus()); -- cgit v1.2.3 From 2ef8a59ae61b83ad2ba9d4c9381eead5ae403cb0 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 31 Oct 2001 12:31:57 +0000 Subject: candidate: rc-1.6c4 --- AUTHORS | 11 ++--- ChangeLog | 16 ++++++++ INSTALL | 22 ++++++++++ Makefile.am | 4 +- configure.ac | 4 +- input.c | 4 -- rc.1 | 129 ++++++++++++++++++++++++----------------------------------- rc.h | 4 +- trip.rc | 12 ++++++ tripping.c | 23 +++++++++++ 10 files changed, 138 insertions(+), 91 deletions(-) diff --git a/AUTHORS b/AUTHORS index bde6a37..a443f8b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,8 +29,9 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, Dale -Scheetz, David Luyer, David Swasey, Decklin Foster, Donn Cave, Gerry -Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc -Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond Venneker, Rich -$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve Simon, Thomas -Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang Zekoll. +Scheetz, David Luyer, David Swasey, Decklin Foster, Donn Cave, Gary +Carvell, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy +Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K Gardner, +Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan +Dalibor, Steve Simon, Thomas Nordin, Tom Culliton, Tom Tromey, Vincent +Broman, Wolfgang Zekoll. diff --git a/ChangeLog b/ChangeLog index 40f3aad..45fcb18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -723,3 +723,19 @@ Changes since rc-1.5b2 2001-10-12 Release: rc-1.6b3. + +2001-10-25 + + Feature: large file support (thanks Scott Schwartz, Chris + Siebenmann). + +2001-10-29 + + Bug: space vs tab confusion in commented out Makefile rules to + rebuild parser (thanks Gary Carvell). + +2001-10-31 + + Documentation: subscripted variables don't work in here documents. + + Release: rc-1.6c4. diff --git a/INSTALL b/INSTALL index cf80210..12129d6 100644 --- a/INSTALL +++ b/INSTALL @@ -11,6 +11,7 @@ need to configure, build, test, and install rc. This will build rc in the source directory (see below for details on how to build rc in a different directory). + BUILD AND CONFIGURATION OPTIONS There are lots of options you can give to configure to modify rc's @@ -134,6 +135,25 @@ do this. This will produce some output, and should end with "trip is complete". If the trip instead ends with "trip took a wrong turn..." please contact the maintainer. + +LARGE FILE SUPPORT + +This release of rc supports large files (i.e. with 64 bit offsets), on +systems where the configure script can figure out how to enable this. +When you run `make trip' (you always run `make trip', right?) the +penultimate line of output (before "trip complete") reports whether +large file support seems to be working or not. + +Large file support is a function of file systems, as well as +applications. For example, NFS and tmpfs file systems often do not +support large files. The test used by `make trip' is therefore +subject to false negatives. That is, a report that "large file +support seems NOT to be working" may be erroneous. To minimise this +possibility, the test is performed both in the current directory +(where you built rc) and /tmp. (I don't think there's any scenario +where a false positive can be reported.) + + BUILDING IN ANOTHER DIRECTORY If you have a suitable `make', you can build rc in a different directory @@ -142,6 +162,7 @@ are building rc for multiple architectures. All you need do is specify the path to the configure script in the first step. Suitable `make's include GNU, HP-UX, and SunOS, but not Irix, nor Ultrix, nor UnixWare. + COMPILATION WARNINGS If your C compiler is gcc, the option `-Wall' is turned on. This may @@ -162,6 +183,7 @@ incorrect declaration of `getgroups()' in those systems' header files. Any other warnings should be reported to the maintainer. + OLD C rc needs an ISO C (89) compiler, or at least one that has a reasonable diff --git a/Makefile.am b/Makefile.am index 6de407a..d003ef6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,8 +58,8 @@ DISTCLEANFILES = sigmsgs.c sigmsgs.h statval.h # portable (I hope). #parse.c parse.h: $(srcdir)/parse.y # $(YACC) -d $(srcdir)/parse.y -# mv y.tab.c parse.c -# mv y.tab.h parse.h +# mv y.tab.c parse.c +# mv y.tab.h parse.h check: trip diff --git a/configure.ac b/configure.ac index 6792d85..564ec85 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6b3) +AM_INIT_AUTOMAKE(rc, 1.6c4) AM_CONFIG_HEADER(config.h) @@ -24,6 +24,8 @@ case "$GCC" in yes) CFLAGS="-Wall $CFLAGS" ;; esac +AC_SYS_LARGEFILE + AC_PROG_CPP AC_CHECK_PROGS(LN, ln cp) diff --git a/input.c b/input.c index 7c0dde7..778f09b 100644 --- a/input.c +++ b/input.c @@ -44,10 +44,6 @@ int lastchar; static char *rlinebuf, *prompt; #endif -#if EDITLINE || READLINE -static char *rlinebuf, *prompt; -#endif - extern int gchar() { int c; diff --git a/rc.1 b/rc.1 index d0992b6..fc5ab76 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2001-10-12" +.TH RC 1 "2001-10-31" .SH NAME rc \- shell .SH SYNOPSIS @@ -254,7 +254,8 @@ flag is present, or if the input to .I rc is not from a terminal, then .I rc -will not be in interactive mode. No prompts will be printed, and +will not be in interactive mode. +No prompts will be printed, and .Cr SIGINT will cause .I rc @@ -312,8 +313,8 @@ scripts; the usual caveats about the setuid bit still apply.) .Cr \-s This flag causes .I rc -to read from standard input. Any arguments are -placed in +to read from standard input. +Any arguments are placed in .Cr $* . .TP .Cr \-v @@ -495,12 +496,14 @@ to the same file, use .PP As in .IR sh , -redirections are processed from left to right. Thus this sequence +redirections are processed from left to right. +Thus this sequence .Ds .Cr "command >[2=1] > file" .De .PP -is usually a mistake. It first duplicates standard error to standard +is usually a mistake. +It first duplicates standard error to standard output; then redirects standard output to a file, leaving standard error wherever standard output originally was. .PP @@ -629,7 +632,8 @@ redirection is implemented with some kind of pipe, and since one cannot .IR lseek (2) on a pipe, commands that use .IR lseek (2) -will hang. For example, some versions of +will hang. +For example, some versions of .IR diff (1) use .IR lseek (2) @@ -908,8 +912,9 @@ Note that the null string, .Cr "''" , and the null list, .Cr "()" , -are two very different things. Assigning the null string to a -variable is a valid operation, but it does not remove its definition. +are two very different things. +Assigning the null string to a variable is a valid operation, but it +does not remove its definition. .Ds .Cr "null = '' empty = () echo $#null $#empty" .De @@ -995,7 +1000,8 @@ has no builtin. .PP Any non-empty sequence of characters, except a sequence including only -digits, may be used as a variable name. Any character except +digits, may be used as a variable name. +Any character except .Cr = may be used, but special characters must be quoted. All user-defined variables are exported into the environment. @@ -1009,7 +1015,8 @@ operator: .PP Any variable which has not been assigned a value returns the null list, .Cr "()" , -when referenced. Multiple references are allowed: +when referenced. +Multiple references are allowed: .Ds .Cr "a = foo" .Cr "b = a" @@ -1072,9 +1079,10 @@ Variables may be subscripted with the notation .PP where .I n -is a list of integers (origin 1). The opening parenthesis must -immediately follow the variable name. The list of subscripts need not -be in order or even unique. Thus, +is a list of integers (origin 1). +The opening parenthesis must immediately follow the variable name. +The list of subscripts need not be in order or even unique. +Thus, .Ds .Cr "a=(one two three)" .Cr "echo $a(3 3 3)" @@ -1194,8 +1202,8 @@ as its value. .SH "SPECIAL VARIABLES" Several variables are known to .I rc -and are treated specially. In the following list, -``(read only)'' indicates that an attempt to set the +and are treated specially. +In the following list, ``(read only)'' indicates that an attempt to set the variable will silently have no effect. .TP .Cr * @@ -1249,7 +1257,8 @@ Note also that an assignment to .Cr $cdpath causes an automatic assignment to .Cr $CDPATH , -and vice-versa. Only +and vice-versa. +Only .Cr $CDPATH is exported into the environment. .TP @@ -1361,15 +1370,16 @@ is about to print .Cr "$prompt(1)" . .TP .Cr status " (read only)" -The exit status of the last command. If the command exited with a -numeric value, that number is the status. If the command died with a -signal, the status is the name of that signal; if a core file was -created, the string +The exit status of the last command. +If the command exited with a numeric value, that number is the status. +If the command died with a signal, the status is the name of that signal; +if a core file was created, the string .Rc `` +core '' is appended. The value of .Cr $status for a pipeline is a list, with one entry, as above, for each process -in the pipeline. For example, the command +in the pipeline. +For example, the command .Ds .Cr "ls | wc" .De @@ -1721,11 +1731,13 @@ is printed; for functions, including signal handlers, their definitions are printed; for executable files, path names are printed; and for variables, their values are printed. The flags restrict output to builtins, functions, executable -programs, signal handlers, and variables, respectively. If no +programs, signal handlers, and variables, respectively. +If no .IR name s are specified, .I rc -lists all objects of that type. (This is not permitted for +lists all objects of that type. +(This is not permitted for .Cr \-p .) Without arguments, .Cr whatis @@ -1821,7 +1833,8 @@ prints (with no final newline) .SH "EXIT STATUS" The exit status of .I rc -is normally the same as that of the last command executed. If the +is normally the same as that of the last command executed. +If the last command was a pipeline, .I rc exits @@ -1956,19 +1969,20 @@ On modern systems that support or .Cr /proc/self/fd , .Cr <{foo} -style redirection is implemented that way. However, on older systems -it is implemented with named pipes. Allegedly, it is sometimes -possible to foil +style redirection is implemented that way. +However, on older systems it is implemented with named pipes. +Allegedly, it is sometimes possible to foil .I rc into removing the FIFO it places in .Cr /tmp prematurely, or it is even possible to cause .I rc -to hang. (The current maintainer has never seen this, but then he +to hang. +(The current maintainer has never seen this, but then he doesn't use systems which lack .Cr /dev/fd -any more. If anybody can reproduce this problem, please let the -maintainer know.) +any more. +If anybody can reproduce this problem, please let the maintainer know.) .PP .B echo is built in only for performance reasons, which is a bad idea. @@ -1979,55 +1993,15 @@ Extra parentheses around a .Cr ~ expression or a .Cr ! -expression are a syntax error. Thus, this code is illegal. +expression are a syntax error. +Thus, this code is illegal. .Ds .Cr "while ((~ $1 -*) && (! ~ $1 --)) { ..." .De .TP The redundant inner parentheses must be omitted. .PP -It is usually possible to use parentheses to defeat -free caret insertion; that is, to use -.Cr $(x.y) -as a synonym for -.Cr $'x.y' . -However, the former syntax is not correctly handled in functions -exported to the environment: a function defined using this syntax will -not work properly in descendant -.I rc -processes. -.PP -List definitions in exported functions are "noisier" than they need to be. -.PP -If both -.Cr $PATH -and -.Cr $path -are set, -.I rc -believes the former. Arguably this is a bug: -.I rc -can quite happily deal with path elements that contain -.Cr : , -but such elements will be split at the colon in descendant -.I rc -processes. -.PP -The -.Cr . -command should search -.Cr $path . -.PP -Extra parentheses around a -.Cr ~ -expression or a -.Cr ! -expression are a syntax error. Thus, this -code is illegal. -.Ds -.Cr "while ((~ $1 -*) && (! ~ $1 --)) { ..." -.De -The redundant inner parentheses must be omitted. +Variable subscripting cannot be used in here documents. .PP Bug reports should be mailed to .Cr "" . @@ -2040,7 +2014,8 @@ The Tenth Edition .I rc does not have the .B else -keyword. Instead, +keyword. +Instead, .B if is optionally followed by an @@ -2057,7 +2032,7 @@ This restriction is not present for single-word commands in this .IR rc . .PP For -.Cr . +.Cr . .IR file , the Tenth Edition .IR rc @@ -2072,7 +2047,7 @@ does not, since it is not considered useful. The list flattening operator, .Cr $^foo , is spelt -.Cr "$\"foo" +.Cr "$""foo" in those versions of the Bell Labs .IR rc which have it. diff --git a/rc.h b/rc.h index abbbf6b..fd3fc27 100644 --- a/rc.h +++ b/rc.h @@ -1,9 +1,9 @@ #define NDEBUG 1 -#include - #include "config.h" #include "proto.h" +#include + /* datatypes */ #define ENV_SEP '\001' diff --git a/trip.rc b/trip.rc index 20e7624..b8e7e58 100644 --- a/trip.rc +++ b/trip.rc @@ -586,3 +586,15 @@ eval z^`{whatis -v x} fn x {echo x.y $(x.y)} ~ ``''{whatis -f x} 'fn x {echo x.y $''x.y''} ' || fail sneaky parens bug + +# large file support + +# this is, by no means, an exhaustive test. since particular file +# systems do, or do not, support large files, we try it both in the +# build directory and /tmp. + +if (./tripping l > big.$pid >[2] /dev/null || + ./tripping l > /tmp/big.$pid >[2] /dev/null) { + echo large file support seems to work +} else echo large file support seems NOT to work - see INSTALL file +rm -f big.$pid /tmp/big.$pid diff --git a/tripping.c b/tripping.c index aff7927..a9099ce 100644 --- a/tripping.c +++ b/tripping.c @@ -1,7 +1,12 @@ /* This is an auxiliary test program for rc. */ +#include "config.h" + #include #include +#include +#include +#include static void out0(void) { putchar('t'); putchar('r'); @@ -14,6 +19,21 @@ static void ctrl_a(void) { puts("a\001ab\002b"); } +static void large(void) { + char c = 'c'; + +#define LARGE (((off_t)1<<33)+1) + + if (lseek(1, LARGE, SEEK_SET) != LARGE) { + perror("lseek"); + exit(1); + } + if (write(1, &c, 1) == -1) { + perror("write"); + exit(1); + } +} + static void makenonblock(void) { int flags; @@ -32,6 +52,9 @@ int main(int argc, char **argv) { case 'a': ctrl_a(); break; + case 'l': + large(); + break; case 'n': makenonblock(); break; -- cgit v1.2.3 From bc11ebf09feec23608459c8e632f30369c6bae49 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Tue, 20 Nov 2001 16:01:03 +0000 Subject: candidate: rc-1.6c5 --- AUTHORS | 14 +++---- ChangeLog | 18 ++++++++ README | 2 +- configure.ac | 2 +- except.c | 4 +- exec.c | 5 +++ fn.c | 4 +- parse.y | 2 + print.c | 6 +-- rc.1 | 131 ++++++++++++++++++++++++++++++++++++++++++----------------- signal.c | 3 +- trip.rc | 2 +- utils.c | 4 +- walk.c | 4 +- 14 files changed, 145 insertions(+), 56 deletions(-) diff --git a/AUTHORS b/AUTHORS index a443f8b..11bbd1d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,10 +28,10 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt -Kleberg, Brynjulv Hauksson, Byron Rakitzis, Chris Siebenmann, Dale -Scheetz, David Luyer, David Swasey, Decklin Foster, Donn Cave, Gary -Carvell, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy -Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K Gardner, -Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan -Dalibor, Steve Simon, Thomas Nordin, Tom Culliton, Tom Tromey, Vincent -Broman, Wolfgang Zekoll. +Kleberg, Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, Chris +Siebenmann, Dale Scheetz, David Luyer, David Swasey, Decklin Foster, +Donn Cave, Gary Carvell, Gerry Tomlinson, Gert-Jan Vons, Ian Lance +Taylor, Jeremy Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K +Gardner, Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, +Stefan Dalibor, Steve Simon, Thomas Nordin, Tom Culliton, Tom Tromey, +Vincent Broman, Wolfgang Zekoll. diff --git a/ChangeLog b/ChangeLog index 45fcb18..1306818 100644 --- a/ChangeLog +++ b/ChangeLog @@ -739,3 +739,21 @@ Changes since rc-1.5b2 Documentation: subscripted variables don't work in here documents. Release: rc-1.6c4. + +2001-11-01 + + Bug: more wrongly ordered header file includes (thanks Callum + Gibson). + +2001-11-06 + + Portability: rename print.c::utoa() to rc_utoa() to avoid QNX name + clash; use "sh -c 'test ...'" in trip.rc for missing standalone + `test' on QNX (thanks Stefan Dalibor). + +2001-11-20 + + Documentation: tighten up various descriptions, and include some + more examples. + + Release: rc-1.6c5. diff --git a/README b/README index 6b6c181..7bddd4f 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is beta release rc-1.6b3. +This is release candidate rc-1.6c5. See COPYING for copying information. All files are diff --git a/configure.ac b/configure.ac index 564ec85..89d737b 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6c4) +AM_INIT_AUTOMAKE(rc, 1.6c5) AM_CONFIG_HEADER(config.h) diff --git a/except.c b/except.c index af30e71..886ab50 100644 --- a/except.c +++ b/except.c @@ -1,6 +1,8 @@ +#include "rc.h" + #include #include -#include "rc.h" + #include "jbwrap.h" /* diff --git a/exec.c b/exec.c index a0ba8d4..55f3bb9 100644 --- a/exec.c +++ b/exec.c @@ -1,7 +1,12 @@ /* exec.c */ + +#include "rc.h" + #include #include +#include "wait.h" + #include "rc.h" #include "wait.h" /* diff --git a/fn.c b/fn.c index e82e832..734c071 100644 --- a/fn.c +++ b/fn.c @@ -3,9 +3,11 @@ Support for signal handlers is also found here. */ +#include "rc.h" + #include #include -#include "rc.h" + #include "sigmsgs.h" static void fn_handler(int), dud_handler(int); diff --git a/parse.y b/parse.y index f83e673..8be65bb 100644 --- a/parse.y +++ b/parse.y @@ -5,6 +5,8 @@ */ %{ +/* note that this actually needs to appear before any system header + files are included; byacc likes to throw in first. */ #include "rc.h" static Node *star, *nolist; diff --git a/print.c b/print.c index ad939a0..3484086 100644 --- a/print.c +++ b/print.c @@ -69,9 +69,9 @@ static bool sconv(Format *format, int ignore) { return FALSE; } -static char *utoa(unsigned long u, char *t, unsigned int radix, const char *digit) { +static char *rc_utoa(unsigned long u, char *t, unsigned int radix, const char *digit) { if (u >= radix) { - t = utoa(u / radix, t, radix, digit); + t = rc_utoa(u / radix, t, radix, digit); u %= radix; } *t++ = digit[u]; @@ -117,7 +117,7 @@ static void intconv(Format *format, unsigned int radix, int upper, const char *a while (*altform != '\0') prefix[pre++] = *altform++; - len = utoa(u, number, radix, table[upper]) - number; + len = rc_utoa(u, number, radix, table[upper]) - number; if ((flags & FMT_f2set) && (size_t) format->f2 > len) zeroes = format->f2 - len; else diff --git a/rc.1 b/rc.1 index fc5ab76..5a570ec 100644 --- a/rc.1 +++ b/rc.1 @@ -32,15 +32,15 @@ .\" for pointing out these problems. .\" .\" Note that sentences should end at the end of a line. nroff and -.\" troff will supply the correct intersentence spacing, but only if +.\" troff will supply the correct inter-sentence spacing, but only if .\" the sentences end at the end of a line. Explicit spaces, if given, -.\" are apparently honored and the normal intersentence spacing is +.\" are apparently honored and the normal inter-sentence spacing is .\" suppressed. .\" .\" DaviD W. Sanderson .\"------- .\" Dd distance to space vertically before a "display" -.\" These are what n/troff use for interparagraph distance +.\" These are what n/troff use for inter-paragraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2001-10-31" +.TH RC 1 "2001-11-20" .SH NAME rc \- shell .SH SYNOPSIS @@ -700,9 +700,7 @@ is omitted, then will set .I var to each element of -.Cr $* -(excluding -.Cr $0 ). +.Cr $* . For example: .Ds .Cr "for (i in \`{ls -F | grep '\e*$' | sed 's/\e*$//'}) { commands }" @@ -876,7 +874,7 @@ Thus, the command .PP returns true if any of the files in the current directory have a single-character name. -(Note that if the +If the .Cr ~ command is given a list as its first argument, then a successful match against any of the elements of that @@ -888,7 +886,7 @@ For example: .Cr "~ (foo goo zoo) z*" .De .PP -is true.) +is true. .SH "LISTS AND VARIABLES" The primary data structure in .IR rc @@ -926,18 +924,7 @@ produces the output .SS "List Concatenation" Two lists may be joined by the concatenation operator .Rc ( ^ ). -A single word is treated as a list of length one, so -.Ds -.Cr "echo foo^bar" -.De -.PP -produces the output -.Ds -.Cr foobar -.De -.PP -For lists of more than one element, -concatenation works according to the following rules: +Concatenation works according to the following rules: if the two lists have the same number of elements, then concatenation is pairwise: .Ds @@ -949,7 +936,7 @@ produces the output .Cr "a\-1 b\-2 c\-3" .De .PP -Otherwise, one of the lists must have a single element, +Otherwise, at least one of the lists must have a single element, and then the concatenation is distributive: .Ds .Cr "cc \-^(O g c) (malloc alloca)^.c" @@ -959,6 +946,16 @@ has the effect of performing the command .Ds .Cr "cc \-O \-g \-c malloc.c alloca.c" .De +.PP +A single word is a list of length one, so +.Ds +.Cr "echo foo^bar" +.De +.PP +produces the output +.Ds +.Cr foobar +.De .SS "Free Carets" .I rc inserts carets (concatenation operators) for free in certain situations, @@ -1214,6 +1211,8 @@ etc. are the same as .Cr $*(1) , .Cr $*(2) , etc. +.TP +.Cr 0 The variable .Cr $0 holds the value of @@ -1230,13 +1229,49 @@ is also set to the name of the file being interpreted for the duration of a .Cr . command. +.Cr $0 +is not an element of +.Cr $* , +and is never treated as one. .TP .Cr apid The process ID of the last process started in the background. .TP .Cr apids " (read only)" -The process IDs of any background processes which are outstanding -or which have died and have not been waited for yet. +A list whose elements are the process IDs of all background processes +which are still alive, or which have died and have not been waited for +yet. +.TP +.Cr bqstatus +The exit status of the +.I rc +forked to execute the most recent backquote substitution. Note that, unlike +.Cr $status , +.Cr $bqstatus +is always a single element list (see +.BR "EXIT STATUS" +below). For example: +.Ds +.Cr "echo foo |grep bar; whatis status" +.De +.TP +\& +prints +.Ds +.Cr "status=(0 1)" +.De +.TP +\& +whereas +.Ds +.Cr "x=`{echo foo |grep bar}; whatis bqstatus" +.De +.TP +\& +prints +.Ds +.Cr "bqstatus=1" +.De .TP .Cr bqstatus The exit status of the @@ -1282,8 +1317,7 @@ does not append commands to any file. .Cr home The default directory for the builtin .B cd -command and is the directory -in which +command, and the directory in which .I rc looks to find its initialization file, .Cr .rcrc , @@ -1364,7 +1398,7 @@ directly into a file for use as a shell script, without further editing being necessary. .TP .Cr prompt " (function)" -If this function is set, then it gets executed every time +If this function is defined, then it gets executed every time .I rc is about to print .Cr "$prompt(1)" . @@ -1391,9 +1425,13 @@ to .Cr "(0 0)" . .TP .Cr version " (read only)" -This variable contains a string which identifies this +The first element of this list variable is a string which identifies this version of .IR rc . +The second element is a string which can be found by +.IR ident +and +.IR "sccs what" . .PP The values of .Cr "$path" , @@ -1568,6 +1606,22 @@ Executes the command ignoring any function definition of the same name. This command is present to allow functions with the same names as builtins to use the underlying builtin or binary. +For example: +.Ds +.Cr "fn ls { builtin ls -FC $* }" +.De +.TP +\& +is a reasonable way to pass a default set of arguments to +.Cr ls (1). +.Ds +.Cr "fn ls { ls -FC $* }" +.De +.TP +\& +is a non-terminating recursion, which will cause +.Cr rc +to exhaust its stack space and (eventually) terminate if it is executed. .TP \fBcd \fR[\fIdirectory\fR] Changes the current directory to @@ -1671,7 +1725,7 @@ Returns from the current function, with status .IR n , where .IR n -is a single value or a list of possible exit statuses. +is a valid exit status, or a list of them. Thus it is legal to have .Ds .Cr "return (sigpipe 1 2 3)" @@ -1699,10 +1753,6 @@ elements down by .IR n . .I n defaults to 1. -(Note that -.Cr $0 -is not affected by -.BR shift .) .TP \fBumask \fR[\fImask\fR] Sets the current umask (see @@ -1712,15 +1762,16 @@ to the octal If no argument is present, the current mask value is printed. .TP \fBwait \fR[\fIpid\fR] -Waits for the specified +Waits for process with the specified .IR pid , which must have been started by -.IR rc . +.IR rc , +to exit. If no .I pid is specified, .I rc -waits for all child processes to exit. +waits for all its child processes to exit. .TP \fBwhatis \fR[\fB\-b\fR] \fR[\fB\-f\fR] \fR[\fB\-p\fR] \fR[\fB\-s\fR] \fR[\fB\-v\fR] [\fB\-\|\-\fR] [\fIname ...\fR] Prints a definition of the named objects. @@ -1823,7 +1874,7 @@ This function allows the separator to be an arbitrary string. With this definition in place, .Ds .Cr "hops=(uunet mcvax ukc tlg)" -.Cr lflat hops ! +.Cr "lflat hops !" .De .PP prints (with no final newline) @@ -1984,8 +2035,12 @@ doesn't use systems which lack any more. If anybody can reproduce this problem, please let the maintainer know.) .PP +The .B echo -is built in only for performance reasons, which is a bad idea. +command does not need to be a builtin. It is one for reasons of +performance and portability (of +.I rc +scripts). .PP There should be a way to avoid exporting a variable. .PP diff --git a/signal.c b/signal.c index ca34dfa..de06633 100644 --- a/signal.c +++ b/signal.c @@ -1,9 +1,10 @@ /* signal.c: a Hugh-approved signal handler. */ +#include "rc.h" + #include #include -#include "rc.h" #include "sigmsgs.h" #include "jbwrap.h" diff --git a/trip.rc b/trip.rc index b8e7e58..8eb4c09 100644 --- a/trip.rc +++ b/trip.rc @@ -352,7 +352,7 @@ if (~ x [y]) if (~ x x?) fail too many characters in pattern -test -f /////tmp//////a?c.$pid || fail glob with many slashes +sh -c 'test -f /////tmp//////a?c.'^$pid || fail glob with many slashes if (!~ /////tmp//////a*.$pid /////tmp//////a?c.$pid) fail glob with many slashes if (!~ ////tmp////di?.$pid////* ////tmp////dir.$pid////*b*) diff --git a/utils.c b/utils.c index b36f5f6..14a55ff 100644 --- a/utils.c +++ b/utils.c @@ -1,8 +1,10 @@ /* utils.c: functions of general utility */ +#include "rc.h" + #include #include -#include "rc.h" + #include "jbwrap.h" /* print error with line number on noninteractive shells (i.e., scripts) */ diff --git a/walk.c b/walk.c index 177e56e..984a68c 100644 --- a/walk.c +++ b/walk.c @@ -1,8 +1,10 @@ /* walk.c: walks the parse tree. */ +#include "rc.h" + #include #include -#include "rc.h" + #include "jbwrap.h" /* -- cgit v1.2.3 From e354cf4fd756584239e7778217ee8860009e6728 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Fri, 8 Feb 2002 14:48:47 +0000 Subject: candidate: rc-1.6c6 --- ChangeLog | 11 +++++++++ NEWS | 7 +++--- README | 4 +-- builtins.c | 79 +++++++++++++++++++++++++++++++++--------------------------- configure.ac | 2 +- exec.c | 5 ++++ execve.c | 3 ++- input.c | 3 ++- rc.1 | 11 +++------ rlimit.h | 11 +++++++++ system-bsd.c | 3 ++- wait.c | 1 - 12 files changed, 87 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1306818..b12d1d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -757,3 +757,14 @@ Changes since rc-1.5b2 more examples. Release: rc-1.6c5. + +2001-11-23 + + Bug: parselimit() was broken in various ways (thanks Chris + Siebenmann). + +2002-02-08 + + Bug: yet more wrongly ordered header file includes. + + Release: rc-1.6c6. diff --git a/NEWS b/NEWS index 34b7d6d..fc00aab 100644 --- a/NEWS +++ b/NEWS @@ -7,12 +7,13 @@ Bug fixes. A number of bugs have been fixed. The serious ones were: a core dump, triggered by `~ () '*''; premature exit, triggered by sourcing a file which could be open()ed but not read() (such as a directory on many systems); uninterruptible looping, triggered by -semantic errors in `fn prompt'. +semantic errors in `fn prompt'; deficiencies in the `limit' builtin. New features. The following features are new: the `$version' variable replaces the `-V' flag; the `-I' flag (definitively not interactive) was added for compatibility with the Plan 9 rc; ASCII SOH (^A) is now -handled transparently. +handled transparently; support for large files; support for more +limits. Documentation. Distributions of this rc used to include a PostScript paper given by Tom Duff to the UKUUG, describing the Plan 9 rc. This @@ -21,4 +22,4 @@ the web, both in its original PostScript version, and an updated HTML version. Tim Goodwin -2001-10-05 +2002-02-08 diff --git a/README b/README index 7bddd4f..fe2b7a0 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -This is release candidate rc-1.6c5. +This is release candidate rc-1.6c6. See COPYING for copying information. All files are - Copyright 1991, 2001 Byron Rakitzis. + Copyright 1991, 2001, 2002 Byron Rakitzis. See INSTALL for build and installation information. diff --git a/builtins.c b/builtins.c index 283d2fa..ea708b6 100644 --- a/builtins.c +++ b/builtins.c @@ -423,14 +423,7 @@ static void b_newpgrp(char **av) { /* Berkeley limit support was cleaned up by Paul Haahr. */ #if HAVE_SETRLIMIT -typedef struct Suffix Suffix; -struct Suffix { - const Suffix *next; - long amount; - char *name; -}; - -static const Suffix +static const struct Suffix kbsuf = { NULL, 1024, "k" }, mbsuf = { &kbsuf, 1024*1024, "m" }, gbsuf = { &mbsuf, 1024*1024*1024, "g" }, @@ -439,32 +432,39 @@ static const Suffix htsuf = { &mtsuf, 60*60, "h" }; #define SIZESUF &gbsuf #define TIMESUF &htsuf -#define NOSUF ((Suffix *) NULL) /* for RLIMIT_NOFILE on SunOS 4.1 */ +#define NOSUF ((struct Suffix *) NULL) /* for RLIMIT_NOFILE on SunOS 4.1 */ -typedef struct { - char *name; - int flag; - const Suffix *suffix; -} Limit; -static const Limit limits[] = { +static const struct Limit limits[] = { { "cputime", RLIMIT_CPU, TIMESUF }, { "filesize", RLIMIT_FSIZE, SIZESUF }, { "datasize", RLIMIT_DATA, SIZESUF }, { "stacksize", RLIMIT_STACK, SIZESUF }, { "coredumpsize", RLIMIT_CORE, SIZESUF }, -#ifdef RLIMIT_RSS /* SysVr4 does not have this */ - { "memoryuse", RLIMIT_RSS, SIZESUF }, +#ifdef RLIMIT_NOFILE /* SUSv2, but not universal */ + { "descriptors", RLIMIT_NOFILE, NOSUF }, #endif -#ifdef RLIMIT_VMEM /* instead, they have this! */ - { "vmemory", RLIMIT_VMEM, SIZESUF }, +#ifdef RLIMIT_AS /* SUSv2, but not universal */ + { "memoryuse", RLIMIT_AS, SIZESUF }, #endif -#ifdef RLIMIT_NOFILE /* SunOS 4.1 adds a limit on file descriptors */ - { "descriptors", RLIMIT_NOFILE, NOSUF }, +#if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS) /* old name for AS */ + { "memoryuse", RLIMIT_VMEM, SIZESUF }, +#endif +#ifdef RLIMIT_RSS + { "memoryrss", RLIMIT_RSS, SIZESUF }, +#endif +#ifdef RLIMIT_NPROC + { "maxproc", RLIMIT_NPROC, NOSUF }, +#endif +#ifdef RLIMIT_MEMLOCK + { "memorylocked", RLIMIT_MEMLOCK, SIZESUF }, +#endif +#ifdef RLIMIT_LOCKS + { "filelocks", RLIMIT_LOCKS, NOSUF }, #endif { NULL, 0, NULL } }; -static void printlimit(const Limit *limit, bool hard) { +static void printlimit(const struct Limit *limit, bool hard) { struct rlimit rlim; rlim_t lim; getrlimit(limit->flag, &rlim); @@ -475,7 +475,7 @@ static void printlimit(const Limit *limit, bool hard) { if (lim == RLIM_INFINITY) fprint(1, "%s \tunlimited\n", limit->name); else { - const Suffix *suf; + const struct Suffix *suf; for (suf = limit->suffix; suf != NULL; suf = suf->next) if (lim % suf->amount == 0 && (lim != 0 || suf->amount > 1)) { lim /= suf->amount; @@ -485,30 +485,39 @@ static void printlimit(const Limit *limit, bool hard) { } } -static rlim_t parselimit(const Limit *limit, char *s) { +static bool parselimit(const struct Limit *resource, rlim_t *limit, char *s) { char *t; int len = strlen(s); - long lim = 1; - const Suffix *suf = limit->suffix; - if (streq(s, "unlimited")) - return RLIM_INFINITY; + const struct Suffix *suf = resource->suffix; + + *limit = 1; + if (streq(s, "unlimited")) { + *limit = RLIM_INFINITY; + return TRUE; + } if (suf == TIMESUF && (t = strchr(s, ':')) != NULL) { + int min, sec; *t++ = '\0'; - lim = 60 * a2u(s) + a2u(t); + min = a2u(s); sec = a2u(t); + if (min == -1 || sec == -1) return FALSE; + *limit = 60 * min + sec; } else { + int n; for (; suf != NULL; suf = suf->next) if (streq(suf->name, s + len - strlen(suf->name))) { s[len - strlen(suf->name)] = '\0'; - lim *= suf->amount; + *limit *= suf->amount; break; } - lim *= a2u(s); + n = a2u(s); + if (n == -1) return FALSE; + *limit *= n; } - return lim; + return TRUE; } static void b_limit(char **av) { - const Limit *lp = limits; + const struct Limit *lp = limits; bool hard = FALSE; if (*++av != NULL && streq(*av, "-h")) { av++; @@ -532,9 +541,9 @@ static void b_limit(char **av) { printlimit(lp, hard); else { struct rlimit rlim; - long pl; + rlim_t pl; getrlimit(lp->flag, &rlim); - if ((pl = parselimit(lp, *av)) < 0) { + if (!parselimit(lp, &pl, *av)) { fprint(2, "bad limit\n"); set(FALSE); return; diff --git a/configure.ac b/configure.ac index 89d737b..9729f63 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6c5) +AM_INIT_AUTOMAKE(rc, 1.6c6) AM_CONFIG_HEADER(config.h) diff --git a/exec.c b/exec.c index 55f3bb9..8be8028 100644 --- a/exec.c +++ b/exec.c @@ -7,6 +7,11 @@ #include "wait.h" +#include +#include + +#include "wait.h" + #include "rc.h" #include "wait.h" /* diff --git a/execve.c b/execve.c index 3fb5cc1..5edde11 100644 --- a/execve.c +++ b/execve.c @@ -5,9 +5,10 @@ spots before av[][] so that execve does not have to call malloc. */ -#include #include "rc.h" +#include + #define giveupif(x) { if (x) goto fail; } extern int rc_execve(char *path, char **av, char **ev) { diff --git a/input.c b/input.c index 778f09b..1c47aee 100644 --- a/input.c +++ b/input.c @@ -1,8 +1,9 @@ /* input.c: i/o routines for files and pseudo-files (strings) */ +#include "rc.h" + #include -#include "rc.h" #include "jbwrap.h" /* diff --git a/rc.1 b/rc.1 index 5a570ec..816ab66 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2001-11-20" +.TH RC 1 "2002-02-08" .SH NAME rc \- shell .SH SYNOPSIS @@ -1273,11 +1273,6 @@ prints .Cr "bqstatus=1" .De .TP -.Cr bqstatus -The exit status of the -.I rc -forked to execute the most recent backquote substitution. -.TP .Cr cdpath A list of directories to search for the target of a .B cd @@ -1429,9 +1424,9 @@ The first element of this list variable is a string which identifies this version of .IR rc . The second element is a string which can be found by -.IR ident +.B ident and -.IR "sccs what" . +.BR "sccs what" . .PP The values of .Cr "$path" , diff --git a/rlimit.h b/rlimit.h index f3c2e3d..a3dbe8d 100644 --- a/rlimit.h +++ b/rlimit.h @@ -39,4 +39,15 @@ typedef long rlim_t; #define RLIMIT_NOFILE RLIMIT_OFILE #endif +struct Suffix { + const struct Suffix *next; + long amount; + char *name; +}; + +struct Limit { + char *name; + int flag; + const struct Suffix *suffix; +}; #endif /* HAVE_SETRLIMIT */ diff --git a/system-bsd.c b/system-bsd.c index 3babaea..f081e1a 100644 --- a/system-bsd.c +++ b/system-bsd.c @@ -1,9 +1,10 @@ /* signal-safe read and write (for BSD slow devices). writeall() also allows partial writes */ +#include "rc.h" + #include -#include "rc.h" #include "jbwrap.h" #include "wait.h" diff --git a/wait.c b/wait.c index 66c5097..7ac9973 100644 --- a/wait.c +++ b/wait.c @@ -1,6 +1,5 @@ #include -#include "rc.h" #include "wait.h" bool forked = FALSE; -- cgit v1.2.3 From 2e67f638ea031ce0138891b6356806b463f5e9af Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 22 May 2002 14:25:10 +0100 Subject: candidate: rc-1.6c7 --- AUTHORS | 12 ++--- COPYING | 2 +- ChangeLog | 16 +++++++ INSTALL | 33 +++++++------- NEWS | 8 ++-- README | 2 +- configure.ac | 2 +- exec.c | 5 --- hash.c | 35 ++++++++++++--- history.1 | 15 ++++++- history.c | 14 ++++-- main.c | 6 ++- rc.1 | 145 +++++++++++++++++++++++++++++------------------------------ rc.h | 9 +++- var.c | 3 +- 15 files changed, 183 insertions(+), 124 deletions(-) diff --git a/AUTHORS b/AUTHORS index 11bbd1d..2c7833d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,9 +29,9 @@ version of rc presented here differs in some respects. Tim would like to thank these people for their contributions since he took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, Chris -Siebenmann, Dale Scheetz, David Luyer, David Swasey, Decklin Foster, -Donn Cave, Gary Carvell, Gerry Tomlinson, Gert-Jan Vons, Ian Lance -Taylor, Jeremy Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K -Gardner, Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, -Stefan Dalibor, Steve Simon, Thomas Nordin, Tom Culliton, Tom Tromey, -Vincent Broman, Wolfgang Zekoll. +Siebenmann, Dale Scheetz, Dan Moniz, David Luyer, David Swasey, +Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell, Gerry +Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc +Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond Venneker, Rich +$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve Simon, Thomas +Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang Zekoll. diff --git a/COPYING b/COPYING index 03ca62d..a66f884 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ /* - * Copyright 1991, 2001 Byron Rakitzis. All rights reserved. + * Copyright 1991 by Byron Rakitzis. All rights reserved. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. diff --git a/ChangeLog b/ChangeLog index b12d1d4..29d04d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -768,3 +768,19 @@ Changes since rc-1.5b2 Bug: yet more wrongly ordered header file includes. Release: rc-1.6c6. + +2002-04-03 + + Feature: make $version less magical, and exportable if it's changed + from its default value. Same for $prompt (thank Erik Quanstrom). + + Bug: make $bqstatus and $status not exportable. + + Feature: "stuttering" colons for multiple replacements in the + history programs (thanks Callum Gibson). + +2002-05-22 + + Documentation: possible warning in tripping.c (thanks Dan Moniz). + + Release: rc-1.6c7. diff --git a/INSTALL b/INSTALL index 12129d6..dfeb2df 100644 --- a/INSTALL +++ b/INSTALL @@ -15,8 +15,8 @@ to build rc in a different directory). BUILD AND CONFIGURATION OPTIONS There are lots of options you can give to configure to modify rc's -behaviour. You can also select a command line history library to -link against---see the README file for details of where to find these +behaviour. You can also select a command line history library to link +against---see the rc web page for details of where to find these libraries. For a summary of all options, run `sh configure --help'. You can specify Makefile variables by setting the corresponding @@ -31,7 +31,7 @@ descending order of usefulness. --with-editline - This option tells rc to use the editline package (see the README file + This option tells rc to use the editline package (see the web page for details) to provide EMACS style command line editing and history. If the editline library is not installed in a standard place, you can tell configure where to find it by setting the environment variable @@ -42,7 +42,7 @@ descending order of usefulness. --with-vrl - This option tells rc to use the vrl package (see the README file for + This option tells rc to use the vrl package (see the web page for details) to provide EMACS style command line editing and history. As for `--with-editline', you may need to set the environment variable LDFLAGS appropriately. @@ -61,13 +61,13 @@ descending order of usefulness. --with-history Use this option if you want to build and install the programs that - support a crude history mechanism. + support a crude command-line history mechanism. You can't use more than one of `--with-editline', `--with-vrl', and `--with-readline' at the same time. If you have any of these you probably don't want to bother with `--with-history'. - --prefix /path + --prefix=/path By default, `prefix' is /usr/local, which means that `make install' installs rc (and possibly the history programs) in /usr/local/bin, and @@ -94,10 +94,10 @@ probably don't want to bother with `--with-history'. --disable-def-interp --enable-def-interp=/bin/foo - By default, a program that fails with "Exec format error" is handed to - /bin/sh. This does the Right Thing for scripts that start with `:' to - indicate that they are sh scripts. You can disable this behaviour - entirely, or specify a different default interpreter. + By default, a program that fails with ENOEXEC (Exec format error) is + handed to /bin/sh. This does the Right Thing for scripts that start + with `:' to indicate that they are sh scripts. You can disable this + behaviour entirely, or specify a different default interpreter. --disable-def-path --enable-def-path "/usr/local/bin","/usr/bin" @@ -129,11 +129,11 @@ probably don't want to bother with `--with-history'. dying or discarding the variables. This option disables the default behaviour. You are unlikely to want this option on any Unix system. -After you've built rc, I recommend that you run it through a test script -to gain some confidence that all is working well. Type `make trip' to -do this. This will produce some output, and should end with "trip is -complete". If the trip instead ends with "trip took a wrong turn..." -please contact the maintainer. +After you've built rc, I recommend that you run it through the test +script to gain some confidence that all is working well. Type `make +trip' to do this. This will produce some output, and should end with +"trip is complete". If the trip instead ends with "trip took a wrong +turn..." please contact the maintainer. LARGE FILE SUPPORT @@ -181,6 +181,9 @@ On some systems there are warnings about "passing arg 2 of `getgroups' from incompatible pointer type" in which.c. I believe this is due to an incorrect declaration of `getgroups()' in those systems' header files. +The warning "left shift count >= width of type" in tripping.c may +occur if off_t is only 32 bits. + Any other warnings should be reported to the maintainer. diff --git a/NEWS b/NEWS index fc00aab..8aee1a8 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ Highlights of changes since rc-1.6. See ChangeLog for further details. -Portability. Many minor tweaks, including fixes for BeOS, CygWin, and -gcc-3. +Portability. Many minor tweaks, including fixes for BeOS, CygWin, +QNX, and gcc-3. Bug fixes. A number of bugs have been fixed. The serious ones were: a core dump, triggered by `~ () '*''; premature exit, triggered by @@ -13,7 +13,7 @@ New features. The following features are new: the `$version' variable replaces the `-V' flag; the `-I' flag (definitively not interactive) was added for compatibility with the Plan 9 rc; ASCII SOH (^A) is now handled transparently; support for large files; support for more -limits. +process resource limits. Documentation. Distributions of this rc used to include a PostScript paper given by Tom Duff to the UKUUG, describing the Plan 9 rc. This @@ -22,4 +22,4 @@ the web, both in its original PostScript version, and an updated HTML version. Tim Goodwin -2002-02-08 +2002-05-21 diff --git a/README b/README index fe2b7a0..1ab489c 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is release candidate rc-1.6c6. +This is release candidate rc-1.6c7. See COPYING for copying information. All files are diff --git a/configure.ac b/configure.ac index 9729f63..d425740 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6c6) +AM_INIT_AUTOMAKE(rc, 1.6c7) AM_CONFIG_HEADER(config.h) diff --git a/exec.c b/exec.c index 8be8028..55f3bb9 100644 --- a/exec.c +++ b/exec.c @@ -7,11 +7,6 @@ #include "wait.h" -#include -#include - -#include "wait.h" - #include "rc.h" #include "wait.h" /* diff --git a/hash.c b/hash.c index 16971ef..3f65ad8 100644 --- a/hash.c +++ b/hash.c @@ -228,14 +228,37 @@ extern void initenv(char **envp) { } } +static char *neverexport[] = { + "apid", "apids", "bqstatus", "cdpath", "home", + "ifs", "path", "pid", "status", "*" +}; + +/* for a few variables that have default values, we export them only +if they've been explicitly set; maybeexport[n].flag is TRUE if this +has occurred. */ +struct nameflag { + char *name; + bool flag; +}; +static struct nameflag maybeexport[] = { + { "prompt", FALSE }, + { "version", FALSE } +}; + +void set_exportable(char *s, bool b) { + int i; + for (i = 0; i < arraysize(maybeexport); ++i) + if (maybeexport[i].flag != b && streq(s, maybeexport[i].name)) + maybeexport[i].flag = b; +} + static bool var_exportable(char *s) { - static char *notforexport[] = { - "apid", "apids", "cdpath", "home", "ifs", - "path", "pid", "version", "*" - }; int i; - for (i = 0; i < arraysize(notforexport); i++) - if (streq(s, notforexport[i])) + for (i = 0; i < arraysize(neverexport); i++) + if (streq(s, neverexport[i])) + return FALSE; + for (i = 0; i < arraysize(maybeexport); i++) + if (maybeexport[i].flag == FALSE && streq(s, maybeexport[i].name)) return FALSE; return TRUE; } diff --git a/history.1 b/history.1 index 5530654..0be8684 100644 --- a/history.1 +++ b/history.1 @@ -176,13 +176,14 @@ matched before a command is selected. Substitutions may also be specified on the command line. These have the syntax: .Ds -.Ic old : new +.Ic old :[:...] new .De .PP (Note that the .I old pattern is used as a search-limiting pattern also.) -Substitutions happen on the first match. +Substitutions happen from left to right and are repeated according to the +number of colons specified. .PP Finally, if the program was invoked as .RI `` -- '' @@ -241,3 +242,13 @@ reinterpretation: .Cr " eval $comm" .Cr " }" .Cr "}" +.De +.PP +Stuttering the `:' in a substitution allows things like: +.Ds +; prog 1 2 3 abc > /very/long/path/abc.out +etc. +- prog abc::xyz +prog 1 2 3 xyz > /very/long/path/xyz.out +; +.De diff --git a/history.c b/history.c index 629751d..2993a69 100644 --- a/history.c +++ b/history.c @@ -26,6 +26,7 @@ static const char id[] = "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $"; static struct { char *old, *new; + int reps; /* no. of repetitions. i.e. 1 means sub twice. */ } *replace; static char **search, *progname, *history; @@ -296,8 +297,12 @@ int main(int argc, char **argv) { search[nsearch++] = argv[i]; else { *(char *)s = '\0'; /* do we confuse ps too much? */ + replace[nreplace].reps = 0; + while(*(++s) == ':') { + replace[nreplace].reps++; + } replace[nreplace].old = argv[i]; - replace[nreplace].new = s + 1; + replace[nreplace].new = s; nreplace++; } @@ -312,8 +317,11 @@ next: s = getcommand(); for (i = 0; i < nreplace; i++) if (!isin(s, replace[i].old)) goto next; - else - s = sub(s, replace[i].old, replace[i].new); + else { + int j; + for (j = 0; j <= replace[i].reps; j++) + s = sub(s, replace[i].old, replace[i].new); + } if (editit) { s = edit(s); if (s == NULL) diff --git a/main.c b/main.c index 57a79c3..6ce7317 100644 --- a/main.c +++ b/main.c @@ -74,12 +74,13 @@ quitopts: initsignal(); inithash(); initparse(); - assigndefault("prompt", "; ", "", (void *)0); + assigndefault("ifs", " ", "\t", "\n", (void *)0); #ifdef DEFAULTPATH assigndefault("path", DEFAULTPATH, (void *)0); #endif - assigndefault("ifs", " ", "\t", "\n", (void *)0); assigndefault("pid", nprint("%d", rc_pid), (void *)0); + assigndefault("prompt", "; ", "", (void *)0); + assigndefault("version", VERSION, "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $", (void *)0); initenv(envp); initinput(); null[0] = NULL; @@ -112,6 +113,7 @@ static void assigndefault(char *name,...) { for (l = NULL; (v = va_arg(ap, char *)) != NULL;) l = append(l, word(v, NULL)); varassign(name, l, FALSE); + set_exportable(name, FALSE); if (streq(name, "path")) alias(name, l, FALSE); va_end(ap); diff --git a/rc.1 b/rc.1 index 816ab66..40fcc67 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2002-02-08" +.TH RC 1 "2002-05-21" .SH NAME rc \- shell .SH SYNOPSIS @@ -1200,10 +1200,38 @@ as its value. Several variables are known to .I rc and are treated specially. -In the following list, ``(read only)'' indicates that an attempt to set the -variable will silently have no effect. +In the following list, ``default'' indicates that +.I rc +gives the variable a default value on startup; ``no-export'' indicates +that the variable is never exported; and ``read-only'' indicates that +an attempt to set the variable will silently have no effect. +.PP +Also, ``alias'' means that the variable is aliased to the same name in +capitals. +For example, an assignment to +.Cr $cdpath +causes an automatic assignment to +.Cr $CDPATH , +and vice-versa. +If +.Cr $CDPATH +is set when +.I rc +is started, its value is imported into +.Cr $cdpath . +.Cr $cdpath +and +.Cr $path +are +.I rc +lists; +.Cr $CDPATH +and +.Cr $PATH +are colon-separated lists. +Only the names spelt in capitals are exported into the environment. .TP -.Cr * +.Cr * " (no-export)" The argument list of .IR rc . .Cr "$1, $2," @@ -1212,7 +1240,7 @@ etc. are the same as .Cr $*(2) , etc. .TP -.Cr 0 +.Cr 0 " (default no-export)" The variable .Cr $0 holds the value of @@ -1234,15 +1262,15 @@ is not an element of .Cr $* , and is never treated as one. .TP -.Cr apid +.Cr apid " (no-export)" The process ID of the last process started in the background. .TP -.Cr apids " (read only)" +.Cr apids " (no-export read-only)" A list whose elements are the process IDs of all background processes which are still alive, or which have died and have not been waited for yet. .TP -.Cr bqstatus +.Cr bqstatus " (no-export)" The exit status of the .I rc forked to execute the most recent backquote substitution. Note that, unlike @@ -1273,7 +1301,7 @@ prints .Cr "bqstatus=1" .De .TP -.Cr cdpath +.Cr cdpath " (alias)" A list of directories to search for the target of a .B cd command. @@ -1283,14 +1311,6 @@ Note that if the variable does not contain the current directory, then the current directory will not be searched; this allows directory searching to begin in a directory other than the current directory. -Note also that an assignment to -.Cr $cdpath -causes an automatic assignment to -.Cr $CDPATH , -and vice-versa. -Only -.Cr $CDPATH -is exported into the environment. .TP .Cr history .Cr $history @@ -1309,7 +1329,7 @@ is not set, then .I rc does not append commands to any file. .TP -.Cr home +.Cr home " (alias)" The default directory for the builtin .B cd command, and the directory in which @@ -1319,30 +1339,17 @@ looks to find its initialization file, if .I rc has been started up as a login shell. -Like -.Cr $cdpath -and -.Cr $CDPATH , -.Cr $home -and -.Cr $HOME -are aliased to each other. .TP -.Cr ifs +.Cr ifs " (default)" The internal field separator, used for splitting up the output of -backquote commands for digestion as a list. +backquote commands for digestion as a list. On startup, +.I rc +assigns the list containing the characters space, tab, and newline to +.Cr $ifs . .TP -.Cr path +.Cr path " (alias)" This is a list of directories to search in for commands. The empty string stands for the current directory. -Note that like -.Cr $cdpath -and -.Cr $CDPATH , -.Cr $path -and -.Cr $PATH -are aliased to each other. If neither .Cr $PATH nor @@ -1353,11 +1360,13 @@ assumes a default value suitable for your system. This is typically .Cr "(/usr/local/bin /usr/bin /usr/ucb /bin .)" .TP -.Cr pid -The process ID of the currently running +.Cr pid " (default no-export)" +On startup, +.Cr $pid +is initialized to the numeric process ID of the currently running .IR rc . .TP -.Cr prompt +.Cr prompt " (default)" This variable holds the two prompts (in list form, of course) that .I rc prints. @@ -1398,7 +1407,7 @@ If this function is defined, then it gets executed every time is about to print .Cr "$prompt(1)" . .TP -.Cr status " (read only)" +.Cr status " (no-export read-only)" The exit status of the last command. If the command exited with a numeric value, that number is the status. If the command died with a signal, the status is the name of that signal; @@ -1419,38 +1428,14 @@ usually sets to .Cr "(0 0)" . .TP -.Cr version " (read only)" -The first element of this list variable is a string which identifies this -version of +.Cr version " (default)" +On startup, the first element of this list variable is initialized to +a string which identifies this version of .IR rc . -The second element is a string which can be found by +The second element is initialized to a string which can be found by .B ident and .BR "sccs what" . -.PP -The values of -.Cr "$path" , -.Cr "$cdpath" , -and -.Cr $home -are derived from the environment -values of -.Cr "$PATH" , -.Cr "$CDPATH" , -and -.Cr "$HOME" . -Otherwise, they are derived from -the environment values of -.Cr $path , -.Cr $cdpath -and -.Cr $home . -This is for compatibility with other Unix programs, like -.IR sh (1). -.Cr $PATH -and -.Cr $CDPATH -are assumed to be colon-separated lists. .SH FUNCTIONS .I rc functions are identical to @@ -1490,7 +1475,7 @@ could be: .PP but not .Ds -.Cr "fn l { ls -FC }" +.Cr "fn l { ls -FC } # WRONG" .De .SH "INTERRUPTS AND SIGNALS" .I rc @@ -1579,7 +1564,7 @@ Thus from within a shell script, .De .TP \& -does the ``right'' thing. +does the ``right thing''. .TP .B break Breaks from the innermost @@ -1682,7 +1667,7 @@ Similar to the .IR csh (1) .B limit builtin, this command operates upon the -BSD-style limits of a process. +BSD-style resource limits of a process. The .Cr \-h flag displays/alters the hard @@ -1695,9 +1680,14 @@ The resources which can be shown or altered are .BR coredumpsize , .BR memoryuse , and, where supported, -.BR descriptors . -For -example: +.BR descriptors , +.BR memoryuse , +.BR memoryrss , +.BR maxproc , +.BR memorylocked , +and +.BR filelocks . +For example: .Ds .Cr "limit coredumpsize 0" .De @@ -2117,6 +2107,11 @@ keywords, the .B echo builtin, +the +.Cr bqstatus +and +.Cr rc_version +variables, the support for the GNU .IR readline (3) library and diff --git a/rc.h b/rc.h index fd3fc27..ca0f51b 100644 --- a/rc.h +++ b/rc.h @@ -194,7 +194,13 @@ extern void sigint(int); /* exec.c */ extern void exec(List *, bool); -extern void doredirs(void); + +#if HASH_BANG +#define rc_execve execve +#else +/* execve.c */ +extern int my_execve(char *, char **, char **); +#endif #if HASH_BANG #define rc_execve execve @@ -251,6 +257,7 @@ extern void fnassign_string(char *); extern void fnrm(char *); extern void initenv(char **); extern void inithash(void); +extern void set_exportable(char *, bool); extern void setsigdefaults(bool); extern void inithandler(void); extern void varassign(char *, List *, bool); diff --git a/var.c b/var.c index 1c30fba..e53ff09 100644 --- a/var.c +++ b/var.c @@ -18,6 +18,7 @@ extern void varassign(char *name, List *def, bool stack) { new = get_var_place(name, stack); new->def = newdef; new->extdef = NULL; + set_exportable(name, TRUE); #if READLINE if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) rl_reset_terminal(NULL); @@ -68,8 +69,6 @@ extern List *varlookup(char *name) { return sgetapids(); if (streq(name, "status")) return sgetstatus(); - if (streq(name, "version")) - return &id1; if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */ for (l = varlookup("*"); l != NULL && sub != 0; --sub) l = l->n; -- cgit v1.2.3 From 77b18786228a8cf9f58aee09677440c61dc218a9 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 19 Jun 2002 16:12:04 +0100 Subject: release: rc-1.7 --- COPYING | 2 +- ChangeLog | 4 ++++ INSTALL | 13 +++++++++---- README | 2 +- configure.ac | 2 +- exec.c | 2 -- mkstatval.c | 26 ++++++++++++++++++++++++++ rc.1 | 16 +++++++++++++--- rc.h | 7 ------- var.c | 3 --- wait.c | 2 ++ 11 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 mkstatval.c diff --git a/COPYING b/COPYING index a66f884..17e0588 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ /* - * Copyright 1991 by Byron Rakitzis. All rights reserved. + * Copyright 1991, 2001, 2002 by Byron Rakitzis. All rights reserved. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. diff --git a/ChangeLog b/ChangeLog index 29d04d6..436a842 100644 --- a/ChangeLog +++ b/ChangeLog @@ -784,3 +784,7 @@ Changes since rc-1.5b2 Documentation: possible warning in tripping.c (thanks Dan Moniz). Release: rc-1.6c7. + +2002-06-18 + + Release: rc-1.7. diff --git a/INSTALL b/INSTALL index dfeb2df..0014d23 100644 --- a/INSTALL +++ b/INSTALL @@ -21,10 +21,11 @@ libraries. For a summary of all options, run `sh configure --help'. You can specify Makefile variables by setting the corresponding environment variables. For example, you might want to set `CC=cc', to -prevent configure looking for gcc, or set an initial value for `LIBS', -as in the example below. It is a good idea to specify static linking -(unless you are linking against a dynamic readline library)---if you are -using gcc, you can do this by setting `CFLAGS=-static'. +prevent configure looking for gcc, or set an initial value for +`LDFLAGS', as in the example below. It is a good idea to specify +static linking (unless you are linking against a dynamic readline +library)---if you are using gcc, you can do this by setting +`CFLAGS=-static'. Here are the configure options you may want to use, in approximately descending order of usefulness. @@ -135,6 +136,10 @@ trip' to do this. This will produce some output, and should end with "trip is complete". If the trip instead ends with "trip took a wrong turn..." please contact the maintainer. +In this release, `make trip' will fail on a file system which does not +implement Unix semantics (specifically permissions bits). This means +that `make trip' is not useful under CygWin, for instance. + LARGE FILE SUPPORT diff --git a/README b/README index 1ab489c..f6fa3f0 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is release candidate rc-1.6c7. +This is release rc-1.7. See COPYING for copying information. All files are diff --git a/configure.ac b/configure.ac index d425740..ffe9357 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl Automake stuff. dnl Use this one for snapshots... dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.6c7) +AM_INIT_AUTOMAKE(rc, 1.7) AM_CONFIG_HEADER(config.h) diff --git a/exec.c b/exec.c index 55f3bb9..c9244c2 100644 --- a/exec.c +++ b/exec.c @@ -7,8 +7,6 @@ #include "wait.h" -#include "rc.h" -#include "wait.h" /* Takes an argument list and does the appropriate thing (calls a builtin, calls a function, etc.) diff --git a/mkstatval.c b/mkstatval.c new file mode 100644 index 0000000..c74ac46 --- /dev/null +++ b/mkstatval.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +int main(void) { + int cstatus, pstatus; + pid_t pid; + + for (cstatus = 0; cstatus < 2; ++cstatus) { + switch (pid = fork()) { + case -1: + perror("fork"); + return 1; + case 0: + _exit(cstatus); + default: + if (wait(&pstatus) != pid) { + perror("wait"); + return 1; + } + printf("#define STATUS%d %d\n", cstatus, pstatus); + } + } + return 0; +} diff --git a/rc.1 b/rc.1 index 40fcc67..19d4a8c 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2002-05-21" +.TH RC 1 "2002-06-18" .SH NAME rc \- shell .SH SYNOPSIS @@ -1135,7 +1135,8 @@ operator: .De .PP This is useful when the normal list concatenation rules need to be -bypassed. For example, to append a single period at the end of +bypassed. +For example, to append a single period at the end of .Cr $path , use: .Ds @@ -1413,7 +1414,8 @@ If the command exited with a numeric value, that number is the status. If the command died with a signal, the status is the name of that signal; if a core file was created, the string .Rc `` +core '' -is appended. The value of +is appended. +The value of .Cr $status for a pipeline is a list, with one entry, as above, for each process in the pipeline. @@ -1694,6 +1696,10 @@ For example: .TP \& disables core dumps. +To set a soft limit equal to the hard limit: +.Ds +.Cr "limit `{limit -h datasize}" +.De .TP .B newpgrp Puts @@ -2043,6 +2049,10 @@ The redundant inner parentheses must be omitted. .PP Variable subscripting cannot be used in here documents. .PP +The +.Cr limit +builtin silently ignores extra arguments. +.PP Bug reports should be mailed to .Cr "" . .SH INCOMPATIBILITIES diff --git a/rc.h b/rc.h index ca0f51b..24a334b 100644 --- a/rc.h +++ b/rc.h @@ -202,13 +202,6 @@ extern void exec(List *, bool); extern int my_execve(char *, char **, char **); #endif -#if HASH_BANG -#define rc_execve execve -#else -/* execve.c */ -extern int my_execve(char *, char **, char **); -#endif - /* footobar.c */ extern char **list2array(List *, bool); extern char *get_name(char *); diff --git a/var.c b/var.c index e53ff09..83c5ff9 100644 --- a/var.c +++ b/var.c @@ -58,9 +58,6 @@ extern bool varassign_string(char *extdef) { associated with $status) */ -static List id2 = { "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $", 0, 0 }; -static List id1 = { VERSION, 0, &id2 }; - extern List *varlookup(char *name) { Variable *look; List *ret, *l; diff --git a/wait.c b/wait.c index 7ac9973..1ab8533 100644 --- a/wait.c +++ b/wait.c @@ -1,3 +1,5 @@ +#include "rc.h" + #include #include "wait.h" -- cgit v1.2.3 From d884971193ef4934424b77ae862e8b0ecf70bab3 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 13 Aug 2003 13:51:14 +0100 Subject: release: rc-1.7.1 --- ChangeLog | 42 ++++++++++++++++++++++++++++++++++++++++++ INSTALL | 30 ++++++------------------------ Makefile.am | 10 +++++----- NEWS | 33 ++++++++++++++------------------- README | 4 ++-- acinclude.m4 | 33 +++++++++------------------------ configure.ac | 53 ++++++++++++++++++++++++++--------------------------- glob.c | 6 +++--- history.c | 24 ++++++++++++------------ input.c | 4 +++- nalloc.c | 4 +++- rc.1 | 21 ++++++++++++--------- rc.h | 2 +- signal.c | 15 +++++++++++---- stat.h | 6 ++++++ trip.rc | 18 +++++++----------- tripping.c | 18 ------------------ var.c | 1 + which.c | 14 +++++++------- 19 files changed, 170 insertions(+), 168 deletions(-) create mode 100644 stat.h diff --git a/ChangeLog b/ChangeLog index 436a842..9fc918b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -788,3 +788,45 @@ Changes since rc-1.5b2 2002-06-18 Release: rc-1.7. + +2002-07-25 + + Bug: fix globbing of broken symlinks. + +2002-07-31 + + Bug: readline doesn't handle EIO either. + +2002-08-15 + + Bug: variables that are sometimes exported (i.e. $prompt and + $version) need to be made exportable if they are inherited from the + environment. + + Portability: don't call sigaction() for SIGKILL or SIGSTOP; don't + hand a garbage signal mask to sigaction() (thanks Jeremy + Fitzhardinge). Also, remove use of SA_INTERRUPT (SUSv3, BSD, + etc. have SA_RESTART with the inverted meaning). + +2002-08-20 + + Bug: don't call ealloc(0) on systems where getgroups() doesn't + return egid (thanks Chris Siebenmann). + +2002-11-27 + + Bug: history dumps core if more colons than substitutions (thanks + Callum Gibson); history fails to avoid itself if it's the only + command; history writes and reads outside allocated memory. + + Configuration: upgrade to autoconf-2.56 and automake-1.7.1. + +2003-07-17 + + Testing: remove test for large file support, as it causes + indigestion on file systems that don't support sparse files (thanks + Scott Schwartz). + +2003-07-22 + + Release: rc-1.7.1. diff --git a/INSTALL b/INSTALL index 0014d23..6174223 100644 --- a/INSTALL +++ b/INSTALL @@ -33,13 +33,13 @@ descending order of usefulness. --with-editline This option tells rc to use the editline package (see the web page - for details) to provide EMACS style command line editing and history. - If the editline library is not installed in a standard place, you can - tell configure where to find it by setting the environment variable - LDFLAGS. For example, the maintainer builds rc by copying libedit.a - into the rc build directory and then running this configure command. + for details) to provide EMACS style command line editing and + history. If the editline library is not installed in a standard + place, you can tell configure where to find it by setting the + environment variable LDFLAGS. For example, you might copy libedit.a + into the rc source directory and then run this configure command. - LDFLAGS=-L. sh ../rc-1.5b3/configure --with-editline + LDFLAGS=-L. sh configure --with-editline --with-vrl @@ -141,24 +141,6 @@ implement Unix semantics (specifically permissions bits). This means that `make trip' is not useful under CygWin, for instance. -LARGE FILE SUPPORT - -This release of rc supports large files (i.e. with 64 bit offsets), on -systems where the configure script can figure out how to enable this. -When you run `make trip' (you always run `make trip', right?) the -penultimate line of output (before "trip complete") reports whether -large file support seems to be working or not. - -Large file support is a function of file systems, as well as -applications. For example, NFS and tmpfs file systems often do not -support large files. The test used by `make trip' is therefore -subject to false negatives. That is, a report that "large file -support seems NOT to be working" may be erroneous. To minimise this -possibility, the test is performed both in the current directory -(where you built rc) and /tmp. (I don't think there's any scenario -where a false positive can be reported.) - - BUILDING IN ANOTHER DIRECTORY If you have a suitable `make', you can build rc in a different directory diff --git a/Makefile.am b/Makefile.am index d003ef6..ee3829c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,5 @@ ## Process this file with automake to produce Makefile.in -if AMC_ADDON -ADDON = @ADDON@ -endif - if AMC_HISTORY man_MANS = rc.1 history.1 HISTORY = history @@ -35,7 +31,7 @@ EXTRA_rc_SOURCES = addon.c execve.c readline.c system.c system-bsd.c rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) rc_LDADD = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) -noinst_HEADERS = getgroups.h jbwrap.h parse.h proto.h rc.h rlimit.h wait.h +noinst_HEADERS = getgroups.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h BUILT_SOURCES = sigmsgs.c @@ -44,6 +40,10 @@ EXTRA_DIST = EXAMPLES RELDATE addon.c addon.h history.1 parse.y rc.1 trip.rc sigmsgs.c sigmsgs.h: mksignal ./mksignal +# Newer automake's buildtime dependency tracking can't seem to figure +# this one out. +status.o: statval.h + statval.h: mkstatval ./mkstatval > statval.h diff --git a/NEWS b/NEWS index 8aee1a8..39126a8 100644 --- a/NEWS +++ b/NEWS @@ -1,25 +1,20 @@ -Highlights of changes since rc-1.6. See ChangeLog for further details. +Highlights of changes since rc-1.7. See ChangeLog for further details. -Portability. Many minor tweaks, including fixes for BeOS, CygWin, -QNX, and gcc-3. +Portability. A fix to the autoconfiguration means that the nasty +longjmp() code is now omitted for all modern Unix systems; previously +rc only did the Right Thing on Linux. The test for large files in +trip.rc was removed, as this causes indigestion on file systems that +don't support sparse files (the configuration and implementation of +large file support is still present of course). -Bug fixes. A number of bugs have been fixed. The serious ones were: -a core dump, triggered by `~ () '*''; premature exit, triggered by -sourcing a file which could be open()ed but not read() (such as a -directory on many systems); uninterruptible looping, triggered by -semantic errors in `fn prompt'; deficiencies in the `limit' builtin. +Bug fixes. Broken symlinks now glob correctly. The variables $prompt +and $version are now exported if they are inherited from the +environment when rc starts. EIO handling is now enabled for readline +too. A few bogosities in the history program were fixed. -New features. The following features are new: the `$version' variable -replaces the `-V' flag; the `-I' flag (definitively not interactive) -was added for compatibility with the Plan 9 rc; ASCII SOH (^A) is now -handled transparently; support for large files; support for more -process resource limits. +New features. None - this is a bugfix release. -Documentation. Distributions of this rc used to include a PostScript -paper given by Tom Duff to the UKUUG, describing the Plan 9 rc. This -paper is no longer distributed with rc, but instead is available on -the web, both in its original PostScript version, and an updated HTML -version. +Documentation. Minor updates only. Tim Goodwin -2002-05-21 +2003-07-17 diff --git a/README b/README index f6fa3f0..7a8e84f 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -This is release rc-1.7. +This is release rc-1.7.1. See COPYING for copying information. All files are - Copyright 1991, 2001, 2002 Byron Rakitzis. + Copyright 1991, 2001, 2002, 2003 Byron Rakitzis. See INSTALL for build and installation information. diff --git a/acinclude.m4 b/acinclude.m4 index 7fbc6aa..e1cd78c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -9,7 +9,7 @@ int main(void) { } ], rc_cv_func_posix_getgroups=yes, rc_cv_func_posix_getgroups=no, rc_cv_func_posix_getgroups=yes)) case "$rc_cv_func_posix_getgroups" in - yes) AC_DEFINE(HAVE_POSIX_GETGROUPS) ;; + yes) AC_DEFINE(HAVE_POSIX_GETGROUPS, 1, [Define to 1 if you have the `getgroups' function with POSIX semantics.]) ;; esac ]) @@ -25,7 +25,7 @@ sigjmp_buf e; sigsetjmp(e, 1); ], rc_cv_sigsetjmp=yes, rc_cv_sigsetjmp=no)) case "$rc_cv_sigsetjmp" in - yes) AC_DEFINE(HAVE_SIGSETJMP) ;; + yes) AC_DEFINE(HAVE_SIGSETJMP, 1, [Define to 1 if you have the `sigsetjmp' function or macro.]) ;; esac ]) @@ -38,7 +38,7 @@ AC_DEFUN(RC_FUNC_STRERROR, [ strerror(0); ], rc_cv_strerror=yes, rc_cv_strerror=no)) case "$rc_cv_strerror" in - yes) AC_DEFINE(HAVE_STRERROR) ;; + yes) AC_DEFINE(HAVE_STRERROR, 1, [Define to 1 if you have the `strerror' function or macro.]) ;; esac ]) @@ -61,7 +61,7 @@ int f; f = RLIMIT_DATA; ], rc_cv_kernel_rlimit=yes, rc_cv_kernel_rlimit=no)])) case "$rc_cv_kernel_rlimit" in - yes) AC_DEFINE(RLIMIT_NEEDS_KERNEL) ;; + yes) AC_DEFINE(RLIMIT_NEEDS_KERNEL, 1, [Define to 1 if `_KERNEL' must be defined for `RLIMIT_*' macros.]) ;; esac ]) @@ -77,7 +77,7 @@ AC_DEFUN(RC_TYPE_RLIM_T, [ ], rc_cv_have_rlim_t=yes, rc_cv_have_rlim_t=no)) case "$rc_cv_have_rlim_t" in - yes) AC_DEFINE(HAVE_RLIM_T) ;; + yes) AC_DEFINE(HAVE_RLIM_T, 1, [Define to 1 if you have the `rlim_t' type.]) ;; no) AC_CACHE_CHECK(for native quad_t, rc_cv_have_quad_t, AC_TRY_COMPILE([ #include @@ -88,7 +88,7 @@ a = (quad_t)0; ], rc_cv_have_quad_t=yes, rc_cv_have_quad_t=no)) case "$rc_cv_have_quad_t" in - yes) AC_DEFINE(HAVE_QUAD_T) + yes) AC_DEFINE(HAVE_QUAD_T, 1, [Define to 1 if you have the `quad_t' type.]) AC_CACHE_CHECK(if rlimit values are quad_t, rc_cv_rlim_t_is_quad_t, AC_TRY_RUN([ #include @@ -108,7 +108,7 @@ main(){ ], rc_cv_rlim_t_is_quad_t=yes, rc_cv_rlim_t_is_quad_t=no, $ac_cv_type_quad_t)) case "$rc_cv_rlim_t_is_quad_t" in - yes) AC_DEFINE(RLIM_T_IS_QUAD_T) ;; + yes) AC_DEFINE(RLIM_T_IS_QUAD_T, 1, [Define to 1 if `rlim_t' is `quad_t'.]) ;; esac ;; esac @@ -123,26 +123,11 @@ AC_DEFUN(RC_TYPE_SIG_ATOMIC_T, [ AC_EGREP_HEADER(sig_atomic_t, signal.h, rc_cv_sig_atomic_t=yes, rc_cv_sig_atomic_t=no)) case "$rc_cv_sig_atomic_t" in - no) AC_DEFINE(sig_atomic_t, int) ;; + no) AC_DEFINE(sig_atomic_t, int, [Define to 1 if you have the `sig_atomic_t' type.]) ;; esac ]) -dnl Check for sigaction and SA_INTERRUPT -AC_DEFUN(RC_FUNC_SIGACTION, [ - AC_CACHE_CHECK(for sigaction and SA_INTERRUPT, rc_cv_sa_int, - AC_TRY_COMPILE([ -#include - ], [ -struct sigaction foo; -foo.sa_flags = SA_INTERRUPT; -sigaction(SIGINT, 0, 0); - ], rc_cv_sa_int=yes, rc_cv_sa_int=no - ) - ) -]) - - dnl Do we have SysV SIGCLD semantics? In other words, if we set the dnl action for SIGCLD to SIG_IGN does wait() always say ECHILD? Linux, dnl of course, is bizarre here. It basically implements the SysV @@ -174,7 +159,7 @@ int main(void) { } ], rc_cv_sysv_sigcld=yes, rc_cv_sysv_sigcld=no, rc_cv_sysv_sigcld=yes)) case "$rc_cv_sysv_sigcld" in - yes) AC_DEFINE(HAVE_SYSV_SIGCLD) ;; + yes) AC_DEFINE(HAVE_SYSV_SIGCLD, 1, [Has SysV SIGCLD]) ;; esac ]) diff --git a/configure.ac b/configure.ac index ffe9357..a2f2043 100644 --- a/configure.ac +++ b/configure.ac @@ -2,13 +2,13 @@ dnl Get things going... AC_INIT(rc.h) RELDATE=`cat $srcdir/RELDATE` -AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE") +AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE", [Release date]) dnl Automake stuff. dnl Use this one for snapshots... -dnl AM_INIT_AUTOMAKE(rc, 1.6s`echo $RELDATE |sed 's/-//g'`) +dnl AM_INIT_AUTOMAKE(rc, 1.7s`echo $RELDATE |sed 's/-//g'`) dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.7) +AM_INIT_AUTOMAKE(rc, 1.7.1) AM_CONFIG_HEADER(config.h) @@ -40,7 +40,16 @@ AC_TYPE_SIZE_T AC_TYPE_UID_T AC_CHECK_TYPE(ssize_t, long) -AC_CHECK_FUNCS(getgroups setpgrp setrlimit) +AC_CHECK_FUNCS(getgroups lstat setpgrp setrlimit sigaction) + +dnl We prefer system calls that don't restart. If we have sigaction() +dnl we'll use it. Otherwise, we check whether good ol' signal() +dnl produces interruptible system calls. +case "$ac_cv_func_sigaction" in +no) AC_SYS_RESTARTABLE_SYSCALLS ;; +esac +AM_CONDITIONAL(AMC_RESTART, test "$ac_cv_sys_restartable_syscalls" = yes) + RC_FUNC_GETGROUPS RC_FUNC_SIGSETJMP @@ -55,22 +64,12 @@ RC_TYPE_RLIM_T RC_TYPE_SIG_ATOMIC_T -dnl We prefer system calls that don't restart. If we have sigaction() -dnl and SA_INTERRUPT, we'll use 'em. Otherwise, we check whether good -dnl ol' signal() produces interruptible system calls. -RC_FUNC_SIGACTION -case "$rc_cv_sa_int" in -yes) AC_DEFINE(HAVE_SA_INTERRUPT) ;; -no) AC_SYS_RESTARTABLE_SYSCALLS ;; -esac -AM_CONDITIONAL(AMC_RESTART, test "$ac_cv_sys_restartable_syscalls" = yes) - RC_SYS_V_SIGCLD dnl Does the kernel handle `#! /interpreter'? AC_SYS_INTERPRETER case "$ac_cv_sys_interpreter" in -yes) AC_DEFINE(HASH_BANG) ;; +yes) AC_DEFINE(HASH_BANG, 1, [Define to 1 if your kernel understands `#!' magic numbers]) ;; esac AM_CONDITIONAL(AMC_NO_HASHBANG, test "$ac_cv_sys_interpreter" = no) @@ -80,27 +79,27 @@ dnl /proc/self/fd. Failing that, we'll try for POSIX mkfifo(), or a dnl mknod() that makes FIFOs. RC_SYS_DEV_FD case "$rc_cv_sys_dev_fd" in -yes) AC_DEFINE(HAVE_DEV_FD) ;; -odd) AC_DEFINE(HAVE_PROC_SELF_FD) ;; +yes) AC_DEFINE(HAVE_DEV_FD, 1, [Define to 1 if you have /dev/fd.]) ;; +odd) AC_DEFINE(HAVE_PROC_SELF_FD, 1, [Define to 1 if you have /proc/self/fd.]) ;; no) AC_CHECK_FUNCS(mkfifo) ;; esac case "$ac_cv_func_mkfifo" in -yes) AC_DEFINE(HAVE_FIFO) ;; +yes) AC_DEFINE(HAVE_FIFO, 1, [Define to 1 if you have the `mkfifo' function.]) ;; no) RC_SYS_MKNOD_FIFO ;; esac dnl Now handle arguments. AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], - test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO), + test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO, 1, [Define to 1 to include `echo' as a builtin.]), AC_DEFINE(RC_ECHO)) AC_ARG_ENABLE(job, [ --disable-job Don't do job-control-style backgrounding], - test "x$enableval" != "xno" && AC_DEFINE(RC_JOB), + test "x$enableval" != "xno" && AC_DEFINE(RC_JOB, 1, [Define to 1 to use job-control-style backgrounding.]), AC_DEFINE(RC_JOB)) AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment names], - test "x$enableval" != "xno" && AC_DEFINE(PROTECT_ENV), + test "x$enableval" != "xno" && AC_DEFINE(PROTECT_ENV, 1, [Define to 1 to encode exported environment names.]), AC_DEFINE(PROTECT_ENV)) AC_ARG_ENABLE(def-interp, @@ -111,7 +110,7 @@ AC_ARG_ENABLE(def-interp, no) ;; yes) - AC_DEFINE(DEFAULTINTERP, "/bin/sh") + AC_DEFINE(DEFAULTINTERP, "/bin/sh", [The default interpreter]) ;; *) AC_DEFINE_UNQUOTED(DEFAULTINTERP, "$enableval") @@ -126,7 +125,7 @@ AC_ARG_ENABLE(def-path, [ case "$enableval" in no|yes) ;; - *) AC_DEFINE_UNQUOTED(DEFAULTPATH, $enableval) ;; + *) AC_DEFINE_UNQUOTED(DEFAULTPATH, $enableval, [The default path]) ;; esac ], enable_def_path=yes) @@ -166,14 +165,14 @@ AC_ARG_WITH(addon, [ --with-addon[=foo.c] Extra builtins, from addon.c by de ]) AM_CONDITIONAL(AMC_ADDON, test "$ADDON" != "") case "$ADDON" in -?*) AC_DEFINE(RC_ADDON) ;; +?*) AC_DEFINE(RC_ADDON, 1, [Define to 1 to use addon functions.]) ;; esac AC_SUBST(ADDON) AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], AC_CHECK_LIB(edit, readline, - AC_DEFINE(EDITLINE) LIBS="$LIBS -ledit", + AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit", AC_MSG_ERROR(editline library not found))) if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then @@ -189,9 +188,9 @@ dnl There are (at least) two incompatible versions of readline, and we dnl need to know which one we are using. We don't support readline 2.0. AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ AC_CHECK_LIB(readline, readline, [ - AC_DEFINE(READLINE) + AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.]) LIBS="$LIBS -lreadline $rc_lib_tgetent" - AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD), $rc_lib_tgetent) + AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent) ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) ]) AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) diff --git a/glob.c b/glob.c index ac26203..b472af9 100644 --- a/glob.c +++ b/glob.c @@ -1,7 +1,7 @@ /* glob.c: rc's (ugly) globber. This code is not elegant, but it works */ #include "rc.h" -#include +#include "stat.h" /* Lifted from autoconf documentation.*/ #if HAVE_DIRENT_H @@ -86,7 +86,7 @@ extern List *glob(List *s) { /* Matches a pattern p against the contents of directory d */ static List *dmatch(char *d, char *p, char *m) { - bool matched = FALSE; + bool matched; List *top, *r; static DIR *dirp; static struct dirent *dp; @@ -107,7 +107,7 @@ static List *dmatch(char *d, char *p, char *m) { if (matched) { char *path = nprint("%s/%s", d, p); - if (stat(path, &s) < 0) + if (lstat(path, &s) < 0) return NULL; r = nnew(List); r->w = ncpy(p); diff --git a/history.c b/history.c index 2993a69..1f22f2e 100644 --- a/history.c +++ b/history.c @@ -78,6 +78,8 @@ static char *sub(char *s, char *old, char *new) { char *t, *u; t = isin(s, old); + if (!t) + return s; u = newstr(); *t = '\0'; @@ -206,9 +208,9 @@ static char *readhistoryfile(char **last) { exit(1); } - size = 0; - count = 0; - buf = ealloc(size = CHUNKSIZE); + size = CHUNKSIZE; + buf = ealloc(size); + buf[0] = '\0'; count = 1; /* sentinel */ while ((nread = fread(buf + count, sizeof (char), size - count, histfile)) > 0) { count += nread; if (size - count == 0) @@ -222,32 +224,30 @@ static char *readhistoryfile(char **last) { return buf; } -static char *getcommand() { +static char *getcommand(void) { char *s, *t; static char *hist = NULL, *last; if (hist == NULL) { hist = readhistoryfile(&last); - *--last = '\0'; /* trim final newline */ + *--last = '\0'; /* replaces final newline */ + ++hist; /* start beyond sentinel */ } again: s = last; if (s < hist) return NULL; - while (*--s != '\n') - if (s <= hist) { - last = hist - 1; - return hist; - } + while (s >= hist && *s != '\n') + --s; *s = '\0'; last = s++; /* * if the command contains the "me" character at the start of the line - * or after any of [`{|()@] then try again + * or after any of [`{|()@/] then try again */ - for (t = s; *t != '\0'; t++) + for (t = s; *t != '\0'; ++t) if (*t == me) { char *u = t - 1; while (u >= s && (*u == ' ' || *u == '\t')) diff --git a/input.c b/input.c index 1c47aee..c5ac5fc 100644 --- a/input.c +++ b/input.c @@ -96,8 +96,10 @@ static int fdgchar() { while (1) { #if EDITLINE || READLINE if (interactive && istack->t == iFd && isatty(istack->fd)) { - /* The readline library doesn't handle read() returning EAGAIN. */ + /* The readline library doesn't handle + * read() returning EAGAIN or EIO. */ makeblocking(istack->fd); + makesamepgrp(istack->fd); rlinebuf = rc_readline(prompt); if (rlinebuf == NULL) { chars_in = 0; diff --git a/nalloc.c b/nalloc.c index eb621e0..0144b48 100644 --- a/nalloc.c +++ b/nalloc.c @@ -112,8 +112,10 @@ extern void restoreblock(Block *old) { /* generic memory allocation functions */ extern void *ealloc(size_t n) { - void *p = malloc(n); + void *p; + assert(n); + p = malloc(n); if (p == NULL) { uerror("malloc"); rc_exit(1); diff --git a/rc.1 b/rc.1 index 19d4a8c..b0e920c 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2002-06-18" +.TH RC 1 "2003-07-17" .SH NAME rc \- shell .SH SYNOPSIS @@ -1435,9 +1435,11 @@ On startup, the first element of this list variable is initialized to a string which identifies this version of .IR rc . The second element is initialized to a string which can be found by -.B ident -and -.BR "sccs what" . +.IR ident (1) +and the +.I what +command of +.IR sccs (1). .SH FUNCTIONS .I rc functions are identical to @@ -1595,9 +1597,10 @@ For example: .TP \& is a reasonable way to pass a default set of arguments to -.Cr ls (1). +.Cr ls (1), +whereas .Ds -.Cr "fn ls { ls -FC $* }" +.Cr "fn ls { ls -FC $* } # WRONG" .De .TP \& @@ -2120,12 +2123,12 @@ builtin, the .Cr bqstatus and -.Cr rc_version +.Cr version variables, the support for the GNU .IR readline (3) -library and -the support for the +library, +and the support for the .Cr prompt function. This diff --git a/rc.h b/rc.h index 24a334b..a0ef908 100644 --- a/rc.h +++ b/rc.h @@ -1,4 +1,4 @@ -#define NDEBUG 1 +#undef NDEBUG #include "config.h" #include "proto.h" diff --git a/signal.c b/signal.c index de06633..b5cbe63 100644 --- a/signal.c +++ b/signal.c @@ -8,17 +8,18 @@ #include "sigmsgs.h" #include "jbwrap.h" -#if HAVE_SA_INTERRUPT +#if HAVE_SIGACTION static void (*sys_signal(int signum, void (*handler)(int)))(int) { struct sigaction new, old; new.sa_handler = handler; - new.sa_flags = SA_INTERRUPT; + new.sa_flags = 0; /* clear SA_RESTART */ + sigfillset(&new.sa_mask); sigaction(signum, &new, &old); return old.sa_handler; } #else -#define sys_signal signal +#define sys_signal(sig, func) (signal((sig), (func))) #endif void (*sighandlers[NUMOFSIGNALS])(int); @@ -40,7 +41,7 @@ extern void catcher(int s) { #if HAVE_RESTARTABLE_SYSCALLS if (slow) { siglongjmp(slowbuf.j, s); -} + } #endif } @@ -96,6 +97,12 @@ extern void initsignal() { #endif for (i = 1; i < NUMOFSIGNALS; i++) { +#ifdef SIGKILL + if (i == SIGKILL) continue; +#endif +#ifdef SIGSTOP + if (i == SIGSTOP) continue; +#endif h = sys_signal(i, SIG_IGN); if (h != SIG_IGN && h != SIG_ERR) sys_signal(i, h); diff --git a/stat.h b/stat.h new file mode 100644 index 0000000..5f87a69 --- /dev/null +++ b/stat.h @@ -0,0 +1,6 @@ +#include + +#if HAVE_LSTAT +#else +#define lstat(name, buf) (stat((name), (buf))) +#endif diff --git a/trip.rc b/trip.rc index 8eb4c09..734429c 100644 --- a/trip.rc +++ b/trip.rc @@ -587,14 +587,10 @@ fn x {echo x.y $(x.y)} ~ ``''{whatis -f x} 'fn x {echo x.y $''x.y''} ' || fail sneaky parens bug -# large file support - -# this is, by no means, an exhaustive test. since particular file -# systems do, or do not, support large files, we try it both in the -# build directory and /tmp. - -if (./tripping l > big.$pid >[2] /dev/null || - ./tripping l > /tmp/big.$pid >[2] /dev/null) { - echo large file support seems to work -} else echo large file support seems NOT to work - see INSTALL file -rm -f big.$pid /tmp/big.$pid +# before rc-1.7.1, certain glob patterns could fail on broken symlinks +mkdir $tmp.qux +ln -s /frobnatz $tmp.qux/foo +x=$tmp.qux/foo* +~ $x $tmp.qux/foo || { rm -rf $tmp.qux; fail broken symlink globbing } +x=$tmp.qux*/foo +~ $x $tmp.qux/foo || { rm -rf $tmp.qux; fail broken symlink globbing } diff --git a/tripping.c b/tripping.c index a9099ce..23b2972 100644 --- a/tripping.c +++ b/tripping.c @@ -19,21 +19,6 @@ static void ctrl_a(void) { puts("a\001ab\002b"); } -static void large(void) { - char c = 'c'; - -#define LARGE (((off_t)1<<33)+1) - - if (lseek(1, LARGE, SEEK_SET) != LARGE) { - perror("lseek"); - exit(1); - } - if (write(1, &c, 1) == -1) { - perror("write"); - exit(1); - } -} - static void makenonblock(void) { int flags; @@ -52,9 +37,6 @@ int main(int argc, char **argv) { case 'a': ctrl_a(); break; - case 'l': - large(); - break; case 'n': makenonblock(); break; diff --git a/var.c b/var.c index 83c5ff9..ee8c228 100644 --- a/var.c +++ b/var.c @@ -48,6 +48,7 @@ extern bool varassign_string(char *extdef) { strcpy(new->extdef, extdef); if (i != -1) alias(name, varlookup(name), FALSE); + set_exportable(name, TRUE); return TRUE; } diff --git a/which.c b/which.c index 9a6e1bb..8abdc60 100644 --- a/which.c +++ b/which.c @@ -37,6 +37,8 @@ static int ingidset(gid_t g) { return 1; return 0; } +#else +#define ingidset(g) (FALSE) #endif /* @@ -56,11 +58,7 @@ static bool rc_access(char *path, bool verbose) { mask = X_ALL; else if (uid == st.st_uid) mask = X_USR; -#if HAVE_GETGROUPS else if (gid == st.st_gid || ingidset(st.st_gid)) -#else - else if (gid == st.st_gid) -#endif mask = X_GRP; else mask = X_OTH; @@ -93,10 +91,12 @@ extern char *which(char *name, bool verbose) { rc_exit(1); } #else - ngroups = NGROUPS; + ngroups = NGROUPS; #endif - gidset = ealloc(ngroups * sizeof(GETGROUPS_T)); - getgroups(ngroups, gidset); + if (ngroups) { + gidset = ealloc(ngroups * sizeof(GETGROUPS_T)); + getgroups(ngroups, gidset); + } #endif } if (isabsolute(name)) /* absolute pathname? */ -- cgit v1.2.3 From a8699a58d8632f21e897ea5c4900a15483a9a8ca Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Tue, 2 Sep 2014 08:01:39 +0100 Subject: release: rc-1.7.2 --- .gitignore | 14 + AUTHORS | 29 +- ChangeLog | 24 ++ INSTALL | 528 +++++++++++++++++--------- Makefile.am | 14 +- NEWS | 33 +- README | 8 +- RELDATE | 1 + ReleaseTime | 7 + acinclude.m4 | 20 +- aclocal.m4 | 1069 +++++++++++++++++++++++++++++++++++++++++++++++++++++ bootstrap | 2 + builtins.c | 16 +- chldign | Bin 0 -> 4115 bytes chldign.c | 9 + configure.ac | 102 ++++-- configure.scan | 49 +++ edit-bsd.c | 91 +++++ edit-gnu.c | 87 +++++ edit-null.c | 35 ++ edit.h | 12 + except.c | 1 + fn.c | 1 + footobar.c | 5 +- glob.c | 2 +- hash.c | 11 - heredoc.c | 6 +- input.c | 328 ++++++++--------- input.h | 35 ++ lex.c | 40 +- main.c | 32 +- mkinstalldirs | 162 ++++++++ nonblock.c | 14 + parse.c | 1117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ parse.h | 37 ++ random.pl | 15 + rc.1 | 13 +- rc.h | 61 +--- rc.spec | 31 ++ signal.c | 19 +- slow | 11 + stamp-h | 1 + stamp-h.in | 1 + testcld.c | 19 + tmp | 2 + tree.c | 3 +- trip.rc | 141 +++---- utils.c | 8 +- var.c | 8 +- which.c | 23 +- 50 files changed, 3677 insertions(+), 620 deletions(-) create mode 100644 RELDATE create mode 100755 ReleaseTime create mode 100644 aclocal.m4 create mode 100644 bootstrap create mode 100755 chldign create mode 100644 chldign.c create mode 100644 configure.scan create mode 100644 edit-bsd.c create mode 100644 edit-gnu.c create mode 100644 edit-null.c create mode 100644 edit.h create mode 100644 input.h create mode 100755 mkinstalldirs create mode 100644 nonblock.c create mode 100644 parse.c create mode 100644 parse.h create mode 100644 random.pl create mode 100644 rc.spec create mode 100644 slow create mode 100644 stamp-h create mode 100644 stamp-h.in create mode 100644 testcld.c create mode 100644 tmp diff --git a/.gitignore b/.gitignore index e69de29..ad32267 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,14 @@ +*~ +.deps/ +Makefile +autom4te.cache/ +config.h +config.log +config.status +configure +depcomp +missing +sigmsgs.c +sigmsgs.h +stamp-h1 +statval.h diff --git a/AUTHORS b/AUTHORS index 2c7833d..3414e61 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -The current maintainer of rc is Tim Goodwin . Please +The current maintainer of rc is Toby Goodwin . Please send all bug reports to him. This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr @@ -7,8 +7,8 @@ bits and pieces to rc (notably the limits code, print.c, most of which.c and the backquote redirection code), and to Hugh Redelmeier for running rc through his fussy ANSI compiler and thereby provoking interesting discussions about portability, and also for providing many valuable -suggestions for improving rc's code in general. Finally, many thanks -go to David Sanderson, for reworking the man page to format well with +suggestions for improving rc's code in general. Finally, many thanks go +to David Sanderson, for reworking the man page to format well with troff, and for providing many suggestions both for rc and its man page. Thanks to Boyd Roberts for the original history.c, and to Hugh again for @@ -16,22 +16,23 @@ re-working parts of that code. Of course, without Tom Duff's design of the original rc, I could not have written this shell (though I probably would have written *a* -shell). Almost all of the features, with minor exceptions, have been -implemented as described in the Unix v10 manuals. Hats off to td for +shell). Almost all of the features, with minor exceptions, have been +implemented as described in the Unix v10 manuals. Hats off to td for designing a C-like, minimal but very useful shell. Tom Duff has kindly given permission for the paper he wrote for UKUUG to be distributed with this version of rc (called "plan9.ps" in the same -FTP or HTTP directory as the shell). Please read this paper bearing in +FTP or HTTP directory as the shell). Please read this paper bearing in mind that it describes a program that was written at AT&T and that the version of rc presented here differs in some respects. -Tim would like to thank these people for their contributions since he -took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt +Toby would like to thank these people for their contributions since he +took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, Chris -Siebenmann, Dale Scheetz, Dan Moniz, David Luyer, David Swasey, -Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell, Gerry -Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc -Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond Venneker, Rich -$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve Simon, Thomas -Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang Zekoll. +Siebenmann, Christian Neukirchen, Dale Scheetz, Dan Moniz, David Luyer, +David Swasey, Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell, +Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jakub Wilk, Jeremy +Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond +Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve +Simon, Thomas Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang +Zekoll. diff --git a/ChangeLog b/ChangeLog index 9fc918b..466b825 100644 --- a/ChangeLog +++ b/ChangeLog @@ -830,3 +830,27 @@ Changes since rc-1.5b2 2003-07-22 Release: rc-1.7.1. + +2003-09-24 + + Tidiness: minor improvements to input.c. + +2014-02-26 + + Bug: fix for CVE-2014-1936 from Jakub Wilk. + +2014-06-29 + + Documentation: update email and web addresses. + +2014-08-31 + + Feature: support quoting for filename completion in GNU readline. + +2014-09-01 + + Bug: quoting of glob characters was broken (thanks Christian + Neukirchen); fix the "sneaky parens" bug properly (thanks Wolfgang + Zekoll). + + Feature: allow $"x as a synonym for $^x diff --git a/INSTALL b/INSTALL index 6174223..007e939 100644 --- a/INSTALL +++ b/INSTALL @@ -1,182 +1,370 @@ -COMPILING +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use 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 `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ -rc uses GNU autoconf and automake. The following commands are all you -need to configure, build, test, and install rc. + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. - $ sh configure - $ make - $ make trip - # make install +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: -This will build rc in the source directory (see below for details on how -to build rc in a different directory). + ./configure CC=/usr/local2/bin/gcc +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). -BUILD AND CONFIGURATION OPTIONS +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: -There are lots of options you can give to configure to modify rc's -behaviour. You can also select a command line history library to link -against---see the rc web page for details of where to find these -libraries. For a summary of all options, run `sh configure --help'. + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash -You can specify Makefile variables by setting the corresponding -environment variables. For example, you might want to set `CC=cc', to -prevent configure looking for gcc, or set an initial value for -`LDFLAGS', as in the example below. It is a good idea to specify -static linking (unless you are linking against a dynamic readline -library)---if you are using gcc, you can do this by setting -`CFLAGS=-static'. +`configure' Invocation +====================== -Here are the configure options you may want to use, in approximately -descending order of usefulness. + `configure' recognizes the following options to control how it +operates. - --with-editline +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. - This option tells rc to use the editline package (see the web page - for details) to provide EMACS style command line editing and - history. If the editline library is not installed in a standard - place, you can tell configure where to find it by setting the - environment variable LDFLAGS. For example, you might copy libedit.a - into the rc source directory and then run this configure command. +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. - LDFLAGS=-L. sh configure --with-editline +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. - --with-vrl - - This option tells rc to use the vrl package (see the web page for - details) to provide EMACS style command line editing and history. As - for `--with-editline', you may need to set the environment variable - LDFLAGS appropriately. - - --with-readline - - This option tells rc to use the GNU readline package, which is similar - to editline or vrl, but has many more features. The readline package - is over 6 times the size of editline (whether you count lines of code, - or the library itself). As for editline, you can set the environment - variable LDFLAGS if your readline library is not installed in a - standard place. - - LDFLAGS=-L/usr/gnu/lib sh configure --with-readline - - --with-history - - Use this option if you want to build and install the programs that - support a crude command-line history mechanism. - -You can't use more than one of `--with-editline', `--with-vrl', and -`--with-readline' at the same time. If you have any of these you -probably don't want to bother with `--with-history'. - - --prefix=/path - - By default, `prefix' is /usr/local, which means that `make install' - installs rc (and possibly the history programs) in /usr/local/bin, and - man pages in /usr/local/man/man1. Use this option to change where - `make install' puts things. - - --disable-builtin-echo - - By default, the `echo' command is builtin to rc for reasons of - efficiency and portability (of rc scripts). It is the only builtin - which is not essential, and purists may wish to omit it. Note that - `make trip' will fail if you disable builtin echo and your system's - `echo' does not understand `-n' to suppress newline. - - --with-addon - --with-addon=foo.c - - On the other hand, non-purists may wish to add extra builtin commands. - An example is included in the files addon.c and addon.h, which will - only be built if you specify `--with-addon'. If your addons are - in another file, you can specify that instead (but beware that the - interface file is still addon.h). - - --disable-def-interp - --enable-def-interp=/bin/foo - - By default, a program that fails with ENOEXEC (Exec format error) is - handed to /bin/sh. This does the Right Thing for scripts that start - with `:' to indicate that they are sh scripts. You can disable this - behaviour entirely, or specify a different default interpreter. - - --disable-def-path - --enable-def-path "/usr/local/bin","/usr/bin" - - By default, if rc is started with no PATH, it uses a default path. - The default path is constructed at configure time, and consists - of each of the following directories that exist, in order. - - /usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin . - - You can disable this, or specify a different default path. Note that - the quote marks (") must be seen by configure; unless you are already - using rc, you will probably need to quote them to your shell. - - --disable-job - - By default, rc puts backgrounded processes into a new process group, - as though it were a job control shell (it isn't). This is usually - needed to work around bugs in application programs which install - signal handlers for the keyboard signals without checking whether the - signal was being ignored. This option disables the default behaviour, - making rc behave like a traditional sh. You are unlikely to want this - option on any Unix system. - - --disable-protect-env - - By default, rc encodes special characters in environment variables. - This is necessary on all known Unix systems to prevent sh either - dying or discarding the variables. This option disables the default - behaviour. You are unlikely to want this option on any Unix system. - -After you've built rc, I recommend that you run it through the test -script to gain some confidence that all is working well. Type `make -trip' to do this. This will produce some output, and should end with -"trip is complete". If the trip instead ends with "trip took a wrong -turn..." please contact the maintainer. - -In this release, `make trip' will fail on a file system which does not -implement Unix semantics (specifically permissions bits). This means -that `make trip' is not useful under CygWin, for instance. - - -BUILDING IN ANOTHER DIRECTORY - -If you have a suitable `make', you can build rc in a different directory -from where the sources are held. This is particularly useful if you -are building rc for multiple architectures. All you need do is specify -the path to the configure script in the first step. Suitable `make's -include GNU, HP-UX, and SunOS, but not Irix, nor Ultrix, nor UnixWare. - - -COMPILATION WARNINGS - -If your C compiler is gcc, the option `-Wall' is turned on. This may -produce a few warnings. - -Warnings about "implicit declaration" of system functions may occur if -your system's include files are deficient---they are usually harmless. - -Some older versions of gcc warn about "variable `n' might be -clobbered" in walk.c. As far as I can tell, this is gcc telling you -that it might not be compiling the code correctly! I don't know how -to eliminate the warning, but it doesn't appear to cause any problems -in practice. - -On some systems there are warnings about "passing arg 2 of `getgroups' -from incompatible pointer type" in which.c. I believe this is due to an -incorrect declaration of `getgroups()' in those systems' header files. - -The warning "left shift count >= width of type" in tripping.c may -occur if off_t is only 32 bits. - -Any other warnings should be reported to the maintainer. - - -OLD C - -rc needs an ISO C (89) compiler, or at least one that has a reasonable -understanding of function prototypes, `', `void', and -`volatile'. If you really need to compile rc with an ancient C -compiler, please contact the maintainer. +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/Makefile.am b/Makefile.am index ee3829c..e739725 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,7 @@ ## Process this file with automake to produce Makefile.in +EDIT=@EDIT@ + if AMC_HISTORY man_MANS = rc.1 history.1 HISTORY = history @@ -11,10 +13,6 @@ if AMC_NO_HASHBANG EXECVE = execve.o endif -if AMC_READLINE -READLINE = readline.o -endif - if AMC_RESTART SYSTEM = system-bsd.o else @@ -26,12 +24,12 @@ noinst_PROGRAMS = mksignal mkstatval tripping $(HISTORY) rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c hash.c heredoc.c input.c lex.c list.c main.c match.c nalloc.c open.c parse.c print.c redir.c signal.c status.c tree.c utils.c var.c wait.c walk.c which.c -EXTRA_rc_SOURCES = addon.c execve.c readline.c system.c system-bsd.c +EXTRA_rc_SOURCES = addon.c edit-bsd.c edit-gnu.c edit-null.c execve.c system.c system-bsd.c -rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) -rc_LDADD = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) +rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM) +rc_LDADD = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM) -noinst_HEADERS = getgroups.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h +noinst_HEADERS = edit.h getgroups.h input.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h BUILT_SOURCES = sigmsgs.c diff --git a/NEWS b/NEWS index 39126a8..4bf4fe1 100644 --- a/NEWS +++ b/NEWS @@ -1,20 +1,23 @@ -Highlights of changes since rc-1.7. See ChangeLog for further details. +Highlights of changes since rc-1.7. See ChangeLog for further details. -Portability. A fix to the autoconfiguration means that the nasty -longjmp() code is now omitted for all modern Unix systems; previously -rc only did the Right Thing on Linux. The test for large files in -trip.rc was removed, as this causes indigestion on file systems that -don't support sparse files (the configuration and implementation of -large file support is still present of course). +Portability. A fix to the autoconfiguration means that the nasty +longjmp() code is now omitted for all modern Unix systems; previously rc +only did the Right Thing on Linux. The test for large files in trip.rc +was removed, as this causes indigestion on file systems that don't +support sparse files (the configuration and implementation of large file +support is still present of course). -Bug fixes. Broken symlinks now glob correctly. The variables $prompt -and $version are now exported if they are inherited from the -environment when rc starts. EIO handling is now enabled for readline -too. A few bogosities in the history program were fixed. +Bug fixes. Fix for CVE-2014-1936. Broken symlinks now glob correctly. +The variables $prompt and $version are now exported if they are +inherited from the environment when rc starts. EIO handling is now +enabled for readline too. A few bogosities in the history program were +fixed. A regression introduced by the fix for the $(a.b) quoting bug was +fixed, and that bug was correctly fixed. -New features. None - this is a bugfix release. +New features. Filename completion with GNU readline now quotes special +characters. -Documentation. Minor updates only. +Documentation. Minor updates only. -Tim Goodwin -2003-07-17 +Toby Goodwin +2014-09-01 diff --git a/README b/README index 7a8e84f..f952ba2 100644 --- a/README +++ b/README @@ -1,15 +1,15 @@ -This is release rc-1.7.1. +This is release rc-1.7.2. See COPYING for copying information. All files are - Copyright 1991, 2001, 2002, 2003 Byron Rakitzis. + Copyright 1991, 2001, 2002, 2003, 2014 Byron Rakitzis. See INSTALL for build and installation information. BUGS -Send bug reports to . If a core dump is generated, +Send bug reports to . If a core dump is generated, sending a backtrace will help a great deal. You can get a backtrace like this. @@ -35,4 +35,4 @@ WWW More information on releases of rc can be found at this web page. - http://www.star.le.ac.uk/~tjg/rc/ + http://tobold.org/article/rc diff --git a/RELDATE b/RELDATE new file mode 100644 index 0000000..b16a0df --- /dev/null +++ b/RELDATE @@ -0,0 +1 @@ +2014-09-01 diff --git a/ReleaseTime b/ReleaseTime new file mode 100755 index 0000000..dfa9ea0 --- /dev/null +++ b/ReleaseTime @@ -0,0 +1,7 @@ +#! /usr/bin/sed 1d +ChangeLog +NEWS +README +RELDATE +configure.ac +rc.1 diff --git a/acinclude.m4 b/acinclude.m4 index e1cd78c..96ec096 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1,6 +1,6 @@ dnl This macro sets HAVE_POSIX_GETGROUPS if the dnl getgroups() function accepts a zero first argument. -AC_DEFUN(RC_FUNC_GETGROUPS, [ +AC_DEFUN([RC_FUNC_GETGROUPS], [ AC_CACHE_CHECK(for POSIX getgroups, rc_cv_func_posix_getgroups, AC_TRY_RUN([ #include #include @@ -16,7 +16,7 @@ int main(void) { dnl We can't use AC_CHECK_FUNCS for sigsetjmp(), since it's a macro in dnl some places. -AC_DEFUN(RC_FUNC_SIGSETJMP, [ +AC_DEFUN([RC_FUNC_SIGSETJMP], [ AC_CACHE_CHECK(for sigsetjmp, rc_cv_sigsetjmp, AC_TRY_LINK([ #include @@ -30,7 +30,7 @@ sigsetjmp(e, 1); ]) dnl Similarly, AC_CHECK_FUNCS doesn't find strerror() on NetBSD. -AC_DEFUN(RC_FUNC_STRERROR, [ +AC_DEFUN([RC_FUNC_STRERROR], [ AC_CACHE_CHECK(for strerror, rc_cv_strerror, AC_TRY_LINK([ #include @@ -43,7 +43,7 @@ strerror(0); ]) dnl HPUX needs _KERNEL defined to pick up RLIMIT_foo defines. (Why?) -AC_DEFUN(RC_NEED_KERNEL, [ +AC_DEFUN([RC_NEED_KERNEL], [ AC_CACHE_CHECK(if _KERNEL is required for RLIMIT defines, rc_cv_kernel_rlimit, AC_TRY_COMPILE([ #include @@ -66,7 +66,7 @@ f = RLIMIT_DATA; ]) dnl Look for rlim_t in sys/types.h and sys/resource.h -AC_DEFUN(RC_TYPE_RLIM_T, [ +AC_DEFUN([RC_TYPE_RLIM_T], [ AC_CACHE_CHECK(for rlim_t, rc_cv_have_rlim_t, AC_EGREP_CPP(rlim_t, [ #include @@ -118,7 +118,7 @@ main(){ dnl Check type of sig_atomic_t. -AC_DEFUN(RC_TYPE_SIG_ATOMIC_T, [ +AC_DEFUN([RC_TYPE_SIG_ATOMIC_T], [ AC_CACHE_CHECK(for sig_atomic_t, rc_cv_sig_atomic_t, AC_EGREP_HEADER(sig_atomic_t, signal.h, rc_cv_sig_atomic_t=yes, rc_cv_sig_atomic_t=no)) @@ -135,7 +135,7 @@ dnl semantics, but if the parent calls wait() before the child calls dnl exit(), wait() returns with the PID of the child as normal. (Real dnl SysV waits for all children to exit, then returns with ECHILD.) dnl Anyway, this is why the `sleep(1)' is there. -AC_DEFUN(RC_SYS_V_SIGCLD, [ +AC_DEFUN([RC_SYS_V_SIGCLD], [ AC_CACHE_CHECK(for SysV SIGCLD semantics, rc_cv_sysv_sigcld, AC_TRY_RUN([ #include @@ -165,7 +165,7 @@ int main(void) { dnl Do we have /dev/fd or /proc/self/fd? -AC_DEFUN(RC_SYS_DEV_FD, [ +AC_DEFUN([RC_SYS_DEV_FD], [ AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd, if test -d /dev/fd && test -r /dev/fd/0; then rc_cv_sys_dev_fd=yes @@ -179,7 +179,7 @@ AC_DEFUN(RC_SYS_DEV_FD, [ dnl Can mknod make FIFOs? -AC_DEFUN(RC_SYS_MKNOD_FIFO, [ +AC_DEFUN([RC_SYS_MKNOD_FIFO], [ AC_CACHE_CHECK(for mknod FIFOs, rc_cv_sys_fifo, AC_TRY_RUN([ #include @@ -196,7 +196,7 @@ main() { ]) dnl Where is tgetent()? -AC_DEFUN(RC_LIB_TGETENT, [ +AC_DEFUN([RC_LIB_TGETENT], [ AC_CHECK_LIB(termcap, tgetent, rc_lib_tgetent=-ltermcap, AC_CHECK_LIB(ncurses, tgetent, diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..145230d --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1069 @@ +# generated automatically by aclocal 1.13.4 -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.13' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.13.4], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.13.4])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# -*- Autoconf -*- +# Obsolete and "removed" macros, that must however still report explicit +# error messages when used, to smooth transition. +# +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +AC_DEFUN([AM_CONFIG_HEADER], +[AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl +AC_CONFIG_HEADERS($@)]) + +AC_DEFUN([AM_PROG_CC_STDC], +[AC_PROG_CC +am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc +AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should simply use the 'AC][_PROG_CC' macro instead. +Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', +but upon 'ac_cv_prog_cc_stdc'.])]) + +AC_DEFUN([AM_C_PROTOTYPES], + [AC_FATAL([automatic de-ANSI-fication support has been removed])]) +AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/bootstrap b/bootstrap new file mode 100644 index 0000000..b499423 --- /dev/null +++ b/bootstrap @@ -0,0 +1,2 @@ +#! /bin/sh +autoreconf --force --install diff --git a/builtins.c b/builtins.c index ea708b6..75ac9cf 100644 --- a/builtins.c +++ b/builtins.c @@ -15,6 +15,7 @@ #include #include "addon.h" +#include "input.h" #include "jbwrap.h" #include "rlimit.h" #include "sigmsgs.h" @@ -87,12 +88,12 @@ extern void funcall(char **av) { } static void arg_count(char *name) { - fprint(2, "too many arguments to %s\n", name); + fprint(2, RC "too many arguments to %s\n", name); set(FALSE); } static void badnum(char *num) { - fprint(2, "%s is a bad number\n", num); + fprint(2, RC "`%s' is a bad number\n", num); set(FALSE); } @@ -389,18 +390,13 @@ extern void b_dot(char **av) { return; fd = rc_open(*av, rFrom); if (fd < 0) { - if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */ - rcrc = FALSE; - else { - uerror(*av); - set(FALSE); - } + uerror(*av); + set(FALSE); return; } - rcrc = FALSE; starassign(*av, av+1, TRUE); - pushfd(fd); interactive = i; + pushfd(fd); star.name = "*"; except(eVarstack, star, &e); doit(TRUE); diff --git a/chldign b/chldign new file mode 100755 index 0000000..7b3b157 Binary files /dev/null and b/chldign differ diff --git a/chldign.c b/chldign.c new file mode 100644 index 0000000..e4e64a6 --- /dev/null +++ b/chldign.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main(int argc, char **argv) { + int i; + signal(SIGCHLD, SIG_IGN); + execvp(argv[1], &argv[1]); +} diff --git a/configure.ac b/configure.ac index a2f2043..d12714a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,14 +1,13 @@ -dnl Get things going... -AC_INIT(rc.h) +dnl Our package name, version, ... +AC_INIT([rc], [1.7.2]) -RELDATE=`cat $srcdir/RELDATE` +dnl ... and release date +RELDATE=`date -I` AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE", [Release date]) -dnl Automake stuff. -dnl Use this one for snapshots... -dnl AM_INIT_AUTOMAKE(rc, 1.7s`echo $RELDATE |sed 's/-//g'`) -dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.7.1) +dnl Get things going... +AC_CONFIG_SRCDIR([rc.h]) +AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -90,7 +89,7 @@ no) RC_SYS_MKNOD_FIFO ;; esac dnl Now handle arguments. -AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], +AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include `echo' as a builtin], test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO, 1, [Define to 1 to include `echo' as a builtin.]), AC_DEFINE(RC_ECHO)) @@ -104,7 +103,7 @@ AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment AC_ARG_ENABLE(def-interp, [ --enable-def-interp=/bin/foo - Use /bin/foo as default interpreter [/bin/sh]], + Use /bin/foo as default interpreter [[/bin/sh]]], [ case "$enableval" in no) @@ -120,8 +119,8 @@ AC_ARG_ENABLE(def-interp, AC_ARG_ENABLE(def-path, [ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" - Default path [All of these that exist - (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]], + Default path [[All of these that exist + (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]]], [ case "$enableval" in no|yes) ;; @@ -156,7 +155,7 @@ AC_ARG_WITH(history, AM_CONDITIONAL(AMC_HISTORY, test "$rc_history" = yes) -AC_ARG_WITH(addon, [ --with-addon[=foo.c] Extra builtins, from addon.c by default ],[ +AC_ARG_WITH(addon, [ --with-addon[[=foo.c]] Extra builtins, from addon.c by default ],[ case "$withval" in yes) ADDON=addon.o ;; no) ADDON='' ;; @@ -170,32 +169,69 @@ esac AC_SUBST(ADDON) -AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], - AC_CHECK_LIB(edit, readline, - AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit", - AC_MSG_ERROR(editline library not found))) +EDIT=edit-null.o +AC_ARG_WITH(edit, [ --with-edit=(bsd,edit,gnu,vrl) Command line editing library], [ + case $withval in + yes) + AC_MSG_ERROR(must specify which library) + # might consider searching + ;; + bsd) + EDIT=edit-bsd.o + RC_LIB_TGETENT + AC_CHECK_LIB(edit, el_init, [ + LIBS="$LIBS -ledit $rc_lib_tgetent" + ], AC_MSG_ERROR(editline library not found), $rc_lib_tgetent) + ;; + gnu) + EDIT=edit-gnu.o + RC_LIB_TGETENT + AC_CHECK_LIB(readline, readline, [ + LIBS="$LIBS -lreadline $rc_lib_tgetent" + ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) + AC_TRY_LINK([ + #include + #include + ], [ + rl_catch_signals = 0; + ], [], AC_MSG_ERROR(readline >= 4.0 not found)) + ;; + no|null) + ;; + edit|vrl) + EDIT=edit-$withval.o + ;; + *) + AC_MSG_ERROR(unknown editing library $withval) + ;; + esac +]) +AC_SUBST(EDIT) +dnl AC_CHECK_LIB(edit, readline, +dnl AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit", +dnl AC_MSG_ERROR(editline library not found))) -if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then - RC_LIB_TGETENT -fi +dnl if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then +dnl RC_LIB_TGETENT +dnl fi -AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing], - AC_CHECK_LIB(vrl, readline, - AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent", - AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent)) +dnl AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing], +dnl AC_CHECK_LIB(vrl, readline, +dnl AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent", +dnl AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent)) dnl There are (at least) two incompatible versions of readline, and we dnl need to know which one we are using. We don't support readline 2.0. -AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ - AC_CHECK_LIB(readline, readline, [ - AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.]) - LIBS="$LIBS -lreadline $rc_lib_tgetent" - AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent) - ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) -]) -AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) +dnl AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ +dnl AC_CHECK_LIB(readline, readline, [ +dnl AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.]) +dnl LIBS="$LIBS -lreadline $rc_lib_tgetent" +dnl AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent) +dnl ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) +dnl ]) +dnl AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) dnl For some reason CPPFLAGS doesn't get propagated. -AC_SUBST(CPPFLAGS) +dnl AC_SUBST(CPPFLAGS) AC_OUTPUT(Makefile) diff --git a/configure.scan b/configure.scan new file mode 100644 index 0000000..237fd6b --- /dev/null +++ b/configure.scan @@ -0,0 +1,49 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.56) +AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) +AC_CONFIG_SRCDIR([parse.c]) +AC_CONFIG_HEADER([config.h]) + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_CPP + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h sys/ioctl.h sys/param.h sys/time.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_C_VOLATILE + +# Checks for library functions. +AC_FUNC_CLOSEDIR_VOID +AC_FUNC_FORK +AC_FUNC_GETGROUPS +AC_FUNC_GETPGRP +AC_FUNC_LSTAT +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_TYPE_SIGNAL +AC_FUNC_STAT +AC_CHECK_FUNCS([dup2 memset mkfifo strchr strerror strrchr strspn]) + +AC_CONFIG_FILES([Makefile + rc-1.7s20020820/Makefile + rc-1.7s20021127/=build/Makefile + rc-1.7s20021127/Makefile]) +AC_OUTPUT diff --git a/edit-bsd.c b/edit-bsd.c new file mode 100644 index 0000000..c2a5260 --- /dev/null +++ b/edit-bsd.c @@ -0,0 +1,91 @@ +#include "rc.h" + +#include + +#include + +#include "edit.h" + +bool editing = 1; + +struct cookie { + EditLine *el; + History *hist; +}; + +static char *prompt; + +void *edit_begin(int fd) { + FILE *f; + HistEvent he; + struct cookie *c; + + c = ealloc(sizeof *c); + if (fd == 0) + f = stdin; + else + f = fdopen(fd, "r"); + c->el = el_init("rc", f, stdout, stderr); + el_set(c->el, EL_SIGNAL, 0); + el_source(c->el, NULL); + + c->hist = history_init(); + history(c->hist, &he, H_SETSIZE, 20); + el_set(c->el, EL_HIST, history, c->hist); + + return c; +} + + +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +char *edit_alloc(void *cookie, size_t *count) { + const char *r; + HistEvent he; + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + r = el_gets(c->el, count); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (r) + history(c->hist, &he, H_ENTER, r); + return (char *)r; /* cast to avoid gcc warning */ +} + +static char *edit_prompter(EditLine *e) { + return prompt; +} + +void edit_prompt(void *cookie, char *pr) { + struct cookie *c = cookie; + + prompt = pr; + el_set(c->el, EL_PROMPT, edit_prompter); +} + +void edit_free(void *cookie) { + /* this function deliberately left blank */ +} + +void edit_end(void *cookie) { + struct cookie *c = cookie; + + el_end(c->el); + history_end(c->hist); + efree(c); +} + +void edit_reset(void *cookie) { + struct cookie *c = cookie; + + el_set(c->el, EL_TERMINAL, NULL); +} diff --git a/edit-gnu.c b/edit-gnu.c new file mode 100644 index 0000000..6a997c5 --- /dev/null +++ b/edit-gnu.c @@ -0,0 +1,87 @@ +#include "rc.h" + +#include +#include +#include +#include +#include + +#include "edit.h" + +bool editing = 1; + +struct cookie { + char *buffer; +}; + +void *edit_begin(int fd) { + List *hist; + struct cookie *c; + + rl_catch_signals = 0; + rl_completer_quote_characters = "'"; + rl_filename_quote_characters = "\t\n !#$&'()*;<=>?@[\\]^`{|}~"; + + hist = varlookup("history"); + if (hist != NULL) + if (read_history(hist->w) != 0 && errno != ENOENT) /* ignore if missing */ + uerror(hist->w); + + c = ealloc(sizeof *c); + c->buffer = NULL; + return c; +} + +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +static char *prompt; + +char *edit_alloc(void *cookie, size_t *count) { + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + c->buffer = readline(prompt); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (c->buffer) { + *count = strlen(c->buffer); + if (*count) + add_history(c->buffer); + c->buffer[*count] = '\n'; + ++*count; /* include the \n */ + } + return c->buffer; +} + +void edit_prompt(void *cookie, char *pr) { + prompt = pr; +} + +void edit_free(void *cookie) { + struct cookie *c = cookie; + + efree(c->buffer); + /* Set c->buffer to NULL, allowing us to "overfree" it. This + is a bit of a kludge, but it's otherwise hard to deal with + the case where a signal causes an early return from + readline. */ + c->buffer = NULL; +} + +void edit_end(void *cookie) { + struct cookie *c = cookie; + + efree(c); +} + +void edit_reset(void *cookie) { + rl_reset_terminal(NULL); +} diff --git a/edit-null.c b/edit-null.c new file mode 100644 index 0000000..e3cbe13 --- /dev/null +++ b/edit-null.c @@ -0,0 +1,35 @@ +#include "rc.h" + +#include + +#include + +#include "edit.h" + +bool editing = 0; + +void *edit_begin(int fd) { + assert(0); /* should never be called */ + return NULL; +} + +char *edit_alloc(void *cookie, size_t *count) { + assert(0); /* should never be called */ + return NULL; +} + +void edit_prompt(void *cookie, char *prompt) { + assert(0); /* should never be called */ +} + +void edit_free(void *buffer) { + assert(0); /* should never be called */ +} + +void edit_end(void *cookie) { + assert(0); /* should never be called */ +} + +void edit_reset(void *cookie) { + assert(0); /* should never be called */ +} diff --git a/edit.h b/edit.h new file mode 100644 index 0000000..5f4eb5c --- /dev/null +++ b/edit.h @@ -0,0 +1,12 @@ +extern bool editing; + +extern void *edit_begin(int fd); + +extern char *edit_alloc(void *, size_t *); +extern void edit_free(void *); + +extern void edit_prompt(void *, char *); + +extern void edit_end(void *); + +extern void edit_reset(void *); diff --git a/except.c b/except.c index 886ab50..8f20676 100644 --- a/except.c +++ b/except.c @@ -3,6 +3,7 @@ #include #include +#include "input.h" #include "jbwrap.h" /* diff --git a/fn.c b/fn.c index 734c071..7d9e4f7 100644 --- a/fn.c +++ b/fn.c @@ -8,6 +8,7 @@ #include #include +#include "input.h" #include "sigmsgs.h" static void fn_handler(int), dud_handler(int); diff --git a/footobar.c b/footobar.c index 4430c05..d6f6dfd 100644 --- a/footobar.c +++ b/footobar.c @@ -5,6 +5,8 @@ #include "rc.h" +#include "input.h" + /* protect an exported name from brain-dead shells */ #if PROTECT_ENV @@ -73,7 +75,8 @@ static bool Tconv(Format *f, int ignore) { case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break; case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; case nWord: - fmtprint(f, quotep(n->u[0].s, dollar) ? "%#S" : "%S", n->u[0].s); + fmtprint(f, n->u[2].i && quotep(n->u[0].s, dollar) ? + "%#S" : "%S", n->u[0].s); break; case nLappend: { static bool inlist; diff --git a/glob.c b/glob.c index b472af9..5507678 100644 --- a/glob.c +++ b/glob.c @@ -143,7 +143,7 @@ static List *dmatch(char *d, char *p, char *m) { } /* - lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*" + lglob() globs a pattern against a list of directory roots. e.g., (/tmp /usr /bin) "*" will return a list with all the files in /tmp, /usr, and /bin. NULL on no match. slashcount indicates the number of slashes to stick between the directory and the matched name. e.g., for matching ////tmp/////foo* diff --git a/hash.c b/hash.c index 3f65ad8..5fafed2 100644 --- a/hash.c +++ b/hash.c @@ -315,14 +315,3 @@ extern void whatare_all_vars(bool showfn, bool showvar) { if (fp[i].name != NULL && fp[i].name != dead) prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name)); } - -/* fake getenv() for readline() follows: */ - -#if EDITLINE || READLINE -extern char *getenv(const char *name) { - List *s; - if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL) - return NULL; - return s->w; -} -#endif diff --git a/heredoc.c b/heredoc.c index 922fc12..348dc84 100644 --- a/heredoc.c +++ b/heredoc.c @@ -2,6 +2,8 @@ #include "rc.h" +#include "input.h" + struct Hq { Node *doc; char *name; @@ -40,7 +42,7 @@ static char *readheredoc(char *eof) { bufend = &buf[bufsize]; \ } for (;;) { - print_prompt2(); + nextline(); for (s = (unsigned char *) eof; (c = gchar()) == *s; s++) ; if (*s == '\0' && (c == '\n' || c == EOF)) { @@ -142,7 +144,7 @@ extern int qdoc(Node *name, Node *n) { Hq *new, **prev; if (name->type != nWord) { yyerror("eof-marker not a single literal word"); - flushu(); + skiptonl(); return FALSE; } for (prev = &hq; (new = *prev) != NULL; prev = &new->n) diff --git a/input.c b/input.c index c5ac5fc..df597c4 100644 --- a/input.c +++ b/input.c @@ -4,161 +4,166 @@ #include +#include "edit.h" +#include "input.h" #include "jbwrap.h" -/* - NB: character unget is supported for up to two characters, but NOT - in the case of EOF. Since EOF does not fit in a char, it is easiest - to support only one unget of EOF. -*/ +/* How many characters can we unget? */ +enum { UNGETSIZE = 2 }; + +typedef enum inputtype { + iFd, iString, iEdit +} inputtype; typedef struct Input { + bool saved; inputtype t; + int fd, index, read, ungetcount, lineno, last; char *ibuf; - int fd, index, read, lineno, last; - bool saved, eofread; + void *cookie; + int ungetbuf[UNGETSIZE]; + int (*gchar)(void); } Input; #define BUFSIZE ((size_t) 256) -static char *prompt2; -bool rcrc; - -static int dead(void); -static int fdgchar(void); -static int stringgchar(void); -static void history(void); -static void ugdead(int); -static void pushcommon(void); - static char *inbuf; static size_t istacksize, chars_out, chars_in; -static bool eofread = FALSE, save_lineno = TRUE; +static bool save_lineno = TRUE; static Input *istack, *itop; -static int (*realgchar)(void); -static void (*realugchar)(int); - int lastchar; -#if EDITLINE || READLINE -static char *rlinebuf, *prompt; -#endif +static char *prompt, *prompt2; + +extern void ugchar(int c) { + assert(istack->ungetcount < UNGETSIZE); + istack->ungetbuf[istack->ungetcount++] = c; +} extern int gchar() { int c; - if (eofread) { - eofread = FALSE; - return lastchar = EOF; - } + if (istack->ungetcount) + return lastchar = istack->ungetbuf[--istack->ungetcount]; - while ((c = (*realgchar)()) == '\0') + while ((c = (*istack->gchar)()) == '\0') pr_error("warning: null character ignored", 0); return c; } -extern void ugchar(int c) { - (*realugchar)(c); -} -static int dead() { - return lastchar = EOF; -} +/* get the next character from a string. */ -static void ugdead(int ignore) { - return; +static int stringgchar() { + return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); } -static void ugalive(int c) { - if (c == EOF) - eofread = TRUE; - else - inbuf[--chars_out] = c; -} -/* get the next character from a string. */ +/* write last command out to a file if interactive && $history is set */ -static int stringgchar() { - return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); +static void history() { + List *hist; + size_t a; + + if (!interactive || (hist = varlookup("history")) == NULL) + return; + + for (a = 0; a < chars_in; a++) { + char c = inbuf[a]; + + /* skip empty lines and comments */ + if (c == '#' || c == '\n') + break; + + /* line matches [ \t]*[^#\n] so it's ok to write out */ + if (c != ' ' && c != '\t') { + char *name = hist->w; + int fd = rc_open(name, rAppend); + if (fd < 0) + uerror(name); + else { + writeall(fd, inbuf, chars_in); + close(fd); + } + break; + } + } } -/* - read a character from a file-descriptor. If GNU readline is defined, - add a newline and doctor the buffer to look like a regular fdgchar - buffer. -*/ -static int fdgchar() { +/* read a character from a file descriptor */ - if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */ - while (1) { -#if EDITLINE || READLINE - if (interactive && istack->t == iFd && isatty(istack->fd)) { - /* The readline library doesn't handle - * read() returning EAGAIN or EIO. */ - makeblocking(istack->fd); - makesamepgrp(istack->fd); - rlinebuf = rc_readline(prompt); - if (rlinebuf == NULL) { - chars_in = 0; - } else { - if (*rlinebuf != '\0') - add_history(rlinebuf); - chars_in = strlen(rlinebuf) + 1; - efree(inbuf); - inbuf = ealloc(chars_in + 3); - strcpy(inbuf+2, rlinebuf); - strcat(inbuf+2, "\n"); - efree(rlinebuf); - } - } else -#endif - { - ssize_t r; - do { - r = rc_read(istack->fd, inbuf + 2, BUFSIZE); - sigchk(); - switch (errno) { - case EAGAIN: - if (!makeblocking(istack->fd)) - panic("not O_NONBLOCK"); +static int fdgchar() { + if (chars_out >= chars_in) { /* replenish empty buffer */ + ssize_t r; + do { + r = rc_read(istack->fd, inbuf, BUFSIZE); + sigchk(); + if (r == -1) + switch (errno) { + case EAGAIN: + if (!makeblocking(istack->fd)) + panic("not O_NONBLOCK"); + errno = EINTR; + break; + case EIO: + if (makesamepgrp(istack->fd)) errno = EINTR; - break; - case EIO: - if (makesamepgrp(istack->fd)) - errno = EINTR; - else - errno = EIO; - break; - } - } while (r < 0 && errno == EINTR); - if (r < 0) { - uerror("read"); - rc_raise(eError); + else + errno = EIO; + break; } - chars_in = (size_t) r; - } - break; + } while (r < 0 && errno == EINTR); + if (r < 0) { + uerror("read"); + rc_raise(eError); } + chars_in = (size_t) r; if (chars_in == 0) return lastchar = EOF; - chars_out = 2; + chars_out = 0; if (dashvee) - writeall(2, inbuf + 2, chars_in); + writeall(2, inbuf, chars_in); history(); } + return lastchar = inbuf[chars_out++]; } +/* read a character from a line-editing file descriptor */ + +static int editgchar() { + if (chars_out >= chars_in) { /* replenish empty buffer */ + edit_free(istack->cookie); + inbuf = edit_alloc(istack->cookie, &chars_in); + if (inbuf == NULL) { + chars_in = 0; + fprint(2, "exit\n"); + return lastchar = EOF; + } + + chars_out = 0; + if (dashvee) + writeall(2, inbuf, chars_in); + history(); + } + + return lastchar = inbuf[chars_out++]; +} + +void termchange(void) { + if (istack->t == iEdit) + edit_reset(istack->cookie); +} + + /* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */ extern void initinput() { istack = itop = ealloc(istacksize = 256 * sizeof (Input)); - istack->t = iFd; - istack->fd = -1; - realugchar = ugalive; + ugchar(EOF); } /* push an input source onto the stack. set up a new input buffer, and set gchar() */ @@ -171,54 +176,56 @@ static void pushcommon() { istack->lineno = lineno; istack->saved = save_lineno; istack->last = lastchar; - istack->eofread = eofread; istack++; idiff = istack - itop; if (idiff >= istacksize / sizeof (Input)) { itop = erealloc(itop, istacksize *= 2); istack = itop + idiff; } - realugchar = ugalive; - chars_out = 2; + chars_out = 0; chars_in = 0; + istack->ungetcount = 0; } extern void pushfd(int fd) { pushcommon(); - istack->t = iFd; save_lineno = TRUE; istack->fd = fd; - realgchar = fdgchar; - inbuf = ealloc(BUFSIZE + 2); lineno = 1; + if (editing && interactive && isatty(fd)) { + istack->t = iEdit; + istack->gchar = editgchar; + istack->cookie = edit_begin(fd); + } else { + istack->t = iFd; + istack->gchar = fdgchar; + inbuf = ealloc(BUFSIZE); + } } extern void pushstring(char **a, bool save) { pushcommon(); istack->t = iString; save_lineno = save; - inbuf = mprint("..%A", a); - realgchar = stringgchar; + inbuf = mprint("%A", a); + istack->gchar = stringgchar; if (save_lineno) lineno = 1; else --lineno; } -/* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */ + +/* remove an input source from the stack. restore associated variables etc. */ extern void popinput() { - if (istack->t == iFd) + if (istack->t == iEdit) + edit_end(istack->cookie); + if (istack->t == iFd || istack->t == iEdit) close(istack->fd); efree(inbuf); --istack; - realgchar = (istack->t == iString ? stringgchar : fdgchar); - if (istack->t == iFd && istack->fd == -1) { /* top of input stack */ - realgchar = dead; - realugchar = ugdead; - } lastchar = istack->last; - eofread = istack->eofread; inbuf = istack->ibuf; chars_out = istack->index; chars_in = istack->read; @@ -229,9 +236,10 @@ extern void popinput() { save_lineno = istack->saved; } -/* flush input characters upto newline. Used by scanerror() */ -extern void flushu() { +/* flush input characters up to newline. Used by scanerror() */ + +extern void skiptonl() { int c; if (lastchar == '\n' || lastchar == EOF) return; @@ -241,6 +249,7 @@ extern void flushu() { ugchar(c); } + /* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */ extern Node *doit(bool clobberexecit) { @@ -259,17 +268,11 @@ extern Node *doit(bool clobberexecit) { for (eof = FALSE; !eof;) { Edata block; Estack e2; + block.b = newblock(); except(eArena, block, &e2); sigchk(); - if (dashell) { - char *fname[3]; - fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w; - fname[2] = NULL; - rcrc = TRUE; - dashell = FALSE; - b_dot(fname); - } + if (interactive) { List *s; if (!dashen && fnlookup("prompt") != NULL) { @@ -282,15 +285,20 @@ extern Node *doit(bool clobberexecit) { } died = FALSE; } - if ((s = varlookup("prompt")) != NULL) { -#if EDITLINE || READLINE - if (istack->t == iFd && isatty(istack->fd)) - prompt = s->w; + s = varlookup("prompt"); + if (s != NULL) { + prompt = s->w; + if (s->n != NULL) + prompt2 = s->n->w; else -#endif - fprint(2, "%s", s->w); - prompt2 = (s->n == NULL ? "" : s->n->w); + prompt2 = ""; + } else { + prompt = prompt2 = ""; } + if (istack->t == iFd) + fprint(2, "%s", prompt); + else if (istack->t == iEdit) + edit_prompt(istack->cookie, prompt); } inityy(); if (yyparse() == 1 && execit) @@ -312,7 +320,7 @@ extern Node *doit(bool clobberexecit) { /* parse a function imported from the environment */ extern Node *parseline(char *extdef) { - int i = interactive; + bool i = interactive; char *in[2]; Node *fun; in[0] = extdef; @@ -324,38 +332,6 @@ extern Node *parseline(char *extdef) { return fun; } -/* write last command out to a file if interactive && $history is set */ - -static void history() { - List *hist; - size_t a; - - if (!interactive || (hist = varlookup("history")) == NULL) - return; - - for (a = 0; a < chars_in; a++) { - char c = inbuf[a+2]; - - /* skip empty lines and comments */ - if (c == '#' || c == '\n') - break; - - /* line matches [ \t]*[^#\n] so it's ok to write out */ - if (c != ' ' && c != '\t') { - char *name = hist->w; - int fd = rc_open(name, rAppend); - if (fd < 0) { - uerror(name); - varrm(name, TRUE); - } else { - writeall(fd, inbuf + 2, chars_in); - close(fd); - } - break; - } - } -} - /* close file descriptors after a fork() */ extern void closefds() { @@ -367,14 +343,14 @@ extern void closefds() { } } -extern void print_prompt2() { +/* print (or set) prompt(2) */ + +extern void nextline() { lineno++; if (interactive) { -#if EDITLINE || READLINE - if (istack->t == iFd && isatty(istack->fd)) - prompt = prompt2; - else -#endif + if (istack->t == iFd) fprint(2, "%s", prompt2); + else if (istack->t == iEdit) + edit_prompt(istack->cookie, prompt2); } } diff --git a/input.h b/input.h new file mode 100644 index 0000000..87db27b --- /dev/null +++ b/input.h @@ -0,0 +1,35 @@ +/* initialize the input stack */ +extern void initinput(void); + +/* push an input onto the stack */ +extern void pushfd(int); +/* the Boolean argument affects line number reporting */ +extern void pushstring(char **, bool); + +/* pop the stack */ +extern void popinput(void); + +/* get / unget the next character */ +extern int gchar(void); +extern void ugchar(int); + +/* $TERM or $TERMCAP has changed */ +extern void termchange(void); + +/* parse a function from the environment */ +extern Node *parseline(char *); + +/* main parsing loop; Boolean says whether to exec also */ +extern Node *doit(bool); + +/* error recovery: skip to the next newline */ +extern void skiptonl(void); + +/* prepare for next line of input */ +extern void nextline(void); + +/* close all file descriptors on the stack */ +extern void closefds(void); + +/* the last character read */ +extern int lastchar; diff --git a/lex.c b/lex.c index 6bc92da..1df705a 100644 --- a/lex.c +++ b/lex.c @@ -1,6 +1,8 @@ /* lex.c: rc's lexical analyzer */ #include "rc.h" + +#include "input.h" #include "parse.h" /* @@ -33,6 +35,7 @@ static void getpair(int); int lineno; +/* lookup table for non-word characters */ const char nw[] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, @@ -44,6 +47,7 @@ const char nw[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* lookup table for non-word characters in variable names */ const char dnw[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, @@ -55,6 +59,18 @@ const char dnw[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +/* lookup table for quotable characters: nw + glob metachars */ +const char q[] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + static size_t bufsize = BUFSIZE; static char *realbuf = NULL; static bool newline = FALSE; @@ -74,7 +90,7 @@ extern bool quotep(char *s, bool dollar) { unsigned char c; const char *meta; - meta = dollar ? dnw : nw; + meta = dollar ? dnw : q; while ((c = *s++)) if (meta[c]) return TRUE; @@ -95,14 +111,14 @@ extern int yylex() { } /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */ meta = (dollar ? dnw : nw); - dollar = FALSE; if (newline) { - --lineno; /* slight space optimization; print_prompt2() always increments lineno */ - print_prompt2(); + --lineno; /* slight space optimization; nextline() always increments lineno */ + nextline(); newline = FALSE; } top: while ((c = gchar()) == ' ' || c == '\t') w = NW; + if (c != '(') dollar = FALSE; if (c == EOF) return END; if (!meta[(unsigned char) c]) { /* it's a word or keyword. */ @@ -118,7 +134,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') } while ((c = gchar()) != EOF && !meta[(unsigned char) c]); while (c == '\\') { if ((c = gchar()) == '\n') { - print_prompt2(); + nextline(); c = ' '; /* Pretend a space was read */ break; } else { @@ -185,7 +201,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') c = gchar(); if (c == '#') return COUNT; - if (c == '^') + if (c == '^' || c == '"') return FLAT; ugchar(c); return '$'; @@ -196,7 +212,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') while ((c = gchar()) != '\'' || (c = gchar()) == '\'') { buf[i++] = c; if (c == '\n') - print_prompt2(); + nextline(); if (c == EOF) { w = NW; scanerror("eof in quoted string"); @@ -213,7 +229,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') return WORD; case '\\': if ((c = gchar()) == '\n') { - print_prompt2(); + nextline(); goto top; /* Pretend it was just another space. */ } ugchar(c); @@ -223,7 +239,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') i = 0; goto bs; case '(': - if (w == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */ + if (w == RW) /* SUB's happen only after real words, not keywords, so if () and while () work */ c = SUB; w = NW; return c; @@ -327,13 +343,13 @@ extern void yyerror(const char *s) { tok = "end of line"; else tok = nprint((lastchar < 32 || lastchar > 126) ? "(decimal %d)" : "'%c'", lastchar); - fprint(2, "line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok); + fprint(2, "rc: line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok); } else - fprint(2, "%s\n", s); + fprint(2, "rc: %s\n", s); } extern void scanerror(char *s) { - flushu(); /* flush upto newline */ + skiptonl(); /* flush upto newline */ yyerror(s); errset = prerror = TRUE; } diff --git a/main.c b/main.c index 6ce7317..4da3014 100644 --- a/main.c +++ b/main.c @@ -2,11 +2,15 @@ #include "rc.h" -bool dashdee, dashee, dashvee, dashex, dashell, dashEYE, dasheye, - dashen, dashpee, dashess, interactive; +#include + +#include "input.h" + +bool dashdee, dashee, dashvee, dashex, dasheye, + dashen, dashpee, interactive; pid_t rc_pid; -static bool dashoh; +static bool dashEYE, dashell, dashoh, dashess; static void assigndefault(char *,...); static void checkfd(int, enum redirtype); @@ -86,6 +90,28 @@ quitopts: null[0] = NULL; starassign(dollarzero, null, FALSE); /* assign $0 to $* */ inithandler(); + + if (dashell) { + char *rcrc; + int fd; + + rcrc = concat(varlookup("home"), word("/.rcrc", NULL))->w; + fd = rc_open(rcrc, rFrom); + if (fd == -1) { + if (errno != ENOENT) + uerror(rcrc); + } else { + bool push_interactive; + + pushfd(fd); + push_interactive = interactive; + interactive = FALSE; + doit(TRUE); + interactive = push_interactive; + close(fd); + } + } + if (dashsee[0] != NULL || dashess) { /* input from -c or -s? */ if (*argv != NULL) starassign(dollarzero, argv, FALSE); diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..55d537f --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,162 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2009-04-28.21; # UTC + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' +IFS=" "" $nl" +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the 'mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because '.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/nonblock.c b/nonblock.c new file mode 100644 index 0000000..dbe31d3 --- /dev/null +++ b/nonblock.c @@ -0,0 +1,14 @@ +/* Set stdin to nonblocking. */ +#include +#include +#include +#include +int main(void) { + int flags; + flags = fcntl(0, F_GETFL); + flags |= O_NONBLOCK; + fcntl(0, F_SETFL, (long) flags); + flags = read(0, &flags, 1); + printf("read returns %d, errno == %d\n", flags, errno); + return 0; +} diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..1275ab5 --- /dev/null +++ b/parse.c @@ -0,0 +1,1117 @@ +#ifndef lint +static char const +yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $"; +#endif +#include "rc.h" +#include +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +static int yygrowstack(); +#define YYPREFIX "yy" +#line 8 "parse.y" + +static Node *star, *nolist; +Node *parsetree; /* not using yylval because bison declares it as an auto */ +#line 26 "parse.y" +typedef union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} YYSTYPE; +#line 31 "y.tab.c" +#define YYERRCODE 256 +#define ANDAND 257 +#define BACKBACK 258 +#define BANG 259 +#define CASE 260 +#define COUNT 261 +#define DUP 262 +#define ELSE 263 +#define END 264 +#define FLAT 265 +#define FN 266 +#define FOR 267 +#define IF 268 +#define IN 269 +#define OROR 270 +#define PIPE 271 +#define REDIR 272 +#define SREDIR 273 +#define SUB 274 +#define SUBSHELL 275 +#define SWITCH 276 +#define TWIDDLE 277 +#define WHILE 278 +#define WORD 279 +#define HUH 280 +const short yylhs[] = { -1, + 0, 0, 22, 22, 8, 8, 13, 13, 3, 3, + 9, 9, 4, 15, 2, 11, 11, 16, 16, 16, + 5, 5, 6, 6, 6, 19, 19, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 24, 24, 18, 18, 18, + 12, 12, 17, 17, 20, 20, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 21, 21, + 14, 14, 14, 23, 23, +}; +const short yylen[] = { 2, + 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, + 1, 2, 3, 3, 3, 0, 2, 1, 2, 2, + 3, 3, 1, 2, 2, 1, 4, 0, 1, 2, + 4, 8, 6, 4, 8, 4, 4, 4, 4, 2, + 2, 3, 3, 3, 2, 0, 1, 1, 2, 2, + 1, 3, 1, 1, 1, 3, 2, 5, 2, 2, + 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, + 0, 2, 2, 0, 2, +}; +const short yydefred[] = { 0, + 0, 0, 0, 0, 18, 0, 79, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 0, 0, 81, 0, + 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, + 3, 4, 2, 77, 75, 74, 73, 68, 71, 69, + 0, 78, 72, 76, 70, 54, 53, 55, 0, 47, + 0, 59, 60, 0, 0, 0, 84, 66, 0, 0, + 0, 0, 0, 84, 0, 0, 0, 11, 0, 0, + 62, 61, 0, 0, 30, 0, 84, 84, 84, 5, + 6, 8, 0, 0, 1, 0, 50, 0, 0, 63, + 64, 0, 44, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 13, 12, 10, 65, 82, 0, 17, 0, + 0, 0, 0, 52, 56, 79, 84, 14, 85, 0, + 0, 31, 84, 0, 0, 0, 0, 0, 39, 0, + 0, 84, 0, 58, 84, 0, 0, 0, 0, 0, + 79, 0, 0, 0, 0, 0, 0, 24, 35, 25, + 22, 21, +}; +const short yydgoto[] = { 21, + 46, 22, 66, 23, 142, 143, 67, 68, 69, 47, + 75, 27, 28, 70, 57, 29, 48, 30, 122, 94, + 54, 33, 97, 51, +}; +const short yysindex[] = { 874, + 24, 1001, -82, 1001, 0, 1001, 0, -27, -26, 900, + 1001, -82, -20, -82, -26, 0, 1001, 1134, 0, 900, + 0, 1134, -203, -30, 1134, 0, -55, 24, 1134, 826, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -66, 0, 0, 0, 0, 0, 0, 0, 849, 0, + 1134, 0, 0, 900, 1001, 1134, 0, 0, -52, -52, + 1134, 1001, 1001, 0, -212, -58, 154, 0, 1134, 426, + 0, 0, -196, 1001, 0, -203, 0, 0, 0, 0, + 0, 0, 1001, 1001, 0, -196, 0, -52, 1001, 0, + 0, -196, 0, -52, -38, 36, 502, -196, -36, -52, + 502, 0, 0, 0, 0, 0, 0, -52, 0, 502, + 502, 502, -52, 0, 0, 0, 0, 0, 0, -97, + -234, 0, 0, 1001, -234, 922, -196, -196, 0, 944, + 502, 0, -9, 0, 0, -234, 502, 967, 502, -234, + 0, 967, -45, 154, 967, -234, 448, 0, 0, 0, + 0, 0, +}; +const short yyrindex[] = { 134, + 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, + 0, 356, 0, 1024, 0, 0, 0, 571, 0, 0, + 0, 487, 529, 54, 134, 0, 62, 0, 487, 548, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 487, 0, 0, 712, 0, 142, 0, 0, 14, 38, + 487, 0, 0, 0, -10, 0, -32, 0, 744, 0, + 0, 0, 749, 0, 0, 529, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 763, 0, 86, 0, 0, + 0, 779, 0, 110, 0, 0, -34, 788, 0, 380, + -34, 0, 0, 0, 0, 0, 0, 470, 0, -34, + -34, -34, 404, 0, 0, 0, 0, 0, 0, 529, + 6, 0, 0, 724, 30, 0, 805, 813, 0, 0, + -34, 0, 0, 0, 0, 119, -34, 571, -34, 187, + 0, 571, 0, -44, 571, 396, 0, 0, 0, 0, + 0, 0, +}; +const short yygindex[] = { 0, + 0, 0, -23, 12, 0, -104, 1319, 2, -127, 1307, + 7, 0, 57, 0, 70, -13, 84, 0, 0, 420, + -81, 59, 369, 31, +}; +#define YYTABLESIZE 1464 +const short yytable[] = { 57, + 119, 25, 117, 28, 123, 83, 28, 81, 9, 76, + 145, 50, 55, 56, 145, 26, 87, 145, 124, 62, + 126, 58, 77, 19, 28, 57, 25, 57, 80, 57, + 57, 71, 96, 32, 130, 78, 79, 148, 84, 34, + 150, 89, 61, 26, 63, 105, 26, 20, 57, 19, + 57, 19, 58, 19, 19, 89, 18, 89, 5, 147, + 90, 102, 76, 7, 26, 93, 103, 34, 74, 11, + 34, 48, 19, 20, 79, 20, 118, 20, 20, 149, + 23, 82, 109, 57, 64, 57, 85, 52, 34, 53, + 28, 0, 9, 0, 0, 49, 20, 48, 0, 48, + 65, 48, 48, 72, 0, 0, 76, 0, 120, 19, + 0, 0, 57, 138, 57, 0, 0, 0, 0, 80, + 48, 49, 0, 49, 0, 49, 49, 0, 33, 0, + 26, 0, 91, 20, 0, 0, 19, 0, 19, 0, + 0, 0, 0, 28, 49, 80, 0, 80, 0, 80, + 80, 28, 0, 0, 34, 0, 33, 48, 0, 33, + 20, 0, 20, 104, 5, 132, 0, 114, 80, 0, + 0, 28, 115, 0, 74, 11, 0, 33, 0, 28, + 0, 49, 28, 0, 0, 0, 48, 0, 0, 0, + 0, 81, 28, 0, 0, 0, 27, 0, 0, 0, + 28, 0, 0, 0, 0, 80, 0, 0, 0, 0, + 49, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 28, 0, 27, 0, 77, 27, 0, 28, + 116, 0, 80, 0, 80, 28, 28, 0, 0, 78, + 79, 0, 0, 33, 0, 27, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 0, 57, 57, 57, 57, 57, 26, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 31, 19, 19, + 19, 19, 19, 34, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 27, 20, 20, 20, 20, 20, 7, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, + 48, 0, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, + 49, 49, 49, 49, 49, 46, 80, 80, 80, 80, + 80, 0, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 33, 0, 80, 80, 80, 80, 80, 79, + 28, 46, 0, 46, 0, 46, 46, 28, 28, 0, + 0, 0, 0, 28, 28, 32, 0, 0, 0, 0, + 77, 28, 28, 15, 46, 79, 0, 79, 0, 79, + 79, 49, 0, 78, 79, 0, 0, 0, 0, 59, + 60, 0, 101, 32, 0, 107, 32, 0, 79, 15, + 0, 15, 0, 15, 15, 110, 111, 112, 0, 88, + 27, 46, 0, 0, 32, 0, 0, 151, 0, 0, + 0, 17, 15, 0, 0, 19, 106, 0, 0, 0, + 0, 0, 0, 0, 95, 79, 0, 0, 46, 83, + 46, 99, 100, 17, 0, 131, 0, 19, 0, 108, + 0, 133, 0, 59, 0, 0, 28, 0, 0, 15, + 137, 0, 113, 139, 79, 83, 152, 0, 0, 83, + 83, 119, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 20, 0, 0, 28, 0, 15, 28, 15, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 16, 0, + 0, 19, 0, 20, 0, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 83, 16, 0, 0, 16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 28, 0, 0, 0, 0, 29, 0, 16, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 0, 28, 0, + 0, 28, 46, 46, 46, 0, 46, 46, 0, 46, + 46, 46, 46, 46, 18, 46, 46, 46, 46, 28, + 46, 46, 46, 46, 46, 0, 79, 79, 79, 79, + 79, 0, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 0, 16, 79, 79, 79, 79, 79, 32, + 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, + 15, 15, 29, 15, 15, 15, 15, 0, 15, 15, + 15, 15, 15, 2, 34, 35, 4, 0, 36, 0, + 6, 37, 38, 39, 40, 28, 0, 41, 0, 0, + 42, 43, 44, 45, 16, 2, 34, 35, 4, 0, + 36, 0, 6, 37, 38, 39, 40, 0, 0, 41, + 0, 45, 42, 43, 44, 45, 16, 83, 83, 83, + 83, 0, 83, 36, 83, 83, 83, 83, 83, 0, + 0, 83, 0, 28, 83, 83, 83, 83, 83, 45, + 28, 0, 45, 28, 0, 0, 28, 28, 41, 2, + 3, 36, 4, 5, 36, 0, 6, 7, 8, 9, + 45, 0, 40, 10, 11, 0, 12, 13, 14, 15, + 16, 28, 36, 0, 28, 16, 41, 0, 42, 41, + 0, 0, 16, 0, 0, 0, 0, 43, 16, 16, + 40, 0, 28, 40, 29, 0, 0, 41, 0, 0, + 0, 29, 0, 0, 37, 0, 42, 29, 29, 42, + 0, 40, 38, 0, 0, 43, 0, 28, 43, 0, + 0, 0, 0, 0, 0, 0, 45, 42, 0, 0, + 28, 28, 37, 0, 0, 37, 43, 0, 36, 0, + 38, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 37, 0, 19, 0, 0, 28, 0, + 0, 38, 0, 41, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 40, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42, 0, 0, 0, 0, 0, 17, + 0, 0, 43, 19, 0, 0, 0, 0, 0, 0, + 0, 20, 0, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 0, 0, 17, 0, 38, 0, 19, + 0, 0, 89, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, + 0, 19, 134, 0, 0, 0, 0, 0, 45, 20, + 0, 18, 0, 0, 0, 45, 0, 0, 0, 17, + 36, 45, 45, 19, 135, 0, 0, 36, 0, 0, + 0, 0, 0, 36, 36, 20, 18, 0, 0, 0, + 28, 0, 17, 0, 0, 41, 19, 0, 0, 0, + 0, 0, 41, 28, 28, 0, 0, 20, 41, 40, + 0, 0, 18, 0, 0, 0, 40, 0, 0, 0, + 0, 0, 40, 0, 0, 42, 17, 0, 0, 20, + 19, 0, 42, 0, 43, 0, 0, 0, 42, 0, + 0, 43, 0, 0, 0, 0, 0, 43, 0, 46, + 0, 37, 20, 46, 0, 0, 0, 0, 37, 38, + 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, + 0, 0, 38, 2, 34, 35, 4, 5, 36, 18, + 6, 37, 38, 39, 40, 0, 20, 10, 11, 0, + 42, 43, 44, 45, 16, 0, 2, 34, 35, 4, + 0, 36, 0, 6, 37, 38, 39, 40, 0, 46, + 41, 0, 0, 42, 43, 44, 45, 16, 0, 1, + 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, + 8, 9, 0, 0, 0, 10, 11, 0, 12, 13, + 14, 15, 16, 0, 0, 0, 0, 2, 34, 35, + 4, 0, 36, 0, 6, 37, 38, 39, 40, 17, + 0, 41, 0, 19, 42, 43, 44, 45, 16, 2, + 34, 35, 4, 0, 36, 0, 6, 37, 38, 39, + 40, 0, 0, 41, 0, 0, 42, 43, 44, 45, + 16, 2, 34, 35, 4, 0, 36, 0, 6, 37, + 38, 39, 40, 0, 0, 41, 0, 0, 42, 43, + 44, 45, 16, 0, 2, 3, 141, 4, 5, 20, + 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, + 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 0, 2, 34, + 35, 4, 0, 36, 0, 6, 37, 38, 39, 40, + 0, 0, 41, 0, 0, 42, 43, 44, 45, 16, + 0, 46, 46, 46, 46, 0, 46, 0, 46, 46, + 46, 46, 46, 0, 0, 46, 0, 0, 46, 46, + 46, 46, 46, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, + 0, 0, 0, 0, 26, 0, 0, 0, 26, 0, + 0, 26, 0, 0, 0, 26, 0, 0, 0, 0, + 73, 0, 0, 24, 0, 0, 0, 86, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, + 0, 0, 26, 0, 0, 0, 0, 26, 0, 92, + 0, 0, 0, 0, 0, 26, 0, 0, 0, 98, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, + 8, 9, 0, 26, 0, 10, 11, 26, 12, 13, + 14, 15, 16, 0, 0, 121, 26, 26, 26, 125, + 0, 0, 0, 0, 0, 0, 0, 0, 127, 128, + 129, 0, 0, 0, 0, 0, 0, 26, 0, 0, + 0, 0, 0, 26, 26, 26, 0, 0, 26, 136, + 0, 26, 0, 0, 0, 140, 144, 146, 0, 0, + 144, 0, 0, 144, +}; +const short yycheck[] = { 10, + 10, 0, 41, 38, 41, 61, 41, 38, 41, 23, + 138, 94, 40, 40, 142, 10, 30, 145, 100, 40, + 102, 10, 257, 10, 59, 36, 25, 38, 59, 40, + 41, 20, 56, 10, 116, 270, 271, 142, 94, 10, + 145, 94, 12, 38, 14, 69, 41, 10, 59, 36, + 61, 38, 41, 40, 41, 94, 123, 94, 262, 141, + 49, 274, 76, 10, 59, 54, 125, 38, 272, 273, + 41, 10, 59, 36, 271, 38, 41, 40, 41, 125, + 125, 25, 76, 94, 15, 96, 28, 4, 59, 6, + 125, -1, 125, -1, -1, 10, 59, 36, -1, 38, + 17, 40, 41, 20, -1, -1, 120, -1, 97, 96, + -1, -1, 123, 123, 125, -1, -1, -1, -1, 10, + 59, 36, -1, 38, -1, 40, 41, -1, 10, -1, + 125, -1, 49, 96, -1, -1, 123, -1, 125, -1, + -1, -1, -1, 10, 59, 36, -1, 38, -1, 40, + 41, 10, -1, -1, 125, -1, 38, 96, -1, 41, + 123, -1, 125, 10, 262, 263, -1, 84, 59, -1, + -1, 38, 89, -1, 272, 273, -1, 59, -1, 38, + -1, 96, 41, -1, -1, -1, 125, -1, -1, -1, + -1, 38, 59, -1, -1, -1, 10, -1, -1, -1, + 59, -1, -1, -1, -1, 96, -1, -1, -1, -1, + 125, -1, 59, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 257, -1, 38, -1, 257, 41, -1, 264, + 269, -1, 123, -1, 125, 270, 271, -1, -1, 270, + 271, -1, -1, 125, -1, 59, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, -1, 275, 276, 277, 278, 279, 264, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 264, 275, 276, + 277, 278, 279, 264, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 125, 275, 276, 277, 278, 279, 264, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, -1, 275, 276, 277, 278, + 279, -1, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, -1, + 275, 276, 277, 278, 279, 10, 257, 258, 259, 260, + 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 264, -1, 275, 276, 277, 278, 279, 10, + 257, 36, -1, 38, -1, 40, 41, 264, 257, -1, + -1, -1, -1, 270, 271, 10, -1, -1, -1, -1, + 257, 270, 271, 10, 59, 36, -1, 38, -1, 40, + 41, 2, -1, 270, 271, -1, -1, -1, -1, 10, + 11, -1, 64, 38, -1, 10, 41, -1, 59, 36, + -1, 38, -1, 40, 41, 77, 78, 79, -1, 30, + 264, 96, -1, -1, 59, -1, -1, 10, -1, -1, + -1, 36, 59, -1, -1, 40, 41, -1, -1, -1, + -1, -1, -1, -1, 55, 96, -1, -1, 123, 10, + 125, 62, 63, 36, -1, 117, -1, 40, -1, 70, + -1, 123, -1, 74, -1, -1, 10, -1, -1, 96, + 132, -1, 83, 135, 125, 36, 59, -1, -1, 40, + 41, 10, -1, -1, -1, -1, -1, -1, -1, -1, + 125, 96, -1, -1, 38, -1, 123, 41, 125, -1, + -1, -1, -1, -1, -1, -1, -1, 36, 10, -1, + -1, 40, -1, 96, -1, 59, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, + -1, -1, -1, -1, -1, 96, 38, -1, -1, 41, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, -1, -1, -1, -1, 38, -1, 59, 41, -1, + -1, -1, -1, -1, -1, -1, -1, 96, -1, -1, + -1, -1, -1, -1, -1, -1, 59, -1, 38, -1, + -1, 125, 257, 258, 259, -1, 261, 262, -1, 264, + 265, 266, 267, 268, 123, 270, 271, 272, 273, 59, + 275, 276, 277, 278, 279, -1, 257, 258, 259, 260, + 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, -1, 125, 275, 276, 277, 278, 279, 264, + 257, 258, 259, -1, 261, 262, -1, 264, 265, 266, + 267, 268, 125, 270, 271, 272, 273, -1, 275, 276, + 277, 278, 279, 258, 259, 260, 261, -1, 263, -1, + 265, 266, 267, 268, 269, 125, -1, 272, -1, -1, + 275, 276, 277, 278, 279, 258, 259, 260, 261, -1, + 263, -1, 265, 266, 267, 268, 269, -1, -1, 272, + -1, 10, 275, 276, 277, 278, 279, 258, 259, 260, + 261, -1, 263, 10, 265, 266, 267, 268, 269, -1, + -1, 272, -1, 257, 275, 276, 277, 278, 279, 38, + 264, -1, 41, 10, -1, -1, 270, 271, 10, 258, + 259, 38, 261, 262, 41, -1, 265, 266, 267, 268, + 59, -1, 10, 272, 273, -1, 275, 276, 277, 278, + 279, 38, 59, -1, 41, 257, 38, -1, 10, 41, + -1, -1, 264, -1, -1, -1, -1, 10, 270, 271, + 38, -1, 59, 41, 257, -1, -1, 59, -1, -1, + -1, 264, -1, -1, 10, -1, 38, 270, 271, 41, + -1, 59, 10, -1, -1, 38, -1, 257, 41, -1, + -1, -1, -1, -1, -1, -1, 125, 59, -1, -1, + 270, 271, 38, -1, -1, 41, 59, -1, 125, -1, + 38, -1, -1, 41, -1, -1, -1, -1, -1, -1, + -1, 36, -1, 59, -1, 40, -1, -1, 125, -1, + -1, 59, -1, 125, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, 125, 40, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 125, -1, -1, -1, -1, -1, 36, + -1, -1, 125, 40, -1, -1, -1, -1, -1, -1, + -1, 96, -1, -1, -1, -1, -1, -1, -1, 125, + -1, -1, -1, -1, -1, 36, -1, 125, -1, 40, + -1, -1, 94, -1, 96, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, + -1, 40, 41, -1, -1, -1, -1, -1, 257, 96, + -1, 123, -1, -1, -1, 264, -1, -1, -1, 36, + 257, 270, 271, 40, 41, -1, -1, 264, -1, -1, + -1, -1, -1, 270, 271, 96, 123, -1, -1, -1, + 257, -1, 36, -1, -1, 257, 40, -1, -1, -1, + -1, -1, 264, 270, 271, -1, -1, 96, 270, 257, + -1, -1, 123, -1, -1, -1, 264, -1, -1, -1, + -1, -1, 270, -1, -1, 257, 36, -1, -1, 96, + 40, -1, 264, -1, 257, -1, -1, -1, 270, -1, + -1, 264, -1, -1, -1, -1, -1, 270, -1, 36, + -1, 257, 96, 40, -1, -1, -1, -1, 264, 257, + -1, -1, -1, -1, 270, -1, 264, -1, -1, -1, + -1, -1, 270, 258, 259, 260, 261, 262, 263, 123, + 265, 266, 267, 268, 269, -1, 96, 272, 273, -1, + 275, 276, 277, 278, 279, -1, 258, 259, 260, 261, + -1, 263, -1, 265, 266, 267, 268, 269, -1, 96, + 272, -1, -1, 275, 276, 277, 278, 279, -1, 256, + -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, + 267, 268, -1, -1, -1, 272, 273, -1, 275, 276, + 277, 278, 279, -1, -1, -1, -1, 258, 259, 260, + 261, -1, 263, -1, 265, 266, 267, 268, 269, 36, + -1, 272, -1, 40, 275, 276, 277, 278, 279, 258, + 259, 260, 261, -1, 263, -1, 265, 266, 267, 268, + 269, -1, -1, 272, -1, -1, 275, 276, 277, 278, + 279, 258, 259, 260, 261, -1, 263, -1, 265, 266, + 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, + 277, 278, 279, -1, 258, 259, 260, 261, 262, 96, + -1, 265, 266, 267, 268, -1, -1, -1, 272, 273, + -1, 275, 276, 277, 278, 279, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 123, -1, 258, 259, + 260, 261, -1, 263, -1, 265, 266, 267, 268, 269, + -1, -1, 272, -1, -1, 275, 276, 277, 278, 279, + -1, 258, 259, 260, 261, -1, 263, -1, 265, 266, + 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, + 277, 278, 279, -1, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, + -1, -1, -1, -1, 18, -1, -1, -1, 22, -1, + -1, 25, -1, -1, -1, 29, -1, -1, -1, -1, + 22, -1, -1, 25, -1, -1, -1, 29, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, + -1, -1, 56, -1, -1, -1, -1, 61, -1, 51, + -1, -1, -1, -1, -1, 69, -1, -1, -1, 61, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, + 267, 268, -1, 97, -1, 272, 273, 101, 275, 276, + 277, 278, 279, -1, -1, 97, 110, 111, 112, 101, + -1, -1, -1, -1, -1, -1, -1, -1, 110, 111, + 112, -1, -1, -1, -1, -1, -1, 131, -1, -1, + -1, -1, -1, 137, 138, 139, -1, -1, 142, 131, + -1, 145, -1, -1, -1, 137, 138, 139, -1, -1, + 142, -1, -1, 145, +}; +#define YYFINAL 21 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 280 +#if YYDEBUG +const char * const yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,"'$'",0,"'&'",0,"'('","')'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0, +"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'^'",0, +"'`'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,"ANDAND","BACKBACK","BANG","CASE","COUNT","DUP","ELSE","END", +"FLAT","FN","FOR","IF","IN","OROR","PIPE","REDIR","SREDIR","SUB","SUBSHELL", +"SWITCH","TWIDDLE","WHILE","WORD","HUH", +}; +const char * const yyrule[] = { +"$accept : rc", +"rc : line end", +"rc : error end", +"end : END", +"end : '\\n'", +"cmdsa : cmd ';'", +"cmdsa : cmd '&'", +"line : cmd", +"line : cmdsa line", +"body : cmd", +"body : cmdsan body", +"cmdsan : cmdsa", +"cmdsan : cmd '\\n'", +"brace : '{' body '}'", +"paren : '(' body ')'", +"assign : first '=' word", +"epilog :", +"epilog : redir epilog", +"redir : DUP", +"redir : REDIR word", +"redir : SREDIR word", +"case : CASE words ';'", +"case : CASE words '\\n'", +"cbody : cmd", +"cbody : case cbody", +"cbody : cmdsan cbody", +"iftail : cmd", +"iftail : brace ELSE optnl cmd", +"cmd :", +"cmd : simple", +"cmd : brace epilog", +"cmd : IF paren optnl iftail", +"cmd : FOR '(' word IN words ')' optnl cmd", +"cmd : FOR '(' word ')' optnl cmd", +"cmd : WHILE paren optnl cmd", +"cmd : SWITCH '(' word ')' optnl '{' cbody '}'", +"cmd : TWIDDLE optcaret word words", +"cmd : cmd ANDAND optnl cmd", +"cmd : cmd OROR optnl cmd", +"cmd : cmd PIPE optnl cmd", +"cmd : redir cmd", +"cmd : assign cmd", +"cmd : BANG optcaret cmd", +"cmd : SUBSHELL optcaret cmd", +"cmd : FN words brace", +"cmd : FN words", +"optcaret :", +"optcaret : '^'", +"simple : first", +"simple : simple word", +"simple : simple redir", +"first : comword", +"first : first '^' sword", +"sword : comword", +"sword : keyword", +"word : sword", +"word : word '^' sword", +"comword : '$' sword", +"comword : '$' sword SUB words ')'", +"comword : COUNT sword", +"comword : FLAT sword", +"comword : '`' sword", +"comword : '`' brace", +"comword : BACKBACK word brace", +"comword : BACKBACK word sword", +"comword : '(' nlwords ')'", +"comword : REDIR brace", +"comword : WORD", +"keyword : FOR", +"keyword : IN", +"keyword : WHILE", +"keyword : IF", +"keyword : SWITCH", +"keyword : FN", +"keyword : ELSE", +"keyword : CASE", +"keyword : TWIDDLE", +"keyword : BANG", +"keyword : SUBSHELL", +"words :", +"words : words word", +"nlwords :", +"nlwords : nlwords '\\n'", +"nlwords : nlwords word", +"optnl :", +"optnl : optnl '\\n'", +}; +#endif +#if YYDEBUG +#include +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +int yystacksize; +#line 167 "parse.y" + +void initparse() { + star = treecpy(mk(nVar, mk(nWord,"*", NULL, FALSE)), ealloc); + nolist = treecpy(mk(nVar, mk(nWord,"ifs", NULL, FALSE)), ealloc); +} + +#line 583 "y.tab.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack() +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + i = yyssp - yyss; + newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : + (short *)malloc(newsize * sizeof *newss); + if (newss == NULL) + return -1; + yyss = newss; + yyssp = newss + i; + newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : + (YYSTYPE *)malloc(newsize * sizeof *newvs); + if (newvs == NULL) + return -1; + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +#ifndef YYPARSE_PARAM +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG void +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* ANSI-C/C++ */ +#else /* YYPARSE_PARAM */ +#ifndef YYPARSE_PARAM_TYPE +#define YYPARSE_PARAM_TYPE void * +#endif +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM; +#endif /* ANSI-C/C++ */ +#endif /* ! YYPARSE_PARAM */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yym, yyn, yystate; +#if YYDEBUG + register const char *yys; + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate])) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 47 "parse.y" +{ parsetree = yyvsp[-1].node; YYACCEPT; } +break; +case 2: +#line 48 "parse.y" +{ yyerrok; parsetree = NULL; YYABORT; } +break; +case 3: +#line 51 "parse.y" +{ if (!heredoc(1)) YYABORT; } +break; +case 4: +#line 52 "parse.y" +{ if (!heredoc(0)) YYABORT; } +break; +case 6: +#line 56 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? mk(nNowait,yyvsp[-1].node) : yyvsp[-1].node); } +break; +case 8: +#line 60 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? mk(nBody,yyvsp[-1].node,yyvsp[0].node) : yyvsp[0].node); } +break; +case 10: +#line 64 "parse.y" +{ yyval.node = (yyvsp[-1].node == NULL ? yyvsp[0].node : yyvsp[0].node == NULL ? yyvsp[-1].node : mk(nBody,yyvsp[-1].node,yyvsp[0].node)); } +break; +case 12: +#line 67 "parse.y" +{ yyval.node = yyvsp[-1].node; if (!heredoc(0)) YYABORT; } +break; +case 13: +#line 69 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 14: +#line 71 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 15: +#line 73 "parse.y" +{ yyval.node = mk(nAssign,yyvsp[-2].node,yyvsp[0].node); } +break; +case 16: +#line 75 "parse.y" +{ yyval.node = NULL; } +break; +case 17: +#line 76 "parse.y" +{ yyval.node = mk(nEpilog,yyvsp[-1].node,yyvsp[0].node); } +break; +case 18: +#line 79 "parse.y" +{ yyval.node = mk(nDup,yyvsp[0].dup.type,yyvsp[0].dup.left,yyvsp[0].dup.right); } +break; +case 19: +#line 80 "parse.y" +{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); + if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ + } +break; +case 20: +#line 83 "parse.y" +{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); + if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ + } +break; +case 21: +#line 87 "parse.y" +{ yyval.node = mk(nCase, yyvsp[-1].node); } +break; +case 22: +#line 88 "parse.y" +{ yyval.node = mk(nCase, yyvsp[-1].node); } +break; +case 23: +#line 90 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[0].node, NULL); } +break; +case 24: +#line 91 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } +break; +case 25: +#line 92 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } +break; +case 27: +#line 95 "parse.y" +{ yyval.node = mk(nElse,yyvsp[-3].node,yyvsp[0].node); } +break; +case 28: +#line 97 "parse.y" +{ yyval.node = NULL; } +break; +case 30: +#line 99 "parse.y" +{ yyval.node = mk(nBrace,yyvsp[-1].node,yyvsp[0].node); } +break; +case 31: +#line 100 "parse.y" +{ yyval.node = mk(nIf,yyvsp[-2].node,yyvsp[0].node); } +break; +case 32: +#line 101 "parse.y" +{ yyval.node = mk(nForin,yyvsp[-5].node,yyvsp[-3].node,yyvsp[0].node); } +break; +case 33: +#line 102 "parse.y" +{ yyval.node = mk(nForin,yyvsp[-3].node,star,yyvsp[0].node); } +break; +case 34: +#line 103 "parse.y" +{ yyval.node = mk(nWhile,yyvsp[-2].node,yyvsp[0].node); } +break; +case 35: +#line 104 "parse.y" +{ yyval.node = mk(nSwitch,yyvsp[-5].node,yyvsp[-1].node); } +break; +case 36: +#line 105 "parse.y" +{ yyval.node = mk(nMatch,yyvsp[-1].node,yyvsp[0].node); } +break; +case 37: +#line 106 "parse.y" +{ yyval.node = mk(nAndalso,yyvsp[-3].node,yyvsp[0].node); } +break; +case 38: +#line 107 "parse.y" +{ yyval.node = mk(nOrelse,yyvsp[-3].node,yyvsp[0].node); } +break; +case 39: +#line 108 "parse.y" +{ yyval.node = mk(nPipe,yyvsp[-2].pipe.left,yyvsp[-2].pipe.right,yyvsp[-3].node,yyvsp[0].node); } +break; +case 40: +#line 109 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 41: +#line 110 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 42: +#line 111 "parse.y" +{ yyval.node = mk(nBang,yyvsp[0].node); } +break; +case 43: +#line 112 "parse.y" +{ yyval.node = mk(nSubshell,yyvsp[0].node); } +break; +case 44: +#line 113 "parse.y" +{ yyval.node = mk(nNewfn,yyvsp[-1].node,yyvsp[0].node); } +break; +case 45: +#line 114 "parse.y" +{ yyval.node = mk(nRmfn,yyvsp[0].node); } +break; +case 49: +#line 120 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nArgs,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 50: +#line 121 "parse.y" +{ yyval.node = mk(nArgs,yyvsp[-1].node,yyvsp[0].node); } +break; +case 52: +#line 124 "parse.y" +{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } +break; +case 54: +#line 127 "parse.y" +{ yyval.node = mk(nWord, yyvsp[0].keyword, NULL, FALSE); } +break; +case 56: +#line 130 "parse.y" +{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } +break; +case 57: +#line 132 "parse.y" +{ yyval.node = mk(nVar,yyvsp[0].node); } +break; +case 58: +#line 133 "parse.y" +{ yyval.node = mk(nVarsub,yyvsp[-3].node,yyvsp[-1].node); } +break; +case 59: +#line 134 "parse.y" +{ yyval.node = mk(nCount,yyvsp[0].node); } +break; +case 60: +#line 135 "parse.y" +{ yyval.node = mk(nFlat, yyvsp[0].node); } +break; +case 61: +#line 136 "parse.y" +{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } +break; +case 62: +#line 137 "parse.y" +{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } +break; +case 63: +#line 138 "parse.y" +{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } +break; +case 64: +#line 139 "parse.y" +{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } +break; +case 65: +#line 140 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 66: +#line 141 "parse.y" +{ yyval.node = mk(nNmpipe,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); } +break; +case 67: +#line 142 "parse.y" +{ yyval.node = mk(nWord, yyvsp[0].word.w, yyvsp[0].word.m, yyvsp[0].word.q); } +break; +case 68: +#line 144 "parse.y" +{ yyval.keyword = "for"; } +break; +case 69: +#line 145 "parse.y" +{ yyval.keyword = "in"; } +break; +case 70: +#line 146 "parse.y" +{ yyval.keyword = "while"; } +break; +case 71: +#line 147 "parse.y" +{ yyval.keyword = "if"; } +break; +case 72: +#line 148 "parse.y" +{ yyval.keyword = "switch"; } +break; +case 73: +#line 149 "parse.y" +{ yyval.keyword = "fn"; } +break; +case 74: +#line 150 "parse.y" +{ yyval.keyword = "else"; } +break; +case 75: +#line 151 "parse.y" +{ yyval.keyword = "case"; } +break; +case 76: +#line 152 "parse.y" +{ yyval.keyword = "~"; } +break; +case 77: +#line 153 "parse.y" +{ yyval.keyword = "!"; } +break; +case 78: +#line 154 "parse.y" +{ yyval.keyword = "@"; } +break; +case 79: +#line 156 "parse.y" +{ yyval.node = NULL; } +break; +case 80: +#line 157 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } +break; +case 81: +#line 159 "parse.y" +{ yyval.node = NULL; } +break; +case 83: +#line 161 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } +break; +#line 1062 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/parse.h b/parse.h new file mode 100644 index 0000000..c193710 --- /dev/null +++ b/parse.h @@ -0,0 +1,37 @@ +#ifndef YYERRCODE +#define YYERRCODE 256 +#endif + +#define ANDAND 257 +#define BACKBACK 258 +#define BANG 259 +#define CASE 260 +#define COUNT 261 +#define DUP 262 +#define ELSE 263 +#define END 264 +#define FLAT 265 +#define FN 266 +#define FOR 267 +#define IF 268 +#define IN 269 +#define OROR 270 +#define PIPE 271 +#define REDIR 272 +#define SREDIR 273 +#define SUB 274 +#define SUBSHELL 275 +#define SWITCH 276 +#define TWIDDLE 277 +#define WHILE 278 +#define WORD 279 +#define HUH 280 +typedef union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} YYSTYPE; +extern YYSTYPE yylval; diff --git a/random.pl b/random.pl new file mode 100644 index 0000000..90998d5 --- /dev/null +++ b/random.pl @@ -0,0 +1,15 @@ +#! /usr/bin/perl + +$count = 10; +$size = rand(1000); + +for ($i = 0; $i < $count; ++$i) { + open OUT, "> t$i" or die; + for ($j = 0; $j < $size; ++$j) { + printf OUT "%c", rand(256); + } + close OUT; + $cmd = "./rc t$i"; + print $cmd, "\n"; + system $cmd; +} diff --git a/rc.1 b/rc.1 index b0e920c..af46aa6 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2003-07-17" +.TH RC 1 "2014-09-01" .SH NAME rc \- shell .SH SYNOPSIS @@ -2056,8 +2056,15 @@ The .Cr limit builtin silently ignores extra arguments. .PP +Backquote substitution never produces empty strings - multiple +consecutive occurrences of the separator are treated the same as a +single occurrence. +.Ds +.Cr "ifs=! { x = `{echo -n a!!b}; whatis x }" +.Cr "x=(a b) # NOT x=(a '' b)" +.PP Bug reports should be mailed to -.Cr "" . +.Cr "" . .SH INCOMPATIBILITIES Here is a list of features which distinguish this incarnation of .I rc @@ -2143,7 +2150,7 @@ Unix Research System, Tenth Edition, Volume 2. (Saunders College Publishing) .PP -.Cr http://www.star.le.ac.uk/~tjg/rc/misc/td , +.Cr http://static.tobold.org/rc/rc-duff.html , an updated version of the above paper. .PP .IR history (1) diff --git a/rc.h b/rc.h index a0ef908..21fe8c0 100644 --- a/rc.h +++ b/rc.h @@ -4,6 +4,10 @@ #include +#define RC "rc: " + +#include + /* datatypes */ #define ENV_SEP '\001' @@ -46,10 +50,6 @@ typedef enum bool { FALSE, TRUE } bool; -typedef enum inputtype { - iFd, iString -} inputtype; - typedef enum redirtype { rFrom, rCreate, rAppend, rHeredoc, rHerestring } redirtype; @@ -128,7 +128,7 @@ struct Format { /* for the formatting routines */ va_list args; long flags, f1, f2; - /* for the buffer maintainence routines */ + /* for the buffer maintenance routines */ char *buf, *bufbegin, *bufend; int flushed; void (*grow)(Format *, size_t); @@ -172,8 +172,7 @@ enum { /* main.c */ extern Rq *redirq; -extern bool dashdee, dashee, dashvee, dashex, dashell, - dasheye, dashen, dashpee, interactive; +extern bool dashdee, dashee, dashvee, dashex, dasheye, dashen, dashpee, interactive; extern pid_t rc_pid; extern int lineno; @@ -265,23 +264,6 @@ extern int heredoc(int); extern int qdoc(Node *, Node *); extern Hq *hq; - -/* input.c */ -extern void initinput(void); -extern Node *parseline(char *); -extern int gchar(void); -extern void ugchar(int); -extern Node *doit(bool); -extern void flushu(void); -extern void print_prompt2(void); -extern void pushfd(int); -extern void pushstring(char **, bool); -extern void popinput(void); -extern void closefds(void); -extern int lastchar; -extern bool rcrc; - - /* lex.c */ extern bool quotep(char *, bool); extern int yylex(void); @@ -344,38 +326,8 @@ extern int yyparse(void); extern void initparse(void); /* readline */ - -#if READLINE - -/* Including the real readline .h files is too complicated, so we just -declare what we actually use. */ - -extern void add_history(char *); -extern char *readline(char *); -extern int rl_clear_signals(void); -extern int rl_pending_input; -extern int rl_reset_terminal(char *); - -#if READLINE_OLD -extern void rl_clean_up_for_exit(void); -extern void rl_deprep_terminal(void); -#else -extern void _rl_clean_up_for_exit(void); -extern void (*rl_deprep_term_function)(void); -#endif - -extern char *rc_readline(char *); - extern volatile sig_atomic_t rl_active; extern struct Jbwrap rl_buf; -#endif - -#if EDITLINE -extern char *readline(char *); -extern void add_history(char *); -#define rc_readline readline -#endif - /* redir.c */ extern void doredirs(void); @@ -386,6 +338,7 @@ extern void initsignal(void); extern void catcher(int); extern void sigchk(void); extern void (*rc_signal(int, void (*)(int)))(int); +extern void (*sys_signal(int, void (*)(int)))(int); extern void (*sighandlers[])(int); diff --git a/rc.spec b/rc.spec new file mode 100644 index 0000000..337964c --- /dev/null +++ b/rc.spec @@ -0,0 +1,31 @@ +%define name rc +%define version 1.7.1 +%define release 1 + +Summary: rc - the Plan 9 and Tenth Edition shell +Name: %name +Version: %version +Release: %release +Group: Shells +License: distributable +Source0: http://www.libra-aries-books.co.uk/software/rc/release/%name-%version.tar.gz +Buildroot: /var/tmp/%{name}-rpmroot + +%description +This is a reimplementation for Unix, by Byron Rakitzis, of the Plan 9 +shell. rc offers much the same capabilities as a traditional Bourne +shell, but with a much cleaner syntax. + +%prep +%setup + +%build +sh configure --with-readline --prefix "$RPM_BUILD_ROOT" --mandir "$RPM_BUILD_ROOT/usr/share/man" +make + +%install +make install + +%files +/bin/rc +/usr/share/man/man1/rc.1.gz diff --git a/signal.c b/signal.c index b5cbe63..037be1d 100644 --- a/signal.c +++ b/signal.c @@ -9,7 +9,7 @@ #include "jbwrap.h" #if HAVE_SIGACTION -static void (*sys_signal(int signum, void (*handler)(int)))(int) { +void (*sys_signal(int signum, void (*handler)(int)))(int) { struct sigaction new, old; new.sa_handler = handler; @@ -19,7 +19,9 @@ static void (*sys_signal(int signum, void (*handler)(int)))(int) { return old.sa_handler; } #else -#define sys_signal(sig, func) (signal((sig), (func))) +void (*sys_signal(int signum, void (*handler)(int)))(int) { + return signal(signum, handler); +} #endif void (*sighandlers[NUMOFSIGNALS])(int); @@ -33,11 +35,6 @@ extern void catcher(int s) { } sys_signal(s, catcher); -#if READLINE - if (rl_active) - siglongjmp(rl_buf.j, s); -#endif /* READLINE */ - #if HAVE_RESTARTABLE_SYSCALLS if (slow) { siglongjmp(slowbuf.j, s); @@ -73,13 +70,11 @@ extern void (*rc_signal(int s, void (*h)(int)))(int) { void (*old)(int); sigchk(); old = sighandlers[s]; - if (h == SIG_DFL || h == SIG_IGN) { - sighandlers[s] = h; + sighandlers[s] = h; + if (h == SIG_DFL || h == SIG_IGN) sys_signal(s, h); - } else { - sighandlers[s] = h; + else sys_signal(s, catcher); - } return old; } diff --git a/slow b/slow new file mode 100644 index 0000000..dcd19ce --- /dev/null +++ b/slow @@ -0,0 +1,11 @@ +for (i in 0 1 2 3 4 5 6 7 8 9) { + x=() + y=() + for (j in 0 1 2 3 4 5 6 7 8 9) + for (k in 0 1 2 3 4 5 6 7 8 9) + for (l in 0 1 2 3 4 5 6 7 8 9) { + x = $x^. + y = ($y $x) + } + echo $#y +} diff --git a/stamp-h b/stamp-h new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h @@ -0,0 +1 @@ +timestamp diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/testcld.c b/testcld.c new file mode 100644 index 0000000..83212e9 --- /dev/null +++ b/testcld.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +int main(void) { + int i; + sigset(SIGCLD, SIG_IGN); + switch (fork()) { + case -1: + return 1; + case 0: + return 0; + default: + sleep(1); + if (wait(&i) == -1 && errno == ECHILD) return 0; + else return 1; + } +} diff --git a/tmp b/tmp new file mode 100644 index 0000000..1b54a36 --- /dev/null +++ b/tmp @@ -0,0 +1,2 @@ +x=('#' '#' '#') +eval z^`{whatis -v x} >[2]/dev/null diff --git a/tree.c b/tree.c index 37db4cd..60b42e3 100644 --- a/tree.c +++ b/tree.c @@ -81,7 +81,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(size_t)) { n->u[2].i = s->u[2].i; break; case nWord: - n = (*alloc)(offsetof(Node, u[2])); + n = (*alloc)(offsetof(Node, u[3])); n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s); if (s->u[1].s != NULL) { size_t i = strlen(s->u[0].s); @@ -89,6 +89,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(size_t)) { memcpy(n->u[1].s, s->u[1].s, i); } else n->u[1].s = NULL; + n->u[2].i = s->u[2].i; break; case nBang: case nNowait: case nCase: case nCount: case nFlat: case nRmfn: case nSubshell: case nVar: diff --git a/trip.rc b/trip.rc index 734429c..ed9c75d 100644 --- a/trip.rc +++ b/trip.rc @@ -4,9 +4,10 @@ rc=$0 echo tripping $rc $version +tmpdir='' fn fail { echo >[1=2] trip took a wrong turn: $* - rm -f $tmp + rm -rf $tmpdir fn sigexit exit 1 } @@ -23,8 +24,8 @@ fn sigexit sigint sigquit sigsegv fn sigexit { echo trip complete } -tmp=/tmp/trip.$pid -rm -f $tmp +tmpdir=`{ mktemp -t -d rc-trip.XXXXXX } +tmp=$tmpdir/tmp nl=' ' @@ -51,19 +52,19 @@ if (false) { # WARNING: this differs from sh umask 0 > $tmp x=`{ls -l $tmp} -if (!~ $x(1) '-rw-rw-rw-') fail umask 0 produced incorrect result: $x(1) +if (!~ $x(1) -rw-rw-rw-*) fail umask 0 produced incorrect result: $x(1) rm -f $tmp umask 027 > $tmp y=`{ls -l $tmp} -if (!~ $y(1) '-rw-r-----') fail umask 027 produced incorrect file: $y(1) +if (!~ $y(1) -rw-r-----*) fail umask 027 produced incorrect file: $y(1) rm -f $tmp if (!~ `umask 027) fail umask reported bad value: `umask submatch 'umask bad' 'bad umask' 'bad umask' submatch 'umask -027' 'bad umask' 'bad umask' submatch 'umask 999999' 'bad umask' 'bad umask' -submatch 'umask hi there' 'too many arguments to umask' 'umask arg count' +submatch 'umask hi there' 'rc: too many arguments to umask' 'umask arg count' if (!~ `umask 027) fail bad umask changed umask value to `umask @@ -85,8 +86,8 @@ rm -f 1 2 expect error from cat, closing stdin cat >[0=] -submatch 'cat>(1 2 3)' 'multi-word filename in redirection' 'redirection error' -submatch 'cat>()' 'null filename in redirection' 'redirection error' +submatch 'cat>(1 2 3)' 'rc: multi-word filename in redirection' 'redirection error' +submatch 'cat>()' 'rc: null filename in redirection' 'redirection error' # # blow the input stack @@ -111,7 +112,7 @@ eval eval eval eval eval eval eval eval eval eval eval echo hi # heredocs and herestrings # -bigfile=/tmp/big.$pid +bigfile=$tmpdir/big.$pid od $rc | sed 5000q > $bigfile abc=(this is a) x=() @@ -140,11 +141,11 @@ eof } '$') fail quoting '$' in heredoc -submatch 'cat< /tmp/$pid.lw +echo here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe. > $tmpdir/$pid.lw -echo 'here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.' > /tmp/$pid.lq +echo 'here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.' > $tmpdir/$pid.lq -if (!~ ``(){cat /tmp/$pid.lw} ``(){cat /tmp/$pid.lq}) +if (!~ ``(){cat $tmpdir/$pid.lw} ``(){cat $tmpdir/$pid.lq}) fail expected long string and long word to be identical -if (! x=`{wc -c /tmp/$pid.lw} ~ $x(1) 1088) +if (! x=`{wc -c $tmpdir/$pid.lw} ~ $x(1) 1088) fail expected long word to be 1088 bytes -if (! x=`{wc -c /tmp/$pid.lq} ~ $x(1) 1088) +if (! x=`{wc -c $tmpdir/$pid.lq} ~ $x(1) 1088) fail expected long quote to be 1088 bytes -rm /tmp/$pid.lw -rm /tmp/$pid.lq +rm $tmpdir/$pid.lw +rm $tmpdir/$pid.lq -submatch 'echo hi |[2' 'expected ''='' or '']'' after digit' 'scan error' -submatch 'echo hi |[92=]' 'expected digit after ''=''' 'scan error' -submatch 'echo hi |[a]' 'expected digit after ''[''' 'scan error' -submatch 'echo hi |[2-' 'expected ''='' or '']'' after digit' 'scan error' -submatch 'echo hi |[2=99a]' 'expected '']'' after digit' 'scan error' -submatch 'echo hi |[2=a99]' 'expected digit or '']'' after ''=''' 'scan error' -submatch 'echo ''hi' 'eof in quoted string' 'scan error' +submatch 'echo hi |[2' 'rc: expected ''='' or '']'' after digit' 'scan error' +submatch 'echo hi |[92=]' 'rc: expected digit after ''=''' 'scan error' +submatch 'echo hi |[a]' 'rc: expected digit after ''[''' 'scan error' +submatch 'echo hi |[2-' 'rc: expected ''='' or '']'' after digit' 'scan error' +submatch 'echo hi |[2=99a]' 'rc: expected '']'' after digit' 'scan error' +submatch 'echo hi |[2=a99]' 'rc: expected digit or '']'' after ''=''' 'scan error' +submatch 'echo ''hi' 'rc: eof in quoted string' 'scan error' ifs='' { if (!~ 'h i' `{echo -n h\ @@ -197,7 +198,7 @@ if (! $rc -c '# eof in comment') # test the syntax error printer -prompt='' if (!~ `` $nl {$rc -cif>[2=1]} 'line 1: '*' error near if') +prompt='' if (!~ `` $nl {$rc -cif>[2=1]} 'rc: line 1: '*' error near if') fail print syntax error prompt='' if (!~ `` $nl {$rc -icif>[2=1]} *' error') @@ -226,9 +227,9 @@ bar if (!~ $i 3) fail return inside loop inside function failed -submatch return 'return outside of function' 'return outside of function' -submatch 'break 1' 'too many arguments to break' 'break arg count' -submatch break 'break outside of loop' 'break outside of loop' +submatch return 'rc: return outside of function' 'return outside of function' +submatch 'break 1' 'rc: too many arguments to break' 'break arg count' +submatch break 'rc: break outside of loop' 'break outside of loop' for (i in 1 2 3 4 5) if (~ $i 2) @@ -236,7 +237,7 @@ for (i in 1 2 3 4 5) if (!~ $i 2) fail break out of loop -submatch 'wait foo' 'foo is a bad number' 'bogus argument to wait' +submatch 'wait foo' 'rc: `foo'' is a bad number' 'bogus argument to wait' if (~ `{echo -n} ?) fail echo -n @@ -303,7 +304,7 @@ if (~ `{whatis limit >[2]/dev/null} builtin) { fn cd -submatch 'cd a b c' 'too many arguments to cd' 'cd arg count' +submatch 'cd a b c' 'rc: too many arguments to cd' 'cd arg count' $rc -c 'cdpath=() cd /frobnatz' >[2]/dev/null && fail 'cd to /frobnatz succeeded!?' submatch 'cdpath='''' cd frobnatz' 'couldn''t cd to frobnatz' 'cd to frobnatz succeeded!?' @@ -315,7 +316,7 @@ submatch 'cdpath='''' cd frobnatz' 'couldn''t cd to frobnatz' 'cd to frobnatz su # wait # -submatch 'wait 1 2 3' 'too many arguments to wait' 'arg count' +submatch 'wait 1 2 3' 'rc: too many arguments to wait' 'wait arg count' $rc -c 'wait 1' >[2]/dev/null && fail wait 1 sleep 3& @@ -329,9 +330,9 @@ if (~ `` '' {wait} ?) # # matching # -touch /tmp/abc.$pid /tmp/bbc.$pid -mkdir /tmp/dir.$pid /tmp/dip.$pid -touch /tmp/dir.$pid/^(a b c) /tmp/dip.$pid/^(a b c) +touch $tmpdir/abc.$pid $tmpdir/bbc.$pid +mkdir $tmpdir/dir.$pid $tmpdir/dip.$pid +touch $tmpdir/dir.$pid/^(a b c) $tmpdir/dip.$pid/^(a b c) if (!~ 123 [~x]?[0-9]) fail match @@ -352,18 +353,18 @@ if (~ x [y]) if (~ x x?) fail too many characters in pattern -sh -c 'test -f /////tmp//////a?c.'^$pid || fail glob with many slashes -if (!~ /////tmp//////a*.$pid /////tmp//////a?c.$pid) +sh -c 'test -f /////$tmpdir//////a?c.'^$pid || fail glob with many slashes +if (!~ /////$tmpdir//////a*.$pid /////$tmpdir//////a?c.$pid) fail glob with many slashes -if (!~ ////tmp////di?.$pid////* ////tmp////dir.$pid////*b*) +if (!~ ////$tmpdir////di?.$pid////* ////$tmpdir////dir.$pid////*b*) fail glob with more slashes -if (! @{cd /; ~ */a*.$pid tmp/a*}) +if (! @{cd $tmpdir; ~ *.$pid/a d*/*}) fail glob in current directory -if (!~ /tmp/?bc.$pid /tmp/bbc.$pid) +if (!~ $tmpdir/?bc.$pid $tmpdir/bbc.$pid) fail match of bbc.$pid against '('abc.$pid bbc.$pid')' -rm /tmp/abc.$pid /tmp/bbc.$pid -rm -rf /tmp/dir.$pid /tmp/dip.$pid +rm $tmpdir/abc.$pid $tmpdir/bbc.$pid +rm -rf $tmpdir/dir.$pid $tmpdir/dip.$pid # # signals @@ -377,12 +378,12 @@ fn sigint # $rc -c /frobnatz >[2]/dev/null && fail 'search error' -touch /tmp/noexec.$pid -chmod a-x /tmp/noexec.$pid -$rc -c /tmp/noexec.$pid >[2]/dev/null && fail /tmp/noexec.$pid is found!? -rm /tmp/noexec.$pid +touch $tmpdir/noexec.$pid +chmod a-x $tmpdir/noexec.$pid +$rc -c $tmpdir/noexec.$pid >[2]/dev/null && fail $tmpdir/noexec.$pid is found!? +rm $tmpdir/noexec.$pid -submatch 'path='''' frobnatz' 'frobnatz not found' 'search error' +submatch 'path='''' frobnatz' 'rc: cannot find `frobnatz''' 'search error' {path=() /bin/sh -c 'exit 0'} || fail abs pathname with path set to null @@ -409,15 +410,15 @@ if (~ `` '' . ?*) if (~ `` '' {. -i} ?*) fail null dot -i -cat > /tmp/dot.$pid << eof +cat > $tmpdir/dot.$pid << eof echo hi eof -prompt=';' if (!~ `` '' {. -i /tmp/dot.$pid>[2=1]} ';hi'^$nl';') +prompt=';' if (!~ `` '' {. -i $tmpdir/dot.$pid>[2=1]} ';hi'^$nl';') fail dot -i -submatch .' '/tmp/dot.$pid hi dot +submatch .' '$tmpdir/dot.$pid hi dot -rm /tmp/dot.$pid +rm $tmpdir/dot.$pid $rc -c '. /frobnatz' >[2]/dev/null && fail 'dot of a nonexistent file' @@ -459,7 +460,7 @@ foo=nest *=nest { ~ $* bar || fail restore of '$*' after local group ~ `{exec>[2=1];$rc -xc 'foo=()'} 'foo=()' || fail -x echo of variable deletion -fn_ff='{' prompt='' if (!~ `` $nl {$rc -cff>[2=1]} 'line 1: '*' error near eof') +fn_ff='{' prompt='' if (!~ `` $nl {$rc -cff>[2=1]} 'rc: line 1: '*' error near eof') fail 'bogus function in environment' # @@ -509,8 +510,8 @@ switch (nothing) { ~ $i frobnatz || fail match '*' in switch -submatch '()=()' 'null variable name' 'assignment diagnostic' -submatch 'fn () {eval}' 'null function name' 'assigning null function name' +submatch '()=()' 'rc: null variable name' 'assignment diagnostic' +submatch 'fn () {eval}' 'rc: null function name' 'assigning null function name' # # prompt @@ -522,19 +523,19 @@ fn prompt # # history # -history=/tmp/hist.$pid prompt='' echo 'history=()' | $rc -i +history=$tmpdir/hist.$pid prompt='' echo 'history=()' | $rc -i -if (!~ `{cat /tmp/hist.$pid} 'history=()') +if (!~ `{cat $tmpdir/hist.$pid} 'history=()') fail output to history file -history=/tmp/hist.$pid prompt='' echo 'history=()' | $rc -i +history=$tmpdir/hist.$pid prompt='' echo 'history=()' | $rc -i -if (!~ `` () {cat /tmp/hist.$pid} 'history=() +if (!~ `` () {cat $tmpdir/hist.$pid} 'history=() history=() ') fail append to history file -rm /tmp/hist.$pid +rm $tmpdir/hist.$pid if (!~ `{history=/frobnatz/foo prompt='' echo eval | $rc -i >[2=1]} ?*) fail accessing bad history file @@ -564,7 +565,7 @@ x=/* # fn sigexit should be cleared in children x = () -expect nonesuch not found +expect rc: cannot find '`nonesuch''' x = `{true | nonesuch}; if (~ $x trip) fail sigexit in children x = `{ < /dev/null wc |grep xxx }; if (~ $x trip) fail sigexit in children x = `{{ wc | wc } < /dev/null }; if (~ $x trip) fail sigexit in children @@ -575,7 +576,7 @@ x = `{{ wc | wc } < /dev/null }; if (~ $x trip) fail sigexit in children # check for ctrl-a bug x=`{./tripping a} -# ~ `{$rc -c 'echo $x'} $x || fail ctrl-a bug detected +~ `{$rc -c 'echo $x'} $x || fail ctrl-a bug detected # check for hilarious quoting bug introduced while fixing ctrl-a x=('#' '#' '#') @@ -584,13 +585,15 @@ eval z^`{whatis -v x} # parens bypass quote detector bug fn x {echo x.y $(x.y)} -~ ``''{whatis -f x} 'fn x {echo x.y $''x.y''} +~ ``''{whatis -f x} 'fn x {echo x.y $(x^.y)} ' || fail sneaky parens bug # before rc-1.7.1, certain glob patterns could fail on broken symlinks -mkdir $tmp.qux -ln -s /frobnatz $tmp.qux/foo -x=$tmp.qux/foo* -~ $x $tmp.qux/foo || { rm -rf $tmp.qux; fail broken symlink globbing } -x=$tmp.qux*/foo -~ $x $tmp.qux/foo || { rm -rf $tmp.qux; fail broken symlink globbing } +mkdir $tmpdir/qux +ln -s /frobnatz $tmpdir/qux/foo +x=$tmpdir/qux/foo* +~ $x $tmpdir/qux/foo || { rm -rf $tmpdir/qux; fail broken symlink globbing } +x=$tmpdir/qux*/foo +~ $x $tmpdir/qux/foo || { rm -rf $tmpdir/qux; fail broken symlink globbing } + +rm -rf $tmpdir diff --git a/utils.c b/utils.c index 14a55ff..482f7a7 100644 --- a/utils.c +++ b/utils.c @@ -12,9 +12,9 @@ extern void pr_error(char *s, int offset) { if (s != NULL) { if (interactive) - fprint(2, "%s\n", s); + fprint(2, RC "%s\n", s); else - fprint(2, "line %d: %s\n", lineno + offset, s); + fprint(2, RC "line %d: %s\n", lineno + offset, s); } } @@ -27,9 +27,9 @@ extern void uerror(char *s) { if (!err) err = "unknown error"; if (s) - fprint(2, "%s: %s\n", s, err); + fprint(2, RC "%s: %s\n", s, err); else - fprint(2, "%s\n", err); + fprint(2, RC "%s\n", err); } /* Die horribly. This should never get called. Please let me know if it does. */ diff --git a/var.c b/var.c index ee8c228..2fa7c35 100644 --- a/var.c +++ b/var.c @@ -2,6 +2,8 @@ #include "rc.h" +#include "input.h" + static void colonassign(char *, List *, bool); static void listassign(char *, List *, bool); static int hasalias(char *); @@ -19,10 +21,8 @@ extern void varassign(char *name, List *def, bool stack) { new->def = newdef; new->extdef = NULL; set_exportable(name, TRUE); -#if READLINE - if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) - rl_reset_terminal(NULL); -#endif + if (streq(name, "TERM") || streq(name, "TERMCAP")) + termchange(); } /* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */ diff --git a/which.c b/which.c index 8abdc60..798d7b0 100644 --- a/which.c +++ b/which.c @@ -1,7 +1,7 @@ /* which.c: check to see if a file is executable. This function was originally written with Maarten Litmaath's which.c as - a template, but was changed in order to accomodate the possibility of + a template, but was changed in order to accommodate the possibility of rc's running setuid or the possibility of executing files not in the primary group. Much of this file has been re-vamped by Paul Haahr. I re-re-vamped the functions that Paul supplied to correct minor bugs @@ -10,6 +10,7 @@ #include "rc.h" +#include #include #include @@ -70,6 +71,19 @@ static bool rc_access(char *path, bool verbose) { return FALSE; } +/* replace non-printing characters with question marks in a freshly + * allocated string */ +static char *protect(char *in) { + int l = strlen(in); + char *out = ealloc(l + 1); + int i; + + for (i = 0; i < l; ++i) + out[i] = isprint(in[i]) ? in[i] : '?'; + out[i] = '\0'; + return out; +} + /* return a full pathname by searching $path, and by checking the status of the file */ extern char *which(char *name, bool verbose) { @@ -119,7 +133,10 @@ extern char *which(char *name, bool verbose) { if (rc_access(test, FALSE)) return test; } - if (verbose) - fprint(2, "%s not found\n", name); + if (verbose) { + char *n = protect(name); + fprint(2, RC "cannot find `%s'\n", n); + efree(n); + } return NULL; } -- cgit v1.2.3 From c68ac7eedea03d0c21cbfbb57704fda65a1c9cc3 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Tue, 21 Apr 2015 21:39:24 +0100 Subject: release: rc-1.7.3 --- AUTHORS | 6 ++-- COPYING | 48 +++++++++++++------------- ChangeLog | 36 ++++++++++++++++++++ Makefile.am | 6 ++-- NEWS | 22 ++++++------ README | 4 +-- ReleaseTime | 1 - acinclude.m4 | 13 ++++--- configure.ac | 34 +++++++++++------- edit-edit.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ edit-editline.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ edit-readline.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++ edit-vrl.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ input.c | 1 + lex.c | 2 +- print.c | 12 +++---- proto.h | 10 +++--- rc.1 | 9 ++++- rc.h | 2 -- rc.spec | 10 +++--- 20 files changed, 518 insertions(+), 80 deletions(-) create mode 100644 edit-edit.c create mode 100644 edit-editline.c create mode 100644 edit-readline.c create mode 100644 edit-vrl.c diff --git a/AUTHORS b/AUTHORS index 3414e61..d231e38 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,7 @@ -The current maintainer of rc is Toby Goodwin . Please -send all bug reports to him. +The current maintainer of rc is Toby Goodwin . Please +send all bug reports to him, or via github: + + https://github.com/rakitzis/rc/issues This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr for letting me know what a shell should do and for contributing certain diff --git a/COPYING b/COPYING index 17e0588..8f2dc71 100644 --- a/COPYING +++ b/COPYING @@ -1,26 +1,24 @@ /* - * Copyright 1991, 2001, 2002 by Byron Rakitzis. All rights reserved. - * - * This software is not subject to any license of the American Telephone - * and Telegraph Company or of the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on - * any computer system, and to alter it and redistribute it freely, subject - * to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits must appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits must appear in the documentation. - * - * 4. This notice may not be removed or altered. - * - * [this copyright notice is adapted from Henry Spencer's - * "awf" copyright notice.] - */ +Copyright (c) 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment (see the following) in the product +documentation is required. + + Portions Copyright (c) 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ diff --git a/ChangeLog b/ChangeLog index 466b825..f1066c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -854,3 +854,39 @@ Changes since rc-1.5b2 Zekoll). Feature: allow $"x as a synonym for $^x + + Release: rc-1.7.2. + +2015-04-03 + + Packaging: the rc.spec file was very out-of-date. + +2015-04-04 + + Portability: the comment from 1999-08-19 may well have been true at + the time, but the final version of the C99 standard called varargs + copying macro va_copy(). + +2015-04-07 + + Portability: look in -ltinfo for tgetent. + + Packaging: various autoconf / automake updates and tweaks. + +2015-04-14 + + Bug: in initinput(), the call ugchar(EOF) used the ungetcount member + of the top Input structure without initializing it. Thanks to Jeff + Johnson for finding this, Robert Scheck for reporting it, and Uli + Drepper for implementing MALLOC_PERTURB_, a cheap way to find uses of + uninitialized memory. + +2015-04-18 + + Licensing: tweaked to match exactly the "zlib with acknowledgement" + license which is used by nunit and is already approved by various + distros. + +2015-04-20 + + Release: rc-1.7.3. diff --git a/Makefile.am b/Makefile.am index e739725..00c5dff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ noinst_PROGRAMS = mksignal mkstatval tripping $(HISTORY) rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c hash.c heredoc.c input.c lex.c list.c main.c match.c nalloc.c open.c parse.c print.c redir.c signal.c status.c tree.c utils.c var.c wait.c walk.c which.c -EXTRA_rc_SOURCES = addon.c edit-bsd.c edit-gnu.c edit-null.c execve.c system.c system-bsd.c +EXTRA_rc_SOURCES = addon.c edit-edit.c edit-editline.c edit-null.c edit-readline.c edit-vrl.c execve.c system.c system-bsd.c rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM) rc_LDADD = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM) @@ -33,7 +33,7 @@ noinst_HEADERS = edit.h getgroups.h input.h jbwrap.h parse.h proto.h rc.h rlimit BUILT_SOURCES = sigmsgs.c -EXTRA_DIST = EXAMPLES RELDATE addon.c addon.h history.1 parse.y rc.1 trip.rc +EXTRA_DIST = EXAMPLES addon.c addon.h history.1 parse.y rc.1 trip.rc sigmsgs.c sigmsgs.h: mksignal ./mksignal @@ -45,8 +45,6 @@ status.o: statval.h statval.h: mkstatval ./mkstatval > statval.h -CONFIGURE_DEPENDENCIES = RELDATE - DISTCLEANFILES = sigmsgs.c sigmsgs.h statval.h # Of course, parse.c and parse.h depend on parse.y. However, unless diff --git a/NEWS b/NEWS index 4bf4fe1..32c2879 100644 --- a/NEWS +++ b/NEWS @@ -7,17 +7,19 @@ was removed, as this causes indigestion on file systems that don't support sparse files (the configuration and implementation of large file support is still present of course). -Bug fixes. Fix for CVE-2014-1936. Broken symlinks now glob correctly. -The variables $prompt and $version are now exported if they are -inherited from the environment when rc starts. EIO handling is now -enabled for readline too. A few bogosities in the history program were -fixed. A regression introduced by the fix for the $(a.b) quoting bug was -fixed, and that bug was correctly fixed. +Bug fixes. Fix a use of uninitialized memory. Fix for CVE-2014-1936. +Broken symlinks now glob correctly. The variables $prompt and $version +are now exported if they are inherited from the environment when rc +starts. EIO handling is now enabled for readline too. A few bogosities +in the history program were fixed. A regression introduced by the fix +for the $(a.b) quoting bug was fixed, and that bug was correctly fixed. -New features. Filename completion with GNU readline now quotes special -characters. +New features. Added $"x as a synonym for $^x. Minimal support for +various alternative line editing libraries. Filename completion with GNU +readline now quotes special characters. -Documentation. Minor updates only. +Documentation. Licence updated to use exactly the text of the zlib- +with-acknowledgement licence. Toby Goodwin -2014-09-01 +2015-04-20 diff --git a/README b/README index f952ba2..542a516 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -This is release rc-1.7.2. +This is release rc-1.7.3. See COPYING for copying information. All files are - Copyright 1991, 2001, 2002, 2003, 2014 Byron Rakitzis. + Copyright 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis. See INSTALL for build and installation information. diff --git a/ReleaseTime b/ReleaseTime index dfa9ea0..7dc6210 100755 --- a/ReleaseTime +++ b/ReleaseTime @@ -2,6 +2,5 @@ ChangeLog NEWS README -RELDATE configure.ac rc.1 diff --git a/acinclude.m4 b/acinclude.m4 index 96ec096..3f9ec93 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -197,11 +197,14 @@ main() { dnl Where is tgetent()? AC_DEFUN([RC_LIB_TGETENT], [ - AC_CHECK_LIB(termcap, tgetent, - rc_lib_tgetent=-ltermcap, - AC_CHECK_LIB(ncurses, tgetent, - rc_lib_tgetent=-lncurses, - AC_MSG_ERROR(tgetent not found) + AC_CHECK_LIB(tinfo, tgetent, + rc_lib_tgetent=-ltinfo, + AC_CHECK_LIB(termcap, tgetent, + rc_lib_tgetent=-ltermcap, + AC_CHECK_LIB(ncurses, tgetent, + rc_lib_tgetent=-lncurses, + AC_MSG_ERROR(tgetent not found) + ) ) ) ]) diff --git a/configure.ac b/configure.ac index d12714a..cf41b32 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ dnl Our package name, version, ... -AC_INIT([rc], [1.7.2]) +AC_INIT([rc], [1.7.3]) dnl ... and release date RELDATE=`date -I` @@ -9,11 +9,10 @@ dnl Get things going... AC_CONFIG_SRCDIR([rc.h]) AM_INIT_AUTOMAKE -AM_CONFIG_HEADER(config.h) +AC_CONFIG_HEADERS(config.h) dnl Find a standard C compiler AC_PROG_CC -AM_PROG_CC_STDC dnl If we're using gcc, specify `-Wall'. I've also checked the code dnl with `-pedantic -W -Wall -Wpointer-arith -Wstrict-prototypes @@ -170,21 +169,30 @@ AC_SUBST(ADDON) EDIT=edit-null.o -AC_ARG_WITH(edit, [ --with-edit=(bsd,edit,gnu,vrl) Command line editing library], [ +AC_ARG_WITH(edit, [ --with-edit=(edit,editline,readline,vrl) Command line editing library], [ case $withval in yes) AC_MSG_ERROR(must specify which library) # might consider searching ;; - bsd) - EDIT=edit-bsd.o + no|null) + ;; + edit|bsd) + EDIT=edit-edit.o RC_LIB_TGETENT AC_CHECK_LIB(edit, el_init, [ LIBS="$LIBS -ledit $rc_lib_tgetent" + ], AC_MSG_ERROR(edit library not found), $rc_lib_tgetent) + ;; + editline) + EDIT=edit-editline.o + RC_LIB_TGETENT + AC_CHECK_LIB(editline, el_ring_bell, [ + LIBS="$LIBS -leditline $rc_lib_tgetent" ], AC_MSG_ERROR(editline library not found), $rc_lib_tgetent) ;; - gnu) - EDIT=edit-gnu.o + readline|gnu) + EDIT=edit-readline.o RC_LIB_TGETENT AC_CHECK_LIB(readline, readline, [ LIBS="$LIBS -lreadline $rc_lib_tgetent" @@ -196,10 +204,12 @@ AC_ARG_WITH(edit, [ --with-edit=(bsd,edit,gnu,vrl) Command line editing librar rl_catch_signals = 0; ], [], AC_MSG_ERROR(readline >= 4.0 not found)) ;; - no|null) - ;; - edit|vrl) - EDIT=edit-$withval.o + vrl) + EDIT=edit-vrl.o + RC_LIB_TGETENT + AC_CHECK_LIB(vrl, iline_peekch, [ + LIBS="$LIBS -lvrl $rc_lib_tgetent" + ], AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent) ;; *) AC_MSG_ERROR(unknown editing library $withval) diff --git a/edit-edit.c b/edit-edit.c new file mode 100644 index 0000000..c2a5260 --- /dev/null +++ b/edit-edit.c @@ -0,0 +1,91 @@ +#include "rc.h" + +#include + +#include + +#include "edit.h" + +bool editing = 1; + +struct cookie { + EditLine *el; + History *hist; +}; + +static char *prompt; + +void *edit_begin(int fd) { + FILE *f; + HistEvent he; + struct cookie *c; + + c = ealloc(sizeof *c); + if (fd == 0) + f = stdin; + else + f = fdopen(fd, "r"); + c->el = el_init("rc", f, stdout, stderr); + el_set(c->el, EL_SIGNAL, 0); + el_source(c->el, NULL); + + c->hist = history_init(); + history(c->hist, &he, H_SETSIZE, 20); + el_set(c->el, EL_HIST, history, c->hist); + + return c; +} + + +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +char *edit_alloc(void *cookie, size_t *count) { + const char *r; + HistEvent he; + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + r = el_gets(c->el, count); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (r) + history(c->hist, &he, H_ENTER, r); + return (char *)r; /* cast to avoid gcc warning */ +} + +static char *edit_prompter(EditLine *e) { + return prompt; +} + +void edit_prompt(void *cookie, char *pr) { + struct cookie *c = cookie; + + prompt = pr; + el_set(c->el, EL_PROMPT, edit_prompter); +} + +void edit_free(void *cookie) { + /* this function deliberately left blank */ +} + +void edit_end(void *cookie) { + struct cookie *c = cookie; + + el_end(c->el); + history_end(c->hist); + efree(c); +} + +void edit_reset(void *cookie) { + struct cookie *c = cookie; + + el_set(c->el, EL_TERMINAL, NULL); +} diff --git a/edit-editline.c b/edit-editline.c new file mode 100644 index 0000000..85e3f40 --- /dev/null +++ b/edit-editline.c @@ -0,0 +1,100 @@ +#include "rc.h" + +#include +#include + +#include "editline.h" + +bool editing = 1; + +struct cookie { + char *buffer; +}; + +static char *prompt; + +void *edit_begin(int fd) { + List *hist; + struct cookie *c; + + hist = varlookup("history"); + if (hist != NULL) + if (read_history(hist->w) != 0 && + errno != ENOENT) /* ignore if missing */ + uerror(hist->w); + + c = ealloc(sizeof *c); + c->buffer = NULL; + return c; +} + +/* +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +*/ + +char *edit_alloc(void *cookie, size_t *count) { + struct cookie *c = cookie; +/* + const char *r; + HistEvent he; + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + r = el_gets(c->el, count); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (r) + history(c->hist, &he, H_ENTER, r); +*/ + + c->buffer = readline(prompt); + if (c->buffer) { + *count = strlen(c->buffer); + c->buffer[*count] = '\n'; + ++*count; + } + return c->buffer; +} + +/* +static char *edit_prompter(ne *e) { + return prompt; +} +*/ + +void edit_prompt(void *cookie, char *pr) { + //struct cookie *c = cookie; + + prompt = pr; + //el_set(c->el, EL_PROMPT, edit_prompter); +} + +void edit_free(void *cookie) { + struct cookie *c = cookie; + + efree(c->buffer); + c->buffer = NULL; /* allow "overfrees" */ +} + +void edit_end(void *cookie) { + //struct cookie *c = cookie; + + //el_end(c->el); + //history_end(c->hist); + //efree(c); +} + +void edit_reset(void *cookie) { + //struct cookie *c = cookie; + + //el_set(c->el, EL_TERMINAL, NULL); +} diff --git a/edit-readline.c b/edit-readline.c new file mode 100644 index 0000000..6a997c5 --- /dev/null +++ b/edit-readline.c @@ -0,0 +1,87 @@ +#include "rc.h" + +#include +#include +#include +#include +#include + +#include "edit.h" + +bool editing = 1; + +struct cookie { + char *buffer; +}; + +void *edit_begin(int fd) { + List *hist; + struct cookie *c; + + rl_catch_signals = 0; + rl_completer_quote_characters = "'"; + rl_filename_quote_characters = "\t\n !#$&'()*;<=>?@[\\]^`{|}~"; + + hist = varlookup("history"); + if (hist != NULL) + if (read_history(hist->w) != 0 && errno != ENOENT) /* ignore if missing */ + uerror(hist->w); + + c = ealloc(sizeof *c); + c->buffer = NULL; + return c; +} + +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +static char *prompt; + +char *edit_alloc(void *cookie, size_t *count) { + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + c->buffer = readline(prompt); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (c->buffer) { + *count = strlen(c->buffer); + if (*count) + add_history(c->buffer); + c->buffer[*count] = '\n'; + ++*count; /* include the \n */ + } + return c->buffer; +} + +void edit_prompt(void *cookie, char *pr) { + prompt = pr; +} + +void edit_free(void *cookie) { + struct cookie *c = cookie; + + efree(c->buffer); + /* Set c->buffer to NULL, allowing us to "overfree" it. This + is a bit of a kludge, but it's otherwise hard to deal with + the case where a signal causes an early return from + readline. */ + c->buffer = NULL; +} + +void edit_end(void *cookie) { + struct cookie *c = cookie; + + efree(c); +} + +void edit_reset(void *cookie) { + rl_reset_terminal(NULL); +} diff --git a/edit-vrl.c b/edit-vrl.c new file mode 100644 index 0000000..5c8ab5a --- /dev/null +++ b/edit-vrl.c @@ -0,0 +1,104 @@ +#include "rc.h" + +#include +#include + +#include "edit.h" + +extern char *readline(char *); +extern void add_history(char *); + +bool editing = 1; + +struct cookie { + char *buffer; +}; + +static char *prompt; + +void *edit_begin(int fd) { + List *hist; + struct cookie *c; + + + hist = varlookup("history"); + if (hist != NULL) + ; + /* XXX will need to loop calling add_history() */ + + c = ealloc(sizeof *c); + c->buffer = NULL; + return c; +} + +/* +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +*/ + +char *edit_alloc(void *cookie, size_t *count) { + struct cookie *c = cookie; +/* + const char *r; + HistEvent he; + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + r = el_gets(c->el, count); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (r) + history(c->hist, &he, H_ENTER, r); +*/ + + c->buffer = readline(prompt); + if (c->buffer) { + add_history(c->buffer); + *count = strlen(c->buffer); + c->buffer[*count] = '\n'; + ++*count; + } + return c->buffer; +} + +/* +static char *edit_prompter(ne *e) { + return prompt; +} +*/ + +void edit_prompt(void *cookie, char *pr) { + //struct cookie *c = cookie; + + prompt = pr; + //el_set(c->el, EL_PROMPT, edit_prompter); +} + +void edit_free(void *cookie) { + struct cookie *c = cookie; + + efree(c->buffer); + c->buffer = NULL; /* allow "overfrees" */ +} + +void edit_end(void *cookie) { + //struct cookie *c = cookie; + + //el_end(c->el); + //history_end(c->hist); + //efree(c); +} + +void edit_reset(void *cookie) { + //struct cookie *c = cookie; + + //el_set(c->el, EL_TERMINAL, NULL); +} diff --git a/input.c b/input.c index df597c4..5737375 100644 --- a/input.c +++ b/input.c @@ -163,6 +163,7 @@ void termchange(void) { extern void initinput() { istack = itop = ealloc(istacksize = 256 * sizeof (Input)); + istack->ungetcount = 0; ugchar(EOF); } diff --git a/lex.c b/lex.c index 1df705a..92732f8 100644 --- a/lex.c +++ b/lex.c @@ -349,7 +349,7 @@ extern void yyerror(const char *s) { } extern void scanerror(char *s) { - skiptonl(); /* flush upto newline */ + skiptonl(); /* flush up to newline */ yyerror(s); errset = prerror = TRUE; } diff --git a/print.c b/print.c index 3484086..2a30b5c 100644 --- a/print.c +++ b/print.c @@ -285,11 +285,11 @@ extern int fmtprint(Format *format, const char *fmt,...) { va_list ap, saveargs; va_start(ap, fmt); - __va_copy(saveargs, format->args); - __va_copy(format->args, ap); + va_copy(saveargs, format->args); + va_copy(format->args, ap); n += printfmt(format, fmt); va_end(format->args); - __va_copy(format->args, saveargs); + va_copy(format->args, saveargs); return n + format->flushed; } @@ -316,7 +316,7 @@ extern int fprint(int fd, const char *fmt,...) { format.u.n = fd; va_start(ap, fmt); - __va_copy(format.args, ap); + va_copy(format.args, ap); printfmt(&format, fmt); va_end(format.args); @@ -361,7 +361,7 @@ extern char *mprint(const char *fmt,...) { format.u.n = 1; va_start(ap, fmt); - __va_copy(format.args, ap); + va_copy(format.args, ap); result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; @@ -374,7 +374,7 @@ extern char *nprint(const char *fmt,...) { format.u.n = 0; va_start(ap, fmt); - __va_copy(format.args, ap); + va_copy(format.args, ap); result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); va_end(format.args); return result; diff --git a/proto.h b/proto.h index 3f1e05b..4a2d74a 100644 --- a/proto.h +++ b/proto.h @@ -23,11 +23,11 @@ typedef long align_t; #include -/* C 9x specifies a __va_copy() macro which should be used for copying -objects of type va_list. Of course, most places don't have this yet, -but where it does exist we need to use it. */ -#ifndef __va_copy -#define __va_copy(x,y) (x)=(y) +/* C 99 specifies a va_copy() macro to be used for copying +objects of type va_list. If this doesn't exist, hope that simple +assignment works. */ +#ifndef va_copy +#define va_copy(x,y) (x)=(y) #endif #if STDC_HEADERS diff --git a/rc.1 b/rc.1 index af46aa6..ac7c813 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2014-09-01" +.TH RC 1 "2015-04-20" .SH NAME rc \- shell .SH SYNOPSIS @@ -1142,6 +1142,13 @@ use: .Ds .Cr "echo $^path." .De +.PP +For compability with the Plan 9 rc, +.Ds +.Cr $"var +.De +.PP +is accepted as a synonym for dollar-caret. .SS "Backquote Substitution" A list may be formed from the output of a command by using backquote substitution: diff --git a/rc.h b/rc.h index 21fe8c0..2912e60 100644 --- a/rc.h +++ b/rc.h @@ -6,8 +6,6 @@ #define RC "rc: " -#include - /* datatypes */ #define ENV_SEP '\001' diff --git a/rc.spec b/rc.spec index 337964c..359661f 100644 --- a/rc.spec +++ b/rc.spec @@ -1,6 +1,6 @@ %define name rc -%define version 1.7.1 -%define release 1 +%define version 1.7.2 +%define release 3 Summary: rc - the Plan 9 and Tenth Edition shell Name: %name @@ -8,8 +8,10 @@ Version: %version Release: %release Group: Shells License: distributable -Source0: http://www.libra-aries-books.co.uk/software/rc/release/%name-%version.tar.gz +Source0: http://static.tobold.org/rc/rc-1.7.2.tar.gz Buildroot: /var/tmp/%{name}-rpmroot +BuildRequires: autoconf +BuildRequires: readline-devel %description This is a reimplementation for Unix, by Byron Rakitzis, of the Plan 9 @@ -20,7 +22,7 @@ shell, but with a much cleaner syntax. %setup %build -sh configure --with-readline --prefix "$RPM_BUILD_ROOT" --mandir "$RPM_BUILD_ROOT/usr/share/man" +sh configure --with-edit=gnu --prefix "$RPM_BUILD_ROOT" --mandir "$RPM_BUILD_ROOT/usr/share/man" make %install -- cgit v1.2.3 From c884da53a7c885d46ace2b92de78946855b18e92 Mon Sep 17 00:00:00 2001 From: Toby Goodwin Date: Wed, 13 May 2015 22:26:26 +0100 Subject: release: rc-1.7.4 --- COPYING | 34 ++++++++++++++++------------------ ChangeLog | 13 +++++++++++++ NEWS | 5 ++--- README | 10 +++++----- configure.ac | 2 +- rc.1 | 2 +- trip.rc | 2 +- 7 files changed, 39 insertions(+), 29 deletions(-) diff --git a/COPYING b/COPYING index 8f2dc71..8d93017 100644 --- a/COPYING +++ b/COPYING @@ -1,24 +1,22 @@ -/* -Copyright (c) 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis +/* rc -- the Plan 9 shell, reimplemented for Unix -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. + Copyright (c) 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment (see the following) in the product -documentation is required. + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: - Portions Copyright (c) 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. -2. Altered source versions must be plainly marked as such, and must not -be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. + Byron Rakitzis */ diff --git a/ChangeLog b/ChangeLog index f1066c5..5ba1cf3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -890,3 +890,16 @@ Changes since rc-1.5b2 2015-04-20 Release: rc-1.7.3. + +2015-05-12 + + Licensing: due to GPL compatibility concerns, the license is changed + again to the "zlib" license. (N.B. This license change was agreed and + approved by Byron Rakitzis, who is the copyright holder.) + + Testing: swap arguments to mktemp to be kinder to NetBSD (thanks Piotr + Meyer). + +2015-05-13 + + Release: rc-1.7.4. diff --git a/NEWS b/NEWS index 32c2879..3b55faf 100644 --- a/NEWS +++ b/NEWS @@ -18,8 +18,7 @@ New features. Added $"x as a synonym for $^x. Minimal support for various alternative line editing libraries. Filename completion with GNU readline now quotes special characters. -Documentation. Licence updated to use exactly the text of the zlib- -with-acknowledgement licence. +Documentation. Licence updated to the zlib licence. Toby Goodwin -2015-04-20 +2015-05-13 diff --git a/README b/README index 542a516..1431b04 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ -This is release rc-1.7.3. +This is release rc-1.7.4. -See COPYING for copying information. All files are +See COPYING for copying information. All files are Copyright 1991, 1999, 2001-2003, 2014, 2015 Byron Rakitzis. @@ -9,8 +9,8 @@ See INSTALL for build and installation information. BUGS -Send bug reports to . If a core dump is generated, -sending a backtrace will help a great deal. You can get a backtrace +Send bug reports to . If a core dump is generated, +sending a backtrace will help a great deal. You can get a backtrace like this. ; gdb rc core @@ -25,7 +25,7 @@ make rc; this information is extremely valuable. FEEPING CREATURISM See the end of the man page, under "INCOMPATIBILITIES" for (known?) -differences from the "real" rc. Most of these changes were necessary +differences from the "real" rc. Most of these changes were necessary to get rc to work in a reasonable fashion on a real (i.e. commercial, non-Labs) Unix system; a few were changes motivated by concern about some inadequacies in the original design. diff --git a/configure.ac b/configure.ac index cf41b32..acc75dc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ dnl Our package name, version, ... -AC_INIT([rc], [1.7.3]) +AC_INIT([rc], [1.7.4]) dnl ... and release date RELDATE=`date -I` diff --git a/rc.1 b/rc.1 index ac7c813..4fecb87 100644 --- a/rc.1 +++ b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2015-04-20" +.TH RC 1 "2015-05-13" .SH NAME rc \- shell .SH SYNOPSIS diff --git a/trip.rc b/trip.rc index ed9c75d..c811347 100644 --- a/trip.rc +++ b/trip.rc @@ -24,7 +24,7 @@ fn sigexit sigint sigquit sigsegv fn sigexit { echo trip complete } -tmpdir=`{ mktemp -t -d rc-trip.XXXXXX } +tmpdir=`{ mktemp -d -t rc-trip.XXXXXX } tmp=$tmpdir/tmp nl=' ' -- cgit v1.2.3