Compilation of rc on Linux (kernel version 1.0+, libc-4.5.21+, gcc-2.5.8+)
--------------------------------------------------------------------------

CHANGES FROM THE STOCK RC-1.5 DISTRIBUTION (AT viz.tamu.edu:/pub/rc)

(NOTE! syntactical changes are in no way condoned by the author Byron Rakitzis,
       he wasn't even contacted.  DON'T BUG him about them.  There still exits
       an rc mailing list for discussion of this kind of stuff.  READ THE FAQ!)

    0)  LITTLE THINGS:

---->   defined the /dev/fd in config.h
---->   Linux has /proc, make a symbolic link: ln -s /proc/self/fd /dev/fd
---->   made sure READLINE was undefined, see line editing section below
---->   Also changed some optimization flags.

    1)  sigmsgs.[ch]

        A "non-standard" signal.h file causes 'mksignal' to completely fail.
        To fix it we use the signal(7) man page to find the 29 signals and
        their descriptions.  See my versions of sigmsgs.[ch] at the bottom
        of this file.  I have left them in the directory and modified 'make
        clean' to not trash them.

    2)  redundant declaration removal
        
        To get rc to compile I had to comment out the (redundant) declaration
        of 'longjmp' in jbwrap.h and compile with SYSVR4 defined.

    3)  trip.rc notes

        rc so obtained passes all 'trip.rc' tests with the following exceptions:

            '. -i' doesn't print out prompts. (not big deal functionally)

            protect_env trip fails, but looking at a '-x' trace of what's going
                on seems to validate the behavior.  The command substitution
                should obviously return (), which it does.  ! ~ () '..' -> true
                so it fails.   I don't thing that the '!' should be there.
                But even if it were, since the function searched for is never
                defined, why would it ever be there?  This 'trip' seems broken.
                By the way, I've tested it other ways and 'rc -p' really does
                'protect' your environment from parent process function
                (but not variable) definitions.

    4)  builtin-cd silenced
    
        I commented out the statement which printf's the directory switched to
        when builtin 'cd' has to resort to $CDPATH to find a directory.  If you
        like this feature, just uncomment lines 160, 161 in builtins.c

        I have commented out these two trips so that all the others get tested.

    5)
        I added several useful builtin functions to rc.  See below for a full
        description.  *These are easily removed*.  I figured I should have 'em
        in the binary distribution because the people most likely to despise
        them would be better equipped to re-compile them out.  Those most likely
        to leave them in either have no philosophical objection or are likely
        to appreciate the extra stuff.

LINE EDITING ALTERNATIVES ****************************************************

---->   To use the readline library you need to get the GNU readline library:
            sunsite.unc.edu:/pub/Linux/libs/librl-2.0.tar.gz
        Note that static linking with readline is probably not recommended
        as the library is HUGE (over 3 times the size of plain 'rc') and makes
        the (static) binary four times larger.  Dynamic linking doesn't change
        the binary by more than a few bytes.  To compile with readline (or
        editline) edit Makefile and config.h appropriately.  See the generic
        unix instructions.

---->   You can also use the 'editline' plug-in replacement for readline which
        is distributed in the package for building sharable linux libraries,
            sunsite.unc.edu:/pub/Linux/GCC/src/tools-2.11.gz
        I haven't found it to edit as reliably as readline though.  It only
        adds like 10K to the static binary though.  Maybe we should encourage
        the author to make it a little stronger.

---->   Yet another alternative is to get my very enhanced version of 'ile' for
        Linux.  Traditionally pseudo-terminal front-ends have had a lot of
        trouble tracking the working directory of the child application.
        All that is over with the '/proc' filesystem.  /proc/PID/cwd is a
        symbolic link to current working directory of the process.  The master
        can just use the child's PID.  This information is maintained by the
        kernel, and so the cwd obtained in this way *IS* the cwd (almost by
        definition!).  The only times I've found this technique to fail was
        in a 'su' shell, where the command just forks a copy of the current
        shell.  ILE continues to look at the cwd of the original process.  This
        might be fixable by modifying 'su', say to set an environment variable
        in the initial process or something.  I've also added a forward history
        search, and a few other things.  See the ILE package for full details.

        Additionally /proc/PID/environ allows the pseudo-terminal front-end
        to allow configuration options via shell environment variables like
        $FINGNORE.  I haven't yet implemented this stuff yet.

