istewart@datlog.co.uk (Ian Stewartson) (02/14/90)
Posting-number: Volume 10, Issue 56 Submitted-by: istewart@datlog.co.uk (Ian Stewartson) Archive-name: sh_dos/part04 #!/bin/sh # this is part 3 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file shell/sh2.c continued # CurArch=3 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/sh2.c" sed 's/^X//' << 'SHAR_EOF' >> shell/sh2.c X { X if (iolist == (Word_B *)NULL) X return (C_Op *)NULL; X X (t = (C_Op *)tree (sizeof (C_Op)))->type = TCOM; X } X X break; X X case '(': X t = nested (TPAREN, ')'); X break; X X case '{': X t = nested (TBRACE, '}'); X break; X X case FOR: X (t = (C_Op *)tree (sizeof (C_Op)))->type = TFOR; X musthave (WORD, 0); X startl = TRUE; X t->str = yylval.cp; X multiline++; X t->words = wordlist (); X X if (((c = yylex (0)) != NL) && (c != ';')) X yyerror (syntax_err); X X t->left = dogroup (0); X multiline--; X break; X X case WHILE: X case UNTIL: X multiline++; X t = (C_Op *)tree (sizeof (C_Op)); X t->type = (c == WHILE) ? TWHILE : TUNTIL; X t->left = c_list (FALSE); X t->right = dogroup (1); X t->words = NULL; X multiline--; X break; X X case CASE: X (t = (C_Op *)tree (sizeof (C_Op)))->type = TCASE; X musthave (WORD, 0); X t->str = yylval.cp; X startl = TRUE; X multiline++; X musthave (IN, CONTIN); X startl = TRUE; X t->left = caselist(); X musthave (ESAC, 0); X multiline--; X break; X X case IF: X multiline++; X (t = (C_Op *)tree (sizeof (C_Op)))->type = TIF; X t->left = c_list (FALSE); X t->right = thenpart (); X musthave (FI, 0); X multiline--; X break; X } X X while (synio (0)) X ; X X t = namelist (t); X iolist = iosave; X return t; X} X Xstatic C_Op *dogroup (onlydone) Xint onlydone; X{ X register int c; X register C_Op *list; X X if (((c = yylex (CONTIN)) == DONE) && onlydone) X return (C_Op *)NULL; X X if (c != DO) X yyerror (syntax_err); X X list = c_list (FALSE); X musthave (DONE, 0); X return list; X} X Xstatic C_Op *thenpart () X{ X register int c; X register C_Op *t; X X if ((c = yylex (0)) != THEN) X { X peeksym = c; X return (C_Op *)NULL; X } X X (t = (C_Op *)tree (sizeof (C_Op)))->type = 0; X X if ((t->left = c_list (FALSE)) == (C_Op *)NULL) X yyerror (syntax_err); X X t->right = elsepart (); X return t; X} X Xstatic C_Op *elsepart () X{ X register int c; X register C_Op *t; X X switch (c = yylex (0)) X { X case ELSE: X if ((t = c_list (FALSE)) == (C_Op *)NULL) X yyerror (syntax_err); X X return t; X X case ELIF: X (t = (C_Op *)tree (sizeof (C_Op)))->type = TELIF; X t->left = c_list (FALSE); X t->right = thenpart (); X return t; X X default: X peeksym = c; X return (C_Op *)NULL; X } X} X Xstatic C_Op *caselist() X{ X register C_Op *t = (C_Op *)NULL; X X while ((peeksym = yylex (CONTIN)) != ESAC) X t = list (t, casepart ()); X X return t; X} X Xstatic C_Op *casepart () X{ X register C_Op *t = (C_Op *)tree (sizeof (C_Op)); X X t->type = TPAT; X t->words = pattern (); X musthave (')', 0); X t->left = c_list (FALSE); X X if ((peeksym = yylex (CONTIN)) != ESAC) X musthave (BREAK, CONTIN); X X return t; X} X Xstatic char **pattern() X{ X register int c, cf; X X cf = CONTIN; X X do X { X musthave (WORD, cf); X word (yylval.cp); X cf = 0; X } while ((c = yylex(0)) == '|'); X X peeksym = c; X word (NOWORD); X return copyw(); X} X Xstatic char **wordlist() X{ X register int c; X X if ((c = yylex(0)) != IN) X { X peeksym = c; X return (char **)NULL; X } X X startl = FALSE; X while ((c = yylex (0)) == WORD) X word (yylval.cp); X X word (NOWORD); X peeksym = c; X X return copyw(); X} X X/* X * supporting functions X */ X Xstatic C_Op *list (t1, t2) Xregister C_Op *t1, *t2; X{ X if (t1 == (C_Op *)NULL) X return t2; X X if (t2 == (C_Op *)NULL) X return t1; X X return block (TLIST, t1, t2, NOWORDS); X} X Xstatic C_Op *block (type, t1, t2, wp) XC_Op *t1, *t2; Xchar **wp; X{ X register C_Op *t = (C_Op *)tree (sizeof (C_Op)); X X t->type = type; X t->left = t1; X t->right = t2; X t->words = wp; X return t; X} X Xstatic struct res { X char *r_name; X int r_val; X} restab[] = { X { "for", FOR}, {"case", CASE}, X {"esac", ESAC}, {"while", WHILE}, X {"do", DO}, {"done", DONE}, X {"if", IF}, {"in", IN}, X {"then", THEN}, {"else", ELSE}, X {"elif", ELIF}, {"until", UNTIL}, X {"fi", FI}, X X {";;", BREAK}, {"||", LOGOR}, X {"&&", LOGAND}, {"{", '{'}, X {"}", '}'}, X X {(char *)NULL, 0} X}; X Xstatic int rlookup (n) Xregister char *n; X{ X register struct res *rp = restab; X X while ((rp->r_name != (char *)NULL) && strcmp (rp->r_name, n)) X rp++; X X return rp->r_val; X} X Xstatic C_Op *namelist(t) Xregister C_Op *t; X{ X if (iolist) X { X iolist = addword ((char *)NULL, iolist); X t->ioact = copyio (); X } X X else X t->ioact = (IO_Actions **)NULL; X X if ((t->type != TCOM) && (t->type != TFUNC)) X { X if ((t->type != TPAREN) && (t->ioact != (IO_Actions **)NULL)) X { X t = block (TPAREN, t, NOBLOCK, NOWORDS); X t->ioact = t->left->ioact; X t->left->ioact = (IO_Actions **)NULL; X } X } X X else X { X word (NOWORD); X t->words = copyw(); X } X X return t; X} X Xstatic char **copyw () X{ X register char **wd = getwords (wdlist); X X wdlist = (Word_B *)NULL; X return wd; X} X Xstatic void word (cp) Xchar *cp; X{ X wdlist = addword (cp, wdlist); X} X Xstatic IO_Actions **copyio () X{ X IO_Actions **iop = (IO_Actions **)getwords (iolist); X X iolist = (Word_B *)NULL; X return iop; X} X Xstatic IO_Actions *io (u, f, cp) Xint f, u; Xchar *cp; X{ X register IO_Actions *iop = (IO_Actions *)tree (sizeof (IO_Actions)); X X iop->io_unit = u; X iop->io_flag = f; X iop->io_name = cp; X iolist = addword ((char *)iop, iolist); X return iop; X} X Xstatic void yyerror (s) Xchar *s; X{ X yynerrs++; X X if (talking && e.iop <= iostack) X { X multiline = 0; X X while ((eofc () == 0) && (yylex (0) != NL)) X ; X } X X print_error (s); X fail (); X} X Xstatic int yylex (cf) Xint cf; X{ X register int c, c1; X bool atstart; X X if ((c = peeksym) > 0) X { X peeksym = 0; X X if (c == NL) X startl = TRUE; X X return c; X } X X e.linep = e.cline; X atstart = startl; X startl = FALSE; X yylval.i = 0; X Xloop: X while ((c = Getc (0)) == SP || c == '\t') X ; X X switch (c) X { X default: X if (isdigit (c)) X { X unget (c1 = Getc(0)); X X if ((c1 == '<') || (c1 == '>')) X { X iounit = c - '0'; X goto loop; X } X X *e.linep++ = (char)c; X c = c1; X } X X break; X X case '#': X while ((c = Getc(0)) != 0 && (c != NL)) X ; X X unget(c); X goto loop; X X case 0: X return c; X X case '$': X *e.linep++ = (char)c; X X if ((c = Getc(0)) == '{') X { X if ((c = collect (c, '}')) != '\0') X return (c); X X goto pack; X } X X break; X X case '`': X case '\'': X case '"': X if ((c = collect (c, c)) != '\0') X return c; X X goto pack; X X case '|': X case '&': X case ';': X if ((c1 = dual (c)) != '\0') X { X startl = TRUE; X return c1; X } X X case '(': X case ')': X startl = TRUE; X return c; X X case '^': X startl = TRUE; X return '|'; X X case '>': X case '<': X diag (c); X return c; X X case NL: X gethere (); X startl = TRUE; X X if (multiline || (cf & CONTIN)) X { X if (talking && e.iop <= iostack) X { X Add_History (FALSE); X put_prompt (ps2->value); X } X X if (cf & CONTIN) X goto loop; X } X X return(c); X } X X unget (c); X Xpack: X while (((c = Getc (0)) != 0) && (!any ((char)c, "`$ '\"\t;&<>()|^\n"))) X { X if (e.linep >= e.eline) X print_error ("sh: word too long\n"); X X else X *e.linep++ = (char)c; X } X X unget (c); X X if (any ((char)c, spcl2)) X goto loop; X X *e.linep++ = '\0'; X X if (atstart && (c = rlookup (e.cline)) != 0) X { X startl = TRUE; X return c; X } X X yylval.cp = strsave (e.cline, areanum); X return WORD; X} X Xstatic int collect (c, c1) Xregister int c, c1; X{ X char *s = "x\n"; X X *e.linep++ = (char)c; X X while ((c = Getc (c1)) != c1) X { X if (c == 0) X { X unget (c); X *s = (char)c1; X S_puts ("sh: no closing "); X yyerror (s); X return YYERRCODE; X } X X if (talking && (c == NL) && (e.iop <= iostack)) X { X Add_History (FALSE); X put_prompt (ps2->value); X } X X *e.linep++ = (char)c; X } X X *e.linep++ = (char)c; X return 0; X} X X/* Check for &&, || and ;; */ X Xstatic int dual (c) Xregister int c; X{ X char s[3]; X register char *cp = s; X X/* Get the next character and set up double string. Look up in valid X * operators. If invalid, unget character X */ X X *cp++ = (char)c; X *cp++ = (char)Getc (0); X *cp = 0; X X if ((c = rlookup (s)) == 0) X unget (*--cp); X X return c; X} X X/* Process I/O re-direction */ X Xstatic void diag (ec) Xregister int ec; X{ X register int c; X X if (((c = Getc (0)) == '>') || (c == '<')) X { X if (c != ec) X yyerror (syntax_err); X X yylval.i = (ec == '>') ? IOWRITE | IOCAT : IOHERE; X c = Getc(0); X } X X else X yylval.i = (ec == '>') ? IOWRITE : IOREAD; X X if ((c != '&') || (yylval.i == IOHERE)) X unget (c); X X else X yylval.i |= IODUP; X} X X/* Get a new tree leaf structure */ X Xstatic char *tree (size) Xunsigned int size; X{ X register char *t; X X if ((t = getcell (size)) == (char *)NULL) X { X S_puts ("sh: command line too complicated\n"); X fail (); X } X X return t; X} SHAR_EOF echo "File shell/sh2.c is complete" chmod 0644 shell/sh2.c || echo "restore of shell/sh2.c fails" set `wc -c shell/sh2.c`;Sum=$1 if test "$Sum" != "15090" then echo original size 15090, current size $Sum;fi echo "x - extracting shell/sh3.c (Text)" sed 's/^X//' << 'SHAR_EOF' > shell/sh3.c && X/* MS-DOS SHELL - Parse Tree Executor 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: sh3.c 1.1 90/01/25 13:41:24 MS_user Exp $ X * X * $Log: sh3.c $ X * Revision 1.1 90/01/25 13:41:24 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 X#include "sh.h" X X/* static Function and string declarations */ X Xstatic int forkexec (C_Op *, int, int, int, char **); Xstatic bool iosetup (IO_Actions *, int, int); Xstatic C_Op **find1case (C_Op *, char *); Xstatic C_Op *findcase (C_Op *, char *); Xstatic void echo (char **); Xstatic void setsig (int, int (*)()); Xstatic int rexecve (char *, char **, char **, bool); Xstatic int Execute_program (char *, char **, char **, bool); Xstatic int S_spawnve (char *, char **, char **); Xstatic void get_sys_info (void); Xstatic void EMS_error (char *, int); Xstatic int EMS_Close (void); Xstatic int build_command_line (char *, char **, char **); Xstatic void Clear_Extended_File (void); Xstatic int setstatus (int); X Xstatic char *AE2big = "arg/env list too big"; Xstatic char *EMS_emsg = "Warning: EMS Error (%x)\n"; X /* Extended Command line processing file name */ Xstatic char *Extend_file = (char *)NULL; Xstatic unsigned int SW_EMsize; /* Number of extend memory blks */ X X/* X * execute tree recursively X */ X Xint execute (t, pin, pout, act) Xregister C_Op *t; Xint pin; Xint pout; Xint act; X{ X register C_Op *t1; X int i, localpipe; X char *cp, **wp; X char **Local_Tword; X Var_List *vp; X Break_C bc; X Break_C *S_RList; /* Save link pointers */ X Break_C *S_BList; X Break_C *S_SList; X int Local_depth; /* Save local values */ X int Local_areanum; X int rv = 0; X X/* End of tree ? */ X X if (t == (C_Op *)NULL) X return 0; X X/* Save original and Increment execute function recursive level */ X X Local_depth = Execute_stack_depth++; X X/* Save original and increment area number */ X X Local_areanum = areanum++; X X/* Save the exit points from SubShells, functions and for/whiles */ X X S_RList = Return_List; X S_BList = Break_List; X S_SList = SShell_List; X X/* Expand any arguments */ X X wp = (Local_Tword = t->words) != (char **)NULL X ? eval (Local_Tword, (t->type == TCOM) ? DOALL : DOALL & ~DOKEY) X : (char **)NULL; X X/* Switch on tree node type */ X X switch (t->type) X { X case TFUNC: /* name () { list; } */ X Save_Function (t, FALSE); X break; X X/* In the case of a () command string, we need to save and restore the X * current environment, directory and traps (can't think of anything else). X * For any other, we just restore the current directory. Also, we don't X * want changes in the Variable list header saved for SubShells, because X * we are effectively back at execute depth zero. X */ X case TPAREN: /* () */ X if ((rv = Create_NG_VL ()) == -1) X break; X X if (setjmp (bc.brkpt) == 0) X { X Return_List = (Break_C *)NULL; X Break_List = (Break_C *)NULL; X bc.nextlev = SShell_List; X SShell_List = &bc; X rv = forkexec (t, pin, pout, act, wp); X } X X/* Restore the original environment */ X X Return_List = S_RList; X Break_List = S_BList; X SShell_List = S_SList; X Restore_Environment (rv, Local_depth); X break; X X/* After a normal command, we need to restore the original directory. Note X * that a cd will have updated the variable $~, so no problem X */ X X case TCOM: /* A command process */ X rv = forkexec (t, pin, pout, act, wp); X Restore_Dir (); X break; X X case TPIPE: /* Pipe processing */ X if ((rv = openpipe ()) < 0) X break; X X/* Create pipe, execute command, reset pipe, execute the other side, close X * the pipe and fini X */ X X localpipe = remap (rv); X execute (t->left, pin, localpipe, 0); X lseek (localpipe, 0L, SEEK_SET); X rv = execute (t->right, localpipe, pout, 0); X closepipe (localpipe); X break; X X case TLIST: /* Entries in a for statement */ X execute (t->left, pin, pout, 0); X rv = execute (t->right, pin, pout, 0); X break; X X case TASYNC: /* Async - not supported */ X rv = -1; X S_puts ("sh: Async commands not supported\n"); X setstatus (rv); X break; X X case TOR: /* || and && */ X case TAND: X rv = execute (t->left, pin, pout, 0); X X if (((t1 = t->right) != (C_Op *)NULL) && X ((rv == 0) == (t->type == TAND))) X rv = execute (t1, pin, pout, 0); X X break; X X case TFOR: /* First part of a for statement*/ X X/* for x do...done - use the parameter values. Need to know how many as X * it is not a NULL terminated array X */ X X if (wp == (char **)NULL) X { X wp = dolv + 1; X X if ((i = dolc) < 0) X i = 0; X } X X/* for x in y do...done - find the start of the variables and use them all */ X X else X { X i = -1; X while (*wp++ != (char *)NULL) X ; X } X X/* Create the loop variable. */ X X vp = lookup (t->str, TRUE); X X/* Set up a long jump return point before executing the for function so that X * the continue statement is executed, ie we reprocessor the for condition. X */ X X while (rv = setjmp (bc.brkpt)) X { X X/* Restore the current stack level and clear out any I/O */ X X Restore_Environment (0, Local_depth + 1); X Return_List = S_RList; X SShell_List = S_SList; X X/* If this is a break - clear the variable and terminate the while loop and X * switch statement X */ X X if (rv == BC_BREAK) X break; X } X X if (rv == BC_BREAK) X break; X X/* Process the next entry - Add to the break/continue chain */ X X bc.nextlev = Break_List; X Break_List = &bc; X X/* Execute the command tree */ X X for (t1 = t->left; i-- && *wp != NULL;) X { X setval (vp, *wp++); X rv = execute (t1, pin, pout, 0); X } X X/* Remove this tree from the break list */ X X Break_List = S_BList; X break; X X/* While and Until function. Similar to the For function. Set up a X * long jump return point before executing the while function so that X * the continue statement is executed OK. X */ X X case TWHILE: /* WHILE and UNTIL functions */ X case TUNTIL: X while (rv = setjmp (bc.brkpt)) X { X X/* Restore the current stack level and clear out any I/O */ X X Restore_Environment (0, Local_depth + 1); X Return_List = S_RList; X SShell_List = S_SList; X X/* If this is a break, terminate the while and switch statements */ X X if (rv == BC_BREAK) X break; X } X X if (rv == BC_BREAK) X break; X X/* Set up links */ X X bc.nextlev = Break_List; X Break_List = &bc; X t1 = t->left; X X while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) X rv = execute (t->right, pin, pout, 0); X X Break_List = S_BList; X break; X X case TIF: /* IF and ELSE IF functions */ X case TELIF: X rv = !execute (t->left, pin, pout, 0) X ? execute (t->right->left, pin, pout, 0) X : execute (t->right->right, pin, pout, 0); X break; X X case TCASE: /* CASE function */ X if ((cp = evalstr (t->str, DOSUB | DOTRIM)) == (char *)NULL) X cp = null; X X if ((t1 = findcase (t->left, cp)) != (C_Op *)NULL) X rv = execute (t1, pin, pout, 0); X X break; X X case TBRACE: /* {} statement */ X if ((rv >= 0) && ((t1 = t->left) != (C_Op *)NULL)) X rv = execute (t1, pin, pout, 0); X X break; X } X X/* Processing Completed - Restore environment */ X X t->words = Local_Tword; X Execute_stack_depth = Local_depth; X X/* Remove unwanted malloced space */ X X freehere (areanum); X freearea (areanum); X X areanum = Local_areanum; X X/* Check for interrupts */ X X if (talking && SW_intr) X { X closeall (); X fail (); X } X X/* Check for traps */ X X if ((i = trapset) != 0) X { X trapset = 0; X runtrap (i); X } X X return rv; X} X X/* X * Restore the original directory X */ X Xvoid Restore_Dir () X{ X unsigned int dummy; X X _dos_setdrive (tolower(*C_dir->value) - 'a' + 1, &dummy); X X if (chdir (&C_dir->value[2]) != 0) X { X S_puts ("Warning: current directory reset to /\n"); X chdir ("/"); X Getcwd (); X } X} X X/* X * Ok - execute the program, resetting any I/O required X */ X Xstatic int forkexec (t, pin, pout, act, wp) Xregister C_Op *t; Xint pin; Xint pout; Xint act; Xchar **wp; X{ X int rv = -1; X int (*shcom)(C_Op *) = (int (*)())NULL; X char *cp; X IO_Actions **iopp; X int resetsig = 0; X char **owp = wp; X bool spawn = FALSE; X Fun_Ops *fop; 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 (FL_TEST ('x')) X echo (cp != (char *)NULL ? wp : owp); X X/* Is it only an assignement? */ X X if ((cp == (char *)NULL) && (t->ioact == (IO_Actions **)NULL)) X { X while (((cp = *owp++) != (char *)NULL) && assign (cp, COPYV)) X ; X X return setstatus (0); X } X X/* Check for built in commands */ X X else if (cp != (char *)NULL) X shcom = inbuilt (cp); X } X X/* Unix fork simulation? */ X X t->words = wp; X if (shcom == NULL && (act & FEXEC) == 0) X { X spawn = TRUE; X X if (talking) X { X#ifdef SIGQUIT X signal (SIGQUIT, SIG_IGN); X#endif X signal (SIGINT, SIG_IGN); X resetsig = 1; X } X } X X/* Set any variables */ X X while (((cp = *owp++) != (char *)NULL) && assign (cp, COPYV)) X { X if (shcom == NULL) X s_vstatus (lookup (cp, TRUE), EXPORT); X } X X/* We cannot close the pipe, because once the exec/spawn has taken place X * the processing of the pipe is not yet complete. X */ X X if (pin != NOPIPE) X { X S_dup2 (pin, STDIN_FILENO); X lseek (STDIN_FILENO, 0L, SEEK_SET); X } X X if (pout != NOPIPE) X { X S_dup2 (pout, STDOUT_FILENO); X lseek (STDOUT_FILENO, 0L, SEEK_END); X } X X/* Set up any other IO required */ X X if ((iopp = t->ioact) != (IO_Actions **)NULL) X { X while (*iopp != (IO_Actions *)NULL) X { X if (iosetup (*iopp++, pin, pout)) X return rv; X } X } X X if (shcom) X return restore_std (setstatus ((*shcom)(t))); X X/* All fids above 10 are autoclosed in the exec file because we have used X * the O_NOINHERIT flag. Note I patched open.obj to pass this flag to the X * open function. X */ X X if (resetsig) X { X#ifdef SIGQUIT X signal (SIGQUIT, SIG_IGN); X#endif X signal (SIGINT, onintr); X } X X if (t->type == TPAREN) X return restore_std (execute (t->left, NOPIPE, NOPIPE, FEXEC)); X X/* Are we just changing the I/O re-direction for the shell ? */ X X if (wp[0] == NULL) X { X if (spawn) X restore_std (0); X X return 0; X } X X/* No - Check for a function the program. At this point, we need to put X * in some processing for return. X */ X X if ((fop = Fun_Search (wp[0])) != (Fun_Ops *)NULL) X { X char **s_dolv = dolv; X int s_dolc = dolc; X Break_C *s_RList = Return_List; X Break_C *s_BList = Break_List; X Break_C *s_SList = SShell_List; X int LS_depth = Execute_stack_depth; X Break_C bc; X X/* Set up $0..$n for the function */ X X dolv = wp; X for (dolc = 0; dolv[dolc] != (char *)NULL; ++dolc); X setval (lookup ("#", TRUE), putn (dolc)); X X if (setjmp (bc.brkpt) == 0) X { X Break_List = (Break_C *)NULL; X bc.nextlev = Return_List; X Return_List = &bc; X rv = execute (fop->tree->left, NOPIPE, NOPIPE, FEXEC); X } X X/* A return has been executed - Unlike, while and for, we just need to X * restore the local execute stack level and the return will restore X * the correct I/O. X */ X X else X rv = getn (lookup ("?", FALSE)->value); X X/* Restore the old $0, and previous return address */ X X Break_List = s_BList; X Return_List = s_RList; X SShell_List = s_SList; X dolv = s_dolv; X dolc = s_dolc; X Restore_Environment (rv, LS_depth); X setval (lookup ("#", TRUE), putn (dolc)); X return rv; X } X X/* Ok - execute the program */ X X return restore_std (rexecve (wp[0], wp, makenv (), spawn)); X} X X/* X * Restore Local Environment X */ X Xvoid Restore_Environment (retval, stack) Xint retval; Xint stack; X{ X Execute_stack_depth = stack; X Delete_G_VL (); X Restore_Dir (); X restore_std (setstatus (retval)); X} X X/* X * Set up I/O redirection. 0< 1> are ignored as required within pipelines. X */ X Xstatic bool iosetup (iop, pipein, pipeout) Xregister IO_Actions *iop; Xint pipein; Xint pipeout; X{ X register int u; X char *cp, *msg; X X if (iop->io_unit == IODEFAULT) /* take default */ X iop->io_unit = (iop->io_flag & (IOREAD | IOHERE)) ? STDIN_FILENO X : STDOUT_FILENO; X X/* Check for pipes */ X X if ((pipein != NOPIPE) && (iop->io_unit == STDIN_FILENO)) X return FALSE; X X if ((pipeout != NOPIPE) && (iop->io_unit == STDOUT_FILENO)) X return FALSE; X X msg = (iop->io_flag & (IOREAD | IOHERE)) ? "open" : "create"; X X if ((iop->io_flag & IOHERE) == 0) X { X if ((cp = evalstr (iop->io_name, DOSUB | DOTRIM)) == (char *)NULL) X return TRUE; X } X X if (iop->io_flag & IODUP) X { X if ((cp[1]) || !isdigit (*cp) && *cp != '-') X { X print_error ("%s: illegal >& argument\n", cp); X return TRUE; X } X X if (*cp == '-') X iop->io_flag = IOCLOSE; X X iop->io_flag &= ~(IOREAD | IOWRITE); X } X X/* Open the file in the appropriate mode */ X X switch (iop->io_flag) X { X case IOREAD: /* < */ X u = S_open (FALSE, cp, O_RDONLY); X break; X X case IOHERE: /* << */ X case IOHERE | IOXHERE: X u = herein (iop->io_name, iop->io_flag & IOXHERE); X cp = "here file"; X break; X X case IOWRITE | IOCAT: /* >> */ X if (check_rsh (cp)) X return TRUE; X X if ((u = S_open (FALSE, cp, O_WRONLY | O_TEXT)) >= 0) X { X lseek (u, 0L, SEEK_END); X break; X } X X case IOWRITE: /* > */ X if (check_rsh (cp)) X return TRUE; X X u = S_open (FALSE, cp, O_CMASK, 0666); X break; X X case IODUP: /* >& */ X if (check_rsh (cp)) X return TRUE; X X u = S_dup2 (*cp - '0', iop->io_unit); X break; X X case IOCLOSE: /* >- */ X if ((iop->io_unit >= STDIN_FILENO) && X (iop->io_unit <= STDERR_FILENO)) X S_dup2 (-1, iop->io_unit); X X S_close (iop->io_unit, TRUE); X return FALSE; X } X X if (u < 0) X { X print_warn ("%s: cannot %s\n", cp, msg); X return TRUE; X } X X else if (u != iop->io_unit) X { X S_dup2 (u, iop->io_unit); X S_close (u, TRUE); X } X X return FALSE; X} X X/* X * -x flag - echo command to be executed X */ X Xstatic void echo (wp) Xregister char **wp; X{ X register int i; X X S_putc ('+'); X X for (i = 0; wp[i] != (char *)NULL; i++) X { X S_putc (SP); X S_puts (wp[i]); X } X X S_putc (NL); X} X Xstatic C_Op **find1case (t, w) XC_Op *t; Xchar *w; X{ X register C_Op *t1; X C_Op **tp; X register char **wp, *cp; X X if (t == (C_Op *)NULL) X return (C_Op **)NULL; X X if (t->type == TLIST) X { X if ((tp = find1case (t->left, w)) != (C_Op *)NULL) X return tp; X X t1 = t->right; /* TPAT */ X } X X else X t1 = t; X X for (wp = t1->words; *wp != (char *)NULL;) X { X if ((cp = evalstr (*(wp++), DOSUB)) && gmatch (w, cp, FALSE)) X return &t1->left; X } X X return (C_Op **)NULL; X} X Xstatic C_Op *findcase (t, w) XC_Op *t; Xchar *w; X{ X register C_Op **tp; X X return ((tp = find1case (t, w)) != (C_Op **)NULL) ? *tp : (C_Op *)NULL; X} X X/* X * Set up the status on exit from a command X */ X Xstatic int setstatus (s) Xregister int s; X{ X exstat = s; X setval (lookup ("?", TRUE), putn (s)); X return s; X} X X/* X * PATH-searching interface to execve. If getenv ("PATH") were kept X * up-to-date, execvp might be used. X */ X Xstatic int rexecve (c, v, envp, d_flag) Xchar *c; Xchar **v; Xchar **envp; Xbool d_flag; X{ X register char *sp; X int res; X char *em; X bool eloop; X X/* If the environment is null - It is too big - error */ X X if (envp == (char **)NULL) X em = AE2big; X X else X { X sp = any ('/', c) ? null : path->value; X X do X { X sp = path_append (sp, c, e.linep); X X if ((res = Execute_program (e.linep, v, envp, d_flag)) != -1) X return res; X X eloop = TRUE; X X switch (errno) X { X X/* No entry for the file - if the file exists, execute it as a shell X * script X */ X case ENOENT: X if ((res = O_for_execute (e.linep)) >= 0) X { X S_close (res, TRUE); X *v = e.linep; X em = *--v; X *v = e.linep; X res = Execute_program (lookup (shell, FALSE)->value, X v, envp, d_flag); X *v = em; X X if (res != -1) X return res; X X em = "no Shell"; X } X X else X em = "not found"; X X eloop = FALSE; X break; X X case ENOEXEC: X em = "program corrupt"; X break; X X case ENOMEM: X em = "program too big"; X break; X X case E2BIG: X em = AE2big; X break; X X default: X em = "cannot execute"; X eloop = FALSE; X break; X } X } while ((sp != (char *)NULL) && !eloop); X } X X print_warn ("%s: %s\n", c, em); X X if (!d_flag) X exit (-1); X X return -1; X} X X/* X * Run the command produced by generator `f' applied to stream `arg'. X */ X Xint run (argp, f) XIO_Args *argp; Xint (*f)(IO_State *); X{ X Word_B *swdlist = wdlist; X Word_B *siolist = iolist; X jmp_buf ev, rt; X int *ofail = failpt; X int rv = -1; X Break_C *S_RList = Return_List; /* Save loval links */ X Break_C *S_BList = Break_List; X Break_C *S_SList = SShell_List; X Break_C bc; X int LS_depth = Execute_stack_depth; X C_Op *outtree; X X/* Create a new environment in which to run */ X X if (Create_NG_VL () == -1) X return -1; X X/* Create a new save area */ X X areanum++; X X/* Execute the command */ X X if (newenv (setjmp (errpt = ev)) == FALSE) X { X Return_List = (Break_C *)NULL; X Break_List = (Break_C *)NULL; X wdlist = (Word_B *)NULL; X iolist = (Word_B *)NULL; X X pushio (argp, f); X e.iobase = e.iop; X yynerrs = 0; X X X if ((setjmp (failpt = rt) == 0) && X ((outtree = yyparse ()) != (C_Op *)NULL)) X { X if (setjmp (bc.brkpt) == 0) X { X bc.nextlev = SShell_List; X SShell_List = &bc; X rv = execute (outtree, NOPIPE, NOPIPE, 0); X } X X else X rv = getn (lookup ("?", FALSE)->value); X } X X quitenv (); X } X X/* Restore the environment */ X X Return_List = S_RList; X Break_List = S_BList; X SShell_List = S_SList; X wdlist = swdlist; X iolist = siolist; X failpt = ofail; X X Restore_Environment (rv, LS_depth); X X freearea (areanum--); X return rv; X} X X/* Exec or spawn the program ? */ X Xstatic int Execute_program (path, parms, envp, d_flag) Xchar *path; Xchar **parms; Xchar **envp; Xbool d_flag; X{ X return setstatus ((!d_flag) ? execve (path, parms, envp) X : S_spawnve (path, parms, envp)); X} X X/* Set up to spawn a process */ X Xstatic int S_spawnve (path, parms, envp) Xchar *path; Xchar **parms; Xchar **envp; X{ X unsigned int c_cur = (unsigned int)(_psp - 1); X unsigned int size = 0; X char *ep, *ep1; X int res, serrno; X struct MCB_list *mp = (struct MCB_list *)((unsigned long)c_cur << 16L); X X X/* Check to see if the file exists */ X X strcpy (path_line, path); X X if ((ep = strrchr (path_line, '/')) == (char *)NULL) X ep = path_line; X X/* If no dot in name - check for .exe and .com files */ X X if ((ep1 = strchr (ep, '.')) == (char *)NULL) X { X ep1 = ep + strlen (ep); X strcpy (ep1, ".exe"); X X if ((res = access (path_line, F_OK)) != 0) X { X strcpy (ep1, ".com"); X res = access (path_line, F_OK); X } X X if (res != 0) X return -1; X } X X else if ((stricmp (ep1, ".exe") != 0) && (stricmp (ep1, ".com") != 0)) X { X errno = ENOEXEC; X return -1; X } X X else if (access (path_line, F_OK) != 0) X return -1; X X/* Process the command line. If no swapping, we have executed the program */ X X res = build_command_line (path_line, parms, envp); X X if ((Swap_Mode == SWAP_OFF) || res) X return res; X X/* Find the length of the swap area */ X X while ((mp = (struct MCB_list *)((unsigned long)c_cur << 16L))->MCB_type X == MCB_CON) X { X if ((mp->MCB_pid != _psp) && (mp->MCB_pid != 0) && X (mp->MCB_type != MCB_END)) X { X Clear_Extended_File (); X print_error ("Fatal: Memory chain corrupt\n"); X return -1; X } X X c_cur += (mp->MCB_len + 1); X size += mp->MCB_len + 1; X } X X/* X * Convert swap size from paragraphs to 16K blocks. X */ X X if (size == 0) X size = mp->MCB_len + 1; X X SW_Blocks = (size / 0x0400) + 1; X X/* OK Now we've set up the FCB's, command line and opened the swap file. X * Get some sys info for the swapper and execute my little assembler X * function to swap us out X */ X X get_sys_info (); X X/* Ok - 3 methods of swapping */ X X/* If expanded memory - try that */ X X if (Swap_Mode & SWAP_EXPAND) X { X int cr; X SW_Mode = 3; /* Set Expanded memory swap */ X X res = SA_spawn (envp); X cr = EMS_Close (); /* Close EMS */ X X if ((res != -2) && cr) /* Report Close error ? */ X { X res = -2; X errno = cr; X } X X if (res == -2) X EMS_error ("Expanded memory swap failed (%x)\n", errno); X X else X { X Clear_Extended_File (); X return res; X } X X/* Failed - disabled */ X X Swap_Mode &= (~SWAP_EXPAND); X } X X if (Swap_Mode & SWAP_EXTEND) X { X SW_Mode = 2; /* Set Extended memory swap */ X X if ((SW_EMsize <= SW_Blocks) || X ((SW_EMstart - 0x100000L + X ((long)(SW_Blocks - SW_EMsize) * 16L * 1024L)) < 0L)) X print_warn ("Not enough Extended memory for swap\n"); X X else if ((res = SA_spawn (envp)) == -2) X print_warn ("Extended memory swap failed (%x)\n", errno); X X else X { X Clear_Extended_File (); X return res; X } X X/* Failed - disabled */ X X Swap_Mode &= (~SWAP_EXTEND); X } X X/* Try the disk if available */ X X if (Swap_Mode & SWAP_DISK) X { X if ((SW_fp = S_open (TRUE, g_tempname (), O_SMASK, 0600)) < 0) X { X print_error ("No Swap files\n"); X errno = ENOSPC; X return -1; X } X X SW_Mode = 1; /* Set Disk file swap */ X X/* Execute the program */ X X res = SA_spawn (envp); X X Clear_Extended_File (); X X if (res == -2) X { X print_warn ("Swap file write failed\n"); X errno = ENOSPC; X res = -1; X } X X/* Close the swap file and return the result */ X X serrno = errno; X S_close (SW_fp, TRUE); X errno = serrno; X return res; X } X X/* No swapping available - give up */ X X Clear_Extended_File (); X print_error ("All Swapping methods failed\n"); X errno = ENOSPC; X return -1; X} X X/* Get some system info */ X Xstatic void get_sys_info () X{ X union REGS or; X struct SREGS sr; X char *sp; X X/* Save the interrupt 0 address */ X X or.x.ax = 0x3500; X intdosx (&or, &or, &sr); X X SW_I0_V_BX = or.x.bx; X SW_I0_V_ES = sr.es; X X/* Save the interrupt 23 address */ X X or.x.ax = 0x3523; X intdosx (&or, &or, &sr); X X SW_I23_V_BX = or.x.bx; X SW_I23_V_ES = sr.es; X X/* Get max Extended memory pages, and convert to 16K blocks. If Extended X * memory swapping disabled, set to zero X */ X X or.x.ax = 0x8800; X int86 (0x15, &or, &or); X SW_EMsize = (Swap_Mode & SWAP_EXTEND) ? or.x.ax / 16 : 0; X X/* Check for the Expand Memory System */ X X if (!(Swap_Mode & SWAP_EXPAND)) X return; X X SW_fp = -1; /* Set EMS handler not defined */ X X or.x.ax = 0x3567; X intdosx (&or, &or, &sr); X X sp = (char *)((unsigned long)(sr.es) << 16L | 10L); X X/* If not there - disable */ X X if (memcmp ("EMMXXXX0", sp, 8) != 0) X { X EMS_error ("Warning: EMS not available\n", 0); X return; X } X X or.h.ah = 0x40; /* Check status */ X int86 (0x67, &or, &or); X X if (or.h.ah != 0) X { X EMS_error (EMS_emsg, or.h.ah); X return; X } X X/* Check version greater than 3.2 */ X X or.h.ah = 0x46; X int86 (0x67, &or, &or); X X if ((or.h.ah != 0) || (or.h.al < 0x32)) X { X EMS_error (EMS_emsg, or.h.ah); X return; X } X X/* get page frame address */ X X or.h.ah = 0x41; X int86 (0x67, &or, &or); X X if (or.h.ah != 0) X { X EMS_error (EMS_emsg, or.h.ah); X return; X } X X SW_EMSFrame = or.x.bx; /* Save the page frame */ X X/* Get the number of pages required */ X X or.h.ah = 0x43; X or.x.bx = SW_Blocks; X int86 (0x67, &or, &or); X X if (or.h.ah != 0) X { X EMS_error (EMS_emsg, or.h.ah); X return; X } X X/* Save the EMS Handler */ X X SW_fp = or.x.dx; X X/* save EMS page map */ X X or.h.ah = 0x47; X or.x.dx = SW_fp; X int86 (0x67, &or, &or); X X if (or.h.ah != 0) X { X EMS_error (EMS_emsg, or.h.ah); X return; X } X} X X/* Print EMS error message */ X Xstatic void EMS_error (s, v) Xchar *s; Xint v; X{ X print_warn (s, v); X Swap_Mode &= ~(SWAP_EXPAND); X EMS_Close (); X} X X X/* If the handler is defined - close it */ X Xstatic int EMS_Close () X{ X union REGS or; X int res = 0; X X if (SW_fp == -1) X return 0; X X/* Restore EMS page */ X X or.h.ah = 0x48; X or.x.dx = SW_fp; X int86 (0x67, &or, &or); X X if (or.h.ah != 0) X res = or.h.al; X X or.h.ah = 0x45; X or.x.dx = SW_fp; X int86 (0x67, &or, &or); X X SW_fp = -1; X return (res) ? res : or.h.ah; X} X X/* Set up command line. If the EXTENDED_LINE variable is set, we create X * a temporary file, write the argument list (one entry per line) to the X * this file and set the command line to @<filename>. If NOSWAPPING, we X * execute the program because I have to modify the argument line X */ X Xint build_command_line (path, argv, envp) Xchar *path; Xchar **argv; Xchar **envp; X{ X char **pl = argv; X char *fname; X int res, fd; X char *pname; X FILE *fp; X char nbuffer[NAME_MAX + 2]; X bool found; X char *ep; X char *new_args[3]; X X/* Find the start of the program name */ X X if ((pname = strrchr (path, '/')) == (char *)NULL) X pname = path; X X else X ++pname; X X/* Translate process name to MSDOS format */ X X Convert_Slashes (path); X strupr (path); X X/* Extended command line processing */ X X Extend_file == (char *)NULL; /* Set no file */ X X if ((*(pl++) != (char *)NULL) && X ((fname = lookup ("EXTENDED_LINE", FALSE)->value) != null) && X ((fp = fopen (fname, "rt")) != (FILE *)NULL)) X { X X/* Loop through the file look for the current program */ X X found = FALSE; X X while (fgets (nbuffer, NAME_MAX + 1, fp) != (char *)NULL) X { X if ((ep = strchr (nbuffer, '\n')) != (char *)NULL) X *ep = 0; X X if (stricmp (nbuffer, pname) == 0) X { X found = TRUE; X break; X } X } X X fclose (fp); X X/* Check parameters don't contain a re-direction parameter */ X X if (found) X { X char **pl1 = pl; X X while (*pl1 != (char *)NULL) X { X if (**(pl1++) == '@') X { X found = FALSE; X break; X } X } X } X X/* If we find it - create a temporary file and write the stuff */ X X if ((found) && X ((fd = S_open (FALSE, Extend_file = g_tempname (), O_CMASK, X 0600)) >= 0)) X { X X/* Copy to end of list */ X X while (*pl != (char *)NULL) X { X if (((res = strlen (*pl)) && (write (fd, *pl, res) != res)) || X (write (fd, "\n", 1) != 1)) X { X close (fd); X unlink (Extend_file); X Extend_file == (char *)NULL; X errno = ENOSPC; X return -1; X } X X ++pl; X } X X/* Completed write OK */ X X close (fd); X X/* Set up cmd_line[1] to contain the filename */ X X memset (cmd_line, 0, CMD_LINE_MAX); X cmd_line[1] = '@'; X strcpy (&cmd_line[2], Extend_file); X cmd_line[0] = (char)(strlen (Extend_file) + 1); X X/* Correctly terminate cmd_line in no swap mode */ X X if (Swap_Mode != SWAP_OFF) X cmd_line[cmd_line[0] + 1] = '\r'; X X/* If the name in the file is in upper case - use \ for separators */ X X if (isupper (*nbuffer)) X Convert_Slashes (&cmd_line[2]); X X/* OK we are ready to execute */ X X if (Swap_Mode == SWAP_OFF) X { X new_args[0] = *argv; X new_args[1] = &cmd_line[1]; X new_args[2] = (char *)NULL; X return spawnve (P_WAIT, path, new_args, envp); X } X X else X return 0; X } X } X X/* Check length of Parameter list */ X X res = 0; X cmd_line[0] = 0; X cmd_line[1] = '\r'; X ep = cmd_line; X X/* Skip the first parameter and get the length of the rest */ X X if (*argv != (char *)NULL) X { X while (*pl != (char *)NULL) X { X if ((res += (strlen (*pl) + 1)) >= CMD_LINE_MAX) X { X errno = E2BIG; X return -1; X } X X strcat (strcat (ep, " "), *(pl++)); X } X X if (res) X cmd_line[res--] = '\r'; X } X X/* Terminate the line and insert the line length */ X X cmd_line[0] = (char)res; X X/* If swapping disabled - just execute it */ X X return (Swap_Mode == SWAP_OFF) ? spawnve (P_WAIT, path, argv, envp) : 0; X} X X/* Clear Extended command line file */ X Xstatic void Clear_Extended_File () X{ X if (Extend_file != (char *)NULL) X unlink (Extend_file); X X Extend_file = (char *)NULL; X} SHAR_EOF chmod 0644 shell/sh3.c || echo "restore of shell/sh3.c fails" set `wc -c shell/sh3.c`;Sum=$1 if test "$Sum" != "28726" then echo original size 28726, current size $Sum;fi echo "x - extracting shell/sh4.c (Text)" sed 's/^X//' << 'SHAR_EOF' > shell/sh4.c && X/* MS-DOS SHELL - 'word' Interpretator 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: sh4.c 1.1 90/01/25 13:41:38 MS_user Exp $ X * X * $Log: sh4.c $ X * Revision 1.1 90/01/25 13:41:38 MS_user X * Initial revision X * X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include <dirent.h> X#include <string.h> X#include <stdlib.h> X#include <unistd.h> X#include <ctype.h> X#include <bios.h> X#include <dos.h> X#include "sh.h" X X/* X * ${}, `command`, blank interpretation, quoting and file name expansion X */ X X#define NSTART 16 /* default number of words to */ X /* allow for initially */ Xstatic Word_B *C_EList; /* For expand functions */ Xstatic Word_B *New_Elist; Xstatic char *spcl = "[?*"; Xstatic char *spcl1 = "\"'"; X Xstatic void globname (char *, char *); Xstatic bool expand (char *, Word_B **, int); Xstatic char dollar (int); Xstatic bool grave (int); Xstatic Word_B *Expand_globs (char *, Word_B *); Xstatic bool anyspcl (Word_B *); Xstatic char *blank (int); Xstatic char *generate (char *, char *, char *, char *); Xstatic char *unquote (char *); Xstatic Word_B *newword (int); Xstatic bool anys (char *, char *); Xstatic char *anys_p (char *, char *); Xstatic void Glob_MDrives (char *, char *); Xstatic char *Check_Multi_Drive (char *); X X/* X * Expand all words to their full potential X */ X Xchar **eval(ap, f) Xregister char **ap; X{ X Word_B *wb = (Word_B *)NULL; X char **wp = (char **)NULL; X char **wf = (char **)NULL; X jmp_buf ev; X X if (newenv (setjmp (errpt = ev)) == FALSE) X { X while ((*ap != (char *)NULL) && isassign (*ap)) X expand (*(ap++), &wb, f & ~DOGLOB); X X if (FL_TEST ('k')) X { X for (wf = ap; *wf != (char *)NULL; wf++) X { X if (isassign (*wf)) X expand (*wf, &wb, f & ~DOGLOB); X } X } X X/* Now expand the words */ X X for (wb = addword ((char *)NULL, wb); *ap; ap++) X { X if (!FL_TEST ('k') || !isassign(*ap)) X expand (*ap, &wb, f & ~DOKEY); X } X X/* Get the word list */ X X wp = getwords (wb = addword ((char *)NULL, wb)); X quitenv (); X } X X else X gflg = 1; X X return gflg ? (char **)NULL : wp; X} X X/* X * Make the exported environment from the exported names in the dictionary. X * Keyword assignments will already have been done. Convert to MSDOS X * format if flag set and m enabled X */ X Xchar **makenv () X{ X register Word_B *wb = (Word_B *)NULL; X register Var_List *vp; X char *cp, *sp; X int len = 0; X X for (vp = vlist; vp != (Var_List *)NULL; vp = vp->next) X { X if (vp->status & EXPORT) X { X if ((len += (strlen (vp->name) + 1)) >= 0x7f00) X return (char **)NULL; X X wb = addword (vp->name, wb); X X/* If MSDOS mode, we need to copy the variable, convert / to \ and put X * the copy in the environment list instead X */ X X if (FL_TEST ('m') && (vp->status & C_MSDOS)) X { X cp = space (strlen (sp = wb->w_words[wb->w_nword - 1]) + 1); X wb->w_words[wb->w_nword - 1] = cp; X Convert_Slashes (strcpy (cp, sp)); X } X } X } X X return getwords (wb = addword ((char *)NULL, wb)); X} X Xchar *evalstr(cp, f) Xregister char *cp; Xint f; X{ X Word_B *wb = (Word_B *)NULL; X X if (expand (cp, &wb, f)) X { X if ((wb == (Word_B *)NULL) || (wb->w_nword == 0) || X ((cp = wb->w_words[0]) == (char *)NULL)) X cp = null; X X DELETE (wb); X } X X else X cp = (char *)NULL; X X return cp; X} X X/* Expand special characters and variables */ X Xstatic bool expand (cp, wbp, f) Xregister char *cp; Xregister Word_B **wbp; X{ X jmp_buf ev; X X gflg = 0; X X if (cp == (char *)NULL) X return FALSE; X X/* If there are no special characters and no separators, nothing to do, X * just save the word X */ X X if (!anys (spcl2, cp) && !anys (ifs->value, cp) && X ((f & DOGLOB) == 0 || !anys (spcl, cp))) X { X cp = strsave (cp, areanum); X X if (f & DOTRIM) X unquote (cp); X X *wbp = addword (cp, *wbp); X return TRUE; X } X X/* Set up to read the word back in */ X X if (newenv (setjmp (errpt = ev)) == FALSE) X { X PUSHIO (aword, cp, strchar); X e.iobase = e.iop; X X while ((cp = blank (f)) && gflg == 0) X { X e.linep = cp; X cp = strsave (cp, areanum); X X/* Global expansion disabled ? */ X X if (((f & DOGLOB) == 0) || FL_TEST ('f')) X { X if (f & DOTRIM) X unquote(cp); X X *wbp = addword (cp, *wbp); X } X X else X *wbp = Expand_globs (cp, *wbp); X } X X quitenv (); X } X X else X gflg = 1; X X return (gflg == 0) ? TRUE : FALSE; X} X X/* X * Blank interpretation and quoting X */ X Xstatic char *blank(f) X{ X register int c, c1; X register char *sp = e.linep; X int scanequals = f & DOKEY; X int foundequals = 0; X Xloop: X switch (c = subgetc ('"', foundequals)) X { X case 0: X if (sp == e.linep) X return (char *)NULL; X X *e.linep++ = 0; X return sp; X X default: X if ((f & DOBLANK) && any ((char)c, ifs->value)) X goto loop; X X break; X X case '"': X case '\'': X scanequals = 0; X if (INSUB()) X break; X X for (c1 = c; (c = subgetc ((char)c1, 1)) != c1;) X { X if (c == 0) X break; X X if ((c == '\'') || !any ((char)c, "$`\"")) X c |= QUOTE; X X *e.linep++ = (char)c; X } X X c = 0; X } X X unget(c); X X if (!isalpha (c)) X scanequals = 0; X X while (1) X { X if (((c = subgetc ('"', foundequals)) == 0) || X (f & DOBLANK) && any ((char)c, ifs->value) || X !INSUB() && any ((char)c, spcl1)) X { X scanequals = 0; X unget (c); X X if (any ((char)c, spcl1)) X goto loop; X X break; X } X X if (scanequals) X { X if (c == '=') X { X foundequals = 1; X scanequals = 0; X } X X else if (!isalnum (c)) X scanequals = 0; X } X X *e.linep++ = (char)c; X } X X *e.linep++ = 0; X return sp; X} X X/* X * Get characters, substituting for ` and $ X */ X Xint subgetc (ec, quoted) Xregister char ec; Xint quoted; X{ X register char c; X Xagain: X c = (char)Getc (ec); X X if (!INSUB() && ec != '\'') X { X if (c == '`') X { X if (grave (quoted) == 0) X return 0; X X e.iop->task = XGRAVE; X goto again; X } X X if (c == '$' && (c = dollar (quoted)) == 0) X { X e.iop->task = XDOLL; X goto again; X } X } X X return c; X} X X/* X * Prepare to generate the string returned by ${} substitution. X */ X Xstatic char dollar (quoted) Xint quoted; X{ X IO_State *oiop; X char *dolp, otask; X register char *s, c, *cp; X Var_List *vp; X bool colon_f = FALSE; X X c = (char)readc (); X s = e.linep; X X/* Bracketed or not ? */ X X if (c != '{') X { X X/* Get the string, while it is a alpha character */ X X *e.linep++ = c; X X if (isalpha (c)) X { X while (((c = (char)readc ()) != 0) && isalnum (c)) X { X if (e.linep < e.eline) X *e.linep++ = c; X } X X unget(c); X } X X c = 0; X } X X/* Bracketed - special case */ X X else X { X oiop = e.iop; X otask = e.iop->task; X e.iop->task = XOTHER; X X while (((c = (char)subgetc ('"', 0)) != 0) && (c != '}') && (c != NL)) X { X if (e.linep < e.eline) X *e.linep++ = c; X } X X if (oiop == e.iop) X e.iop->task = otask; X X/* Check terminate correctly */ X X if (c != '}') X { X print_error ("sh: unclosed ${\n"); X gflg++; X return c; X } X } X X/* Check line length */ X X if (e.linep >= e.eline) X { X print_error ("sh: string in ${} too long\n"); X gflg++; X e.linep -= 10; X } X X *e.linep = 0; X X/* Scan for =-+? in string */ X X if (*s) X { X for (cp = s + 1; *cp; cp++) X { X X/* Check for end character other than null (=-+?) */ X X if (any (*cp, "=-+?")) X { X c = *cp; X X/* Check for case of :[=-+?]. If found - set flag */ X X if (*(cp - 1) == ':') X { X colon_f = TRUE; X *(cp - 1) = 0; X } X X *(cp++) = 0; X break; X } X } X } X X/* Check for * and @ processing */ X X if (s[1] == 0 && (*s == '*' || *s == '@')) X { X if (dolc > 1) X { X e.linep = s; X PUSHIO (awordlist, dolv + 1, dol_char); X e.iop->dflag = (char)(!quoted ? DSA_NULL X : ((*s == '*') ? DSA_STAR : DSA_AMP)); X return 0; X } X X/* trap the nasty ${=} */ X X else X { X s[0] = '1'; X s[1] = 0; X } X } X X/* Find the current value X * X * $~xxx variables are used by the Shell internally and cannot be accessed X * by the user. X */ X X if (*s == '~') X dolp = null; X X else if ((dolp = (vp = lookup (s, FALSE))->value) == null) X { X switch (c) X { X case '=': X if (isdigit (*s)) X { X print_error ("sh: cannot use ${...=...} with $n\n"); X gflg++; X break; X } X X setval ((vp = lookup (s, TRUE)), cp); X dolp = vp->value; X break; X X case '-': X dolp = strsave (cp, areanum); X break; X X case '?': X if (*cp == 0) X cp = "parameter null or not set"; X X print_error ("%s: %s\n", s, cp); X X gflg++; X break; X } X } X X else if (c == '+') X dolp = strsave (cp, areanum); X X/* Check for unset values */ X X if (FL_TEST ('u') && dolp == null) X { X print_error ("sh: unset variable %s\n", s); X gflg++; X } X X e.linep = s; X PUSHIO (aword, dolp, quoted ? qstrchar : strchar); X return 0; X} X X/* X * Run the command in `...` and read its output. X */ X Xstatic bool grave (quoted) Xint quoted; X{ X char *cp, *sp; X int localpipe, rv; X jmp_buf ev, rt; X C_Op *outtree; X Break_C bc; X X/* Save area */ X X long s_flags = flags; X Word_B *s_wdlist = wdlist; X Word_B *s_iolist = iolist; X Break_C *S_RList = Return_List; /* Save loval links */ X Break_C *S_BList = Break_List; X Break_C *S_SList = SShell_List; X int *s_fail = failpt; X int s_execflg = execflg; X int Local_depth; X X/* Check there is an ending grave */ X X if ((cp = strchr (e.iop->argp->aword, '`')) == (char *)NULL) X { X print_error ("sh: no closing `\n"); X return FALSE; X } X X/* Create the pipe to read the output from the command string */ X X if ((localpipe = openpipe ()) < 0) X return FALSE; X X/* Terminate string and initialise save area */ X X *cp = 0; X X/* Create a new environment */ X X S_dup2 (localpipe, 1); X X FL_CLEAR ('e'); X FL_CLEAR ('v'); X FL_CLEAR ('n'); X X sp = strsave (e.iop->argp->aword, areanum++); X unquote (sp); X X/* Set up new environment */ X X Local_depth = Execute_stack_depth++; X rv = Create_NG_VL (); X X if ((rv != -1) && (newenv (setjmp (errpt = ev)) == FALSE)) X { X Return_List = (Break_C *)NULL; X Break_List = (Break_C *)NULL; X wdlist = (Word_B *)NULL; X wdlist = (Word_B *)NULL; X iolist = (Word_B *)NULL; X X PUSHIO (aword, sp, nlchar); X e.cline = space (LINE_MAX); X e.eline = e.cline + LINE_MAX - 5; X e.linep = e.cline; X e.iobase = e.iop; X X/* Clear interrupt, error, multiline, parse and execute flags. */ X X SW_intr = 0; X yynerrs = 0; X multiline = 0; X inparse = 0; X execflg = 1; X X/* Parse the line and execute it */ X X if ((setjmp (failpt = rt) == 0) && X ((outtree = yyparse ()) != (C_Op *)NULL)) X { X if (setjmp (bc.brkpt) == 0) X { X bc.nextlev = SShell_List; X SShell_List = &bc; X execute (outtree, NOPIPE, NOPIPE, 0); X } X } X X quitenv (); X } X X/* Fail - close pipe and delete it */ X X else X { X S_Delete (localpipe); X S_close (localpipe, TRUE); X } X X/* Restore environment */ X X Restore_Environment (0, Local_depth); X X/* Free old space */ X X freehere (areanum); X freearea (areanum--); /* free old space */ X X/* Ok - completed processing - restore environment and read the pipe */ X X execflg = s_execflg; X flags = s_flags; X wdlist = s_wdlist; X iolist = s_iolist; X failpt = s_fail; X Return_List = S_RList; X Break_List = S_BList; X SShell_List = S_SList; X X/* Move pipe to start so we can read it */ X X *(cp++) = '`'; X lseek (localpipe, 0L, SEEK_SET); X e.iop->argp->aword = cp; X PUSHIO (afile, remap (localpipe), quoted ? qgravechar: gravechar); X return TRUE; X} X X/* X * Remove Quotes from a string X */ X Xstatic char *unquote (as) Xregister char *as; X{ X register char *s; X X if ((s = as) != (char *)NULL) X { X while (*s) X *(s++) &= ~QUOTE; X } X X return as; X} X X/* X * Expand *, [] and ? X */ X Xstatic Word_B *Expand_globs (cp, wb) Xchar *cp; XWord_B *wb; X{ X register int i = 0; X register char *pp; X X/* Ignore null strings */ X X if (cp == (char *)NULL) X return wb; X X/* Any special characters */ X X for (pp = cp; *pp; pp++) X { X if (any (*pp, spcl)) X i++; X X else if (!any (*pp & ~QUOTE, spcl)) X *pp &= ~QUOTE; X } X X/* No - just add the word to the selected block */ X X if (i == 0) X return addword (unquote (cp), wb); X X/* OK - we have to expand the word whilst any words in cl have special X * characters in them X */ X X for (C_EList = addword (strsave (cp, areanum), (Word_B *)NULL); X anyspcl (C_EList); C_EList = New_Elist) X { X X/* Get a new block for this pass of the expansion */ X X New_Elist = newword (C_EList->w_nword * 2); X X/* For each word, expand it */ X X for (i = 0; i < C_EList->w_nword; i++) X { X if ((pp = anys_p (C_EList->w_words[i], spcl)) != (char *)NULL) X Glob_MDrives (C_EList->w_words[i], pp); X X else X New_Elist = addword (strsave (C_EList->w_words[i], areanum), X New_Elist); X } X X/* The current list is now the previous list, so delete it */ X X for (i = 0; i < C_EList->w_nword; i++) X DELETE (C_EList->w_words[i]); X X DELETE (C_EList); X } X X for (i = 0; i < C_EList->w_nword; i++) X unquote (C_EList->w_words[i]); X X qsort (C_EList->w_words, C_EList->w_nword, sizeof (char *), sort_compare); X X/* Did we find any files matching the specification. Yes - add them to X * the block X */ X X if (C_EList->w_nword) X { X for (i = 0; i < C_EList->w_nword; i++) X wb = addword (C_EList->w_words[i], wb); X X DELETE (C_EList); X return wb; X } X X/* No - add the original word */ X X else X return addword (unquote (cp), wb); X} X X/* X * Read a directory for matches against the specified name X */ X Xstatic void globname (we, pp) Xchar *we; /* Start */ Xregister char *pp; /* First special character */ X{ X register char *np, *cp; X char *name, *gp, *dp; X DIR *dn; X struct dirent *d_ce; X char dname[NAME_MAX + 1]; X struct stat dbuf; X X/* Find the previous directory separator */ X X for (np = we; np != pp; pp--) X { X if (pp[-1] == '/') X break; X } X X/* If we don't find it, check for a drive */ X X if ((np == pp) && (strlen (we) > 2) && (we[1] == ':')) X pp += 2; X X/* Save copy of directory name */ X X for (dp = cp = space ((int)(pp - np) + 3); np < pp;) X *cp++ = *np++; X X *cp++ = '.'; X *cp = '\0'; X X/* Save copy of pattern for this directory. NP is left pointing to the X * rest of the string for any subdirectories X */ X X for (gp = cp = space (strlen (pp) + 1); *np && *np != '/';) X *cp++ = *np++; X X *cp = '\0'; X X/* Open the directory */ X X if ((dn = opendir (dp)) == (DIR *)NULL) X { X DELETE (dp); X DELETE (gp); X return; X } X X/* Scan for matches */ X X while ((d_ce = readdir (dn)) != (struct dirent *)NULL) X { X if ((*(strcpy (dname, d_ce->d_name)) == '.') && (*gp != '.')) X continue; X X for (cp = dname; *cp; cp++) X { X if (any (*cp, spcl)) X *cp |= QUOTE; X } X X/* Check for a match */ X X if (gmatch (dname, gp, TRUE)) X { X X/* If there are no special characters in the new full name, the file must X * exist X */ X X name = generate (we, pp, dname, np); X X if (*np && !anys (np, spcl)) X { X if (stat (name, &dbuf)) X { X DELETE (name); X continue; X } X } X X/* Ok save the name */ X X New_Elist = addword (name, New_Elist); X } X } X X closedir (dn); X DELETE (dp); X DELETE (gp); X} X X/* X * generate a pathname as below. start..end1 / middle end. The slashes come X * for free X */ X Xstatic char *generate (start1, end1, middle, end) Xchar *start1; Xregister char *end1; Xchar *middle, *end; X{ X register char *op; X int clen = (int)(end1 - start1); X X op = space (clen + strlen (middle) + strlen (end) + 2); X X strncpy (op, start1, clen); X strcat (strcpy (&op[clen], middle), end); X return op; X} X X/* X * Scan a Word Block for special characters X */ X Xstatic bool anyspcl (wb) Xregister Word_B *wb; X{ X register int i; X register char **wd = wb->w_words; X X for (i = 0; i < wb->w_nword; i++) X { X if (anys (spcl, *wd++)) X return TRUE; X } X X return FALSE; X} X X/* X * Create a new Word Block X */ X Xstatic Word_B *newword (nw) Xregister int nw; X{ X register Word_B *wb; X X wb = (Word_B *) space (sizeof (Word_B) + nw * sizeof (char *)); X wb->w_bsize = nw; X wb->w_nword = 0; X X return wb; X} X X/* X * Add a new word to a Word Block or list X */ X XWord_B *addword (wd, wb) Xchar *wd; Xregister Word_B *wb; X{ X register Word_B *wb2; X register int nw; X X if (wb == (Word_B *)NULL) X wb = newword (NSTART); X X/* Do we require more space ? */ X X if ((nw = wb->w_nword) >= wb->w_bsize) X { X wb2 = newword (nw * 2); X memcpy ((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *)); X wb2->w_nword = nw; X DELETE (wb); X wb = wb2; X } X X/* Add to the list */ X X wb->w_words[wb->w_nword++] = wd; X return wb; X} X X/* X * Convert a word block structure into a array of strings X */ X Xchar **getwords(wb) Xregister Word_B *wb; X{ X register char **wd; X register nb; X X/* If the word block is empty or does not exist, return no list */ X X if (wb == (Word_B **)NULL) X return (char *)NULL; X X if (wb->w_nword == 0) X { X DELETE (wb); X return (char *)NULL; X } X X/* Get some space for the array and set it up */ X X wd = (char **)space (nb = sizeof (char *) * wb->w_nword); X X memcpy ((char *)wd, (char *)wb->w_words, nb); X DELETE (wb); /* perhaps should done by caller */ X return wd; X} X X/* X * Is any character from s1 in s2? Return a boolean. X */ X Xstatic bool anys (s1, s2) Xregister char *s1, *s2; X{ X while (*s1) X { X if (any (*(s1++), s2)) X return TRUE; X } X X return FALSE; X} X X/* X * Is any character from s1 in s2? Yes - return a pointer to that X * character. X */ X Xstatic char *anys_p (s1, s2) Xregister char *s1, *s2; X{ X while (*s1) X { X if (any (*(s1++), s2)) X return --s1; X } X X return (char *)NULL; X} X X/* X * Expansion - check for multiple drive request X * X * If there is a multi-drive expansion (*:, ?: or []:), we have to check X * out each existing drive and then expand. So we check for a multi-drive X * condition and then for each existing drive, we check that pattern X * against the drive and then expand the rest of the pattern. X * X * Otherwise, we just expand the pattern. X */ X Xstatic void Glob_MDrives (pattern, start) Xchar *pattern; Xchar *start; X{ X unsigned int c_drive; /* Current drive */ X unsigned int m_drive; /* Max drive */ X unsigned int s_drive; /* Selected drive */ X unsigned int x_drive, y_drive; /* Dummies */ X char *multi; /* Multi-drive flag */ X static char *t_drive = "x"; X char *new_pattern; X X/* Search all drives ? */ X X if ((multi = Check_Multi_Drive (pattern)) != (char *)NULL) X { X _dos_getdrive (&c_drive); /* Get number of drives */ X _dos_setdrive (c_drive, &m_drive); X new_pattern = space (strlen (multi) + 2); X X strcpy (new_pattern + 1, multi); X *multi = 0; X X for (s_drive = 1; s_drive <= m_drive; ++s_drive) X { X _dos_setdrive (s_drive, &x_drive); X _dos_getdrive (&y_drive); X _dos_setdrive (c_drive, &x_drive); X X/* Check to see if the second diskette drive is really there */ X X if (((_bios_equiplist () & 0x00c0) == 0x0000) && (s_drive == 2)) X continue; X X/* If the drive exists and is in our list - process it */ X X *t_drive = (char)(s_drive + 'a' - 1); X X if ((y_drive == s_drive) && gmatch (t_drive, pattern, TRUE)) X { X *new_pattern = *t_drive; X globname (new_pattern, &new_pattern[2]); X } X } X X/* Restore and delete space */ X X *multi = ':'; X DELETE (new_pattern); X } X X/* No drive specifier - just check it out */ X X else X globname (pattern, start); X} X X/* X * Check for multi_drive prefix - *:, ?: or []: X * X * Return NULL or the address of the colon character X */ X Xstatic char *Check_Multi_Drive (pattern) Xchar *pattern; X{ X if (strlen (pattern) < 3) X return (char *)NULL; X X if (((*pattern == '*') || (*pattern == '?')) && (pattern[1] == ':')) X return pattern + 1; X X if (*pattern != '[') X return (char *)NULL; X X while (*pattern && (*pattern != ']')) X { X if ((*pattern == '\\') && (*(pattern + 1))) X ++pattern; X X ++pattern; X } X X return (*pattern && (*(pattern + 1) == ':')) ? pattern + 1 : (char *)NULL; X} SHAR_EOF chmod 0644 shell/sh4.c || echo "restore of shell/sh4.c fails" set `wc -c shell/sh4.c`;Sum=$1 if test "$Sum" != "20630" then echo original size 20630, current size $Sum;fi echo "x - extracting shell/sh5.c (Text)" sed 's/^X//' << 'SHAR_EOF' > shell/sh5.c && X/* MS-DOS SHELL - Main I/O Functions 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: sh5.c 1.1 90/01/25 13:41:50 MS_user Exp $ X * X * $Log: sh5.c $ X * Revision 1.1 90/01/25 13:41:50 MS_user X * Initial revision X * X */ X X#include <sys/types.h> X#include <stdio.h> X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include <stdlib.h> X#include <string.h> X#include <fcntl.h> X#include <io.h> X#include <limits.h> X#include <unistd.h> X#include "sh.h" X X/* X * shell IO X */ X Xstatic IO_Buf sharedbuf = {AFID_NOBUF}; Xstatic IO_Buf mainbuf = {AFID_NOBUF}; Xstatic unsigned int bufid = AFID_ID; /* buffer id counter */ X /* list of hear docs while parsing */ Xstatic Here_D *inhere = (Here_D *)NULL; X /* list of active here documents */ Xstatic Here_D *acthere = (Here_D *)NULL; X Xstatic int dol1_char (IO_State *); Xstatic void readhere (char **, char *, int); Xstatic int herechar (IO_State *); X Xint Getc (ec) Xregister int ec; X{ X register int c; X X if (e.linep > e.eline) X { X while (((c = readc ()) != NL) && c) X ; X X print_error ("sh: input line too long\n"); X gflg++; X return c; X } X X c = readc(); X if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) X { X if (c == '\\') X { X if (((c = readc ()) == NL) && (ec != '\"')) X return Getc (ec); X X c |= QUOTE; X } X } X X return c; X} X Xvoid unget (c) Xint c; X{ X if (e.iop >= e.iobase) X e.iop->peekc = c; X} X Xint eofc () X{ X return (e.iop < e.iobase) || ((e.iop->peekc == 0) && (e.iop->prev == 0)); X} X X/* Read the next character */ X Xint readc () X{ X register int c; X char s_dflag = e.iop->dflag; X X/* The dflag is transfered from the higher level to the lower level at end X * of input at the higher level. This is part of the implementation of X * $* and $@ processing. X */ X X for (; e.iop >= e.iobase; e.iop--) X { X X/* Set up the current dflag */ X X e.iop->dflag = s_dflag; X X/* If there is an unget character, use it */ X X if ((c = e.iop->peekc) != '\0') X { X e.iop->peekc = 0; X return c; X } X X/* Some special processing for multi-line commands */ X X else X { X if (e.iop->prev != 0) X { X X/* Get the next character from the IO function */ X X if ((c = (*e.iop->iofn)(e.iop)) != '\0') X { X X/* End of current level, but continue at this level as another read X * function has been put on the stack X */ X X if (c == -1) X { X e.iop++; X continue; X } X X/* If we are at the bottom - echo the character */ X X if ((e.iop == iostack) && (FL_TEST ('v'))) X S_putc ((char)c); X X/* Return the current character */ X X return (e.iop->prev = (char)c); X } X X else if (e.iop->task == XIO && e.iop->prev != NL) X { X e.iop->prev = 0; X X if ((e.iop == iostack) && (FL_TEST ('v'))) X S_putc (NL); X X return NL; X } X X else X s_dflag = e.iop->dflag; X } X X if (e.iop->task == XIO) X { X if (multiline) X return e.iop->prev = 0; X X if (talking && e.iop == iostack + 1) X put_prompt (ps1->value); X } X } X } X X if (e.iop >= iostack) X return 0; X X leave(); X /* NOTREACHED */ X} X X/* Add an Input channel to the input stack */ X Xvoid pushio (argp, fn) XIO_Args *argp; Xint (*fn)(IO_State *); X{ X if (++e.iop >= &iostack[NPUSH]) X { X e.iop--; X print_error ("sh: Shell input nested too deeply\n"); X gflg++; X return; X } X X e.iop->iofn = fn; X X if (argp->afid != AFID_NOBUF) X e.iop->argp = argp; X X else X { X e.iop->argp = ioargstack + (e.iop - iostack); X *e.iop->argp = *argp; X e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf; X X if ((isatty (e.iop->argp->afile) == 0) && X ((e.iop == &iostack[0]) || X (lseek (e.iop->argp->afile, 0L, 1) != -1L))) X { X if (++bufid == AFID_NOBUF) X bufid = AFID_ID; X X e.iop->argp->afid = bufid; X } X } X X e.iop->prev = ~NL; X e.iop->peekc = 0; X e.iop->xchar = 0; X e.iop->nlcount = 0; X X if ((fn == filechar) || (fn == linechar)) X e.iop->task = XIO; X X else if ((fn == gravechar) || (fn == qgravechar)) X e.iop->task = XGRAVE; X X else X e.iop->task = XOTHER; X} X X/* X * Input generating functions X */ X X/* X * Produce the characters of a string, then a newline, then EOF. X */ Xint nlchar (iop) Xregister IO_State *iop; X{ X register int c; X X if (iop->argp->aword == (char *)NULL) X return 0; X X if ((c = *iop->argp->aword++) == 0) X { X iop->argp->aword = (char *)NULL; X return NL; X } X X return c; X} X X/* X * Given a list of words, produce the characters X * in them, with a space after each word. X */ X Xint wdchar (iop) Xregister IO_State *iop; X{ X register char c; X register char **wl; X X if ((wl = iop->argp->awordlist) == (char **)NULL) X return 0; X X if (*wl != (char *)NULL) X { X if ((c = *(*wl)++) != 0) X return (c & 0177); X X iop->argp->awordlist++; X return SP; X } X X iop->argp->awordlist = (char **)NULL; X return NL; X} X X/* X * Return the characters of a list of words, producing a space between them. X */ X Xint dol_char (iop) XIO_State *iop; X{ X register char *wp; X char cflag; X X if ((wp = *(iop->argp->awordlist)++) != (char *)NULL) X { X if (*iop->argp->awordlist == (char *)NULL) X iop->dflag |= DSA_END; X X cflag = iop->dflag; X PUSHIO (aword, wp, dol1_char); X e.iop->dflag = cflag; X return -1; X } X X return 0; X} X X/* Return next character from the word with a space at the end */ X Xstatic int dol1_char (iop) XIO_State *iop; X{ X register int c; X X if ((iop->dflag & DSA_MODE) == DSA_AMP) X { X if (!(iop->dflag & DSA_START)) X iop->dflag |= DSA_START; X X/* Has the previous word ended */ X X else if (iop->dflag & DSA_START1) X { X iop->dflag &= ~DSA_START1; X return '"'; X } X } X X if (iop->argp->aword == (char *)NULL) X return 0; X X if ((c = *iop->argp->aword) == '\0') X { X if ((iop->dflag & DSA_MODE) != DSA_AMP) X { X iop->argp->aword = (char *)NULL; X return (iop->dflag & DSA_END) ? 0 : SP; X } X X if (!(iop->dflag & DSA_END1)) X { X iop->dflag |= DSA_END1; X return '"'; X } X X iop->argp->aword = (char *)NULL; X iop->dflag &= ~DSA_END1; X iop->dflag |= DSA_START1; X return (iop->dflag & DSA_END) ? 0 : SP; X } X X iop->argp->aword++; X if ((iop->dflag != DSA_NULL) && any ((char)c, ifs->value)) X c |= QUOTE; X X return c; X} X X/* X * Produce the characters from a single word (string). X */ X Xint strchar (iop) XIO_State *iop; X{ X register int c; X X return ((iop->argp->aword == (char *)NULL) || X ((c = *(iop->argp->aword++)) == 0)) ? 0 : c; X} X X/* X * Produce quoted characters from a single word (string). X */ X Xint qstrchar (iop) XIO_State *iop; X{ X register int c; X X return ((iop->argp->aword == (char *)NULL) || X ((c = *(iop->argp->aword++)) == 0)) ? 0 : (c | QUOTE); X} X X/* X * Return the characters from a file. X */ X Xint filechar (iop) XIO_State *iop; X{ X register IO_Args *ap = iop->argp; X register int i; X char c; X IO_Buf *bp = ap->afbuf; X X if (ap->afid != AFID_NOBUF) X { X if ((i = (ap->afid != bp->id)) || (bp->bufp == bp->ebufp)) X { X if (i) X lseek (ap->afile, ap->afpos, SEEK_SET); X X if ((i = read (ap->afile, bp->buf, sizeof (bp->buf))) <= 0) X { X if (ap->afile > STDERR_FILENO) X S_close (ap->afile, TRUE); X X return 0; X } X X bp->id = ap->afid; X bp->ebufp = (bp->bufp = bp->buf) + i; X } X X ap->afpos++; X X return *bp->bufp++ & 0177; X } X X/* If this is the terminal, there is special input processing */ X X else if ((ap->afile == 0) && isatty (ap->afile)) X return Get_stdin (ap); X X if ((i = read (ap->afile, &c, sizeof(c))) == sizeof (c)) X return (int)c & 0177; X X if (ap->afile > STDERR_FILENO) X S_close (ap->afile, TRUE); X X return 0; X} X X/* X * Return the characters from a here temp file. X */ X Xstatic int herechar (iop) Xregister IO_State *iop; X{ X char c; X X if (read (iop->argp->afile, &c, sizeof(c)) != sizeof(c)) X { X S_close (iop->argp->afile, TRUE); X c = 0; X } X X return c; X} X X/* X * Return the characters produced by a process (`...`). X * Quote them if required, and remove any trailing newline characters. X */ X Xint gravechar (iop) XIO_State *iop; X{ X register int c; X X if ((c = qgravechar (iop) & ~QUOTE) == NL) X c = SP; X X return c; X} X X/* X * Process input from a `...` string X */ X Xint qgravechar (iop) XIO_State *iop; X{ X register int c; X X if (iop->xchar) X { X if (iop->nlcount) X { X iop->nlcount--; X return (NL | QUOTE); X } X X c = iop->xchar; X iop->xchar = 0; X } X X else if ((c = filechar (iop)) == NL) X { X iop->nlcount = 1; X X while ((c = filechar (iop)) == NL) X iop->nlcount++; X X iop->xchar = (char)c; X X if (c == 0) X return(c); X X iop->nlcount--; X c = NL; X } X X return (c != 0) ? (c | QUOTE): 0; X} X X/* X * Return a single command (usually the first line) from a file. X */ X Xint linechar (iop) XIO_State *iop; X{ X register int c; X X if ((c = filechar (iop)) == NL) X { X if (!multiline) X { X if (iop->argp->afile > STDERR_FILENO) X S_close (iop->argp->afile, TRUE); X X iop->argp->afile = -1; /* illegal value */ X } X } X X return c; X} X Xvoid closeall () X{ X register int u; X X for (u = NUFILE; u < NOFILE;) X S_close (u++, TRUE); X} X X/* X * remap fd into Shell's fd space X */ X Xint remap (fd) Xregister int fd; X{ X register int i; X register int n_io = 0; X int map[NOFILE]; X int o_fd = fd; X X if (fd < e.iofd) X { X do X { X map[n_io++] = fd; X fd = dup (fd); X X } while ((fd >= 0) && (fd < e.iofd)); X X for (i = 0; i < n_io; i++) X close (map[i]); X X S_Remap (o_fd, fd); X S_close (o_fd, TRUE); X X if (fd < 0) X print_error ("sh: too many files open\n"); X } X X return fd; X} X X/* X * here documents X */ X Xvoid markhere (s, iop) Xregister char *s; XIO_Actions *iop; X{ X register Here_D *h, *lh; X X if ((h = (Here_D *) space(sizeof(Here_D))) == (Here_D *)NULL) X return; X X if ((h->h_tag = evalstr (s, DOSUB)) == (char *)NULL) X return; X X h->h_iop = iop; X iop->io_name = (char *)NULL; X h->h_next = (Here_D *)NULL; X X if (inhere == (Here_D *)NULL) X inhere = h; X X else X { X for (lh = inhere; lh != (Here_D *)NULL; lh = lh->h_next) X { X if (lh->h_next == (Here_D *)NULL) X { X lh->h_next = h; X break; X } X } X } X X iop->io_flag |= IOHERE|IOXHERE; X X for (s = h->h_tag; *s; s++) X { X if (*s & QUOTE) X { X iop->io_flag &= ~ IOXHERE; X *s &= ~ QUOTE; X } X } X X h->h_dosub = iop->io_flag & IOXHERE; X} X Xvoid gethere () X{ X register Here_D *h, *hp; X X/* Scan here files first leaving inhere list in place */ X X for (hp = h = inhere; h != (Here_D *)NULL; hp = h, h = h->h_next) X readhere (&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\''); X X/* Make inhere list active - keep list intact for scraphere */ X X if (hp != (Here_D *)NULL) X { X hp->h_next = acthere; X acthere = inhere; X inhere = (Here_D *)NULL; X } X} X Xstatic void readhere (name, s, ec) Xchar **name; Xregister char *s; X{ X int tf; X register int c; X jmp_buf ev; X char *line; X char *next; X X *name = strsave (g_tempname (), areanum); X X if ((tf = S_open (FALSE, *name, O_CMASK | O_NOINHERIT, 0600)) < 0) X return; X X if (newenv (setjmp (errpt = ev)) == TRUE) X S_Delete (tf); X X else X { X line = space (LINE_MAX + 1); X pushio (e.iop->argp, e.iop->iofn); X e.iobase = e.iop; X X while (1) X { X if (talking && e.iop <= iostack) X put_prompt (ps2->value); X X next = line; X while ((c = Getc (ec)) != NL && c) X { X if (ec == '\'') X c &= ~ QUOTE; X X if (next >= &line[LINE_MAX]) X { X c = 0; X break; X } X X *next++ = (char)c; X } X X *next = 0; X if (strcmp (s, line) == 0 || c == 0) X break; X X *next++ = NL; X write (tf, line, (int)(next-line)); X } X X if (c == 0) X print_error ("here document `%s' unclosed\n", s); X X quitenv (); X } X X S_close (tf, TRUE); X} X X/* X * open here temp file. X * If unquoted here, expand here temp file into second temp file. X */ X Xint herein (hname, xdoll) Xchar *hname; Xint xdoll; X{ X register int hf, tf; X X if (hname == (char *)NULL) X return -1; X X if ((hf = S_open (FALSE, hname, O_RDONLY)) < 0) X return -1; X X if (xdoll) X { X char c; X char *tname = g_tempname(); X jmp_buf ev; X X if ((tf = S_open (FALSE, tname, O_CMASK | O_NOINHERIT, 0600)) < 0) X return -1; X X if (newenv (setjmp (errpt = ev)) == FALSE) X { X PUSHIO (afile, hf, herechar); X e.iobase = e.iop; X X while ((c = (char)subgetc(0, 0)) != 0) X { X c &= ~ QUOTE; X write (tf, &c, sizeof c); X } X X quitenv (); X } X X else X S_Delete (tf); X X S_close (tf, TRUE); X return S_open (TRUE, tname, O_RDONLY); X } X X else X return hf; X} X Xvoid scraphere() X{ X register Here_D *h; X X for (h = inhere; h != (Here_D *)NULL; h = h->h_next) X { X if ((h->h_iop != (IO_Actions *)NULL) && X (h->h_iop->io_name != (char *)NULL)) X unlink (h->h_iop->io_name); X } X X inhere = (Here_D *)NULL; X} X X/* unlink here temp files before a freearea (area) */ X Xvoid freehere (area) Xint area; X{ X register Here_D *h; X register Here_D *hl = (Here_D *)NULL; X X for (h = acthere; h != (Here_D *)NULL; hl = h, h = h->h_next) X { X if (getarea ((char *)h) >= area) X { X if (h->h_iop->io_name != (char *)NULL) X unlink (h->h_iop->io_name); X X if (hl == (Here_D *)NULL) X acthere = h->h_next; X X else X hl->h_next = h->h_next; X } X } X} X Xchar *g_tempname () X{ X static char tmpfile[FFNAME_MAX]; X char *tmpdir; /* Points to directory prefix of pipe */ X static int temp_count = 0; X X/* Find out where we should put temporary files */ X X if ((tmpdir = lookup ("TMPDIR", FALSE)->value) == null) X tmpdir = lookup ("TMP", FALSE)->value; X X/* Get a unique temporary file name */ X X while (1) X { X sprintf (tmpfile, "%s/sht%.5u.tmp", tmpdir, temp_count++); X X if (access (tmpfile, F_OK) != 0) X break; X } X X return tmpfile; X} SHAR_EOF chmod 0644 shell/sh5.c || echo "restore of shell/sh5.c fails" set `wc -c shell/sh5.c`;Sum=$1 if test "$Sum" != "14249" then echo original size 14249, current size $Sum;fi echo "x - extracting shell/sh6.c (Text)" sed 's/^X//' << 'SHAR_EOF' > shell/sh6.c && X/* MS-DOS SHELL - Data Declarations 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: sh6.c 1.1 90/01/25 13:42:04 MS_user Exp $ X * X * $Log: sh6.c $ X * Revision 1.1 90/01/25 13:42:04 MS_user X * Initial revision X * X */ X X#include <sys/types.h> X#include <stddef.h> X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include <stdlib.h> X#include <limits.h> X#include <unistd.h> X#include "sh.h" X Xchar *Copy_Right1 = "MS-DOS SH Version 1.4\341 (DOS %d.%d)\n"; Xchar *Copy_Right2 = "Copyright (c) Data Logic Ltd and Charles Forsyth 1990\n"; Xchar **dolv; /* Parameter array */ Xint dolc; /* Number of entries in parameter array */ Xint exstat; /* Exit status */ Xchar gflg; Xint fn_area_number = -1; /* Next function area number */ Xint talking; /* interactive (talking-type wireless) */ Xint execflg; /* Exec mode */ Xint multiline; /* \n changed to ; */ Xint Current_Event = 0; /* Current history event */ Xint *failpt; /* Current fail point jump address */ Xint *errpt; /* Current error point jump address */ X /* Swap mode */ Xint Swap_Mode = SWAP_EXPAND | SWAP_DISK; XBreak_C *Break_List; /* Break list for FOR/WHILE */ XBreak_C *Return_List; /* Return list for RETURN */ XBreak_C *SShell_List; /* SubShell list for EXIT */ Xbool level0 = FALSE; /* Level Zero flag */ Xbool r_flag = FALSE; /* Restricted shell */ X /* History processing enabled flag */ Xbool History_Enabled = FALSE; XFun_Ops *fun_list = (Fun_Ops *)NULL; /* Function list */ XSave_IO *SSave_IO; /* Save IO array */ Xint NSave_IO_E = 0; /* Number of entries in Save IO array */ Xint MSave_IO_E = 0; /* Max Number of entries in SSave_IO */ XS_SubShell *SubShells; /* Save Vars array */ Xint NSubShells = 0; /* Number of entries in SubShells */ Xint MSubShells = 0; /* Max Number of entries in SubShells */ X XWord_B *wdlist; /* Current Word List */ XWord_B *iolist; /* Current IO List */ Xlong ourtrap = 0L; /* Signal detected */ Xint trapset; /* Trap pending */ Xint yynerrs; /* yacc errors detected */ Xint Execute_stack_depth; /* execute function recursion */ X /* depth */ XVar_List *vlist = (Var_List *)NULL; /* dictionary */ SHAR_EOF echo "End of part 3" echo "File shell/sh6.c is continued in part 4" echo "4" > s2_seq_.tmp exit 0 -- Regards, Ian Stewartson Data Logic Ltd.