doc@pucc-j.UUCP (09/02/86)
Reply-To: dillon%cory.Berkeley.EDU@BERKELEY.EDU (Matt Dillon)
This shar file contains the latest version of my shell. See the
README and instructions.txt file within for more details.
-Matt
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# README
# comm1.c
# comm2.c
# execom.c
# globals.c
# instructions.txt
# main.c
# run.c
# set.c
# shell.h
# sub.c
# This archive created: Wed Aug 27 19:51:38 1986
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(464 characters)'
if test -f 'README'
then
echo shar: "will not over-write existing file 'README'"
else
cat << \!Funky!Stuff! > 'README'
SHELL V 2.01 Matthew Dillon COMPILATION
-Use a 32 bit compiler
-Use Astartup.obj (or equivalent) as your startup object file.
Do NOT use Lstartup.obj.
-Use the libraries (in this order): MY.LIB AMIGA.LIB LC.LIB
MY.LIB is my own library which you should have. If not, mail
via UUCP or ARPAnet and I'll give you a copy.
LC.LIB is only in there because lattice uses a function in
LC.LIB for long integer multiplies.
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'comm1.c'" '(7826 characters)'
if test -f 'comm1.c'
then
echo shar: "will not over-write existing file 'comm1.c'"
else
cat << \!Funky!Stuff! > 'comm1.c'
/*
* COMM1.C
*
* Matthew Dillon, August 1986
*
*
*
*/
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <lattice/fcntl.h>
#include "shell.h"
extern struct FileLock *CreateDir(), *CurrentDir(), *ParentDir();
extern struct FileLock *Lock(), *DupLock();
extern struct FileLock *cdgo();
extern char *AllocMem();
extern long disp_entry();
struct FileLock *Clock;
do_sleep()
{
register int i;
if (ac == 2) {
i = atoi(av[1]);
while (i > 0) {
Delay (50*2);
i -= 2;
if (CHECKBREAK())
break;
}
}
return (1);
}
do_number()
{
return (1);
}
do_cat()
{
int fi, i;
char buf[256];
if (ac == 1) {
while (Ogets(buf))
Oputs(buf);
return (1);
}
for (i = 1; i < ac; ++i) {
if (fi = xopen (av[i], "r", 512)) {
while (xgets (fi, buf, 256)) {
Oputs(buf);
if (CHECKBREAK())
break;
}
xclose (fi);
} else {
printf ("could not open %s\n", av[i]);
}
}
return (1);
}
do_dir(garbage, com)
char *garbage;
{
struct DPTR *dp;
struct InfoData *info;
char *name;
int i, stat;
long total = 0;
if (ac == 1) {
++ac;
av[1] = "";
}
for (i = 1; i < ac; ++i) {
if ((dp = dopen (av[i], &stat)) == NULL)
continue;
if (com < 0) {
info = (struct InfoData *)AllocMem(sizeof(struct InfoData), MEMF_PUBLIC);
if (Info (dp->lock, info)) {
int bpb = info->id_BytesPerBlock;
fprintf (Cout, "Unit:%2ld Errs:%3ld Bytes: %-7ld Free: %-7ld\n",
info->id_UnitNumber,
info->id_NumSoftErrors,
bpb * info->id_NumBlocks,
bpb * (info->id_NumBlocks - info->id_NumBlocksUsed));
} else {
perror (av[i]);
}
FreeMem (info, sizeof(*info));
} else {
if (stat) {
while (dnext (dp, &name, &stat)) {
total += disp_entry (dp->fib);
if (CHECKBREAK())
break;
}
} else {
total += disp_entry(dp->fib);
}
}
dclose (dp);
}
fprintf (Cout, "TOTAL: %ld\n", total);
return (1);
}
long
disp_entry(fib)
register struct FileInfoBlock *fib;
{
char str[5];
register char *dirstr;
str[4] = '\0';
str[0] = (fib->fib_Protection & FIBF_READ) ? '-' : 'r';
str[1] = (fib->fib_Protection & FIBF_WRITE) ? '-' : 'w';
str[2] = (fib->fib_Protection & FIBF_EXECUTE) ? '-' : 'x';
str[3] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd';
dirstr = (fib->fib_DirEntryType < 0) ? " " : "DIR";
fprintf (Cout, "%s %6ld %s %s\n", str, (long)fib->fib_Size, dirstr, fib->fib_FileName);
return ((long)fib->fib_Size);
}
do_quit()
{
if (Src_stack) {
Quit = 1;
return(do_return());
}
main_exit (0);
}
do_echo(str)
char *str;
{
register char *ptr;
char nl = 1;
for (ptr = str; *ptr && *ptr != ' '; ++ptr);
if (*ptr == ' ')
++ptr;
if (av[1] && strcmp (av[1], "-n") == 0) {
nl = 0;
ptr += 2;
if (*ptr == ' ')
++ptr;
}
Write(Cout, ptr, strlen(ptr));
if (nl)
Oputs("");
return (1);
}
do_source(str)
char *str;
{
register int fi;
char buf[256];
if (Src_stack == MAXSRC) {
puts ("Too many source levels");
return(-1);
}
fi = xopen (next_word(str), "r", 512);
if (fi == 0) {
printf ("Cannot open %s\n", next_word(str));
return(-1);
}
++H_stack;
Src_pos[Src_stack] = 0;
Src_base[Src_stack] = fi;
++Src_stack;
while (xgets (fi, buf, 256)) {
Src_pos[Src_stack - 1] += 1+strlen(buf);
if (Verbose)
puts(buf);
exec_command (buf);
if (CHECKBREAK())
break;
}
--H_stack;
--Src_stack;
unset_level(LEVEL_LABEL + Src_stack);
xclose (fi);
return (1);
}
/*
* cd. Additionally, allow '..' to get you back one directory in the path.
*/
do_cd()
{
static char root[32];
register struct FileLock *lock;
register char *str, *ptr;
register int notdone;
if (ac != 2) {
Oputs (root);
Clock = cdgo (root, NULL);
return (1);
}
str = av[1];
while (*str == '/') {
++str;
if (Clock)
Clock = cdgo (NULL, Clock);
}
notdone = 1;
while (notdone) {
ptr = str;
while (*str && *str != '/' && *str != ':')
++str;
notdone = *str;
*str++ = '\0';
if (ptr == str - 1)
continue;
if (notdone == ':') {
*(str-1) = notdone;
notdone = *str;
*str = '\0';
strcpy (root, ptr);
Clock = cdgo (root, NULL);
*str = notdone;
} else
if (strcmp (ptr, "..") == 0) {
if (Clock)
Clock = cdgo (NULL, Clock);
} else {
if ((lock = cdgo (ptr, NULL)) == NULL)
puts ("not found");
else
Clock = lock;
}
}
return (1);
}
struct FileLock *
cdgo(ptr, lock)
char *ptr;
struct FileLock *lock;
{
register struct FileLock *newlock, *oldlock;
if (lock)
newlock = ParentDir (lock);
else
newlock = Lock (ptr, ACCESS_READ);
if (newlock) {
if (oldlock = CurrentDir (newlock))
UnLock (oldlock);
}
return (newlock);
}
do_mkdir()
{
register int i;
register struct FileLock *lock;
for (i = 1; i < ac; ++i) {
if (lock = CreateDir (av[i])) {
UnLock (lock);
continue;
}
perror (av[i]);
}
return (1);
}
do_mv()
{
if (Rename (av[1], av[2]))
return (1);
perror ("rm:");
return (-1);
}
do_rm()
{
register int i;
for (i = 1; i < ac; ++i) {
if (!DeleteFile(av[i]))
perror (av[i]);
}
return (1);
}
do_history()
{
register struct HIST *hist;
register int i = H_tail_base;
register int len = (av[1]) ? strlen(av[1]) : 0;
for (hist = H_tail; hist; hist = hist->prev) {
if (len == 0 || strncmp(av[1], hist->line, len) == 0) {
fprintf (Cout, "%3ld ", i);
Oputs (hist->line);
}
++i;
if (CHECKBREAK())
break;
}
return (1);
}
do_mem()
{
register long cfree, ffree;
extern long AvailMem();
Forbid();
cfree = AvailMem (MEMF_CHIP);
ffree = AvailMem (MEMF_FAST);
Permit();
if (ffree)
fprintf (Cout, "FAST memory:%10ld\n", ffree);
fprintf (Cout, "CHIP memory:%10ld\n", cfree);
fprintf (Cout, "Total -----:%5ld K\n", (ffree + cfree) >> 10);
return (1);
}
/*
* foreach var_name ( str str str str... str ) commands
* spacing is important (unfortunetly)
*
* ac=0 1 2 3 4 5 6 7
* foreach i ( a b c ) echo $i
* foreach i ( *.c ) "echo -n "file ->";echo $i"
*/
do_foreach()
{
register int i, cstart, cend, old;
register char *cstr, *vname, *ptr, *scr, *args;
cstart = i = (*av[2] == '(') ? 3 : 2;
while (i < ac) {
if (*av[i] == ')')
break;
++i;
}
if (i == ac) {
puts ("')' expected");
return (-1);
}
++H_stack;
cend = i;
vname = strcpy(malloc(strlen(av[1])+1), av[1]);
cstr = compile_av (av, cend + 1, ac);
ptr = args = compile_av (av, cstart, cend);
while (*ptr) {
while (*ptr == ' ' || *ptr == 9)
++ptr;
scr = ptr;
if (*scr == '\0')
break;
while (*ptr && *ptr != ' ' && *ptr != 9)
++ptr;
old = *ptr;
*ptr = '\0';
set_var (LEVEL_SET, vname, scr);
if (CHECKBREAK())
break;
exec_command (cstr);
*ptr = old;
}
--H_stack;
free (args);
free (cstr);
unset_var (LEVEL_SET, vname);
free (vname);
return (1);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'comm2.c'" '(3867 characters)'
if test -f 'comm2.c'
then
echo shar: "will not over-write existing file 'comm2.c'"
else
cat << \!Funky!Stuff! > 'comm2.c'
/*
* MORE commands
*/
#include "shell.h"
do_return()
{
if (Src_stack) {
xseek (Src_base[Src_stack - 1], 0, 1);
Rval = (ac < 2) ? 1 : atoi(av[1]);
return (-1);
} else {
main_exit ((ac < 2) ? 1 : atoi(av[1]));
}
}
/*
* STRHEAD
*
* place a string into a variable removing everything after and including
* the 'break' character or until a space is found in the string.
*
* strhead varname breakchar string
*
*/
do_strhead()
{
register char *str = av[3];
char bc = *av[2];
while (*str && *str != bc)
++str;
*str = '\0';
set_var (LEVEL_SET, av[1], av[3]);
}
do_strtail()
{
register char *str = av[3];
char bc = *av[2];
while (*str && *str != bc)
++str;
if (*str)
++str;
set_var (LEVEL_SET, av[1], str);
}
/*
* if A < B <, >, =, <=, >=, !=, where A and B are either:
* nothing
* a string
* a value (begins w/ number)
*/
do_if(garbage, com)
char *garbage;
{
char *v1, *v2, *v3, result, num;
int n1, n2;
switch (com) {
case 0:
if (If_stack && If_base[If_stack - 1]) {
If_base[If_stack++] = 1;
break;
}
result = num = 0;
if (ac <= 2) { /* if $var; */
if (ac == 1 || strlen(av[1]) == 0 || (strlen(av[1]) == 1 && *av[1] == ' '))
goto do_result;
result = 1;
goto do_result;
}
if (ac != 4) {
ierror(NULL, 500);
break;
}
v1 = av[1]; v2 = av[2]; v3 = av[3];
while (*v1 == ' ')
++v1;
while (*v2 == ' ')
++v2;
while (*v3 == ' ')
++v3;
if (*v1 >= '0' && *v1 <= '9') {
num = 1;
n1 = atoi(v1);
n2 = atoi(v3);
}
while (*v2) {
switch (*v2++) {
case '>':
result |= (num) ? (n1 > n2) : (strcmp(v1, v3) > 0);
break;
case '<':
result |= (num) ? (n1 < n2) : (strcmp(v1, v3) < 0);
break;
case '=':
result |= (num) ? (n1 == n2) : (strcmp(v1, v3) ==0);
break;
default:
ierror (NULL, 503);
break;
}
}
do_result:
If_base[If_stack++] = !result;
break;
case 1:
if (If_stack > 1 && If_base[If_stack - 2])
break;
if (If_stack)
If_base[If_stack - 1] ^= 1;
break;
case 2:
if (If_stack)
--If_stack;
break;
}
Disable = (If_stack) ? If_base[If_stack - 1] : 0;
return (1);
}
do_label()
{
char aseek[32];
if (Src_stack == 0) {
ierror (NULL, 502);
return (-1);
}
sprintf (aseek, "%ld %ld", Src_pos[Src_stack-1], If_stack);
set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
return (1);
}
do_goto()
{
int new;
long pos;
char *lab;
if (Src_stack == 0) {
ierror (NULL, 502);
} else {
lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
if (lab == NULL) {
ierror (NULL, 501);
} else {
pos = atoi(lab);
xseek (Src_base[Src_stack - 1], pos, -1);
Src_pos[Src_stack - 1] = pos;
new = atoi(next_word(lab));
for (; If_stack < new; ++If_stack)
If_base[If_stack] = 0;
If_stack = new;
}
}
return (-1); /* Don't execute reset of this line */
}
do_failat()
{
Faillevel = 1;
Oputs ("NOT IMPLIMENTED YET");
}
do_checkbrk()
{
Oputs ("NOT IMPLIMENTED YET");
}
do_inc(garbage, com)
char *garbage;
{
char *var;
char num[32];
if (ac == 3)
com = atoi(av[2]);
var = get_var (LEVEL_SET, av[1]);
if (var) {
sprintf (num, "%ld", atoi(var)+com);
set_var (LEVEL_SET, av[1], num);
}
}
do_input()
{
char in[256];
if (Ogets(in))
set_var (LEVEL_SET, av[1], in);
return (1);
}
do_ver()
{
Oputs (VERSION);
return (1);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'execom.c'" '(14496 characters)'
if test -f 'execom.c'
then
echo shar: "will not over-write existing file 'execom.c'"
else
cat << \!Funky!Stuff! > 'execom.c'
/*
* EXECOM.C
*
* Matthew Dillon, 10 August 1986
*
* Finally re-written.
*
*/
#include "shell.h"
#define F_EXACT 0
#define F_ABBR 1
#define ST_COND 0x01
#define ST_NAME 0x02
struct COMMAND {
int (*func)();
short minargs;
short stat;
int val;
char *name;
};
extern char *format_insert_string();
extern char *mpush(), *exarg();
extern int do_run(), do_number();
extern int do_quit(), do_set_var(), do_unset_var();
extern int do_echo(), do_source(), do_mv();
extern int do_cd(), do_rm(), do_mkdir(), do_history();
extern int do_mem(), do_cat(), do_dir();
extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
extern int do_failat(), do_checkbrk(), do_inc();
extern int do_input(), do_ver(), do_sleep(), do_help();
extern int do_strhead(), do_strtail();
static struct COMMAND Command[] = {
do_run , 0, ST_NAME, 0 , "\001",
do_number , 0, 0, 0 , "\001",
do_quit , 0, 0, 0 , "quit",
do_set_var , 0, 0, LEVEL_SET , "set",
do_unset_var, 0, 0, LEVEL_SET , "unset",
do_set_var , 0, 0, LEVEL_ALIAS, "alias",
do_unset_var, 0, 0, LEVEL_ALIAS, "unalias",
do_echo , 0, 0, 0 , "echo",
do_source , 0, 0, 0 , "source",
do_mv , 2, 0, 0 , "mv",
do_cd , 0, 0, 0 , "cd",
do_rm , 0, 0, 0 , "rm",
do_mkdir , 0, 0, 0 , "mkdir",
do_history , 0, 0, 0 , "history",
do_mem , 0, 0, 0 , "mem",
do_cat , 0, 0, 0 , "cat",
do_dir , 0, 0, 0 , "dir",
do_dir , 0, 0, -1 , "devinfo",
do_foreach , 3, 0, 0 , "foreach",
do_return , 0, 0, 0 , "return",
do_if , 1, ST_COND, 0 , "if",
do_if , 0, ST_COND, 1 , "else",
do_if , 0, ST_COND, 2 , "endif",
do_label , 1, ST_COND, 0 , "label",
do_goto , 1, 0, 0 , "goto",
do_failat , 1, 0, 0 , "failat",
do_checkbrk , 0, 0, 0 , "checkbreak",
do_strhead , 3, 0, 0 , "strhead",
do_strtail , 3, 0, 0 , "strtail",
do_inc , 1, 0, 1 , "inc",
do_inc , 1, 0, -1, "dec",
do_input , 1, 0, 0, "input",
do_ver , 0, 0, 0, "version",
do_sleep , 0, 0, 0, "sleep",
do_help , 0, 0, 0, "help",
NULL , 0, 0, 0 , NULL
};
static unsigned char elast; /* last end delimeter */
static char Cin_ispipe, Cout_ispipe;
exec_command(base)
char *base;
{
register char *scr;
register int i;
if (!H_stack)
add_history(base);
scr = malloc((strlen(base) << 2) + 2); /* 4X */
preformat(base, scr);
i = fcomm(scr, 1);
return ((i) ? -1 : 1);
}
isalphanum(c)
{
if (c >= '0' && c <= '9')
return (1);
if (c >= 'a' && c <= 'z')
return (1);
if (c >= 'A' && c <= 'Z')
return (1);
if (c == '_')
return (1);
return (0);
}
preformat(s, d)
register char *s, *d;
{
register int si, di, qm;
si = di = qm = 0;
while (s[si] == ' ' || s[si] == 9)
++si;
while (s[si]) {
if (qm && s[si] != '\"' && s[si] != '\\') {
d[di++] = s[si++] | 0x80;
continue;
}
switch (s[si]) {
case ' ':
case 9:
d[di++] = ' ';
while (s[si] == ' ' || s[si] == 9)
++si;
if (s[si] == 0 || s[si] == '|' || s[si] == ';')
--di;
break;
case '*':
case '?':
d[di++] = 0x80;
case '!':
d[di++] = s[si++];
break;
case ';':
case '|':
d[di++] = s[si++];
while (s[si] == ' ' || s[si] == 9)
++si;
break;
case '\\':
d[di++] = s[++si] | 0x80;
if (s[si]) ++si;
break;
case '\"':
qm = 1 - qm;
++si;
break;
case '^':
d[di++] = s[++si] & 0x1F;
if (s[si]) ++si;
break;
case '$': /* search end of var name and place false space */
d[di++] = 0x80;
d[di++] = s[si++];
while (isalphanum(s[si]))
d[di++] = s[si++];
d[di++] = 0x80;
break;
default:
d[di++] = s[si++];
break;
}
}
d[di++] = 0;
d[di] = 0;
if (Debug & 0x01) {
printf ("PREFORMAT: %ld :%s:\n", strlen(d), d);
}
}
/*
* process formatted string. ' ' is the delimeter.
*
* 0: check '\0': no more, stop, done.
* 1: check $. if so, extract, format, insert
* 2: check alias. if so, extract, format, insert. goto 1
* 3: check history or substitution, extract, format, insert. goto 1
*
* 4: assume first element now internal or disk based command.
*
* 5: extract each ' ' or 0x80 delimited argument and process, placing
* in av[] list (except 0x80 args appended). check in order:
*
* '$' insert string straight
* '>' setup stdout
* '<' setup stdin
* '*' or '?' do directory search and insert as separate args.
*
* ';' 0 '|' end of command. if '|' setup stdout
* -execute command, fix stdin and out (|) sets
* up stdin for next guy.
*/
fcomm(str, freeok)
register char *str;
{
register char *istr;
char *nextstr;
char *command;
char *pend_alias = NULL; /* pending alias */
char err = 0;
mpush_base();
if (*str == 0)
goto done1;
step1:
if (*str == '$') {
if (istr = get_var (LEVEL_SET, str + 1))
str = format_insert_string(str, istr, &freeok);
}
istr = get_var (LEVEL_ALIAS, str);
if (istr) {
if (*istr == '%') {
pend_alias = istr;
} else {
str = format_insert_string(str, istr, &freeok);
goto step1;
}
}
if (*str == '!') {
istr = get_history(str);
replace_head(istr);
str = format_insert_string(str, istr, &freeok);
goto step1;
}
nextstr = str;
command = exarg(&nextstr);
if (*command == 0)
goto done0;
if (pend_alias == 0) {
register int ccno;
ccno = find_command(command);
if (Command[ccno].stat & ST_COND)
goto skipgood;
}
if (Disable)
goto done0;
skipgood:
{
register char *arg, *ptr, *scr;
short redir;
short doexpand;
short cont;
short inc;
ac = 1;
av[0] = command;
step5: /* ac = nextac */
if (!elast || elast == ';' || elast == '|')
goto stepdone;
av[ac] = NULL;
cont = 1;
doexpand = redir = inc = 0;
while (cont && elast) {
ptr = exarg(&nextstr);
inc = 1;
arg = "";
cont = (elast == 0x80);
switch (*ptr) {
case '<':
redir = -2;
case '>':
++redir;
arg = ptr + 1;
cont = 1;
break;
case '$':
if ((arg = get_var(LEVEL_SET, ptr + 1)) == NULL)
arg = ptr;
break;
case '*':
case '?':
doexpand = 1;
arg = ptr;
break;
default:
arg = ptr;
break;
}
/* Append arg to av[ac] */
for (scr = arg; *scr; ++scr)
*scr &= 0x7F;
if (av[ac]) {
register char *old = av[ac];
av[ac] = mpush(strlen(arg)+1+strlen(av[ac]));
strcpy(av[ac], old);
strcat(av[ac], arg);
} else {
av[ac] = mpush(strlen(arg)+1);
strcpy(av[ac], arg);
}
if (elast != 0x80)
break;
}
/* process expansion */
if (doexpand) {
char **eav, **ebase;
int eac;
eav = ebase = expand(av[ac], &eac);
if (eav) {
inc = 0;
if (ac + eac + 2 > MAXAV) {
ierror (NULL, 506);
err = 1;
} else {
for (; eac; --eac, ++eav)
av[ac++] = strcpy(mpush(strlen(*eav)+1), *eav);
}
free_expand (ebase);
} else {
puts ("null expansion");
err = 1;
}
}
/* process redirection */
if (redir && !err) {
register char *file = (doexpand) ? av[--ac] : av[ac];
if (redir < 0)
Cin_name = file;
else
Cout_name = file;
inc = 0;
}
/* check elast for space */
if (inc) {
++ac;
if (ac + 2 > MAXAV) {
ierror (NULL, 506);
err = 1; /* error condition */
elast = 0; /* don't process any more arguemnts */
}
}
if (elast == ' ')
goto step5;
}
stepdone:
av[ac] = NULL;
/* process pipes via files */
if (elast == '|' && !err) {
static int which; /* 0 or 1 in case of multiple pipes */
which = 1 - which;
Cout_name = (which) ? Pipe1 : Pipe2;
Cout_ispipe = 1;
}
/* DO COMMAND HERE! */
if (err)
goto done0;
{
register int i, len;
char save_elast;
char *avline;
save_elast = elast;
for (i = len = 0; i < ac; ++i)
len += strlen(av[i]) + 1;
avline = malloc(len+1);
for (len = 0, i = ((pend_alias) ? 1 : 0); i < ac; ++i) {
if (Debug & 0x02) printf ("AV[%2ld] %ld :%s:\n", i, strlen(av[i]), av[i]);
strcpy(avline + len, av[i]);
len += strlen(av[i]);
if (i + 1 < ac)
avline[len++] = ' ';
}
avline[len] = 0;
if (pend_alias) { /* special % alias */
register char *ptr, *scr;
for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
set_var (LEVEL_SET, pend_alias + 1, avline);
free (avline);
scr = malloc((strlen(ptr) << 2) + 2);
preformat (ptr, scr);
fcomm (scr, 1);
unset_var (LEVEL_SET, pend_alias + 1);
} else { /* normal command */
register int ccno;
register long cin, cout;
ccno = find_command (command);
if ((Command[ccno].stat & ST_NAME) == 0) {
if (Cin_name) {
cin = Cin;
Cin = Open(Cin_name, 1005);
if (Cin == 0) {
ierror (NULL, 504);
err = 1;
Cin = cin;
Cin_name = NULL;
}
}
if (Cout_name) {
cout = Cout;
Cout = Open(Cout_name, 1006);
if (Cout == NULL) {
err = 1;
ierror (NULL, 504);
Cout = cout;
Cout_name = NULL;
}
}
}
if (ac < Command[ccno].minargs + 1) {
ierror (NULL, 500);
err = 1;
} else {
i = (*Command[ccno].func)(avline, Command[ccno].val);
err = (i < 0);
}
free (avline);
if ((Command[ccno].stat & ST_NAME) == 0) {
if (Cin_name) {
Close(Cin);
Cin = cin;
}
if (Cout_name) {
Close(Cout);
Cout = cout;
}
}
}
if (Cin_ispipe && Cin_name)
DeleteFile(Cin_name);
if (Cout_ispipe) {
Cin_name = Cout_name; /* ok to assign.. static name */
Cin_ispipe = 1;
} else {
Cin_name = NULL;
}
Cout_name = NULL;
Cout_ispipe = 0;
elast = save_elast;
}
mpop_tobase(); /* free arguments */
mpush_base(); /* push dummy base */
done0:
if (elast != 0 && !err) /* done? or more? */
err = fcomm(nextstr, 0); /* do next command ';' or '|' sep. */
if (Cin_name) /* pipe segment complete */
DeleteFile(Cin_name);
Cin_name = NULL;
Cin_ispipe = 0;
done1:
mpop_tobase();
if (freeok)
free(str);
return ((int)err); /* TRUE = error occured */
}
char *
exarg(ptr)
unsigned char **ptr;
{
register unsigned char *end;
register unsigned char *start;
start = end = *ptr;
while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
++end;
elast = *end;
*end = '\0';
*ptr = end + 1;
return ((char *)start);
}
static char **Mlist;
mpush_base()
{
char *str;
str = malloc(5);
*(char ***)str = Mlist;
str[4] = 0;
Mlist = (char **)str;
}
char *
mpush(bytes)
{
char *str;
str = malloc(5 + bytes);
*(char ***)str = Mlist;
str[4] = 1;
Mlist = (char **)str;
return (str + 5);
}
mpop_tobase()
{
register char *next;
while (Mlist) {
next = *Mlist;
if (((char *)Mlist)[4] == 0) {
free (Mlist);
Mlist = (char **)next;
break;
}
free (Mlist);
Mlist = (char **)next;
}
}
/*
* Insert 'from' string in front of 'str' while deleting the
* first entry in 'str'. if freeok is set, then 'str' will be
* free'd
*/
char *
format_insert_string(str, from, freeok)
char *str;
char *from;
int *freeok;
{
register char *new1, *new2;
register unsigned char *strskip;
int len;
for (strskip = str; *strskip && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip);
len = strlen(from);
new1 = malloc((len << 2) + 2);
preformat(from, new1);
len = strlen(new1) + strlen(strskip);
new2 = malloc(len+2);
strcpy(new2, new1);
strcat(new2, strskip);
new2[len+1] = 0;
free (new1);
if (*freeok)
free (str);
*freeok = 1;
return (new2);
}
find_command(str)
char *str;
{
int i;
int len = strlen(str);
if (*str >= '0' && *str <= '9')
return (1);
for (i = 0; Command[i].func; ++i) {
if (strncmp (str, Command[i].name, len) == 0)
return (i);
}
return (0);
}
do_help()
{
register struct COMMAND *com;
for (com = &Command[2]; com->func; ++com)
fprintf (Cout, "%s ", com->name);
Oputs ("");
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'globals.c'" '(1912 characters)'
if test -f 'globals.c'
then
echo shar: "will not over-write existing file 'globals.c'"
else
cat << \!Funky!Stuff! > 'globals.c'
/*
* GLOBALS.C
*
* Matthew Dillon, 24 Feb 1986
*
*/
#include "shell.h"
struct HIST *H_head, *H_tail;
struct PERROR Perror[] = {
103, "insufficient free storage",
105, "task table full",
120, "argument line invalid or too long",
121, "file is not an object module",
122, "invalid resident library during load",
201, "no default directory",
202, "object in use",
203, "object already exists",
204, "directory not found",
205, "object not found",
206, "bad stream name",
207, "object too large",
209, "action not known",
210, "invalid stream component name",
211, "invalid object lock",
212, "object not of required type",
213, "disk not validated",
214, "disk write protected",
215, "rename across devices",
216, "directory not empty",
217, "too many levels",
218, "device not mounted",
219, "seek error",
220, "comment too long",
221, "disk full",
222, "file delete protected",
223, "file write protected",
224, "file read protected",
225, "not a DOS disk",
226, "no disk",
232, "no more entries in directory",
/* custom error messages */
500, "bad arguments",
501, "label not found",
502, "must be within source file",
503, "Syntax Error",
504, "redirection error",
505, "pipe error",
506, "too many arguments",
0, NULL
};
char *av[MAXAV];
int Src_base[MAXSRC];
long Src_pos[MAXSRC];
char If_base[MAXIF];
int H_len, H_tail_base, H_stack;
int Src_stack, If_stack;
int ac;
int Debug, Rval, Disable, Faillevel, Verbose;
int Quit;
int Cout, Cin; /* current input and output file handles */
int Uniq; /* unique value */
char *Cin_name, *Cout_name; /* redirection input/output name or NULL */
char *Pipe1, *Pipe2; /* the two pipe temp. files */
int S_histlen = 20;
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'instructions.txt'" '(11840 characters)'
if test -f 'instructions.txt'
then
echo shar: "will not over-write existing file 'instructions.txt'"
else
cat << \!Funky!Stuff! > 'instructions.txt'
INSTRUCTIONS FOR SHELL 2.01
(A) Compiling
(B) Overview
(C) Quicky tech notes on implimentation.
(D) Command pre-processor
(E) Command-list
(F) special SET variables
(G) example .login file.
(A) COMPILING:
Compile the shell with a 32 bit compiler. 16 bit compilers will not
work. Use the Astartup.obj startup module, and the three libraries:
MY.LIB AMIGA.LIB LC.LIB
NOTE the order in which the libraries occur. LC.LIB is only in there
because the idiots at lattice use a call to do 32-bit integer multiplies.
MY.LIB is my own library which has been posted (but feel free to ask
me to send it to you if you haven't got it)
lc1 -i$incdir/ -i$incdir/lattice/ $y
lc2 -s -v $y
where $incdir is the include directory for C, and '$y' stands for
each .C file. At this point you have nothing but object modules and
must now link them together:
alink faster Astartup.obj+main.o+...+run.o library $libdir/my.lib+$libdir/amiga.lib+$libs+$libdir/lc.lib to ram:shell
main.o+...+run.o stands for all the object modules. Note that my
library 'my.lib' must exist. Note also that Lattice's library is at
the end. $libdir stands for where your C libraries are.
Astartup.obj is Lattice's startup module which doesn't use Lattice's
library (thank god!). As I said above, the only routine used from
LC.LIB is their long multiply routine.
Executable Size should be around 24K.
(B) OVERVIEW:
overview of the major features:
-simple history
-redirection
-piping
-aliases
-variables & variable handling
-file name expansion via '?' and '*'
-conditionals
-source files (w/ gotos and labels)
-many built in commands to speed things up
changes from V1.02:
-you can now redirect through internal commands as well as external.
-piping has been added. You can pipe from/to internal commands.
-you can now embed strings ( charlie/$var/ben ), making the shell more
flexible.
-history substitution displays line to be executed.
-verbose mode for debugging source files
-break handled a little better (still can't send break to external
commands)
-some new commands
sorry, I still havent figured out how to get the return value from
external commands.
(C) QUICK TECH NOTES:
PIPES have been implimented using temporary RAM: files. Thus, you
should be careful when specifying a 'ram:*' expansion as it might
include the temp. files. These files are deleted on completion of
the pipe segment.
My favorite new feature is the fact that you can now redirect to and
from, and pipe internal commands. 'echo charlie >ram:x', for
instance. Another favorite:
echo "echo mem | shell" | shell
To accomplish these new features, I completely re-wrote the command
parser in execom.c
(D) COMMAND LINE PRE-PROCESSING:
preprocessing is done on the command line before it is passed on to
an internal or external routine:
^c where c is a character is converted to that control character.
Thus, say '^l' for control-l.
$name where name is a variable name. Variable names can consist of
0-9, a-z, A-Z, and underscore (_). The contents of the
specified variable is used. If the variable doesn't exist,
the specifier is used. That is, if the variable 'i' contains
'charlie', then '$i' -> 'charlie'. If the variable 'i' doesn't
exist, then '$i'->'$i' .
; delimits commands. echo charlie ; echo ben.
' ' (a space). delimits arguments.
"string" a quoted string. For instance, if you want to echo five spaces
and an 'a':
echo a -> a
echo " a" -> a
\c overide the meaning of special characters. '\^a' is a
circumflex and an a rather than control-a. To get a backslash,
you must say '\\'.
>file specify output redirection. All output from the command is
placed in the specified file.
<file specify input redirection. The command takes input from the
file rather than the keyboard (note: not all commands require
input). It makes no sense to say 'echo <charlie' since
the 'echo' command only outputs its arguments.
| PIPE specifier. The output from the command on the left becomes
the input to the command on the right. The current SHELL
implimentation uses temporary files to store the data.
!! execute the previously executed command.
!nn (nn is a number). Insert the history command numbered n (see
the HISTORY command)
!partial search backwards through the history list for a command which
looks the same as 'partial', and execute it.
(E) COMMAND LIST:
The first argument is the command-name... if it doesn't exist in the
list below and isn't an alias, it is assumed to be an external (disk)
command.
NOTE: Many CLI specific external commands, such as 'path', and 'cd' will
have no effect on the shell. However, you can execute these commands
from the initial CLI (startup script) BEFORE you run the shell.
HELP
simply displays all the available commands.
QUIT
quit my SHELL (awww!). End, El-Zappo, Kapow. Done, Finis
SET
SET name
SET name string
The first method lists all current variable settings.
The second method lists the setting for that particular variable,
or creates the variable if it doesn't exist (to "")
The last method sets a variable to a string.
UNSET name name name....
unset one or more variables. Deletes them entirely.
ALIAS
ALIAS name
ALIAS name string
same as SET, but applies to the alias list. You can alias a single
name to a set of commands. For instance:
alias hi "echo a; echo b"
then you can simply say 'hi'. Aliases come in two forms the second
form allows you to place the arguments after an alias in a variable
for retrieval:
alias xxx "%i echo this $i is a test"
% xxx charlie
this charlie is a test
The rest of the command line is placed in the specified variable
for the duration of the alias. This is especially useful when used
in conjunction with the 'FOREACH' command.
UNALIAS name name name...
delete aliases..
ECHO string
ECHO -n string
echo the string to the screen. If '-n' is specified, no newline is
output.
STRHEAD varname breakchar string
remove everything after and including the breakchar in 'string' and
place in variable 'varname':
% strhead j . aaa.bbb
% echo $j
aaa
%
STRTAIL varname breakchar string
remove everything before and including the breakchar in 'string' and
place in variable 'varname':
% strtail j . aaa.bbb
% echo $j
bbb
%
SOURCE file
execute commands from a file. You can create SHELL programs in
a file and then execute them with this command. Source'd files
have the added advantage that you can have loops in your command
files (see GOTO and LABEL)
MV from to
Exactly the Rename() call. Allows you to rename files or move them
around within a disk.
CD ..
CD path
Change your current working directory. You may specify '..' to go
back one directory (this is a CD specific feature, and does not
work with normal path specifications).
RM file file file...
DeleteFile(). Remove the specified files.
MKDIR name name name...
create the following directories.
HISTORY [partial string]
Displays the enumerated history list. The size of the list is
controlled by the _history variable. If you specify a partial-
string, only those entries matching that string are displayed.
MEM
Display current memory statistics.
CAT [file file....]
Type the specified files onto the screen. If no file is specified,
STDIN in used.
DIR [path path ... ]
Get a directory listing of the current directory or specified
directories.
DEVINFO [device: device:... ]
Display Device statistics for the current device (CD base), or
specified devices.
FOREACH varname ( strings ) command
'strings' is broken up into arguments. Each argument is placed in
the variable 'varname' in turn and 'command' executed. To execute
multiple commands, place them in quotes:
% foreach i ( a b c d ) "echo -n $i;echo \" ha\""
a ha
b ha
c ha
d ha
RETURN [value]
return from a source file. The rest of the source file is
discarded. Currently, the optional value is thrown away.
IF argument conditional argument ;
IF argument
If a single argument is something to another argument. Conditional
clauses allowed:
<, >, =, and combinations (wire or). Thus <> is not-equal, >=
larger or equal, etc...
If the left argument is numeric, both arguments are treated as
numeric.
usually the argument is either a constant or a variable ($varname).
The second form if IF is conditional on the existance of the argument.
If the argument is a "" string, then false , else TRUE.
ELSE ;
else clause.
ENDIF ;
the end of an if statement.
LABEL name
create a program label right here.
GOTO label
goto the specified label name. You can only use this command from a
source file.
FAILAT
CHECKBREAK
not implimented yet.
DEC var
INC var
decrement or increment the numerical equivalent of the variable and
place the ascii-string result back into that variable.
INPUT varname
input from STDIN (or a redirection, or a pipe) to a variable. The
next input line is placed in the variable.
VER
display my name and the version number.
SLEEP timeout
Sleep for 'timeout' seconds.
(F) SPECIAL SET VARIABLES
_prompt
This variable is set to the command you wish executed that will
create your prompt.
_history
This variable is set to a numerical value, and specifies how far
back your history should extend.
_debug
Debug mode... use it if you dare.
_verbose
Verbose mode (for source files). display commands as they are
executed.
(G) EXAMPLE .login file.
from a CLI or the startup-script say 'SHELL filename'. That file
is sourced first. thus, 'SHELL .login' will set up your favorite
aliases:
------------------------------ example source file -----------------
echo "shells, Matt"
alias l "%var if $var;echo $var;else;echo *;endif"
alias c "echo ^l"
alias cc "assign c: cb:c ;cd ram:"
alias wb "assign c: sys:c ;cd ram:"
alias ram "cp c:run ram:; cp c:assign ram:; cp c:cp ram:; assign c: ram:"
alias ram2 "assign c: ram:"
alias ed "run ED"
alias c1 "%z foreach y ( $z ) \"echo $y;lc1 -o$temp -i$incdir/ -i$incdir/lattice/ $y\";echo DONE"
alias c2 "%z foreach y ( $z ) \"echo $y;lc2 -s -v $temp$y\";echo DONE"
alias ld "%var alink faster $libdir/lstartup.obj+$var library $libdir/lc.lib+$libdir/amiga.lib to $dest"
alias lds "%var alink faster $libdir/Astartup.obj+$var library $libdir/my.lib+$libdir/amiga.lib+$libs to $dest"
set dest ram:a
set temp ram:
set libdir cb:clib
set incdir cb:include
set libs $libdir/lc.lib
cd ram:
--------------------------------------------------------------------
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'main.c'" '(1465 characters)'
if test -f 'main.c'
then
echo shar: "will not over-write existing file 'main.c'"
else
cat << \!Funky!Stuff! > 'main.c'
/*
* MAIN.C
*
* Matthew Dillon, 24 Feb 1986
*
* el main routine.
*/
#include "shell.h"
#include <libraries/dosextens.h>
extern long SetSignal();
char Inline[256];
main(argc, argv)
register char *argv[];
{
char *prompt;
register int i;
check32();
init_vars();
init();
for (i = 1; i < argc; ++i) {
strcpy (Inline, "source ");
strcat (Inline, argv[i]);
do_source (Inline, 0);
}
for (;;) {
if ((prompt = get_var (LEVEL_SET, V_PROMPT)) == NULL)
prompt = "echo -n \"% \"";
if (CHECKBREAK()) {
while (WaitForChar(Input(), 1))
gets(Inline);
}
++H_stack;
exec_command (prompt);
--H_stack;
if (Quit || !gets(Inline))
main_exit(0);
breakreset();
if (*Inline)
exec_command(Inline);
}
}
init_vars()
{
if (IsInteractive(Input()))
set_var (LEVEL_SET, V_PROMPT, "echo -n \"% \"");
else
set_var (LEVEL_SET, V_PROMPT, "");
set_var (LEVEL_SET, V_HIST, "20");
}
init()
{
static char pipe1[32], pipe2[32];
Cin = Input();
Cout= Output();
Uniq= FindTask(0);
Pipe1 = pipe1;
Pipe2 = pipe2;
sprintf (pipe1, "ram:pipe1_%ld", Uniq);
sprintf (pipe2, "ram:pipe2_%ld", Uniq);
}
main_exit(n)
{
free_memory();
exit (n);
}
breakcheck()
{
if (SetSignal(0,0) & SIGBREAKF_CTRL_C)
return (1);
else
return (0);
}
breakreset()
{
SetSignal(0, SIGBREAKF_CTRL_C);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'run.c'" '(789 characters)'
if test -f 'run.c'
then
echo shar: "will not over-write existing file 'run.c'"
else
cat << \!Funky!Stuff! > 'run.c'
/*
* RUN.C
*
* Matthew Dillon
*
*/
#include "shell.h"
do_run(str)
char *str;
{
register char *ptr, *scr;
register char *cin_name, *cout_name;
register int i;
cin_name = (Cin_name) ? Cin_name : "*";
cout_name= (Cout_name)? Cout_name: "*";
ptr = malloc(strlen(str) + strlen(cin_name) + strlen(cout_name) + 10);
for (scr = str; *scr && *scr != ' '; ++scr);
i = scr - str; /* str[i] is a space or \0 */
bmov (str, ptr, i);
ptr[i++] = ' ';
ptr[i++] = '<';
bmov (cin_name, ptr + i, strlen(cin_name));
i += strlen(cin_name);
ptr[i++] = ' ';
ptr[i++] = '>';
bmov (cout_name, ptr + i, strlen(cout_name));
i += strlen(cout_name);
strcpy (ptr + i, scr);
i = Execute (ptr, 0, 0);
free (ptr);
return ((i) ? 1 : -1);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'set.c'" '(3549 characters)'
if test -f 'set.c'
then
echo shar: "will not over-write existing file 'set.c'"
else
cat << \!Funky!Stuff! > 'set.c'
/*
* SET.C
*
* Matthew Dillon, July 1986
*
*/
#include "shell.h"
#define MAXLEVELS (3 + MAXSRC)
struct MASTER {
struct MASTER *next;
struct MASTER *last;
char *name;
char *text;
};
static struct MASTER *Mbase[MAXLEVELS];
char *
set_var(level, name, str)
register char *name, *str;
{
register struct MASTER *base = Mbase[level];
register struct MASTER *last;
register int len;
for (len = 0; isalphanum(name[len]); ++len);
while (base != NULL) {
if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) {
Free (base->text);
goto gotit;
}
last = base;
base = base->next;
}
if (base == Mbase[level]) {
base = Mbase[level] = (struct MASTER *)malloc (sizeof(struct MASTER));
base->last = NULL;
} else {
base = (struct MASTER *)malloc (sizeof(struct MASTER));
base->last = last;
last->next = base;
}
base->name = malloc (len + 1);
bmov (name, base->name, len);
base->name[len] = 0;
base->next = NULL;
gotit:
base->text = malloc (strlen(str) + 1);
strcpy (base->text, str);
return (base->text);
}
char *
get_var (level, name)
register char *name;
{
register struct MASTER *base = Mbase[level];
register unsigned char *scr;
register int len;
for (scr = name; *scr && *scr != 0x80 && *scr != ' ' && *scr != ';' && *scr != '|'; ++scr);
len = scr - name;
while (base != NULL) {
if (strlen(base->name) == len && strncmp (name, base->name, len) == 0)
return (base->text);
base = base->next;
}
return (NULL);
}
unset_level(level)
{
register struct MASTER *base = Mbase[level];
while (base) {
Free (base->name);
Free (base->text);
Free (base);
base = base->next;
}
Mbase[level] = NULL;
}
unset_var(level, name)
char *name;
{
register struct MASTER *base = Mbase[level];
register struct MASTER *last = NULL;
register int len;
for (len = 0; isalphanum(name[len]); ++len);
while (base) {
if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) {
if (base != Mbase[level])
last->next = base->next;
else
Mbase[level] = base->next;
if (base->next != NULL)
base->next->last = last;
if (base == Mbase[level])
Mbase[level] = base->next;
Free (base->name);
Free (base->text);
Free (base);
return (1);
}
last = base;
base = base->next;
}
return (-1);
}
do_unset_var(str, level)
char *str;
{
register int i;
for (i = 1; i < ac; ++i)
unset_var (level, av[i]);
return (1);
}
do_set_var(command, level)
char *command;
{
register struct MASTER *base = Mbase[level];
register char *str;
if (ac == 1) {
while (base) {
fprintf (Cout, "%-10s ", base->name);
Oputs (base->text);
base = base->next;
}
return (1);
}
if (ac == 2) {
str = get_var (level, av[1]);
if (str) {
fprintf (Cout, "%-10s ", av[1]);
Oputs(str);
} else {
set_var (level, av[1], "");
}
}
if (ac > 2)
set_var (level, av[1], next_word (next_word (command)));
if (*av[1] == '_') {
S_histlen = (str = get_var(LEVEL_SET, V_HIST)) ? atoi(str) : 0;
Debug = (str = get_var(LEVEL_SET, V_DEBUG)) ? atoi(str) : 0;
Verbose = (get_var(LEVEL_SET, V_VERBOSE)) ? 1 : 0;
if (S_histlen < 2) S_histlen = 2;
}
return (1);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'shell.h'" '(2220 characters)'
if test -f 'shell.h'
then
echo shar: "will not over-write existing file 'shell.h'"
else
cat << \!Funky!Stuff! > 'shell.h'
/*
* SHELL.H
*
* Matthew Dillon, 24 Feb 1986
*
*/
#include <exec/types.h>
#define MAXAV 128 /* Max. # arguments */
#define MAXSRC 5 /* Max. # of source file levels */
#define MAXIF 10 /* Max. # of if levels */
#define LEVEL_SET 0
#define LEVEL_ALIAS 1
#define LEVEL_LABEL 2
#define M_RESET 0
#define M_CONT 1
#define V_PROMPT "_prompt" /* Special variable names */
#define V_HIST "_history"
#define V_DEBUG "_debug"
#define V_VERBOSE "_verbose"
#define FL_DOLLAR 0x01 /* One of the following */
#define FL_BANG 0x02
#define FL_PERCENT 0x04
#define FL_QUOTE 0x08
#define FL_IDOLLAR 0x10 /* Any or all of the following may be set */
#define FL_EOC 0x20
#define FL_EOL 0x40
#define FL_OVERIDE 0x80
#define FL_WILD 0x100
#define FL_MASK (FL_DOLLAR|FL_BANG|FL_PERCENT|FL_QUOTE)
#define VERSION "V2.01 (c)1986 Matthew Dillon."
#ifndef NULL
#define NULL 0L
#endif
#define CHECKBREAK() ( breakcheck() ? (printf("^C\n"),1) : 0)
struct HIST {
struct HIST *next, *prev; /* doubly linked list */
char *line; /* line in history */
};
struct PERROR {
int errnum; /* Format of global error lookup */
char *errstr;
};
struct DPTR { /* Format of directory fetch pointer */
struct FileLock *lock; /* lock on directory */
struct FileInfoBlock *fib; /* mod'd fib for entry */
};
extern struct HIST *H_head, *H_tail;
extern struct PERROR Perror[];
extern struct DPTR *dopen();
extern char *set_var(), *get_var(), *next_word();
extern char *get_history(), *compile_av();
extern char *malloc(), *strcpy(), *strcat(), *AllocMem(), *gets(), *Ogets();
extern char **expand();
extern char *av[];
extern char *Current;
extern int H_len, H_tail_base, H_stack;
extern int Src_stack, If_stack;
extern int ac;
extern int Debug, Rval, Verbose, Disable, Faillevel, Quit;
extern int S_histlen, Uniq;
extern int Cin, Cout;
extern char *Cin_name, *Cout_name;
extern char *Pipe1, *Pipe2;
extern int Src_base[MAXSRC];
extern long Src_pos[MAXSRC];
extern char If_base[MAXIF];
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'sub.c'" '(10083 characters)'
if test -f 'sub.c'
then
echo shar: "will not over-write existing file 'sub.c'"
else
cat << \!Funky!Stuff! > 'sub.c'
/*
* SUB.C
*
* Matthew Dillon, 24 Feb 1986
*
*/
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "shell.h"
#define HM_STR 0
#define HM_REL 1
#define HM_ABS 2
extern struct FileLock *Lock(), *DupLock(), *CurrentDir();
extern struct FileLock *Clock;
char *
next_word(str)
register char *str;
{
while (*str && *str != ' ' && *str != 9)
++str;
while (*str && (*str == ' ' || *str == 9))
++str;
return (str);
}
char *
compile_av(av, start, end)
char **av;
{
char *cstr;
int i, len;
len = 0;
for (i = start; i < end; ++i)
len += strlen(av[i]) + 1;
cstr = malloc(len + 1);
*cstr = '\0';
for (i = start; i < end; ++i) {
strcat (cstr, av[i]);
strcat (cstr, " ");
}
return (cstr);
}
Free(ptr)
char *ptr;
{
static char *old_ptr;
if (old_ptr)
free (old_ptr);
old_ptr = ptr;
}
/*
* Add new string to history (H_head, H_tail, H_len,
* S_histlen
*/
add_history(str)
char *str;
{
register struct HIST *hist;
while (H_len > S_histlen)
del_history();
hist = (struct HIST *)malloc (sizeof(struct HIST));
if (H_head == NULL) {
H_head = H_tail = hist;
hist->next = NULL;
} else {
hist->next = H_head;
H_head->prev = hist;
H_head = hist;
}
hist->prev = NULL;
hist->line = malloc (strlen(str) + 1);
strcpy (hist->line, str);
++H_len;
}
del_history()
{
if (H_tail) {
--H_len;
++H_tail_base;
free (H_tail->line);
if (H_tail->prev) {
H_tail = H_tail->prev;
free (H_tail->next);
H_tail->next = NULL;
} else {
free (H_tail);
H_tail = H_head = NULL;
}
}
}
char *
get_history(ptr)
char *ptr;
{
register struct HIST *hist;
register int len;
int mode = HM_REL;
int num = 1;
char *str;
char *result = NULL;
if (ptr[1] >= '0' && ptr[1] <= '9') {
mode = HM_ABS;
num = atoi(&ptr[1]);
goto skip;
}
switch (ptr[1]) {
case '!':
break;
case '-':
num += atoi(&ptr[2]);
break;
default:
mode = HM_STR;
str = ptr + 1;
break;
}
skip:
switch (mode) {
case HM_STR:
len = strlen(str);
for (hist = H_head; hist; hist = hist->next) {
if (strncmp(hist->line, str, len) == 0) {
result = hist->line;
break;
}
}
break;
case HM_REL:
for (hist = H_head; hist && num--; hist = hist->next);
if (hist)
result = hist->line;
break;
case HM_ABS:
len = H_tail_base;
for (hist = H_tail; hist && len != num; hist = hist->prev, ++len);
if (hist)
result = hist->line;
break;
}
if (result)
puts (result);
return (result);
}
replace_head(str)
char *str;
{
if (str == NULL)
str = "";
if (H_head) {
free (H_head->line);
H_head->line = malloc (strlen(str)+1);
strcpy (H_head->line, str);
}
}
perror(str)
char *str;
{
ierror(str, IoErr());
}
ierror(str, err)
register char *str;
{
register struct PERROR *per = Perror;
if (err) {
for (; per->errstr; ++per) {
if (per->errnum == err) {
printf ("%s%s%s\n",
per->errstr,
(str) ? ": " : "",
(str) ? str : "");
return (err);
}
}
printf ("Unknown DOS error %ld %s\n", err, (str) ? str : "");
}
return (err);
}
/*
* Disk directory routines
*
* dptr = dopen(name, stat)
* struct DPTR *dptr;
* char *name;
* int *stat;
*
* dnext(dptr, name, stat)
* struct DPTR *dptr;
* char **name;
* int *stat;
*
* dclose(dptr) -may be called with NULL without harm
*
* dopen() returns a struct DPTR, or NULL if the given file does not
* exist. stat will be set to 1 if the file is a directory. If the
* name is "", then the current directory is openned.
*
* dnext() returns 1 until there are no more entries. The **name and
* *stat are set. *stat = 1 if the file is a directory.
*
* dclose() closes a directory channel.
*
*/
struct DPTR *
dopen(name, stat)
char *name;
int *stat;
{
struct DPTR *dp;
int namelen, endslash = 0;
namelen = strlen(name);
if (namelen && name[namelen - 1] == '/') {
name[namelen - 1] = '\0';
endslash = 1;
}
*stat = 0;
dp = (struct DPTR *)malloc(sizeof(struct DPTR));
if (*name == '\0')
dp->lock = DupLock (Clock);
else
dp->lock = Lock (name, ACCESS_READ);
if (endslash)
name[namelen - 1] = '/';
if (dp->lock == NULL) {
free (dp);
return (NULL);
}
dp->fib = (struct FileInfoBlock *)
AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC);
if (!Examine (dp->lock, dp->fib)) {
perror (name);
dclose (dp);
return (NULL);
}
if (dp->fib->fib_DirEntryType >= 0)
*stat = 1;
return (dp);
}
dnext(dp, pname, stat)
struct DPTR *dp;
char **pname;
int *stat;
{
if (dp == NULL)
return (0);
if (ExNext (dp->lock, dp->fib)) {
*stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1;
*pname = dp->fib->fib_FileName;
return (1);
}
return (0);
}
dclose(dp)
struct DPTR *dp;
{
if (dp == NULL)
return (1);
if (dp->fib)
FreeMem (dp->fib, sizeof(*dp->fib));
if (dp->lock)
UnLock (dp->lock);
free (dp);
return (1);
}
free_expand(av)
char **av;
{
char **base = av;
if (av) {
while (*av) {
free (*av);
++av;
}
free (base);
}
}
/*
* EXPAND(wild_name, pac)
* wild_name - char * (example: "df0:*.c")
* pac - int * will be set to # of arguments.
*
* Standalone, except in requires Clock to point to the Current-Directory
* lock.
*/
char **
expand(base, pac)
char *base;
int *pac;
{
char **eav = (char **)malloc (sizeof(char *));
int eleft, eac;
char *ptr, *name;
char *bname, *ename, *tail;
int stat, scr;
struct DPTR *dp;
*pac = eleft = eac = 0;
base = strcpy(malloc(strlen(base)+1), base);
for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
if (ptr < base) {
bname = strcpy (malloc(1), "");
} else {
scr = ptr[1];
ptr[1] = '\0';
bname = strcpy (malloc(strlen(base)+1), base);
ptr[1] = scr;
}
ename = ptr + 1;
for (ptr = ename; *ptr && *ptr != '/'; ++ptr);
scr = *ptr;
*ptr = '\0';
tail = (scr) ? ptr + 1 : NULL;
if ((dp = dopen (bname, &stat)) == NULL || stat == 0) {
free (bname);
free (base);
free (eav);
puts ("Could not open directory");
return (NULL);
}
while (dnext (dp, &name, &stat)) {
if (compare_ok(ename, name)) {
if (tail) {
int alt_ac;
char *search, **alt_av, **scrav;
struct FileLock *lock;
if (!stat) /* expect more dirs, but this not a dir */
continue;
lock = CurrentDir (Clock = dp->lock);
search = malloc(strlen(name)+strlen(tail)+2);
strcpy (search, name);
strcat (search, "/");
strcat (search, tail);
scrav = alt_av = expand (search, &alt_ac);
CurrentDir (Clock = lock);
if (scrav) {
while (*scrav) {
if (eleft < 2) {
char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
bmov (eav, scrav, (eac + 1) << 2);
free (eav);
eav = scrav;
eleft = 10;
}
eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1);
strcpy(eav[eac], bname);
strcat(eav[eac], *scrav);
free (*scrav);
++scrav;
--eleft, ++eac;
}
free (alt_av);
}
} else {
if (eleft < 2) {
char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
bmov (eav, scrav, (eac + 1) << 2);
free (eav);
eav = scrav;
eleft = 10;
}
eav[eac] = malloc (strlen(bname)+strlen(name)+1);
eav[eac] = strcpy(eav[eac], bname);
strcat(eav[eac], name);
--eleft, ++eac;
}
}
}
dclose (dp);
*pac = eac;
eav[eac] = NULL;
free (bname);
free (base);
if (eac)
return (eav);
free (eav);
return (NULL);
}
/*
* Compare a wild card name with a normal name
*/
#define MAXB 8
compare_ok(wild, name)
char *wild, *name;
{
char *w = wild;
char *n = name;
char *back[MAXB][2];
int bi = 0;
while (*n || *w) {
switch (*w) {
case '*':
if (bi == MAXB) {
puts ("Too many levels of '*'");
return (0);
}
back[bi][0] = w;
back[bi][1] = n;
++bi;
++w;
continue;
goback:
--bi;
while (bi >= 0 && *back[bi][1] == '\0')
--bi;
if (bi < 0)
return (0);
w = back[bi][0] + 1;
n = ++back[bi][1];
++bi;
continue;
case '?':
if (!*n) {
if (bi)
goto goback;
return (0);
}
break;
default:
if (*n != *w) {
if (bi)
goto goback;
return (0);
}
break;
}
if (*n) ++n;
if (*w) ++w;
}
return (1);
}
Oputs(str)
char *str;
{
Write (Cout, str, strlen(str));
Write (Cout, "\n", 1);
}
char *
Ogets(str)
char *str;
{
register int i = 0;
while (Read(Cin, str + i, 1) == 1) {
if (str[i] == '\n') {
str[i] = 0;
return (str);
}
if (++i == 255) {
str[i] = 0;
return (str);
}
}
return (NULL);
}
!Funky!Stuff!
fi # end of overwriting check
exit 0
# End of shell archive