---->   There are a few other pseudo-terminal front-ends (atty, fe, rkbd,..)
        the first of which is purported to work well under Linux.  Try those
        out as well, if you don't like ReadLine or ILE (Interactive Line Ed.).

NOTES ON MY ADDED BUILTINS ****************************************************

I altered the Makefile interface to builtins to understand all files of the
form b_*.c to be addons.  You may have to change this to an explicit list
if you don't have the GNU make. You also might change it to selectively remove
some of my builtins.  I have NOT updated the rc man page to reflect these
builtin commands.  For and explanation of what they do, see each b_*.c line
below.

With no extra builtins, rc is 62468 bytes (dynamic) or 82948 (static).  With
my builtins for test, expr, getopts, read, seq, ssub, it is 74756 bytes, only
12288 bytes or 20% larger.  The static binary becomes 115716 bytes, 32768 bytes
or 40% larger.  Depending on the subset of builtins you want, you can make this
binary size hit as small as desired.  Even with the kitchen sink, rc is still
smaller than almost any other shell by a significant margin.  The only real
competitor is ash.  Csh, ksh, bash, tcsh, zsh,...  don't even come close(unless
you compile readline in statically!).

I ran some performance tests.  To do all kinds of stat()'s took only .06 sec
real time with the builtin test, while it took over 1.9 sec real time for
the exact same tests using an external program.  That's a factor of 30 folks.
The improvement for builtin 'expr' isn't as spectacular, only a 2.25 fold
increase in speed.  But still... Anyway, here's a brief description of my
builtins.  Under the filename of each source I list its *individual*
contribution to static and dynamic binary sizes.  Adding multiple builtins
*does not* incur increasing the binary by the sum of these individual con-
tributions because of padding out to page boundaries and joint use of the same
library functions(string, stdio, etc).

b_expr.c Simple expr with buggy '(' handling.  Need to fix that.  Also
20480(s) doesn't do ':' mode.  As an external program under Linux this
4096(d)  is only 1.5K, while the GNU expr is over 35K.  Go figure.  I
         don't think it's only because of ':' either ;-).  If desired
         the static contribution of expr could be greatly diminished by
         removin the "printf" reference.  An itoa() function would then
         be needed.  Feel free.  Mail me the patch.

b_test.c Enhanced test.  Only real difference from the GNU test is that
4096(s)  there's a '-h' flag to tell you that a file has more than 1 hard
8192(d)  link.  And it's faster than the GNU test code by 5% or so (as an
         external program, of course :-).  Also, in my test, the closing
         ']' is optional.  Note also that if '=' isn't quoted, rc gets
         confused.  This happens with all commands and external programs too,
         e.g. 'dd'.

Both b_expr.c and b_test.c are set up to be made into external programs
if compiled without ADDON defined, in case you want a *tiny* replacement for
the GNU utilities, for say a boot/recovery floppy or something.

b_read.c The final, best builtin read from the rc mailing list.  Reads an
0(s)     entire line into a single variable.  If you want multiple variables,
0(d)     you can trivially write a 'Read' function to do the proper word
         splitting and assignment.  The important thing about this builtin
         is that it doesn't buffer it's input *at all*.  Also included in this
         distribution is 'line.c', the source for a tiny external program that
         can be combined with a shell function to achieve the same behavior
         at a reduction in performance.  Note also that it doesn't add enough
         bytes to either a dynamic *or* a static executable to add another
         page of virtual memory!  The same is true for true and false below.
         These builtins cost essentially *nothing* in size.

