home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / sh_dos / part05 < prev    next >
Text File  |  1990-02-13  |  81KB  |  4,242 lines

  1. Newsgroups: comp.sources.misc
  2. organization: ITM Sector, Data Logic Ltd. (A Raytheon Company)
  3. From: istewart@datlog.co.uk (Ian Stewartson)
  4. subject: v10i057: MSDOS Shell (sh) Implementation - Part 04 of 05
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 10, Issue 57
  8. Submitted-by: istewart@datlog.co.uk (Ian Stewartson)
  9. Archive-name: sh_dos/part05
  10.  
  11. #!/bin/sh
  12. # this is part 4 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file shell/sh6.c continued
  15. #
  16. CurArch=4
  17. if test ! -r s2_seq_.tmp
  18. then echo "Please unpack part 1 first!"
  19.      exit 1; fi
  20. ( read Scheck
  21.   if test "$Scheck" != $CurArch
  22.   then echo "Please unpack part $Scheck next!"
  23.        exit 1;
  24.   else exit 0; fi
  25. ) < s2_seq_.tmp || exit 1
  26. echo "x - Continuing file shell/sh6.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> shell/sh6.c
  28. XVar_List    *path;        /* search path for commands        */
  29. XVar_List    *ps1;        /* Prompt 1                */
  30. XVar_List    *ps2;        /* Prompt 2                */
  31. XVar_List    *C_dir;        /* Current directory            */
  32. Xchar        *last_prompt;    /* Last prompt output            */
  33. XVar_List    *ifs;        /* Inter-field separator        */
  34. Xchar        *home = "HOME";
  35. Xchar        *shell = "SHELL";
  36. Xchar        *history_file = "HISTFILE";
  37. Xchar        *hsymbol = "#";
  38. Xchar        *msymbol = "-";
  39. Xchar        *spcl2 = "$`'\"";
  40. X
  41. X                /* I/O stacks                */
  42. XIO_Args        ioargstack[NPUSH];
  43. XIO_State    iostack[NPUSH];
  44. X
  45. X                /* Temporary I/O argument        */
  46. XIO_Args        temparg = {
  47. X    (char *)NULL,        /* Word                    */
  48. X    (char **)NULL,        /* Word list                */
  49. X    0,                /* File descriptor            */
  50. X    AFID_NOBUF,            /* Buffer id                */
  51. X    0L,                /* File position            */
  52. X    (IO_Buf *)NULL        /* Buffer                */
  53. X};
  54. X
  55. Xint        areanum;    /* Current allocation area        */
  56. Xint        inparse;    /* In parser flag            */
  57. Xlong        flags = 0L;    /* Command line flags            */
  58. Xchar        *null = "";
  59. X
  60. X                /* Current environment            */
  61. XEnviron    e = {
  62. X    (char *)NULL,        /* Current line buffer            */
  63. X    (char *)NULL,        /* Current pointer in line        */
  64. X    (char *)NULL,        /* End of line pointer            */
  65. X    iostack,            /* I/O Stack pointers            */
  66. X    iostack - 1,
  67. X    (int *)NULL,
  68. X    FDBASE,            /* Base file handler            */
  69. X    (Environ *)NULL        /* Previous Env pointer            */
  70. X};
  71. SHAR_EOF
  72. echo "File shell/sh6.c is complete"
  73. chmod 0644 shell/sh6.c || echo "restore of shell/sh6.c fails"
  74. set `wc -c shell/sh6.c`;Sum=$1
  75. if test "$Sum" != "3994"
  76. then echo original size 3994, current size $Sum;fi
  77. echo "x - extracting shell/sh7.c (Text)"
  78. sed 's/^X//' << 'SHAR_EOF' > shell/sh7.c &&
  79. X/* MS-DOS SHELL - Internal Command Processing
  80. X *
  81. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  82. X *
  83. X * This code is based on (in part) the shell program written by Charles
  84. X * Forsyth and is subject to the following copyright restrictions:
  85. X *
  86. X * 1.  Redistribution and use in source and binary forms are permitted
  87. X *     provided that the above copyright notice is duplicated in the
  88. X *     source form and the copyright notice in file sh6.c is displayed
  89. X *     on entry to the program.
  90. X *
  91. X * 2.  The sources (or parts thereof) or objects generated from the sources
  92. X *     (or parts of sources) cannot be sold under any circumstances.
  93. X *
  94. X *    $Header: sh7.c 1.1 90/01/29 17:46:25 MS_user Exp $
  95. X *
  96. X *    $Log:    sh7.c $
  97. X * Revision 1.1  90/01/29  17:46:25  MS_user
  98. X * Initial revision
  99. X * 
  100. X * 
  101. X */
  102. X
  103. X#include <sys/types.h>
  104. X#include <sys/stat.h>
  105. X#include <stdio.h>
  106. X#include <process.h>
  107. X#include <dos.h>
  108. X#include <signal.h>
  109. X#include <errno.h>
  110. X#include <setjmp.h>
  111. X#include <ctype.h>
  112. X#include <string.h>
  113. X#include <unistd.h>
  114. X#include <stdlib.h>
  115. X#include <fcntl.h>
  116. X#include <limits.h>
  117. X#include <stdarg.h>
  118. X#include "sh.h"
  119. X
  120. X#define    SECS        60L
  121. X#define    MINS        3600L
  122. X#define IS_OCTAL(a)    (((a) >= '0') && ((a) <= '7'))
  123. X
  124. X/* Definitions for test */
  125. X
  126. X#define END_OF_INPUT    0
  127. X#define FILE_READABLE    1
  128. X#define FILE_WRITABLE    2
  129. X#define FILE_REGULAR    3
  130. X#define FILE_DIRECTORY    4
  131. X#define FILE_NONZERO    5
  132. X#define FILE_TERMINAL    6
  133. X#define STRING_ZERO    7
  134. X#define STRING_NONZERO    8
  135. X#define STRING_EQUAL    9
  136. X#define STRING_NOTEQUAL    10
  137. X#define NUMBER_EQUAL    11
  138. X#define NUMBER_NOTEQUAL    12
  139. X#define NUMBER_EQ_GREAT    13
  140. X#define NUMBER_GREATER    14
  141. X#define NUMBER_EQ_LESS    15
  142. X#define NUMBER_LESS    16
  143. X#define UNARY_NOT    17
  144. X#define BINARY_AND    18
  145. X#define BINARY_OR    19
  146. X#define LPAREN        20
  147. X#define RPAREN        21
  148. X#define OPERAND        22
  149. X#define FILE_EXECUTABLE    23
  150. X#define FILE_USER    24
  151. X#define FILE_GROUP    25
  152. X#define FILE_TEXT    26
  153. X#define FILE_BLOCK    27
  154. X#define FILE_CHARACTER    28
  155. X#define FILE_FIFO    29
  156. X
  157. X#define UNARY_OP    1
  158. X#define BINARY_OP    2
  159. X#define B_UNARY_OP    3
  160. X#define B_BINARY_OP    4
  161. X#define PAREN        5
  162. X
  163. Xstatic struct test_op {
  164. X    char    *op_text;
  165. X    short     op_num;
  166. X    short     op_type;
  167. X} test_ops[] = {
  168. X    {"-r",    FILE_READABLE,        UNARY_OP},
  169. X    {"-w",    FILE_WRITABLE,        UNARY_OP},
  170. X    {"-x",    FILE_EXECUTABLE,    UNARY_OP},
  171. X    {"-f",    FILE_REGULAR,        UNARY_OP},
  172. X    {"-d",    FILE_DIRECTORY,        UNARY_OP},
  173. X    {"-s",    FILE_NONZERO,        UNARY_OP},
  174. X    {"-t",    FILE_TERMINAL,        UNARY_OP},
  175. X    {"-z",    STRING_ZERO,        UNARY_OP},
  176. X    {"-n",    STRING_NONZERO,        UNARY_OP},
  177. X    {"=",    STRING_EQUAL,        BINARY_OP},
  178. X    {"!=",    STRING_NOTEQUAL,    BINARY_OP},
  179. X    {"-eq",    NUMBER_EQUAL,        BINARY_OP},
  180. X    {"-ne",    NUMBER_NOTEQUAL,    BINARY_OP},
  181. X    {"-ge",    NUMBER_EQ_GREAT,    BINARY_OP},
  182. X    {"-gt",    NUMBER_GREATER,        BINARY_OP},
  183. X    {"-le",    NUMBER_EQ_LESS,        BINARY_OP},
  184. X    {"-lt",    NUMBER_LESS,        BINARY_OP},
  185. X    {"!",    UNARY_NOT,        B_UNARY_OP},
  186. X    {"-a",    BINARY_AND,        B_BINARY_OP},
  187. X    {"-o",    BINARY_OR,        B_BINARY_OP},
  188. X    {"(",    LPAREN,            PAREN},
  189. X    {")",    RPAREN,            PAREN},
  190. X#ifdef S_IFCHR
  191. X    {"-c",    FILE_CHARACTER,        UNARY_OP},
  192. X#endif
  193. X#ifdef S_IFBLK
  194. X    {"-b",    FILE_BLOCK,        UNARY_OP},
  195. X#endif
  196. X#ifdef S_ISUID
  197. X    {"-u",    FILE_USER,        UNARY_OP},
  198. X#endif
  199. X#ifdef S_ISGID
  200. X    {"-g",    FILE_GROUP,        UNARY_OP},
  201. X#endif
  202. X#ifdef S_ISVTX
  203. X    {"-k",    FILE_TEXT,        UNARY_OP},
  204. X#endif
  205. X#ifdef S_IFIFO
  206. X    {"-p",    FILE_FIFO,        UNARY_OP},
  207. X#endif
  208. X    {(char *)NULL,    NULL,        NULL}
  209. X};
  210. X
  211. Xstatic int        expr (int);
  212. Xstatic int        bexpr (int);
  213. Xstatic int        primary (int);
  214. Xstatic int        lex (char *);
  215. Xstatic long        num (char *);
  216. Xstatic void        syntax (void);
  217. Xstatic int        dolabel (C_Op *);
  218. Xstatic int        dochdir (C_Op *);
  219. Xstatic int        dodrive (C_Op *);
  220. Xstatic int        doshift (C_Op *);
  221. Xstatic int        doumask (C_Op *);
  222. Xstatic int        dodot (C_Op *);
  223. Xstatic int        doecho (C_Op *);
  224. Xstatic int        dogetopt (C_Op *);
  225. Xstatic int        dopwd (C_Op *);
  226. Xstatic int        doswap (C_Op *);
  227. Xstatic int        dounset (C_Op *);
  228. Xstatic int        dotype (C_Op *);
  229. Xstatic int        dotest (C_Op *);
  230. Xstatic int        dover (C_Op *);
  231. Xstatic int        doread (C_Op *);
  232. Xstatic int        doeval (C_Op *);
  233. Xstatic int        dotrap (C_Op *);
  234. Xstatic int        getsig (char *);
  235. Xstatic int        dobreak (C_Op *);
  236. Xstatic int        docontinue (C_Op *);
  237. Xstatic int        brkcontin (char *, int);
  238. Xstatic int        doexit (C_Op *);
  239. Xstatic int        doexec (C_Op *);
  240. Xstatic int        doreturn (C_Op *);
  241. Xstatic int        doexport (C_Op *);
  242. Xstatic int        domsdos (C_Op *);
  243. Xstatic int        doreadonly (C_Op *);
  244. Xstatic int        doset (C_Op *);
  245. Xstatic int        dohistory (C_Op *);
  246. Xstatic void        setsig (int, int (*)());
  247. Xstatic int        rdexp (char **, int, char *);
  248. Xstatic void        v1_putsn (char *, int);
  249. X
  250. Xstatic char        **test_alist;
  251. Xstatic struct test_op    *test_op;
  252. Xstatic jmp_buf        test_jmp;
  253. X
  254. X/*
  255. X * built-in commands: doX
  256. X */
  257. X
  258. Xstatic int    dolabel (t)
  259. XC_Op        *t;
  260. X{
  261. X    return 0;
  262. X}
  263. X
  264. X/*
  265. X * Getopt - split arguments.  getopts pattern args
  266. X */
  267. X
  268. Xstatic int    dogetopt (t)
  269. Xregister C_Op    *t;
  270. X{
  271. X    int            argc;
  272. X    char        **argv = t->words;
  273. X    int            c;
  274. X
  275. X/* Count arguments */
  276. X
  277. X    optind = 1;                /* Reset the optind flag    */
  278. X    opterr = 1;                /* Reset the error flag        */
  279. X
  280. X    for (argc = 0; t->words[argc] != (char *)NULL; argc++);
  281. X
  282. X    if (argc < 2)
  283. X    {
  284. X    S_puts ("usage: getopt legal-args $*\n");
  285. X    return 2;
  286. X    }
  287. X
  288. X    argc -= 2;
  289. X    argv += 2;
  290. X
  291. X/* Scan each argument */
  292. X
  293. X    while ((c = getopt (argc, argv, t->words[1])) != EOF)
  294. X    {
  295. X    if (c == '?')
  296. X        return 2;
  297. X
  298. X    v1printf ("-%c ", c);
  299. X
  300. X/* Check for addition parameter */
  301. X
  302. X    if (*(strchr (t->words[1], c) + 1) == ':')
  303. X    {
  304. X        v1_puts (optarg);
  305. X        v1_putc (SP);
  306. X    }
  307. X    }
  308. X
  309. X    v1_puts ("-- ");
  310. X    argv += optind;
  311. X
  312. X    while (optind++ < argc)
  313. X    {
  314. X    v1_puts (*argv++);
  315. X    v1_putc ((char)((optind == argc) ? NL : SP));
  316. X    }
  317. X
  318. X    return 0;
  319. X}
  320. X
  321. X/*
  322. X * Echo the parameters
  323. X */
  324. X
  325. Xstatic int    doecho (t)
  326. Xregister C_Op    *t;
  327. X{
  328. X    int        n = 1;
  329. X    int        no_eol = 0;        /* No EOL            */
  330. X    char    *ip;            /* Input pointer        */
  331. X    int        c_val;            /* Current character        */
  332. X    char    c;
  333. X    bool    end_s;
  334. X    char    *cp = e.linep;
  335. X                    /* Always leave room for NL    */
  336. X    char    *ep = &e.linep[LINE_MAX - 3];
  337. X
  338. X    while ((ip = t->words[n++]) != (char *)NULL)
  339. X    {
  340. X    if ((n == 2) && (strcmp (ip, "-n") == 0))
  341. X    {
  342. X        no_eol++;
  343. X        continue;
  344. X    }
  345. X
  346. X/* Process the string */
  347. X
  348. X    end_s = FALSE;
  349. X
  350. X    do
  351. X    {
  352. X
  353. X/* Any special character processing ? */
  354. X
  355. X        if ((c = *(ip++)) == '\\')
  356. X        {
  357. X        if ((c_val = Process_Escape (&ip)) == -1)
  358. X        {
  359. X            no_eol = 1;
  360. X            continue;
  361. X        }
  362. X
  363. X        c = (char)c_val;
  364. X        }
  365. X
  366. X/* End of string - check to see if a space if required */
  367. X
  368. X        else if (c == 0)
  369. X        {
  370. X        end_s = TRUE;
  371. X
  372. X        if (t->words[n] != (char *)NULL)
  373. X            c = SP;
  374. X
  375. X        else
  376. X            continue;
  377. X        }
  378. X
  379. X/* Output the character */
  380. X
  381. X        if (cp < ep)
  382. X        *(cp++) = c;
  383. X
  384. X        else
  385. X        {
  386. X        v1_putsn (e.linep, (int)(cp - e.linep));
  387. X        cp = e.linep;
  388. X        }
  389. X
  390. X    } while (!end_s);
  391. X    }
  392. X
  393. X/* Is EOL required ? */
  394. X
  395. X    if (!no_eol)
  396. X    *(cp++) = NL;
  397. X
  398. X/* Flush buffer */
  399. X
  400. X    if ((n = (int)(cp - e.linep)))
  401. X    v1_putsn (e.linep, n);
  402. X
  403. X    return 0;
  404. X}
  405. X
  406. X/*
  407. X * Process_Escape - Convert an escaped character to a binary value.
  408. X *
  409. X * Returns the binary value and updates the string pointer.
  410. X */
  411. X
  412. Xint    Process_Escape (cp)
  413. Xchar    **cp;                    /* Pointer to character */
  414. X{
  415. X    int        c_val = **cp;            /* Current character    */
  416. X
  417. X    if (c_val)
  418. X        (*cp)++;
  419. X
  420. X/* Process escaped characters */
  421. X
  422. X    switch (c_val)
  423. X    {
  424. X        case 'b':            /* Backspace                    */
  425. X            return 0x08;
  426. X
  427. X        case 'f':            /* Form Feed                    */
  428. X            return 0x0c;
  429. X
  430. X        case 'v':            /* Vertical Tab                 */
  431. X            return 0x0b;
  432. X
  433. X        case 'n':            /* New Line                     */
  434. X            return 0x0a;
  435. X
  436. X        case 'r':            /* Carriage return              */
  437. X            return 0x0d;
  438. X
  439. X        case 't':            /* Forward tab                  */
  440. X        return 0x09;
  441. X
  442. X        case '\\':            /* Backslash                    */
  443. X        return '\\';
  444. X
  445. X        case 'c':            /* no eol            */
  446. X        return -1;
  447. X    }
  448. X
  449. X/* Check for an octal string */
  450. X
  451. X    if ((c_val >= 0) && (c_val < 8))
  452. X    {
  453. X    while ((IS_OCTAL (**cp)))
  454. X        c_val = (c_val * 8) + *((*cp)++) - '0';
  455. X
  456. X    return c_val;
  457. X    }
  458. X
  459. X    return c_val;
  460. X}
  461. X
  462. X/*
  463. X * Display the current version
  464. X */
  465. X
  466. Xstatic int    dover (t)
  467. XC_Op        *t;
  468. X{
  469. X    v1printf (Copy_Right1, _osmajor, _osminor);
  470. X    v1a_puts (Copy_Right2);
  471. X    return 0;
  472. X}
  473. X
  474. Xstatic char    *swap_device[] = {"disk", "extend", "expand"};
  475. X
  476. X/*
  477. X * Modify swapping information: swap options
  478. X */
  479. X
  480. Xstatic int    doswap (t)
  481. Xregister C_Op    *t;
  482. X{
  483. X    register int    n = 1;
  484. X    char        *cp;
  485. X
  486. X/* Display current values ? */
  487. X
  488. X    if (t->words[1] == (char *)NULL)
  489. X    {
  490. X    if (Swap_Mode == SWAP_OFF)
  491. X        v1a_puts ("Swapping disabled");
  492. X
  493. X    else
  494. X    {
  495. X        register int    j;
  496. X
  497. X        v1_puts ("Swap devices: ");
  498. X
  499. X        for (j = 0, n = 1; j < 3; ++j, n <<= 1)
  500. X        {
  501. X        if (Swap_Mode & n)
  502. X        {
  503. X            v1printf ("%s ", swap_device[j]);
  504. X
  505. X            if (n == SWAP_EXTEND)
  506. X            v1printf ("(0x%.6lx) ", SW_EMstart);
  507. X        }
  508. X        }
  509. X
  510. X        v1_putc (NL);
  511. X    }
  512. X
  513. X    return 0;
  514. X    }
  515. X
  516. X/* Set up new values */
  517. X
  518. X    Swap_Mode = SWAP_OFF;
  519. X
  520. X    while ((cp = t->words[n++]) != (char *)NULL)
  521. X    {
  522. X    if (strcmp (cp, "off") == 0)
  523. X        Swap_Mode = SWAP_OFF;
  524. X
  525. X    else if (strcmp (cp, "on") == 0)
  526. X        Swap_Mode = SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND;
  527. X
  528. X/* Scan for valid arguments */
  529. X
  530. X    else
  531. X    {
  532. X        register int    j, k;
  533. X
  534. X        for (j = 0, k = 1; j < 3; ++j, k <<= 1)
  535. X        {
  536. X        if (strcmp (cp, swap_device[j]) == 0)
  537. X        {
  538. X            Swap_Mode |= k;
  539. X
  540. X/* If extended memory, they can specify the start address as a hex number */
  541. X
  542. X            if (k == SWAP_EXTEND)
  543. X            {
  544. X            char    *sp;
  545. X            long    start;
  546. X
  547. X/* Check for not changed */
  548. X
  549. X            if ((sp = t->words[n]) == (char *)NULL)
  550. X                break;
  551. X
  552. X/* Convert hex number */
  553. X
  554. X            start = strtol (sp, &sp, 16);
  555. X
  556. X/* If not completely a hex number, ignore */
  557. X
  558. X            if (*sp)
  559. X                break;
  560. X
  561. X/* Set used and saved new value */
  562. X
  563. X            SW_EMstart = start;
  564. X            ++n;
  565. X
  566. X            if ((SW_EMstart < 0x100000L) ||
  567. X                (SW_EMstart > 0xf00000L))
  568. X                SW_EMstart = 0x100000L;
  569. X
  570. X            v1printf ("Extend memory start set to 0x%.6lx\n",
  571. X                  SW_EMstart);
  572. X            }
  573. X
  574. X            break;
  575. X        }
  576. X        }
  577. X    }
  578. X    }
  579. X
  580. X    return 0;
  581. X}
  582. X
  583. X/*
  584. X * Output the current path: pwd
  585. X */
  586. X
  587. Xstatic int    dopwd (t)
  588. Xregister C_Op    *t;
  589. X{
  590. X    v1a_puts (C_dir->value);
  591. X    return 0;
  592. X}
  593. X
  594. X/*
  595. X * Unset a variable: unset <flag..> <variable name...>
  596. X */
  597. X
  598. Xstatic int    dounset (t)
  599. Xregister C_Op    *t;
  600. X{
  601. X    register int    n = 1;
  602. X
  603. X    while (t->words[n] != (char *)NULL)
  604. X        unset (t->words[n++], FALSE);
  605. X
  606. X    return 0;
  607. X}
  608. X
  609. X/* Delete a variable or function.  If all is set, system variables can be
  610. X * deleted.  This is used to delete the trap functions
  611. X */
  612. X
  613. Xvoid        unset (cp, all)
  614. Xregister char    *cp;
  615. Xbool        all;
  616. X{
  617. X    register Var_List        *vp;
  618. X    register Var_List        *pvp;
  619. X
  620. X/* Unset a flag */
  621. X
  622. X    if (*cp == '-')
  623. X    {
  624. X    while (*(++cp) != 0)
  625. X    {
  626. X        if (islower (*cp))
  627. X        FL_CLEAR (*cp);
  628. X    }
  629. X
  630. X    setdash ();
  631. X    return;
  632. X    }
  633. X
  634. X/* Ok - unset a variable and not a local value */
  635. X
  636. X    if (!all && !(isalpha (*cp)))
  637. X    return;
  638. X
  639. X/* Check in list */
  640. X
  641. X    pvp = (Var_List *)NULL;
  642. X
  643. X    for (vp = vlist; (vp != (Var_List *)NULL) && !eqname (vp->name, cp);
  644. X     vp = vp->next)
  645. X    pvp = vp;
  646. X
  647. X/* If not found, delete the function if it exists */
  648. X
  649. X    if (vp == (Var_List *)NULL)
  650. X    {
  651. X    Fun_Ops     *fp;
  652. X
  653. X    if ((fp = Fun_Search (cp)) != (Fun_Ops *)NULL)
  654. X        Save_Function (fp->tree, TRUE);
  655. X
  656. X    return;
  657. X    }
  658. X
  659. X/* Error if read-only */
  660. X
  661. X    if (vp->status & (RONLY | PONLY))
  662. X    {
  663. X    if ((cp = strchr (vp->name, '=')) != (char *)NULL)
  664. X        *cp = 0;
  665. X
  666. X    S_puts (vp->name);
  667. X
  668. X    if (cp != (char *)NULL)
  669. X        *cp = '=';
  670. X
  671. X    S_puts ((vp->status & PONLY) ? ": cannot unset\n" : " is read-only\n");
  672. X    return;
  673. X    }
  674. X
  675. X/* Delete it */
  676. X
  677. X    if (vp->status & GETCELL)
  678. X    DELETE (vp->name);
  679. X
  680. X    if (pvp == (Var_List *)NULL)
  681. X    vlist = vp->next;
  682. X
  683. X    else
  684. X    pvp->next = vp->next;
  685. X
  686. X    DELETE (vp);
  687. X}
  688. X
  689. X/*
  690. X * Execute a test: test <arguments>
  691. X */
  692. X
  693. Xstatic int    dotest (t)
  694. Xregister C_Op    *t;
  695. X{
  696. X    int        st = 0;
  697. X
  698. X    if (*(test_alist = &t->words[1]) == (char *)NULL)
  699. X    return 1;
  700. X
  701. X/* If [ <arguments> ] form, check for end ] and remove it */
  702. X
  703. X    if (strcmp (t->words[0], "[") == 0)
  704. X    {
  705. X    while (t->words[++st] != (char *)NULL)
  706. X        ;
  707. X
  708. X    if (strcmp (t->words[--st], "]") != 0)
  709. X    {
  710. X        print_error ("test: missing ']'\n");
  711. X        return 1;
  712. X    }
  713. X
  714. X    else
  715. X        t->words[st] = (char *)NULL;
  716. X    }
  717. X
  718. X/* Set abort address */
  719. X
  720. X    if (setjmp (test_jmp))
  721. X    return 1;
  722. X
  723. X    st = !expr (lex (*test_alist));
  724. X
  725. X    if (*(++test_alist) != (char *)NULL)
  726. X    syntax ();
  727. X
  728. X    return (st);
  729. X}
  730. X
  731. Xstatic int    expr (n)
  732. Xint        n;
  733. X{
  734. X    int        res;
  735. X
  736. X    if (n == END_OF_INPUT)
  737. X    syntax ();
  738. X
  739. X    res = bexpr (n);
  740. X
  741. X    if (lex (*(++test_alist)) == BINARY_OR)
  742. X    return expr (lex (*(++test_alist))) || res;
  743. X
  744. X    test_alist--;
  745. X    return res;
  746. X}
  747. X
  748. Xstatic int    bexpr (n)
  749. Xint        n;
  750. X{
  751. X    int res;
  752. X
  753. X    if (n == END_OF_INPUT)
  754. X    syntax ();
  755. X
  756. X    res = primary (n);
  757. X    if (lex (*(++test_alist)) == BINARY_AND)
  758. X    return bexpr (lex (*(++test_alist))) && res;
  759. X
  760. X    test_alist--;
  761. X    return res;
  762. X}
  763. X
  764. Xstatic int    primary (n)
  765. Xint        n;
  766. X{
  767. X    register char    *opnd1, *opnd2;
  768. X    struct stat        s;
  769. X    int            res;
  770. X
  771. X    if (n == END_OF_INPUT)
  772. X    syntax ();
  773. X
  774. X    if (n == UNARY_NOT)
  775. X    return !expr (lex (*(++test_alist)));
  776. X
  777. X    if (n == LPAREN)
  778. X    {
  779. X    res = expr (lex (*(++test_alist)));
  780. X
  781. X    if (lex (*(++test_alist)) != RPAREN)
  782. X        syntax ();
  783. X
  784. X    return res;
  785. X    }
  786. X
  787. X    if (n == OPERAND)
  788. X    {
  789. X    opnd1 = *test_alist;
  790. X    (void) lex (*(++test_alist));
  791. X
  792. X    if ((test_op != (C_Op *)NULL) && test_op->op_type == BINARY_OP)
  793. X    {
  794. X        struct test_op *op = test_op;
  795. X
  796. X        if ((opnd2 = *(++test_alist)) == (char *)NULL)
  797. X        syntax ();
  798. X
  799. X        switch (op->op_num)
  800. X        {
  801. X        case STRING_EQUAL:
  802. X            return strcmp (opnd1, opnd2) == 0;
  803. X
  804. X        case STRING_NOTEQUAL:
  805. X            return strcmp (opnd1, opnd2) != 0;
  806. X
  807. X        case NUMBER_EQUAL:
  808. X            return num (opnd1) == num (opnd2);
  809. X
  810. X        case NUMBER_NOTEQUAL:
  811. X            return num (opnd1) != num (opnd2);
  812. X
  813. X        case NUMBER_EQ_GREAT:
  814. X            return num (opnd1) >= num (opnd2);
  815. X
  816. X        case NUMBER_GREATER:
  817. X            return num (opnd1) > num (opnd2);
  818. X
  819. X        case NUMBER_EQ_LESS:
  820. X            return num (opnd1) <= num (opnd2);
  821. X
  822. X        case NUMBER_LESS:
  823. X            return num (opnd1) < num (opnd2);
  824. X        }
  825. X    }
  826. X
  827. X    test_alist--;
  828. X    return strlen (opnd1) > 0;
  829. X    }
  830. X
  831. X/* unary expression */
  832. X
  833. X    if (test_op->op_type != UNARY_OP || *++test_alist == 0)
  834. X    syntax ();
  835. X
  836. X    switch (n)
  837. X    {
  838. X    case STRING_ZERO:
  839. X        return strlen (*test_alist) == 0;
  840. X
  841. X    case STRING_NONZERO:
  842. X        return strlen (*test_alist) != 0;
  843. X
  844. X    case FILE_READABLE:
  845. X        return access (*test_alist, R_OK) == 0;
  846. X
  847. X    case FILE_WRITABLE:
  848. X        return access (*test_alist, W_OK) == 0;
  849. X
  850. X    case FILE_EXECUTABLE:
  851. X        return access (*test_alist, X_OK) == 0;
  852. X
  853. X    case FILE_REGULAR:
  854. X        return stat (*test_alist, &s) == 0 && S_ISREG(s.st_mode);
  855. X
  856. X    case FILE_DIRECTORY:
  857. X        return stat (*test_alist, &s) == 0 && S_ISDIR(s.st_mode);
  858. X
  859. X    case FILE_NONZERO:
  860. X        return stat (*test_alist, &s) == 0 && (s.st_size > 0L);
  861. X
  862. X    case FILE_TERMINAL:
  863. X        return isatty ((int)num (*test_alist));
  864. X
  865. X#ifdef S_ISUID
  866. X    case FILE_USER:
  867. X        return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISUID);
  868. X#endif
  869. X
  870. X#ifdef S_ISGID
  871. X    case FILE_GROUP:
  872. X        return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISGID);
  873. X#endif
  874. X
  875. X#ifdef S_ISVTX
  876. X    case FILE_TEXT:
  877. X        return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISVTX);
  878. X#endif
  879. X
  880. X#ifdef S_IFBLK
  881. X    case FILE_BLOCK:
  882. X        return stat (*test_alist, &s) == 0 && S_ISBLK(s.st_mode);
  883. X#endif
  884. X
  885. X#ifdef S_IFCHR
  886. X    case FILE_CHARACTER:
  887. X        return stat (*test_alist, &s) == 0 && S_ISCHR(s.st_mode);
  888. X#endif
  889. X
  890. X#ifdef S_IFIFO
  891. X    case FILE_FIFO:
  892. X        return stat (*test_alist, &s) == 0 && S_ISFIFO(s.st_mode);
  893. X#endif
  894. X    }
  895. X}
  896. X
  897. Xstatic int    lex (s)
  898. Xregister char    *s;
  899. X{
  900. X    register struct test_op    *op = test_ops;
  901. X
  902. X    if (s == (char *)NULL)
  903. X    return END_OF_INPUT;
  904. X
  905. X    while (op->op_text)
  906. X    {
  907. X    if (strcmp (s, op->op_text) == 0)
  908. X    {
  909. X        test_op = op;
  910. X        return op->op_num;
  911. X    }
  912. X
  913. X    op++;
  914. X    }
  915. X
  916. X    test_op = (struct test_op *)NULL;
  917. X    return OPERAND;
  918. X}
  919. X
  920. X/*
  921. X * Get a long numeric value
  922. X */
  923. X
  924. Xstatic long    num (s)
  925. Xregister char    *s;
  926. X{
  927. X    char    *ep;
  928. X    long    l = strtol (s, &ep, 10);
  929. X
  930. X    if (!*s || *ep)
  931. X    syntax ();
  932. X
  933. X    return l;
  934. X}
  935. X
  936. X/*
  937. X * test syntax error - abort
  938. X */
  939. X
  940. Xstatic void    syntax ()
  941. X{
  942. X    print_error ("test: syntax error\n");
  943. X    longjmp (test_jmp, 1);
  944. X}
  945. X
  946. X/*
  947. X * Select a new drive: x:
  948. X *
  949. X * Select the drive, get the current directory and check that we have
  950. X * actually selected the drive
  951. X */
  952. X
  953. Xstatic int    dodrive (t)
  954. Xregister C_Op    *t;
  955. X{
  956. X    unsigned int    cdrive;
  957. X    unsigned int    ndrive = tolower (**t->words) - 'a' + 1;
  958. X
  959. X    _dos_setdrive (ndrive, &cdrive);
  960. X    Getcwd ();
  961. X    _dos_getdrive (&cdrive);
  962. X    return (ndrive == cdrive) ? 0 : 1;
  963. X}
  964. X
  965. X/*
  966. X * Select a new directory: cd
  967. X */
  968. X
  969. Xstatic int    dochdir (t)
  970. Xregister C_Op    *t;
  971. X{
  972. X    char        *p;
  973. X    char        *nd;
  974. X    register char    *cp;
  975. X    int            first = 0;
  976. X    unsigned int    dummy;
  977. X    unsigned int    cdrive;
  978. X
  979. X/* If restricted shell - illegal */
  980. X
  981. X    if (check_rsh ("cd"))
  982. X    return 1;
  983. X
  984. X/* Use default ? */
  985. X
  986. X    if (((p = t->words[1]) == (char *)NULL) &&
  987. X    ((p = lookup (home, FALSE)->value) == null))
  988. X    {
  989. X    print_error ("cd: no home directory\n");
  990. X    return 1;
  991. X    }
  992. X
  993. X/* Save the current drive */
  994. X
  995. X    _dos_getdrive (&cdrive);
  996. X
  997. X/* Scan for the directory.  If there is not a / or : at start, use the
  998. X * CDPATH variable
  999. X */
  1000. X
  1001. X    cp = (*p == '/') ? null : lookup ("CDPATH", FALSE)->value;
  1002. X    cp = (*(p + 1) == ':') ? null : cp;
  1003. X
  1004. X    do
  1005. X    {
  1006. X    cp = path_append (cp, p, e.linep);
  1007. X
  1008. X/* Check for new disk drive */
  1009. X
  1010. X    nd = e.linep;
  1011. X
  1012. X    if (*(nd+ 1) == ':')
  1013. X    {
  1014. X        _dos_setdrive (tolower (*nd) - 'a' + 1, &dummy);
  1015. X        nd += 2;
  1016. X    }
  1017. X
  1018. X/* Was the change successful? */
  1019. X
  1020. X    if ((!*nd) || (chdir (nd) == 0))
  1021. X    {
  1022. X
  1023. X/* OK - reset the current directory (in the shell) and display the new
  1024. X * path if appropriate
  1025. X */
  1026. X
  1027. X        Getcwd ();
  1028. X
  1029. X        if (first || (strchr (p, '/') != (char *)NULL))
  1030. X        dopwd (t);
  1031. X
  1032. X        return 0;
  1033. X    }
  1034. X
  1035. X    first = 1;
  1036. X
  1037. X    } while (cp != (char *)NULL);
  1038. X
  1039. X/* Restore our original drive and restore directory info */
  1040. X
  1041. X    _dos_setdrive (cdrive, &dummy);
  1042. X    Getcwd ();
  1043. X
  1044. X    print_error ("%s: bad directory\n", p);
  1045. X    return 1;
  1046. X}
  1047. X
  1048. X/*
  1049. X * Extract the next path from a string and build a new path from the
  1050. X * extracted path and a file name
  1051. X */
  1052. Xchar        *path_append (s1, s2, si)
  1053. Xregister char    *s1;            /* Path string            */
  1054. Xregister char    *s2;            /* File name string        */
  1055. Xchar        *si;            /* Output path            */
  1056. X{
  1057. X    register char    *s;
  1058. X
  1059. X    s = si;
  1060. X
  1061. X    while (*s1 && *s1 != ';')
  1062. X    *s++ = *s1++;
  1063. X
  1064. X    if ((si != s) && (*(s - 1) != '/'))
  1065. X    *s++ = '/';
  1066. X
  1067. X    *s = '\0';
  1068. X
  1069. X    if (s2 != (char *)NULL)
  1070. X    strcpy (s, s2);
  1071. X
  1072. X    return (*s1 ? ++s1 : (char *)NULL);
  1073. X}
  1074. X
  1075. X/*
  1076. X * Execute a shift command: shift <n>
  1077. X */
  1078. X
  1079. Xstatic int    doshift (t)
  1080. Xregister C_Op    *t;
  1081. X{
  1082. X    register int    n;
  1083. X
  1084. X    n = (t->words[1] != (char *)NULL) ? getn (t->words[1]) : 1;
  1085. X
  1086. X    if (dolc < n)
  1087. X    {
  1088. X    print_error ("sh: nothing to shift\n");
  1089. X    return 1;
  1090. X    }
  1091. X
  1092. X    dolv[n] = dolv[0];
  1093. X    dolv += n;
  1094. X    dolc -= n;
  1095. X    setval (lookup ("#", TRUE), putn (dolc));
  1096. X    return 0;
  1097. X}
  1098. X
  1099. X/*
  1100. X * Execute a umask command: umask <n>
  1101. X */
  1102. X
  1103. Xstatic int    doumask (t)
  1104. Xregister C_Op    *t;
  1105. X{
  1106. X    register int    i;
  1107. X    register char    *cp;
  1108. X
  1109. X    if ((cp = t->words[1]) == (char *)NULL)
  1110. X    {
  1111. X    i = umask (0);
  1112. X    umask (i);
  1113. X    v1printf ("%o\n", i);
  1114. X    }
  1115. X
  1116. X    else
  1117. X    {
  1118. X    i = 0;
  1119. X    while (IS_OCTAL (*cp))
  1120. X        i = i * 8 + (*(cp++) - '0');
  1121. X
  1122. X    umask (i);
  1123. X    }
  1124. X
  1125. X    return 0;
  1126. X}
  1127. X
  1128. X/*
  1129. X * Execute an exec command: exec <arguments>
  1130. X */
  1131. X
  1132. Xstatic int    doexec (t)
  1133. Xregister C_Op    *t;
  1134. X{
  1135. X    register int    i;
  1136. X    jmp_buf        ex;
  1137. X    int            *ofail;
  1138. X
  1139. X    t->ioact = (IO_Actions **)NULL;
  1140. X
  1141. X    for (i = 0; (t->words[i] = t->words[i + 1]) != (char *)NULL; i++)
  1142. X    ;
  1143. X
  1144. X    if (i == 0)
  1145. X    return 0;
  1146. X
  1147. X    execflg = 1;
  1148. X    ofail = failpt;
  1149. X
  1150. X/* Set execute function recursive level to zero */
  1151. X
  1152. X    Execute_stack_depth = 0;
  1153. X
  1154. X    if (setjmp (failpt = ex) == 0)
  1155. X    execute (t, NOPIPE, NOPIPE, FEXEC);
  1156. X
  1157. X    failpt = ofail;
  1158. X    execflg = 0;
  1159. X    return 1;
  1160. X}
  1161. X
  1162. X/*
  1163. X * Execute a script in the current shell
  1164. X */
  1165. X
  1166. Xstatic int    dodot (t)
  1167. XC_Op        *t;
  1168. X{
  1169. X    register int    i;
  1170. X    register char    *sp;
  1171. X    char        *cp;
  1172. X
  1173. X    if ((cp = t->words[1]) == (char *)NULL)
  1174. X    return 0;
  1175. X
  1176. X    sp = any ('/', cp) ? null : path->value;
  1177. X
  1178. X    do
  1179. X    {
  1180. X    sp = path_append (sp, cp, e.linep);
  1181. X
  1182. X    if ((i = O_for_execute (e.linep)) >= 0)
  1183. X    {
  1184. X        exstat = 0;
  1185. X        next (remap (i));
  1186. X        return exstat;
  1187. X    }
  1188. X    } while (sp != (char *)NULL);
  1189. X
  1190. X    print_error ("%s: not found\n", cp);
  1191. X    return 1;
  1192. X}
  1193. X
  1194. X/*
  1195. X * Read from standard input into a variable list
  1196. X */
  1197. X
  1198. Xstatic int    doread (t)
  1199. XC_Op        *t;
  1200. X{
  1201. X    register char    *cp, **wp;
  1202. X    register int    nb;
  1203. X
  1204. X    if (t->words[1] == (char *)NULL)
  1205. X    {
  1206. X    print_error ("Usage: read name ...\n");
  1207. X    return 1;
  1208. X    }
  1209. X
  1210. X    for (wp = t->words + 1; *wp != (char *)NULL; wp++)
  1211. X    {
  1212. X    for (cp = e.linep; cp < e.eline - 1; cp++)
  1213. X    {
  1214. X        if (((nb = read (STDIN_FILENO, cp, 1)) != 1) || (*cp == NL) ||
  1215. X        ((wp[1] != (char *)NULL) && any (*cp, ifs->value)))
  1216. X
  1217. X        break;
  1218. X    }
  1219. X
  1220. X    *cp = 0;
  1221. X
  1222. X    if (nb <= 0)
  1223. X        break;
  1224. X
  1225. X    setval (lookup (*wp, TRUE), e.linep);
  1226. X    }
  1227. X
  1228. X    return (nb <= 0);
  1229. X}
  1230. X
  1231. X/*
  1232. X * Evaluate an expression
  1233. X */
  1234. X
  1235. Xstatic int    doeval (t)
  1236. Xregister C_Op    *t;
  1237. X{
  1238. X    return RUN (awordlist, t->words + 1, wdchar);
  1239. X}
  1240. X
  1241. X/*
  1242. X * Execute a trap
  1243. X */
  1244. X
  1245. Xstatic int    dotrap (t)
  1246. Xregister C_Op    *t;
  1247. X{
  1248. X    register int    n, i;
  1249. X    register int    resetsig;
  1250. X    char        tval[10];
  1251. X    char        *cp;
  1252. X
  1253. X
  1254. X    if (t->words[1] == (char *)NULL)
  1255. X    {
  1256. X
  1257. X/* Display trap - look up each trap and print those we find */
  1258. X
  1259. X    for (i = 0; i < NSIG; i++)
  1260. X    {
  1261. X        sprintf (tval, "~%d", i);
  1262. X
  1263. X        if ((cp = lookup (tval, FALSE)->value) != null)
  1264. X        {
  1265. X        v1printf ("%u: ", i);
  1266. X        v1a_puts (cp);
  1267. X        }
  1268. X    }
  1269. X
  1270. X    return 0;
  1271. X    }
  1272. X
  1273. X    resetsig = isdigit (*t->words[1]);        /* Reset signal?    */
  1274. X
  1275. X    for (i = resetsig ? 1 : 2; t->words[i] != (char *)NULL; ++i)
  1276. X    {
  1277. X
  1278. X/* Generate the variable name */
  1279. X
  1280. X    sprintf (tval, "~%d", (n = getsig (t->words[i])));
  1281. X
  1282. X    if (n == -1)
  1283. X        return 1;
  1284. X
  1285. X    unset (tval, TRUE);
  1286. X
  1287. X/* Re-define signal processing */
  1288. X
  1289. X    if (!resetsig)
  1290. X    {
  1291. X        if (*t->words[1] != '\0')
  1292. X        {
  1293. X        setval (lookup (tval, TRUE), t->words[1]);
  1294. X        setsig (n, sig);
  1295. X        }
  1296. X
  1297. X        else
  1298. X        setsig (n, SIG_IGN);
  1299. X    }
  1300. X
  1301. X/* Clear signal processing */
  1302. X
  1303. X    else if (talking)
  1304. X    {
  1305. X        if (n == SIGINT)
  1306. X        setsig (n, onintr);
  1307. X
  1308. X        else
  1309. X#ifdef SIGQUIT
  1310. X        setsig (n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
  1311. X#else
  1312. X        setsig (n, SIG_DFL);
  1313. X#endif
  1314. X    }
  1315. X
  1316. X    else
  1317. X        setsig (n, SIG_DFL);
  1318. X    }
  1319. X
  1320. X    return 0;
  1321. X}
  1322. X
  1323. X/*
  1324. X * Get a signal number
  1325. X */
  1326. X
  1327. Xstatic int    getsig (s)
  1328. Xchar        *s;
  1329. X{
  1330. X    register int    n;
  1331. X
  1332. X    if (((n = getn (s)) < 0) || (n >= NSIG))
  1333. X    {
  1334. X    print_error ("trap: bad signal number\n");
  1335. X    n = -1;
  1336. X    }
  1337. X
  1338. X    return n;
  1339. X}
  1340. X
  1341. X/*
  1342. X * Set up a signal function
  1343. X */
  1344. X
  1345. Xstatic void    setsig (n, f)
  1346. Xregister int    n;
  1347. Xint        (*f)();
  1348. X{
  1349. X    if (n == 0)
  1350. X    return;
  1351. X
  1352. X    if ((signal (n, SIG_IGN) != SIG_IGN) || (ourtrap & (1L << n)))
  1353. X    {
  1354. X    ourtrap |= (1L << n);
  1355. X    signal (n, f);
  1356. X    }
  1357. X}
  1358. X
  1359. X/* Convert a string to a number */
  1360. X
  1361. Xint    getn (as)
  1362. Xchar    *as;
  1363. X{
  1364. X    char    *s;
  1365. X    int        n = (int)strtol (as, &s, 10);
  1366. X
  1367. X    if (*s)
  1368. X    print_error ("%s: bad number\n", as);
  1369. X
  1370. X    return n;
  1371. X}
  1372. X
  1373. X/*
  1374. X * BREAK and CONTINUE processing
  1375. X */
  1376. X
  1377. Xstatic int    dobreak (t)
  1378. XC_Op        *t;
  1379. X{
  1380. X    return brkcontin (t->words[1], BC_BREAK);
  1381. X}
  1382. X
  1383. Xstatic int    docontinue (t)
  1384. XC_Op        *t;
  1385. X{
  1386. X    return brkcontin (t->words[1], BC_CONTINUE);
  1387. X}
  1388. X
  1389. Xstatic int    brkcontin (cp, val)
  1390. Xregister char    *cp;
  1391. Xint        val;
  1392. X{
  1393. X    register Break_C    *Break_Loc;
  1394. X    register int    nl;
  1395. X
  1396. X    if ((nl = (cp == (char *)NULL) ? 1 : getn (cp)) <= 0)
  1397. X    nl = 999;
  1398. X
  1399. X    do
  1400. X    {
  1401. X    if ((Break_Loc = Break_List) == (Break_C *)NULL)
  1402. X        break;
  1403. X
  1404. X    Break_List = Break_Loc->nextlev;
  1405. X
  1406. X    } while (--nl);
  1407. X
  1408. X    if (nl)
  1409. X    {
  1410. X    print_error ("sh: bad break/continue level\n");
  1411. X    return 1;
  1412. X    }
  1413. X
  1414. X    longjmp (Break_Loc->brkpt, val);
  1415. X
  1416. X/* NOTREACHED */
  1417. X}
  1418. X
  1419. X/*
  1420. X * Exit function
  1421. X */
  1422. X
  1423. Xstatic int    doexit (t)
  1424. XC_Op        *t;
  1425. X{
  1426. X    Break_C    *SShell_Loc = SShell_List;
  1427. X
  1428. X    execflg = 0;
  1429. X
  1430. X/* Set up error codes */
  1431. X
  1432. X    if (t->words[1] != (char *)NULL)
  1433. X    {
  1434. X    exstat = getn (t->words[1]);
  1435. X    setval (lookup ("?", TRUE), t->words[1]);
  1436. X    }
  1437. X
  1438. X/* Are we in a subshell.  Yes - do a longjmp instead of an exit */
  1439. X
  1440. X    if (SShell_Loc != (Break_C *)NULL)
  1441. X    {
  1442. X    SShell_List = SShell_Loc->nextlev;
  1443. X    longjmp (SShell_Loc->brkpt, 1);
  1444. X    }
  1445. X
  1446. X    leave ();
  1447. X    return 1;
  1448. X}
  1449. X
  1450. X/*
  1451. X * Function return - set exit value and return via a long jmp
  1452. X */
  1453. X
  1454. Xstatic int    doreturn (t)
  1455. XC_Op        *t;
  1456. X{
  1457. X    Break_C    *Return_Loc = Return_List;
  1458. X
  1459. X    if  (t->words[1] != (char *)NULL)
  1460. X    setval (lookup ("?", TRUE), t->words[1]);
  1461. X
  1462. X/* If the return address is defined - return to it.  Otherwise, return
  1463. X * the value
  1464. X */
  1465. X
  1466. X    if (Return_Loc != (Break_C *)NULL)
  1467. X    {
  1468. X    Return_List = Return_Loc->nextlev;
  1469. X    longjmp (Return_Loc->brkpt, 1);
  1470. X    }
  1471. X
  1472. X    return getn (t->words[1]);
  1473. X}
  1474. X
  1475. X/*
  1476. X * MSDOS, EXPORT and READONLY functions
  1477. X */
  1478. X
  1479. Xstatic int    doexport (t)
  1480. XC_Op        *t;
  1481. X{
  1482. X    return rdexp (t->words + 1, EXPORT, "export ");
  1483. X}
  1484. X
  1485. Xstatic int    doreadonly (t)
  1486. XC_Op         *t;
  1487. X{
  1488. X    return rdexp (t->words + 1, RONLY, "readonly ");
  1489. X}
  1490. X
  1491. Xstatic int    domsdos (t)
  1492. XC_Op        *t;
  1493. X{
  1494. X    return rdexp (t->words + 1, C_MSDOS, "msdos ");
  1495. X}
  1496. X
  1497. Xstatic int    rdexp (wp, key, tstring)
  1498. Xregister char    **wp;
  1499. Xint        key;
  1500. Xchar        *tstring;
  1501. X{
  1502. X    char    *cp;
  1503. X    bool    valid;
  1504. X
  1505. X    if (*wp != (char *)NULL)
  1506. X    {
  1507. X    for (; *wp != (char *)NULL; wp++)
  1508. X    {
  1509. X        cp = *wp;
  1510. X        valid = TRUE;
  1511. X
  1512. X/* Check for a valid name */
  1513. X
  1514. X        if (!isalpha (*(cp++)))
  1515. X        valid = FALSE;
  1516. X
  1517. X        else
  1518. X        {
  1519. X        while (*cp)
  1520. X        {
  1521. X            if (!isalnum (*(cp++)))
  1522. X            {
  1523. X            valid = FALSE;
  1524. X            break;
  1525. X            }
  1526. X        }
  1527. X        }
  1528. X
  1529. X/* If valid - update, otherwise print a message */
  1530. X
  1531. X        if (valid)
  1532. X        s_vstatus (lookup (*wp, TRUE), key);
  1533. X
  1534. X        else
  1535. X        print_error ("%s: bad identifier\n", *wp);
  1536. X    }
  1537. X    }
  1538. X
  1539. X    else
  1540. X    {
  1541. X    register Var_List    *vp;
  1542. X
  1543. X    for (vp = vlist; vp != (Var_List *) NULL; vp = vp->next)
  1544. X    {
  1545. X        if ((vp->status & key) && isalpha (*vp->name))
  1546. X        {
  1547. X        v1_puts (tstring);
  1548. X        v1_putsn (vp->name, (int)(findeq (vp->name) - vp->name));
  1549. X        v1_putc (NL);
  1550. X        }
  1551. X    }
  1552. X    }
  1553. X
  1554. X    return 0;
  1555. X}
  1556. X
  1557. X/*
  1558. X * Sort Compare function for displaying variables
  1559. X */
  1560. X
  1561. Xint    sort_compare (s1, s2)
  1562. Xchar    **s1;
  1563. Xchar    **s2;
  1564. X{
  1565. X    return strcmp (*s1, *s2);
  1566. X}
  1567. X
  1568. X/*
  1569. X * Set function
  1570. X */
  1571. X
  1572. Xstatic int    doset (t)
  1573. Xregister C_Op    *t;
  1574. X{
  1575. X    register Var_List    *vp;
  1576. X    register char    *cp;
  1577. X    register int    n, j;
  1578. X    Fun_Ops        *fp;
  1579. X    char        sign;
  1580. X    char        **list;
  1581. X
  1582. X/* Display ? */
  1583. X
  1584. X    if ((cp = t->words[1]) == (char *)NULL)
  1585. X    {
  1586. X
  1587. X/* Count the number of entries to print */
  1588. X
  1589. X    for (n = 0, vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
  1590. X    {
  1591. X        if (isalnum (*vp->name))
  1592. X        n++;
  1593. X    }
  1594. X
  1595. X/* Build a local array of name */
  1596. X
  1597. X    list = (char **)space (sizeof (char *) * n);
  1598. X
  1599. X    for (n = 0, vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
  1600. X    {
  1601. X        if (isalnum (*vp->name))
  1602. X        {
  1603. X        if (list == (char **)NULL)
  1604. X            v1a_puts (vp->name);
  1605. X
  1606. X        else
  1607. X            list[n++] = vp->name;
  1608. X        }
  1609. X    }
  1610. X
  1611. X/* Sort them and then print */
  1612. X
  1613. X    if (list != (char **)NULL)
  1614. X    {
  1615. X        qsort (list, n, sizeof (char *), sort_compare);
  1616. X
  1617. X        for (j = 0; j < n; j++)
  1618. X        v1a_puts (list[j]);
  1619. X
  1620. X        DELETE (list);
  1621. X    }
  1622. X
  1623. X/* Print the list of functions */
  1624. X
  1625. X    for (fp = fun_list; fp != (Fun_Ops *)NULL; fp = fp->next)
  1626. X        Print_ExTree (fp->tree);
  1627. X
  1628. X    return 0;
  1629. X    }
  1630. X
  1631. X/* Set/Unset a flag ? */
  1632. X
  1633. X    if (((sign = *cp) == '-') || (*cp == '+'))
  1634. X    {
  1635. X    for (n = 0; (t->words[n] = t->words[n + 1]) != (char *)NULL; n++)
  1636. X        ;
  1637. X
  1638. X    for (; *cp; cp++)
  1639. X    {
  1640. X        if (*cp == 'r')
  1641. X        {
  1642. X        print_error ("set: -r bad option\n");
  1643. X        return 1;
  1644. X        }
  1645. X
  1646. X        if (*cp == 'e')
  1647. X        {
  1648. X        if (!talking)
  1649. X        {
  1650. X            if (sign == '-')
  1651. X            FL_SET ('e');
  1652. X
  1653. X            else
  1654. X            FL_CLEAR ('e');
  1655. X        }
  1656. X        }
  1657. X
  1658. X        else if (islower (*cp))
  1659. X        {
  1660. X        if (sign == '-')
  1661. X            FL_SET (*cp);
  1662. X
  1663. X        else
  1664. X            FL_CLEAR (*cp);
  1665. X        }
  1666. X    }
  1667. X
  1668. X    setdash ();
  1669. X    }
  1670. X
  1671. X/* Set up parameters ? */
  1672. X
  1673. X    if (t->words[1])
  1674. X    {
  1675. X    t->words[0] = dolv[0];
  1676. X
  1677. X    for (n = 1; t->words[n] != (char *)NULL; n++)
  1678. X        setarea ((char *)t->words[n], 0);
  1679. X
  1680. X    dolc = n-1;
  1681. X    dolv = t->words;
  1682. X    setval (lookup ("#", TRUE), putn (dolc));
  1683. X    setarea ((char *)(dolv - 1), 0);
  1684. X    }
  1685. X
  1686. X    return 0;
  1687. X}
  1688. X
  1689. X/*
  1690. X * History functions - display, initialise, enable, disable
  1691. X */
  1692. X
  1693. Xstatic int    dohistory (t)
  1694. XC_Op        *t;
  1695. X{
  1696. X    char    *cp;
  1697. X
  1698. X    if (!talking)
  1699. X    return 1;
  1700. X
  1701. X    if ((cp = t->words[1]) == (char *)NULL)
  1702. X    Display_History ();
  1703. X
  1704. X    else if (strcmp (cp, "-i") == 0)
  1705. X    Clear_History ();
  1706. X
  1707. X    else if (strcmp (cp, "-d") == 0)
  1708. X    History_Enabled = FALSE;
  1709. X
  1710. X    else if (strcmp (cp, "-e") == 0)
  1711. X    History_Enabled = TRUE;
  1712. X
  1713. X    return 0;
  1714. X}
  1715. X
  1716. X/*
  1717. X * Type fucntion: For each name, indicate how it would be interpreted
  1718. X */
  1719. X
  1720. Xstatic char    *type_ext[] = {
  1721. X    "", ".exe", ".com", ".sh"
  1722. X};
  1723. X
  1724. Xstatic int    dotype (t)
  1725. Xregister C_Op    *t;
  1726. X{
  1727. X    register char    *sp;            /* Path pointers    */
  1728. X    char        *cp;
  1729. X    char        *ep;
  1730. X    char        *xp;            /* In file name pointers */
  1731. X    char        *xp1;
  1732. X    int            n = 1;            /* Argument count    */
  1733. X    int            i, fp;    
  1734. X    bool        found;            /* Found flag        */
  1735. X
  1736. X    while ((cp = t->words[n++]) != (char *)NULL)
  1737. X    {
  1738. X    sp = any ('/', cp) ? null : path->value;
  1739. X    found = FALSE;
  1740. X
  1741. X    do
  1742. X    {
  1743. X        sp = path_append (sp, cp, e.linep);
  1744. X        ep = &e.linep[strlen (e.linep)];
  1745. X
  1746. X/* Get start of file name */
  1747. X
  1748. X        if ((xp1 = strrchr (e.linep, '/')) == (char *)NULL)
  1749. X        xp1 = e.linep;
  1750. X        
  1751. X        else
  1752. X        ++xp1;
  1753. X
  1754. X/* Look up all 4 types */
  1755. X
  1756. X        for (i = 0; (i < 4) && !found; i++)
  1757. X        {
  1758. X        strcpy (ep, type_ext[i]);
  1759. X
  1760. X        if (access (e.linep, F_OK) == 0)
  1761. X        {
  1762. X
  1763. X/* If no extension or .sh extension, check for shell script */
  1764. X
  1765. X            if (((xp = strchr (xp1, '.')) == (char *)NULL) ||
  1766. X            (stricmp (xp, ".sh") == 0))
  1767. X            {
  1768. X            if ((fp = Check_Script (e.linep)) < 0)
  1769. X                continue;
  1770. X
  1771. X            S_close (fp, TRUE);
  1772. X            }
  1773. X
  1774. X            else if ((stricmp (xp, ".exe") != 0) &&
  1775. X                 (stricmp (xp, ".com") != 0))
  1776. X            continue;
  1777. X
  1778. X            print_error ("%s is %s\n", cp, e.linep);
  1779. X            found = TRUE;
  1780. X        }
  1781. X        }
  1782. X    } while ((sp != (char *)NULL) && !found);
  1783. X
  1784. X    if (!found)
  1785. X        print_error ("%s not found\n", cp);
  1786. X    }
  1787. X
  1788. X    return 0;
  1789. X}
  1790. X
  1791. X/* Table of internal commands */
  1792. X
  1793. Xstatic struct    builtin    builtin[] = {
  1794. X    ".",        dodot,
  1795. X    ":",        dolabel,
  1796. X    "[",        dotest,
  1797. X    "break",    dobreak,
  1798. X    "cd",        dochdir,
  1799. X    "continue",    docontinue,
  1800. X    "echo",        doecho,
  1801. X    "eval",        doeval,
  1802. X    "exec",        doexec,
  1803. X    "exit",        doexit,
  1804. X    "export",    doexport,
  1805. X    "getopt",    dogetopt,
  1806. X    "history",    dohistory,
  1807. X    "msdos",    domsdos,
  1808. X    "pwd",        dopwd,
  1809. X    "read",        doread,
  1810. X    "readonly",    doreadonly,
  1811. X    "return",    doreturn,
  1812. X    "set",        doset,
  1813. X    "shift",    doshift,
  1814. X    "swap",        doswap,
  1815. X    "test",        dotest,
  1816. X    "trap",        dotrap,
  1817. X    "type",        dotype,
  1818. X    "umask",    doumask,
  1819. X    "unset",    dounset,
  1820. X    "ver",        dover,
  1821. X    (char *)NULL,
  1822. X};
  1823. X
  1824. X/*
  1825. X * Look up a built in command
  1826. X */
  1827. X
  1828. Xint        (*inbuilt (s))()
  1829. Xregister char    *s;
  1830. X{
  1831. X    register struct builtin    *bp;
  1832. X
  1833. X    if ((strlen (s) == 2) && isalpha (*s) && (*s != '_') && (*(s + 1) == ':'))
  1834. X    return dodrive;
  1835. X
  1836. X    for (bp = builtin; bp->command != (char *)NULL; bp++)
  1837. X    {
  1838. X    if (stricmp (bp->command, s) == 0)
  1839. X        return bp->fn;
  1840. X    }
  1841. X
  1842. X    return NULL;
  1843. X}
  1844. X
  1845. X/* Write to stdout functions - printf, fputs, fputc, and a special */
  1846. X
  1847. X/*
  1848. X * Equivalent of printf without using streams
  1849. X */
  1850. X
  1851. Xvoid    v1printf (fmt)
  1852. Xchar    *fmt;
  1853. X{
  1854. X    va_list    ap;
  1855. X    char    x[100];
  1856. X
  1857. X    va_start (ap, fmt);
  1858. X    vsprintf (x, fmt, ap);
  1859. X    v1_puts (x);
  1860. X    va_end (ap);
  1861. X}
  1862. X
  1863. X/*
  1864. X * Write string to STDOUT
  1865. X */
  1866. X
  1867. Xvoid        v1_puts (s)
  1868. Xchar        *s;
  1869. X{
  1870. X    write (STDOUT_FILENO, s, strlen (s));
  1871. X}
  1872. X
  1873. X/*
  1874. X * Write string to STDOUT with a NL at end
  1875. X */
  1876. X
  1877. Xvoid        v1a_puts (s)
  1878. Xchar        *s;
  1879. X{
  1880. X    char    c = NL;
  1881. X
  1882. X    write (STDOUT_FILENO, s, strlen (s));
  1883. X    write (STDOUT_FILENO, &c, 1);
  1884. X}
  1885. X
  1886. X/*
  1887. X * Write n characters to STDOUT
  1888. X */
  1889. X
  1890. Xstatic void    v1_putsn (s, n)
  1891. Xchar        *s;
  1892. Xint        n;
  1893. X{
  1894. X    write (STDOUT_FILENO, s, n);
  1895. X}
  1896. X
  1897. X/*
  1898. X * Write 1 character to STDOUT
  1899. X */
  1900. X
  1901. Xvoid        v1_putc (c)
  1902. Xchar        c;
  1903. X{
  1904. X    write (STDOUT_FILENO, &c, 1);
  1905. X}
  1906. SHAR_EOF
  1907. chmod 0644 shell/sh7.c || echo "restore of shell/sh7.c fails"
  1908. set `wc -c shell/sh7.c`;Sum=$1
  1909. if test "$Sum" != "30980"
  1910. then echo original size 30980, current size $Sum;fi
  1911. echo "x - extracting shell/sh8.c (Text)"
  1912. sed 's/^X//' << 'SHAR_EOF' > shell/sh8.c &&
  1913. X/* MS-DOS SHELL - Unix File I/O Emulation
  1914. X *
  1915. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
  1916. X *
  1917. X * This code is subject to the following copyright restrictions:
  1918. X *
  1919. X * 1.  Redistribution and use in source and binary forms are permitted
  1920. X *     provided that the above copyright notice is duplicated in the
  1921. X *     source form and the copyright notice in file sh6.c is displayed
  1922. X *     on entry to the program.
  1923. X *
  1924. X * 2.  The sources (or parts thereof) or objects generated from the sources
  1925. X *     (or parts of sources) cannot be sold under any circumstances.
  1926. X *
  1927. X *    $Header: sh8.c 1.1 90/01/29 17:46:37 MS_user Exp $
  1928. X *
  1929. X *    $Log:    sh8.c $
  1930. X * Revision 1.1  90/01/29  17:46:37  MS_user
  1931. X * Initial revision
  1932. X * 
  1933. X * 
  1934. X */
  1935. X
  1936. X#include <sys/types.h>
  1937. X#include <signal.h>
  1938. X#include <errno.h>
  1939. X#include <setjmp.h>
  1940. X#include <stdlib.h>
  1941. X#include <fcntl.h>
  1942. X#include <io.h>
  1943. X#include <stdarg.h>
  1944. X#include <string.h>
  1945. X#include <unistd.h>
  1946. X#include <limits.h>
  1947. X#include "sh.h"
  1948. X
  1949. X#define F_START        4
  1950. X
  1951. Xstatic char        *nopipe = "can't create pipe - try again\n";
  1952. X
  1953. X/* List of open files to allow us to simulate the Unix open and unlink
  1954. X * operation for temporary files
  1955. X */
  1956. X
  1957. Xtypedef struct flist {
  1958. X    struct flist    *fl_next;    /* Next link            */
  1959. X    char        *fl_name;    /* File name            */
  1960. X    bool        fl_close;    /* Delete on close flag        */
  1961. X    int            fl_size;    /* Size of fl_fd array        */
  1962. X    int            fl_count;    /* Number of entries in array    */
  1963. X    int            fl_mode;    /* File open mode        */
  1964. X    int            *fl_fd;        /* File ID array (for dup)    */
  1965. X} s_flist;
  1966. X
  1967. Xstatic s_flist        *list_start = (s_flist *)NULL;
  1968. Xstatic s_flist        *find_entry (int);
  1969. X
  1970. X/*
  1971. X * Open a file and add it to the Open file list.  Errors are the same as
  1972. X * for a normal open.
  1973. X */
  1974. X
  1975. Xint    S_open (d_flag, name, mode)
  1976. Xbool    d_flag;
  1977. Xchar    *name;
  1978. Xint    mode;
  1979. X{
  1980. X    va_list        ap;
  1981. X    int            pmask;
  1982. X    s_flist        *fp = (struct s_flist *)NULL;
  1983. X    int            *f_list = (int *)NULL;
  1984. X    char        *f_name = (char *)NULL;
  1985. X
  1986. X/* Check the permission mask if it exists */
  1987. X
  1988. X    va_start (ap, mode);
  1989. X    pmask =  va_arg (ap, int);
  1990. X    va_end (ap);
  1991. X
  1992. X/* Grap some space.  If it fails, free space and return an error */
  1993. X
  1994. X    if (((fp = (s_flist *) space (sizeof (s_flist))) == (s_flist *)NULL) ||
  1995. X    ((f_list = (int *) space (sizeof (int) * F_START)) == (int *)NULL) ||
  1996. X    ((f_name = strsave (name, 0)) == null))
  1997. X    {
  1998. X    if (f_list == (int *)NULL)
  1999. X        DELETE (f_list);
  2000. X
  2001. X    if (fp == (s_flist *)NULL)
  2002. X        DELETE (fp);
  2003. X
  2004. X    errno = ENOMEM;
  2005. X    return -1;
  2006. X    }
  2007. X
  2008. X/* Set up the structure */
  2009. X
  2010. X    fp->fl_name  = strcpy (f_name, name);
  2011. X    fp->fl_close = d_flag;
  2012. X    fp->fl_size  = F_START;
  2013. X    fp->fl_count = 1;
  2014. X    fp->fl_fd    = f_list;
  2015. X    fp->fl_mode  = mode;
  2016. X
  2017. X/* Open the file */
  2018. X
  2019. X    if ((fp->fl_fd[0] = open (name, mode, pmask)) < 0)
  2020. X    {
  2021. X    pmask = errno;
  2022. X    DELETE (f_name);
  2023. X    DELETE (f_list);
  2024. X    DELETE (fp);
  2025. X    errno = pmask;
  2026. X    return -1;
  2027. X    }
  2028. X
  2029. X/* Make sure everything is in area 0 */
  2030. X
  2031. X    setarea ((char *)fp, 0);
  2032. X    setarea ((char *)f_list, 0);
  2033. X
  2034. X/* List into the list */
  2035. X
  2036. X    fp->fl_next   = list_start;
  2037. X    list_start = fp;
  2038. X
  2039. X/* Return the file descriptor */
  2040. X
  2041. X    return fp->fl_fd[0];
  2042. X}
  2043. X
  2044. X/*
  2045. X * Scan the File list for the appropriate entry for the specified ID
  2046. X */
  2047. X
  2048. Xstatic s_flist        *find_entry (fid)
  2049. Xint            fid;
  2050. X{
  2051. X    s_flist    *fp = list_start;
  2052. X    int        i;
  2053. X
  2054. X    while (fp != (s_flist *)NULL)
  2055. X    {
  2056. X    for (i = 0; i < fp->fl_count; i++)
  2057. X    {
  2058. X        if (fp->fl_fd[i] == fid)
  2059. X        return fp;
  2060. X    }
  2061. X
  2062. X    fp = fp->fl_next;
  2063. X    }
  2064. X
  2065. X    return (s_flist *)NULL;
  2066. X}
  2067. X
  2068. X/* Close the file
  2069. X *
  2070. X * We need a version of close that does everything but close for dup2 as
  2071. X * new file id is closed.  If c_flag is TRUE, close the file as well.
  2072. X */
  2073. X
  2074. Xint    S_close (fid, c_flag)
  2075. Xint    fid;
  2076. Xbool    c_flag;
  2077. X{
  2078. X    s_flist    *fp = find_entry (fid);
  2079. X    s_flist    *last = (s_flist *)NULL;
  2080. X    s_flist    *fp1 = list_start;
  2081. X    int        i, serrno;
  2082. X    bool    release = TRUE;
  2083. X    bool    delete = FALSE;
  2084. X    char    *fname;
  2085. X
  2086. X/* Find the entry for this ID */
  2087. X
  2088. X    if (fp != (s_flist *)NULL)
  2089. X    {
  2090. X    for (i = 0; i < fp->fl_count; i++)
  2091. X    {
  2092. X        if (fp->fl_fd[i] == fid)
  2093. X        fp->fl_fd[i] = -1;
  2094. X
  2095. X        if (fp->fl_fd[i] != -1)
  2096. X        release = FALSE;
  2097. X    }
  2098. X
  2099. X/* Are all the Fids closed ? */
  2100. X
  2101. X    if (release)
  2102. X    {
  2103. X        fname = fp->fl_name;
  2104. X        delete = fp->fl_close;
  2105. X        DELETE (fp->fl_fd);
  2106. X
  2107. X/* Scan the list and remove the entry */
  2108. X
  2109. X        while (fp1 != (s_flist *)NULL)
  2110. X        {
  2111. X        if (fp1 != fp)
  2112. X        {
  2113. X            last = fp1;
  2114. X            fp1 = fp1->fl_next;
  2115. X            continue;
  2116. X        }
  2117. X
  2118. X        if (last == (s_flist *)NULL)
  2119. X            list_start = fp->fl_next;
  2120. X
  2121. X        else
  2122. X            last->fl_next = fp->fl_next;
  2123. X
  2124. X        break;
  2125. X        }
  2126. X
  2127. X/* OK - delete the area */
  2128. X
  2129. X        DELETE (fp);
  2130. X    }
  2131. X    }
  2132. X
  2133. X/* Close the file anyway */
  2134. X
  2135. X    if (c_flag)
  2136. X    {
  2137. X    i = close (fid);
  2138. X    serrno = errno;
  2139. X    }
  2140. X
  2141. X/* Delete the file ? */
  2142. X
  2143. X    if (delete)
  2144. X    {
  2145. X    unlink (fname);
  2146. X    DELETE (fname);
  2147. X    }
  2148. X
  2149. X/* Restore results and error code */
  2150. X
  2151. X    errno = serrno;
  2152. X    return i;
  2153. X}
  2154. X
  2155. X/*
  2156. X * Duplicate file handler.  Add the new handler to the ID array for this
  2157. X * file.
  2158. X */
  2159. X
  2160. Xint    S_dup (old_fid)
  2161. Xint    old_fid;
  2162. X{
  2163. X    int        new_fid;
  2164. X
  2165. X    if ((new_fid = dup (old_fid)) >= 0)
  2166. X    S_Remap (old_fid, new_fid);
  2167. X
  2168. X    return new_fid;
  2169. X}
  2170. X
  2171. X/*
  2172. X * Add the ID to the ID array for this file
  2173. X */
  2174. X
  2175. Xvoid    S_Remap (old_fid, new_fid)
  2176. Xint    old_fid, new_fid;
  2177. X{
  2178. X    s_flist    *fp = find_entry (old_fid);
  2179. X    int        *flist;
  2180. X    int        i;
  2181. X
  2182. X    if (fp == (s_flist *)NULL)
  2183. X    return;
  2184. X
  2185. X/* Is there an empty slot ? */
  2186. X
  2187. X    for (i = 0; i < fp->fl_count; i++)
  2188. X    {
  2189. X    if (fp->fl_fd[i] == -1)
  2190. X    {
  2191. X        fp->fl_fd[i] = new_fid;
  2192. X        return;
  2193. X    }
  2194. X    }
  2195. X
  2196. X/* Is there any room at the end ? No - grap somemore space and effect a
  2197. X * re-alloc.  What to do if the re-alloc fails - should really get here.
  2198. X * Safty check only??
  2199. X */
  2200. X
  2201. X    if (fp->fl_count == fp->fl_size)
  2202. X    {
  2203. X    if ((flist = (int *) space ((fp->fl_size + F_START) * sizeof (int)))
  2204. X        == (int *)NULL)
  2205. X        return;
  2206. X
  2207. X    memcpy ((char *)flist, (char *)fp->fl_fd, sizeof (int) * fp->fl_size);
  2208. X    DELETE (fp->fl_fd);
  2209. X
  2210. X    fp->fl_fd   = flist;
  2211. X    fp->fl_size += F_START;
  2212. X    }
  2213. X
  2214. X    fp->fl_fd[fp->fl_count++] = new_fid;
  2215. X}
  2216. X
  2217. X/*
  2218. X * Set Delete on Close flag
  2219. X */
  2220. X
  2221. Xvoid    S_Delete (fid)
  2222. Xint    fid;
  2223. X{
  2224. X    s_flist    *fp = find_entry (fid);
  2225. X
  2226. X    if (fp != (s_flist *)NULL)
  2227. X    fp->fl_close = TRUE;
  2228. X}
  2229. X
  2230. X/*
  2231. X * Duplicate file handler onto specific handler
  2232. X */
  2233. X
  2234. Xint    S_dup2 (old_fid, new_fid)
  2235. Xint    old_fid;
  2236. Xint    new_fid;
  2237. X{
  2238. X    int        res = 0;
  2239. X    int        i;
  2240. X    Save_IO    *sp;
  2241. X
  2242. X/* If duping onto stdin, stdout or stderr, Search the Save IO stack for an
  2243. X * entry matching us
  2244. X */
  2245. X
  2246. X    if ((new_fid >= STDIN_FILENO) && (new_fid <= STDERR_FILENO))
  2247. X    {
  2248. X    for (sp = SSave_IO, i = 0; (i < NSave_IO_E) &&
  2249. X                   (SSave_IO[i].depth < Execute_stack_depth);
  2250. X         i++);
  2251. X
  2252. X/* If depth is greater the Execute_stack_depth - we should panic as this
  2253. X * should not happen.  However, for the moment, I'll ignore it
  2254. X */
  2255. X
  2256. X/* If there an entry for this depth ? */
  2257. X
  2258. X    if (i == NSave_IO_E)
  2259. X    {
  2260. X
  2261. X/* Do we need more space? */
  2262. X
  2263. X        if (NSave_IO_E == MSave_IO_E)
  2264. X        {
  2265. X        sp = (Save_IO *)space ((MSave_IO_E + SSAVE_IO_SIZE) * sizeof (Save_IO));
  2266. X
  2267. X/* Check for error */
  2268. X
  2269. X        if (sp == (Save_IO *)NULL)
  2270. X        {
  2271. X            errno = ENOMEM;
  2272. X            return -1;
  2273. X        }
  2274. X
  2275. X/* Save original data */
  2276. X
  2277. X        if (MSave_IO_E != 0)
  2278. X        {
  2279. X            memcpy (sp, SSave_IO, sizeof (Save_IO) * MSave_IO_E);
  2280. X            DELETE (SSave_IO);
  2281. X        }
  2282. X
  2283. X        setarea ((char *)sp, 1);
  2284. X        SSave_IO = sp;
  2285. X        MSave_IO_E += SSAVE_IO_SIZE;
  2286. X        }
  2287. X
  2288. X/* Initialise the new entry */
  2289. X
  2290. X        sp = &SSave_IO[NSave_IO_E++];
  2291. X        sp->depth             = Execute_stack_depth;
  2292. X        sp->fp[STDIN_FILENO]  = -1;
  2293. X        sp->fp[STDOUT_FILENO] = -1;
  2294. X        sp->fp[STDERR_FILENO] = -1;
  2295. X    }
  2296. X
  2297. X    if (sp->fp[new_fid] == -1)
  2298. X        sp->fp[new_fid] = remap (new_fid);
  2299. X    }
  2300. X
  2301. X/* OK - Dup the descriptor */
  2302. X
  2303. X    if ((old_fid != -1) && ((res = dup2 (old_fid, new_fid)) >= 0))
  2304. X    {
  2305. X    S_close (new_fid, FALSE);
  2306. X    S_Remap (old_fid, new_fid);
  2307. X    }
  2308. X
  2309. X    return res;
  2310. X}
  2311. X
  2312. X/*
  2313. X * Restore the Stdin, Stdout and Stderr to original values
  2314. X */
  2315. X
  2316. Xint    restore_std (rv)
  2317. Xint    rv;
  2318. X{
  2319. X    int        j, i;
  2320. X    Save_IO    *sp;
  2321. X
  2322. X/* Start at the top and remove any entries above the current execute stack
  2323. X * depth
  2324. X */
  2325. X
  2326. X    for (j = NSave_IO_E; j > 0; j--)
  2327. X    {
  2328. X       sp = &SSave_IO[j - 1];
  2329. X
  2330. X       if (sp->depth < Execute_stack_depth)
  2331. X       break;
  2332. X
  2333. X/* Reduce number of entries */
  2334. X
  2335. X    --NSave_IO_E;
  2336. X
  2337. X/* Close and restore any files */
  2338. X
  2339. X    for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
  2340. X    {
  2341. X        if (sp->fp[i] != -1)
  2342. X        {
  2343. X        S_close (i, TRUE);
  2344. X        dup2 (sp->fp[i], i);
  2345. X        S_close (sp->fp[i], TRUE);
  2346. X        }
  2347. X    }
  2348. X    }
  2349. X
  2350. X    return rv;
  2351. X}
  2352. X
  2353. X/*
  2354. X * Create a Pipe
  2355. X */
  2356. X
  2357. Xint        openpipe ()
  2358. X{
  2359. X    register int    i;
  2360. X
  2361. X    if ((i = S_open (TRUE, g_tempname (), O_PMASK, 0600)) < 0)
  2362. X    print_error (nopipe);
  2363. X
  2364. X    return i;
  2365. X}
  2366. X
  2367. X/*
  2368. X * Close a pipe
  2369. X */
  2370. X
  2371. Xvoid        closepipe (pv)
  2372. Xregister int    pv;
  2373. X{
  2374. X    if (pv != -1)
  2375. X    S_close (pv, TRUE);
  2376. X}
  2377. X
  2378. X/*
  2379. X * Write a character to STDERR
  2380. X */
  2381. X
  2382. Xvoid    S_putc (c)
  2383. Xint    c;
  2384. X{
  2385. X    write (STDERR_FILENO, (char *)&c, 1);
  2386. X}
  2387. X
  2388. X/*
  2389. X * Write a string to STDERR
  2390. X */
  2391. X
  2392. Xvoid    S_puts (s)
  2393. Xchar    *s;
  2394. X{
  2395. X    write (STDERR_FILENO, s, strlen (s));
  2396. X}
  2397. X
  2398. X/*
  2399. X * Check for restricted shell
  2400. X */
  2401. X
  2402. Xbool    check_rsh (s)
  2403. Xchar    *s;
  2404. X{
  2405. X    if (r_flag)
  2406. X    {
  2407. X    print_error ("%s: restricted\n", s);
  2408. X    return TRUE;
  2409. X    }
  2410. X
  2411. X    return FALSE;
  2412. X}
  2413. X
  2414. X/*
  2415. X * Check to see if a file is a shell script.  If it is, return the file
  2416. X * handler for the file
  2417. X */
  2418. X
  2419. Xint    O_for_execute (path)
  2420. Xchar    *path;
  2421. X{
  2422. X    int        i, end;
  2423. X    char    local_path[FFNAME_MAX];
  2424. X
  2425. X/* Work on a copy of the path */
  2426. X
  2427. X    strcpy (local_path, path);
  2428. X
  2429. X/* Try the file name and then with a .sh appended */
  2430. X
  2431. X    for (end = 0; end < 2; end++)
  2432. X    {
  2433. X    if ((i = Check_Script (local_path)) >= 0)
  2434. X        return i;
  2435. X
  2436. X    if (!end)
  2437. X        strcat (local_path, ".sh");
  2438. X    }
  2439. X
  2440. X    return -1;
  2441. X}
  2442. X
  2443. X/*
  2444. X * Check for shell script
  2445. X */
  2446. X
  2447. Xint    Check_Script (path)
  2448. Xchar    *path;
  2449. X{
  2450. X    char    buf[5];
  2451. X    int        i;
  2452. X
  2453. X    if (((i = S_open (FALSE, path, O_RMASK)) >= 0) &&
  2454. X    ((read (i, buf, 6) == 5) && (strncmp (buf, "#!sh\n", 5) == 0)))
  2455. X    return i;
  2456. X
  2457. X    if (i != -1)
  2458. X    S_close (i, TRUE);
  2459. X
  2460. X    return -1;
  2461. X}
  2462. X
  2463. X/*
  2464. X * Convert slashes to backslashes for MSDOS
  2465. X */
  2466. X
  2467. Xvoid    Convert_Slashes (sp)
  2468. Xchar    *sp;
  2469. X{
  2470. X    while (*sp)
  2471. X    {
  2472. X    if (*sp == '/')
  2473. X        *sp = '\\';
  2474. X
  2475. X    ++sp;
  2476. X    }
  2477. X}
  2478. SHAR_EOF
  2479. chmod 0644 shell/sh8.c || echo "restore of shell/sh8.c fails"
  2480. set `wc -c shell/sh8.c`;Sum=$1
  2481. if test "$Sum" != "9874"
  2482. then echo original size 9874, current size $Sum;fi
  2483. echo "x - extracting shell/sh9.c (Text)"
  2484. sed 's/^X//' << 'SHAR_EOF' > shell/sh9.c &&
  2485. X/* MS-DOS SHELL - History Processing
  2486. X *
  2487. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
  2488. X *
  2489. X * This code is subject to the following copyright restrictions:
  2490. X *
  2491. X * 1.  Redistribution and use in source and binary forms are permitted
  2492. X *     provided that the above copyright notice is duplicated in the
  2493. X *     source form and the copyright notice in file sh6.c is displayed
  2494. X *     on entry to the program.
  2495. X *
  2496. X * 2.  The sources (or parts thereof) or objects generated from the sources
  2497. X *     (or parts of sources) cannot be sold under any circumstances.
  2498. X *
  2499. X *    $Header: sh9.c 1.1 90/01/26 17:25:19 MS_user Exp $
  2500. X *
  2501. X *    $Log:    sh9.c $
  2502. X * Revision 1.1  90/01/26  17:25:19  MS_user
  2503. X * Initial revision
  2504. X * 
  2505. X * 
  2506. X */
  2507. X
  2508. X#include <sys/types.h>
  2509. X#include <stdio.h>
  2510. X#include <conio.h>
  2511. X#include <string.h>
  2512. X#include <memory.h>
  2513. X#include <ctype.h>
  2514. X#include <signal.h>
  2515. X#include <stdlib.h>
  2516. X#include <stddef.h>
  2517. X#include <errno.h>
  2518. X#include <setjmp.h>
  2519. X#include <limits.h>
  2520. X#include <dos.h>
  2521. X#include <unistd.h>
  2522. X#include "sh.h"
  2523. X
  2524. Xstatic bool    alpha_numeric (int);
  2525. Xstatic bool    function (int);
  2526. Xstatic bool    Process_History (int);
  2527. Xstatic bool    Scan_History (void);
  2528. Xstatic void    Redisplay_Line (void);
  2529. Xstatic void    Process_Stdin (void);
  2530. Xstatic void    Page_History (int);
  2531. Xstatic bool    UpDate_CLine (char *);
  2532. Xstatic bool    Re_start (char *);
  2533. Xstatic void    memrcpy (char *, char *, int);
  2534. Xstatic int    read_cursor_position (void);
  2535. Xstatic void    set_cursor_position (int);
  2536. Xstatic void    gen_cursor_position (void);
  2537. X
  2538. Xstatic bool    insert_mode = FALSE;
  2539. Xstatic char    *c_buffer_pos;        /* Position in command line    */
  2540. Xstatic char    *end_buffer;        /* End of command line        */
  2541. Xstatic int    s_cursor;        /* Start cursor position    */
  2542. Xstatic int    c_history = -1;        /* Current entry        */
  2543. Xstatic int    l_history = 0;        /* End of history array        */
  2544. Xstatic int    M_length = -1;        /* Match length            */
  2545. Xstatic char    l_buffer[LINE_MAX + 1];
  2546. Xstatic char    *No_prehistory   = "history: No previous commands\033[2K\n";
  2547. Xstatic char    *No_MatchHistory = "history: No history match found\033[2K\n";
  2548. Xstatic char    *No_posthistory  = "history: No more commands\033[2K\n";
  2549. Xstatic char    *History_2long   = "history: History line too long\033[2K\n";
  2550. Xstatic char    *H_TooLongI = "History file line too long - ignored (%d)\n";
  2551. X
  2552. X/* Arrary of history Items */
  2553. X
  2554. Xstatic struct    cmd_history {
  2555. X    int        number;
  2556. X    char    *command;
  2557. X} cmd_history[HISTORY_MAX];
  2558. X
  2559. X/* Processing standard input */
  2560. X
  2561. Xint            Get_stdin (ap)
  2562. Xregister IO_Args    *ap;
  2563. X{
  2564. X    int        coff = (int)ap->afpos;
  2565. X    char    rv;
  2566. X
  2567. X/* Is there anything in the input buffer.  If not, add the previous line to
  2568. X * the history buffer and get the next line
  2569. X */
  2570. X
  2571. X    if (!coff)
  2572. X    Process_Stdin ();            /* No - get input    */
  2573. X
  2574. X/* Get the next character */
  2575. X
  2576. X    if ((rv = l_buffer[coff]) == NL)
  2577. X    {
  2578. X    l_buffer[coff] = 0;
  2579. X    ap->afpos = 0L;
  2580. X    }
  2581. X
  2582. X/* Check for end of file */
  2583. X
  2584. X    else if (rv == 0x1a)
  2585. X    {
  2586. X    l_buffer[coff] = 0;
  2587. X    ap->afpos = 0L;
  2588. X    rv = 0;
  2589. X    }
  2590. X
  2591. X    else
  2592. X    ap->afpos++;
  2593. X
  2594. X    return rv;
  2595. X}
  2596. X
  2597. X/* Input processing function */
  2598. X
  2599. Xstatic void    Process_Stdin ()
  2600. X{
  2601. X    int        i;
  2602. X    char    *control = "^x";
  2603. X
  2604. X/* Set to last history item */
  2605. X
  2606. X    c_history = l_history - 1;
  2607. X
  2608. X/* Process the input */
  2609. X
  2610. X    while (TRUE)
  2611. X    {
  2612. X    c_buffer_pos = l_buffer;    /* Initialise            */
  2613. X    end_buffer = l_buffer;
  2614. X    insert_mode = FALSE;
  2615. X    M_length = -1;
  2616. X    s_cursor = read_cursor_position ();
  2617. X
  2618. X    while (((i = getch ()) != 0x1a) && (i != NL) && (i != '\r'))
  2619. X    {
  2620. X
  2621. X/* Re-position the line? */
  2622. X
  2623. X        if (((i) ? alpha_numeric (i) : function (getch ())))
  2624. X        Redisplay_Line ();
  2625. X
  2626. X/* Reposition the cursor */
  2627. X
  2628. X        gen_cursor_position ();
  2629. X    }
  2630. X
  2631. X/* Terminate the line */
  2632. X
  2633. X    *end_buffer = 0;
  2634. X    v1_putc (NL);
  2635. X
  2636. X/* Line input - check for history */
  2637. X
  2638. X    if ((*l_buffer == '!') && Process_History (0))
  2639. X    {
  2640. X        v1a_puts (l_buffer);
  2641. X        break;
  2642. X    }
  2643. X    
  2644. X    else if (*l_buffer != '!')
  2645. X        break;
  2646. X
  2647. X/* Output prompt and try again */
  2648. X
  2649. X    Re_start ((char *)NULL);
  2650. X    }
  2651. X
  2652. X    *end_buffer = (char)((i == '\r') ? NL : i);
  2653. X}
  2654. X
  2655. X/* Handler Alpha_numeric characters */
  2656. X
  2657. Xstatic bool    alpha_numeric (c)
  2658. Xint        c;
  2659. X{
  2660. X    bool    redisplay = FALSE;
  2661. X
  2662. X/* Backspace processing */
  2663. X
  2664. X    if (c == 0x08)
  2665. X    {
  2666. X    if (c_buffer_pos == l_buffer)
  2667. X    {
  2668. X        v1_putc (0x07);        /* Ring bell            */
  2669. X        return FALSE;
  2670. X    }
  2671. X
  2672. X/* Decrement current position */
  2673. X
  2674. X    if ((c_buffer_pos--) == end_buffer)
  2675. X        --end_buffer;
  2676. X
  2677. X    else
  2678. X        *c_buffer_pos = ' ';
  2679. X
  2680. X        return TRUE;
  2681. X    }
  2682. X
  2683. X/* Normal character processing */
  2684. X
  2685. X    if ((c_buffer_pos - l_buffer) == LINE_MAX)
  2686. X    {
  2687. X    v1_putc (0x07);            /* Ring bell            */
  2688. X    return FALSE;
  2689. X    }
  2690. X
  2691. X    else if (!insert_mode)
  2692. X    {
  2693. X    if (c_buffer_pos == end_buffer)
  2694. X        ++end_buffer;
  2695. X
  2696. X    else if (iscntrl (*c_buffer_pos) || iscntrl (c))
  2697. X        redisplay = TRUE;
  2698. X
  2699. X    *(c_buffer_pos++) = (char)c;
  2700. X
  2701. X    if (redisplay || (c == '\t'))
  2702. X        return TRUE;
  2703. X
  2704. X    if (iscntrl (c))
  2705. X    {
  2706. X        v1_putc ('^');
  2707. X        c += '@';
  2708. X    }
  2709. X
  2710. X    v1_putc ((char)c);
  2711. X    return FALSE;
  2712. X    }
  2713. X
  2714. X    else if ((end_buffer - l_buffer) == LINE_MAX)
  2715. X    {
  2716. X    v1_putc (0x07);            /* Ring bell - line full    */
  2717. X    return FALSE;
  2718. X    }
  2719. X
  2720. X    else
  2721. X    {
  2722. X    if (c_buffer_pos != end_buffer)
  2723. X        memrcpy (end_buffer + 1, end_buffer, end_buffer - c_buffer_pos + 1);
  2724. X
  2725. X    ++end_buffer;
  2726. X    *(c_buffer_pos++) = (char)c;
  2727. X    return TRUE;
  2728. X    }
  2729. X}
  2730. X
  2731. X/* Process function keys */
  2732. X
  2733. Xstatic bool    function (fn)
  2734. Xint        fn;
  2735. X{
  2736. X    switch (fn)
  2737. X    {
  2738. X    case 'I':            /* Scan back command line    */
  2739. X    case 'Q':            /* Scan up command line        */
  2740. X        if (M_length == -1)
  2741. X        break;
  2742. X
  2743. X        Page_History ((fn == 'I') ? -1 : 1);
  2744. X        return TRUE;
  2745. X
  2746. X    case 'H':            /* Previous command line    */
  2747. X        Process_History (-1);
  2748. X        return TRUE;
  2749. X
  2750. X    case 'P':            /* Next command line        */
  2751. X        Process_History (1);
  2752. X        return TRUE;
  2753. X
  2754. X    case 'K':            /* Cursor left            */
  2755. X        if (c_buffer_pos != l_buffer)
  2756. X        --c_buffer_pos;
  2757. X
  2758. X        else
  2759. X        v1_putc (0x07);
  2760. X
  2761. X        return FALSE;
  2762. X
  2763. X    case 'M':            /* Cursor right            */
  2764. X        if (c_buffer_pos != end_buffer)
  2765. X        ++c_buffer_pos;
  2766. X
  2767. X        else
  2768. X        v1_putc (0x07);
  2769. X
  2770. X        return FALSE;
  2771. X
  2772. X    case 's':            /* Cursor left a word        */
  2773. X        if (c_buffer_pos != l_buffer)
  2774. X        {
  2775. X        --c_buffer_pos;        /* Reposition on previous char    */
  2776. X
  2777. X        while (isspace (*c_buffer_pos) && (c_buffer_pos != l_buffer))
  2778. X            --c_buffer_pos;
  2779. X
  2780. X        while (!isspace (*c_buffer_pos) && (c_buffer_pos != l_buffer))
  2781. X            --c_buffer_pos;
  2782. X
  2783. X        if (c_buffer_pos != l_buffer)
  2784. X            ++c_buffer_pos;
  2785. X        }
  2786. X
  2787. X        else
  2788. X        v1_putc (0x07);
  2789. X
  2790. X        return FALSE;
  2791. X
  2792. X    case 't':            /* Cursor right a word        */
  2793. X        if (c_buffer_pos != end_buffer)
  2794. X        {
  2795. X
  2796. X/* Skip to the end of the current word */
  2797. X
  2798. X        while (!isspace (*c_buffer_pos) && (c_buffer_pos != end_buffer))
  2799. X            ++c_buffer_pos;
  2800. X
  2801. X/* Skip over the white space */
  2802. X
  2803. X        while (isspace (*c_buffer_pos) && (c_buffer_pos != end_buffer))
  2804. X            ++c_buffer_pos;
  2805. X        }
  2806. X
  2807. X        else
  2808. X        v1_putc (0x07);
  2809. X
  2810. X        return FALSE;
  2811. X
  2812. X    case 'G':            /* Cursor home            */
  2813. X        c_buffer_pos = l_buffer;
  2814. X        return FALSE;
  2815. X
  2816. X    case 'u':            /* Flush to end            */
  2817. X        memset (c_buffer_pos, ' ', end_buffer - c_buffer_pos);
  2818. X        end_buffer = c_buffer_pos;
  2819. X        return TRUE;
  2820. X
  2821. X    case 'O':            /* Cursor end of command    */
  2822. X        if (*l_buffer == '!')
  2823. X        {
  2824. X        *end_buffer = 0;
  2825. X        Process_History (2);
  2826. X        return TRUE;
  2827. X        }
  2828. X
  2829. X        c_buffer_pos = end_buffer;
  2830. X        return FALSE;
  2831. X
  2832. X    case 'R':            /* Switch insert mode        */
  2833. X        insert_mode = (insert_mode) ? FALSE : TRUE;
  2834. X        return FALSE;
  2835. X
  2836. X    case 'S':            /* Delete character        */
  2837. X        if (c_buffer_pos != end_buffer)
  2838. X        memcpy (c_buffer_pos, c_buffer_pos + 1,
  2839. X            end_buffer - c_buffer_pos);
  2840. X
  2841. X        if (end_buffer == l_buffer)
  2842. X        {
  2843. X        v1_putc (0x07);
  2844. X        return TRUE;
  2845. X        }
  2846. X
  2847. X        if (--end_buffer < c_buffer_pos)
  2848. X        --c_buffer_pos;
  2849. X
  2850. X           return TRUE;
  2851. X    }
  2852. X
  2853. X    v1_putc (0x07);
  2854. X    return FALSE;
  2855. X}
  2856. X
  2857. X/* Read Cursor position */
  2858. X
  2859. Xstatic int    read_cursor_position ()
  2860. X{
  2861. X    union REGS    r;
  2862. X
  2863. X    r.h.ah = 0x03;                /* Read cursor position    */
  2864. X    r.h.bh = 0;                    /* Page zero        */
  2865. X    int86 (0x10, &r, &r);
  2866. X    return (r.h.dh * 80) + r.h.dl;
  2867. X}
  2868. X
  2869. X/* Re-position the cursor */
  2870. X
  2871. Xstatic void    set_cursor_position (new)
  2872. Xint        new;
  2873. X{
  2874. X    union REGS    r;
  2875. X
  2876. X    r.h.ah = 0x02;                /* Set new position    */
  2877. X    r.h.bh = 0;                    /* Page zero        */
  2878. X    r.h.dh = (unsigned char)(new / 80);
  2879. X    r.h.dl = (unsigned char)(new % 80);
  2880. X
  2881. X/* Are we at the bottom of the page? */
  2882. X
  2883. X    if (r.h.dh == 25)
  2884. X    {
  2885. X    r.h.dh = 24;
  2886. X    s_cursor -= 80;
  2887. X    }
  2888. X
  2889. X    int86 (0x10, &r, &r);
  2890. X}
  2891. X
  2892. X/* Generate the new cursor position */
  2893. X
  2894. Xstatic void    gen_cursor_position ()
  2895. X{
  2896. X    char    *cp = l_buffer - 1;
  2897. X    int        off = s_cursor;
  2898. X
  2899. X/* Search to current position */
  2900. X
  2901. X    while (++cp != c_buffer_pos)
  2902. X    {
  2903. X    if (*cp == '\t')
  2904. X        while ((++off) % 8);
  2905. X
  2906. X    else if (iscntrl (*cp))
  2907. X        off += 2;
  2908. X
  2909. X    else
  2910. X        ++off;
  2911. X    }
  2912. X
  2913. X/* Position the cursor */
  2914. X
  2915. X    set_cursor_position (off);
  2916. X}
  2917. X
  2918. X/* Redisplay the current line */
  2919. X
  2920. Xstatic void    Redisplay_Line ()
  2921. X{
  2922. X    char    *control = "^x";
  2923. X    char    *cp = l_buffer;
  2924. X    int        off = s_cursor;
  2925. X
  2926. X/* Reposition to start of line */
  2927. X
  2928. X    set_cursor_position (s_cursor);
  2929. X
  2930. X/* Output the line */
  2931. X
  2932. X    while (cp != end_buffer)
  2933. X    {
  2934. X    if (*cp == '\t')
  2935. X    {
  2936. X        do
  2937. X        {
  2938. X        v1_putc (SP);
  2939. X        } while ((++off) % 8);
  2940. X    }
  2941. X
  2942. X    else if (iscntrl (*cp))
  2943. X    {
  2944. X        control[1] = *cp + '@';
  2945. X        v1_puts (control);
  2946. X        off += 2;
  2947. X    }
  2948. X
  2949. X    else
  2950. X    {
  2951. X        ++off;
  2952. X        v1_putc (*cp);
  2953. X    }
  2954. X
  2955. X    ++cp;
  2956. X    }
  2957. X
  2958. X    v1_puts ("\033[2K");        /* clear to end of line    */
  2959. X}
  2960. X
  2961. X/* Process history command
  2962. X *
  2963. X * -1: Previous command
  2964. X *  1: Next command
  2965. X *  0: Current command
  2966. X *  2: Current command with no options processing
  2967. X */
  2968. X
  2969. Xstatic bool    Process_History (direction)
  2970. Xint        direction;
  2971. X{
  2972. X    char    *optionals = null;
  2973. X
  2974. X    c_buffer_pos = l_buffer;
  2975. X    end_buffer = l_buffer;
  2976. X    c_history += (direction == 2) ? 0 : direction;
  2977. X
  2978. X    switch (direction)
  2979. X    {
  2980. X    case -1:            /* Move up one line        */
  2981. X        if (c_history < 0)
  2982. X        {
  2983. X        ++c_history;
  2984. X        return Re_start (No_prehistory);
  2985. X        }
  2986. X
  2987. X        break;
  2988. X
  2989. X    case 1:                /* Move to next history line    */
  2990. X        if (c_history >= l_history)
  2991. X        {
  2992. X        --c_history;
  2993. X        return Re_start (No_posthistory);
  2994. X        }
  2995. X
  2996. X        break;
  2997. X
  2998. X    case 0:                /* Check out l_buffer        */
  2999. X        optionals = l_buffer;    /* Are there any additions to    */
  3000. X                    /* the history line        */
  3001. X
  3002. X/* Find the end of the first part */
  3003. X
  3004. X        while (!isspace (*optionals) && *optionals)
  3005. X        ++optionals;
  3006. X
  3007. X/* Terminate the history command */
  3008. X
  3009. X        if (*optionals)
  3010. X        *(optionals++) = 0;
  3011. X
  3012. X/* Find the end of the space separator part which gives the start of the
  3013. X * optionals
  3014. X */
  3015. X
  3016. X        while (isspace (*optionals))
  3017. X        ++optionals;
  3018. X        
  3019. X
  3020. X/* Copy selected item into line buffer */
  3021. X
  3022. X    case 2:
  3023. X        M_length = strlen (l_buffer) - 1;
  3024. X        if (!Scan_History ())
  3025. X        return FALSE;
  3026. X
  3027. X        break;
  3028. X    }
  3029. X
  3030. X    return UpDate_CLine (optionals);
  3031. X}
  3032. X
  3033. X/* Ok c_history points to the new line.  Move optionals after history
  3034. X * and the copy in history and add a space
  3035. X */
  3036. X
  3037. Xstatic bool    UpDate_CLine (optionals)
  3038. Xchar        *optionals;
  3039. X{
  3040. X    int        opt_len;
  3041. X
  3042. X    end_buffer = &l_buffer[strlen (cmd_history[c_history].command)];
  3043. X
  3044. X    if ((end_buffer - l_buffer + (opt_len = strlen (optionals)) + 1) >= LINE_MAX)
  3045. X    return Re_start (History_2long);
  3046. X
  3047. X    if (end_buffer > optionals)
  3048. X    memrcpy (end_buffer + 1 + opt_len, optionals + opt_len, opt_len + 1);
  3049. X    
  3050. X    else
  3051. X    strcpy (end_buffer + 1, optionals);
  3052. X
  3053. X    strcpy (l_buffer, cmd_history[c_history].command);
  3054. X
  3055. X    if (opt_len)
  3056. X    *end_buffer = ' ';
  3057. X
  3058. X    end_buffer = &l_buffer[strlen (l_buffer)];
  3059. X    return TRUE;
  3060. X}
  3061. X
  3062. X/* Scan the line buffer for a history match */
  3063. X
  3064. Xstatic bool    Scan_History ()
  3065. X{
  3066. X    char    *cp = &l_buffer[1];
  3067. X    int        c_len = strlen (cp);
  3068. X    char    *ep;
  3069. X    int        i = (int)strtol (cp, &ep, 10);
  3070. X
  3071. X/* Get the previous command ? (single !) */
  3072. X
  3073. X    if (c_len == 0)
  3074. X    {
  3075. X    if (c_history < 0)
  3076. X    {
  3077. X        M_length = -1;
  3078. X        return Re_start (No_prehistory);
  3079. X    }
  3080. X
  3081. X    return TRUE;
  3082. X    }
  3083. X
  3084. X/* Request for special history number item.  Check History file empty */
  3085. X
  3086. X    if (l_history == 0)
  3087. X    {
  3088. X    M_length = -1;
  3089. X    return Re_start (No_MatchHistory);
  3090. X    }
  3091. X
  3092. X/* Check for number */
  3093. X
  3094. X    if (!*ep)
  3095. X    {
  3096. X    M_length = -1;
  3097. X
  3098. X    for (c_history = l_history - 1;
  3099. X        (cmd_history[c_history].number != i) && (c_history >= 0);
  3100. X        --c_history);
  3101. X    }
  3102. X
  3103. X/* No - scan for a match */
  3104. X
  3105. X    else
  3106. X    {
  3107. X    for (c_history = l_history - 1;
  3108. X        (strncmp (cp, cmd_history[c_history].command, c_len) != 0)
  3109. X         && (c_history >= 0);
  3110. X        --c_history);
  3111. X    }
  3112. X
  3113. X/* Anything found ? */
  3114. X
  3115. X    if (c_history == -1)
  3116. X    {
  3117. X    c_history = l_history - 1;
  3118. X    return Re_start (No_MatchHistory);
  3119. X    }
  3120. X
  3121. X    return TRUE;
  3122. X}
  3123. X
  3124. X/* Scan back or forward from current history */
  3125. X
  3126. Xstatic void    Page_History (direction)
  3127. Xint        direction;
  3128. X{
  3129. X    c_buffer_pos = l_buffer;
  3130. X    end_buffer = l_buffer;
  3131. X
  3132. X    if (l_history == 0)
  3133. X    {
  3134. X    M_length = -1;
  3135. X    Re_start (No_MatchHistory);
  3136. X    return;
  3137. X    }
  3138. X
  3139. X/* scan for a match */
  3140. X
  3141. X    while (((c_history += direction) >= 0) && (c_history != l_history) &&
  3142. X       (strncmp (l_buffer, cmd_history[c_history].command, M_length) != 0));
  3143. X
  3144. X/* Anything found ? */
  3145. X
  3146. X    if ((c_history < 0) || (c_history == l_history))
  3147. X    {
  3148. X    c_history = l_history - 1;
  3149. X    Re_start (No_MatchHistory);
  3150. X    }
  3151. X
  3152. X    else
  3153. X    UpDate_CLine (null);
  3154. X}
  3155. X
  3156. X/* Load history file */
  3157. X
  3158. Xvoid    Load_History ()
  3159. X{
  3160. X    FILE        *fp;
  3161. X    char        *cp;
  3162. X    int            i = 0;
  3163. X    Var_List        *lset;
  3164. X
  3165. X/* Initialise history array */
  3166. X
  3167. X    memset (cmd_history, 0, sizeof (struct cmd_history) * HISTORY_MAX);
  3168. X    c_history = -1;            /* Current entry        */
  3169. X    l_history = 0;            /* End of history array        */
  3170. X
  3171. X    if ((lset = lookup (history_file, TRUE))->value == null)
  3172. X    setval (lset, strcat (strcpy (l_buffer, lookup (home, FALSE)->value),
  3173. X                  "history.sh"));
  3174. X
  3175. X    if (!History_Enabled || ((fp = fopen (lset->value, "rt")) == (FILE *)NULL))
  3176. X    return;
  3177. X
  3178. X/* Read in file */
  3179. X
  3180. X    while (fgets (l_buffer, LINE_MAX, fp) != (char *)NULL)
  3181. X    {
  3182. X    ++i;
  3183. X
  3184. X    if ((cp = strchr (l_buffer, NL)) == (char *)NULL)
  3185. X        print_warn (H_TooLongI, i);
  3186. X
  3187. X    else
  3188. X    {
  3189. X        *cp = 0;
  3190. X        Add_History (TRUE);
  3191. X    }
  3192. X    }
  3193. X
  3194. X    fclose (fp);
  3195. X}
  3196. X
  3197. X/* Add entry to history file */
  3198. X
  3199. Xvoid    Add_History (past)
  3200. Xbool    past;                /* Past history?    */
  3201. X{
  3202. X    int            i;
  3203. X
  3204. X    if ((!History_Enabled) || (strlen (l_buffer) == 0))
  3205. X    return;
  3206. X
  3207. X/* If adding past history, decrement all numbers previous */
  3208. X
  3209. X    if ((past) && l_history)
  3210. X    {
  3211. X    for (i = 0; i < l_history; i++)
  3212. X        --(cmd_history[i].number);
  3213. X    }
  3214. X
  3215. X/* If the array is full, remove the last item */
  3216. X
  3217. X    if (l_history == HISTORY_MAX)
  3218. X    {
  3219. X    if (cmd_history[0].command != null)
  3220. X        DELETE (cmd_history[0].command);
  3221. X
  3222. X    --l_history;
  3223. X    memcpy (&cmd_history[0], &cmd_history[1],
  3224. X        sizeof (struct cmd_history) * (HISTORY_MAX - 1));
  3225. X    }
  3226. X
  3227. X/* If there are any items in the array */
  3228. X
  3229. X    c_history = l_history;
  3230. X    Current_Event = (l_history) ? cmd_history[l_history - 1].number + 1 : 0;
  3231. X    cmd_history[l_history].number = Current_Event;
  3232. X
  3233. X/* Save the string */
  3234. X
  3235. X    cmd_history[l_history++].command = strsave (l_buffer, 0);
  3236. X}
  3237. X
  3238. X/* Print history */
  3239. X
  3240. Xvoid    Display_History ()
  3241. X{
  3242. X    int            i;
  3243. X    struct cmd_history    *cp = cmd_history;
  3244. X
  3245. X    if (!l_history)
  3246. X    return;
  3247. X
  3248. X    for (i = 0; i < l_history; ++cp, ++i)
  3249. X    {
  3250. X    v1printf ("%5d: ", cp->number);
  3251. X    v1a_puts (cp->command);
  3252. X    }
  3253. X}
  3254. X
  3255. X/* Dump history to file */
  3256. X
  3257. Xvoid    Dump_History ()
  3258. X{
  3259. X    int            i;
  3260. X    struct cmd_history    *cp = cmd_history;
  3261. X    FILE        *fp;
  3262. X
  3263. X    if (!History_Enabled ||
  3264. X    ((fp = fopen (lookup (history_file, FALSE)->value, "wt")) ==
  3265. X     (FILE *)NULL))
  3266. X    return;
  3267. X
  3268. X    for (i = 0; i < l_history; ++cp, ++i)
  3269. X    {
  3270. X    fputs (cp->command, fp);
  3271. X    fputc (NL, fp);
  3272. X    }
  3273. X
  3274. X    fclose (fp);
  3275. X}
  3276. X
  3277. X/* Clear out history */
  3278. X
  3279. Xvoid    Clear_History ()
  3280. X{
  3281. X    int            i;
  3282. X    struct cmd_history    *cp = cmd_history;
  3283. X
  3284. X    for (i = 0; i < l_history; ++cp, ++i)
  3285. X    {
  3286. X    if (cp->command != null)
  3287. X        DELETE (cp->command);
  3288. X    }
  3289. X
  3290. X    memset (cmd_history, 0, sizeof (struct cmd_history) * HISTORY_MAX);
  3291. X
  3292. X    c_history = -1;            /* Current entry        */
  3293. X    l_history = 0;            /* End of history array        */
  3294. X    Current_Event = 0;
  3295. X}
  3296. X
  3297. X/* Output warning message and prompt */
  3298. X
  3299. Xstatic bool    Re_start (cp)
  3300. Xchar        *cp;
  3301. X{
  3302. X    if (cp != (char *)NULL)
  3303. X    print_warn (cp);
  3304. X
  3305. X    put_prompt (last_prompt);
  3306. X
  3307. X/* Re-initialise */
  3308. X
  3309. X    c_buffer_pos = l_buffer;
  3310. X    end_buffer = l_buffer;
  3311. X    s_cursor = read_cursor_position ();
  3312. X
  3313. X    return FALSE;
  3314. X}
  3315. X
  3316. X/* Copy backwards */
  3317. X
  3318. Xstatic void    memrcpy (sp1, sp, cnt)
  3319. Xchar        *sp1;
  3320. Xchar        *sp;
  3321. Xint        cnt;
  3322. X{
  3323. X    while (cnt--)
  3324. X    *(sp1--) =  *(sp--);
  3325. X}
  3326. SHAR_EOF
  3327. chmod 0644 shell/sh9.c || echo "restore of shell/sh9.c fails"
  3328. set `wc -c shell/sh9.c`;Sum=$1
  3329. if test "$Sum" != "15932"
  3330. then echo original size 15932, current size $Sum;fi
  3331. echo "x - extracting shell/sh10.c (Text)"
  3332. sed 's/^X//' << 'SHAR_EOF' > shell/sh10.c &&
  3333. X/* MS-DOS SHELL - Function Processing
  3334. X *
  3335. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
  3336. X *
  3337. X * This code is subject to the following copyright restrictions:
  3338. X *
  3339. X * 1.  Redistribution and use in source and binary forms are permitted
  3340. X *     provided that the above copyright notice is duplicated in the
  3341. X *     source form and the copyright notice in file sh6.c is displayed
  3342. X *     on entry to the program.
  3343. X *
  3344. X * 2.  The sources (or parts thereof) or objects generated from the sources
  3345. X *     (or parts of sources) cannot be sold under any circumstances.
  3346. X *
  3347. X *    $Header: sh10.c 1.1 90/01/25 13:40:54 MS_user Exp $
  3348. X *
  3349. X *    $Log:    sh10.c $
  3350. X * Revision 1.1  90/01/25  13:40:54  MS_user
  3351. X * Initial revision
  3352. X * 
  3353. X */
  3354. X
  3355. X#include <sys/types.h>
  3356. X#include <sys/stat.h>
  3357. X#include <stdio.h>
  3358. X#include <process.h>
  3359. X#include <dos.h>
  3360. X#include <signal.h>
  3361. X#include <errno.h>
  3362. X#include <setjmp.h>
  3363. X#include <ctype.h>
  3364. X#include <string.h>
  3365. X#include <unistd.h>
  3366. X#include <stdlib.h>
  3367. X#include <fcntl.h>
  3368. X#include <limits.h>
  3369. X#include "sh.h"
  3370. X
  3371. X/* Function declarations */
  3372. X
  3373. Xstatic void    Print_Command (C_Op *);
  3374. Xstatic void    Print_IO (IO_Actions *);
  3375. Xstatic void    Print_Case (C_Op *);
  3376. Xstatic void    Print_IString (char *, int);
  3377. Xstatic void    Set_Free_ExTree (C_Op *, void (*)(char *));
  3378. Xstatic void    Set_Free_Command (C_Op *, void (*)(char *));
  3379. Xstatic void    Set_Free_Case (C_Op *, void (*)(char *));
  3380. Xstatic void    Set_ExTree (char *);
  3381. Xstatic void    Free_ExTree (char *);
  3382. X
  3383. Xstatic int    Print_indent;            /* Current indent level    */
  3384. X
  3385. X/*
  3386. X * print the execute tree - used for displaying functions
  3387. X */
  3388. X
  3389. Xvoid        Print_ExTree (t)
  3390. Xregister C_Op    *t;
  3391. X{
  3392. X    char        **wp;
  3393. X
  3394. X    if (t == (C_Op *)NULL)
  3395. X    return;
  3396. X
  3397. X/* Check for start of print */
  3398. X
  3399. X    if (t->type == TFUNC)
  3400. X    {
  3401. X    Print_indent = 0;
  3402. X    v1_puts (*t->words);
  3403. X    v1a_puts (" ()");
  3404. X    Print_ExTree (t->left);
  3405. X    return;
  3406. X    }
  3407. X
  3408. X/* Otherwise, process the tree and print it */
  3409. X
  3410. X    switch (t->type) 
  3411. X    {
  3412. X    case TPAREN:            /* ()            */
  3413. X    case TCOM:            /* A command process    */
  3414. X        Print_Command (t);
  3415. X        return;
  3416. X
  3417. X    case TPIPE:            /* Pipe processing        */
  3418. X        Print_ExTree (t->left);
  3419. X        Print_IString ("|\n", 0);
  3420. X        Print_ExTree (t->right);
  3421. X        return;
  3422. X
  3423. X    case TLIST:            /* Entries in a for statement    */
  3424. X        Print_ExTree (t->left);
  3425. X        Print_ExTree (t->right);
  3426. X        return;
  3427. X
  3428. X    case TOR:            /* || and &&            */
  3429. X    case TAND:
  3430. X        Print_ExTree (t->left);
  3431. X
  3432. X        if (t->right != (C_Op *)NULL)
  3433. X        {
  3434. X        Print_IString ((t->type == TAND) ? "&&\n" : "||\n", 0);
  3435. X        Print_ExTree (t->right);
  3436. X        }
  3437. X
  3438. X        return;
  3439. X
  3440. X    case TFOR:            /* First part of a for statement*/
  3441. X        Print_IString ("for ", 0);
  3442. X        v1_puts (t->str);
  3443. X
  3444. X        if ((wp = t->words) != (char **)NULL)
  3445. X        {
  3446. X        v1_puts (" in");
  3447. X
  3448. X        while (*wp != (char *)NULL)
  3449. X        {
  3450. X            v1_putc (SP);
  3451. X            v1_puts (*wp++);
  3452. X        }
  3453. X        }
  3454. X
  3455. X        v1_putc (NL);
  3456. X        Print_IString ("do\n", 1);
  3457. X        Print_ExTree (t->left);
  3458. X        Print_IString ("done\n", -1);
  3459. X        return;
  3460. X
  3461. X    case TWHILE:            /* WHILE and UNTIL functions    */
  3462. X    case TUNTIL:
  3463. X        Print_IString ((t->type == TWHILE) ? "while " : "until ", 1);
  3464. X        Print_ExTree (t->left);
  3465. X        Print_IString ("do\n", 0);
  3466. X        Print_ExTree (t->right);
  3467. X        Print_IString ("done\n", -1);
  3468. X        return;
  3469. X
  3470. X    case TIF:            /* IF and ELSE IF functions    */
  3471. X    case TELIF:
  3472. X        if (t->type == TIF)
  3473. X        Print_IString ("if\n", 1);
  3474. X        
  3475. X        else
  3476. X        Print_IString ("elif\n", 1);
  3477. X        
  3478. X        Print_ExTree (t->left);
  3479. X
  3480. X        Print_indent -= 1;
  3481. X        Print_IString ("then\n", 1);
  3482. X        Print_ExTree (t->right->left);
  3483. X
  3484. X        if (t->right->right != (C_Op *)NULL)
  3485. X        {
  3486. X        Print_indent -= 1;
  3487. X
  3488. X        if (t->right->right->type != TELIF)
  3489. X            Print_IString ("else\n", 1);
  3490. X
  3491. X        Print_ExTree (t->right->right);
  3492. X        }
  3493. X
  3494. X        if (t->type == TIF)
  3495. X        Print_IString ("fi\n", -1);
  3496. X
  3497. X        return;
  3498. X
  3499. X    case TCASE:            /* CASE function        */
  3500. X        Print_IString ("case ", 1);
  3501. X        v1_puts (t->str);
  3502. X        v1a_puts (" do");
  3503. X        Print_Case (t->left);
  3504. X        Print_IString (" esac\n", -1);
  3505. X        return;
  3506. X
  3507. X    case TBRACE:            /* {} statement            */
  3508. X        Print_IString ("{\n", 1);
  3509. X        if (t->left != (C_Op *)NULL)
  3510. X        Print_ExTree (t->left);
  3511. X
  3512. X        Print_IString ("}\n", -1);
  3513. X        return;
  3514. X    }
  3515. X}
  3516. X
  3517. X/*
  3518. X * Print a command line
  3519. X */
  3520. X
  3521. Xstatic void    Print_Command (t)
  3522. Xregister C_Op    *t;
  3523. X{
  3524. X    char    *cp;
  3525. X    IO_Actions    **iopp;
  3526. X    char    **wp = t->words;
  3527. X    char    **owp = wp;
  3528. X
  3529. X    if (t->type == TCOM) 
  3530. X    {
  3531. X    while ((cp = *wp++) != (char *)NULL)
  3532. X        ;
  3533. X
  3534. X    cp = *wp;
  3535. X
  3536. X/* strip all initial assignments not correct wrt PATH=yyy command  etc */
  3537. X
  3538. X    if ((cp == (char *)NULL) && (t->ioact == (IO_Actions **)NULL))
  3539. X    {
  3540. X        Print_IString (null, 0);
  3541. X
  3542. X        while (*owp != (char *)NULL)
  3543. X        v1a_puts (*(owp++));
  3544. X
  3545. X        return;
  3546. X    }
  3547. X    }
  3548. X
  3549. X/* Parenthesis ? */
  3550. X
  3551. X    if (t->type == TPAREN)
  3552. X    {
  3553. X    Print_IString ("(\n", 1);
  3554. X    Print_ExTree (t->left);
  3555. X    Print_IString (")", -1);
  3556. X    }
  3557. X
  3558. X    else
  3559. X    {
  3560. X    Print_IString (null, 0);
  3561. X
  3562. X    while (*owp != (char *)NULL)
  3563. X    {
  3564. X        v1_puts (*owp++);
  3565. X
  3566. X        if (*owp != (char *)NULL)
  3567. X        v1_putc (SP);
  3568. X    }
  3569. X    }
  3570. X
  3571. X/* Set up anyother IO required */
  3572. X
  3573. X    if ((iopp = t->ioact) != (IO_Actions **)NULL) 
  3574. X    {
  3575. X    while (*iopp != (IO_Actions *)NULL)
  3576. X        Print_IO (*iopp++);
  3577. X    }
  3578. X
  3579. X    v1_putc (NL);
  3580. X}
  3581. X
  3582. X/*
  3583. X * Print the IO re-direction
  3584. X */
  3585. X
  3586. Xstatic void        Print_IO (iop)
  3587. Xregister IO_Actions    *iop;
  3588. X{
  3589. X    int        unit = iop->io_unit;
  3590. X    static char    *cunit = " x";
  3591. X
  3592. X    if (unit == IODEFAULT)    /* take default */
  3593. X    unit = (iop->io_flag & (IOREAD | IOHERE)) ? STDIN_FILENO
  3594. X                          : STDOUT_FILENO;
  3595. X
  3596. X/* Output unit number */
  3597. X
  3598. X    cunit[1] = (char)(unit + '0');
  3599. X    v1_puts (cunit);
  3600. X
  3601. X    switch (iop->io_flag) 
  3602. X    {
  3603. X    case IOHERE:
  3604. X    case IOHERE | IOXHERE:
  3605. X        v1_putc ('<');
  3606. X
  3607. X    case IOREAD:
  3608. X        v1_putc ('<');
  3609. X        break;
  3610. X
  3611. X    case IOWRITE | IOCAT:
  3612. X        v1_putc ('>');
  3613. X
  3614. X    case IOWRITE:
  3615. X        v1_putc ('>');
  3616. X        break;
  3617. X
  3618. X    case IODUP:
  3619. X        v1_puts (">&");
  3620. X        v1_putc (*iop->io_name);
  3621. X        return;
  3622. X    }
  3623. X
  3624. X    v1_puts (iop->io_name);
  3625. X}
  3626. X
  3627. X/*
  3628. X * Print out the contents of a case statement
  3629. X */
  3630. X
  3631. Xstatic void    Print_Case (t)
  3632. XC_Op        *t;
  3633. X{
  3634. X    register C_Op    *t1;
  3635. X    register char    **wp;
  3636. X
  3637. X    if (t == (C_Op *)NULL)
  3638. X    return;
  3639. X
  3640. X/* type - TLIST - go down the left tree first and then processes this level */
  3641. X
  3642. X    if (t->type == TLIST) 
  3643. X    {
  3644. X    Print_Case (t->left);
  3645. X    t1 = t->right;
  3646. X    }
  3647. X    
  3648. X    else
  3649. X    t1 = t;
  3650. X
  3651. X/* Output the conditions */
  3652. X
  3653. X    Print_IString (null, 0);
  3654. X
  3655. X    for (wp = t1->words; *wp != (char *)NULL;)
  3656. X    {
  3657. X    v1_puts (*(wp++));
  3658. X
  3659. X    if (*wp != (char *)NULL)
  3660. X        v1_puts (" | ");
  3661. X    }
  3662. X
  3663. X    v1a_puts (" )");
  3664. X    Print_indent += 1;
  3665. X
  3666. X/* Output the commands */
  3667. X
  3668. X    Print_ExTree (t1->left);
  3669. X    Print_IString (";;\n", -1);
  3670. X}
  3671. X
  3672. X/*
  3673. X * Print an indented string
  3674. X */
  3675. X
  3676. Xstatic void    Print_IString (cp, indent)
  3677. Xchar        *cp;
  3678. Xint        indent;
  3679. X{
  3680. X    int        i;
  3681. X
  3682. X    if (indent < 0)
  3683. X    Print_indent += indent;
  3684. X
  3685. X    for (i = 0; i < (Print_indent / 2); i++)
  3686. X    v1_putc ('\t');
  3687. X
  3688. X    if (Print_indent % 2)
  3689. X    v1_puts ("    ");
  3690. X    
  3691. X    v1_puts (cp);
  3692. X
  3693. X    if (indent > 0)
  3694. X    Print_indent += indent;
  3695. X}
  3696. X
  3697. X/*
  3698. X * Look up a function in the save tree
  3699. X */
  3700. X
  3701. XFun_Ops        *Fun_Search (name)
  3702. Xchar        *name;
  3703. X{
  3704. X    Fun_Ops    *fp;
  3705. X
  3706. X    for (fp = fun_list; fp != (Fun_Ops *)NULL; fp = fp->next)
  3707. X    {
  3708. X    if (strcmp (*(fp->tree->words), name) == 0)
  3709. X        return fp;
  3710. X    }
  3711. X
  3712. X    return (Fun_Ops *)NULL;
  3713. X}
  3714. X
  3715. X/*
  3716. X * Save or delete a function tree
  3717. X */
  3718. X
  3719. Xvoid    Save_Function (t, delete_only)
  3720. XC_Op    *t;
  3721. Xbool    delete_only;            /* True - delete        */
  3722. X{
  3723. X    char        *name = *t->words;
  3724. X    register Fun_Ops    *fp = Fun_Search (name);
  3725. X    Fun_Ops        *p_fp = (Fun_Ops *)NULL;
  3726. X
  3727. X/* Find the entry */
  3728. X
  3729. X    for (fp = fun_list; (fp != (Fun_Ops *)NULL) &&
  3730. X            (strcmp (*(fp->tree->words), name) != 0);
  3731. X            p_fp = fp, fp = fp->next);
  3732. X
  3733. X/* If it already exists, free the tree and delete the entry */
  3734. X
  3735. X    if (fp != (Fun_Ops *)NULL)
  3736. X    {
  3737. X    Set_Free_ExTree (fp->tree, Free_ExTree);
  3738. X
  3739. X    if (p_fp == (Fun_Ops *)NULL)
  3740. X        fun_list = fp->next;
  3741. X
  3742. X    else
  3743. X        p_fp->next = fp->next;
  3744. X
  3745. X    DELETE (fp);
  3746. X    }
  3747. X
  3748. X/* If delete only - exit */
  3749. X
  3750. X    if (delete_only)
  3751. X    return;
  3752. X
  3753. X/* Create new entry */
  3754. X
  3755. X    if ((fp = (Fun_Ops *)space (sizeof (Fun_Ops))) == (Fun_Ops *)NULL)
  3756. X    return;
  3757. X
  3758. X    setarea ((char *)fp, 0);
  3759. X    Set_Free_ExTree (t, Set_ExTree);
  3760. X
  3761. X    fp->tree = t;
  3762. X    fp->next = fun_list;
  3763. X    fun_list = fp;
  3764. X}
  3765. X
  3766. X/*
  3767. X * Set ExTree areas to zero function
  3768. X */
  3769. X
  3770. Xstatic void    Set_ExTree (s)
  3771. Xchar        *s;
  3772. X{
  3773. X    setarea (s, 0);
  3774. X}
  3775. X
  3776. X/*
  3777. X * Free the ExTree function
  3778. X */
  3779. X
  3780. Xstatic void    Free_ExTree (s)
  3781. Xchar        *s;
  3782. X{
  3783. X    DELETE (s);
  3784. X}
  3785. X
  3786. X/*
  3787. X * Set/Free function tree area by recursively processing of tree
  3788. X */
  3789. X
  3790. Xstatic void    Set_Free_ExTree (t, func)
  3791. XC_Op        *t;
  3792. Xvoid        (*func)(char *);
  3793. X{
  3794. X    char        **wp;
  3795. X
  3796. X    if (t == (C_Op *)NULL)
  3797. X    return;
  3798. X
  3799. X/* Check for start of print */
  3800. X
  3801. X    if (t->type == TFUNC)
  3802. X    {
  3803. X    (*func)(*t->words);
  3804. X    (*func)((char *)t->words);
  3805. X    Set_Free_ExTree (t->left, func);
  3806. X    }
  3807. X
  3808. X/* Otherwise, process the tree and print it */
  3809. X
  3810. X    switch (t->type) 
  3811. X    {
  3812. X    case TPAREN:            /* ()            */
  3813. X    case TCOM:            /* A command process    */
  3814. X        Set_Free_Command (t, func);
  3815. X        break;
  3816. X
  3817. X    case TPIPE:            /* Pipe processing        */
  3818. X    case TLIST:            /* Entries in a for statement    */
  3819. X    case TOR:            /* || and &&            */
  3820. X    case TAND:
  3821. X    case TWHILE:            /* WHILE and UNTIL functions    */
  3822. X    case TUNTIL:
  3823. X        Set_Free_ExTree (t->left, func);
  3824. X        Set_Free_ExTree (t->right, func);
  3825. X        break;
  3826. X
  3827. X    case TFOR:            /* First part of a for statement*/
  3828. X        (*func)(t->str);
  3829. X
  3830. X        if ((wp = t->words) != (char **)NULL)
  3831. X        {
  3832. X        while (*wp != (char *)NULL)
  3833. X            (*func) (*wp++);
  3834. X
  3835. X        (*func)((char *)t->words);
  3836. X        }
  3837. X
  3838. X        Set_Free_ExTree (t->left, func);
  3839. X        break;
  3840. X
  3841. X    case TIF:            /* IF and ELSE IF functions    */
  3842. X    case TELIF:
  3843. X        Set_Free_ExTree (t->right->left, func);
  3844. X        Set_Free_ExTree (t->right->right, func);
  3845. X        (*func)((char *)t->right);
  3846. X
  3847. X    case TBRACE:            /* {} statement            */
  3848. X        Set_Free_ExTree (t->left, func);
  3849. X        break;
  3850. X
  3851. X    case TCASE:            /* CASE function        */
  3852. X        (*func)(t->str);
  3853. X        Set_Free_Case (t->left, func);
  3854. X        break;
  3855. X    }
  3856. X
  3857. X    (*func)((char *)t);
  3858. X}
  3859. X
  3860. X/*
  3861. X * Set/Free a command line
  3862. X */
  3863. X
  3864. Xstatic void    Set_Free_Command (t, func)
  3865. XC_Op        *t;
  3866. Xvoid        (*func)(char *);
  3867. X{
  3868. X    IO_Actions    **iopp;
  3869. X    char    **wp = t->words;
  3870. X
  3871. X/* Parenthesis ? */
  3872. X
  3873. X    if (t->type == TPAREN)
  3874. X    Set_Free_ExTree (t->left, func);
  3875. X
  3876. X    else
  3877. X    {
  3878. X    while (*wp != (char *)NULL)
  3879. X        (*func)(*wp++);
  3880. X
  3881. X    (*func) ((char *)t->words);
  3882. X    }
  3883. X
  3884. X/* Process up any IO required */
  3885. X
  3886. X    if ((iopp = t->ioact) != (IO_Actions **)NULL) 
  3887. X    {
  3888. X    while (*iopp != (IO_Actions *)NULL)
  3889. X    {
  3890. X        (*func)((char *)(*iopp)->io_name);
  3891. X        (*func)((char *)*iopp);
  3892. X        iopp++;
  3893. X    }
  3894. X
  3895. X    (*func)((char *)t->ioact);
  3896. X    }
  3897. X}
  3898. X
  3899. X/*
  3900. X * Set/Free the contents of a case statement
  3901. X */
  3902. X
  3903. Xstatic void    Set_Free_Case (t, func)
  3904. XC_Op        *t;
  3905. Xvoid        (*func)(char *);
  3906. X{
  3907. X    register C_Op    *t1;
  3908. X    register char    **wp;
  3909. X
  3910. X    if (t == (C_Op *)NULL)
  3911. X    return;
  3912. X
  3913. X/* type - TLIST - go down the left tree first and then processes this level */
  3914. X
  3915. X    if (t->type == TLIST) 
  3916. X    {
  3917. X    Set_Free_Case (t->left, func);
  3918. X    t1 = t->right;
  3919. X    }
  3920. X    
  3921. X    else
  3922. X    t1 = t;
  3923. X
  3924. X/* Set/Free the conditions */
  3925. X
  3926. X    for (wp = t1->words; *wp != (char *)NULL;)
  3927. X    (*func)(*(wp++));
  3928. X
  3929. X    (*func)((char *)t1->words);
  3930. X
  3931. X    Set_Free_ExTree (t1->left, func);
  3932. X}
  3933. SHAR_EOF
  3934. chmod 0644 shell/sh10.c || echo "restore of shell/sh10.c fails"
  3935. set `wc -c shell/sh10.c`;Sum=$1
  3936. if test "$Sum" != "10869"
  3937. then echo original size 10869, current size $Sum;fi
  3938. echo "x - extracting shell/sh0.asm (Text)"
  3939. sed 's/^X//' << 'SHAR_EOF' > shell/sh0.asm &&
  3940. X    TITLE   sh0.asm
  3941. X    NAME    sh0
  3942. X    .8087
  3943. X
  3944. X; MS-DOS SHELL - Swapper
  3945. X;
  3946. X; MS-DOS SHELL - Copyright (c) 1989 Data Logic Limited.
  3947. X;
  3948. X; MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
  3949. X;
  3950. X; This code is subject to the following copyright restrictions:
  3951. X;
  3952. X; 1.  Redistribution and use in source and binary forms are permitted
  3953. X;     provided that the above copyright notice is duplicated in the
  3954. X;     source form and the copyright notice in file sh6.c is displayed
  3955. X;     on entry to the program.
  3956. X;
  3957. X; 2.  The sources (or parts thereof) or objects generated from the sources
  3958. X;     (or parts of sources) cannot be sold under any circumstances.
  3959. X;
  3960. X;    $Header: sh0.asm 1.1 90/01/25 13:43:36 MS_user Exp $
  3961. X;
  3962. X;    $Log:    sh0.asm $
  3963. X;    Revision 1.1  90/01/25  13:43:36  MS_user
  3964. X;    Initial revision
  3965. X;    
  3966. X;
  3967. X
  3968. X;
  3969. X; Segment declarations
  3970. X;
  3971. X
  3972. XSH0_TEXT    segment word public 'CODE'
  3973. XSH0_TEXT    ends
  3974. X
  3975. X_DATA        segment word public 'DATA'
  3976. X_DATA        ends
  3977. X
  3978. XCONST        segment word public 'CONST'
  3979. XCONST        ends
  3980. X
  3981. X_BSS        segment word public 'BSS'
  3982. X_BSS        ends
  3983. X
  3984. XDGROUP        group    CONST, _BSS, _DATA
  3985. X
  3986. X;
  3987. X; Declare external functions and data
  3988. X;
  3989. X    extrn    _raise:far
  3990. X    extrn    __maperror:far
  3991. X    extrn    _errno:word
  3992. X    extrn    __psp:word
  3993. X
  3994. X;
  3995. X; Start of the spawn function
  3996. X;
  3997. X
  3998. XSH0_TEXT    segment
  3999. X        assume  cs: SH0_TEXT, ds: NOTHING, ss: DGROUP
  4000. X
  4001. X;
  4002. X; For this function, all the code and data space are in the code space
  4003. X;
  4004. X        public    _cmd_line
  4005. X        public    _path_line
  4006. X        public    _SW_intr
  4007. X        public    _SW_Blocks
  4008. X        public    _SW_fp
  4009. X        public    _SW_I0_V_BX
  4010. X        public    _SW_I0_V_ES
  4011. X        public    _SW_I23_V_ES
  4012. X        public    _SW_I23_V_BX
  4013. X        public    _SW_EMstart
  4014. X        public    _SW_Mode
  4015. X        public    _SW_EMSFrame
  4016. X
  4017. X_cmd_line    db    129 dup (?)    ; Command line
  4018. X_path_line    db    80 dup (?)    ; Path line
  4019. X_SW_Blocks    dw    0        ; Number of blocks to read/write
  4020. X_SW_fp        dw    0        ; File ID
  4021. X_SW_I23_V_ES    dw    0        ; Interrupt 23 address
  4022. X_SW_I23_V_BX    dw    0
  4023. X_SW_I0_V_BX    dw    0        ; Our Interrupt zero value
  4024. X_SW_I0_V_ES    dw    0
  4025. X_SW_EMstart    dd    0100000H    ; Default Extended Mem start
  4026. X_SW_Mode    dw    0        ; Type of swapping to do
  4027. X                    ;   1 - disk
  4028. X                    ;   2 - Extended memory
  4029. X                    ;   3 - Expanded memory
  4030. X_SW_EMSFrame    dw    0        ; EMS Frame segment
  4031. X_SW_intr    dw    0        ; Interrupt 23 detected.
  4032. X
  4033. X
  4034. X;
  4035. X; Some addition variables
  4036. X;
  4037. X
  4038. XSW_LMstart    dd    0        ; Low Mem start for Extended Mem swap
  4039. XN_mcb        dw    0        ; Start write address
  4040. XResult        dw    0        ; Return value
  4041. XInShell        db    0        ; In shell flag for Interrupt 23
  4042. X
  4043. X;
  4044. X; Stack save pointers
  4045. X;
  4046. X
  4047. XS_ss        dw    0            ; Save Stack pointers
  4048. XS_sp        dw    0
  4049. XS_di        dw    0            ; Save DI, SI
  4050. XS_si        dw    0
  4051. XS_ds        dw    0            ; Save the original DS
  4052. X
  4053. X;
  4054. X; Two blank FCB
  4055. X;
  4056. X
  4057. XFCB1        dw    16    dup (?)
  4058. XFCB2        dw    16    dup (?)
  4059. X
  4060. X;
  4061. X; Extended Memory Global Descriptor tables
  4062. X;
  4063. X
  4064. XGD_table    equ    $
  4065. XGDT_Dummy    dw    4    dup (0)        ; Dummy
  4066. XGDT_self    dw    4    dup (0)        ; For self
  4067. XGDT_src        equ    $            ; Source
  4068. X        dw    04000H            ; Length - 16K bytes
  4069. XGDT_src_low    dw    0            ;     Low Order address
  4070. XGDT_src_high    db    0            ;     High Order address
  4071. X        db    093h            ;     Access Rights
  4072. X        dw    0            ;     Reserved
  4073. XGDT_dest    equ    $            ; Destination
  4074. X        dw    04000H            ;     Length - 16K bytes
  4075. XGDT_dest_low    dw    0            ;     Low Order address
  4076. XGDT_dest_high    db    0            ;     High Order address
  4077. X        db    093h            ;     Access Rights
  4078. X        dw    0            ;     Reserved
  4079. XGDT_bios    dw    4    dup (0)        ; Bios
  4080. XGDT_stack    dw    4    dup (0)        ; Stack
  4081. X
  4082. X;
  4083. X; Execute interrupt structure
  4084. X;
  4085. X
  4086. Xexec_parms    equ    $
  4087. Xexec_env    dw    0
  4088. X        dw    offset _cmd_line    ; Command line address
  4089. Xexec_cseg    dw    ?
  4090. X        dw    offset FCB1        ; FCB1 address
  4091. Xexec_f1seg    dw    ?
  4092. X        dw    offset FCB2        ; FCB1 address
  4093. Xexec_f2seg    dw    ?
  4094. X
  4095. XSwap_PANIC    db    'PANIC: Swap file re-load error - REBOOT', 0aH, 0dH
  4096. X        db    '$'
  4097. X
  4098. XSwap_DZERO    db    'PANIC: Divide by zero', 0aH, 0dH
  4099. X        db    '$'
  4100. X
  4101. X;
  4102. X; OK - exec requires a local stack, cause some programs overwrite it
  4103. X;
  4104. X        even
  4105. X        db    398 dup (0)
  4106. XLocal_Stack:
  4107. X        dw    0
  4108. X
  4109. X;
  4110. X; Code starts
  4111. X;
  4112. X    public    _SA_spawn
  4113. X
  4114. X_SA_spawn    proc    far
  4115. X
  4116. X    push    bp
  4117. X    mov    bp, sp
  4118. X
  4119. X;
  4120. X; Entry Offsets
  4121. X;
  4122. X;    Environment      = 6
  4123. X;
  4124. X
  4125. X    mov    word ptr cs:S_di, di        ; Save registers
  4126. X    mov    word ptr cs:S_si, si
  4127. X    mov    word ptr cs:S_ds, ds
  4128. X
  4129. X;
  4130. X; Set up to ingnore Control C interrupts
  4131. X;
  4132. X
  4133. X    push    ds
  4134. X    mov    ax, 02523H        ; Set Control C Interrupt
  4135. X    mov    dx, offset SA_IRET
  4136. X    push    cs
  4137. X    pop    ds
  4138. X    mov    byte ptr cs:InShell, 0    ; Set In shell flag for Interrupt 23
  4139. X    int    021H
  4140. X
  4141. X    mov    ax, 02500H        ; Set Divide Zero Interrupt
  4142. X    mov    dx, offset SA_DZERO
  4143. X    push    cs
  4144. X    pop    ds
  4145. X    int    021H
  4146. X
  4147. X    pop    ds
  4148. X
  4149. X;
  4150. X; Save the length of the current MCB block;
  4151. X;
  4152. X
  4153. X    mov    ax, word ptr ds:__psp
  4154. X    dec    ax
  4155. X    mov    word ptr cs:N_mcb, ax        ; Save MCB address for swap out
  4156. X
  4157. X; Calculate low mem start for extended memory
  4158. X
  4159. X    mov    bx, ax                ; Save copy
  4160. X    mov    cl, 4                ; mult low order by 16
  4161. X    shl    ax, cl
  4162. X    mov    word ptr cs:SW_LMstart, ax    ; Save low order
  4163. X    mov    cl, 12                ; div by 16 ** 3
  4164. X    shr    bx, cl
  4165. X    mov    byte ptr cs:SW_LMstart + 2, bl    ; Save low order
  4166. X
  4167. X;
  4168. X; Set up Environment segment in execute structure
  4169. X;
  4170. X
  4171. X    mov    bx, cs
  4172. X    mov    ax, offset Env_OWrite
  4173. X    mov    cl, 4
  4174. X    shr    ax, cl
  4175. X    add    ax, bx
  4176. X    mov    word ptr cs:exec_env, ax    ; Save Env seg.
  4177. X
  4178. X;
  4179. X; Set up rest of execute structure
  4180. X;
  4181. X
  4182. X    mov    word ptr cs:exec_cseg, cs    ; Command line address
  4183. X    mov    word ptr cs:exec_f1seg, cs    ; FCB 1 address
  4184. X    mov    word ptr cs:exec_f2seg, cs    ; FCB 2 address
  4185. X
  4186. X;
  4187. X; Generate the FCBs
  4188. X;
  4189. X
  4190. X    mov    ax, cs        ; Set up segments
  4191. X    mov    ds, ax
  4192. X    mov    es, ax
  4193. X
  4194. X    mov    ax, 02901H    ; Set up FCB interrupt
  4195. X    mov    si, offset _cmd_line + 1
  4196. X    mov    di, offset FCB1    ; FCB 1;
  4197. X
  4198. X    int    021H        ; Execute the interrupt
  4199. X
  4200. X    mov    ax, cs        ; Set up segment
  4201. X    mov    es, ax
  4202. X
  4203. X    mov    ax, 02901H    ; Reset AX cause errors are ignored
  4204. X    mov    di, offset FCB2    ; FCB 2;
  4205. X
  4206. X    int    021H        ; Execute the interrupt
  4207. X
  4208. X;
  4209. X; Copy out to the swap file
  4210. X;
  4211. X
  4212. X    mov    si, word ptr cs:_SW_Blocks    ; Load Number of blocks to read
  4213. X    mov    bx, word ptr cs:_SW_fp        ; Load file handler
  4214. X
  4215. X; load up extended memory GDT for destination
  4216. X
  4217. X    mov    ax, word ptr cs:_SW_EMstart
  4218. X    mov    dl, byte ptr cs:_SW_EMstart + 2
  4219. X    call    $GDT_dest_load
  4220. X
  4221. X;
  4222. X; set up DS register with start of start copy
  4223. X;
  4224. X
  4225. X    mov    ax, word ptr cs:N_mcb        ; Load the start address
  4226. X    mov    ds, ax
  4227. X
  4228. X    mov    ax, word ptr cs:SW_LMstart     ; Load Full start address
  4229. X    mov    dl, byte ptr cs:SW_LMstart + 2
  4230. SHAR_EOF
  4231. echo "End of part 4"
  4232. echo "File shell/sh0.asm is continued in part 5"
  4233. echo "5" > s2_seq_.tmp
  4234. exit 0
  4235.  
  4236. -- 
  4237. Regards,
  4238.  
  4239. Ian Stewartson
  4240. Data Logic Ltd.
  4241.  
  4242.