[Contents] [Index] [Help] [Retrace] [Browse <] [Browse >]

There are several possible places a shell can look for commands passed to
it. The resident list is an important place to look as it contains many
commands that the user finds important enough to keep loaded into memory
at all times. Some shells have commands built directly into them.  Of
course, if the shell cannot find a command in the resident list or in its
collection of internal commands, the shell has to scan the path looking
for the command.  If a shell supports the script bit, when it finds a
command on disk with the script bit set, it should read commands from the
script file.

Here's how you deal with commands on the resident list: After finding the
command (under Forbid()!), if the Segment structure's seg_UC is >= 0,
increment it; if less than 0, don't modify it.  If seg_UC is less than
CMD_DISABLED, the corresponding resident command is currently disabled and
you should not execute it.  The same is true if seg_UC is equal to
CMD_SYSTEM.  After incrementing seg_UC, you can Permit().  After using a
resident command, decrement the seg_UC count if it's greater than 0 (under
Forbid() again).

When identifying scripts, I advise that you use something unique to
identify your scripts, and pass all other scripts to the Boot Shell via
System() for execution.  A good method (which was worked out on BIX long
ago) is to include within the first 256 characters or so, the string
"#!<your shell name, ala csh>!#".  BootShells could, for example, start
with "; #!c:execute!#.  The idea is the string inside the #!...!# should
be the interpreter to run on the script.  If none is specified, give it to
the BootShell.  If you want, you could extend this to include handling of
the sequence for all interpreters. The programs should be invoked as
"<interpreter> <filename> <args>" as if the user had typed that.

Don't forget to set pr_HomeDir for programs loaded from disk.  The Lock in
pr_HomeDir should be a DupLock() of the directory the program was loaded
from. For programs from the resident list, leave it NULL.

Please support multi-assigned C: directories.  The important thing here is
to not lock C:.  Instead, prepend ``C:'' onto the filename you wish to
Lock()/LoadSeg().  Also, if a command is loaded from C:, get its
pr_HomeDir by Lock()ing the file (with C: prepended), and then using
ParentDir() to get its home directory.

The Path is attached to cli_CommandDir.  It is a BPTR to a NULL
terminated, singly-linked list (connected via BPTRs) of directory Locks:

    struct pathBPTRlistentry {
        BPTR   pathBPTRlistentry *next;
        struct Lock              directorylock
    }

Please don't modify the list; use the Path command instead.  This will
make it far easier for us to improve this in the future.

Make sure you clear the SIGBREAK_CTRL_x signals before starting a program.
In order to prevent the user from hitting a break key somewhere between
where you check for the break and where you clear the signals (thus losing
the break signal), you may wish check for a break and clear the signals at
the same time. The safest way is to use:

    oldsigs = SetSignal(0L, SIGBREAK_CTRL_C |
                            SIGBREAK_CTRL_D |
                            SIGBREAK_CTRL_E |
                            SIGBREAK_CTRL_F);

Then you can check oldsigs for any signals that you care about.