amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (04/17/91)
Submitted-by: umueller@iiic.ethz.ch
Posting-number: Volume 91, Issue 093
Archive-name: shells/cshell-5.10/part06
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 6 (of 6)."
# Contents: execom.c
# Wrapped by tadguy@ab20 on Tue Apr 16 15:34:35 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'execom.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'execom.c'\"
else
echo shar: Extracting \"'execom.c'\" \(37168 characters\)
sed "s/^X//" >'execom.c' <<'END_OF_FILE'
X/*
X * EXECOM.C
X *
X * Matthew Dillon, 10 August 1986
X * Version 2.07M by Steve Drew 10-Sep-87
X * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
X * Version 5.00L by Urban Mueller 17-Feb-91
X *
X */
X
X#include "shell.h"
X
X#define DEFAULTFRAME 1024
X
X
Xtypedef struct StackFrame {
X struct StackFrame *next;
X int bytesleft;
X char *ptr;
X char mem[1];
X} FRAME;
X
X/* execom.c */
Xstatic char *compile_avf(FRAME **frame,char **av,int start,int end,char delim,int quote);
Xstatic int hasspace( char *s );
Xstatic void preformat(char *s, char *d);
Xstatic void backtrans(char *str);
Xstatic int fcomm(char *str,FRAME **frame,char *from);
Xstatic char *exarg(char **ptr, char *elast);
Xstatic char *format_insert_string(FRAME **frameptr, char *str, char *from);
Xstatic int find_command(char *str);
Xstatic void exec_every(void);
Xstatic void show_usage(char *str);
Xstatic void get_opt(char **av, int *ac, int ccno);
Xstatic int checkav( FRAME **frame,int n );
Xstatic char *tempname( int which );
Xstatic char *skipword( char *strskip );
Xstatic int myfgets( char *buf, FILE *in );
X
Xstatic void newframe( FRAME **frame, int bytes);
Xstatic char *falloc( FRAME **frame, int bytes );
Xstatic char *frealloc( FRAME **frame, char *oldstring, int morebytes );
Xstatic void funalloc( FRAME **frame, int bytes );
Xstatic char *push_cpy( FRAME **frame, char *s);
Xstatic void deleteframe( FRAME *frame);
X
Xint do_nothing(void);
X
Xstruct COMMAND {
X int (*func)();
X short minargs;
X short stat;
X int val;
X char *name;
X char *options;
X char *usage;
X};
X
X#define ST_COND 0x01
X#define ST_NORED 0x02
X#define ST_NOEXP 0x04
X#define ST_AV 0x08 /* delimit args within a variable */
X#define ST_FUNC 0x10
X#define ST_EQUAL 0x20
X
X#define COND ST_COND
X#define NORED ST_NORED
X#define NOEXP ST_NOEXP
X#define AV ST_AV
X#define FUNC ST_FUNC
X#define EQUAL ST_EQUAL
X
X#define ALIAS LEVEL_ALIAS
X#define SET LEVEL_SET
X#define LOCAL LEVEL_LOCAL
X
Xstruct COMMAND Command[] = {
X do_run, 0, AV, 0, "\001", NULL, NULL, /* may call do_source, do_cd */
X do_nothing, 0, 0, 0, "\002", NULL, NULL, /* dummy for aliases */
X do_nothing, 0, 0, 0, "\003", NULL, NULL, /* dummy for aliases with args */
X do_abortline, 0, 0, 0, "abortline", NULL, "",
X do_action, 2, 0, 9, "action", "av", "action file [args]",
X do_addbuffers,2, 0, 0, "addbuffers", NULL, "{drive bufs}",
X do_set_var, 0, 0, ALIAS, "alias", NULL, "[name [string] ]",/* uses avline */
X do_ascii, 0, 0, 0, "ascii", "oh", "-oh [string]",
X do_aset, 1, 0, 0, "aset", NULL, "name value",
X do_assign, 0, 0, 0, "assign", "lnp",",logical,-lnp {logical physical}",
X do_basename, 2, FUNC, 0, "basename", NULL, "var path",
X do_cat, 0, 0, 0, "cat", "n", "-n [file file...]",
X do_cd, 0, 0, 0, "cd", "g", "[path],-g path...path",
X do_class, 0, AV, 0, "class", "n", "-n name {type=param} \"actions\" {action=command}",
X do_close, 0, 0, 0, "close", NULL, "filenumber",
X do_copy, 1, 0, 0, "copy", "rudpfm","-dfmpru file file,-ud file...file dir,-ud dir...dir dir",
X do_copy, 1, 0, 0, "cp", "rudpfm","-dfmpru file file,-ud file...file dir,-ud dir...dir dir",
X do_date, 0, 0, 0, "date", "sr", "-sr [date/time]",
X do_inc, 1, 0, -1, "dec", NULL, "varname [step]",
X do_rm, 0, 0, 0, "delete", "rp", "-pr file...file",
X do_dir, 0,NOEXP, 0, "dir", "sfdcnhltbuikqavopzeg","-abcdefghiklnopqstuv [-z lformat] [path...path]",
X do_diskchange,1, 0, 0, "diskchange", NULL, "drive",
X do_echo, 0, AV, 0, "echo", "ne", "-ne string",
X do_if, 0, COND, 1, "else", NULL, "",
X do_if, 0, COND, 2, "endif", NULL, "",
X do_error, 1, 0, 0, "error", NULL, "num",
X do_exec, 1, 0, 0, "exec", NULL, "command",
X do_fault, 1, 0, 0, "fault", NULL, "error",
X do_filenote, 1, 0, 0, "filenote", "s", "file...file note,-s file...file",
X do_fileslist, 0, 0, 0, "flist", NULL, "",
X do_fltlower, 0, 0, 0, "fltlower", NULL, "<in >out",
X do_fltupper, 0, 0, 0, "fltupper", NULL, "<in >out",
X do_foreach, 3, 0, 0, "foreach", "v", "-v varname ( string ) command",
X do_forever, 1, 0, 0, "forever", NULL, "command",
X do_forline, 3, 0, 0, "forline", NULL, "var filename command",
X do_fornum, 4, 0, 0, "fornum", "vs", "-vs var n1 n2 command",
X do_getenv, 1, FUNC, 0, "getenv", NULL, "shellvar envvar",
X do_goto, 1, 0, 0, "goto", NULL, "label",
X do_head, 1, 0, 0, "head", NULL, "filename [num]",
X do_help, 0, 0, 0, "help", NULL, "",
X do_history, 0, 0, 0, "history", NULL, "[partial_string]",
X do_howmany, 0, 0, 0, "howmany", NULL, "",
X do_htype, 1, 0, 0, "htype", "r", "-r file...file",
X do_if, 1,COND|NORED,0, "if", "rftmdvn","-n arg cond arg,-n arg,-nf file,-nd dir -nm,-nt file...file,-nr rpn_expr,-v varname",
X do_inc, 1, 0, 1, "inc", NULL, "varname [step]",
X do_info, 0, 0, 0, "info", NULL, "[drive...drive]",
X do_input, 1, 0, 0, "input", "sr", "-rs var...var",
X do_join, 2, 0, 1, "join", "r", "-r file...file",
X do_keymap, 1, 0, 0, "keymap", "n", "-n number {key=function}",
X do_label, 1, COND, 0, "label", NULL, "name",
X do_local, 0, 0, 0, "local", NULL, "[var...var]",
X do_linecnt, 0, 0, 0, "linecnt", NULL, "<in >out",
X do_dir, 0,NOEXP, 0, "ls", "sfdcnhltbuikqavopzeg","-abcdefghiklnopqstuv [-z format] [path...path]",
X do_man, 0, 0, 0, "man", NULL, "command...command",
X do_mkdir, 0, 0, 0, "md", NULL, "name...name",
X do_mem, 0, 0, 0, "mem", "cfqsr","-cfqsr",
X do_menu, 0, 0, 0, "menu", "n", "-n [title item...item]",
X do_mkdir, 0, 0, 0, "mkdir", NULL, "name...name",
X do_mv, 2, 0, 0, "mv", NULL, "from to,from...from todir",
X do_open, 3, 0, 0, "open", NULL, "file mode number",
X do_path, 0, 0, 0, "path", "r", "-r [dir...dir]",
X do_pri, 2, 0, 0, "pri", NULL, "clinumber pri,0 pri",
X do_protect, 2, 0, 0, "protect", NULL, "file...file flags",
X do_ps, 0, 0, 0, "ps", "le", "-el [commandname...commandname]",
X do_pwd, 0, 0, 0, "pwd", NULL, "",
X do_qsort, 0, 0, 0, "qsort", "r", "-r <in >out",
X do_quit, 0,NORED, 0, "quit", NULL, "",
X do_truerun, 1,NORED, 1, "rback", NULL, "command",
X do_mv, 2, 0, 0, "rename", NULL, "from to,from...from todir",
X do_readfile, 1, 0, 0, "readfile", NULL, "varname [filename]",
X do_relabel, 2, 0, 0, "relabel", NULL, "drive name",
X do_resident, 0, 0, 0, "resident", "ard",",-ard file...file",
X do_return, 0, 0, 0, "return", NULL, "[n]",
X do_rm, 0, 0, 0, "rm", "rp", "-rp file...file",
X do_rpn, 0,NOEXP, 0, "rpn", NULL, "expression",
X do_rxrec, 0, 0, 0, "rxrec", NULL, "[portname]",
X do_rxsend, 2, 0, 0, "rxsend", "rl", "-lc portname string",
X do_truerun, 1,NORED, 0, "run", NULL, "command",
X do_search, 2, 0, 0, "search", "rcwneqvbfalo","-abceflnoqrvw file...file string",
X do_set_var, 0, AV, SET, "set", NULL, "[name [string] ]",
X do_setenv, 2, 0, 0, "setenv", NULL, "var value",
X do_sleep, 0, 0, 0, "sleep", NULL, "timeout",
X do_split, 1, 0, 0, "split", NULL, "srcvar dstvar...dstvar",
X do_source, 1, AV, 0, "source", NULL, "file", /* uses avline */
X do_stack, 0, 0, 0, "stack", NULL, "[bytes]",
X do_strhead, 3, FUNC, 0, "strhead", NULL, "varname breakchar string",
X do_strings, 1, 0, 0, "strings", "r", "-r file...file minlength",
X do_strleft, 3, FUNC, 0, "strleft", NULL, "varname string n",
X do_strlen, 2, FUNC, 0, "strlen", NULL, "varname string",
X do_strmid, 3, FUNC, 0, "strmid", NULL, "varname string n1 [n2]",
X do_strright, 3, FUNC, 0, "strright", NULL, "varname string n",
X do_strtail, 3, FUNC, 0, "strtail", NULL, "varname breakchar string",
X do_tackon, 3, FUNC, 0, "tackon", NULL, "var pathname filename",
X do_head, 1, 0, 1, "tail", NULL, "filename [num]",
X do_tee, 0, 0, 0, "tee", NULL, "<in >out",
X do_touch, 0, 0, 0, "touch", NULL, "file...file",
X do_truncate, 0, 0, 0, "truncate", NULL, "<in >out",
X do_cat, 0, 0, 0, "type", NULL, "-n [file...file]",
X do_unset_var, 0, 0, ALIAS, "unalias", NULL, "name...name",
X do_uniq, 0, 0, 0, "uniq", NULL, "<in >out",
X do_unset_var, 0, 0, LOCAL, "unlocal", NULL, "var...var",
X do_unset_var, 0, 0, SET, "unset", NULL, "name...name",
X do_usage, 0, 0, 0, "usage", NULL, "[command...command]",
X do_ver, 0, 0, 0, "version", NULL, "",
X do_waitport, 1, 0, 0, "waitforport",NULL, "portname [seconds]",
X do_whereis, 1,NOEXP, 0, "whereis", "r", "-r file [path...path]",
X do_window, 0,NOEXP, 0, "window", "slfbaq","-slfbaq",
X NULL, 0, 0, 0, NULL, NULL, NULL,
X};
X
X
X/* do_which, 1, 0, 0, "which", NULL, "command", */
X
X#ifdef isalphanum
Xchar isalph[256];
X#endif
X
Xint
Xexec_command( char *base )
X{
X FRAME *frame=NULL;
X char *scr, buf[6];
X int len, ret;
X
X if (!H_stack && S_histlen>1) {
X add_history(base);
X sprintf(buf, "%d", H_tail_base + H_len);
X set_var(LEVEL_SET, v_histnum, buf);
X }
X
X len=strlen(base)*3+20;
X newframe( &frame, len+DEFAULTFRAME );
X
X scr = falloc(&frame,len);
X preformat( base,scr );
X
X funalloc( &frame, len-strlen(scr)-2 );
X ret=fcomm(scr,&frame,NULL);
X
X deleteframe( frame );
X
X return ret;
X}
X
X#ifndef isalphanum
Xisalphanum( char c )
X{
X return (
X (c >= 'a' && c <= 'z') ||
X (c >= 'A' && c <= 'Z') ||
X (c >= '0' && c <= '9') ||
X (c == '_')
X );
X}
X#endif
X
X#define HOT_GAP 0x80
X#define HOT_BLANK 0x81
X#define HOT_STAR 0x82
X#define HOT_QUES 0x83
X#define HOT_EXCL 0x84
X#define HOT_SEMI 0x85
X#define HOT_PIPE 0x86
X#define HOT_DOLLAR 0x87
X#define HOT_IN 0x88
X#define HOT_OUT 0x89
X#define HOT_BSLASH 0x8a
X#define HOT_LASTCD 0x8b
X#define HOT_BACKG 0x8c
X#define HOT_CURLL 0x8d
X#define HOT_CURLR 0x8e
X#define HOT_CURDIR 0x8f
X#define HOT_PARDIR 0x90
X#define HOT_BEGOUT 0x91
X#define HOT_ENDOUT 0x92
X#define HOT_EQUAL 0x93
X#define HOT_BEGIN 0x94
X#define HOT_APOSTR 0x95
X
X
X
X
Xvoid
Xpreformat( char *s, char *d )
X{
X static char termchar[]={ 0, '}', ')', '`' };
X static char hotchar []={ 0, HOT_CURLR, HOT_ENDOUT, HOT_APOSTR };
X int qm=0, i, level, curmode, argc=0, beg=1;
X char mode[100], c;
X
X while (*s) {
X if (qm ) {
X while( *s && *s != '\"' && *s != '\\')
X *d++ = *s++;
X if( !*s ) break;
X }
X if( beg ) c=HOT_BEGIN,beg=0; else c=*s;
X switch (c) {
X case ' ':
X case 9:
X *d++ = HOT_BLANK;
Xargstart:
X while (*s == ' ' || *s == 9) ++s;
X if( *s == '\\' && !argc ) { *d++=HOT_BSLASH; if( *d++=*++s ) ++s; }
X if( *s == '~' ) { *d++=HOT_LASTCD; s++; }
X else if( *s=='.'&&s[1]=='.') { *d++=HOT_PARDIR; *d++='.'; s+=2; }
X else if( *s=='.' ) { *d++=HOT_CURDIR; s++; }
X else if( argc && (!*s || *s == '|' || *s == ';' || *s=='#')) --d;
X argc++;
X break;
X case '*':
X *d++ = HOT_GAP;
X *d++ = HOT_STAR;
X ++s;
X break;
X case '?':
X *d++ = HOT_GAP;
X *d++ = HOT_QUES;
X ++s;
X break;
X case '!':
X *d++ = HOT_EXCL;
X ++s;
X break;
X case '#':
X *d++ = '\0';
X while (*s) ++s;
X break;
X case HOT_BEGIN:
X argc=0;
X goto argstart;
X case ';':
X *d++= HOT_SEMI, argc=0, s++;
X goto argstart;
X case '|':
X *d++= HOT_PIPE, argc=0, s++;
X goto argstart;
X case '\\':
X if( (i=*++s-'0')>=0 && i<=7 ) {
X if( *++s>='0' && *s<='7' ) {
X i= 8*i + *s++-'0';
X if( *s>='0' && *s<='7' )
X i= 8*i + *s++-'0';
X }
X *d++ = i;
X } else {
X *d++ = *s;
X if (*s) ++s;
X }
X break;
X case '\"':
X qm = 1 - qm;
X ++s;
X break;
X case '^':
X *d++ = *++s & 0x1F;
X if (*s) ++s;
X break;
X case '<':
X *d++ = HOT_IN;
X ++s;
X break;
X case '>':
X *d++ = HOT_OUT;
X ++s;
X break;
X case '&':
X *d++ = HOT_BACKG;
X ++s;
X break;
X case '$': /* search end of var name */
X if( s[1]=='(' ) {
X curmode=2;
X *d++=HOT_BEGOUT;
X *d++=*++s;
X goto brace;
X }
X *d++ = HOT_GAP;
X *d++ = HOT_DOLLAR;
X ++s;
X while (isalphanum(*s)) *d++ = *s++;
X *d++ = HOT_GAP;
X break;
X case '`':
X curmode=3;
X *d++=HOT_APOSTR;
X goto brace;
X case '{':
X curmode=1;
X *d++ = HOT_CURLL;
Xbrace:
X level=0; s++;
X mode[level++]=curmode;
X while( *s && level ) {
X switch( *s ) {
X case '\"': *d++=*s++;
X while( *s && *s!='\"' )
X if( *s=='\\' ) { *d++=*s++; if( *s ) *d++=*s++; }
X else *d++=*s++;
X if( *s ) *d++=*s++;
X break;
X case '\\': *d++=*s++; if( *s ) *d++=*s++;
X break;
X case '{' : mode[level++]=1; s++;
X break;
X case '}' :
X case ')' :
X case '`' : for( i=level-1; i>=0 && termchar[mode[i]]!=*s;--i ) ;
X if( i==0 ) *d++=hotchar [mode[i]];
X if( i>=0 ) level=i;
X s++;
X break;
X default : *d++=*s++;
X break;
X }
X }
X break;
X default:
X *d++ = *s++;
X while( *s>=65 && (*s&31)<=26 )
X *d++=*s++;
X break;
X }
X }
X *d++=0;
X *d=0;
X if (debug) fprintf (stderr,"PREFORMAT: %d :%s:\n", strlen(d), d);
X return;
X}
X
Xstatic void
Xbacktrans( char *str )
X{
X while( *str ) {
X while( *(signed char *)str>0 ) str++;
X if( !*str ) break;
X switch( *str) {
X case HOT_GAP : *str++=0; break;
X case HOT_BLANK : *str++=' '; break;
X case HOT_STAR : *str++='*'; break;
X case HOT_QUES : *str++='?'; break;
X case HOT_EXCL : *str++='!'; break;
X case HOT_SEMI : *str++=';'; break;
X case HOT_PIPE : *str++='|'; break;
X case HOT_DOLLAR: *str++='$'; break;
X case HOT_IN : *str++='<'; break;
X case HOT_OUT : *str++='>'; break;
X case HOT_BSLASH: *str++='\\'; break;
X case HOT_LASTCD: *str++='~'; break;
X case HOT_BACKG : *str++='&'; break;
X case HOT_CURLL : *str++='{'; break;
X case HOT_CURLR : *str++='}'; break;
X case HOT_CURDIR: *str++='.'; break;
X case HOT_PARDIR: *str++='.'; break;
X case HOT_BEGOUT: *str++='$'; break;
X case HOT_ENDOUT: *str++=')'; break;
X case HOT_EQUAL : *str++='='; break;
X case HOT_APOSTR: *str++='`'; break;
X default : str++; break;
X }
X }
X}
X
X/*
X * process formatted string. ' ' is the delimeter.
X *
X * 0: check '\0': no more, stop, done.
X * 1: check $. if so, extract, format, insert
X * 2: check alias. if so, extract, format, insert. goto 1
X * 3: check history or substitution, extract, format, insert. goto 1
X *
X * 4: assume first element now internal or disk based command.
X *
X * 5: extract each ' ' or 0x80 delimited argument and process, placing
X * in av[] list (except 0x80 args appended). check in order:
X *
X * '$' insert string straight
X * '>' setup stdout
X * '>>' setup stdout flag for append
X * '<' setup stdin
X * '*' or '?' do directory search and insert as separate args.
X *
X * ';' 0 '|' end of command. if '|' setup stdout
X * -execute command, fix stdin and out (|) sets
X * up stdin for next guy.
X */
X
Xint alias_count;
Xint has_wild; /* set if any arg has wild card */
Xchar *LastCommand;
XBPTR OldCin;
X
X#define MAXACDEF 32
X
Xint
Xfcomm( char *str, FRAME **frameptr, char *from )
X{
X char *nextstr, *command;
X char *pend_alias;
X char cout_ispipe=0, cin_ispipe=0, cout_append=0, elast;
X char backg, firstrun, override, block;
X char *cin_name=NULL, *cout_name=NULL;
X char **oldav=av;
X int oldac=ac, oldmax=max_ac, err, ccno, cstat;
X
X max_ac= MAXACDEF;
X av=(char **)falloc( frameptr, max_ac*sizeof(char *));
X ac=0;
X
X if (++alias_count >= MAXALIAS) { /* Recursion getting too deep? */
X fprintf(stderr,"Alias Loop\n");
X err = 20;
X goto done1;
X }
X
Xnextcommand:
X command = NULL;
X pend_alias= NULL;
X err = 0;
X has_wild = 0;
X firstrun = 1;
X ccno=cstat= 0;
X elast = 1;
X block = 0;
X
X if (*str == 0)
X goto done1;
X
X if (*str == HOT_EXCL) {
X char *p, c, *istr; /* fix to allow !cmd1;!cmd2 */
X for(p = str; *p && *p != HOT_SEMI ; ++p);
X c = *p;
X *p = 0;
X if( str[1]==HOT_EXCL ) str[1]='!';
X istr = get_history(str,1);
X *p = c;
X replace_head(istr);
X str = format_insert_string( frameptr, str, istr );
X }
X
X /*******************************************************
X * Part one of the parser:
X * The argument line is generated as an array of strings
X */
X
X nextstr = str;
X ac = 0;
X do { /* outer loop: each pass typically generates one av[ac] */
X char *arg, *ptr;
X short redir;
X short doexpand;
X short cont;
X short inc;
X
X av[ac] = NULL;
X cont = 1;
X doexpand = redir = inc = 0;
X
X while (cont && elast) { /* inner loop: adds one piece to av[ac] */
X ptr = exarg(&nextstr,&elast);
X inc = 1;
X cont = (elast == 0x80);
X switch (*ptr) { /* arg must be set in every case */
X case HOT_IN:
X redir = -2;
X case HOT_OUT:
X if (cstat & (ST_NORED | ST_COND)) { /* don't extract */
X redir = 0; /* <> stuff if its */
X arg = ptr; /* external cmd. */
X break;
X }
X ++redir;
X arg = ptr + 1;
X if (*arg == HOT_OUT) {
X redir = 2; /* append >> */
X ++arg;
X }
X cont = 1;
X break;
X case HOT_DOLLAR:
X /* restore args if from set command or pend_alias */
X if ((arg = get_var(LEVEL_SET, ptr + 1)) != NULL) {
X char *pe, sv;
X while (pe = index(arg,0xA0)) {
X sv = *pe;
X *pe = '\0';
X checkav(frameptr,1);
X
X if (av[ac]) {
X av[ac] = frealloc( frameptr,av[ac],strlen(arg));
X strcat(av[ac++], arg);
X } else
X av[ac++] = push_cpy(frameptr,arg);
X
X *pe = sv;
X av[ac] = NULL;
X arg = pe+1;
X }
X } else
X arg = ptr;
X break;
X case HOT_LASTCD:
X if ((!ptr[1] || ptr[1]=='/')&&(arg=get_var(LEVEL_SET, v_lcd))) {
X if( ptr[1] ) {
X strcpy(Buf,arg);
X strcat(Buf,ptr+1);
X arg=Buf;
X }
X } else
X arg = ptr;
X break;
X case HOT_CURDIR:
X arg=ptr;
X if( !ptr[1] || ptr[1]=='/' )
X arg= ptr[1] ? ptr+2 : ptr+1;
X break;
X case HOT_PARDIR:
X arg=ptr;
X if( !ptr[2] || ptr[2]=='/' )
X arg= ptr[2] ? ptr+2 : "/";
X break;
X
X case HOT_STAR:
X case HOT_QUES:
X if( !(cstat & ST_NOEXP) && !(pend_alias && *pend_alias=='*'))
X if( ac!=1 || av[1]&&*av[1] || *ptr!=HOT_QUES || ptr[1] )
X doexpand = 1;
X arg = ptr;
X break;
X default:
X arg = ptr;
X break;
X }
X
X /* Append arg to av[ac] */
X
X if (av[ac]) {
X av[ac] = frealloc( frameptr,av[ac],strlen(arg));
X strcat(av[ac], arg);
X } else
X av[ac] = push_cpy(frameptr,arg);
X
X if (elast != 0x80)
X break;
X }
X
X /* one argument is now complete */
X
X backg = *av[ac] && av[ac][strlen(av[ac])-1]==HOT_BACKG;
X override= *av[ac] == HOT_BSLASH;
X
X if( firstrun && *av[0] == HOT_CURLL ) {
X char *end;
X av[0]++;
X if( end=index(av[0],HOT_CURLR)) *end=0;
X block=1;
X }
X
X if( *av[ac]==HOT_BEGOUT || *av[ac]==HOT_APOSTR ) {
X BPTR cout, oldcout= Myprocess->pr_COS;
X FILE *in;
X char *t, *val;
X int apo;
X
X apo= *av[ac]==HOT_APOSTR;
X inc=0;
X if( t=index(av[ac]+1, apo ? HOT_APOSTR : HOT_ENDOUT ))
X *t=0;
X
X if(!(cout = Open(tempname(2),MODE_NEWFILE))) {
X err= 20;
X ierror (NULL, 504);
X } else {
X Myprocess->pr_COS = DEVTAB(stdout) = cout;
X execute(av[ac]+2-apo);
X Close(cout);
X
X if(!(in=fopen(tempname(2),"r"))) {
X err= 1;
X ierror (NULL, 504);
X } else {
X while( myfgets(Buf,in))
X if( apo ) {
X for( val=Buf; t=index(val,' '); val=t+1)
X *t=0, av[ac++]=push_cpy(frameptr,val);
X av[ac++]= push_cpy(frameptr,val);
X } else
X av[ac++]= push_cpy(frameptr,Buf);
X fclose(in);
X DeleteFile(tempname(2));
X }
X }
X
X Myprocess->pr_COS = DEVTAB(stdout) = oldcout;
X }
X
X backtrans( av[ac] );
X
X if (doexpand) { /* process expansion */
X char **eav, **ebase;
X int eac;
X has_wild = 1;
X eav = ebase = expand(av[ac], &eac);
X inc = 0;
X if (eav) {
X if( checkav( frameptr, eac ) ) {
X ierror (NULL, 506);
X err = 1;
X } else {
X QuickSort(eav, eac);
X for (; eac; --eac, ++eav)
X av[ac++] = push_cpy(frameptr,*eav);
X }
X free_expand (ebase);
X }
X } else if( av[ac][0]==')' ) {
X int i;
X char *pe, sv;
X for( i=ac-1; i>0; i-- )
X if( *av[i]=='@' )
X break;
X if( i>0 && av[i][strlen(av[i])-1]=='(' ) {
X extern int exec_fn_err;
X char *exec_function();
X char *avi=av[i], *last=av[ac];
X av[i]=v_value; av[ac]=NULL;
X arg=exec_function( avi+1, av+i, ac-i );
X av[i]=avi; av[ac]=last;
X inc=0;
X if( exec_fn_err<0 )
X ac++;
X else if( exec_fn_err>0 || !arg )
X ac=i, av[ac]=NULL;
X else {
X ac=i;
X while (pe = index(arg,0xA0)) {
X sv = *pe;
X *pe = '\0';
X checkav( frameptr, 1 );
X av[ac++] = push_cpy(frameptr,arg);
X *pe = sv;
X arg= pe+1;
X }
X av[ac] = falloc(frameptr,strlen(arg)+strlen(last+1)+4);
X strcpy(av[ac],arg);
X strcat(av[ac++], last+1 );
X }
X }
X }
X
X /*******************************
X * special handling of first arg
X */
X
X if( firstrun ) { /* we just found out the command */
X firstrun=0;
X command=av[0];
X
X if (*command == 0)
X goto done0;
X
X if( block )
X pend_alias=command;
X else if ( override )
X memmove( command, command+1, strlen(command));
X else {
X pend_alias=get_var(LEVEL_ALIAS,command); /* if not \command */
X if( pend_alias && pend_alias==from )
X pend_alias=NULL;
X }
X
X if( pend_alias )
X ccno=*pend_alias=='%' || *pend_alias=='*' ? 2 : 1;
X else
X ccno=find_command(command);
X cstat=Command[ccno].stat;
X
X if ( !(cstat & ST_COND) && (disable || forward_goto) ) {
X while (elast && elast != HOT_SEMI && elast != HOT_PIPE)
X exarg(&nextstr,&elast);
X goto done0;
X }
X }
X
X if (redir && !err) { /* store redirection */
X char *file = (doexpand) ? av[--ac] : av[ac];
X
X if (redir < 0)
X cin_name = file;
X else {
X cout_name = file;
X cout_append = (redir == 2);
X }
X inc = 0;
X }
X
X if (inc) { /* check elast for space */
X ++ac;
X if( checkav(frameptr,1) ) {
X ierror (NULL, 506);
X err = 1; /* error condition */
X elast = 0; /* don't process any more arguemnts */
X }
X }
X } while( elast==HOT_BLANK );
X av[ac] = NULL;
X
X
X /******************************************************************
X * Part two:
X * The argument line is processed (pipes, commands, recursive calls
X */
X
X /* process pipes via files */
X
X if (elast == HOT_PIPE && !err) {
X static int which; /* 0 or 1 in case of multiple pipes */
X which = 1 - which;
X cout_name = tempname( which );
X cout_ispipe = 1;
X }
X
X
X if (err)
X goto done0;
X
X {
X char *avline;
X char delim = ' ';
X BPTR oldcin = Myprocess->pr_CIS, cin=NULL;
X BPTR oldcout = Myprocess->pr_COS, cout=NULL;
X char *cin_buf=NULL;
X struct FileHandle *ci=NULL;
X long oldbuf=NULL;
X
X if( backg ) {
X char *larg=av[ac-1];
X memmove( av+1, av, ac*sizeof(*av));
X command=av[0]="rback";
X ccno=find_command(command);
X cstat=Command[ccno].stat;
X if( strlen(larg)>1 )
X larg[strlen(larg)-1]=0, ac++;
X }
X if( ccno==2 || (cstat & ST_AV)) /* alias with argument */
X delim = 0xA0;
X avline = compile_avf(frameptr,av,(pend_alias?1:0), ac, delim, ccno==1);
X
X OldCin=oldcin;
X fflush(stdout);
X LastCommand=command;
X if ( !(cstat & (ST_NORED | ST_COND))) { /* redirection not disabled */
X if (cin_name) {
X if (!(cin = extOpen(cin_name,MODE_OLDFILE))) {
X ierror (NULL, 504);
X err = 20;
X cin_name = NULL;
X } else {
X Myprocess->pr_CIS = DEVTAB(stdin) = cin;
X ci = (struct FileHandle *)(cin<<2);
X cin_buf = SAllocMem(202L, MEMF_PUBLIC);
X oldbuf = ci->fh_Buf;
X if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
X ci->fh_Buf = (long)cin_buf>>2;
X }
X }
X if (cout_name) {
X if (cout_append && (cout =extOpen(cout_name,1005L))) {
X Seek(cout, 0L, OFFSET_END );
X } else {
X cout = extOpen(cout_name,MODE_NEWFILE);
X }
X if (cout == NULL) {
X err = 20;
X ierror (NULL, 504);
X cout_name = NULL;
X cout_append = 0;
X } else {
X Myprocess->pr_COS = DEVTAB(stdout) = cout;
X }
X }
X }
X
X if( Verbose&VERBOSE_ALIAS ) {
X if( Verbose&VERBOSE_HILITE ) fprintf(stderr,"%s",o_hilite);
X if( pend_alias )
X fprintf(stderr,"%-*s%s %s\n",alias_count,">",av[0],avline);
X else
X fprintf(stderr,"%-*s%s\n",alias_count,">",avline);
X if( Verbose&VERBOSE_HILITE ) fprintf(stderr,"%s",o_lolite);
X }
X
X if( pend_alias ) {
X char *scr;
X FRAME *subframe=NULL;
X
X if( ccno==2 ) { /* has arguments */
X char *ptr=pend_alias, *val=avline;
X int clen;
X
X clen=strlen(ptr)*2+20;
X newframe( &subframe, clen+DEFAULTFRAME );
X push_locals( (ROOT *)falloc( &subframe, sizeof(ROOT) ));
X do { /* set all args */
X char *varname, *gap=NULL;
X for( varname= ++ptr; *ptr && *ptr!=' ' && *ptr!='%'; ++ptr);
X if( *ptr=='%' && (gap=index(val,0xA0 )) ) *gap=0;
X set_var( LEVEL_LOCAL, varname, val );
X val= gap ? gap+1 : "";
X } while( *ptr=='%' );
X scr = falloc(&subframe,clen);
X preformat (ptr, scr);
X } else {
X char *scr2;
X int clen=strlen(pend_alias)+strlen(avline)+20;
X
X newframe( &subframe,3*clen+DEFAULTFRAME );
X push_locals( (ROOT *)falloc( &subframe, sizeof(ROOT) ));
X scr2= falloc( &subframe,clen );
X sprintf(scr2,"%s %s",pend_alias,avline);
X scr = falloc( &subframe, 2*clen );
X preformat( scr2,scr);
X }
X fcomm (scr,&subframe,pend_alias);
X pop_locals();
X deleteframe(subframe);
X } else {
X if (ac < Command[ccno].minargs + 1) {
X show_usage( NULL );
X err = 20;
X if (E_stack == 0 )
X seterr(err);
X } else if (!err) {
X int (*func)(char*,int)=Command[ccno].func, i;
X get_opt( av, &ac, ccno );
X i=0;
X if( ccno>0 && ac==2 && !strcmp(av[1],"?") )
X show_usage(avline);
X else
X i = (*func)(avline, Command[ccno].val); /* do the call */
X if (i < 0)
X i = 20;
X err = i;
X if (E_stack == 0 )
X seterr(err);
X fflush(stderr);
X }
X }
X if (!(cstat & (ST_NORED | ST_COND))) {
X if (cin_name) {
X ci->fh_Buf = oldbuf;
X fflush(stdin);
X clearerr(stdin);
X#ifdef AZTEC_C
X stdin->_bp=stdin->_bend;
X#else
X stdin->_rcnt=stdin->_wcnt;
X#endif
X extClose(cin);
X FreeMem(cin_buf, 202L);
X }
X if (cout_name) {
X fflush(stdout);
X clearerr(stdout);
X#ifdef AZTEC_C
X stdout->_flags &= ~_IODIRTY; /* because of nil: device */
X#endif
X extClose(cout);
X cout_append = 0;
X }
X }
X Myprocess->pr_CIS = DEVTAB(stdin) = oldcin;
X Myprocess->pr_COS = DEVTAB(stdout) = oldcout;
X
X if (cin_ispipe && cin_name)
X DeleteFile(cin_name);
X if (cout_ispipe) {
X cin_name = cout_name; /* ok to assign.. static name */
X cin_ispipe = 1;
X } else {
X cin_name = NULL;
X }
X cout_name = NULL;
X cout_ispipe = 0;
X }
X
Xdone0:
X {
X char *exc;
X if (err && E_stack==0) {
X exc = get_var(LEVEL_SET, v_except);
X if (err >= ((exc)?atoi(exc):1)) {
X if (exc) {
X ++H_stack, ++E_stack;
X a0tospace(exc);
X exec_command(exc);
X --E_stack, --H_stack;
X } else {
X Exec_abortline = 1;
X }
X }
X seterr(err);
X }
X if (elast != 0 && Exec_abortline == 0) {
X memmove( str, nextstr, strlen(nextstr)+1 );
X goto nextcommand;
X }
X Exec_abortline = 0;
X if (cin_name)
X DeleteFile(cin_name);
X }
Xdone1:
X
X av=oldav; ac=oldac; max_ac=oldmax;
X --alias_count;
X return err; /* TRUE = error occured */
X}
X
X
Xstatic char *
Xexarg(char **ptr, char *elast)
X{
X char *end, *start;
X
X start = end = *ptr;
X while ( *(signed char *)end>0 || *end && *end != 0x80 &&
X *end != HOT_SEMI && *end != HOT_PIPE && *end != HOT_BLANK)
X ++end;
X *elast = *end;
X *end = '\0';
X *ptr = end + 1;
X return start;
X}
X
X
Xstatic void
Xnewframe(FRAME **frameptr, int bytes)
X{
X FRAME *new;
X
X new=salloc( bytes + 4 + sizeof(FRAME) );
X new->next= *frameptr;
X
X new->bytesleft = bytes;
X new->ptr = new->mem;
X *frameptr=new;
X}
X
Xstatic char *
Xfalloc( FRAME **frameptr, int bytes )
X{
X char *mem,inc;
X
X bytes+=2; /* 2 extra bytes for do_run */
X
X if( (*frameptr)->bytesleft <= bytes )
X newframe( frameptr, bytes+DEFAULTFRAME );
X
X inc=4-((long)(*frameptr)->ptr&3); /* 1 extra byte and longword alignment */
X mem=(*frameptr)->ptr+inc;
X (*frameptr)->bytesleft-=bytes+inc;
X (*frameptr)->ptr +=bytes+inc;
X return mem;
X}
X
Xstatic char *
Xfrealloc( FRAME **frameptr, char *oldstring, int morebytes )
X{
X char *mem=oldstring;
X
X if( (*frameptr)->bytesleft <= morebytes ) {
X int oldlen=(*frameptr)->ptr-oldstring;
X newframe( frameptr, oldlen+morebytes+DEFAULTFRAME );
X mem= (*frameptr)->ptr;
X strcpy((*frameptr)->ptr,oldstring);
X oldlen+=morebytes;
X (*frameptr)->ptr +=oldlen;
X (*frameptr)->bytesleft-=oldlen;
X }
X (*frameptr)->bytesleft-=morebytes;
X (*frameptr)->ptr +=morebytes;
X return mem;
X}
X
Xstatic void
Xfunalloc( FRAME **frameptr, int bytes )
X{
X (*frameptr)->bytesleft+=bytes;
X (*frameptr)->ptr -=bytes;
X}
X
X
X
Xvoid
Xdeleteframe(FRAME *frame)
X{
X FRAME *nxt;
X
X for( ; frame; frame=nxt ) {
X nxt=frame->next;
X free(frame);
X }
X}
X
X/*
X * Insert 'from' string in front of 'str' while deleting the
X * first entry in 'str'. if freeok is set, then 'str' will be
X * free'd
X */
X
Xstatic char *
Xformat_insert_string(FRAME **frameptr, char *str, char *from)
X{
X char *new, *strskip;
X int len;
X
X strskip=skipword( str );
X len = strlen(from)*3+20;
X new = falloc( frameptr, len);
X preformat(from, new);
X funalloc( frameptr, len -strlen(new) - 2 );
X frealloc( frameptr, new, strlen(strskip)+2);
X strcat(new, strskip);
X new[strlen(new)+1] = 0;
X return new;
X}
X
Xstatic char *
Xskipword( char *strskip )
X{
X for ( ; *(signed char *)strskip>0
X || *strskip && *strskip != HOT_BLANK
X && *strskip != HOT_SEMI && *strskip != HOT_PIPE
X && *strskip != 0x80; ++strskip);
X return strskip;
X}
X
Xchar *
Xfind_internal( char *str )
X{
X return Command[find_command(str)].name;
X}
X
Xstatic int
Xfind_command( char *str )
X{
X int i, len = strlen(str);
X struct COMMAND *com;
X char c=*str;
X
X for( com=Command, i=0; com->func; com++, i++ )
X if ( c==*com->name && !strncmp(str, com->name, len))
X if(o_abbrev || len==strlen(com->name))
X return i;
X return 0;
X}
X
Xint exec_fn_err;
X
Xextern struct FUNCTION {
X short id, minargs, maxargs;
X char *name;
X} Function[];
X
X
Xchar *gotfunc( int i, char **fav, int fac );
X
Xchar *
Xexec_function( char *str, char **fav, int fac)
X{
X int len=strlen(str)-1, i;
X
X exec_fn_err=0;
X for (i = 0; Command[i].func; ++i)
X if ( Command[i].stat&ST_FUNC && !strncmp(str,Command[i].name,len)) {
X if( fac<Command[i].minargs ) {
X exec_fn_err=20;
X return NULL;
X } else {
X int (*func)( void )=Command[i].func;
X char **oldav=av;
X int oldac=ac;
X av=fav-1, ac=fac+1;
X exec_fn_err=(*func)();
X av=oldav, ac=oldac;
X return get_var( LEVEL_SET, fav[0] );
X }
X }
X for (i = 0; Function[i].id; ++i)
X if ( len==strlen(Function[i].name)&&!strncmp(str,Function[i].name,len))
X return gotfunc( i,fav,fac );
X
X exec_fn_err=-1;
X return NULL;
X}
X
Xint
Xechofunc(void)
X{
X int i;
X char *str;
X
X if( !strlen(av[0]) ) return -1;
X exec_fn_err=0;
X for (i = 0; Function[i].id; ++i)
X if ( !strcmp(av[0],Function[i].name)) {
X if(str=gotfunc( i,av,ac ))
X printf("%s\n",str);
X return exec_fn_err;
X }
X return -1;
X}
X
X
Xchar *
Xgotfunc( int i, char **fav, int fac )
X{
X fac--; fav++;
X if( fac<Function[i].minargs ) {
X fprintf( stderr, "Not enough arguments for @%s\n",
X Function[i].name );
X exec_fn_err=20;
X return NULL;
X } else if( fac>Function[i].maxargs ) {
X if( ac > Function[i].maxargs )
X fprintf( stderr, "Too many arguments for @%s\n",
X Function[i].name );
X exec_fn_err=20;
X return NULL;
X } else {
X exec_fn_err=dofunc( Function[i].id, fav, fac);
X return get_var( LEVEL_SET, v_value );
X }
X return NULL;
X}
X
X
X
Xdo_help()
X{
X struct COMMAND *com;
X int i=0;
X
X for (com = &Command[3]; com->func; ++com) {
X printf ("%-12s", com->name);
X if (++i % 6 == 0) printf("\n");
X }
X printf("\n\nUse man <command> for more information\n");
X return 0;
X}
X
Xdo_nothing()
X{
X return 0;
X}
X
Xstatic char *
Xpush_cpy(FRAME **frameptr, char *s)
X{
X return strcpy(falloc(frameptr,strlen(s)+1), s);
X}
X
Xvoid
Xexec_every(void)
X{
X char *str = get_var(LEVEL_SET, v_every);
X
X if (str) {
X ++H_stack, ++E_stack;
X a0tospace( str );
X exec_command(str);
X --E_stack, --H_stack;
X }
X}
X
Xchar *
Xa0tospace( str )
X char *str;
X{
X char *get=str, *put=str;
X
X while( *get )
X if( *get==0xA0 )
X *put++=' ', get++;
X else
X *put++=*get++;
X return str;
X}
X
Xvoid
Xshow_usage( str )
X char *str;
X{
X int ccno, first=0, err=0;
X char *get, *put, buf[300];
X
X if( !str )
X str=LastCommand, err=1;
X for( put=str; *put && (*put&127)!=32; put++ ) ;
X *put=0;
X
X put=buf;
X ccno = find_command (str);
X if( get= Command[ccno].usage ) {
X do {
X put+=sprintf(put, first++?" %s ":"Usage: %s ",
X Command[ccno].name );
X if( *get=='-' ) {
X *put++='['; *put++='-';
X get++;
X while( *get && *get!=' ' && *get!=',' )
X *put++=*get++;
X *put++=']';
X }
X while( *get && *get!=',' )
X *put++=*get++;
X *put++='\n';
X } while( *get++ );
X *put=0;
X fprintf( err ? stderr : stdout, "%s", buf );
X }
X}
X
Xint
Xexecute( char *str )
X{
X ULONG toptions=options;
X BPTR toldcin=OldCin;
X int ret, oldac=ac, oldmax=max_ac;
X char **oldav=av;
X
X if( !str ) return -1;
X
X ++H_stack;
X ret=exec_command(str);
X --H_stack;
X
X av=oldav; max_ac=oldmax; ac=oldac;
X options=toptions; OldCin=toldcin;
X
X return ret;
X}
X
Xdo_exec( char *str )
X{
X return execute( next_word( str ) );
X}
X
Xint
Xinteractive( void )
X{
X return IsInteractive(Output());
X}
X
Xstatic int
Xcheckav( FRAME **frameptr, int n )
X{
X char **tmp;
X int newac;
X
X if( ac+n+10>=max_ac ) {
X newac=max_ac+n+40;
X tmp=(char **)falloc(frameptr,newac*sizeof(char *));
X memcpy(tmp,av,max_ac*sizeof(char *));
X av=tmp; max_ac=newac;
X }
X return 0;
X}
X
X/* Parse the options specified in sw[]
X Setting a bit in global variable options
X for each one found
X*/
X
Xstatic void
Xget_opt( char **av, int *ac, int ccno )
X{
X char **get=av+1,**put=av+1, *c, *s;
X int i=1, l, usage=0, nac;
X long oldopts;
X
X options=0;
X if( !ccno )
X return;
X
X for( ; i<*ac && *av[i]=='-'; i++, get++ ) {
X if( !*(c=*get+1) )
X goto stop;
X oldopts=options;
X for ( ; *c ; c++) {
X if( *c<'a' || *c>'z' )
X { options=oldopts; goto stop; }
X for( l=0, s=Command[ccno].options; *s && *s != *c; ++s )
X ++l;
X if ( *s )
X options |= (1 << l);
X else if( !usage ) {
X usage=1;
X show_usage(NULL);
X }
X }
X }
Xstop:
X for( nac=1; i<*ac; i++ )
X *put++=*get++, nac++;
X *put=NULL;
X *ac=nac;
X}
X
X#if 0
XUSHORT Options[160];
X
Xint
Xdo_options()
X{
X for( i=1; i<ac; i+=2 ) {
X if( ac-i<=1 )
X { ierror( av[i], 500 ); return 20; }
X if( *av[i+1]!='-' )
X { ierror( av[i+1], 500 ); return 20; }
X options=0;
X parseopts( av[i+1]+1 );
X }
X}
X#endif
X
Xextern char *MyMem;
Xstatic char Pipe[2][32];
X
Xchar *
Xtempname( int which )
X{
X sprintf(Pipe[which],"%spipe%c%d_%lx",o_pipe,'A'+which,alias_count,MyMem);
X return Pipe[which];
X}
X
X#define ISSPACE(c) ((c)==' ' || (c)==9 || (c)==0xA0)
X
Xstatic int
Xhasspace( char *s )
X{
X if( !*s )
X return 1;
X for ( ; *s; s++)
X if (ISSPACE(*s)) return 1;
X return 0;
X}
X
Xchar *
Xcompile_avf(FRAME **framep,char **av, int start, int end, char delim, int quote)
X{
X char *cstr, *p;
X int len, i;
X
X len = 3;
X for (i = start; i < end; ++i) len += strlen(av[i]) + 3;
X if( framep )
X p = cstr = falloc(framep,len);
X else
X p = cstr = salloc(len);
X *cstr = '\0';
X for (i = start; i < end; ++i) {
X if (debug) fprintf (stderr, "AV[%2d] :%s:\n", i, av[i]);
X if (quote && hasspace(av[i]))
X p += sprintf(p, "\"%s\"", av[i]);
X else
X p += sprintf(p, "%s", av[i]);
X if (i+1 < end) *p++=delim;
X }
X *p='\0';
X return cstr;
X}
X
Xchar *
Xcompile_av(char **av, int start, int end, char delim, int quote)
X{
X return compile_avf(NULL,av, start, end, delim, quote);
X}
X
Xstatic int
Xmyfgets( char *buf, FILE *in )
X{
X int l;
X char *ret;
X if( ret=fgets(buf,253,in) ) {
X l=strlen(buf);
X if( buf[l-1]=='\n' )
X buf[l-1]=0;
X }
X return ret!=NULL && !dobreak();
X}
END_OF_FILE
if test 37168 -ne `wc -c <'execom.c'`; then
echo shar: \"'execom.c'\" unpacked with wrong size!
fi
# end of 'execom.c'
fi
echo shar: End of archive 6 \(of 6\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.