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.