home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
sh_dos
/
part05
< prev
next >
Wrap
Text File
|
1990-02-13
|
81KB
|
4,242 lines
Newsgroups: comp.sources.misc
organization: ITM Sector, Data Logic Ltd. (A Raytheon Company)
From: istewart@datlog.co.uk (Ian Stewartson)
subject: v10i057: MSDOS Shell (sh) Implementation - Part 04 of 05
Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Posting-number: Volume 10, Issue 57
Submitted-by: istewart@datlog.co.uk (Ian Stewartson)
Archive-name: sh_dos/part05
#!/bin/sh
# this is part 4 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file shell/sh6.c continued
#
CurArch=4
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file shell/sh6.c"
sed 's/^X//' << 'SHAR_EOF' >> shell/sh6.c
XVar_List *path; /* search path for commands */
XVar_List *ps1; /* Prompt 1 */
XVar_List *ps2; /* Prompt 2 */
XVar_List *C_dir; /* Current directory */
Xchar *last_prompt; /* Last prompt output */
XVar_List *ifs; /* Inter-field separator */
Xchar *home = "HOME";
Xchar *shell = "SHELL";
Xchar *history_file = "HISTFILE";
Xchar *hsymbol = "#";
Xchar *msymbol = "-";
Xchar *spcl2 = "$`'\"";
X
X /* I/O stacks */
XIO_Args ioargstack[NPUSH];
XIO_State iostack[NPUSH];
X
X /* Temporary I/O argument */
XIO_Args temparg = {
X (char *)NULL, /* Word */
X (char **)NULL, /* Word list */
X 0, /* File descriptor */
X AFID_NOBUF, /* Buffer id */
X 0L, /* File position */
X (IO_Buf *)NULL /* Buffer */
X};
X
Xint areanum; /* Current allocation area */
Xint inparse; /* In parser flag */
Xlong flags = 0L; /* Command line flags */
Xchar *null = "";
X
X /* Current environment */
XEnviron e = {
X (char *)NULL, /* Current line buffer */
X (char *)NULL, /* Current pointer in line */
X (char *)NULL, /* End of line pointer */
X iostack, /* I/O Stack pointers */
X iostack - 1,
X (int *)NULL,
X FDBASE, /* Base file handler */
X (Environ *)NULL /* Previous Env pointer */
X};
SHAR_EOF
echo "File shell/sh6.c is complete"
chmod 0644 shell/sh6.c || echo "restore of shell/sh6.c fails"
set `wc -c shell/sh6.c`;Sum=$1
if test "$Sum" != "3994"
then echo original size 3994, current size $Sum;fi
echo "x - extracting shell/sh7.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh7.c &&
X/* MS-DOS SHELL - Internal Command Processing
X *
X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
X *
X * This code is based on (in part) the shell program written by Charles
X * Forsyth and is subject to the following copyright restrictions:
X *
X * 1. Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in the
X * source form and the copyright notice in file sh6.c is displayed
X * on entry to the program.
X *
X * 2. The sources (or parts thereof) or objects generated from the sources
X * (or parts of sources) cannot be sold under any circumstances.
X *
X * $Header: sh7.c 1.1 90/01/29 17:46:25 MS_user Exp $
X *
X * $Log: sh7.c $
X * Revision 1.1 90/01/29 17:46:25 MS_user
X * Initial revision
X *
X *
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <process.h>
X#include <dos.h>
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <stdarg.h>
X#include "sh.h"
X
X#define SECS 60L
X#define MINS 3600L
X#define IS_OCTAL(a) (((a) >= '0') && ((a) <= '7'))
X
X/* Definitions for test */
X
X#define END_OF_INPUT 0
X#define FILE_READABLE 1
X#define FILE_WRITABLE 2
X#define FILE_REGULAR 3
X#define FILE_DIRECTORY 4
X#define FILE_NONZERO 5
X#define FILE_TERMINAL 6
X#define STRING_ZERO 7
X#define STRING_NONZERO 8
X#define STRING_EQUAL 9
X#define STRING_NOTEQUAL 10
X#define NUMBER_EQUAL 11
X#define NUMBER_NOTEQUAL 12
X#define NUMBER_EQ_GREAT 13
X#define NUMBER_GREATER 14
X#define NUMBER_EQ_LESS 15
X#define NUMBER_LESS 16
X#define UNARY_NOT 17
X#define BINARY_AND 18
X#define BINARY_OR 19
X#define LPAREN 20
X#define RPAREN 21
X#define OPERAND 22
X#define FILE_EXECUTABLE 23
X#define FILE_USER 24
X#define FILE_GROUP 25
X#define FILE_TEXT 26
X#define FILE_BLOCK 27
X#define FILE_CHARACTER 28
X#define FILE_FIFO 29
X
X#define UNARY_OP 1
X#define BINARY_OP 2
X#define B_UNARY_OP 3
X#define B_BINARY_OP 4
X#define PAREN 5
X
Xstatic struct test_op {
X char *op_text;
X short op_num;
X short op_type;
X} test_ops[] = {
X {"-r", FILE_READABLE, UNARY_OP},
X {"-w", FILE_WRITABLE, UNARY_OP},
X {"-x", FILE_EXECUTABLE, UNARY_OP},
X {"-f", FILE_REGULAR, UNARY_OP},
X {"-d", FILE_DIRECTORY, UNARY_OP},
X {"-s", FILE_NONZERO, UNARY_OP},
X {"-t", FILE_TERMINAL, UNARY_OP},
X {"-z", STRING_ZERO, UNARY_OP},
X {"-n", STRING_NONZERO, UNARY_OP},
X {"=", STRING_EQUAL, BINARY_OP},
X {"!=", STRING_NOTEQUAL, BINARY_OP},
X {"-eq", NUMBER_EQUAL, BINARY_OP},
X {"-ne", NUMBER_NOTEQUAL, BINARY_OP},
X {"-ge", NUMBER_EQ_GREAT, BINARY_OP},
X {"-gt", NUMBER_GREATER, BINARY_OP},
X {"-le", NUMBER_EQ_LESS, BINARY_OP},
X {"-lt", NUMBER_LESS, BINARY_OP},
X {"!", UNARY_NOT, B_UNARY_OP},
X {"-a", BINARY_AND, B_BINARY_OP},
X {"-o", BINARY_OR, B_BINARY_OP},
X {"(", LPAREN, PAREN},
X {")", RPAREN, PAREN},
X#ifdef S_IFCHR
X {"-c", FILE_CHARACTER, UNARY_OP},
X#endif
X#ifdef S_IFBLK
X {"-b", FILE_BLOCK, UNARY_OP},
X#endif
X#ifdef S_ISUID
X {"-u", FILE_USER, UNARY_OP},
X#endif
X#ifdef S_ISGID
X {"-g", FILE_GROUP, UNARY_OP},
X#endif
X#ifdef S_ISVTX
X {"-k", FILE_TEXT, UNARY_OP},
X#endif
X#ifdef S_IFIFO
X {"-p", FILE_FIFO, UNARY_OP},
X#endif
X {(char *)NULL, NULL, NULL}
X};
X
Xstatic int expr (int);
Xstatic int bexpr (int);
Xstatic int primary (int);
Xstatic int lex (char *);
Xstatic long num (char *);
Xstatic void syntax (void);
Xstatic int dolabel (C_Op *);
Xstatic int dochdir (C_Op *);
Xstatic int dodrive (C_Op *);
Xstatic int doshift (C_Op *);
Xstatic int doumask (C_Op *);
Xstatic int dodot (C_Op *);
Xstatic int doecho (C_Op *);
Xstatic int dogetopt (C_Op *);
Xstatic int dopwd (C_Op *);
Xstatic int doswap (C_Op *);
Xstatic int dounset (C_Op *);
Xstatic int dotype (C_Op *);
Xstatic int dotest (C_Op *);
Xstatic int dover (C_Op *);
Xstatic int doread (C_Op *);
Xstatic int doeval (C_Op *);
Xstatic int dotrap (C_Op *);
Xstatic int getsig (char *);
Xstatic int dobreak (C_Op *);
Xstatic int docontinue (C_Op *);
Xstatic int brkcontin (char *, int);
Xstatic int doexit (C_Op *);
Xstatic int doexec (C_Op *);
Xstatic int doreturn (C_Op *);
Xstatic int doexport (C_Op *);
Xstatic int domsdos (C_Op *);
Xstatic int doreadonly (C_Op *);
Xstatic int doset (C_Op *);
Xstatic int dohistory (C_Op *);
Xstatic void setsig (int, int (*)());
Xstatic int rdexp (char **, int, char *);
Xstatic void v1_putsn (char *, int);
X
Xstatic char **test_alist;
Xstatic struct test_op *test_op;
Xstatic jmp_buf test_jmp;
X
X/*
X * built-in commands: doX
X */
X
Xstatic int dolabel (t)
XC_Op *t;
X{
X return 0;
X}
X
X/*
X * Getopt - split arguments. getopts pattern args
X */
X
Xstatic int dogetopt (t)
Xregister C_Op *t;
X{
X int argc;
X char **argv = t->words;
X int c;
X
X/* Count arguments */
X
X optind = 1; /* Reset the optind flag */
X opterr = 1; /* Reset the error flag */
X
X for (argc = 0; t->words[argc] != (char *)NULL; argc++);
X
X if (argc < 2)
X {
X S_puts ("usage: getopt legal-args $*\n");
X return 2;
X }
X
X argc -= 2;
X argv += 2;
X
X/* Scan each argument */
X
X while ((c = getopt (argc, argv, t->words[1])) != EOF)
X {
X if (c == '?')
X return 2;
X
X v1printf ("-%c ", c);
X
X/* Check for addition parameter */
X
X if (*(strchr (t->words[1], c) + 1) == ':')
X {
X v1_puts (optarg);
X v1_putc (SP);
X }
X }
X
X v1_puts ("-- ");
X argv += optind;
X
X while (optind++ < argc)
X {
X v1_puts (*argv++);
X v1_putc ((char)((optind == argc) ? NL : SP));
X }
X
X return 0;
X}
X
X/*
X * Echo the parameters
X */
X
Xstatic int doecho (t)
Xregister C_Op *t;
X{
X int n = 1;
X int no_eol = 0; /* No EOL */
X char *ip; /* Input pointer */
X int c_val; /* Current character */
X char c;
X bool end_s;
X char *cp = e.linep;
X /* Always leave room for NL */
X char *ep = &e.linep[LINE_MAX - 3];
X
X while ((ip = t->words[n++]) != (char *)NULL)
X {
X if ((n == 2) && (strcmp (ip, "-n") == 0))
X {
X no_eol++;
X continue;
X }
X
X/* Process the string */
X
X end_s = FALSE;
X
X do
X {
X
X/* Any special character processing ? */
X
X if ((c = *(ip++)) == '\\')
X {
X if ((c_val = Process_Escape (&ip)) == -1)
X {
X no_eol = 1;
X continue;
X }
X
X c = (char)c_val;
X }
X
X/* End of string - check to see if a space if required */
X
X else if (c == 0)
X {
X end_s = TRUE;
X
X if (t->words[n] != (char *)NULL)
X c = SP;
X
X else
X continue;
X }
X
X/* Output the character */
X
X if (cp < ep)
X *(cp++) = c;
X
X else
X {
X v1_putsn (e.linep, (int)(cp - e.linep));
X cp = e.linep;
X }
X
X } while (!end_s);
X }
X
X/* Is EOL required ? */
X
X if (!no_eol)
X *(cp++) = NL;
X
X/* Flush buffer */
X
X if ((n = (int)(cp - e.linep)))
X v1_putsn (e.linep, n);
X
X return 0;
X}
X
X/*
X * Process_Escape - Convert an escaped character to a binary value.
X *
X * Returns the binary value and updates the string pointer.
X */
X
Xint Process_Escape (cp)
Xchar **cp; /* Pointer to character */
X{
X int c_val = **cp; /* Current character */
X
X if (c_val)
X (*cp)++;
X
X/* Process escaped characters */
X
X switch (c_val)
X {
X case 'b': /* Backspace */
X return 0x08;
X
X case 'f': /* Form Feed */
X return 0x0c;
X
X case 'v': /* Vertical Tab */
X return 0x0b;
X
X case 'n': /* New Line */
X return 0x0a;
X
X case 'r': /* Carriage return */
X return 0x0d;
X
X case 't': /* Forward tab */
X return 0x09;
X
X case '\\': /* Backslash */
X return '\\';
X
X case 'c': /* no eol */
X return -1;
X }
X
X/* Check for an octal string */
X
X if ((c_val >= 0) && (c_val < 8))
X {
X while ((IS_OCTAL (**cp)))
X c_val = (c_val * 8) + *((*cp)++) - '0';
X
X return c_val;
X }
X
X return c_val;
X}
X
X/*
X * Display the current version
X */
X
Xstatic int dover (t)
XC_Op *t;
X{
X v1printf (Copy_Right1, _osmajor, _osminor);
X v1a_puts (Copy_Right2);
X return 0;
X}
X
Xstatic char *swap_device[] = {"disk", "extend", "expand"};
X
X/*
X * Modify swapping information: swap options
X */
X
Xstatic int doswap (t)
Xregister C_Op *t;
X{
X register int n = 1;
X char *cp;
X
X/* Display current values ? */
X
X if (t->words[1] == (char *)NULL)
X {
X if (Swap_Mode == SWAP_OFF)
X v1a_puts ("Swapping disabled");
X
X else
X {
X register int j;
X
X v1_puts ("Swap devices: ");
X
X for (j = 0, n = 1; j < 3; ++j, n <<= 1)
X {
X if (Swap_Mode & n)
X {
X v1printf ("%s ", swap_device[j]);
X
X if (n == SWAP_EXTEND)
X v1printf ("(0x%.6lx) ", SW_EMstart);
X }
X }
X
X v1_putc (NL);
X }
X
X return 0;
X }
X
X/* Set up new values */
X
X Swap_Mode = SWAP_OFF;
X
X while ((cp = t->words[n++]) != (char *)NULL)
X {
X if (strcmp (cp, "off") == 0)
X Swap_Mode = SWAP_OFF;
X
X else if (strcmp (cp, "on") == 0)
X Swap_Mode = SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND;
X
X/* Scan for valid arguments */
X
X else
X {
X register int j, k;
X
X for (j = 0, k = 1; j < 3; ++j, k <<= 1)
X {
X if (strcmp (cp, swap_device[j]) == 0)
X {
X Swap_Mode |= k;
X
X/* If extended memory, they can specify the start address as a hex number */
X
X if (k == SWAP_EXTEND)
X {
X char *sp;
X long start;
X
X/* Check for not changed */
X
X if ((sp = t->words[n]) == (char *)NULL)
X break;
X
X/* Convert hex number */
X
X start = strtol (sp, &sp, 16);
X
X/* If not completely a hex number, ignore */
X
X if (*sp)
X break;
X
X/* Set used and saved new value */
X
X SW_EMstart = start;
X ++n;
X
X if ((SW_EMstart < 0x100000L) ||
X (SW_EMstart > 0xf00000L))
X SW_EMstart = 0x100000L;
X
X v1printf ("Extend memory start set to 0x%.6lx\n",
X SW_EMstart);
X }
X
X break;
X }
X }
X }
X }
X
X return 0;
X}
X
X/*
X * Output the current path: pwd
X */
X
Xstatic int dopwd (t)
Xregister C_Op *t;
X{
X v1a_puts (C_dir->value);
X return 0;
X}
X
X/*
X * Unset a variable: unset <flag..> <variable name...>
X */
X
Xstatic int dounset (t)
Xregister C_Op *t;
X{
X register int n = 1;
X
X while (t->words[n] != (char *)NULL)
X unset (t->words[n++], FALSE);
X
X return 0;
X}
X
X/* Delete a variable or function. If all is set, system variables can be
X * deleted. This is used to delete the trap functions
X */
X
Xvoid unset (cp, all)
Xregister char *cp;
Xbool all;
X{
X register Var_List *vp;
X register Var_List *pvp;
X
X/* Unset a flag */
X
X if (*cp == '-')
X {
X while (*(++cp) != 0)
X {
X if (islower (*cp))
X FL_CLEAR (*cp);
X }
X
X setdash ();
X return;
X }
X
X/* Ok - unset a variable and not a local value */
X
X if (!all && !(isalpha (*cp)))
X return;
X
X/* Check in list */
X
X pvp = (Var_List *)NULL;
X
X for (vp = vlist; (vp != (Var_List *)NULL) && !eqname (vp->name, cp);
X vp = vp->next)
X pvp = vp;
X
X/* If not found, delete the function if it exists */
X
X if (vp == (Var_List *)NULL)
X {
X Fun_Ops *fp;
X
X if ((fp = Fun_Search (cp)) != (Fun_Ops *)NULL)
X Save_Function (fp->tree, TRUE);
X
X return;
X }
X
X/* Error if read-only */
X
X if (vp->status & (RONLY | PONLY))
X {
X if ((cp = strchr (vp->name, '=')) != (char *)NULL)
X *cp = 0;
X
X S_puts (vp->name);
X
X if (cp != (char *)NULL)
X *cp = '=';
X
X S_puts ((vp->status & PONLY) ? ": cannot unset\n" : " is read-only\n");
X return;
X }
X
X/* Delete it */
X
X if (vp->status & GETCELL)
X DELETE (vp->name);
X
X if (pvp == (Var_List *)NULL)
X vlist = vp->next;
X
X else
X pvp->next = vp->next;
X
X DELETE (vp);
X}
X
X/*
X * Execute a test: test <arguments>
X */
X
Xstatic int dotest (t)
Xregister C_Op *t;
X{
X int st = 0;
X
X if (*(test_alist = &t->words[1]) == (char *)NULL)
X return 1;
X
X/* If [ <arguments> ] form, check for end ] and remove it */
X
X if (strcmp (t->words[0], "[") == 0)
X {
X while (t->words[++st] != (char *)NULL)
X ;
X
X if (strcmp (t->words[--st], "]") != 0)
X {
X print_error ("test: missing ']'\n");
X return 1;
X }
X
X else
X t->words[st] = (char *)NULL;
X }
X
X/* Set abort address */
X
X if (setjmp (test_jmp))
X return 1;
X
X st = !expr (lex (*test_alist));
X
X if (*(++test_alist) != (char *)NULL)
X syntax ();
X
X return (st);
X}
X
Xstatic int expr (n)
Xint n;
X{
X int res;
X
X if (n == END_OF_INPUT)
X syntax ();
X
X res = bexpr (n);
X
X if (lex (*(++test_alist)) == BINARY_OR)
X return expr (lex (*(++test_alist))) || res;
X
X test_alist--;
X return res;
X}
X
Xstatic int bexpr (n)
Xint n;
X{
X int res;
X
X if (n == END_OF_INPUT)
X syntax ();
X
X res = primary (n);
X if (lex (*(++test_alist)) == BINARY_AND)
X return bexpr (lex (*(++test_alist))) && res;
X
X test_alist--;
X return res;
X}
X
Xstatic int primary (n)
Xint n;
X{
X register char *opnd1, *opnd2;
X struct stat s;
X int res;
X
X if (n == END_OF_INPUT)
X syntax ();
X
X if (n == UNARY_NOT)
X return !expr (lex (*(++test_alist)));
X
X if (n == LPAREN)
X {
X res = expr (lex (*(++test_alist)));
X
X if (lex (*(++test_alist)) != RPAREN)
X syntax ();
X
X return res;
X }
X
X if (n == OPERAND)
X {
X opnd1 = *test_alist;
X (void) lex (*(++test_alist));
X
X if ((test_op != (C_Op *)NULL) && test_op->op_type == BINARY_OP)
X {
X struct test_op *op = test_op;
X
X if ((opnd2 = *(++test_alist)) == (char *)NULL)
X syntax ();
X
X switch (op->op_num)
X {
X case STRING_EQUAL:
X return strcmp (opnd1, opnd2) == 0;
X
X case STRING_NOTEQUAL:
X return strcmp (opnd1, opnd2) != 0;
X
X case NUMBER_EQUAL:
X return num (opnd1) == num (opnd2);
X
X case NUMBER_NOTEQUAL:
X return num (opnd1) != num (opnd2);
X
X case NUMBER_EQ_GREAT:
X return num (opnd1) >= num (opnd2);
X
X case NUMBER_GREATER:
X return num (opnd1) > num (opnd2);
X
X case NUMBER_EQ_LESS:
X return num (opnd1) <= num (opnd2);
X
X case NUMBER_LESS:
X return num (opnd1) < num (opnd2);
X }
X }
X
X test_alist--;
X return strlen (opnd1) > 0;
X }
X
X/* unary expression */
X
X if (test_op->op_type != UNARY_OP || *++test_alist == 0)
X syntax ();
X
X switch (n)
X {
X case STRING_ZERO:
X return strlen (*test_alist) == 0;
X
X case STRING_NONZERO:
X return strlen (*test_alist) != 0;
X
X case FILE_READABLE:
X return access (*test_alist, R_OK) == 0;
X
X case FILE_WRITABLE:
X return access (*test_alist, W_OK) == 0;
X
X case FILE_EXECUTABLE:
X return access (*test_alist, X_OK) == 0;
X
X case FILE_REGULAR:
X return stat (*test_alist, &s) == 0 && S_ISREG(s.st_mode);
X
X case FILE_DIRECTORY:
X return stat (*test_alist, &s) == 0 && S_ISDIR(s.st_mode);
X
X case FILE_NONZERO:
X return stat (*test_alist, &s) == 0 && (s.st_size > 0L);
X
X case FILE_TERMINAL:
X return isatty ((int)num (*test_alist));
X
X#ifdef S_ISUID
X case FILE_USER:
X return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISUID);
X#endif
X
X#ifdef S_ISGID
X case FILE_GROUP:
X return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISGID);
X#endif
X
X#ifdef S_ISVTX
X case FILE_TEXT:
X return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISVTX);
X#endif
X
X#ifdef S_IFBLK
X case FILE_BLOCK:
X return stat (*test_alist, &s) == 0 && S_ISBLK(s.st_mode);
X#endif
X
X#ifdef S_IFCHR
X case FILE_CHARACTER:
X return stat (*test_alist, &s) == 0 && S_ISCHR(s.st_mode);
X#endif
X
X#ifdef S_IFIFO
X case FILE_FIFO:
X return stat (*test_alist, &s) == 0 && S_ISFIFO(s.st_mode);
X#endif
X }
X}
X
Xstatic int lex (s)
Xregister char *s;
X{
X register struct test_op *op = test_ops;
X
X if (s == (char *)NULL)
X return END_OF_INPUT;
X
X while (op->op_text)
X {
X if (strcmp (s, op->op_text) == 0)
X {
X test_op = op;
X return op->op_num;
X }
X
X op++;
X }
X
X test_op = (struct test_op *)NULL;
X return OPERAND;
X}
X
X/*
X * Get a long numeric value
X */
X
Xstatic long num (s)
Xregister char *s;
X{
X char *ep;
X long l = strtol (s, &ep, 10);
X
X if (!*s || *ep)
X syntax ();
X
X return l;
X}
X
X/*
X * test syntax error - abort
X */
X
Xstatic void syntax ()
X{
X print_error ("test: syntax error\n");
X longjmp (test_jmp, 1);
X}
X
X/*
X * Select a new drive: x:
X *
X * Select the drive, get the current directory and check that we have
X * actually selected the drive
X */
X
Xstatic int dodrive (t)
Xregister C_Op *t;
X{
X unsigned int cdrive;
X unsigned int ndrive = tolower (**t->words) - 'a' + 1;
X
X _dos_setdrive (ndrive, &cdrive);
X Getcwd ();
X _dos_getdrive (&cdrive);
X return (ndrive == cdrive) ? 0 : 1;
X}
X
X/*
X * Select a new directory: cd
X */
X
Xstatic int dochdir (t)
Xregister C_Op *t;
X{
X char *p;
X char *nd;
X register char *cp;
X int first = 0;
X unsigned int dummy;
X unsigned int cdrive;
X
X/* If restricted shell - illegal */
X
X if (check_rsh ("cd"))
X return 1;
X
X/* Use default ? */
X
X if (((p = t->words[1]) == (char *)NULL) &&
X ((p = lookup (home, FALSE)->value) == null))
X {
X print_error ("cd: no home directory\n");
X return 1;
X }
X
X/* Save the current drive */
X
X _dos_getdrive (&cdrive);
X
X/* Scan for the directory. If there is not a / or : at start, use the
X * CDPATH variable
X */
X
X cp = (*p == '/') ? null : lookup ("CDPATH", FALSE)->value;
X cp = (*(p + 1) == ':') ? null : cp;
X
X do
X {
X cp = path_append (cp, p, e.linep);
X
X/* Check for new disk drive */
X
X nd = e.linep;
X
X if (*(nd+ 1) == ':')
X {
X _dos_setdrive (tolower (*nd) - 'a' + 1, &dummy);
X nd += 2;
X }
X
X/* Was the change successful? */
X
X if ((!*nd) || (chdir (nd) == 0))
X {
X
X/* OK - reset the current directory (in the shell) and display the new
X * path if appropriate
X */
X
X Getcwd ();
X
X if (first || (strchr (p, '/') != (char *)NULL))
X dopwd (t);
X
X return 0;
X }
X
X first = 1;
X
X } while (cp != (char *)NULL);
X
X/* Restore our original drive and restore directory info */
X
X _dos_setdrive (cdrive, &dummy);
X Getcwd ();
X
X print_error ("%s: bad directory\n", p);
X return 1;
X}
X
X/*
X * Extract the next path from a string and build a new path from the
X * extracted path and a file name
X */
Xchar *path_append (s1, s2, si)
Xregister char *s1; /* Path string */
Xregister char *s2; /* File name string */
Xchar *si; /* Output path */
X{
X register char *s;
X
X s = si;
X
X while (*s1 && *s1 != ';')
X *s++ = *s1++;
X
X if ((si != s) && (*(s - 1) != '/'))
X *s++ = '/';
X
X *s = '\0';
X
X if (s2 != (char *)NULL)
X strcpy (s, s2);
X
X return (*s1 ? ++s1 : (char *)NULL);
X}
X
X/*
X * Execute a shift command: shift <n>
X */
X
Xstatic int doshift (t)
Xregister C_Op *t;
X{
X register int n;
X
X n = (t->words[1] != (char *)NULL) ? getn (t->words[1]) : 1;
X
X if (dolc < n)
X {
X print_error ("sh: nothing to shift\n");
X return 1;
X }
X
X dolv[n] = dolv[0];
X dolv += n;
X dolc -= n;
X setval (lookup ("#", TRUE), putn (dolc));
X return 0;
X}
X
X/*
X * Execute a umask command: umask <n>
X */
X
Xstatic int doumask (t)
Xregister C_Op *t;
X{
X register int i;
X register char *cp;
X
X if ((cp = t->words[1]) == (char *)NULL)
X {
X i = umask (0);
X umask (i);
X v1printf ("%o\n", i);
X }
X
X else
X {
X i = 0;
X while (IS_OCTAL (*cp))
X i = i * 8 + (*(cp++) - '0');
X
X umask (i);
X }
X
X return 0;
X}
X
X/*
X * Execute an exec command: exec <arguments>
X */
X
Xstatic int doexec (t)
Xregister C_Op *t;
X{
X register int i;
X jmp_buf ex;
X int *ofail;
X
X t->ioact = (IO_Actions **)NULL;
X
X for (i = 0; (t->words[i] = t->words[i + 1]) != (char *)NULL; i++)
X ;
X
X if (i == 0)
X return 0;
X
X execflg = 1;
X ofail = failpt;
X
X/* Set execute function recursive level to zero */
X
X Execute_stack_depth = 0;
X
X if (setjmp (failpt = ex) == 0)
X execute (t, NOPIPE, NOPIPE, FEXEC);
X
X failpt = ofail;
X execflg = 0;
X return 1;
X}
X
X/*
X * Execute a script in the current shell
X */
X
Xstatic int dodot (t)
XC_Op *t;
X{
X register int i;
X register char *sp;
X char *cp;
X
X if ((cp = t->words[1]) == (char *)NULL)
X return 0;
X
X sp = any ('/', cp) ? null : path->value;
X
X do
X {
X sp = path_append (sp, cp, e.linep);
X
X if ((i = O_for_execute (e.linep)) >= 0)
X {
X exstat = 0;
X next (remap (i));
X return exstat;
X }
X } while (sp != (char *)NULL);
X
X print_error ("%s: not found\n", cp);
X return 1;
X}
X
X/*
X * Read from standard input into a variable list
X */
X
Xstatic int doread (t)
XC_Op *t;
X{
X register char *cp, **wp;
X register int nb;
X
X if (t->words[1] == (char *)NULL)
X {
X print_error ("Usage: read name ...\n");
X return 1;
X }
X
X for (wp = t->words + 1; *wp != (char *)NULL; wp++)
X {
X for (cp = e.linep; cp < e.eline - 1; cp++)
X {
X if (((nb = read (STDIN_FILENO, cp, 1)) != 1) || (*cp == NL) ||
X ((wp[1] != (char *)NULL) && any (*cp, ifs->value)))
X
X break;
X }
X
X *cp = 0;
X
X if (nb <= 0)
X break;
X
X setval (lookup (*wp, TRUE), e.linep);
X }
X
X return (nb <= 0);
X}
X
X/*
X * Evaluate an expression
X */
X
Xstatic int doeval (t)
Xregister C_Op *t;
X{
X return RUN (awordlist, t->words + 1, wdchar);
X}
X
X/*
X * Execute a trap
X */
X
Xstatic int dotrap (t)
Xregister C_Op *t;
X{
X register int n, i;
X register int resetsig;
X char tval[10];
X char *cp;
X
X
X if (t->words[1] == (char *)NULL)
X {
X
X/* Display trap - look up each trap and print those we find */
X
X for (i = 0; i < NSIG; i++)
X {
X sprintf (tval, "~%d", i);
X
X if ((cp = lookup (tval, FALSE)->value) != null)
X {
X v1printf ("%u: ", i);
X v1a_puts (cp);
X }
X }
X
X return 0;
X }
X
X resetsig = isdigit (*t->words[1]); /* Reset signal? */
X
X for (i = resetsig ? 1 : 2; t->words[i] != (char *)NULL; ++i)
X {
X
X/* Generate the variable name */
X
X sprintf (tval, "~%d", (n = getsig (t->words[i])));
X
X if (n == -1)
X return 1;
X
X unset (tval, TRUE);
X
X/* Re-define signal processing */
X
X if (!resetsig)
X {
X if (*t->words[1] != '\0')
X {
X setval (lookup (tval, TRUE), t->words[1]);
X setsig (n, sig);
X }
X
X else
X setsig (n, SIG_IGN);
X }
X
X/* Clear signal processing */
X
X else if (talking)
X {
X if (n == SIGINT)
X setsig (n, onintr);
X
X else
X#ifdef SIGQUIT
X setsig (n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
X#else
X setsig (n, SIG_DFL);
X#endif
X }
X
X else
X setsig (n, SIG_DFL);
X }
X
X return 0;
X}
X
X/*
X * Get a signal number
X */
X
Xstatic int getsig (s)
Xchar *s;
X{
X register int n;
X
X if (((n = getn (s)) < 0) || (n >= NSIG))
X {
X print_error ("trap: bad signal number\n");
X n = -1;
X }
X
X return n;
X}
X
X/*
X * Set up a signal function
X */
X
Xstatic void setsig (n, f)
Xregister int n;
Xint (*f)();
X{
X if (n == 0)
X return;
X
X if ((signal (n, SIG_IGN) != SIG_IGN) || (ourtrap & (1L << n)))
X {
X ourtrap |= (1L << n);
X signal (n, f);
X }
X}
X
X/* Convert a string to a number */
X
Xint getn (as)
Xchar *as;
X{
X char *s;
X int n = (int)strtol (as, &s, 10);
X
X if (*s)
X print_error ("%s: bad number\n", as);
X
X return n;
X}
X
X/*
X * BREAK and CONTINUE processing
X */
X
Xstatic int dobreak (t)
XC_Op *t;
X{
X return brkcontin (t->words[1], BC_BREAK);
X}
X
Xstatic int docontinue (t)
XC_Op *t;
X{
X return brkcontin (t->words[1], BC_CONTINUE);
X}
X
Xstatic int brkcontin (cp, val)
Xregister char *cp;
Xint val;
X{
X register Break_C *Break_Loc;
X register int nl;
X
X if ((nl = (cp == (char *)NULL) ? 1 : getn (cp)) <= 0)
X nl = 999;
X
X do
X {
X if ((Break_Loc = Break_List) == (Break_C *)NULL)
X break;
X
X Break_List = Break_Loc->nextlev;
X
X } while (--nl);
X
X if (nl)
X {
X print_error ("sh: bad break/continue level\n");
X return 1;
X }
X
X longjmp (Break_Loc->brkpt, val);
X
X/* NOTREACHED */
X}
X
X/*
X * Exit function
X */
X
Xstatic int doexit (t)
XC_Op *t;
X{
X Break_C *SShell_Loc = SShell_List;
X
X execflg = 0;
X
X/* Set up error codes */
X
X if (t->words[1] != (char *)NULL)
X {
X exstat = getn (t->words[1]);
X setval (lookup ("?", TRUE), t->words[1]);
X }
X
X/* Are we in a subshell. Yes - do a longjmp instead of an exit */
X
X if (SShell_Loc != (Break_C *)NULL)
X {
X SShell_List = SShell_Loc->nextlev;
X longjmp (SShell_Loc->brkpt, 1);
X }
X
X leave ();
X return 1;
X}
X
X/*
X * Function return - set exit value and return via a long jmp
X */
X
Xstatic int doreturn (t)
XC_Op *t;
X{
X Break_C *Return_Loc = Return_List;
X
X if (t->words[1] != (char *)NULL)
X setval (lookup ("?", TRUE), t->words[1]);
X
X/* If the return address is defined - return to it. Otherwise, return
X * the value
X */
X
X if (Return_Loc != (Break_C *)NULL)
X {
X Return_List = Return_Loc->nextlev;
X longjmp (Return_Loc->brkpt, 1);
X }
X
X return getn (t->words[1]);
X}
X
X/*
X * MSDOS, EXPORT and READONLY functions
X */
X
Xstatic int doexport (t)
XC_Op *t;
X{
X return rdexp (t->words + 1, EXPORT, "export ");
X}
X
Xstatic int doreadonly (t)
XC_Op *t;
X{
X return rdexp (t->words + 1, RONLY, "readonly ");
X}
X
Xstatic int domsdos (t)
XC_Op *t;
X{
X return rdexp (t->words + 1, C_MSDOS, "msdos ");
X}
X
Xstatic int rdexp (wp, key, tstring)
Xregister char **wp;
Xint key;
Xchar *tstring;
X{
X char *cp;
X bool valid;
X
X if (*wp != (char *)NULL)
X {
X for (; *wp != (char *)NULL; wp++)
X {
X cp = *wp;
X valid = TRUE;
X
X/* Check for a valid name */
X
X if (!isalpha (*(cp++)))
X valid = FALSE;
X
X else
X {
X while (*cp)
X {
X if (!isalnum (*(cp++)))
X {
X valid = FALSE;
X break;
X }
X }
X }
X
X/* If valid - update, otherwise print a message */
X
X if (valid)
X s_vstatus (lookup (*wp, TRUE), key);
X
X else
X print_error ("%s: bad identifier\n", *wp);
X }
X }
X
X else
X {
X register Var_List *vp;
X
X for (vp = vlist; vp != (Var_List *) NULL; vp = vp->next)
X {
X if ((vp->status & key) && isalpha (*vp->name))
X {
X v1_puts (tstring);
X v1_putsn (vp->name, (int)(findeq (vp->name) - vp->name));
X v1_putc (NL);
X }
X }
X }
X
X return 0;
X}
X
X/*
X * Sort Compare function for displaying variables
X */
X
Xint sort_compare (s1, s2)
Xchar **s1;
Xchar **s2;
X{
X return strcmp (*s1, *s2);
X}
X
X/*
X * Set function
X */
X
Xstatic int doset (t)
Xregister C_Op *t;
X{
X register Var_List *vp;
X register char *cp;
X register int n, j;
X Fun_Ops *fp;
X char sign;
X char **list;
X
X/* Display ? */
X
X if ((cp = t->words[1]) == (char *)NULL)
X {
X
X/* Count the number of entries to print */
X
X for (n = 0, vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
X {
X if (isalnum (*vp->name))
X n++;
X }
X
X/* Build a local array of name */
X
X list = (char **)space (sizeof (char *) * n);
X
X for (n = 0, vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
X {
X if (isalnum (*vp->name))
X {
X if (list == (char **)NULL)
X v1a_puts (vp->name);
X
X else
X list[n++] = vp->name;
X }
X }
X
X/* Sort them and then print */
X
X if (list != (char **)NULL)
X {
X qsort (list, n, sizeof (char *), sort_compare);
X
X for (j = 0; j < n; j++)
X v1a_puts (list[j]);
X
X DELETE (list);
X }
X
X/* Print the list of functions */
X
X for (fp = fun_list; fp != (Fun_Ops *)NULL; fp = fp->next)
X Print_ExTree (fp->tree);
X
X return 0;
X }
X
X/* Set/Unset a flag ? */
X
X if (((sign = *cp) == '-') || (*cp == '+'))
X {
X for (n = 0; (t->words[n] = t->words[n + 1]) != (char *)NULL; n++)
X ;
X
X for (; *cp; cp++)
X {
X if (*cp == 'r')
X {
X print_error ("set: -r bad option\n");
X return 1;
X }
X
X if (*cp == 'e')
X {
X if (!talking)
X {
X if (sign == '-')
X FL_SET ('e');
X
X else
X FL_CLEAR ('e');
X }
X }
X
X else if (islower (*cp))
X {
X if (sign == '-')
X FL_SET (*cp);
X
X else
X FL_CLEAR (*cp);
X }
X }
X
X setdash ();
X }
X
X/* Set up parameters ? */
X
X if (t->words[1])
X {
X t->words[0] = dolv[0];
X
X for (n = 1; t->words[n] != (char *)NULL; n++)
X setarea ((char *)t->words[n], 0);
X
X dolc = n-1;
X dolv = t->words;
X setval (lookup ("#", TRUE), putn (dolc));
X setarea ((char *)(dolv - 1), 0);
X }
X
X return 0;
X}
X
X/*
X * History functions - display, initialise, enable, disable
X */
X
Xstatic int dohistory (t)
XC_Op *t;
X{
X char *cp;
X
X if (!talking)
X return 1;
X
X if ((cp = t->words[1]) == (char *)NULL)
X Display_History ();
X
X else if (strcmp (cp, "-i") == 0)
X Clear_History ();
X
X else if (strcmp (cp, "-d") == 0)
X History_Enabled = FALSE;
X
X else if (strcmp (cp, "-e") == 0)
X History_Enabled = TRUE;
X
X return 0;
X}
X
X/*
X * Type fucntion: For each name, indicate how it would be interpreted
X */
X
Xstatic char *type_ext[] = {
X "", ".exe", ".com", ".sh"
X};
X
Xstatic int dotype (t)
Xregister C_Op *t;
X{
X register char *sp; /* Path pointers */
X char *cp;
X char *ep;
X char *xp; /* In file name pointers */
X char *xp1;
X int n = 1; /* Argument count */
X int i, fp;
X bool found; /* Found flag */
X
X while ((cp = t->words[n++]) != (char *)NULL)
X {
X sp = any ('/', cp) ? null : path->value;
X found = FALSE;
X
X do
X {
X sp = path_append (sp, cp, e.linep);
X ep = &e.linep[strlen (e.linep)];
X
X/* Get start of file name */
X
X if ((xp1 = strrchr (e.linep, '/')) == (char *)NULL)
X xp1 = e.linep;
X
X else
X ++xp1;
X
X/* Look up all 4 types */
X
X for (i = 0; (i < 4) && !found; i++)
X {
X strcpy (ep, type_ext[i]);
X
X if (access (e.linep, F_OK) == 0)
X {
X
X/* If no extension or .sh extension, check for shell script */
X
X if (((xp = strchr (xp1, '.')) == (char *)NULL) ||
X (stricmp (xp, ".sh") == 0))
X {
X if ((fp = Check_Script (e.linep)) < 0)
X continue;
X
X S_close (fp, TRUE);
X }
X
X else if ((stricmp (xp, ".exe") != 0) &&
X (stricmp (xp, ".com") != 0))
X continue;
X
X print_error ("%s is %s\n", cp, e.linep);
X found = TRUE;
X }
X }
X } while ((sp != (char *)NULL) && !found);
X
X if (!found)
X print_error ("%s not found\n", cp);
X }
X
X return 0;
X}
X
X/* Table of internal commands */
X
Xstatic struct builtin builtin[] = {
X ".", dodot,
X ":", dolabel,
X "[", dotest,
X "break", dobreak,
X "cd", dochdir,
X "continue", docontinue,
X "echo", doecho,
X "eval", doeval,
X "exec", doexec,
X "exit", doexit,
X "export", doexport,
X "getopt", dogetopt,
X "history", dohistory,
X "msdos", domsdos,
X "pwd", dopwd,
X "read", doread,
X "readonly", doreadonly,
X "return", doreturn,
X "set", doset,
X "shift", doshift,
X "swap", doswap,
X "test", dotest,
X "trap", dotrap,
X "type", dotype,
X "umask", doumask,
X "unset", dounset,
X "ver", dover,
X (char *)NULL,
X};
X
X/*
X * Look up a built in command
X */
X
Xint (*inbuilt (s))()
Xregister char *s;
X{
X register struct builtin *bp;
X
X if ((strlen (s) == 2) && isalpha (*s) && (*s != '_') && (*(s + 1) == ':'))
X return dodrive;
X
X for (bp = builtin; bp->command != (char *)NULL; bp++)
X {
X if (stricmp (bp->command, s) == 0)
X return bp->fn;
X }
X
X return NULL;
X}
X
X/* Write to stdout functions - printf, fputs, fputc, and a special */
X
X/*
X * Equivalent of printf without using streams
X */
X
Xvoid v1printf (fmt)
Xchar *fmt;
X{
X va_list ap;
X char x[100];
X
X va_start (ap, fmt);
X vsprintf (x, fmt, ap);
X v1_puts (x);
X va_end (ap);
X}
X
X/*
X * Write string to STDOUT
X */
X
Xvoid v1_puts (s)
Xchar *s;
X{
X write (STDOUT_FILENO, s, strlen (s));
X}
X
X/*
X * Write string to STDOUT with a NL at end
X */
X
Xvoid v1a_puts (s)
Xchar *s;
X{
X char c = NL;
X
X write (STDOUT_FILENO, s, strlen (s));
X write (STDOUT_FILENO, &c, 1);
X}
X
X/*
X * Write n characters to STDOUT
X */
X
Xstatic void v1_putsn (s, n)
Xchar *s;
Xint n;
X{
X write (STDOUT_FILENO, s, n);
X}
X
X/*
X * Write 1 character to STDOUT
X */
X
Xvoid v1_putc (c)
Xchar c;
X{
X write (STDOUT_FILENO, &c, 1);
X}
SHAR_EOF
chmod 0644 shell/sh7.c || echo "restore of shell/sh7.c fails"
set `wc -c shell/sh7.c`;Sum=$1
if test "$Sum" != "30980"
then echo original size 30980, current size $Sum;fi
echo "x - extracting shell/sh8.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh8.c &&
X/* MS-DOS SHELL - Unix File I/O Emulation
X *
X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
X *
X * This code is subject to the following copyright restrictions:
X *
X * 1. Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in the
X * source form and the copyright notice in file sh6.c is displayed
X * on entry to the program.
X *
X * 2. The sources (or parts thereof) or objects generated from the sources
X * (or parts of sources) cannot be sold under any circumstances.
X *
X * $Header: sh8.c 1.1 90/01/29 17:46:37 MS_user Exp $
X *
X * $Log: sh8.c $
X * Revision 1.1 90/01/29 17:46:37 MS_user
X * Initial revision
X *
X *
X */
X
X#include <sys/types.h>
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <stdlib.h>
X#include <fcntl.h>
X#include <io.h>
X#include <stdarg.h>
X#include <string.h>
X#include <unistd.h>
X#include <limits.h>
X#include "sh.h"
X
X#define F_START 4
X
Xstatic char *nopipe = "can't create pipe - try again\n";
X
X/* List of open files to allow us to simulate the Unix open and unlink
X * operation for temporary files
X */
X
Xtypedef struct flist {
X struct flist *fl_next; /* Next link */
X char *fl_name; /* File name */
X bool fl_close; /* Delete on close flag */
X int fl_size; /* Size of fl_fd array */
X int fl_count; /* Number of entries in array */
X int fl_mode; /* File open mode */
X int *fl_fd; /* File ID array (for dup) */
X} s_flist;
X
Xstatic s_flist *list_start = (s_flist *)NULL;
Xstatic s_flist *find_entry (int);
X
X/*
X * Open a file and add it to the Open file list. Errors are the same as
X * for a normal open.
X */
X
Xint S_open (d_flag, name, mode)
Xbool d_flag;
Xchar *name;
Xint mode;
X{
X va_list ap;
X int pmask;
X s_flist *fp = (struct s_flist *)NULL;
X int *f_list = (int *)NULL;
X char *f_name = (char *)NULL;
X
X/* Check the permission mask if it exists */
X
X va_start (ap, mode);
X pmask = va_arg (ap, int);
X va_end (ap);
X
X/* Grap some space. If it fails, free space and return an error */
X
X if (((fp = (s_flist *) space (sizeof (s_flist))) == (s_flist *)NULL) ||
X ((f_list = (int *) space (sizeof (int) * F_START)) == (int *)NULL) ||
X ((f_name = strsave (name, 0)) == null))
X {
X if (f_list == (int *)NULL)
X DELETE (f_list);
X
X if (fp == (s_flist *)NULL)
X DELETE (fp);
X
X errno = ENOMEM;
X return -1;
X }
X
X/* Set up the structure */
X
X fp->fl_name = strcpy (f_name, name);
X fp->fl_close = d_flag;
X fp->fl_size = F_START;
X fp->fl_count = 1;
X fp->fl_fd = f_list;
X fp->fl_mode = mode;
X
X/* Open the file */
X
X if ((fp->fl_fd[0] = open (name, mode, pmask)) < 0)
X {
X pmask = errno;
X DELETE (f_name);
X DELETE (f_list);
X DELETE (fp);
X errno = pmask;
X return -1;
X }
X
X/* Make sure everything is in area 0 */
X
X setarea ((char *)fp, 0);
X setarea ((char *)f_list, 0);
X
X/* List into the list */
X
X fp->fl_next = list_start;
X list_start = fp;
X
X/* Return the file descriptor */
X
X return fp->fl_fd[0];
X}
X
X/*
X * Scan the File list for the appropriate entry for the specified ID
X */
X
Xstatic s_flist *find_entry (fid)
Xint fid;
X{
X s_flist *fp = list_start;
X int i;
X
X while (fp != (s_flist *)NULL)
X {
X for (i = 0; i < fp->fl_count; i++)
X {
X if (fp->fl_fd[i] == fid)
X return fp;
X }
X
X fp = fp->fl_next;
X }
X
X return (s_flist *)NULL;
X}
X
X/* Close the file
X *
X * We need a version of close that does everything but close for dup2 as
X * new file id is closed. If c_flag is TRUE, close the file as well.
X */
X
Xint S_close (fid, c_flag)
Xint fid;
Xbool c_flag;
X{
X s_flist *fp = find_entry (fid);
X s_flist *last = (s_flist *)NULL;
X s_flist *fp1 = list_start;
X int i, serrno;
X bool release = TRUE;
X bool delete = FALSE;
X char *fname;
X
X/* Find the entry for this ID */
X
X if (fp != (s_flist *)NULL)
X {
X for (i = 0; i < fp->fl_count; i++)
X {
X if (fp->fl_fd[i] == fid)
X fp->fl_fd[i] = -1;
X
X if (fp->fl_fd[i] != -1)
X release = FALSE;
X }
X
X/* Are all the Fids closed ? */
X
X if (release)
X {
X fname = fp->fl_name;
X delete = fp->fl_close;
X DELETE (fp->fl_fd);
X
X/* Scan the list and remove the entry */
X
X while (fp1 != (s_flist *)NULL)
X {
X if (fp1 != fp)
X {
X last = fp1;
X fp1 = fp1->fl_next;
X continue;
X }
X
X if (last == (s_flist *)NULL)
X list_start = fp->fl_next;
X
X else
X last->fl_next = fp->fl_next;
X
X break;
X }
X
X/* OK - delete the area */
X
X DELETE (fp);
X }
X }
X
X/* Close the file anyway */
X
X if (c_flag)
X {
X i = close (fid);
X serrno = errno;
X }
X
X/* Delete the file ? */
X
X if (delete)
X {
X unlink (fname);
X DELETE (fname);
X }
X
X/* Restore results and error code */
X
X errno = serrno;
X return i;
X}
X
X/*
X * Duplicate file handler. Add the new handler to the ID array for this
X * file.
X */
X
Xint S_dup (old_fid)
Xint old_fid;
X{
X int new_fid;
X
X if ((new_fid = dup (old_fid)) >= 0)
X S_Remap (old_fid, new_fid);
X
X return new_fid;
X}
X
X/*
X * Add the ID to the ID array for this file
X */
X
Xvoid S_Remap (old_fid, new_fid)
Xint old_fid, new_fid;
X{
X s_flist *fp = find_entry (old_fid);
X int *flist;
X int i;
X
X if (fp == (s_flist *)NULL)
X return;
X
X/* Is there an empty slot ? */
X
X for (i = 0; i < fp->fl_count; i++)
X {
X if (fp->fl_fd[i] == -1)
X {
X fp->fl_fd[i] = new_fid;
X return;
X }
X }
X
X/* Is there any room at the end ? No - grap somemore space and effect a
X * re-alloc. What to do if the re-alloc fails - should really get here.
X * Safty check only??
X */
X
X if (fp->fl_count == fp->fl_size)
X {
X if ((flist = (int *) space ((fp->fl_size + F_START) * sizeof (int)))
X == (int *)NULL)
X return;
X
X memcpy ((char *)flist, (char *)fp->fl_fd, sizeof (int) * fp->fl_size);
X DELETE (fp->fl_fd);
X
X fp->fl_fd = flist;
X fp->fl_size += F_START;
X }
X
X fp->fl_fd[fp->fl_count++] = new_fid;
X}
X
X/*
X * Set Delete on Close flag
X */
X
Xvoid S_Delete (fid)
Xint fid;
X{
X s_flist *fp = find_entry (fid);
X
X if (fp != (s_flist *)NULL)
X fp->fl_close = TRUE;
X}
X
X/*
X * Duplicate file handler onto specific handler
X */
X
Xint S_dup2 (old_fid, new_fid)
Xint old_fid;
Xint new_fid;
X{
X int res = 0;
X int i;
X Save_IO *sp;
X
X/* If duping onto stdin, stdout or stderr, Search the Save IO stack for an
X * entry matching us
X */
X
X if ((new_fid >= STDIN_FILENO) && (new_fid <= STDERR_FILENO))
X {
X for (sp = SSave_IO, i = 0; (i < NSave_IO_E) &&
X (SSave_IO[i].depth < Execute_stack_depth);
X i++);
X
X/* If depth is greater the Execute_stack_depth - we should panic as this
X * should not happen. However, for the moment, I'll ignore it
X */
X
X/* If there an entry for this depth ? */
X
X if (i == NSave_IO_E)
X {
X
X/* Do we need more space? */
X
X if (NSave_IO_E == MSave_IO_E)
X {
X sp = (Save_IO *)space ((MSave_IO_E + SSAVE_IO_SIZE) * sizeof (Save_IO));
X
X/* Check for error */
X
X if (sp == (Save_IO *)NULL)
X {
X errno = ENOMEM;
X return -1;
X }
X
X/* Save original data */
X
X if (MSave_IO_E != 0)
X {
X memcpy (sp, SSave_IO, sizeof (Save_IO) * MSave_IO_E);
X DELETE (SSave_IO);
X }
X
X setarea ((char *)sp, 1);
X SSave_IO = sp;
X MSave_IO_E += SSAVE_IO_SIZE;
X }
X
X/* Initialise the new entry */
X
X sp = &SSave_IO[NSave_IO_E++];
X sp->depth = Execute_stack_depth;
X sp->fp[STDIN_FILENO] = -1;
X sp->fp[STDOUT_FILENO] = -1;
X sp->fp[STDERR_FILENO] = -1;
X }
X
X if (sp->fp[new_fid] == -1)
X sp->fp[new_fid] = remap (new_fid);
X }
X
X/* OK - Dup the descriptor */
X
X if ((old_fid != -1) && ((res = dup2 (old_fid, new_fid)) >= 0))
X {
X S_close (new_fid, FALSE);
X S_Remap (old_fid, new_fid);
X }
X
X return res;
X}
X
X/*
X * Restore the Stdin, Stdout and Stderr to original values
X */
X
Xint restore_std (rv)
Xint rv;
X{
X int j, i;
X Save_IO *sp;
X
X/* Start at the top and remove any entries above the current execute stack
X * depth
X */
X
X for (j = NSave_IO_E; j > 0; j--)
X {
X sp = &SSave_IO[j - 1];
X
X if (sp->depth < Execute_stack_depth)
X break;
X
X/* Reduce number of entries */
X
X --NSave_IO_E;
X
X/* Close and restore any files */
X
X for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
X {
X if (sp->fp[i] != -1)
X {
X S_close (i, TRUE);
X dup2 (sp->fp[i], i);
X S_close (sp->fp[i], TRUE);
X }
X }
X }
X
X return rv;
X}
X
X/*
X * Create a Pipe
X */
X
Xint openpipe ()
X{
X register int i;
X
X if ((i = S_open (TRUE, g_tempname (), O_PMASK, 0600)) < 0)
X print_error (nopipe);
X
X return i;
X}
X
X/*
X * Close a pipe
X */
X
Xvoid closepipe (pv)
Xregister int pv;
X{
X if (pv != -1)
X S_close (pv, TRUE);
X}
X
X/*
X * Write a character to STDERR
X */
X
Xvoid S_putc (c)
Xint c;
X{
X write (STDERR_FILENO, (char *)&c, 1);
X}
X
X/*
X * Write a string to STDERR
X */
X
Xvoid S_puts (s)
Xchar *s;
X{
X write (STDERR_FILENO, s, strlen (s));
X}
X
X/*
X * Check for restricted shell
X */
X
Xbool check_rsh (s)
Xchar *s;
X{
X if (r_flag)
X {
X print_error ("%s: restricted\n", s);
X return TRUE;
X }
X
X return FALSE;
X}
X
X/*
X * Check to see if a file is a shell script. If it is, return the file
X * handler for the file
X */
X
Xint O_for_execute (path)
Xchar *path;
X{
X int i, end;
X char local_path[FFNAME_MAX];
X
X/* Work on a copy of the path */
X
X strcpy (local_path, path);
X
X/* Try the file name and then with a .sh appended */
X
X for (end = 0; end < 2; end++)
X {
X if ((i = Check_Script (local_path)) >= 0)
X return i;
X
X if (!end)
X strcat (local_path, ".sh");
X }
X
X return -1;
X}
X
X/*
X * Check for shell script
X */
X
Xint Check_Script (path)
Xchar *path;
X{
X char buf[5];
X int i;
X
X if (((i = S_open (FALSE, path, O_RMASK)) >= 0) &&
X ((read (i, buf, 6) == 5) && (strncmp (buf, "#!sh\n", 5) == 0)))
X return i;
X
X if (i != -1)
X S_close (i, TRUE);
X
X return -1;
X}
X
X/*
X * Convert slashes to backslashes for MSDOS
X */
X
Xvoid Convert_Slashes (sp)
Xchar *sp;
X{
X while (*sp)
X {
X if (*sp == '/')
X *sp = '\\';
X
X ++sp;
X }
X}
SHAR_EOF
chmod 0644 shell/sh8.c || echo "restore of shell/sh8.c fails"
set `wc -c shell/sh8.c`;Sum=$1
if test "$Sum" != "9874"
then echo original size 9874, current size $Sum;fi
echo "x - extracting shell/sh9.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh9.c &&
X/* MS-DOS SHELL - History Processing
X *
X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
X *
X * This code is subject to the following copyright restrictions:
X *
X * 1. Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in the
X * source form and the copyright notice in file sh6.c is displayed
X * on entry to the program.
X *
X * 2. The sources (or parts thereof) or objects generated from the sources
X * (or parts of sources) cannot be sold under any circumstances.
X *
X * $Header: sh9.c 1.1 90/01/26 17:25:19 MS_user Exp $
X *
X * $Log: sh9.c $
X * Revision 1.1 90/01/26 17:25:19 MS_user
X * Initial revision
X *
X *
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <conio.h>
X#include <string.h>
X#include <memory.h>
X#include <ctype.h>
X#include <signal.h>
X#include <stdlib.h>
X#include <stddef.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <limits.h>
X#include <dos.h>
X#include <unistd.h>
X#include "sh.h"
X
Xstatic bool alpha_numeric (int);
Xstatic bool function (int);
Xstatic bool Process_History (int);
Xstatic bool Scan_History (void);
Xstatic void Redisplay_Line (void);
Xstatic void Process_Stdin (void);
Xstatic void Page_History (int);
Xstatic bool UpDate_CLine (char *);
Xstatic bool Re_start (char *);
Xstatic void memrcpy (char *, char *, int);
Xstatic int read_cursor_position (void);
Xstatic void set_cursor_position (int);
Xstatic void gen_cursor_position (void);
X
Xstatic bool insert_mode = FALSE;
Xstatic char *c_buffer_pos; /* Position in command line */
Xstatic char *end_buffer; /* End of command line */
Xstatic int s_cursor; /* Start cursor position */
Xstatic int c_history = -1; /* Current entry */
Xstatic int l_history = 0; /* End of history array */
Xstatic int M_length = -1; /* Match length */
Xstatic char l_buffer[LINE_MAX + 1];
Xstatic char *No_prehistory = "history: No previous commands\033[2K\n";
Xstatic char *No_MatchHistory = "history: No history match found\033[2K\n";
Xstatic char *No_posthistory = "history: No more commands\033[2K\n";
Xstatic char *History_2long = "history: History line too long\033[2K\n";
Xstatic char *H_TooLongI = "History file line too long - ignored (%d)\n";
X
X/* Arrary of history Items */
X
Xstatic struct cmd_history {
X int number;
X char *command;
X} cmd_history[HISTORY_MAX];
X
X/* Processing standard input */
X
Xint Get_stdin (ap)
Xregister IO_Args *ap;
X{
X int coff = (int)ap->afpos;
X char rv;
X
X/* Is there anything in the input buffer. If not, add the previous line to
X * the history buffer and get the next line
X */
X
X if (!coff)
X Process_Stdin (); /* No - get input */
X
X/* Get the next character */
X
X if ((rv = l_buffer[coff]) == NL)
X {
X l_buffer[coff] = 0;
X ap->afpos = 0L;
X }
X
X/* Check for end of file */
X
X else if (rv == 0x1a)
X {
X l_buffer[coff] = 0;
X ap->afpos = 0L;
X rv = 0;
X }
X
X else
X ap->afpos++;
X
X return rv;
X}
X
X/* Input processing function */
X
Xstatic void Process_Stdin ()
X{
X int i;
X char *control = "^x";
X
X/* Set to last history item */
X
X c_history = l_history - 1;
X
X/* Process the input */
X
X while (TRUE)
X {
X c_buffer_pos = l_buffer; /* Initialise */
X end_buffer = l_buffer;
X insert_mode = FALSE;
X M_length = -1;
X s_cursor = read_cursor_position ();
X
X while (((i = getch ()) != 0x1a) && (i != NL) && (i != '\r'))
X {
X
X/* Re-position the line? */
X
X if (((i) ? alpha_numeric (i) : function (getch ())))
X Redisplay_Line ();
X
X/* Reposition the cursor */
X
X gen_cursor_position ();
X }
X
X/* Terminate the line */
X
X *end_buffer = 0;
X v1_putc (NL);
X
X/* Line input - check for history */
X
X if ((*l_buffer == '!') && Process_History (0))
X {
X v1a_puts (l_buffer);
X break;
X }
X
X else if (*l_buffer != '!')
X break;
X
X/* Output prompt and try again */
X
X Re_start ((char *)NULL);
X }
X
X *end_buffer = (char)((i == '\r') ? NL : i);
X}
X
X/* Handler Alpha_numeric characters */
X
Xstatic bool alpha_numeric (c)
Xint c;
X{
X bool redisplay = FALSE;
X
X/* Backspace processing */
X
X if (c == 0x08)
X {
X if (c_buffer_pos == l_buffer)
X {
X v1_putc (0x07); /* Ring bell */
X return FALSE;
X }
X
X/* Decrement current position */
X
X if ((c_buffer_pos--) == end_buffer)
X --end_buffer;
X
X else
X *c_buffer_pos = ' ';
X
X return TRUE;
X }
X
X/* Normal character processing */
X
X if ((c_buffer_pos - l_buffer) == LINE_MAX)
X {
X v1_putc (0x07); /* Ring bell */
X return FALSE;
X }
X
X else if (!insert_mode)
X {
X if (c_buffer_pos == end_buffer)
X ++end_buffer;
X
X else if (iscntrl (*c_buffer_pos) || iscntrl (c))
X redisplay = TRUE;
X
X *(c_buffer_pos++) = (char)c;
X
X if (redisplay || (c == '\t'))
X return TRUE;
X
X if (iscntrl (c))
X {
X v1_putc ('^');
X c += '@';
X }
X
X v1_putc ((char)c);
X return FALSE;
X }
X
X else if ((end_buffer - l_buffer) == LINE_MAX)
X {
X v1_putc (0x07); /* Ring bell - line full */
X return FALSE;
X }
X
X else
X {
X if (c_buffer_pos != end_buffer)
X memrcpy (end_buffer + 1, end_buffer, end_buffer - c_buffer_pos + 1);
X
X ++end_buffer;
X *(c_buffer_pos++) = (char)c;
X return TRUE;
X }
X}
X
X/* Process function keys */
X
Xstatic bool function (fn)
Xint fn;
X{
X switch (fn)
X {
X case 'I': /* Scan back command line */
X case 'Q': /* Scan up command line */
X if (M_length == -1)
X break;
X
X Page_History ((fn == 'I') ? -1 : 1);
X return TRUE;
X
X case 'H': /* Previous command line */
X Process_History (-1);
X return TRUE;
X
X case 'P': /* Next command line */
X Process_History (1);
X return TRUE;
X
X case 'K': /* Cursor left */
X if (c_buffer_pos != l_buffer)
X --c_buffer_pos;
X
X else
X v1_putc (0x07);
X
X return FALSE;
X
X case 'M': /* Cursor right */
X if (c_buffer_pos != end_buffer)
X ++c_buffer_pos;
X
X else
X v1_putc (0x07);
X
X return FALSE;
X
X case 's': /* Cursor left a word */
X if (c_buffer_pos != l_buffer)
X {
X --c_buffer_pos; /* Reposition on previous char */
X
X while (isspace (*c_buffer_pos) && (c_buffer_pos != l_buffer))
X --c_buffer_pos;
X
X while (!isspace (*c_buffer_pos) && (c_buffer_pos != l_buffer))
X --c_buffer_pos;
X
X if (c_buffer_pos != l_buffer)
X ++c_buffer_pos;
X }
X
X else
X v1_putc (0x07);
X
X return FALSE;
X
X case 't': /* Cursor right a word */
X if (c_buffer_pos != end_buffer)
X {
X
X/* Skip to the end of the current word */
X
X while (!isspace (*c_buffer_pos) && (c_buffer_pos != end_buffer))
X ++c_buffer_pos;
X
X/* Skip over the white space */
X
X while (isspace (*c_buffer_pos) && (c_buffer_pos != end_buffer))
X ++c_buffer_pos;
X }
X
X else
X v1_putc (0x07);
X
X return FALSE;
X
X case 'G': /* Cursor home */
X c_buffer_pos = l_buffer;
X return FALSE;
X
X case 'u': /* Flush to end */
X memset (c_buffer_pos, ' ', end_buffer - c_buffer_pos);
X end_buffer = c_buffer_pos;
X return TRUE;
X
X case 'O': /* Cursor end of command */
X if (*l_buffer == '!')
X {
X *end_buffer = 0;
X Process_History (2);
X return TRUE;
X }
X
X c_buffer_pos = end_buffer;
X return FALSE;
X
X case 'R': /* Switch insert mode */
X insert_mode = (insert_mode) ? FALSE : TRUE;
X return FALSE;
X
X case 'S': /* Delete character */
X if (c_buffer_pos != end_buffer)
X memcpy (c_buffer_pos, c_buffer_pos + 1,
X end_buffer - c_buffer_pos);
X
X if (end_buffer == l_buffer)
X {
X v1_putc (0x07);
X return TRUE;
X }
X
X if (--end_buffer < c_buffer_pos)
X --c_buffer_pos;
X
X return TRUE;
X }
X
X v1_putc (0x07);
X return FALSE;
X}
X
X/* Read Cursor position */
X
Xstatic int read_cursor_position ()
X{
X union REGS r;
X
X r.h.ah = 0x03; /* Read cursor position */
X r.h.bh = 0; /* Page zero */
X int86 (0x10, &r, &r);
X return (r.h.dh * 80) + r.h.dl;
X}
X
X/* Re-position the cursor */
X
Xstatic void set_cursor_position (new)
Xint new;
X{
X union REGS r;
X
X r.h.ah = 0x02; /* Set new position */
X r.h.bh = 0; /* Page zero */
X r.h.dh = (unsigned char)(new / 80);
X r.h.dl = (unsigned char)(new % 80);
X
X/* Are we at the bottom of the page? */
X
X if (r.h.dh == 25)
X {
X r.h.dh = 24;
X s_cursor -= 80;
X }
X
X int86 (0x10, &r, &r);
X}
X
X/* Generate the new cursor position */
X
Xstatic void gen_cursor_position ()
X{
X char *cp = l_buffer - 1;
X int off = s_cursor;
X
X/* Search to current position */
X
X while (++cp != c_buffer_pos)
X {
X if (*cp == '\t')
X while ((++off) % 8);
X
X else if (iscntrl (*cp))
X off += 2;
X
X else
X ++off;
X }
X
X/* Position the cursor */
X
X set_cursor_position (off);
X}
X
X/* Redisplay the current line */
X
Xstatic void Redisplay_Line ()
X{
X char *control = "^x";
X char *cp = l_buffer;
X int off = s_cursor;
X
X/* Reposition to start of line */
X
X set_cursor_position (s_cursor);
X
X/* Output the line */
X
X while (cp != end_buffer)
X {
X if (*cp == '\t')
X {
X do
X {
X v1_putc (SP);
X } while ((++off) % 8);
X }
X
X else if (iscntrl (*cp))
X {
X control[1] = *cp + '@';
X v1_puts (control);
X off += 2;
X }
X
X else
X {
X ++off;
X v1_putc (*cp);
X }
X
X ++cp;
X }
X
X v1_puts ("\033[2K"); /* clear to end of line */
X}
X
X/* Process history command
X *
X * -1: Previous command
X * 1: Next command
X * 0: Current command
X * 2: Current command with no options processing
X */
X
Xstatic bool Process_History (direction)
Xint direction;
X{
X char *optionals = null;
X
X c_buffer_pos = l_buffer;
X end_buffer = l_buffer;
X c_history += (direction == 2) ? 0 : direction;
X
X switch (direction)
X {
X case -1: /* Move up one line */
X if (c_history < 0)
X {
X ++c_history;
X return Re_start (No_prehistory);
X }
X
X break;
X
X case 1: /* Move to next history line */
X if (c_history >= l_history)
X {
X --c_history;
X return Re_start (No_posthistory);
X }
X
X break;
X
X case 0: /* Check out l_buffer */
X optionals = l_buffer; /* Are there any additions to */
X /* the history line */
X
X/* Find the end of the first part */
X
X while (!isspace (*optionals) && *optionals)
X ++optionals;
X
X/* Terminate the history command */
X
X if (*optionals)
X *(optionals++) = 0;
X
X/* Find the end of the space separator part which gives the start of the
X * optionals
X */
X
X while (isspace (*optionals))
X ++optionals;
X
X
X/* Copy selected item into line buffer */
X
X case 2:
X M_length = strlen (l_buffer) - 1;
X if (!Scan_History ())
X return FALSE;
X
X break;
X }
X
X return UpDate_CLine (optionals);
X}
X
X/* Ok c_history points to the new line. Move optionals after history
X * and the copy in history and add a space
X */
X
Xstatic bool UpDate_CLine (optionals)
Xchar *optionals;
X{
X int opt_len;
X
X end_buffer = &l_buffer[strlen (cmd_history[c_history].command)];
X
X if ((end_buffer - l_buffer + (opt_len = strlen (optionals)) + 1) >= LINE_MAX)
X return Re_start (History_2long);
X
X if (end_buffer > optionals)
X memrcpy (end_buffer + 1 + opt_len, optionals + opt_len, opt_len + 1);
X
X else
X strcpy (end_buffer + 1, optionals);
X
X strcpy (l_buffer, cmd_history[c_history].command);
X
X if (opt_len)
X *end_buffer = ' ';
X
X end_buffer = &l_buffer[strlen (l_buffer)];
X return TRUE;
X}
X
X/* Scan the line buffer for a history match */
X
Xstatic bool Scan_History ()
X{
X char *cp = &l_buffer[1];
X int c_len = strlen (cp);
X char *ep;
X int i = (int)strtol (cp, &ep, 10);
X
X/* Get the previous command ? (single !) */
X
X if (c_len == 0)
X {
X if (c_history < 0)
X {
X M_length = -1;
X return Re_start (No_prehistory);
X }
X
X return TRUE;
X }
X
X/* Request for special history number item. Check History file empty */
X
X if (l_history == 0)
X {
X M_length = -1;
X return Re_start (No_MatchHistory);
X }
X
X/* Check for number */
X
X if (!*ep)
X {
X M_length = -1;
X
X for (c_history = l_history - 1;
X (cmd_history[c_history].number != i) && (c_history >= 0);
X --c_history);
X }
X
X/* No - scan for a match */
X
X else
X {
X for (c_history = l_history - 1;
X (strncmp (cp, cmd_history[c_history].command, c_len) != 0)
X && (c_history >= 0);
X --c_history);
X }
X
X/* Anything found ? */
X
X if (c_history == -1)
X {
X c_history = l_history - 1;
X return Re_start (No_MatchHistory);
X }
X
X return TRUE;
X}
X
X/* Scan back or forward from current history */
X
Xstatic void Page_History (direction)
Xint direction;
X{
X c_buffer_pos = l_buffer;
X end_buffer = l_buffer;
X
X if (l_history == 0)
X {
X M_length = -1;
X Re_start (No_MatchHistory);
X return;
X }
X
X/* scan for a match */
X
X while (((c_history += direction) >= 0) && (c_history != l_history) &&
X (strncmp (l_buffer, cmd_history[c_history].command, M_length) != 0));
X
X/* Anything found ? */
X
X if ((c_history < 0) || (c_history == l_history))
X {
X c_history = l_history - 1;
X Re_start (No_MatchHistory);
X }
X
X else
X UpDate_CLine (null);
X}
X
X/* Load history file */
X
Xvoid Load_History ()
X{
X FILE *fp;
X char *cp;
X int i = 0;
X Var_List *lset;
X
X/* Initialise history array */
X
X memset (cmd_history, 0, sizeof (struct cmd_history) * HISTORY_MAX);
X c_history = -1; /* Current entry */
X l_history = 0; /* End of history array */
X
X if ((lset = lookup (history_file, TRUE))->value == null)
X setval (lset, strcat (strcpy (l_buffer, lookup (home, FALSE)->value),
X "history.sh"));
X
X if (!History_Enabled || ((fp = fopen (lset->value, "rt")) == (FILE *)NULL))
X return;
X
X/* Read in file */
X
X while (fgets (l_buffer, LINE_MAX, fp) != (char *)NULL)
X {
X ++i;
X
X if ((cp = strchr (l_buffer, NL)) == (char *)NULL)
X print_warn (H_TooLongI, i);
X
X else
X {
X *cp = 0;
X Add_History (TRUE);
X }
X }
X
X fclose (fp);
X}
X
X/* Add entry to history file */
X
Xvoid Add_History (past)
Xbool past; /* Past history? */
X{
X int i;
X
X if ((!History_Enabled) || (strlen (l_buffer) == 0))
X return;
X
X/* If adding past history, decrement all numbers previous */
X
X if ((past) && l_history)
X {
X for (i = 0; i < l_history; i++)
X --(cmd_history[i].number);
X }
X
X/* If the array is full, remove the last item */
X
X if (l_history == HISTORY_MAX)
X {
X if (cmd_history[0].command != null)
X DELETE (cmd_history[0].command);
X
X --l_history;
X memcpy (&cmd_history[0], &cmd_history[1],
X sizeof (struct cmd_history) * (HISTORY_MAX - 1));
X }
X
X/* If there are any items in the array */
X
X c_history = l_history;
X Current_Event = (l_history) ? cmd_history[l_history - 1].number + 1 : 0;
X cmd_history[l_history].number = Current_Event;
X
X/* Save the string */
X
X cmd_history[l_history++].command = strsave (l_buffer, 0);
X}
X
X/* Print history */
X
Xvoid Display_History ()
X{
X int i;
X struct cmd_history *cp = cmd_history;
X
X if (!l_history)
X return;
X
X for (i = 0; i < l_history; ++cp, ++i)
X {
X v1printf ("%5d: ", cp->number);
X v1a_puts (cp->command);
X }
X}
X
X/* Dump history to file */
X
Xvoid Dump_History ()
X{
X int i;
X struct cmd_history *cp = cmd_history;
X FILE *fp;
X
X if (!History_Enabled ||
X ((fp = fopen (lookup (history_file, FALSE)->value, "wt")) ==
X (FILE *)NULL))
X return;
X
X for (i = 0; i < l_history; ++cp, ++i)
X {
X fputs (cp->command, fp);
X fputc (NL, fp);
X }
X
X fclose (fp);
X}
X
X/* Clear out history */
X
Xvoid Clear_History ()
X{
X int i;
X struct cmd_history *cp = cmd_history;
X
X for (i = 0; i < l_history; ++cp, ++i)
X {
X if (cp->command != null)
X DELETE (cp->command);
X }
X
X memset (cmd_history, 0, sizeof (struct cmd_history) * HISTORY_MAX);
X
X c_history = -1; /* Current entry */
X l_history = 0; /* End of history array */
X Current_Event = 0;
X}
X
X/* Output warning message and prompt */
X
Xstatic bool Re_start (cp)
Xchar *cp;
X{
X if (cp != (char *)NULL)
X print_warn (cp);
X
X put_prompt (last_prompt);
X
X/* Re-initialise */
X
X c_buffer_pos = l_buffer;
X end_buffer = l_buffer;
X s_cursor = read_cursor_position ();
X
X return FALSE;
X}
X
X/* Copy backwards */
X
Xstatic void memrcpy (sp1, sp, cnt)
Xchar *sp1;
Xchar *sp;
Xint cnt;
X{
X while (cnt--)
X *(sp1--) = *(sp--);
X}
SHAR_EOF
chmod 0644 shell/sh9.c || echo "restore of shell/sh9.c fails"
set `wc -c shell/sh9.c`;Sum=$1
if test "$Sum" != "15932"
then echo original size 15932, current size $Sum;fi
echo "x - extracting shell/sh10.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh10.c &&
X/* MS-DOS SHELL - Function Processing
X *
X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
X *
X * This code is subject to the following copyright restrictions:
X *
X * 1. Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in the
X * source form and the copyright notice in file sh6.c is displayed
X * on entry to the program.
X *
X * 2. The sources (or parts thereof) or objects generated from the sources
X * (or parts of sources) cannot be sold under any circumstances.
X *
X * $Header: sh10.c 1.1 90/01/25 13:40:54 MS_user Exp $
X *
X * $Log: sh10.c $
X * Revision 1.1 90/01/25 13:40:54 MS_user
X * Initial revision
X *
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <process.h>
X#include <dos.h>
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <fcntl.h>
X#include <limits.h>
X#include "sh.h"
X
X/* Function declarations */
X
Xstatic void Print_Command (C_Op *);
Xstatic void Print_IO (IO_Actions *);
Xstatic void Print_Case (C_Op *);
Xstatic void Print_IString (char *, int);
Xstatic void Set_Free_ExTree (C_Op *, void (*)(char *));
Xstatic void Set_Free_Command (C_Op *, void (*)(char *));
Xstatic void Set_Free_Case (C_Op *, void (*)(char *));
Xstatic void Set_ExTree (char *);
Xstatic void Free_ExTree (char *);
X
Xstatic int Print_indent; /* Current indent level */
X
X/*
X * print the execute tree - used for displaying functions
X */
X
Xvoid Print_ExTree (t)
Xregister C_Op *t;
X{
X char **wp;
X
X if (t == (C_Op *)NULL)
X return;
X
X/* Check for start of print */
X
X if (t->type == TFUNC)
X {
X Print_indent = 0;
X v1_puts (*t->words);
X v1a_puts (" ()");
X Print_ExTree (t->left);
X return;
X }
X
X/* Otherwise, process the tree and print it */
X
X switch (t->type)
X {
X case TPAREN: /* () */
X case TCOM: /* A command process */
X Print_Command (t);
X return;
X
X case TPIPE: /* Pipe processing */
X Print_ExTree (t->left);
X Print_IString ("|\n", 0);
X Print_ExTree (t->right);
X return;
X
X case TLIST: /* Entries in a for statement */
X Print_ExTree (t->left);
X Print_ExTree (t->right);
X return;
X
X case TOR: /* || and && */
X case TAND:
X Print_ExTree (t->left);
X
X if (t->right != (C_Op *)NULL)
X {
X Print_IString ((t->type == TAND) ? "&&\n" : "||\n", 0);
X Print_ExTree (t->right);
X }
X
X return;
X
X case TFOR: /* First part of a for statement*/
X Print_IString ("for ", 0);
X v1_puts (t->str);
X
X if ((wp = t->words) != (char **)NULL)
X {
X v1_puts (" in");
X
X while (*wp != (char *)NULL)
X {
X v1_putc (SP);
X v1_puts (*wp++);
X }
X }
X
X v1_putc (NL);
X Print_IString ("do\n", 1);
X Print_ExTree (t->left);
X Print_IString ("done\n", -1);
X return;
X
X case TWHILE: /* WHILE and UNTIL functions */
X case TUNTIL:
X Print_IString ((t->type == TWHILE) ? "while " : "until ", 1);
X Print_ExTree (t->left);
X Print_IString ("do\n", 0);
X Print_ExTree (t->right);
X Print_IString ("done\n", -1);
X return;
X
X case TIF: /* IF and ELSE IF functions */
X case TELIF:
X if (t->type == TIF)
X Print_IString ("if\n", 1);
X
X else
X Print_IString ("elif\n", 1);
X
X Print_ExTree (t->left);
X
X Print_indent -= 1;
X Print_IString ("then\n", 1);
X Print_ExTree (t->right->left);
X
X if (t->right->right != (C_Op *)NULL)
X {
X Print_indent -= 1;
X
X if (t->right->right->type != TELIF)
X Print_IString ("else\n", 1);
X
X Print_ExTree (t->right->right);
X }
X
X if (t->type == TIF)
X Print_IString ("fi\n", -1);
X
X return;
X
X case TCASE: /* CASE function */
X Print_IString ("case ", 1);
X v1_puts (t->str);
X v1a_puts (" do");
X Print_Case (t->left);
X Print_IString (" esac\n", -1);
X return;
X
X case TBRACE: /* {} statement */
X Print_IString ("{\n", 1);
X if (t->left != (C_Op *)NULL)
X Print_ExTree (t->left);
X
X Print_IString ("}\n", -1);
X return;
X }
X}
X
X/*
X * Print a command line
X */
X
Xstatic void Print_Command (t)
Xregister C_Op *t;
X{
X char *cp;
X IO_Actions **iopp;
X char **wp = t->words;
X char **owp = wp;
X
X if (t->type == TCOM)
X {
X while ((cp = *wp++) != (char *)NULL)
X ;
X
X cp = *wp;
X
X/* strip all initial assignments not correct wrt PATH=yyy command etc */
X
X if ((cp == (char *)NULL) && (t->ioact == (IO_Actions **)NULL))
X {
X Print_IString (null, 0);
X
X while (*owp != (char *)NULL)
X v1a_puts (*(owp++));
X
X return;
X }
X }
X
X/* Parenthesis ? */
X
X if (t->type == TPAREN)
X {
X Print_IString ("(\n", 1);
X Print_ExTree (t->left);
X Print_IString (")", -1);
X }
X
X else
X {
X Print_IString (null, 0);
X
X while (*owp != (char *)NULL)
X {
X v1_puts (*owp++);
X
X if (*owp != (char *)NULL)
X v1_putc (SP);
X }
X }
X
X/* Set up anyother IO required */
X
X if ((iopp = t->ioact) != (IO_Actions **)NULL)
X {
X while (*iopp != (IO_Actions *)NULL)
X Print_IO (*iopp++);
X }
X
X v1_putc (NL);
X}
X
X/*
X * Print the IO re-direction
X */
X
Xstatic void Print_IO (iop)
Xregister IO_Actions *iop;
X{
X int unit = iop->io_unit;
X static char *cunit = " x";
X
X if (unit == IODEFAULT) /* take default */
X unit = (iop->io_flag & (IOREAD | IOHERE)) ? STDIN_FILENO
X : STDOUT_FILENO;
X
X/* Output unit number */
X
X cunit[1] = (char)(unit + '0');
X v1_puts (cunit);
X
X switch (iop->io_flag)
X {
X case IOHERE:
X case IOHERE | IOXHERE:
X v1_putc ('<');
X
X case IOREAD:
X v1_putc ('<');
X break;
X
X case IOWRITE | IOCAT:
X v1_putc ('>');
X
X case IOWRITE:
X v1_putc ('>');
X break;
X
X case IODUP:
X v1_puts (">&");
X v1_putc (*iop->io_name);
X return;
X }
X
X v1_puts (iop->io_name);
X}
X
X/*
X * Print out the contents of a case statement
X */
X
Xstatic void Print_Case (t)
XC_Op *t;
X{
X register C_Op *t1;
X register char **wp;
X
X if (t == (C_Op *)NULL)
X return;
X
X/* type - TLIST - go down the left tree first and then processes this level */
X
X if (t->type == TLIST)
X {
X Print_Case (t->left);
X t1 = t->right;
X }
X
X else
X t1 = t;
X
X/* Output the conditions */
X
X Print_IString (null, 0);
X
X for (wp = t1->words; *wp != (char *)NULL;)
X {
X v1_puts (*(wp++));
X
X if (*wp != (char *)NULL)
X v1_puts (" | ");
X }
X
X v1a_puts (" )");
X Print_indent += 1;
X
X/* Output the commands */
X
X Print_ExTree (t1->left);
X Print_IString (";;\n", -1);
X}
X
X/*
X * Print an indented string
X */
X
Xstatic void Print_IString (cp, indent)
Xchar *cp;
Xint indent;
X{
X int i;
X
X if (indent < 0)
X Print_indent += indent;
X
X for (i = 0; i < (Print_indent / 2); i++)
X v1_putc ('\t');
X
X if (Print_indent % 2)
X v1_puts (" ");
X
X v1_puts (cp);
X
X if (indent > 0)
X Print_indent += indent;
X}
X
X/*
X * Look up a function in the save tree
X */
X
XFun_Ops *Fun_Search (name)
Xchar *name;
X{
X Fun_Ops *fp;
X
X for (fp = fun_list; fp != (Fun_Ops *)NULL; fp = fp->next)
X {
X if (strcmp (*(fp->tree->words), name) == 0)
X return fp;
X }
X
X return (Fun_Ops *)NULL;
X}
X
X/*
X * Save or delete a function tree
X */
X
Xvoid Save_Function (t, delete_only)
XC_Op *t;
Xbool delete_only; /* True - delete */
X{
X char *name = *t->words;
X register Fun_Ops *fp = Fun_Search (name);
X Fun_Ops *p_fp = (Fun_Ops *)NULL;
X
X/* Find the entry */
X
X for (fp = fun_list; (fp != (Fun_Ops *)NULL) &&
X (strcmp (*(fp->tree->words), name) != 0);
X p_fp = fp, fp = fp->next);
X
X/* If it already exists, free the tree and delete the entry */
X
X if (fp != (Fun_Ops *)NULL)
X {
X Set_Free_ExTree (fp->tree, Free_ExTree);
X
X if (p_fp == (Fun_Ops *)NULL)
X fun_list = fp->next;
X
X else
X p_fp->next = fp->next;
X
X DELETE (fp);
X }
X
X/* If delete only - exit */
X
X if (delete_only)
X return;
X
X/* Create new entry */
X
X if ((fp = (Fun_Ops *)space (sizeof (Fun_Ops))) == (Fun_Ops *)NULL)
X return;
X
X setarea ((char *)fp, 0);
X Set_Free_ExTree (t, Set_ExTree);
X
X fp->tree = t;
X fp->next = fun_list;
X fun_list = fp;
X}
X
X/*
X * Set ExTree areas to zero function
X */
X
Xstatic void Set_ExTree (s)
Xchar *s;
X{
X setarea (s, 0);
X}
X
X/*
X * Free the ExTree function
X */
X
Xstatic void Free_ExTree (s)
Xchar *s;
X{
X DELETE (s);
X}
X
X/*
X * Set/Free function tree area by recursively processing of tree
X */
X
Xstatic void Set_Free_ExTree (t, func)
XC_Op *t;
Xvoid (*func)(char *);
X{
X char **wp;
X
X if (t == (C_Op *)NULL)
X return;
X
X/* Check for start of print */
X
X if (t->type == TFUNC)
X {
X (*func)(*t->words);
X (*func)((char *)t->words);
X Set_Free_ExTree (t->left, func);
X }
X
X/* Otherwise, process the tree and print it */
X
X switch (t->type)
X {
X case TPAREN: /* () */
X case TCOM: /* A command process */
X Set_Free_Command (t, func);
X break;
X
X case TPIPE: /* Pipe processing */
X case TLIST: /* Entries in a for statement */
X case TOR: /* || and && */
X case TAND:
X case TWHILE: /* WHILE and UNTIL functions */
X case TUNTIL:
X Set_Free_ExTree (t->left, func);
X Set_Free_ExTree (t->right, func);
X break;
X
X case TFOR: /* First part of a for statement*/
X (*func)(t->str);
X
X if ((wp = t->words) != (char **)NULL)
X {
X while (*wp != (char *)NULL)
X (*func) (*wp++);
X
X (*func)((char *)t->words);
X }
X
X Set_Free_ExTree (t->left, func);
X break;
X
X case TIF: /* IF and ELSE IF functions */
X case TELIF:
X Set_Free_ExTree (t->right->left, func);
X Set_Free_ExTree (t->right->right, func);
X (*func)((char *)t->right);
X
X case TBRACE: /* {} statement */
X Set_Free_ExTree (t->left, func);
X break;
X
X case TCASE: /* CASE function */
X (*func)(t->str);
X Set_Free_Case (t->left, func);
X break;
X }
X
X (*func)((char *)t);
X}
X
X/*
X * Set/Free a command line
X */
X
Xstatic void Set_Free_Command (t, func)
XC_Op *t;
Xvoid (*func)(char *);
X{
X IO_Actions **iopp;
X char **wp = t->words;
X
X/* Parenthesis ? */
X
X if (t->type == TPAREN)
X Set_Free_ExTree (t->left, func);
X
X else
X {
X while (*wp != (char *)NULL)
X (*func)(*wp++);
X
X (*func) ((char *)t->words);
X }
X
X/* Process up any IO required */
X
X if ((iopp = t->ioact) != (IO_Actions **)NULL)
X {
X while (*iopp != (IO_Actions *)NULL)
X {
X (*func)((char *)(*iopp)->io_name);
X (*func)((char *)*iopp);
X iopp++;
X }
X
X (*func)((char *)t->ioact);
X }
X}
X
X/*
X * Set/Free the contents of a case statement
X */
X
Xstatic void Set_Free_Case (t, func)
XC_Op *t;
Xvoid (*func)(char *);
X{
X register C_Op *t1;
X register char **wp;
X
X if (t == (C_Op *)NULL)
X return;
X
X/* type - TLIST - go down the left tree first and then processes this level */
X
X if (t->type == TLIST)
X {
X Set_Free_Case (t->left, func);
X t1 = t->right;
X }
X
X else
X t1 = t;
X
X/* Set/Free the conditions */
X
X for (wp = t1->words; *wp != (char *)NULL;)
X (*func)(*(wp++));
X
X (*func)((char *)t1->words);
X
X Set_Free_ExTree (t1->left, func);
X}
SHAR_EOF
chmod 0644 shell/sh10.c || echo "restore of shell/sh10.c fails"
set `wc -c shell/sh10.c`;Sum=$1
if test "$Sum" != "10869"
then echo original size 10869, current size $Sum;fi
echo "x - extracting shell/sh0.asm (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh0.asm &&
X TITLE sh0.asm
X NAME sh0
X .8087
X
X; MS-DOS SHELL - Swapper
X;
X; MS-DOS SHELL - Copyright (c) 1989 Data Logic Limited.
X;
X; MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
X;
X; This code is subject to the following copyright restrictions:
X;
X; 1. Redistribution and use in source and binary forms are permitted
X; provided that the above copyright notice is duplicated in the
X; source form and the copyright notice in file sh6.c is displayed
X; on entry to the program.
X;
X; 2. The sources (or parts thereof) or objects generated from the sources
X; (or parts of sources) cannot be sold under any circumstances.
X;
X; $Header: sh0.asm 1.1 90/01/25 13:43:36 MS_user Exp $
X;
X; $Log: sh0.asm $
X; Revision 1.1 90/01/25 13:43:36 MS_user
X; Initial revision
X;
X;
X
X;
X; Segment declarations
X;
X
XSH0_TEXT segment word public 'CODE'
XSH0_TEXT ends
X
X_DATA segment word public 'DATA'
X_DATA ends
X
XCONST segment word public 'CONST'
XCONST ends
X
X_BSS segment word public 'BSS'
X_BSS ends
X
XDGROUP group CONST, _BSS, _DATA
X
X;
X; Declare external functions and data
X;
X extrn _raise:far
X extrn __maperror:far
X extrn _errno:word
X extrn __psp:word
X
X;
X; Start of the spawn function
X;
X
XSH0_TEXT segment
X assume cs: SH0_TEXT, ds: NOTHING, ss: DGROUP
X
X;
X; For this function, all the code and data space are in the code space
X;
X public _cmd_line
X public _path_line
X public _SW_intr
X public _SW_Blocks
X public _SW_fp
X public _SW_I0_V_BX
X public _SW_I0_V_ES
X public _SW_I23_V_ES
X public _SW_I23_V_BX
X public _SW_EMstart
X public _SW_Mode
X public _SW_EMSFrame
X
X_cmd_line db 129 dup (?) ; Command line
X_path_line db 80 dup (?) ; Path line
X_SW_Blocks dw 0 ; Number of blocks to read/write
X_SW_fp dw 0 ; File ID
X_SW_I23_V_ES dw 0 ; Interrupt 23 address
X_SW_I23_V_BX dw 0
X_SW_I0_V_BX dw 0 ; Our Interrupt zero value
X_SW_I0_V_ES dw 0
X_SW_EMstart dd 0100000H ; Default Extended Mem start
X_SW_Mode dw 0 ; Type of swapping to do
X ; 1 - disk
X ; 2 - Extended memory
X ; 3 - Expanded memory
X_SW_EMSFrame dw 0 ; EMS Frame segment
X_SW_intr dw 0 ; Interrupt 23 detected.
X
X
X;
X; Some addition variables
X;
X
XSW_LMstart dd 0 ; Low Mem start for Extended Mem swap
XN_mcb dw 0 ; Start write address
XResult dw 0 ; Return value
XInShell db 0 ; In shell flag for Interrupt 23
X
X;
X; Stack save pointers
X;
X
XS_ss dw 0 ; Save Stack pointers
XS_sp dw 0
XS_di dw 0 ; Save DI, SI
XS_si dw 0
XS_ds dw 0 ; Save the original DS
X
X;
X; Two blank FCB
X;
X
XFCB1 dw 16 dup (?)
XFCB2 dw 16 dup (?)
X
X;
X; Extended Memory Global Descriptor tables
X;
X
XGD_table equ $
XGDT_Dummy dw 4 dup (0) ; Dummy
XGDT_self dw 4 dup (0) ; For self
XGDT_src equ $ ; Source
X dw 04000H ; Length - 16K bytes
XGDT_src_low dw 0 ; Low Order address
XGDT_src_high db 0 ; High Order address
X db 093h ; Access Rights
X dw 0 ; Reserved
XGDT_dest equ $ ; Destination
X dw 04000H ; Length - 16K bytes
XGDT_dest_low dw 0 ; Low Order address
XGDT_dest_high db 0 ; High Order address
X db 093h ; Access Rights
X dw 0 ; Reserved
XGDT_bios dw 4 dup (0) ; Bios
XGDT_stack dw 4 dup (0) ; Stack
X
X;
X; Execute interrupt structure
X;
X
Xexec_parms equ $
Xexec_env dw 0
X dw offset _cmd_line ; Command line address
Xexec_cseg dw ?
X dw offset FCB1 ; FCB1 address
Xexec_f1seg dw ?
X dw offset FCB2 ; FCB1 address
Xexec_f2seg dw ?
X
XSwap_PANIC db 'PANIC: Swap file re-load error - REBOOT', 0aH, 0dH
X db '$'
X
XSwap_DZERO db 'PANIC: Divide by zero', 0aH, 0dH
X db '$'
X
X;
X; OK - exec requires a local stack, cause some programs overwrite it
X;
X even
X db 398 dup (0)
XLocal_Stack:
X dw 0
X
X;
X; Code starts
X;
X public _SA_spawn
X
X_SA_spawn proc far
X
X push bp
X mov bp, sp
X
X;
X; Entry Offsets
X;
X; Environment = 6
X;
X
X mov word ptr cs:S_di, di ; Save registers
X mov word ptr cs:S_si, si
X mov word ptr cs:S_ds, ds
X
X;
X; Set up to ingnore Control C interrupts
X;
X
X push ds
X mov ax, 02523H ; Set Control C Interrupt
X mov dx, offset SA_IRET
X push cs
X pop ds
X mov byte ptr cs:InShell, 0 ; Set In shell flag for Interrupt 23
X int 021H
X
X mov ax, 02500H ; Set Divide Zero Interrupt
X mov dx, offset SA_DZERO
X push cs
X pop ds
X int 021H
X
X pop ds
X
X;
X; Save the length of the current MCB block;
X;
X
X mov ax, word ptr ds:__psp
X dec ax
X mov word ptr cs:N_mcb, ax ; Save MCB address for swap out
X
X; Calculate low mem start for extended memory
X
X mov bx, ax ; Save copy
X mov cl, 4 ; mult low order by 16
X shl ax, cl
X mov word ptr cs:SW_LMstart, ax ; Save low order
X mov cl, 12 ; div by 16 ** 3
X shr bx, cl
X mov byte ptr cs:SW_LMstart + 2, bl ; Save low order
X
X;
X; Set up Environment segment in execute structure
X;
X
X mov bx, cs
X mov ax, offset Env_OWrite
X mov cl, 4
X shr ax, cl
X add ax, bx
X mov word ptr cs:exec_env, ax ; Save Env seg.
X
X;
X; Set up rest of execute structure
X;
X
X mov word ptr cs:exec_cseg, cs ; Command line address
X mov word ptr cs:exec_f1seg, cs ; FCB 1 address
X mov word ptr cs:exec_f2seg, cs ; FCB 2 address
X
X;
X; Generate the FCBs
X;
X
X mov ax, cs ; Set up segments
X mov ds, ax
X mov es, ax
X
X mov ax, 02901H ; Set up FCB interrupt
X mov si, offset _cmd_line + 1
X mov di, offset FCB1 ; FCB 1;
X
X int 021H ; Execute the interrupt
X
X mov ax, cs ; Set up segment
X mov es, ax
X
X mov ax, 02901H ; Reset AX cause errors are ignored
X mov di, offset FCB2 ; FCB 2;
X
X int 021H ; Execute the interrupt
X
X;
X; Copy out to the swap file
X;
X
X mov si, word ptr cs:_SW_Blocks ; Load Number of blocks to read
X mov bx, word ptr cs:_SW_fp ; Load file handler
X
X; load up extended memory GDT for destination
X
X mov ax, word ptr cs:_SW_EMstart
X mov dl, byte ptr cs:_SW_EMstart + 2
X call $GDT_dest_load
X
X;
X; set up DS register with start of start copy
X;
X
X mov ax, word ptr cs:N_mcb ; Load the start address
X mov ds, ax
X
X mov ax, word ptr cs:SW_LMstart ; Load Full start address
X mov dl, byte ptr cs:SW_LMstart + 2
SHAR_EOF
echo "End of part 4"
echo "File shell/sh0.asm is continued in part 5"
echo "5" > s2_seq_.tmp
exit 0
--
Regards,
Ian Stewartson
Data Logic Ltd.