b_seq.c  is a builtin for the very commonly needed 'seqence of integers'
20930(s) function in 'rc' functions/scripts.  It's used to reference ranges
0(d)     of elements in a list, e.g. elements 2 to the end of 'hiho' might
         be referenced by $hiho(`{seq 2 $#hiho}).  See source and rc-FAQ
         for more info.

b_ssub.c is a builtin for the very frequent suffix/prefix substitution many
20480(s) of us are always doing.  E.g. we want a variable that contains
4096(d)  the names of all '.c' files with no matching '.h' files.
         TheVar=`{for(x in *.c)! [ -f `{ssub $x .c .h} ]&&echo $x}
         ssub can also to *prefix* substition (ssub -p) and path stripping
         like basename (ssub -S).  See source for more info.

b_getopt.c Standard getopt utility to parse option arguments.  Basically this
28672(s)   just puts all options before a '--' so if you enter:
0(d)          'hiho -x junk -y more_junk arg1 -z still_more arg2 -egads'
           getopt will return:
              '-x junk -y more_junk -z still_more -e -g -a -d -s -- arg1 arg2'
           getopt must have the getopt parse string as it's first argument and
           the rest of the command line following it.  For the above example
           this translates into:
              'getopt x:y:z:egads $entered_command_line'
           Note: ordinarily $* doesn't include argv[0], but you can if you
                 want by using '$0 $*' were I have $entered_command_line.
           The ':' indicates that the option takes an argument.
           See any decent man page for getopt(3) or getopt(1) for more details.

b_true.c   These are self explanatory :-)
0(d or s)
b_false.c  Well, OK.  They just return a status of true(0) or false(1).  This is
0(d or s)  a *really* intuitive thing in a script or function and adds minimal
           overhead.  Only a few bytes really.  Not enough to change the size of
           a demand paged binary.

It is *so* easy to remove these builtins that I'm including them by default for
your enjoyment.  All you need to do to selectively remove one is comment out
the two lines it's mentioned in in addon.h and "mv b_<builtin>.c B_<builtin>.c"
(or "rm b_<builtin>.c" if you *really* hate it :-).

You don't even have to recompile the whole thing.  Just rename the b_<builtin>.c
file and 'make'.  builtins.o is the only module which includes addon.h and the
only module in which the _b_<builtin> symbol is referenced, so re-makes are fast.

To remove *all* the added builtins, uncomment out the '-DADDON' in the
CFLAGS in the Makefile, rm builtin.o, and 'make'.

If you want to create your own builtins, it's *really* easy.  They have the
form:

void b_foo(char* argv[]) {
    ...
    set(TRUE) or set(FALSE) (depending on what you want the exit status to be)
}

I tried to add all of the functions that most shells seem to have builtin
nowadays and the binary is still under 64K.  I realize that this is basically
in *direct* opposition to the whole 'rc' philosophy (religion?), but
what the hey, I like the 'rc' syntax and quoting rules.  I always thought
the 'rc' philosophy had two major components: minimal syntax and minimal
builtins.  I agree with the former while thinking the latter is at odds
with significant performance and portability issues in shell script programming.
No matter what happens with POSIX and all, you can just bet that some of the
semantics of things like getopt, test, expr, etc. are going to be different on
different unices.  Having a *core* set of *simple* one's in the shell is *not*
an inherently evil idea.

In any case, I don't want to hear any flack that goes like 'How could you
POSSIBLY add all those builtins to rc???!!!'.  If you don't like 'em,
undefine ADDON and recompile.  I included them because I think a lot of people
will find them icing on a well designed shell, perhaps enough to change over.

Charles Blake
July 27, 1994


Backups of Linux specific files.  Extract these to the filenames indicated if
for some reason, they get clobbered/trashed.

------- sigmsgs.c ----------
#include "sigmsgs.h"

Sigmsgs signals[] = {
	{"",""},
	{"sighup","hangup"},
	{"sigint",""},
	{"sigquit","quit"},
	{"sigill","illegal instruction"},
	{"sigtrap","trace trap"},
	{"sigabrt","abort instruction"},
	{"sigunused","unused signal"},
	{"sigfpe","floating point exception"},
	{"sigkill","killed"},
	{"sigusr1","user defined signal 1"},
	{"sigsegv","segmentation violation"},
	{"sigusr2","user defined signal 2"},
	{"sigpipe",""},
	{"sigalrm","alarm clock"},
	{"sigterm","terminated"},
	{"sigstkflt","stack fault"},
	{"sigchld","child stop or exit"},
	{"sigcont","continue"},
	{"sigtstop","stopped"},
	{"sigstp","stopped"},
	{"sigttin","background tty read"},
	{"sigttou","background tty write"},
	{"sigio","input/output possible"},
	{"sigxcpu","exceeded cpu time limit"},
	{"sigxfsz","exceeded file size limit"},
	{"sigvtalrm","virtual time alarm"},
	{"sigprof","profiling time alarm"},
	{"sigwinch","window changed"}
};

------ sigmsgs.h ------

typedef struct {
	char *name, *msg;
} Sigmsgs;
extern Sigmsgs signals[];
#define NUMOFSIGNALS 29
