istewart@datlog.co.uk (Ian Stewartson) (02/14/90)
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.