[comp.sources.amiga] v91i012: line 1.15 - shell with csh-line features, Part02/02

amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (02/12/91)

Submitted-by: aycock@cpsc.ucalgary.ca (John Aycock)
Posting-number: Volume 91, Issue 012
Archive-name: shells/line-1.15/part02

#!/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 2 (of 2)."
# Contents:  line.c
# Wrapped by tadguy@ab20 on Mon Feb 11 19:34:40 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'line.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'line.c'\"
else
echo shar: Extracting \"'line.c'\" \(27070 characters\)
sed "s/^X//" >'line.c' <<'END_OF_FILE'
X/*  :ts=8  */
X/*  $Header: yyy:work/sh/RCS/line.c,v 1.15 90/08/28 01:16:08 john Beta $  */
X
X/*
X *	known bugs: 
X *	o  env var args limited to 20
X *	o  any number of them at end of long line
X *	o  recognises scripts, but doesn't know what to do with them
X */
X
X#include <ctype.h>
X#include <string.h>
X#include <arpbase.h>
X#include <exec/exec.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <functions.h>
X
X#pragma amicall(ArpBase,0x276,BaseName(a0))
X#pragma amicall(ArpBase,0xea,FPrintf(d0,a0,a1))
X#pragma amicall(ArpBase,0xfc,GADS(a0,d0,a1,a2,a3))
X#pragma amicall(ArpBase,0x11a,Getenv(a0,a1,d0))
X#pragma amicall(ArpBase,0x14a,PathName(d0,a0,d1))
X#pragma amicall(ArpBase,0xe4,Printf(a0,a1))
X#pragma amicall(ArpBase,0x210,Strncmp(a0,a1,d0))
X#pragma amicall(ArpBase,0x21c,SyncRun(a0,a1,d0,d1))
Xstruct ArpBase *ArpBase;
X
Xchar *tmpnam (char *_s);
X
X#define CSI		0x9b
X#define KEY_UNKNOWN	-1
X
X#define CTRL(c)		('c'&037)
X
X#define WERASE		CTRL(w)
X#define KILL		CTRL(u)
X#define ESC		'\033'
X#define TAB		CTRL(i)
X#define BS		CTRL(h)
X#define RET		CTRL(j)
X#define NL		CTRL(m)
X#define QUIT		CTRL(q)
X#define AMIKILL		CTRL(x)
X
X#define BIGNUMBER	256
X#define MAXLINE		255
X#define ALIASLOOP	20
X#define BUILTIN		9
X#define IGNORE		""
X#define PROMPT		"%N> "
X#define TMPDIR		"tmp:"
X#define STARTUP		"s:.linerc"
X#define MAXHIST		20
X#define MAXALIAS	20
X#define MAXPP		5
X
X#define DOS_TRUE	-1
X#define DOS_FALSE	0
X#define raw()		ttymode(DOS_TRUE)
X#define cooked()	ttymode(DOS_FALSE)
X
Xtypedef unsigned char byte;
Xtypedef char bool;
X
Xchar *progname;
Xbool is_dflt=TRUE;
Xchar *prompt=PROMPT, *ignorelist=IGNORE, *tmpdir=TMPDIR;
Xchar *startup=STARTUP;
X
Xstruct FileInfoBlock *fib;
Xstruct MsgPort *rp;
Xstruct StandardPacket *packet;
X
X#define A_EMPTY(x)	(!A[x].name)
X
Xint a_max=MAXALIAS;
X
Xstruct alias {
X    char *name, *sub;
X} *A;
X
X#define hINC(i)		(((i)+1) % h_max)
X#define hDEC(i)		(!(i) ? h_max-1 : (i)-1)
X
Xint h_num, h_max=MAXHIST, cmd_number;
X
Xstruct history {
X    int num;
X    char line[MAXLINE+1];
X} *H;
X
Xint pp_max=MAXPP, pp_sp=-1;
Xlong *pp_stk;
X
Xint errcode=-1;
X
Xint fprintf (long _fh, const char *_format, ...)
X{
X    return (FPrintf (_fh, _format, (char *) &_format + sizeof (char *)));
X}
X
Xint printf (const char *_format, ...)
X{
X    return (Printf (_format, (char *) &_format + sizeof (char *)));
X}
X
Xint do_csi ()
X{
X    char ch;
X
X    Read (Input(), &ch, 1);
X    switch (ch) {
X    	case 'A':
X    	case 'B':
X    	case 'C':
X    	case 'D':
X    	case 'T':
X    	case 'S':
X	    break;
X    	case '1':
X	    Read (Input(), &ch, 1);
X    	    if (ch == '~') break;
X	    /* else falls through */
X    	case '?':
X	case ' ':
X    	default:
X	    Read (Input(), &ch, 1);
X    }
X    return (KEY_UNKNOWN);
X}
X
X/*
X *	The code for ttymode() was garnered directly from code
X *	by Chuck McManis, CBM (Phil Lindsay, Carolyn Scheppner,
X *	&& Andy Finkel), and a tutorial from Michael van Elst.
X */
X
Xvoid ttymode (mode)
Xlong mode;
X{
X    long fh;
X    struct MsgPort *mp;
X
X    fh = Input();
X    mp = ((struct FileHandle *)(fh<<2))->fh_Type;
X    packet->sp_Msg.mn_Node.ln_Name = (char *) &packet->sp_Pkt;
X    packet->sp_Pkt.dp_Link = &packet->sp_Msg;
X    packet->sp_Pkt.dp_Port = rp;
X    packet->sp_Pkt.dp_Type = ACTION_SCREEN_MODE;
X    packet->sp_Pkt.dp_Arg1 = mode;
X    PutMsg (mp, (struct Message *) packet);
X    WaitPort (rp);
X    GetMsg (rp);
X}
X
Xvoid cleanup ()
X{
X    int i;
X
X    if (pp_stk)
X    	for (i = 0; i < pp_max; i++) if (pp_stk[i]) UnLock (pp_stk[i]);
X    CloseLibrary (ArpBase);
X    if (fib) FreeMem (fib, sizeof (struct FileInfoBlock));
X    if (packet) FreeMem (packet, sizeof (struct StandardPacket));
X    if (rp) DeletePort (rp);
X}
X
Xvoid _abort    () { /* stub */ }
Xvoid _wb_parse () { /* stub */ }
X
Xchar *toint (p, i)
Xchar *p;
Xint *i;
X{
X    *i = 0;
X    while (isdigit (*p))
X    	*i = *i * 10 + (*p++ - '0');
X    return (p);
X}
X
Xvoid makeargs (s, n, args)
Xchar *s, ***args;
Xint *n;
X{
X    int i, j;
X
X    i = *n = 0;
X    while (s[i]) {
X    	while (s[i] && isspace(s[i])) i++;
X    	if (s[i]) (*n)++;
X    	while (s[i] && !isspace(s[i])) {
X	    if (s[i] == '\"') {
X	    	i++;
X	    	while (s[i] && s[i] != '\"') i++;
X	    }
X	    i++;
X	}
X    }
X    if ( !(*args = (char **) malloc (*n * sizeof (char *))) ) {
X    	printf ("%s: out of memory\n", progname);
X    	exit (RETURN_FAIL);
X    }
X    i = j = 0;
X    while (s[i]) {
X    	while (s[i] && isspace(s[i])) i++;
X    	if (s[i]) {
X    	    (*args)[j] = &s[i];
X    	    j++;
X    	}
X    	while (s[i] && !isspace(s[i])) {
X	    if (s[i] == '\"') {
X	    	i++;
X	    	while (s[i] && s[i] != '\"') i++;
X	    }
X	    i++;
X	}
X	if (s[i]) s[i++] = '\0';
X    }
X}
X
X/*
X *	return -1 if error (-2 if it be fatal), 0 if not builtin,
X *	1 otherwise
X */
X
Xint builtin (name, args, fh)
Xchar *name, *args;
Xlong fh;
X{
X    int i, j, k, orig_len;
X    char **argv, *p, t[MAXLINE];
X
X    static char rcsid[] = 
X	"$Revision: 1.15 $\n"
X	"$Date: 90/08/28 01:16:08 $\n";
X    /* if adding commands, don't forget to update BUILTIN */
X    static char *C[] = {
X    	"cls",
X    	"history",
X	"alias",
X	"unalias",
X	"dirs",
X	"push",
X	"pop",
X	"ver",
X	"exit"
X    };
X
X    for (i = 0; i < BUILTIN && strcmp (C[i], name); i++) ;
X    switch (i) {
X    	case 0:	/* cls */
X    	    if (args && *args) goto bi_err;
X	    fprintf (fh, "\f");
X	    break;
X    	case 1:	/* history */
X    	    if (args && *args) goto bi_err;
X    	    for (i = h_num, j = 0; j < h_max; i = hDEC(i), j++) 
X    	    	if (H[i].line[0])
X    	    	    fprintf (fh, "%6ld  %s\n", H[i].num, H[i].line);
X    	    break;
X	case 2:	/* alias */
X	    if (!args) {
X		for (i = 0; i < a_max; i++)
X		    if (!A_EMPTY(i)) 
X			fprintf (fh, "%s\t%s\n", A[i].name, A[i].sub);
X	    } else {
X		orig_len = strlen (args);
X		makeargs (args, &i, &argv);
X		if (i == 1) {
X		    for (j = 0; j < a_max; j++)
X			if (!A_EMPTY(j) && !strcmp (A[j].name, argv[0])) 
X			    break;
X		    if (j != a_max) fprintf (fh, "%s\n", A[j].sub);
X		} else {
X		    for (j = 0; j < a_max && !A_EMPTY(j) &&
X			strcmp (A[j].name, argv[0]); j++) ;
X		    if (j == a_max) {
X			fprintf (fh, "Too many aliases\n");
X			return (-1);
X		    } else if (A_EMPTY(j)) {
X			if ( !(A[j].name = (char *) malloc 
X			    (strlen (argv[0]) + 1)) ) {
X				printf ("%s: out of memory\n", progname);
X				return (-2);
X			}
X			strcpy (A[j].name, argv[0]);
X		    } else free (A[j].sub);
X		    p = argv[1];
X		    for (k = 0; k < orig_len; k++)
X			if (!args[k]) args[k] = ' ';
X		    if ( !(A[j].sub = (char *) malloc (strlen (p) + 1)) ) {
X			printf ("%s: out of memory\n", progname);
X			return (-2);
X		    }
X		    strcpy (A[j].sub, p);
X		}
X		free (argv);
X	    }
X	    break;
X	case 3:	/* unalias */
X	    if (!args) break;
X	    makeargs (args, &i, &argv);
X	    for ( ; i; --i) {
X		for (j = 0; j < a_max; j++)
X		    if (!A_EMPTY(j) && !strcmp (A[j].name, argv[i-1])) {
X			free (A[j].name);
X			free (A[j].sub);
X			A[j].name = A[j].sub = NULL;
X			break;
X		    }
X	    }
X	    free (argv);
X	    break;
X	case 4:	/* dirs */
X	    if (args && *args) goto bi_err;
X	    for (i = pp_sp; i >= 0; --i) {
X	    	PathName (pp_stk[i], t, BIGNUMBER);
X		fprintf (fh, "%s\n", t);
X	    }
X	    break;
X	case 5:	/* push */
X	    if (args && *args) goto bi_err;
X	    if (pp_sp < pp_max-1) {
X		if ( !(pp_stk[++pp_sp] = Lock ("", ACCESS_READ)) ||
X		    !PathName (pp_stk[pp_sp], t, BIGNUMBER) ) {
X			--pp_sp;
X			break;
X		}
X		fprintf (fh, "(%s)\n", t);
X	    } else {
X	    	fprintf (fh, "Directory stack full\n");
X		return (-1);
X	    }
X	    break;
X	case 6:	/* pop */
X	    if (args && *args) goto bi_err;
X	    if (pp_sp >= 0) {
X	    	CurrentDir ((struct FileLock *) pp_stk[pp_sp]);
X		PathName (pp_stk[pp_sp], t, BIGNUMBER);
X		pp_stk[pp_sp--] = 0L;
X		fprintf (fh, "(%s)\n", t);
X	    } else {
X	    	fprintf (fh, "Directory stack empty\n");
X		return (-1);
X	    }
X	    break;
X	case 7:	/* ver */
X	    if (args && *args) goto bi_err;
X	    fprintf (fh, "%s... by John D Aycock\n%s", progname, rcsid);
X	    break;
X	case 8:	/* exit */
X	    if (args && *args) goto bi_err;
X	    errcode = RETURN_OK;
X	    return (-2);
X    	case BUILTIN:
X    	    return (0);
X    }
X    return (1);
X
Xbi_err:
X    printf ("Syntax error\n");
X    return (-1);
X}
X
X/*
X *	returns NULL if no alias sub done, else char * to
X *	malloc'ed substitution... amount malloc'ed is MAXLINE+1
X */
X
Xchar *alias (arg)
Xchar *arg;
X{
X    int i;
X    char *ret, *p, *q;
X
X    for (i = 0; i < a_max; i++) {
X	if (!A_EMPTY(i) && !strcmp (A[i].name, arg)) {
X	    if ( !(ret = (char *) malloc (MAXLINE+1)) ) {
X		printf ("%s: out of memory\n", progname);
X		exit (RETURN_FAIL);
X	    }
X	    for (p = A[i].sub, q = ret; *p; )
X		if (*p == '\"') p++;
X		else if (*p == '!' && *(p+1) == '\'') {
X		    p += 2;
X		    *q++ = '\"';
X		} else *q++ = *p++;
X	    *q = '\0';
X	    return (ret);
X	}
X    }
X    return (NULL);
X}
X
X/*
X *	returns 0 if no history substitution done,
X *	-1 if error, or char * to new (malloc'ed) arg
X */
X
Xchar *history (arg)
Xchar *arg;
X{
X    int num, len, s_len, r_len, repl;
X    char *new, *s=NULL, *r;
X    register int i, j;
X
X    if (!h_max) return (NULL);
X    if (*arg == '!') {
X    	if (*++arg == '!') arg++, num = -1;
X	else if (isdigit (*arg)) arg = toint (arg, &num);
X	else if (*arg == '-') {
X	    arg = toint (++arg, &num);
X	    num = -num;
X	} else if (*arg) {
X	    len = strlen (arg);
X	    for (i = hINC(h_num); i != h_num; i = hINC(i))
X	        if (!strncmp (H[i].line, arg, len)) break;
X	    if (strncmp (H[i].line, arg, len)) goto h_fail;
X	    num = H[i].num;
X	    arg += len;
X	} else goto h_err;
X    } else if (*arg == '^') {
X	for (r = s = ++arg; *r && *r != '^'; r++) ;
X	if (!*r || !(s_len = r - s) ) goto h_err;
X	for (arg = ++r; *arg && *arg != '^'; arg++) ;
X	r_len = arg - r;
X	if (*arg) arg++;	/* skip optional final '^' */
X	num = -1;
X    } else return (NULL);
X    if (!num) {
Xh_err:
X	printf ("Syntax error\n");
X	return ((char *) -1);
X    }
X    if (num < 0) {
X	if ((num = -num) > h_max) goto h_fail;
X	for (i = h_num; num; i = hINC(i), --num) ;
X    } else {
X    	for (i = 0; i < h_max; i++) if (H[i].num == num) break;
X	if (i == h_max) goto h_fail;
X    }
X    if (!H[i].line[0]) {
Xh_fail:
X	printf ("Invalid history substitution\n");
X	return ((char *) -1);
X    }
X    if ( !(new = (char *) malloc (MAXLINE+1)) ) {
X	printf ("%s: out of memory\n", progname);
X	exit (RETURN_FAIL);
X    }
X    strcpy (new, H[i].line);
X    if (s) {
X	for (i = repl = 0; new[i]; i++) { 
X	    if (!strncmp (&new[i], s, s_len)) {
X		len = strlen (new);
X		for (j = s_len + i; j <= len; j++) new[j-s_len] = new[j];
X		len -= s_len;
X		for (j = len + r_len; j >= i; --j)
X		    if (j < MAXLINE+1) new[j] = new[j-r_len];
X		new[MAXLINE] = '\0';
X		strncpy (&new[i], r, r_len);
X		i += r_len;
X	    	repl++;
X	    }
X	}
X	if (!repl) goto h_fail;
X    }
X    strcat (new, arg);
X    return (new);
X}
X
X#define STDIN		0
X#define STDOUT		0
X#define PIPE		1
X#define REDIRECT	2
X
X#define issep(x)	((*(x)=='|'||*(x)==';')&&*((x)+1)=='\0')
X
Xstruct command {
X    byte I, O;
X    char *name, *args, *in_fname, *out_fname;
X};
X
Xvoid doit (s, tmpdir)
Xchar *s, *tmpdir;
X{
X    int argc, n_cmds, cur_cmd, cmd_st, len, arg_st;
X    int orig_len, h_len, rv, aliascnt=0, a_len, copy_args;
X    long in_fh, out_fh;
X    bool h_sub=FALSE, re_eval, aliasing=FALSE, fatal=FALSE;
X    char **argv=NULL, *p, ch, *hist, *aka, *q;
X    struct command *cmd=NULL;
X    register int i, j, cmd_end;
X
XX:
X    re_eval = FALSE;
X    orig_len = strlen (s);
X    makeargs (s, &argc, &argv);
X    for (i = 0, n_cmds = 1; i < argc; i++)
X    	if (issep (argv[i])) n_cmds++;
X    if ( !(cmd = (struct command *) calloc 
X    	(n_cmds, sizeof (struct command))) ) {
X	    printf ("%s: out of memory\n", progname);
X	    exit (RETURN_FAIL);
X    }
X    for (cur_cmd = cmd_end = 0; cur_cmd < n_cmds; cur_cmd++, cmd_end++) {
X    	for (cmd_st = cmd_end, len = 0; cmd_end < argc && 
X	    !issep (argv[cmd_end]); ++cmd_end) {
X		if (cmd_st == cmd_end)
X		    cmd[cur_cmd].name = argv[cmd_st];
X		else {
X		    if (*argv[cmd_end] == '<') {
X			i = cmd_end;
X		    	cmd[cur_cmd].in_fname = (*(argv[cmd_end]+1) ? 
X			    argv[cmd_end]+1 : argv[++cmd_end]);
X			if (cmd_end >= argc || issep (cmd[cur_cmd].in_fname)
X			    || cmd[cur_cmd].I) {
X			    	printf ("Syntax error\n");
X				goto error;
X			}
X			cmd[cur_cmd].I = REDIRECT;
X			argv[i] = argv[cmd_end] = NULL;
X		    } else if (*argv[cmd_end] == '>') {
X			i = cmd_end;
X		    	cmd[cur_cmd].out_fname = (*(argv[cmd_end]+1) ? 
X			    argv[cmd_end]+1 : argv[++cmd_end]);
X			if (cmd_end >= argc || issep (cmd[cur_cmd].out_fname)
X			    || cmd[cur_cmd].O) {
X			    	printf ("Syntax error\n");
X				goto error;
X			}
X			cmd[cur_cmd].O = REDIRECT;
X			argv[i] = argv[cmd_end] = NULL;
X		    } else {
X		    	len += strlen (argv[cmd_end]) + 1;
X			if (cmd_end - cmd_st == 1) arg_st = cmd_end;
X		    }
X		}
X	}
X	if (len) {
X	    if ( !(cmd[cur_cmd].args = (char *) malloc (len)) ) {
X	        printf ("%s: out of memory\n", progname);
X	        exit (RETURN_FAIL);
X   	    }
X	    for (i = arg_st, *(cmd[cur_cmd].args) = '\0'; i < cmd_end; i++) {
X		if (!argv[i]) continue;
X	        strcat (cmd[cur_cmd].args, argv[i]);
X		for (j = i+1; j <= cmd_end && !argv[j]; j++) ;
X	        if (j < cmd_end) strcat (cmd[cur_cmd].args, " ");
X	    }
X	}
X	if (cmd_end < argc && !strcmp (argv[cmd_end], "|")) {
X	    if (cmd[cur_cmd].O || cur_cmd+1 >= n_cmds) {
X		    printf ("Syntax error\n");
X		    goto error;
X	    }
X	    cmd[cur_cmd].O = cmd[cur_cmd+1].I = PIPE;
X	}
X    	if (!cmd[cur_cmd].name) {
X	    printf ("Syntax error\n");
X	    goto error;
X	}
X    }
X    for (i = 0; !aliasing && i < n_cmds; i++) {
X    	if ( !(hist = history (cmd[i].name)) ) continue;
X	else if ((int) hist == -1) goto error;
X	h_len = strlen (cmd[i].name);
X	for (j = 0; j < orig_len; j++) if (!s[j]) s[j] = ' ';
X	for (j = (cmd[i].name - s) + h_len; j <= orig_len; j++)
X	    s[j-h_len] = s[j];
X	orig_len -= h_len;
X	h_len = strlen (hist);
X	for (j = orig_len + h_len; j >= cmd[i].name - s; --j)
X	    if (j < MAXLINE+1) s[j] = s[j-h_len];
X	s[MAXLINE] = '\0';
X	strncpy (&s[j]+1, hist, h_len);
X	free (hist);
X	h_sub = re_eval = TRUE;
X	goto error;	/* loops back up && re-evaluates */
X    }
X    if (!aliasing && h_max) {
X	H[h_num].num = cmd_number;
X	for (i = 0; i < orig_len; i++) 
X	    H[h_num].line[i] = (!s[i] ? ' ' : s[i]);
X	H[h_num].line[i] = '\0';
X	if (h_sub) printf ("%s\n", H[h_num].line);
X	h_num = hDEC(h_num);
X    }
X    if (a_max) for (i = 0; i < n_cmds; i++) {
X	if ( !(aka = alias (cmd[i].name)) ) continue;
X	for (j = copy_args = 0; aka[j]; j++)
X	    if (aka[j] == '!' && aka[j+1] == '*') copy_args++;
X	for (arg_st = 0; argv[arg_st] != cmd[i].name; arg_st++) ;
X	for ( ; arg_st < argc && !issep (argv[arg_st]); arg_st++) ;
X	if (arg_st == argc)
X	    len = orig_len - (cmd[i].name - s + strlen (cmd[i].name) + 1);
X	else
X	    len = argv[arg_st] - cmd[i].name - strlen (cmd[i].name) - 2;
X	if (len < 0) len = 0;
X	if (!len) p = &ch;
X	else if ( !(p = (char *) malloc (len + 1)) ) {
X	    printf ("%s: out of memory\n", progname);
X	    exit (RETURN_FAIL);
X	}
X	q = cmd[i].name + strlen (cmd[i].name) + 1;
X	for (j = 0; j < len; j++) p[j] = (!q[j] ? ' ' : q[j]);
X	p[j] = '\0';
X	a_len = strlen (cmd[i].name);
X	if (copy_args) a_len += len + (len ? 1 : 0);
X	for (j = 0; j < orig_len; j++) if (!s[j]) s[j] = ' ';
X	for (j = (cmd[i].name - s) + a_len; j <= orig_len; j++)
X	    s[j-a_len] = s[j];
X	orig_len -= a_len;
X	a_len = strlen (aka) - 2*copy_args + copy_args*len;
X	for (j = orig_len + a_len; j >= cmd[i].name - s; --j)
X	    if (j < MAXLINE+1) s[j] = s[j-a_len];
X	s[MAXLINE] = '\0';
X	for (j = 0, q = cmd[i].name; aka[j]; j++)
X	    if (aka[j] == '!' && aka[j+1] == '*') {
X	    	strncpy (q, p, len);
X		q += len;
X		j++;
X	    } else *q++ = aka[j];
X	if (len) free (p);
X	free (aka);
X	aliasing = TRUE;
X	if (++aliascnt > ALIASLOOP) {
X	    printf ("Alias loop\n");
X	    goto error;
X	}
X	re_eval = TRUE;
X	goto error;
X    }
X    cmd_number++;
X    for (i = 0; i < n_cmds; i++) {
X	switch (cmd[i].I) {
X	    case STDIN:
X	    	in_fh = Input ();
X		break;
X	    case PIPE:
X	    	in_fh = out_fh;
X		if (Seek (in_fh, 0L, OFFSET_BEGINNING) == -1) {
X		    printf ("Error in pipe\n");
X		    Close (in_fh);
X		    DeleteFile (cmd[i-1].out_fname);
X		    free (cmd[i-1].out_fname);
X		    goto error;
X		}
X		break;
X	    case REDIRECT:
X	    	if ( !(in_fh = Open (cmd[i].in_fname, MODE_OLDFILE)) ) {
X		    printf ("Error on input redirection\n");
X		    goto error;
X		}
X		break;
X	}
X	switch (cmd[i].O) {
X	    case STDOUT:
X	    	out_fh = Output ();
X		break;
X	    case PIPE:
X	    	p = tmpnam (NULL);
X		if ( !(cmd[i].out_fname = (char *) malloc (strlen (tmpdir) +
X		    strlen (p) + 1)) ) {
X			printf ("%s: out of memory\n", progname);
X			if (cmd[i].I) Close (in_fh);
X			if (cmd[i].I == PIPE)
X			    DeleteFile (cmd[i-1].out_fname);
X			exit (RETURN_FAIL);
X		}
X		strcpy (cmd[i].out_fname, tmpdir);
X		ch = tmpdir[strlen(tmpdir)-1];
X		if (*tmpdir && ch != ':' && ch != '/')
X		    strcat (cmd[i].out_fname, "/");
X		strcat (cmd[i].out_fname, p);
X		if ( !(out_fh = Open (cmd[i].out_fname, MODE_NEWFILE)) ) {
X		    printf ("Error in pipe\n");
X		    if (cmd[i].I) Close (in_fh);
X		    if (cmd[i].I == PIPE) {
X		    	DeleteFile (cmd[i-1].out_fname);
X		    	free (cmd[i-1].out_fname);
X		    }
X		    goto error;
X		}
X		break;
X	    case REDIRECT:
X	    	if ( !(out_fh = Open (cmd[i].out_fname, MODE_NEWFILE)) ) {
X		    printf ("Error on output redirection\n");
X		    if (cmd[i].I) Close (in_fh);
X		    if (cmd[i].I == PIPE) {
X		    	DeleteFile (cmd[i-1].out_fname);
X			free (cmd[i-1].out_fname);
X		    }
X		    goto error;
X		}
X		break;
X	}
X	rv = 0;
X	if ( (rv = builtin (cmd[i].name, cmd[i].args, out_fh)) == -2)
X	    fatal = TRUE;
X	if (rv < 0) goto do_err;
X	if (!rv && (rv=SyncRun (cmd[i].name, cmd[i].args, in_fh, out_fh))) {
X	    switch (rv) {
X	    	case PR_NOFILE:
X		    printf ("Unknown command %s\n", cmd[i].name);
X		    break;
X		case PR_NOEXEC:
X		    printf ("Execute bit not set for %s\n", cmd[i].name);
X		    break;
X		case PR_SCRIPT:
X		    printf ("Script bit set for %s\n", cmd[i].name);
X		    break;
X		case PR_WANTSMESSAGE:
X		    printf ("Program returned error #%ld\n", IoErr());
X		    break;
X		default:
X		    if (rv < 0) printf ("Error %ld from SyncRun()\n", rv);
X	    }
Xdo_err:
X	    if (cmd[i].I) Close (in_fh);
X	    if (cmd[i].I == PIPE) {
X	    	DeleteFile (cmd[i-1].out_fname);
X		free (cmd[i-1].out_fname);
X	    }
X	    if (cmd[i].O) Close (out_fh);
X	    if (cmd[i].O == PIPE) {
X	    	DeleteFile (cmd[i].out_fname);
X		free (cmd[i].out_fname);
X	    }
X	    if (fatal) exit (errcode);
X	    break;
X	}
X	if (cmd[i].I) Close (in_fh);
X	if (cmd[i].I == PIPE) {
X	    DeleteFile (cmd[i-1].out_fname);
X	    free (cmd[i-1].out_fname);
X	}
X	if (cmd[i].O == REDIRECT) Close (out_fh);
X    }
X
Xerror:
X    free (argv);
X    if (cmd) {
X    	for (i = 0; i < n_cmds; i++) if (cmd[i].args) free (cmd[i].args);
X	free (cmd);
X	cmd = NULL;
X    }
X    if (re_eval) goto X;
X}
X
Xbool fignore (s, list)
Xchar *s, *list;
X{
X    int s_len, e_len;
X    char *l_ptr;
X
X    s_len = strlen (s);
X    while (*list) {
X    	if (l_ptr = strchr (list, '|')) e_len = l_ptr - list;
X	else {
X	    e_len = strlen (list);
X	    l_ptr = " ";  /* makes it look like end of list */
X	}
X	if ( !Strncmp (list, &s[s_len-e_len], e_len) )
X	    return (TRUE);
X	list = l_ptr + 1;
X    }
X    return (FALSE);
X}
X
Xchar *fcomp (s, n, ignorelist)
Xchar *s, *ignorelist;
Xint *n;	/* RETURN */
X{
X    int bn_len;
X    long lock;
X    bool first=TRUE;
X    char *p, *q, basename[FCHARS], pathname[FCHARS];
X
X    static char common[FCHARS];
X
X    p = BaseName (s);
X    bn_len = strlen (p);
X    *n = 0;
X    strcpy (basename, p);
X    strcpy (pathname, s);
X    if (p == s) *pathname = '\0';
X    else *(pathname+strlen(s)-bn_len) = '\0';
X    if ( !(lock = Lock (pathname, ACCESS_READ)) || 
X    	!Examine (lock, (BPTR) fib) ) {
X	    if (lock) UnLock (lock);
X    	    return ("");
X    }
X    strcpy (common, basename);
X    while (ExNext (lock, (BPTR) fib)) {
X    	if (!bn_len || !Strncmp (basename, fib->fib_FileName, bn_len)) {
X	    if (fignore (fib->fib_FileName, ignorelist)) continue;
X	    if (first) {
X		strcpy (common, fib->fib_FileName);
X	    	first = FALSE;
X	    } else {
X	    	for (p = common+bn_len, q = fib->fib_FileName+bn_len;
X		    *p && *q && tolower(*p) == tolower(*q); p++, q++) ;
X		*p = '\0';
X	    }
X	}
X    }
X    UnLock (lock);
X    *n = bn_len;
X    return (common);
X}
X
Xchar *int2s (p, i)
Xchar *p;
Xint i;
X{
X    int off=0;
X    char buffer[20];	/* arbitrary */
X
X    do {
X    	buffer[off++] = i % 10 + '0';
X	i /= 10;
X    } while (i);
X    while (off > 0) *p++ = buffer[--off];
X    return (p);
X}
X
Xchar *makeprompt (format)
Xchar *format;
X{
X    int len;
X    long lock;
X    struct Process *proc;
X    register char *pf, *pb;
X    static char prompt[MAXLINE];
X
X    for (pf = format, pb = prompt; *pf; pf++) {
X    	if (*pf != '%') *pb++ = *pf;
X	else if (*(pf+1)) {
X	    switch (*++pf) {
X	    	case 'b':
X		    if ( !(lock = Lock ("", ACCESS_READ)) || 
X		    	!Examine (lock, (BPTR) fib) ) {
X			    if (lock) UnLock (lock);
X			    break;
X		    }
X		    strcpy (pb, fib->fib_FileName);
X		    pb += strlen (fib->fib_FileName);
X		    UnLock (lock);
X		    break;
X		case 'c':
X		    pb = int2s (pb, cmd_number);
X		    break;
X		case 'e':
X		    *pb++ = ESC;
X		    break;
X		case 'h':
X		    *pb++ = BS;
X		    break;
X		case 'i':
X		    *pb++ = TAB;
X		    break;
X		case 'n':
X		    *pb++ = NL;
X		    break;
X		case 'p':
X		    if ( !(lock = Lock ("", ACCESS_READ)) ||
X		    	!(len = PathName (lock, pb, BIGNUMBER)) ) {
X		    	    if (lock) UnLock (lock);
X			    break;
X		    }
X		    pb += len;
X		    UnLock (lock);
X		    break;
X		case 'N':
X		    proc = (struct Process *) FindTask (NULL);
X		    pb = int2s (pb, proc->pr_TaskNum);
X		    break;
X		default:
X		    *pb++ = *pf;
X		    break;
X	    }
X	}
X    }
X    *pb = '\0';
X    return (prompt);
X}
X
Xvoid edit (prompt, ignorelist, tmpdir)
Xchar *prompt, *ignorelist, *tmpdir;
X{
X    int b_i, n;
X    char buf[MAXLINE+1], *rest;
X    unsigned char ch;
X    register int i;
X
X    raw ();
X    b_i = 0;
X    printf (makeprompt (prompt));
X
X    while (1) {
X	if (Read (Input(), (char *) &ch, 1) != 1) ch = QUIT;
X	switch (ch) {
X	    case CSI:
X		(void) do_csi ();
X		break;
X	    case WERASE:
X		for (i = b_i; i && isspace (buf[i-1]); --i) ;
X		for ( ; i && !isspace (buf[i-1]); --i) ;
X		for ( ; b_i > i; --b_i) printf ("\b \b");
X		break;
X	    case TAB:
X		buf[b_i] = '\0';
X		for (i = b_i; i && !isspace (buf[i-1]); --i) ;
X		rest = fcomp (&buf[i], &n, ignorelist);
X		if (n) printf ("\033[%ldD", n);
X		b_i -= n;
X		for ( ; b_i < MAXLINE && *rest; rest++) {
X		    buf[b_i++] = *rest;
X		    Write (Output(), rest, 1);
X		}
X		break;
X	    case AMIKILL:
X	    case KILL:
X		for (i = 0; i < b_i; i++) printf ("\b \b");
X		b_i = 0;
X		break;
X	    case BS:
X		if (b_i) {
X		    printf ("\b \b");
X		    --b_i;
X		}
X		break;
X	    case RET:
X	    case NL:
X		for (i = 0; i < b_i && isspace(buf[i]); i++) ;
X		printf ("\n");
X		if (b_i && i != b_i) {
X		    cooked ();
X		    buf[b_i] = '\0';
X		    doit (buf, tmpdir);
X		    b_i = 0;
X		    raw ();
X		}
X		printf (makeprompt (prompt));
X		break;
X	    case QUIT:
X		for (i = 0; i < b_i; i++) printf ("\b \b");
X		printf ("\n");
X		cooked ();
X		return;
X	    default:
X		if (!iscntrl (ch) && b_i < MAXLINE) {
X		    buf[b_i++] = ch;
X		    Write (Output(), (char *) &ch, 1);
X		}
X		break;
X	}
X    }
X}
X
Xvoid parseargs (start_arg, argc, argv)
Xint start_arg, argc;
Xchar **argv;
X{
X    int i;
X    char *cp;
X
X    for (i = start_arg; i < argc; i++) {
X    	if (*(cp = argv[i]) == '-') {
X	    switch (*++cp) {
X		case 'a':
X		    if (*(cp+1)) cp++;
X		    else if (i < argc-1) cp = argv[++i];
X		    else cp = "0";
X		    toint (cp, &a_max);
X		    break;
X		case 'c':
X		    if (*(cp+1)) cp++;
X		    else if (i < argc-1) cp = argv[++i];
X		    else cp = "0";
X		    toint (cp, &h_max);
X		    break;
X		case 'd':
X		    if (*(cp+1)) cp++;
X		    else if (i < argc-1) cp = argv[++i];
X		    else cp = "0";
X		    toint (cp, &pp_max);
X		    break;
X		case 'f':
X		    if (*(cp+1)) ignorelist = cp+1;
X		    else if (i < argc-1) ignorelist = argv[++i];
X		    else ignorelist = "";
X		    break;
X		case 'p':
X		    if (*(cp+1)) prompt = cp+1;
X		    else if (i < argc-1) prompt = argv[++i];
X		    else prompt = "";
X		    break;
X		case 'h':
X		    printf ("Usage: %s [-a<maxaliases>] [-c<histsize>] "
X		    	"[-d<dirstack>] [-f<ignorelist>] [-p<prompt>] "
X			"[-s<startup>] [-t<tmpdir>]\n", progname);
X		    printf ("       %s -h[elp]\n", progname);
X		    exit (RETURN_OK);
X		case 's':
X		    if (*(cp+1)) startup = cp+1;
X		    else if (i < argc-1) startup = argv[++i];
X		    else startup = NULL;
X		    is_dflt = FALSE;
X		    break;
X		case 't':
X		    if (*(cp+1)) tmpdir = cp+1;
X		    else if (i < argc-1) tmpdir = argv[++i];
X		    else tmpdir = "";
X		    break;
X	    	default:
X		    printf ("%s: bad option\n", progname);
X		    exit (RETURN_ERROR);
X	    }
X	} else {
X	    printf ("%s: bad arguments\n", progname);
X	    exit (RETURN_ERROR);
X	}
X    }
X}
X
Xvoid main (argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int i, h_tmp, j, want, actual, lines;
X    long fh;
X    char ch, t[MAXLINE+1], cmd_buf[MAXLINE+1];
X
X    int E_argc;
X    long E_argv[20];
X    char E[MAXLINE+1];
X
X    Enable_Abort = FALSE;
X    if ( !(ArpBase = (struct ArpBase *) OpenLibrary ("arp.library", 0L)) ) {
X	Write (Output(), "Can\'t open arp.library\n", 23);
X	exit (RETURN_FAIL);
X    }
X    atexit (cleanup);
X    if ( !(rp = (struct MsgPort *) CreatePort (NULL, 0)) ) {
X	printf ("Can\'t create port\n");
X	exit (RETURN_FAIL);
X    }
X    if ( !(packet = (struct StandardPacket *) AllocMem 
X    	(sizeof (struct StandardPacket), MEMF_PUBLIC|MEMF_CLEAR)) ||
X	!(fib = (struct FileInfoBlock *) AllocMem
X	(sizeof (struct FileInfoBlock), 0L)) ) {
X    	    printf ("Can\'t allocate memory\n");
X	    exit (RETURN_FAIL);
X    }
X    progname = BaseName (argv[0]);
X    if (Getenv ("LINEOPTS", E, MAXLINE+1)) {
X	E_argc = GADS (E, strlen(E), NULL, E_argv, ",,,,,,,,,,,,,,,,,,,");
X	parseargs (0, E_argc, (char **) E_argv);
X    }
X    parseargs (1, argc, argv);
X    if ( h_max && !(H = (struct history *) calloc (h_max, 
X	sizeof (struct history))) ) {
X	    printf ("%s: out of memory\n", progname);
X	    exit (RETURN_FAIL);
X    }
X    if ( a_max && !(A = (struct alias *) calloc (a_max,
X	sizeof (struct alias))) ) {
X	    printf ("%s: out of memory\n", progname);
X	    exit (RETURN_FAIL);
X    }
X    if ( pp_max && !(pp_stk = (long *) calloc (pp_max, sizeof (long))) ) {
X    	printf ("%s: out of memory\n", progname);
X	exit (RETURN_FAIL);
X    }
X    if (startup) {
X    	if ( !(fh = Open (startup, MODE_OLDFILE)) ) {
X	    if (!is_dflt) printf ("Can\'t open %s\n", startup);
X	} else {
X	    /* temporarily disable history */
X	    h_tmp = h_max;  h_max = 0;
X	    j = 0;  want = MAXLINE;
X	    while ((actual = Read (fh, &t[j], want)) > 0) {
X		actual += j;
X		for (i = lines = 0; i < actual; ) 
X		    if (t[i++]=='\n') lines++;
X		if (!lines) {
X		    printf ("Error reading %s\n", startup);
X		    break;
X		}
X		for ( ; lines-- ; ) {
X		    for (i = 0; t[i] != '\n'; i++) ;
X		    t[i] = '\0';
X		    for (j = 0; t[j] && isspace(t[j]); j++) ;
X		    if (t[j] && t[j] != '#') {
X			strcpy (cmd_buf, &t[j]);
X		    	doit (cmd_buf, tmpdir);
X		    }
X		    for (j = 0, i++; i < actual; ) t[j++] = t[i++];
X		    actual = j;
X		}
X		want = MAXLINE - j;
X	    }
X	    h_max = h_tmp;
X	    Close (fh);
X	}
X    }
X    cmd_number = 1;
X    edit (prompt, ignorelist, tmpdir);
X    exit (RETURN_OK);
X}
X
END_OF_FILE
if test 27070 -ne `wc -c <'line.c'`; then
    echo shar: \"'line.c'\" unpacked with wrong size!
fi
chmod +x 'line.c'
# end of 'line.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both 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.