home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / sh.zoo / sh.4 < prev    next >
Encoding:
Text File  |  1990-02-21  |  79.0 KB  |  4,234 lines

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