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.