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

  1.  
  2. #!/bin/sh
  3. # this is part 3 of a multipart archive
  4. # do not concatenate these parts, unpack them in order with /bin/sh
  5. # file shell/sh2.c continued
  6. #
  7. CurArch=3
  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/sh2.c"
  18. sed 's/^X//' << 'SHAR_EOF' >> shell/sh2.c
  19. X        {
  20. X        if (iolist == (Word_B *)NULL)
  21. X            return (C_Op *)NULL;
  22. X
  23. X        (t = (C_Op *)tree (sizeof (C_Op)))->type = TCOM;
  24. X        }
  25. X
  26. X        break;
  27. X
  28. X    case '(':
  29. X        t = nested (TPAREN, ')');
  30. X        break;
  31. X
  32. X    case '{':
  33. X        t = nested (TBRACE, '}');
  34. X        break;
  35. X
  36. X    case FOR:
  37. X        (t = (C_Op *)tree (sizeof (C_Op)))->type = TFOR;
  38. X        musthave (WORD, 0);
  39. X        startl = TRUE;
  40. X        t->str = yylval.cp;
  41. X        multiline++;
  42. X        t->words = wordlist ();
  43. X
  44. X        if (((c = yylex (0)) != NL) && (c != ';'))
  45. X        yyerror (syntax_err);
  46. X
  47. X        t->left = dogroup (0);
  48. X        multiline--;
  49. X        break;
  50. X
  51. X    case WHILE:
  52. X    case UNTIL:
  53. X        multiline++;
  54. X        t = (C_Op *)tree (sizeof (C_Op));
  55. X        t->type = (c == WHILE) ? TWHILE : TUNTIL;
  56. X        t->left = c_list (FALSE);
  57. X        t->right = dogroup (1);
  58. X        t->words = NULL;
  59. X        multiline--;
  60. X        break;
  61. X
  62. X    case CASE:
  63. X        (t = (C_Op *)tree (sizeof (C_Op)))->type = TCASE;
  64. X        musthave (WORD, 0);
  65. X        t->str = yylval.cp;
  66. X        startl = TRUE;
  67. X        multiline++;
  68. X        musthave (IN, CONTIN);
  69. X        startl = TRUE;
  70. X        t->left = caselist();
  71. X        musthave (ESAC, 0);
  72. X        multiline--;
  73. X        break;
  74. X
  75. X    case IF:
  76. X        multiline++;
  77. X        (t = (C_Op *)tree (sizeof (C_Op)))->type = TIF;
  78. X        t->left = c_list (FALSE);
  79. X        t->right = thenpart ();
  80. X        musthave (FI, 0);
  81. X        multiline--;
  82. X        break;
  83. X    }
  84. X
  85. X    while (synio (0))
  86. X    ;
  87. X
  88. X    t = namelist (t);
  89. X    iolist = iosave;
  90. X    return t;
  91. X}
  92. X
  93. Xstatic C_Op    *dogroup (onlydone)
  94. Xint        onlydone;
  95. X{
  96. X    register int    c;
  97. X    register C_Op    *list;
  98. X
  99. X    if (((c = yylex (CONTIN)) == DONE) && onlydone)
  100. X    return (C_Op *)NULL;
  101. X
  102. X    if (c != DO)
  103. X    yyerror (syntax_err);
  104. X
  105. X    list = c_list (FALSE);
  106. X    musthave (DONE, 0);
  107. X    return list;
  108. X}
  109. X
  110. Xstatic C_Op    *thenpart ()
  111. X{
  112. X    register int    c;
  113. X    register C_Op    *t;
  114. X
  115. X    if ((c = yylex (0)) != THEN) 
  116. X    {
  117. X    peeksym = c;
  118. X    return (C_Op *)NULL;
  119. X    }
  120. X
  121. X    (t = (C_Op *)tree (sizeof (C_Op)))->type = 0;
  122. X
  123. X    if ((t->left = c_list (FALSE)) == (C_Op *)NULL)
  124. X    yyerror (syntax_err);
  125. X
  126. X    t->right = elsepart ();
  127. X    return t;
  128. X}
  129. X
  130. Xstatic C_Op    *elsepart ()
  131. X{
  132. X    register int    c;
  133. X    register C_Op    *t;
  134. X
  135. X    switch (c = yylex (0)) 
  136. X    {
  137. X    case ELSE:
  138. X        if ((t = c_list (FALSE)) == (C_Op *)NULL)
  139. X        yyerror (syntax_err);
  140. X
  141. X        return t;
  142. X
  143. X    case ELIF:
  144. X        (t = (C_Op *)tree (sizeof (C_Op)))->type = TELIF;
  145. X        t->left = c_list (FALSE);
  146. X        t->right = thenpart ();
  147. X        return t;
  148. X
  149. X    default:
  150. X        peeksym = c;
  151. X        return (C_Op *)NULL;
  152. X    }
  153. X}
  154. X
  155. Xstatic C_Op    *caselist()
  156. X{
  157. X    register C_Op    *t = (C_Op *)NULL;
  158. X
  159. X    while ((peeksym = yylex (CONTIN)) != ESAC)
  160. X    t = list (t, casepart ());
  161. X
  162. X    return t;
  163. X}
  164. X
  165. Xstatic C_Op    *casepart ()
  166. X{
  167. X    register C_Op    *t = (C_Op *)tree (sizeof (C_Op));
  168. X
  169. X    t->type = TPAT;
  170. X    t->words = pattern ();
  171. X    musthave (')', 0);
  172. X    t->left = c_list (FALSE);
  173. X
  174. X    if ((peeksym = yylex (CONTIN)) != ESAC)
  175. X    musthave (BREAK, CONTIN);
  176. X
  177. X    return t;
  178. X}
  179. X
  180. Xstatic char    **pattern()
  181. X{
  182. X    register int    c, cf;
  183. X
  184. X    cf = CONTIN;
  185. X
  186. X    do
  187. X    {
  188. X    musthave (WORD, cf);
  189. X    word (yylval.cp);
  190. X    cf = 0;
  191. X    } while ((c = yylex(0)) == '|');
  192. X
  193. X    peeksym = c;
  194. X    word (NOWORD);
  195. X    return copyw();
  196. X}
  197. X
  198. Xstatic char    **wordlist()
  199. X{
  200. X    register int    c;
  201. X
  202. X    if ((c = yylex(0)) != IN) 
  203. X    {
  204. X    peeksym = c;
  205. X    return (char **)NULL;
  206. X    }
  207. X
  208. X    startl = FALSE;
  209. X    while ((c = yylex (0)) == WORD)
  210. X    word (yylval.cp);
  211. X
  212. X    word (NOWORD);
  213. X    peeksym = c;
  214. X
  215. X    return copyw();
  216. X}
  217. X
  218. X/*
  219. X * supporting functions
  220. X */
  221. X
  222. Xstatic C_Op    *list (t1, t2)
  223. Xregister C_Op    *t1, *t2;
  224. X{
  225. X    if (t1 == (C_Op *)NULL)
  226. X    return t2;
  227. X
  228. X    if (t2 == (C_Op *)NULL)
  229. X    return t1;
  230. X
  231. X    return block (TLIST, t1, t2, NOWORDS);
  232. X}
  233. X
  234. Xstatic C_Op    *block (type, t1, t2, wp)
  235. XC_Op        *t1, *t2;
  236. Xchar            **wp;
  237. X{
  238. X    register C_Op *t = (C_Op *)tree (sizeof (C_Op));
  239. X
  240. X    t->type = type;
  241. X    t->left = t1;
  242. X    t->right = t2;
  243. X    t->words = wp;
  244. X    return t;
  245. X}
  246. X
  247. Xstatic struct res {
  248. X    char    *r_name;
  249. X    int        r_val;
  250. X} restab[] = {
  251. X    {    "for",        FOR},        {"case",    CASE},
  252. X    {"esac",    ESAC},        {"while",    WHILE},
  253. X    {"do",        DO},        {"done",    DONE},
  254. X    {"if",        IF},        {"in",        IN},
  255. X    {"then",    THEN},        {"else",    ELSE},
  256. X    {"elif",    ELIF},        {"until",    UNTIL},
  257. X    {"fi",        FI},
  258. X
  259. X    {";;",        BREAK},        {"||",        LOGOR},
  260. X    {"&&",        LOGAND},    {"{",        '{'},
  261. X    {"}",        '}'},
  262. X
  263. X    {(char *)NULL,    0}
  264. X};
  265. X
  266. Xstatic int    rlookup (n)
  267. Xregister char    *n;
  268. X{
  269. X    register struct res        *rp = restab;
  270. X
  271. X    while ((rp->r_name != (char *)NULL) && strcmp (rp->r_name, n))
  272. X    rp++;
  273. X
  274. X    return rp->r_val;
  275. X}
  276. X
  277. Xstatic C_Op    *namelist(t)
  278. Xregister C_Op    *t;
  279. X{
  280. X    if (iolist) 
  281. X    {
  282. X    iolist = addword ((char *)NULL, iolist);
  283. X    t->ioact = copyio ();
  284. X    }
  285. X    
  286. X    else
  287. X    t->ioact = (IO_Actions **)NULL;
  288. X
  289. X    if ((t->type != TCOM) && (t->type != TFUNC))
  290. X    {
  291. X    if ((t->type != TPAREN) && (t->ioact != (IO_Actions **)NULL))
  292. X    {
  293. X        t = block (TPAREN, t, NOBLOCK, NOWORDS);
  294. X        t->ioact = t->left->ioact;
  295. X        t->left->ioact = (IO_Actions **)NULL;
  296. X    }
  297. X    }
  298. X
  299. X    else
  300. X    {
  301. X    word (NOWORD);
  302. X    t->words = copyw();
  303. X    }
  304. X
  305. X    return t;
  306. X}
  307. X
  308. Xstatic char    **copyw ()
  309. X{
  310. X    register char **wd = getwords (wdlist);
  311. X
  312. X    wdlist = (Word_B *)NULL;
  313. X    return wd;
  314. X}
  315. X
  316. Xstatic void    word (cp)
  317. Xchar        *cp;
  318. X{
  319. X    wdlist = addword (cp, wdlist);
  320. X}
  321. X
  322. Xstatic IO_Actions    **copyio ()
  323. X{
  324. X    IO_Actions    **iop = (IO_Actions **)getwords (iolist);
  325. X
  326. X    iolist = (Word_B *)NULL;
  327. X    return iop;
  328. X}
  329. X
  330. Xstatic IO_Actions    *io (u, f, cp)
  331. Xint            f, u;
  332. Xchar            *cp;
  333. X{
  334. X    register IO_Actions *iop = (IO_Actions *)tree (sizeof (IO_Actions));
  335. X
  336. X    iop->io_unit = u;
  337. X    iop->io_flag = f;
  338. X    iop->io_name = cp;
  339. X    iolist = addword ((char *)iop, iolist);
  340. X    return iop;
  341. X}
  342. X
  343. Xstatic void    yyerror (s)
  344. Xchar        *s;
  345. X{
  346. X    yynerrs++;
  347. X
  348. X    if (talking && e.iop <= iostack) 
  349. X    {
  350. X    multiline = 0;
  351. X
  352. X    while ((eofc () == 0) && (yylex (0) != NL))
  353. X        ;
  354. X    }
  355. X
  356. X    print_error (s);
  357. X    fail ();
  358. X}
  359. X
  360. Xstatic int    yylex (cf)
  361. Xint        cf;
  362. X{
  363. X    register int    c, c1;
  364. X    bool        atstart;
  365. X
  366. X    if ((c = peeksym) > 0) 
  367. X    {
  368. X    peeksym = 0;
  369. X
  370. X    if (c == NL)
  371. X        startl = TRUE;
  372. X
  373. X    return c;
  374. X    }
  375. X
  376. X    e.linep = e.cline;
  377. X    atstart = startl;
  378. X    startl = FALSE;
  379. X    yylval.i = 0;
  380. X
  381. Xloop:
  382. X    while ((c = Getc (0)) == SP || c == '\t')
  383. X    ;
  384. X
  385. X    switch (c) 
  386. X    {
  387. X    default:
  388. X        if (isdigit (c)) 
  389. X        {
  390. X        unget (c1 = Getc(0));
  391. X
  392. X        if ((c1 == '<') || (c1 == '>'))
  393. X        {
  394. X            iounit = c - '0';
  395. X            goto loop;
  396. X        }
  397. X
  398. X        *e.linep++ = (char)c;
  399. X        c = c1;
  400. X        }
  401. X
  402. X        break;
  403. X
  404. X    case '#':
  405. X        while ((c = Getc(0)) != 0 && (c != NL))
  406. X        ;
  407. X
  408. X        unget(c);
  409. X        goto loop;
  410. X
  411. X    case 0:
  412. X        return c;
  413. X
  414. X    case '$':
  415. X        *e.linep++ = (char)c;
  416. X
  417. X        if ((c = Getc(0)) == '{') 
  418. X        {
  419. X        if ((c = collect (c, '}')) != '\0')
  420. X            return (c);
  421. X
  422. X        goto pack;
  423. X        }
  424. X
  425. X        break;
  426. X
  427. X    case '`':
  428. X    case '\'':
  429. X    case '"':
  430. X        if ((c = collect (c, c)) != '\0')
  431. X        return c;
  432. X
  433. X        goto pack;
  434. X
  435. X    case '|':
  436. X    case '&':
  437. X    case ';':
  438. X        if ((c1 = dual (c)) != '\0') 
  439. X        {
  440. X        startl = TRUE;
  441. X        return c1;
  442. X        }
  443. X
  444. X    case '(':
  445. X    case ')':
  446. X        startl = TRUE;
  447. X        return c;
  448. X
  449. X    case '^':
  450. X        startl = TRUE;
  451. X        return '|';
  452. X
  453. X    case '>':
  454. X    case '<':
  455. X        diag (c);
  456. X        return c;
  457. X
  458. X    case NL:
  459. X        gethere ();
  460. X        startl = TRUE;
  461. X
  462. X        if (multiline || (cf & CONTIN))
  463. X        {
  464. X        if (talking && e.iop <= iostack)
  465. X        {
  466. X            Add_History (FALSE);
  467. X            put_prompt (ps2->value);
  468. X        }
  469. X
  470. X        if (cf & CONTIN)
  471. X            goto loop;
  472. X        }
  473. X
  474. X        return(c);
  475. X    }
  476. X
  477. X    unget (c);
  478. X
  479. Xpack:
  480. X    while (((c = Getc (0)) != 0) && (!any ((char)c, "`$ '\"\t;&<>()|^\n")))
  481. X    {
  482. X    if (e.linep >= e.eline)
  483. X        print_error ("sh: word too long\n");
  484. X
  485. X    else
  486. X        *e.linep++ = (char)c;
  487. X    }
  488. X
  489. X    unget (c);
  490. X
  491. X    if (any ((char)c, spcl2))
  492. X    goto loop;
  493. X
  494. X    *e.linep++ = '\0';
  495. X
  496. X    if (atstart && (c = rlookup (e.cline)) != 0) 
  497. X    {
  498. X    startl = TRUE;
  499. X    return c;
  500. X    }
  501. X
  502. X    yylval.cp = strsave (e.cline, areanum);
  503. X    return WORD;
  504. X}
  505. X
  506. Xstatic int    collect (c, c1)
  507. Xregister int    c, c1;
  508. X{
  509. X    char *s = "x\n";
  510. X
  511. X    *e.linep++ = (char)c;
  512. X
  513. X    while ((c = Getc (c1)) != c1) 
  514. X    {
  515. X    if (c == 0) 
  516. X    {
  517. X        unget (c);
  518. X        *s = (char)c1;
  519. X        S_puts ("sh: no closing ");
  520. X        yyerror (s);
  521. X        return YYERRCODE;
  522. X    }
  523. X
  524. X    if (talking && (c == NL) && (e.iop <= iostack))
  525. X    {
  526. X        Add_History (FALSE);
  527. X        put_prompt (ps2->value);
  528. X    }
  529. X
  530. X    *e.linep++ = (char)c;
  531. X    }
  532. X
  533. X    *e.linep++ = (char)c;
  534. X    return 0;
  535. X}
  536. X
  537. X/* Check for &&, || and ;; */
  538. X
  539. Xstatic int    dual (c)
  540. Xregister int    c;
  541. X{
  542. X    char        s[3];
  543. X    register char    *cp = s;
  544. X
  545. X/* Get the next character and set up double string.  Look up in valid
  546. X * operators.  If invalid, unget character
  547. X */
  548. X
  549. X    *cp++ = (char)c;
  550. X    *cp++ = (char)Getc (0);
  551. X    *cp = 0;
  552. X
  553. X    if ((c = rlookup (s)) == 0)
  554. X    unget (*--cp);
  555. X
  556. X    return c;
  557. X}
  558. X
  559. X/* Process I/O re-direction */
  560. X
  561. Xstatic void    diag (ec)
  562. Xregister int    ec;
  563. X{
  564. X    register int    c;
  565. X
  566. X    if (((c = Getc (0)) == '>') || (c == '<'))
  567. X    {
  568. X    if (c != ec)
  569. X        yyerror (syntax_err);
  570. X
  571. X    yylval.i = (ec == '>') ? IOWRITE | IOCAT : IOHERE;
  572. X    c = Getc(0);
  573. X    }
  574. X    
  575. X    else
  576. X    yylval.i = (ec == '>') ? IOWRITE : IOREAD;
  577. X
  578. X    if ((c != '&') || (yylval.i == IOHERE))
  579. X    unget (c);
  580. X
  581. X    else
  582. X    yylval.i |= IODUP;
  583. X}
  584. X
  585. X/* Get a new tree leaf structure */
  586. X
  587. Xstatic char    *tree (size)
  588. Xunsigned int    size;
  589. X{
  590. X    register char *t;
  591. X
  592. X    if ((t = getcell (size)) == (char *)NULL)
  593. X    {
  594. X    S_puts ("sh: command line too complicated\n");
  595. X    fail ();
  596. X    }
  597. X
  598. X    return t;
  599. X}
  600. SHAR_EOF
  601. echo "File shell/sh2.c is complete"
  602. chmod 0644 shell/sh2.c || echo "restore of shell/sh2.c fails"
  603. set `wc -c shell/sh2.c`;Sum=$1
  604. if test "$Sum" != "15090"
  605. then echo original size 15090, current size $Sum;fi
  606. echo "x - extracting shell/sh3.c (Text)"
  607. sed 's/^X//' << 'SHAR_EOF' > shell/sh3.c &&
  608. X/* MS-DOS SHELL - Parse Tree Executor
  609. X *
  610. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  611. X *
  612. X * This code is based on (in part) the shell program written by Charles
  613. X * Forsyth and is subject to the following copyright restrictions:
  614. X *
  615. X * 1.  Redistribution and use in source and binary forms are permitted
  616. X *     provided that the above copyright notice is duplicated in the
  617. X *     source form and the copyright notice in file sh6.c is displayed
  618. X *     on entry to the program.
  619. X *
  620. X * 2.  The sources (or parts thereof) or objects generated from the sources
  621. X *     (or parts of sources) cannot be sold under any circumstances.
  622. X *
  623. X *    $Header: sh3.c 1.1 90/01/25 13:41:24 MS_user Exp $
  624. X *
  625. X *    $Log:    sh3.c $
  626. X * Revision 1.1  90/01/25  13:41:24  MS_user
  627. X * Initial revision
  628. X * 
  629. X */
  630. X
  631. X#include <sys/types.h>
  632. X#include <sys/stat.h>
  633. X#include <stdio.h>
  634. X#include <process.h>
  635. X#include <dos.h>
  636. X#include <signal.h>
  637. X#include <errno.h>
  638. X#include <setjmp.h>
  639. X#include <ctype.h>
  640. X#include <string.h>
  641. X#include <unistd.h>
  642. X#include <stdlib.h>
  643. X#include <fcntl.h>
  644. X#include <limits.h>
  645. X
  646. X#include "sh.h"
  647. X
  648. X/* static Function and string declarations */
  649. X
  650. Xstatic int    forkexec (C_Op *, int, int, int, char **);
  651. Xstatic bool    iosetup (IO_Actions *, int, int);
  652. Xstatic C_Op    **find1case (C_Op *, char *);
  653. Xstatic C_Op    *findcase (C_Op *, char *);
  654. Xstatic void    echo (char **);
  655. Xstatic void    setsig (int, int (*)());
  656. Xstatic int    rexecve (char *, char **, char **, bool);
  657. Xstatic int    Execute_program (char *, char **, char **, bool);
  658. Xstatic int    S_spawnve (char *, char **, char **);
  659. Xstatic void    get_sys_info (void);
  660. Xstatic void    EMS_error (char *, int);
  661. Xstatic int    EMS_Close (void);
  662. Xstatic int    build_command_line (char *, char **, char **);
  663. Xstatic void    Clear_Extended_File (void);
  664. Xstatic int    setstatus (int);
  665. X
  666. Xstatic char    *AE2big = "arg/env list too big";
  667. Xstatic char    *EMS_emsg = "Warning: EMS Error (%x)\n";
  668. X            /* Extended Command line processing file name    */
  669. Xstatic char        *Extend_file = (char *)NULL;
  670. Xstatic unsigned int    SW_EMsize;    /* Number of extend memory blks    */
  671. X
  672. X/*
  673. X * execute tree recursively
  674. X */
  675. X
  676. Xint        execute (t, pin, pout, act)
  677. Xregister C_Op    *t;
  678. Xint        pin;
  679. Xint        pout;
  680. Xint        act;
  681. X{
  682. X    register C_Op    *t1;
  683. X    int            i, localpipe;
  684. X    char        *cp, **wp;
  685. X    char        **Local_Tword;
  686. X    Var_List        *vp;
  687. X    Break_C        bc;
  688. X    Break_C        *S_RList;        /* Save link pointers    */
  689. X    Break_C        *S_BList;
  690. X    Break_C        *S_SList;
  691. X    int            Local_depth;        /* Save local values    */
  692. X    int            Local_areanum;
  693. X    int            rv = 0;
  694. X
  695. X/* End of tree ? */
  696. X
  697. X    if (t == (C_Op *)NULL)
  698. X    return 0;
  699. X
  700. X/* Save original and Increment execute function recursive level */
  701. X
  702. X    Local_depth = Execute_stack_depth++;
  703. X
  704. X/* Save original and increment area number */
  705. X
  706. X    Local_areanum = areanum++;
  707. X
  708. X/* Save the exit points from SubShells, functions and for/whiles */
  709. X
  710. X    S_RList = Return_List;
  711. X    S_BList = Break_List;
  712. X    S_SList = SShell_List;
  713. X
  714. X/* Expand any arguments */
  715. X
  716. X    wp = (Local_Tword = t->words) != (char **)NULL
  717. X     ? eval (Local_Tword, (t->type == TCOM) ? DOALL : DOALL & ~DOKEY)
  718. X     : (char **)NULL;
  719. X
  720. X/* Switch on tree node type */
  721. X
  722. X    switch (t->type)
  723. X    {
  724. X    case TFUNC:            /* name () { list; }    */
  725. X        Save_Function (t, FALSE);
  726. X        break;
  727. X
  728. X/* In the case of a () command string, we need to save and restore the
  729. X * current environment, directory and traps (can't think of anything else).
  730. X * For any other, we just restore the current directory.  Also, we don't
  731. X * want changes in the Variable list header saved for SubShells, because
  732. X * we are effectively back at execute depth zero.
  733. X */
  734. X    case TPAREN:            /* ()            */
  735. X        if ((rv = Create_NG_VL ()) == -1)
  736. X        break;
  737. X
  738. X        if (setjmp (bc.brkpt) == 0)
  739. X        {
  740. X        Return_List = (Break_C *)NULL;
  741. X        Break_List  = (Break_C *)NULL;
  742. X        bc.nextlev  = SShell_List;
  743. X        SShell_List = &bc;
  744. X        rv = forkexec (t, pin, pout, act, wp);
  745. X        }
  746. X
  747. X/* Restore the original environment */
  748. X
  749. X        Return_List    = S_RList;
  750. X        Break_List    = S_BList;
  751. X        SShell_List    = S_SList;
  752. X        Restore_Environment (rv, Local_depth);
  753. X        break;
  754. X
  755. X/* After a normal command, we need to restore the original directory.  Note
  756. X * that a cd will have updated the variable $~, so no problem
  757. X */
  758. X
  759. X    case TCOM:            /* A command process    */
  760. X        rv = forkexec (t, pin, pout, act, wp);
  761. X        Restore_Dir ();
  762. X        break;
  763. X
  764. X    case TPIPE:            /* Pipe processing        */
  765. X        if ((rv = openpipe ()) < 0)
  766. X        break;
  767. X
  768. X/* Create pipe, execute command, reset pipe, execute the other side, close
  769. X * the pipe and fini
  770. X */
  771. X
  772. X        localpipe = remap (rv);
  773. X        execute (t->left, pin, localpipe, 0);
  774. X        lseek (localpipe, 0L, SEEK_SET);
  775. X        rv = execute (t->right, localpipe, pout, 0);
  776. X        closepipe (localpipe);
  777. X        break;
  778. X
  779. X    case TLIST:            /* Entries in a for statement    */
  780. X        execute (t->left, pin, pout, 0);
  781. X        rv = execute (t->right, pin, pout, 0);
  782. X        break;
  783. X
  784. X    case TASYNC:            /* Async - not supported    */
  785. X        rv = -1;
  786. X        S_puts ("sh: Async commands not supported\n");
  787. X        setstatus (rv);
  788. X        break;
  789. X
  790. X    case TOR:            /* || and &&            */
  791. X    case TAND:
  792. X        rv = execute (t->left, pin, pout, 0);
  793. X
  794. X        if (((t1 = t->right) != (C_Op *)NULL) &&
  795. X        ((rv == 0) == (t->type == TAND)))
  796. X        rv = execute (t1, pin, pout, 0);
  797. X
  798. X        break;
  799. X
  800. X    case TFOR:            /* First part of a for statement*/
  801. X
  802. X/* for x do...done - use the parameter values.  Need to know how many as
  803. X * it is not a NULL terminated array
  804. X */
  805. X
  806. X        if (wp == (char **)NULL)
  807. X        {
  808. X        wp = dolv + 1;
  809. X
  810. X        if ((i = dolc) < 0)
  811. X            i = 0;
  812. X        }
  813. X
  814. X/* for x in y do...done - find the start of the variables and use them all */
  815. X
  816. X        else
  817. X        {
  818. X        i = -1;
  819. X        while (*wp++ != (char *)NULL)
  820. X            ;
  821. X        }
  822. X
  823. X/* Create the loop variable. */
  824. X
  825. X        vp = lookup (t->str, TRUE);
  826. X
  827. X/* Set up a long jump return point before executing the for function so that
  828. X * the continue statement is executed, ie we reprocessor the for condition.
  829. X */
  830. X
  831. X        while (rv = setjmp (bc.brkpt))
  832. X        {
  833. X
  834. X/* Restore the current stack level and clear out any I/O */
  835. X
  836. X        Restore_Environment (0, Local_depth + 1);
  837. X        Return_List = S_RList;
  838. X        SShell_List = S_SList;
  839. X
  840. X/* If this is a break - clear the variable and terminate the while loop and
  841. X * switch statement
  842. X */
  843. X
  844. X        if (rv == BC_BREAK)
  845. X            break;
  846. X        }
  847. X
  848. X        if (rv == BC_BREAK)
  849. X        break;
  850. X
  851. X/* Process the next entry - Add to the break/continue chain */
  852. X
  853. X        bc.nextlev = Break_List;
  854. X        Break_List = &bc;
  855. X
  856. X/* Execute the command tree */
  857. X
  858. X        for (t1 = t->left; i-- && *wp != NULL;)
  859. X        {
  860. X        setval (vp, *wp++);
  861. X        rv = execute (t1, pin, pout, 0);
  862. X        }
  863. X
  864. X/* Remove this tree from the break list */
  865. X
  866. X        Break_List = S_BList;
  867. X        break;
  868. X
  869. X/* While and Until function.  Similar to the For function.  Set up a
  870. X * long jump return point before executing the while function so that
  871. X * the continue statement is executed OK.
  872. X */
  873. X
  874. X    case TWHILE:            /* WHILE and UNTIL functions    */
  875. X    case TUNTIL:
  876. X        while (rv = setjmp (bc.brkpt))
  877. X        {
  878. X
  879. X/* Restore the current stack level and clear out any I/O */
  880. X
  881. X        Restore_Environment (0, Local_depth + 1);
  882. X        Return_List = S_RList;
  883. X        SShell_List = S_SList;
  884. X
  885. X/* If this is a break, terminate the while and switch statements */
  886. X
  887. X        if (rv == BC_BREAK)
  888. X            break;
  889. X        }
  890. X
  891. X        if (rv == BC_BREAK)
  892. X        break;
  893. X
  894. X/* Set up links */
  895. X
  896. X        bc.nextlev = Break_List;
  897. X        Break_List = &bc;
  898. X        t1 = t->left;
  899. X
  900. X        while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
  901. X        rv = execute (t->right, pin, pout, 0);
  902. X
  903. X        Break_List = S_BList;
  904. X        break;
  905. X
  906. X    case TIF:            /* IF and ELSE IF functions    */
  907. X    case TELIF:
  908. X        rv = !execute (t->left, pin, pout, 0)
  909. X                ? execute (t->right->left, pin, pout, 0)
  910. X             : execute (t->right->right, pin, pout, 0);
  911. X        break;
  912. X
  913. X    case TCASE:            /* CASE function        */
  914. X        if ((cp = evalstr (t->str, DOSUB | DOTRIM)) == (char *)NULL)
  915. X        cp = null;
  916. X
  917. X        if ((t1 = findcase (t->left, cp)) != (C_Op *)NULL)
  918. X        rv = execute (t1, pin, pout, 0);
  919. X
  920. X        break;
  921. X
  922. X    case TBRACE:            /* {} statement            */
  923. X        if ((rv >= 0) && ((t1 = t->left) != (C_Op *)NULL))
  924. X        rv = execute (t1, pin, pout, 0);
  925. X
  926. X        break;
  927. X    }
  928. X
  929. X/* Processing Completed - Restore environment */
  930. X
  931. X    t->words        = Local_Tword;
  932. X    Execute_stack_depth = Local_depth;
  933. X
  934. X/* Remove unwanted malloced space */
  935. X
  936. X    freehere (areanum);
  937. X    freearea (areanum);
  938. X
  939. X    areanum        = Local_areanum;
  940. X
  941. X/* Check for interrupts */
  942. X
  943. X    if (talking && SW_intr)
  944. X    {
  945. X    closeall ();
  946. X    fail ();
  947. X    }
  948. X
  949. X/* Check for traps */
  950. X
  951. X    if ((i = trapset) != 0)
  952. X    {
  953. X    trapset = 0;
  954. X    runtrap (i);
  955. X    }
  956. X
  957. X    return rv;
  958. X}
  959. X
  960. X/*
  961. X * Restore the original directory
  962. X */
  963. X
  964. Xvoid    Restore_Dir ()
  965. X{
  966. X    unsigned int    dummy;
  967. X
  968. X    _dos_setdrive (tolower(*C_dir->value) - 'a' + 1, &dummy);
  969. X
  970. X    if (chdir (&C_dir->value[2]) != 0)
  971. X    {
  972. X    S_puts ("Warning: current directory reset to /\n");
  973. X    chdir ("/");
  974. X    Getcwd ();
  975. X    }
  976. X}
  977. X
  978. X/*
  979. X * Ok - execute the program, resetting any I/O required
  980. X */
  981. X
  982. Xstatic int    forkexec (t, pin, pout, act, wp)
  983. Xregister C_Op    *t;
  984. Xint        pin;
  985. Xint        pout;
  986. Xint        act;
  987. Xchar        **wp;
  988. X{
  989. X    int        rv = -1;
  990. X    int        (*shcom)(C_Op *) = (int (*)())NULL;
  991. X    char    *cp;
  992. X    IO_Actions    **iopp;
  993. X    int        resetsig = 0;
  994. X    char    **owp = wp;
  995. X    bool    spawn = FALSE;
  996. X    Fun_Ops    *fop;
  997. X
  998. X    if (t->type == TCOM)
  999. X    {
  1000. X    while ((cp = *wp++) != (char *)NULL)
  1001. X        ;
  1002. X
  1003. X    cp = *wp;
  1004. X
  1005. X/* strip all initial assignments not correct wrt PATH=yyy command  etc */
  1006. X
  1007. X    if (FL_TEST ('x'))
  1008. X        echo (cp != (char *)NULL ? wp : owp);
  1009. X
  1010. X/* Is it only an assignement? */
  1011. X
  1012. X    if ((cp == (char *)NULL) && (t->ioact == (IO_Actions **)NULL))
  1013. X    {
  1014. X        while (((cp = *owp++) != (char *)NULL) && assign (cp, COPYV))
  1015. X        ;
  1016. X
  1017. X        return setstatus (0);
  1018. X    }
  1019. X
  1020. X/* Check for built in commands */
  1021. X
  1022. X    else if (cp != (char *)NULL)
  1023. X        shcom = inbuilt (cp);
  1024. X    }
  1025. X
  1026. X/* Unix fork simulation? */
  1027. X
  1028. X    t->words = wp;
  1029. X    if (shcom == NULL && (act & FEXEC) == 0)
  1030. X    {
  1031. X    spawn = TRUE;
  1032. X
  1033. X    if (talking)
  1034. X    {
  1035. X#ifdef SIGQUIT
  1036. X        signal (SIGQUIT, SIG_IGN);
  1037. X#endif
  1038. X        signal (SIGINT, SIG_IGN);
  1039. X        resetsig = 1;
  1040. X    }
  1041. X    }
  1042. X
  1043. X/* Set any variables */
  1044. X
  1045. X    while (((cp = *owp++) != (char *)NULL) && assign (cp, COPYV))
  1046. X    {
  1047. X    if (shcom == NULL)
  1048. X        s_vstatus (lookup (cp, TRUE), EXPORT);
  1049. X    }
  1050. X
  1051. X/* We cannot close the pipe, because once the exec/spawn has taken place
  1052. X * the processing of the pipe is not yet complete.
  1053. X */
  1054. X
  1055. X    if (pin != NOPIPE)
  1056. X    {
  1057. X    S_dup2 (pin, STDIN_FILENO);
  1058. X    lseek (STDIN_FILENO, 0L, SEEK_SET);
  1059. X    }
  1060. X
  1061. X    if (pout != NOPIPE)
  1062. X    {
  1063. X    S_dup2 (pout, STDOUT_FILENO);
  1064. X    lseek (STDOUT_FILENO, 0L, SEEK_END);
  1065. X    }
  1066. X
  1067. X/* Set up any other IO required */
  1068. X
  1069. X    if ((iopp = t->ioact) != (IO_Actions **)NULL)
  1070. X    {
  1071. X    while (*iopp != (IO_Actions *)NULL)
  1072. X    {
  1073. X        if (iosetup (*iopp++, pin, pout))
  1074. X        return rv;
  1075. X    }
  1076. X    }
  1077. X
  1078. X    if (shcom)
  1079. X    return restore_std (setstatus ((*shcom)(t)));
  1080. X
  1081. X/* All fids above 10 are autoclosed in the exec file because we have used
  1082. X * the O_NOINHERIT flag.  Note I patched open.obj to pass this flag to the
  1083. X * open function.
  1084. X */
  1085. X
  1086. X    if (resetsig)
  1087. X    {
  1088. X#ifdef SIGQUIT
  1089. X    signal (SIGQUIT, SIG_IGN);
  1090. X#endif
  1091. X    signal (SIGINT, onintr);
  1092. X    }
  1093. X
  1094. X    if (t->type == TPAREN)
  1095. X    return restore_std (execute (t->left, NOPIPE, NOPIPE, FEXEC));
  1096. X
  1097. X/* Are we just changing the I/O re-direction for the shell ? */
  1098. X
  1099. X    if (wp[0] == NULL)
  1100. X    {
  1101. X    if (spawn)
  1102. X        restore_std (0);
  1103. X
  1104. X    return 0;
  1105. X    }
  1106. X
  1107. X/* No - Check for a function the program.  At this point, we need to put
  1108. X * in some processing for return.
  1109. X */
  1110. X
  1111. X    if ((fop = Fun_Search (wp[0])) != (Fun_Ops *)NULL)
  1112. X    {
  1113. X    char            **s_dolv = dolv;
  1114. X    int            s_dolc   = dolc;
  1115. X    Break_C            *s_RList = Return_List;
  1116. X    Break_C            *s_BList = Break_List;
  1117. X    Break_C            *s_SList = SShell_List;
  1118. X    int            LS_depth = Execute_stack_depth;
  1119. X    Break_C            bc;
  1120. X
  1121. X/* Set up $0..$n for the function */
  1122. X
  1123. X    dolv = wp;
  1124. X    for (dolc = 0; dolv[dolc] != (char *)NULL; ++dolc);
  1125. X    setval (lookup ("#", TRUE), putn (dolc));
  1126. X
  1127. X    if (setjmp (bc.brkpt) == 0)
  1128. X    {
  1129. X        Break_List  = (Break_C *)NULL;
  1130. X        bc.nextlev  = Return_List;
  1131. X        Return_List = &bc;
  1132. X        rv = execute (fop->tree->left, NOPIPE, NOPIPE, FEXEC);
  1133. X    }
  1134. X
  1135. X/* A return has been executed - Unlike, while and for, we just need to
  1136. X * restore the local execute stack level and the return will restore
  1137. X * the correct I/O.
  1138. X */
  1139. X
  1140. X    else
  1141. X        rv = getn (lookup ("?", FALSE)->value);
  1142. X
  1143. X/* Restore the old $0, and previous return address */
  1144. X
  1145. X    Break_List  = s_BList;
  1146. X    Return_List = s_RList;
  1147. X    SShell_List = s_SList;
  1148. X    dolv        = s_dolv;
  1149. X    dolc        = s_dolc;
  1150. X    Restore_Environment (rv, LS_depth);
  1151. X    setval (lookup ("#", TRUE), putn (dolc));
  1152. X    return rv;
  1153. X    }
  1154. X
  1155. X/* Ok - execute the program */
  1156. X
  1157. X    return restore_std (rexecve (wp[0], wp, makenv (), spawn));
  1158. X}
  1159. X
  1160. X/*
  1161. X * Restore Local Environment
  1162. X */
  1163. X
  1164. Xvoid    Restore_Environment (retval, stack)
  1165. Xint    retval;
  1166. Xint    stack;
  1167. X{
  1168. X    Execute_stack_depth = stack;
  1169. X    Delete_G_VL ();
  1170. X    Restore_Dir ();
  1171. X    restore_std (setstatus (retval));
  1172. X}
  1173. X
  1174. X/*
  1175. X * Set up I/O redirection.  0< 1> are ignored as required within pipelines.
  1176. X */
  1177. X
  1178. Xstatic bool        iosetup (iop, pipein, pipeout)
  1179. Xregister IO_Actions    *iop;
  1180. Xint            pipein;
  1181. Xint            pipeout;
  1182. X{
  1183. X    register int    u;
  1184. X    char        *cp, *msg;
  1185. X
  1186. X    if (iop->io_unit == IODEFAULT)    /* take default */
  1187. X    iop->io_unit = (iop->io_flag & (IOREAD | IOHERE)) ? STDIN_FILENO
  1188. X                              : STDOUT_FILENO;
  1189. X
  1190. X/* Check for pipes */
  1191. X
  1192. X    if ((pipein != NOPIPE) && (iop->io_unit == STDIN_FILENO))
  1193. X    return FALSE;
  1194. X
  1195. X    if ((pipeout != NOPIPE) && (iop->io_unit == STDOUT_FILENO))
  1196. X    return FALSE;
  1197. X
  1198. X    msg = (iop->io_flag & (IOREAD | IOHERE)) ? "open" : "create";
  1199. X
  1200. X    if ((iop->io_flag & IOHERE) == 0)
  1201. X    {
  1202. X    if ((cp = evalstr (iop->io_name, DOSUB | DOTRIM)) == (char *)NULL)
  1203. X        return TRUE;
  1204. X    }
  1205. X
  1206. X    if (iop->io_flag & IODUP)
  1207. X    {
  1208. X    if ((cp[1]) || !isdigit (*cp) && *cp != '-')
  1209. X    {
  1210. X        print_error ("%s: illegal >& argument\n", cp);
  1211. X        return TRUE;
  1212. X    }
  1213. X
  1214. X    if (*cp == '-')
  1215. X        iop->io_flag = IOCLOSE;
  1216. X
  1217. X    iop->io_flag &= ~(IOREAD | IOWRITE);
  1218. X    }
  1219. X
  1220. X/* Open the file in the appropriate mode */
  1221. X
  1222. X    switch (iop->io_flag)
  1223. X    {
  1224. X    case IOREAD:                /* <            */
  1225. X        u = S_open (FALSE, cp, O_RDONLY);
  1226. X        break;
  1227. X
  1228. X    case IOHERE:                /* <<            */
  1229. X    case IOHERE | IOXHERE:
  1230. X        u = herein (iop->io_name, iop->io_flag & IOXHERE);
  1231. X        cp = "here file";
  1232. X        break;
  1233. X
  1234. X    case IOWRITE | IOCAT:            /* >>            */
  1235. X        if (check_rsh (cp))
  1236. X        return TRUE;
  1237. X
  1238. X        if ((u = S_open (FALSE, cp, O_WRONLY | O_TEXT)) >= 0)
  1239. X        {
  1240. X        lseek (u, 0L, SEEK_END);
  1241. X        break;
  1242. X        }
  1243. X
  1244. X    case IOWRITE:                /* >            */
  1245. X        if (check_rsh (cp))
  1246. X        return TRUE;
  1247. X
  1248. X        u = S_open (FALSE, cp, O_CMASK, 0666);
  1249. X        break;
  1250. X
  1251. X    case IODUP:                /* >&            */
  1252. X        if (check_rsh (cp))
  1253. X        return TRUE;
  1254. X
  1255. X        u = S_dup2 (*cp - '0', iop->io_unit);
  1256. X        break;
  1257. X
  1258. X    case IOCLOSE:                /* >-            */
  1259. X        if ((iop->io_unit >= STDIN_FILENO) &&
  1260. X        (iop->io_unit <= STDERR_FILENO))
  1261. X        S_dup2 (-1, iop->io_unit);
  1262. X
  1263. X        S_close (iop->io_unit, TRUE);
  1264. X        return FALSE;
  1265. X    }
  1266. X
  1267. X    if (u < 0)
  1268. X    {
  1269. X    print_warn ("%s: cannot %s\n", cp, msg);
  1270. X    return TRUE;
  1271. X    }
  1272. X
  1273. X    else if (u != iop->io_unit)
  1274. X    {
  1275. X    S_dup2 (u, iop->io_unit);
  1276. X    S_close (u, TRUE);
  1277. X    }
  1278. X
  1279. X    return FALSE;
  1280. X}
  1281. X
  1282. X/*
  1283. X * -x flag - echo command to be executed
  1284. X */
  1285. X
  1286. Xstatic void    echo (wp)
  1287. Xregister char    **wp;
  1288. X{
  1289. X    register int    i;
  1290. X
  1291. X    S_putc ('+');
  1292. X
  1293. X    for (i = 0; wp[i] != (char *)NULL; i++)
  1294. X    {
  1295. X    S_putc (SP);
  1296. X    S_puts (wp[i]);
  1297. X    }
  1298. X
  1299. X    S_putc (NL);
  1300. X}
  1301. X
  1302. Xstatic C_Op    **find1case (t, w)
  1303. XC_Op        *t;
  1304. Xchar        *w;
  1305. X{
  1306. X    register C_Op    *t1;
  1307. X    C_Op        **tp;
  1308. X    register char    **wp, *cp;
  1309. X
  1310. X    if (t == (C_Op *)NULL)
  1311. X    return (C_Op **)NULL;
  1312. X
  1313. X    if (t->type == TLIST)
  1314. X    {
  1315. X    if ((tp = find1case (t->left, w)) != (C_Op *)NULL)
  1316. X        return tp;
  1317. X
  1318. X    t1 = t->right;    /* TPAT */
  1319. X    }
  1320. X
  1321. X    else
  1322. X    t1 = t;
  1323. X
  1324. X    for (wp = t1->words; *wp != (char *)NULL;)
  1325. X    {
  1326. X    if ((cp = evalstr (*(wp++), DOSUB)) && gmatch (w, cp, FALSE))
  1327. X        return &t1->left;
  1328. X    }
  1329. X
  1330. X    return (C_Op **)NULL;
  1331. X}
  1332. X
  1333. Xstatic C_Op    *findcase (t, w)
  1334. XC_Op        *t;
  1335. Xchar        *w;
  1336. X{
  1337. X    register C_Op **tp;
  1338. X
  1339. X    return ((tp = find1case (t, w)) != (C_Op **)NULL) ? *tp : (C_Op *)NULL;
  1340. X}
  1341. X
  1342. X/*
  1343. X * Set up the status on exit from a command
  1344. X */
  1345. X
  1346. Xstatic int    setstatus (s)
  1347. Xregister int    s;
  1348. X{
  1349. X    exstat = s;
  1350. X    setval (lookup ("?", TRUE), putn (s));
  1351. X    return s;
  1352. X}
  1353. X
  1354. X/*
  1355. X * PATH-searching interface to execve.  If getenv ("PATH") were kept
  1356. X * up-to-date, execvp might be used.
  1357. X */
  1358. X
  1359. Xstatic int    rexecve (c, v, envp, d_flag)
  1360. Xchar        *c;
  1361. Xchar        **v;
  1362. Xchar        **envp;
  1363. Xbool        d_flag;
  1364. X{
  1365. X    register char    *sp;
  1366. X    int            res;
  1367. X    char        *em;
  1368. X    bool        eloop;
  1369. X
  1370. X/* If the environment is null - It is too big - error */
  1371. X
  1372. X    if (envp == (char **)NULL)
  1373. X    em = AE2big;
  1374. X
  1375. X    else
  1376. X    {
  1377. X    sp = any ('/', c) ? null : path->value;
  1378. X
  1379. X    do
  1380. X    {
  1381. X        sp = path_append (sp, c, e.linep);
  1382. X
  1383. X        if ((res = Execute_program (e.linep, v, envp, d_flag)) != -1)
  1384. X        return res;
  1385. X
  1386. X        eloop = TRUE;
  1387. X
  1388. X        switch (errno)
  1389. X        {
  1390. X
  1391. X/* No entry for the file - if the file exists, execute it as a shell
  1392. X * script
  1393. X */
  1394. X        case ENOENT:
  1395. X            if ((res = O_for_execute (e.linep)) >= 0)
  1396. X            {
  1397. X            S_close (res, TRUE);
  1398. X            *v = e.linep;
  1399. X            em = *--v;
  1400. X            *v = e.linep;
  1401. X                res = Execute_program (lookup (shell, FALSE)->value,
  1402. X                           v, envp, d_flag);
  1403. X            *v = em;
  1404. X
  1405. X            if (res != -1)
  1406. X            return res;
  1407. X
  1408. X            em = "no Shell";
  1409. X            }
  1410. X
  1411. X            else
  1412. X            em = "not found";
  1413. X
  1414. X            eloop = FALSE;
  1415. X            break;
  1416. X
  1417. X        case ENOEXEC:
  1418. X            em = "program corrupt";
  1419. X            break;
  1420. X
  1421. X        case ENOMEM:
  1422. X            em = "program too big";
  1423. X            break;
  1424. X
  1425. X        case E2BIG:
  1426. X            em = AE2big;
  1427. X            break;
  1428. X
  1429. X        default:
  1430. X            em = "cannot execute";
  1431. X            eloop = FALSE;
  1432. X            break;
  1433. X        }
  1434. X    } while ((sp != (char *)NULL) && !eloop);
  1435. X    }
  1436. X
  1437. X    print_warn ("%s: %s\n", c, em);
  1438. X
  1439. X    if (!d_flag)
  1440. X    exit (-1);
  1441. X
  1442. X    return -1;
  1443. X}
  1444. X
  1445. X/*
  1446. X * Run the command produced by generator `f' applied to stream `arg'.
  1447. X */
  1448. X
  1449. Xint        run (argp, f)
  1450. XIO_Args        *argp;
  1451. Xint        (*f)(IO_State *);
  1452. X{
  1453. X    Word_B        *swdlist = wdlist;
  1454. X    Word_B        *siolist = iolist;
  1455. X    jmp_buf        ev, rt;
  1456. X    int            *ofail = failpt;
  1457. X    int            rv = -1;
  1458. X    Break_C        *S_RList = Return_List;    /* Save loval links    */
  1459. X    Break_C        *S_BList = Break_List;
  1460. X    Break_C        *S_SList = SShell_List;
  1461. X    Break_C        bc;
  1462. X    int            LS_depth = Execute_stack_depth;
  1463. X    C_Op        *outtree;
  1464. X
  1465. X/* Create a new environment in which to run */
  1466. X
  1467. X    if (Create_NG_VL () == -1)
  1468. X    return -1;
  1469. X
  1470. X/* Create a new save area */
  1471. X
  1472. X    areanum++;
  1473. X
  1474. X/* Execute the command */
  1475. X
  1476. X    if (newenv (setjmp (errpt = ev)) == FALSE)
  1477. X    {
  1478. X    Return_List = (Break_C *)NULL;
  1479. X    Break_List  = (Break_C *)NULL;
  1480. X    wdlist      = (Word_B *)NULL;
  1481. X    iolist      = (Word_B *)NULL;
  1482. X
  1483. X    pushio (argp, f);
  1484. X    e.iobase = e.iop;
  1485. X    yynerrs = 0;
  1486. X
  1487. X
  1488. X    if ((setjmp (failpt = rt) == 0) &&
  1489. X        ((outtree = yyparse ()) != (C_Op *)NULL))
  1490. X    {
  1491. X        if (setjmp (bc.brkpt) == 0)
  1492. X        {
  1493. X        bc.nextlev = SShell_List;
  1494. X        SShell_List = &bc;
  1495. X        rv = execute (outtree, NOPIPE, NOPIPE, 0);
  1496. X        }
  1497. X
  1498. X        else
  1499. X        rv = getn (lookup ("?", FALSE)->value);
  1500. X    }
  1501. X
  1502. X    quitenv ();
  1503. X    }
  1504. X
  1505. X/* Restore the environment */
  1506. X
  1507. X    Return_List = S_RList;
  1508. X    Break_List = S_BList;
  1509. X    SShell_List = S_SList;
  1510. X    wdlist = swdlist;
  1511. X    iolist = siolist;
  1512. X    failpt = ofail;
  1513. X
  1514. X    Restore_Environment (rv, LS_depth);
  1515. X
  1516. X    freearea (areanum--);
  1517. X    return rv;
  1518. X}
  1519. X
  1520. X/* Exec or spawn the program ? */
  1521. X
  1522. Xstatic int    Execute_program (path, parms, envp, d_flag)
  1523. Xchar        *path;
  1524. Xchar        **parms;
  1525. Xchar        **envp;
  1526. Xbool        d_flag;
  1527. X{
  1528. X    return setstatus ((!d_flag) ? execve (path, parms, envp)
  1529. X                : S_spawnve (path, parms, envp));
  1530. X}
  1531. X
  1532. X/* Set up to spawn a process */
  1533. X
  1534. Xstatic int    S_spawnve (path, parms, envp)
  1535. Xchar        *path;
  1536. Xchar        **parms;
  1537. Xchar        **envp;
  1538. X{
  1539. X    unsigned int    c_cur = (unsigned int)(_psp - 1);
  1540. X    unsigned int    size = 0;
  1541. X    char        *ep, *ep1;
  1542. X    int            res, serrno;
  1543. X    struct MCB_list    *mp = (struct MCB_list *)((unsigned long)c_cur << 16L);
  1544. X
  1545. X
  1546. X/* Check to see if the file exists */
  1547. X
  1548. X    strcpy (path_line, path);
  1549. X
  1550. X    if ((ep = strrchr (path_line, '/')) == (char *)NULL)
  1551. X    ep = path_line;
  1552. X
  1553. X/* If no dot in name - check for .exe and .com files */
  1554. X
  1555. X    if ((ep1 = strchr (ep, '.')) == (char *)NULL)
  1556. X    {
  1557. X    ep1 = ep + strlen (ep);
  1558. X    strcpy (ep1, ".exe");
  1559. X
  1560. X    if ((res = access (path_line, F_OK)) != 0)
  1561. X    {
  1562. X        strcpy (ep1, ".com");
  1563. X        res = access (path_line, F_OK);
  1564. X    }
  1565. X
  1566. X    if (res != 0)
  1567. X        return -1;
  1568. X    }
  1569. X
  1570. X    else if ((stricmp (ep1, ".exe") != 0) && (stricmp (ep1, ".com") != 0))
  1571. X    {
  1572. X    errno = ENOEXEC;
  1573. X    return -1;
  1574. X    }
  1575. X
  1576. X    else if (access (path_line, F_OK) != 0)
  1577. X    return -1;
  1578. X
  1579. X/* Process the command line.  If no swapping, we have executed the program */
  1580. X
  1581. X    res = build_command_line (path_line, parms, envp);
  1582. X
  1583. X    if ((Swap_Mode == SWAP_OFF) || res)
  1584. X    return res;
  1585. X
  1586. X/* Find the length of the swap area */
  1587. X
  1588. X    while ((mp = (struct MCB_list *)((unsigned long)c_cur << 16L))->MCB_type
  1589. X        == MCB_CON)
  1590. X    {
  1591. X    if ((mp->MCB_pid != _psp) && (mp->MCB_pid != 0) &&
  1592. X        (mp->MCB_type != MCB_END))
  1593. X    {
  1594. X        Clear_Extended_File ();
  1595. X        print_error ("Fatal: Memory chain corrupt\n");
  1596. X        return -1;
  1597. X    }
  1598. X
  1599. X    c_cur += (mp->MCB_len + 1);
  1600. X    size += mp->MCB_len + 1;
  1601. X    }
  1602. X
  1603. X/*
  1604. X * Convert swap size from paragraphs to 16K blocks.
  1605. X */
  1606. X
  1607. X    if (size == 0)
  1608. X    size = mp->MCB_len + 1;
  1609. X
  1610. X    SW_Blocks = (size / 0x0400) + 1;
  1611. X
  1612. X/* OK Now we've set up the FCB's, command line and opened the swap file.
  1613. X * Get some sys info for the swapper and execute my little assembler
  1614. X * function to swap us out
  1615. X */
  1616. X
  1617. X    get_sys_info ();
  1618. X
  1619. X/* Ok - 3 methods of swapping */
  1620. X
  1621. X/* If expanded memory - try that */
  1622. X
  1623. X    if (Swap_Mode & SWAP_EXPAND)
  1624. X    {
  1625. X    int    cr;
  1626. X    SW_Mode = 3;            /* Set Expanded memory swap    */
  1627. X
  1628. X    res = SA_spawn (envp);
  1629. X    cr = EMS_Close ();        /* Close EMS            */
  1630. X
  1631. X    if ((res != -2) && cr)        /* Report Close error ?        */
  1632. X    {
  1633. X        res = -2;
  1634. X        errno = cr;
  1635. X    }
  1636. X
  1637. X    if (res == -2)
  1638. X        EMS_error ("Expanded memory swap failed (%x)\n", errno);
  1639. X
  1640. X    else
  1641. X    {
  1642. X        Clear_Extended_File ();
  1643. X        return res;
  1644. X    }
  1645. X
  1646. X/* Failed - disabled */
  1647. X
  1648. X    Swap_Mode &= (~SWAP_EXPAND);
  1649. X    }
  1650. X
  1651. X    if (Swap_Mode & SWAP_EXTEND)
  1652. X    {
  1653. X    SW_Mode = 2;            /* Set Extended memory swap    */
  1654. X
  1655. X        if ((SW_EMsize <= SW_Blocks) ||
  1656. X        ((SW_EMstart - 0x100000L +
  1657. X          ((long)(SW_Blocks - SW_EMsize) * 16L * 1024L)) < 0L))
  1658. X        print_warn ("Not enough Extended memory for swap\n");
  1659. X
  1660. X    else if ((res = SA_spawn (envp)) == -2)
  1661. X        print_warn ("Extended memory swap failed (%x)\n", errno);
  1662. X
  1663. X    else
  1664. X    {
  1665. X        Clear_Extended_File ();
  1666. X        return res;
  1667. X    }
  1668. X
  1669. X/* Failed - disabled */
  1670. X
  1671. X    Swap_Mode &= (~SWAP_EXTEND);
  1672. X    }
  1673. X
  1674. X/* Try the disk if available */
  1675. X
  1676. X    if (Swap_Mode & SWAP_DISK)
  1677. X    {
  1678. X    if ((SW_fp = S_open (TRUE, g_tempname (), O_SMASK, 0600)) < 0)
  1679. X    {
  1680. X        print_error ("No Swap files\n");
  1681. X        errno = ENOSPC;
  1682. X        return -1;
  1683. X    }
  1684. X
  1685. X    SW_Mode = 1;            /* Set Disk file swap        */
  1686. X
  1687. X/* Execute the program */
  1688. X
  1689. X    res = SA_spawn (envp);
  1690. X
  1691. X    Clear_Extended_File ();
  1692. X
  1693. X    if (res == -2)
  1694. X    {
  1695. X        print_warn ("Swap file write failed\n");
  1696. X        errno = ENOSPC;
  1697. X        res = -1;
  1698. X    }
  1699. X
  1700. X/* Close the swap file and return the result */
  1701. X
  1702. X    serrno = errno;
  1703. X    S_close (SW_fp, TRUE);
  1704. X    errno = serrno;
  1705. X    return res;
  1706. X    }
  1707. X
  1708. X/* No swapping available - give up */
  1709. X
  1710. X    Clear_Extended_File ();
  1711. X    print_error ("All Swapping methods failed\n");
  1712. X    errno = ENOSPC;
  1713. X    return -1;
  1714. X}
  1715. X
  1716. X/* Get some system info */
  1717. X
  1718. Xstatic void    get_sys_info ()
  1719. X{
  1720. X    union REGS        or;
  1721. X    struct SREGS    sr;
  1722. X    char        *sp;
  1723. X
  1724. X/* Save the interrupt 0 address */
  1725. X
  1726. X    or.x.ax = 0x3500;
  1727. X    intdosx (&or, &or, &sr);
  1728. X
  1729. X    SW_I0_V_BX = or.x.bx;
  1730. X    SW_I0_V_ES = sr.es;
  1731. X
  1732. X/* Save the interrupt 23 address */
  1733. X
  1734. X    or.x.ax = 0x3523;
  1735. X    intdosx (&or, &or, &sr);
  1736. X
  1737. X    SW_I23_V_BX = or.x.bx;
  1738. X    SW_I23_V_ES = sr.es;
  1739. X
  1740. X/* Get max Extended memory pages, and convert to 16K blocks.  If Extended
  1741. X * memory swapping disabled, set to zero
  1742. X */
  1743. X
  1744. X    or.x.ax = 0x8800;
  1745. X    int86 (0x15, &or, &or);
  1746. X    SW_EMsize = (Swap_Mode & SWAP_EXTEND) ? or.x.ax / 16 : 0;
  1747. X
  1748. X/* Check for the Expand Memory System */
  1749. X
  1750. X    if (!(Swap_Mode & SWAP_EXPAND))
  1751. X    return;
  1752. X
  1753. X    SW_fp = -1;                /* Set EMS handler not defined    */
  1754. X
  1755. X    or.x.ax = 0x3567;
  1756. X    intdosx (&or, &or, &sr);
  1757. X
  1758. X    sp = (char *)((unsigned long)(sr.es) << 16L | 10L);
  1759. X
  1760. X/* If not there - disable */
  1761. X
  1762. X    if (memcmp ("EMMXXXX0", sp, 8) != 0)
  1763. X    {
  1764. X    EMS_error ("Warning: EMS not available\n", 0);
  1765. X    return;
  1766. X    }
  1767. X
  1768. X    or.h.ah = 0x40;            /* Check status            */
  1769. X    int86 (0x67, &or, &or);
  1770. X
  1771. X    if (or.h.ah != 0)
  1772. X    {
  1773. X    EMS_error (EMS_emsg, or.h.ah);
  1774. X    return;
  1775. X    }
  1776. X
  1777. X/* Check version greater than 3.2 */
  1778. X
  1779. X    or.h.ah = 0x46;
  1780. X    int86 (0x67, &or, &or);
  1781. X
  1782. X    if ((or.h.ah != 0) || (or.h.al < 0x32))
  1783. X    {
  1784. X    EMS_error (EMS_emsg, or.h.ah);
  1785. X    return;
  1786. X    }
  1787. X
  1788. X/*  get page frame address */
  1789. X
  1790. X    or.h.ah = 0x41;
  1791. X    int86 (0x67, &or, &or);
  1792. X
  1793. X    if (or.h.ah != 0)
  1794. X    {
  1795. X    EMS_error (EMS_emsg, or.h.ah);
  1796. X    return;
  1797. X    }
  1798. X
  1799. X    SW_EMSFrame = or.x.bx;        /* Save the page frame        */
  1800. X
  1801. X/* Get the number of pages required */
  1802. X
  1803. X    or.h.ah = 0x43;
  1804. X    or.x.bx = SW_Blocks;
  1805. X    int86 (0x67, &or, &or);
  1806. X
  1807. X    if (or.h.ah != 0)
  1808. X    {
  1809. X    EMS_error (EMS_emsg, or.h.ah);
  1810. X    return;
  1811. X    }
  1812. X
  1813. X/* Save the EMS Handler */
  1814. X
  1815. X    SW_fp = or.x.dx;
  1816. X
  1817. X/* save EMS page map */
  1818. X
  1819. X    or.h.ah = 0x47;
  1820. X    or.x.dx = SW_fp;
  1821. X    int86 (0x67, &or, &or);
  1822. X
  1823. X    if (or.h.ah != 0)
  1824. X    {
  1825. X    EMS_error (EMS_emsg, or.h.ah);
  1826. X    return;
  1827. X    }
  1828. X}
  1829. X
  1830. X/* Print EMS error message */
  1831. X
  1832. Xstatic void    EMS_error (s, v)
  1833. Xchar        *s;
  1834. Xint        v;
  1835. X{
  1836. X    print_warn (s, v);
  1837. X    Swap_Mode &= ~(SWAP_EXPAND);
  1838. X    EMS_Close ();
  1839. X}
  1840. X
  1841. X
  1842. X/* If the handler is defined - close it */
  1843. X
  1844. Xstatic int    EMS_Close ()
  1845. X{
  1846. X    union REGS        or;
  1847. X    int            res = 0;
  1848. X
  1849. X    if (SW_fp == -1)
  1850. X    return 0;
  1851. X
  1852. X/* Restore EMS page */
  1853. X
  1854. X    or.h.ah = 0x48;
  1855. X    or.x.dx = SW_fp;
  1856. X    int86 (0x67, &or, &or);
  1857. X
  1858. X    if (or.h.ah != 0)
  1859. X    res = or.h.al;
  1860. X
  1861. X    or.h.ah = 0x45;
  1862. X    or.x.dx = SW_fp;
  1863. X    int86 (0x67, &or, &or);
  1864. X
  1865. X    SW_fp = -1;
  1866. X    return (res) ? res : or.h.ah;
  1867. X}
  1868. X
  1869. X/* Set up command line.  If the EXTENDED_LINE variable is set, we create
  1870. X * a temporary file, write the argument list (one entry per line) to the
  1871. X * this file and set the command line to @<filename>.  If NOSWAPPING, we
  1872. X * execute the program because I have to modify the argument line
  1873. X */
  1874. X
  1875. Xint    build_command_line (path, argv, envp)
  1876. Xchar    *path;
  1877. Xchar    **argv;
  1878. Xchar    **envp;
  1879. X{
  1880. X    char        **pl = argv;
  1881. X    char        *fname;
  1882. X    int            res, fd;
  1883. X    char        *pname;
  1884. X    FILE        *fp;
  1885. X    char        nbuffer[NAME_MAX + 2];
  1886. X    bool        found;
  1887. X    char        *ep;
  1888. X    char        *new_args[3];
  1889. X
  1890. X/* Find the start of the program name */
  1891. X
  1892. X    if ((pname = strrchr (path, '/')) == (char *)NULL)
  1893. X    pname = path;
  1894. X
  1895. X    else
  1896. X    ++pname;
  1897. X
  1898. X/* Translate process name to MSDOS format */
  1899. X
  1900. X    Convert_Slashes (path);
  1901. X    strupr (path);
  1902. X
  1903. X/* Extended command line processing */
  1904. X
  1905. X    Extend_file == (char *)NULL;        /* Set no file        */
  1906. X
  1907. X    if ((*(pl++) != (char *)NULL) &&
  1908. X    ((fname = lookup ("EXTENDED_LINE", FALSE)->value) != null) &&
  1909. X    ((fp = fopen (fname, "rt")) != (FILE *)NULL))
  1910. X    {
  1911. X
  1912. X/* Loop through the file look for the current program */
  1913. X
  1914. X    found = FALSE;
  1915. X
  1916. X    while (fgets (nbuffer, NAME_MAX + 1, fp) != (char *)NULL)
  1917. X    {
  1918. X        if ((ep = strchr (nbuffer, '\n')) != (char *)NULL)
  1919. X        *ep = 0;
  1920. X
  1921. X        if (stricmp (nbuffer, pname) == 0)
  1922. X        {
  1923. X        found = TRUE;
  1924. X        break;
  1925. X        }
  1926. X    }
  1927. X
  1928. X    fclose (fp);
  1929. X
  1930. X/* Check parameters don't contain a re-direction parameter */
  1931. X
  1932. X    if (found)
  1933. X    {
  1934. X        char    **pl1 = pl;
  1935. X
  1936. X        while (*pl1 != (char *)NULL)
  1937. X        {
  1938. X        if (**(pl1++) == '@')
  1939. X        {
  1940. X            found = FALSE;
  1941. X            break;
  1942. X        }
  1943. X        }
  1944. X    }
  1945. X
  1946. X/* If we find it - create a temporary file and write the stuff */
  1947. X
  1948. X    if ((found) &&
  1949. X        ((fd = S_open (FALSE, Extend_file = g_tempname (), O_CMASK,
  1950. X               0600)) >= 0))
  1951. X    {
  1952. X
  1953. X/* Copy to end of list */
  1954. X
  1955. X        while (*pl != (char *)NULL)
  1956. X        {
  1957. X        if (((res = strlen (*pl)) && (write (fd, *pl, res) != res)) ||
  1958. X            (write (fd, "\n", 1) != 1))
  1959. X        {
  1960. X            close (fd);
  1961. X            unlink (Extend_file);
  1962. X            Extend_file == (char *)NULL;
  1963. X            errno = ENOSPC;
  1964. X            return -1;
  1965. X        }
  1966. X
  1967. X        ++pl;
  1968. X        }
  1969. X
  1970. X/* Completed write OK */
  1971. X
  1972. X        close (fd);
  1973. X
  1974. X/* Set up cmd_line[1] to contain the filename */
  1975. X
  1976. X        memset (cmd_line, 0, CMD_LINE_MAX);
  1977. X        cmd_line[1] = '@';
  1978. X        strcpy (&cmd_line[2], Extend_file);
  1979. X        cmd_line[0] = (char)(strlen (Extend_file) + 1);
  1980. X
  1981. X/* Correctly terminate cmd_line in no swap mode */
  1982. X
  1983. X        if (Swap_Mode != SWAP_OFF)
  1984. X        cmd_line[cmd_line[0] + 1] = '\r';
  1985. X
  1986. X/* If the name in the file is in upper case - use \ for separators */
  1987. X
  1988. X        if (isupper (*nbuffer))
  1989. X        Convert_Slashes (&cmd_line[2]);
  1990. X
  1991. X/* OK we are ready to execute */
  1992. X
  1993. X        if (Swap_Mode == SWAP_OFF)
  1994. X        {
  1995. X        new_args[0] = *argv;
  1996. X        new_args[1] = &cmd_line[1];
  1997. X        new_args[2] = (char *)NULL;
  1998. X        return spawnve (P_WAIT, path, new_args, envp);
  1999. X        }
  2000. X
  2001. X        else
  2002. X        return 0;
  2003. X    }
  2004. X    }
  2005. X
  2006. X/* Check length of Parameter list */
  2007. X
  2008. X    res = 0;
  2009. X    cmd_line[0] = 0;
  2010. X    cmd_line[1] = '\r';
  2011. X    ep = cmd_line;
  2012. X
  2013. X/* Skip the first parameter and get the length of the rest */
  2014. X
  2015. X    if (*argv != (char *)NULL)
  2016. X    {
  2017. X    while (*pl != (char *)NULL)
  2018. X    {
  2019. X        if ((res += (strlen (*pl) + 1)) >= CMD_LINE_MAX)
  2020. X        {
  2021. X        errno = E2BIG;
  2022. X        return -1;
  2023. X        }
  2024. X
  2025. X        strcat (strcat (ep, " "), *(pl++));
  2026. X    }
  2027. X
  2028. X    if (res)
  2029. X        cmd_line[res--] = '\r';
  2030. X    }
  2031. X
  2032. X/* Terminate the line and insert the line length */
  2033. X
  2034. X    cmd_line[0] = (char)res;
  2035. X
  2036. X/* If swapping disabled - just execute it */
  2037. X
  2038. X    return (Swap_Mode == SWAP_OFF) ? spawnve (P_WAIT, path, argv, envp) : 0;
  2039. X}
  2040. X
  2041. X/* Clear Extended command line file */
  2042. X
  2043. Xstatic void    Clear_Extended_File ()
  2044. X{
  2045. X    if (Extend_file != (char *)NULL)
  2046. X    unlink (Extend_file);
  2047. X
  2048. X    Extend_file = (char *)NULL;
  2049. X}
  2050. SHAR_EOF
  2051. chmod 0644 shell/sh3.c || echo "restore of shell/sh3.c fails"
  2052. set `wc -c shell/sh3.c`;Sum=$1
  2053. if test "$Sum" != "28726"
  2054. then echo original size 28726, current size $Sum;fi
  2055. echo "x - extracting shell/sh4.c (Text)"
  2056. sed 's/^X//' << 'SHAR_EOF' > shell/sh4.c &&
  2057. X/* MS-DOS SHELL - 'word' Interpretator
  2058. X *
  2059. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  2060. X *
  2061. X * This code is based on (in part) the shell program written by Charles
  2062. X * Forsyth and is subject to the following copyright restrictions:
  2063. X *
  2064. X * 1.  Redistribution and use in source and binary forms are permitted
  2065. X *     provided that the above copyright notice is duplicated in the
  2066. X *     source form and the copyright notice in file sh6.c is displayed
  2067. X *     on entry to the program.
  2068. X *
  2069. X * 2.  The sources (or parts thereof) or objects generated from the sources
  2070. X *     (or parts of sources) cannot be sold under any circumstances.
  2071. X *
  2072. X *    $Header: sh4.c 1.1 90/01/25 13:41:38 MS_user Exp $
  2073. X *
  2074. X *    $Log:    sh4.c $
  2075. X * Revision 1.1  90/01/25  13:41:38  MS_user
  2076. X * Initial revision
  2077. X * 
  2078. X */
  2079. X
  2080. X#include <sys/types.h>
  2081. X#include <sys/stat.h>
  2082. X#include <signal.h>
  2083. X#include <errno.h>
  2084. X#include <setjmp.h>
  2085. X#include <dirent.h>
  2086. X#include <string.h>
  2087. X#include <stdlib.h>
  2088. X#include <unistd.h>
  2089. X#include <ctype.h>
  2090. X#include <bios.h>
  2091. X#include <dos.h>
  2092. X#include "sh.h"
  2093. X
  2094. X/*
  2095. X * ${}, `command`, blank interpretation, quoting and file name expansion
  2096. X */
  2097. X
  2098. X#define    NSTART        16        /* default number of words to    */
  2099. X                    /* allow for initially        */
  2100. Xstatic Word_B        *C_EList;    /* For expand functions        */
  2101. Xstatic Word_B        *New_Elist;
  2102. Xstatic char        *spcl  = "[?*";
  2103. Xstatic char        *spcl1 = "\"'";
  2104. X
  2105. Xstatic void        globname (char *, char *);
  2106. Xstatic bool        expand (char *, Word_B **, int);
  2107. Xstatic char        dollar (int);
  2108. Xstatic bool        grave (int);
  2109. Xstatic Word_B        *Expand_globs (char *, Word_B *);
  2110. Xstatic bool        anyspcl (Word_B *);
  2111. Xstatic char        *blank (int);
  2112. Xstatic char        *generate (char *, char *, char *, char *);
  2113. Xstatic char        *unquote (char *);
  2114. Xstatic Word_B        *newword (int);
  2115. Xstatic bool        anys (char *, char *);
  2116. Xstatic char        *anys_p (char *, char *);
  2117. Xstatic void        Glob_MDrives (char *, char *);
  2118. Xstatic char        *Check_Multi_Drive (char *);
  2119. X
  2120. X/*
  2121. X * Expand all words to their full potential
  2122. X */
  2123. X
  2124. Xchar        **eval(ap, f)
  2125. Xregister char    **ap;
  2126. X{
  2127. X    Word_B    *wb = (Word_B *)NULL;
  2128. X    char    **wp = (char **)NULL;
  2129. X    char    **wf = (char **)NULL;
  2130. X    jmp_buf    ev;
  2131. X
  2132. X    if (newenv (setjmp (errpt = ev)) == FALSE)
  2133. X    {
  2134. X    while ((*ap != (char *)NULL) && isassign (*ap))
  2135. X        expand (*(ap++), &wb, f & ~DOGLOB);
  2136. X
  2137. X    if (FL_TEST ('k'))
  2138. X    {
  2139. X        for (wf = ap; *wf != (char *)NULL; wf++)
  2140. X        {
  2141. X        if (isassign (*wf))
  2142. X            expand (*wf, &wb, f & ~DOGLOB);
  2143. X        }
  2144. X    }
  2145. X
  2146. X/* Now expand the words */
  2147. X
  2148. X    for (wb = addword ((char *)NULL, wb); *ap; ap++)
  2149. X    {
  2150. X        if (!FL_TEST ('k') || !isassign(*ap))
  2151. X        expand (*ap, &wb, f & ~DOKEY);
  2152. X    }
  2153. X
  2154. X/* Get the word list */
  2155. X
  2156. X    wp = getwords (wb = addword ((char *)NULL, wb));
  2157. X    quitenv ();
  2158. X    }
  2159. X
  2160. X    else
  2161. X    gflg = 1;
  2162. X
  2163. X    return gflg ? (char **)NULL : wp;
  2164. X}
  2165. X
  2166. X/*
  2167. X * Make the exported environment from the exported names in the dictionary.
  2168. X * Keyword assignments will already have been done.  Convert to MSDOS
  2169. X * format if flag set and m enabled
  2170. X */
  2171. X
  2172. Xchar    **makenv ()
  2173. X{
  2174. X    register Word_B    *wb = (Word_B *)NULL;
  2175. X    register Var_List    *vp;
  2176. X    char        *cp, *sp;
  2177. X    int            len = 0;
  2178. X
  2179. X    for (vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
  2180. X    {
  2181. X    if (vp->status & EXPORT)
  2182. X    {
  2183. X        if ((len += (strlen (vp->name) + 1)) >= 0x7f00)
  2184. X        return (char **)NULL;
  2185. X
  2186. X        wb = addword (vp->name, wb);
  2187. X
  2188. X/* If MSDOS mode, we need to copy the variable, convert / to \ and put
  2189. X * the copy in the environment list instead
  2190. X */
  2191. X
  2192. X        if (FL_TEST ('m') && (vp->status & C_MSDOS))
  2193. X        {
  2194. X        cp = space (strlen (sp = wb->w_words[wb->w_nword - 1]) + 1);
  2195. X        wb->w_words[wb->w_nword - 1] = cp;
  2196. X        Convert_Slashes (strcpy (cp, sp));
  2197. X        }
  2198. X    }
  2199. X    }
  2200. X
  2201. X    return getwords (wb = addword ((char *)NULL, wb));
  2202. X}
  2203. X
  2204. Xchar        *evalstr(cp, f)
  2205. Xregister char    *cp;
  2206. Xint        f;
  2207. X{
  2208. X    Word_B    *wb = (Word_B *)NULL;
  2209. X
  2210. X    if (expand (cp, &wb, f))
  2211. X    {
  2212. X    if ((wb == (Word_B *)NULL) || (wb->w_nword == 0) ||
  2213. X        ((cp = wb->w_words[0]) == (char *)NULL))
  2214. X        cp = null;
  2215. X
  2216. X    DELETE (wb);
  2217. X    }
  2218. X
  2219. X    else
  2220. X    cp = (char *)NULL;
  2221. X
  2222. X    return cp;
  2223. X}
  2224. X
  2225. X/* Expand special characters and variables */
  2226. X
  2227. Xstatic bool        expand (cp, wbp, f)
  2228. Xregister char        *cp;
  2229. Xregister Word_B        **wbp;
  2230. X{
  2231. X    jmp_buf    ev;
  2232. X
  2233. X    gflg = 0;
  2234. X
  2235. X    if (cp == (char *)NULL)
  2236. X    return FALSE;
  2237. X
  2238. X/* If there are no special characters and no separators, nothing to do,
  2239. X * just save the word
  2240. X */
  2241. X
  2242. X    if (!anys (spcl2, cp) && !anys (ifs->value, cp) &&
  2243. X    ((f & DOGLOB) == 0 || !anys (spcl, cp)))
  2244. X    {
  2245. X    cp = strsave (cp, areanum);
  2246. X
  2247. X    if (f & DOTRIM)
  2248. X        unquote (cp);
  2249. X
  2250. X    *wbp = addword (cp, *wbp);
  2251. X    return TRUE;
  2252. X    }
  2253. X
  2254. X/* Set up to read the word back in */
  2255. X
  2256. X    if (newenv (setjmp (errpt = ev)) == FALSE)
  2257. X    {
  2258. X    PUSHIO (aword, cp, strchar);
  2259. X    e.iobase = e.iop;
  2260. X
  2261. X    while ((cp = blank (f)) && gflg == 0)
  2262. X    {
  2263. X        e.linep = cp;
  2264. X        cp = strsave (cp, areanum);
  2265. X
  2266. X/* Global expansion disabled ? */
  2267. X
  2268. X        if (((f & DOGLOB) == 0) || FL_TEST ('f'))
  2269. X        {
  2270. X        if (f & DOTRIM)
  2271. X            unquote(cp);
  2272. X
  2273. X        *wbp = addword (cp, *wbp);
  2274. X        }
  2275. X
  2276. X        else
  2277. X        *wbp = Expand_globs (cp, *wbp);
  2278. X    }
  2279. X
  2280. X    quitenv ();
  2281. X    }
  2282. X
  2283. X    else
  2284. X    gflg = 1;
  2285. X
  2286. X    return (gflg == 0) ? TRUE : FALSE;
  2287. X}
  2288. X
  2289. X/*
  2290. X * Blank interpretation and quoting
  2291. X */
  2292. X
  2293. Xstatic char    *blank(f)
  2294. X{
  2295. X    register int    c, c1;
  2296. X    register char    *sp = e.linep;
  2297. X    int            scanequals = f & DOKEY;
  2298. X    int            foundequals = 0;
  2299. X
  2300. Xloop:
  2301. X    switch (c = subgetc ('"', foundequals))
  2302. X    {
  2303. X    case 0:
  2304. X        if (sp == e.linep)
  2305. X        return (char *)NULL;
  2306. X
  2307. X        *e.linep++ = 0;
  2308. X        return sp;
  2309. X
  2310. X    default:
  2311. X        if ((f & DOBLANK) && any ((char)c, ifs->value))
  2312. X        goto loop;
  2313. X
  2314. X        break;
  2315. X
  2316. X    case '"':
  2317. X    case '\'':
  2318. X        scanequals = 0;
  2319. X        if (INSUB())
  2320. X        break;
  2321. X
  2322. X        for (c1 = c; (c = subgetc ((char)c1, 1)) != c1;)
  2323. X        {
  2324. X        if (c == 0)
  2325. X            break;
  2326. X
  2327. X        if ((c == '\'') || !any ((char)c, "$`\""))
  2328. X            c |= QUOTE;
  2329. X
  2330. X        *e.linep++ = (char)c;
  2331. X        }
  2332. X
  2333. X        c = 0;
  2334. X    }
  2335. X
  2336. X    unget(c);
  2337. X
  2338. X    if (!isalpha (c))
  2339. X    scanequals = 0;
  2340. X
  2341. X    while (1)
  2342. X    {
  2343. X    if (((c = subgetc ('"', foundequals)) == 0) ||
  2344. X        (f & DOBLANK) && any ((char)c, ifs->value) ||
  2345. X        !INSUB() && any ((char)c, spcl1))
  2346. X    {
  2347. X        scanequals = 0;
  2348. X        unget (c);
  2349. X
  2350. X        if (any ((char)c, spcl1))
  2351. X        goto loop;
  2352. X
  2353. X        break;
  2354. X    }
  2355. X
  2356. X    if (scanequals)
  2357. X    {
  2358. X        if (c == '=')
  2359. X        {
  2360. X        foundequals = 1;
  2361. X        scanequals  = 0;
  2362. X        }
  2363. X
  2364. X        else if (!isalnum (c))
  2365. X        scanequals = 0;
  2366. X    }
  2367. X
  2368. X    *e.linep++ = (char)c;
  2369. X    }
  2370. X
  2371. X    *e.linep++ = 0;
  2372. X    return sp;
  2373. X}
  2374. X
  2375. X/*
  2376. X * Get characters, substituting for ` and $
  2377. X */
  2378. X
  2379. Xint        subgetc (ec, quoted)
  2380. Xregister char    ec;
  2381. Xint        quoted;
  2382. X{
  2383. X    register char    c;
  2384. X
  2385. Xagain:
  2386. X    c = (char)Getc (ec);
  2387. X
  2388. X    if (!INSUB() && ec != '\'')
  2389. X    {
  2390. X    if (c == '`')
  2391. X    {
  2392. X        if (grave (quoted) == 0)
  2393. X        return 0;
  2394. X
  2395. X        e.iop->task = XGRAVE;
  2396. X        goto again;
  2397. X    }
  2398. X
  2399. X    if (c == '$' && (c = dollar (quoted)) == 0)
  2400. X    {
  2401. X        e.iop->task = XDOLL;
  2402. X        goto again;
  2403. X    }
  2404. X    }
  2405. X
  2406. X    return c;
  2407. X}
  2408. X
  2409. X/*
  2410. X * Prepare to generate the string returned by ${} substitution.
  2411. X */
  2412. X
  2413. Xstatic char    dollar (quoted)
  2414. Xint        quoted;
  2415. X{
  2416. X    IO_State        *oiop;
  2417. X    char        *dolp, otask;
  2418. X    register char    *s, c, *cp;
  2419. X    Var_List        *vp;
  2420. X    bool        colon_f = FALSE;
  2421. X
  2422. X    c = (char)readc ();
  2423. X    s = e.linep;
  2424. X
  2425. X/* Bracketed or not ? */
  2426. X
  2427. X    if (c != '{')
  2428. X    {
  2429. X
  2430. X/* Get the string, while it is a alpha character */
  2431. X
  2432. X    *e.linep++ = c;
  2433. X
  2434. X    if (isalpha (c))
  2435. X    {
  2436. X        while (((c = (char)readc ()) != 0) && isalnum (c))
  2437. X        {
  2438. X        if (e.linep < e.eline)
  2439. X            *e.linep++ = c;
  2440. X        }
  2441. X
  2442. X        unget(c);
  2443. X    }
  2444. X
  2445. X    c = 0;
  2446. X    }
  2447. X
  2448. X/* Bracketed - special case */
  2449. X
  2450. X    else
  2451. X    {
  2452. X    oiop = e.iop;
  2453. X    otask = e.iop->task;
  2454. X    e.iop->task = XOTHER;
  2455. X
  2456. X    while (((c = (char)subgetc ('"', 0)) != 0) && (c != '}') && (c != NL))
  2457. X    {
  2458. X        if (e.linep < e.eline)
  2459. X        *e.linep++ = c;
  2460. X    }
  2461. X
  2462. X    if (oiop == e.iop)
  2463. X        e.iop->task = otask;
  2464. X
  2465. X/* Check terminate correctly */
  2466. X
  2467. X    if (c != '}')
  2468. X    {
  2469. X        print_error ("sh: unclosed ${\n");
  2470. X        gflg++;
  2471. X        return c;
  2472. X    }
  2473. X    }
  2474. X
  2475. X/* Check line length */
  2476. X
  2477. X    if (e.linep >= e.eline)
  2478. X    {
  2479. X    print_error ("sh: string in ${} too long\n");
  2480. X    gflg++;
  2481. X    e.linep -= 10;
  2482. X    }
  2483. X
  2484. X    *e.linep = 0;
  2485. X
  2486. X/* Scan for =-+? in string */
  2487. X
  2488. X    if (*s)
  2489. X    {
  2490. X    for (cp = s + 1; *cp; cp++)
  2491. X    {
  2492. X
  2493. X/* Check for end character other than null (=-+?) */
  2494. X
  2495. X        if (any (*cp, "=-+?"))
  2496. X        {
  2497. X        c = *cp;
  2498. X
  2499. X/* Check for case of :[=-+?].  If found - set flag */
  2500. X
  2501. X        if (*(cp - 1) == ':')
  2502. X        {
  2503. X            colon_f = TRUE;
  2504. X            *(cp - 1) = 0;
  2505. X        }
  2506. X
  2507. X        *(cp++) = 0;
  2508. X        break;
  2509. X        }
  2510. X    }
  2511. X    }
  2512. X
  2513. X/* Check for * and @ processing */
  2514. X
  2515. X    if (s[1] == 0 && (*s == '*' || *s == '@'))
  2516. X    {
  2517. X    if (dolc > 1)
  2518. X    {
  2519. X        e.linep = s;
  2520. X        PUSHIO (awordlist, dolv + 1, dol_char);
  2521. X        e.iop->dflag = (char)(!quoted ? DSA_NULL
  2522. X                      : ((*s == '*') ? DSA_STAR : DSA_AMP));
  2523. X        return 0;
  2524. X    }
  2525. X
  2526. X/* trap the nasty ${=} */
  2527. X
  2528. X    else
  2529. X    {
  2530. X        s[0] = '1';
  2531. X        s[1] = 0;
  2532. X    }
  2533. X    }
  2534. X
  2535. X/* Find the current value
  2536. X *
  2537. X * $~xxx variables are used by the Shell internally and cannot be accessed
  2538. X * by the user.
  2539. X */
  2540. X
  2541. X    if (*s == '~')
  2542. X    dolp = null;
  2543. X
  2544. X    else if ((dolp = (vp = lookup (s, FALSE))->value) == null)
  2545. X    {
  2546. X    switch (c)
  2547. X    {
  2548. X        case '=':
  2549. X        if (isdigit (*s))
  2550. X        {
  2551. X            print_error ("sh: cannot use ${...=...} with $n\n");
  2552. X            gflg++;
  2553. X            break;
  2554. X        }
  2555. X
  2556. X        setval ((vp = lookup (s, TRUE)), cp);
  2557. X        dolp = vp->value;
  2558. X        break;
  2559. X
  2560. X        case '-':
  2561. X        dolp = strsave (cp, areanum);
  2562. X        break;
  2563. X
  2564. X        case '?':
  2565. X        if (*cp == 0)
  2566. X            cp = "parameter null or not set";
  2567. X
  2568. X        print_error ("%s: %s\n", s, cp);
  2569. X
  2570. X        gflg++;
  2571. X        break;
  2572. X    }
  2573. X    }
  2574. X
  2575. X    else if (c == '+')
  2576. X    dolp = strsave (cp, areanum);
  2577. X
  2578. X/* Check for unset values */
  2579. X
  2580. X    if (FL_TEST ('u') && dolp == null)
  2581. X    {
  2582. X    print_error ("sh: unset variable %s\n", s);
  2583. X    gflg++;
  2584. X    }
  2585. X
  2586. X    e.linep = s;
  2587. X    PUSHIO (aword, dolp, quoted ? qstrchar : strchar);
  2588. X    return 0;
  2589. X}
  2590. X
  2591. X/*
  2592. X * Run the command in `...` and read its output.
  2593. X */
  2594. X
  2595. Xstatic bool    grave (quoted)
  2596. Xint        quoted;
  2597. X{
  2598. X    char        *cp, *sp;
  2599. X    int            localpipe, rv;
  2600. X    jmp_buf        ev, rt;
  2601. X    C_Op        *outtree;
  2602. X    Break_C        bc;
  2603. X
  2604. X/* Save area */
  2605. X
  2606. X    long        s_flags = flags;
  2607. X    Word_B        *s_wdlist = wdlist;
  2608. X    Word_B        *s_iolist = iolist;
  2609. X    Break_C        *S_RList = Return_List;    /* Save loval links    */
  2610. X    Break_C        *S_BList = Break_List;
  2611. X    Break_C        *S_SList = SShell_List;
  2612. X    int            *s_fail = failpt;
  2613. X    int            s_execflg = execflg;
  2614. X    int            Local_depth;
  2615. X
  2616. X/* Check there is an ending grave */
  2617. X
  2618. X    if ((cp = strchr (e.iop->argp->aword, '`')) == (char *)NULL)
  2619. X    {
  2620. X    print_error ("sh: no closing `\n");
  2621. X    return FALSE;
  2622. X    }
  2623. X
  2624. X/* Create the pipe to read the output from the command string */
  2625. X
  2626. X    if ((localpipe = openpipe ()) < 0)
  2627. X    return FALSE;
  2628. X
  2629. X/* Terminate string and initialise save area */
  2630. X
  2631. X    *cp = 0;
  2632. X
  2633. X/* Create a new environment */
  2634. X
  2635. X    S_dup2 (localpipe, 1);
  2636. X
  2637. X    FL_CLEAR ('e');
  2638. X    FL_CLEAR ('v');
  2639. X    FL_CLEAR ('n');
  2640. X
  2641. X    sp = strsave (e.iop->argp->aword, areanum++);
  2642. X    unquote (sp);
  2643. X
  2644. X/* Set up new environment */
  2645. X
  2646. X    Local_depth = Execute_stack_depth++;
  2647. X    rv = Create_NG_VL ();
  2648. X
  2649. X    if ((rv != -1) && (newenv (setjmp (errpt = ev)) == FALSE))
  2650. X    {
  2651. X    Return_List = (Break_C *)NULL;
  2652. X    Break_List  = (Break_C *)NULL;
  2653. X    wdlist        = (Word_B *)NULL;
  2654. X    wdlist        = (Word_B *)NULL;
  2655. X    iolist        = (Word_B *)NULL;
  2656. X
  2657. X    PUSHIO (aword, sp, nlchar);
  2658. X    e.cline = space (LINE_MAX);
  2659. X    e.eline = e.cline + LINE_MAX - 5;
  2660. X    e.linep = e.cline;
  2661. X    e.iobase = e.iop;
  2662. X
  2663. X/* Clear interrupt, error, multiline, parse and execute flags.  */
  2664. X
  2665. X    SW_intr = 0;
  2666. X    yynerrs = 0;
  2667. X    multiline = 0;
  2668. X    inparse = 0;
  2669. X    execflg = 1;
  2670. X
  2671. X/* Parse the line and execute it */
  2672. X
  2673. X    if ((setjmp (failpt = rt) == 0) &&
  2674. X        ((outtree = yyparse ()) != (C_Op *)NULL))
  2675. X    {
  2676. X        if (setjmp (bc.brkpt) == 0)
  2677. X        {
  2678. X        bc.nextlev = SShell_List;
  2679. X        SShell_List = &bc;
  2680. X        execute (outtree, NOPIPE, NOPIPE, 0);
  2681. X        }
  2682. X    }
  2683. X
  2684. X    quitenv ();
  2685. X    }
  2686. X
  2687. X/* Fail - close pipe and delete it */
  2688. X
  2689. X    else
  2690. X    {
  2691. X    S_Delete (localpipe);
  2692. X    S_close (localpipe, TRUE);
  2693. X    }
  2694. X
  2695. X/* Restore environment */
  2696. X
  2697. X    Restore_Environment (0, Local_depth);
  2698. X
  2699. X/* Free old space */
  2700. X
  2701. X    freehere (areanum);
  2702. X    freearea (areanum--);    /* free old space */
  2703. X
  2704. X/* Ok - completed processing - restore environment and read the pipe */
  2705. X
  2706. X    execflg    = s_execflg;
  2707. X    flags    = s_flags;
  2708. X    wdlist    = s_wdlist;
  2709. X    iolist    = s_iolist;
  2710. X    failpt    = s_fail;
  2711. X    Return_List = S_RList;
  2712. X    Break_List    = S_BList;
  2713. X    SShell_List = S_SList;
  2714. X
  2715. X/* Move pipe to start so we can read it */
  2716. X
  2717. X    *(cp++) = '`';
  2718. X    lseek (localpipe, 0L, SEEK_SET);
  2719. X    e.iop->argp->aword = cp;
  2720. X    PUSHIO (afile, remap (localpipe), quoted ? qgravechar: gravechar);
  2721. X    return TRUE;
  2722. X}
  2723. X
  2724. X/*
  2725. X * Remove Quotes from a string
  2726. X */
  2727. X
  2728. Xstatic char    *unquote (as)
  2729. Xregister char    *as;
  2730. X{
  2731. X    register char    *s;
  2732. X
  2733. X    if ((s = as) != (char *)NULL)
  2734. X    {
  2735. X    while (*s)
  2736. X        *(s++) &= ~QUOTE;
  2737. X    }
  2738. X
  2739. X    return as;
  2740. X}
  2741. X
  2742. X/*
  2743. X * Expand *, [] and ?
  2744. X */
  2745. X
  2746. Xstatic Word_B    *Expand_globs (cp, wb)
  2747. Xchar        *cp;
  2748. XWord_B        *wb;
  2749. X{
  2750. X    register int    i = 0;
  2751. X    register char    *pp;
  2752. X
  2753. X/* Ignore null strings */
  2754. X
  2755. X    if (cp == (char *)NULL)
  2756. X    return wb;
  2757. X
  2758. X/* Any special characters */
  2759. X
  2760. X    for (pp = cp; *pp; pp++)
  2761. X    {
  2762. X    if (any (*pp, spcl))
  2763. X        i++;
  2764. X
  2765. X    else if (!any (*pp & ~QUOTE, spcl))
  2766. X        *pp &= ~QUOTE;
  2767. X    }
  2768. X
  2769. X/* No - just add the word to the selected block */
  2770. X
  2771. X    if (i == 0)
  2772. X    return addword (unquote (cp), wb);
  2773. X
  2774. X/* OK - we have to expand the word whilst any words in cl have special
  2775. X * characters in them
  2776. X */
  2777. X
  2778. X    for (C_EList = addword (strsave (cp, areanum), (Word_B *)NULL);
  2779. X     anyspcl (C_EList); C_EList = New_Elist)
  2780. X    {
  2781. X
  2782. X/* Get a new block for this pass of the expansion */
  2783. X
  2784. X    New_Elist = newword (C_EList->w_nword * 2);
  2785. X
  2786. X/* For each word, expand it */
  2787. X
  2788. X    for (i = 0; i < C_EList->w_nword; i++)
  2789. X    {
  2790. X        if ((pp = anys_p (C_EList->w_words[i], spcl)) != (char *)NULL)
  2791. X        Glob_MDrives (C_EList->w_words[i], pp);
  2792. X
  2793. X        else
  2794. X        New_Elist = addword (strsave (C_EList->w_words[i], areanum),
  2795. X                     New_Elist);
  2796. X    }
  2797. X
  2798. X/* The current list is now the previous list, so delete it */
  2799. X
  2800. X    for (i = 0; i < C_EList->w_nword; i++)
  2801. X        DELETE (C_EList->w_words[i]);
  2802. X
  2803. X    DELETE (C_EList);
  2804. X    }
  2805. X
  2806. X    for (i = 0; i < C_EList->w_nword; i++)
  2807. X    unquote (C_EList->w_words[i]);
  2808. X
  2809. X    qsort (C_EList->w_words, C_EList->w_nword, sizeof (char *), sort_compare);
  2810. X
  2811. X/* Did we find any files matching the specification.  Yes - add them to
  2812. X * the block
  2813. X */
  2814. X
  2815. X    if (C_EList->w_nword)
  2816. X    {
  2817. X    for (i = 0; i < C_EList->w_nword; i++)
  2818. X        wb = addword (C_EList->w_words[i], wb);
  2819. X
  2820. X    DELETE (C_EList);
  2821. X    return wb;
  2822. X    }
  2823. X
  2824. X/* No - add the original word */
  2825. X
  2826. X    else
  2827. X    return addword (unquote (cp), wb);
  2828. X}
  2829. X
  2830. X/*
  2831. X * Read a directory for matches against the specified name
  2832. X */
  2833. X
  2834. Xstatic void    globname (we, pp)
  2835. Xchar        *we;            /* Start            */
  2836. Xregister char    *pp;            /* First special character    */
  2837. X{
  2838. X    register char    *np, *cp;
  2839. X    char        *name, *gp, *dp;
  2840. X    DIR            *dn;
  2841. X    struct dirent    *d_ce;
  2842. X    char        dname[NAME_MAX + 1];
  2843. X    struct stat        dbuf;
  2844. X
  2845. X/* Find the previous directory separator */
  2846. X
  2847. X    for (np = we; np != pp; pp--)
  2848. X    {
  2849. X    if (pp[-1] == '/')
  2850. X        break;
  2851. X    }
  2852. X
  2853. X/* If we don't find it, check for a drive */
  2854. X
  2855. X    if ((np == pp) && (strlen (we) > 2) && (we[1] == ':'))
  2856. X    pp += 2;
  2857. X
  2858. X/* Save copy of directory name */
  2859. X
  2860. X    for (dp = cp = space ((int)(pp - np) + 3); np < pp;)
  2861. X    *cp++ = *np++;
  2862. X
  2863. X    *cp++ = '.';
  2864. X    *cp = '\0';
  2865. X
  2866. X/* Save copy of pattern for this directory.  NP is left pointing to the
  2867. X * rest of the string for any subdirectories
  2868. X */
  2869. X
  2870. X    for (gp = cp = space (strlen (pp) + 1); *np && *np != '/';)
  2871. X    *cp++ = *np++;
  2872. X
  2873. X    *cp = '\0';
  2874. X
  2875. X/* Open the directory */
  2876. X
  2877. X    if ((dn = opendir (dp)) == (DIR *)NULL)
  2878. X    {
  2879. X    DELETE (dp);
  2880. X    DELETE (gp);
  2881. X    return;
  2882. X    }
  2883. X
  2884. X/* Scan for matches */
  2885. X
  2886. X    while ((d_ce = readdir (dn)) != (struct dirent *)NULL)
  2887. X    {
  2888. X    if ((*(strcpy (dname, d_ce->d_name)) == '.') && (*gp != '.'))
  2889. X        continue;
  2890. X
  2891. X    for (cp = dname; *cp; cp++)
  2892. X    {
  2893. X        if (any (*cp, spcl))
  2894. X        *cp |= QUOTE;
  2895. X    }
  2896. X
  2897. X/* Check for a match */
  2898. X
  2899. X    if (gmatch (dname, gp, TRUE))
  2900. X    {
  2901. X
  2902. X/* If there are no special characters in the new full name, the file must
  2903. X * exist
  2904. X */
  2905. X
  2906. X        name = generate (we, pp, dname, np);
  2907. X
  2908. X        if (*np && !anys (np, spcl))
  2909. X        {
  2910. X        if (stat (name, &dbuf))
  2911. X        {
  2912. X            DELETE (name);
  2913. X            continue;
  2914. X        }
  2915. X        }
  2916. X
  2917. X/* Ok save the name */
  2918. X
  2919. X        New_Elist = addword (name, New_Elist);
  2920. X    }
  2921. X    }
  2922. X
  2923. X    closedir (dn);
  2924. X    DELETE (dp);
  2925. X    DELETE (gp);
  2926. X}
  2927. X
  2928. X/*
  2929. X * generate a pathname as below.  start..end1 / middle end.  The slashes come
  2930. X * for free
  2931. X */
  2932. X
  2933. Xstatic char    *generate (start1, end1, middle, end)
  2934. Xchar        *start1;
  2935. Xregister char    *end1;
  2936. Xchar        *middle, *end;
  2937. X{
  2938. X    register char    *op;
  2939. X    int            clen = (int)(end1 - start1);
  2940. X
  2941. X    op = space (clen + strlen (middle) + strlen (end) + 2);
  2942. X
  2943. X    strncpy (op, start1, clen);
  2944. X    strcat (strcpy (&op[clen], middle), end);
  2945. X    return op;
  2946. X}
  2947. X
  2948. X/*
  2949. X * Scan a Word Block for special characters
  2950. X */
  2951. X
  2952. Xstatic bool    anyspcl (wb)
  2953. Xregister Word_B    *wb;
  2954. X{
  2955. X    register int    i;
  2956. X    register char    **wd = wb->w_words;
  2957. X
  2958. X    for (i = 0; i < wb->w_nword; i++)
  2959. X    {
  2960. X    if (anys (spcl, *wd++))
  2961. X        return TRUE;
  2962. X    }
  2963. X
  2964. X    return FALSE;
  2965. X}
  2966. X
  2967. X/*
  2968. X * Create a new Word Block
  2969. X */
  2970. X
  2971. Xstatic Word_B    *newword (nw)
  2972. Xregister int    nw;
  2973. X{
  2974. X    register Word_B    *wb;
  2975. X
  2976. X    wb = (Word_B *) space (sizeof (Word_B) + nw * sizeof (char *));
  2977. X    wb->w_bsize = nw;
  2978. X    wb->w_nword = 0;
  2979. X
  2980. X    return wb;
  2981. X}
  2982. X
  2983. X/*
  2984. X * Add a new word to a Word Block or list
  2985. X */
  2986. X
  2987. XWord_B        *addword (wd, wb)
  2988. Xchar        *wd;
  2989. Xregister Word_B    *wb;
  2990. X{
  2991. X    register Word_B    *wb2;
  2992. X    register int    nw;
  2993. X
  2994. X    if (wb == (Word_B *)NULL)
  2995. X    wb = newword (NSTART);
  2996. X
  2997. X/* Do we require more space ? */
  2998. X
  2999. X    if ((nw = wb->w_nword) >= wb->w_bsize)
  3000. X    {
  3001. X    wb2 = newword (nw * 2);
  3002. X    memcpy ((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
  3003. X    wb2->w_nword = nw;
  3004. X    DELETE (wb);
  3005. X    wb = wb2;
  3006. X    }
  3007. X
  3008. X/* Add to the list */
  3009. X
  3010. X    wb->w_words[wb->w_nword++] = wd;
  3011. X    return wb;
  3012. X}
  3013. X
  3014. X/*
  3015. X * Convert a word block structure into a array of strings
  3016. X */
  3017. X
  3018. Xchar        **getwords(wb)
  3019. Xregister Word_B    *wb;
  3020. X{
  3021. X    register char    **wd;
  3022. X    register nb;
  3023. X
  3024. X/* If the word block is empty or does not exist, return no list */
  3025. X
  3026. X    if (wb == (Word_B **)NULL)
  3027. X    return (char *)NULL;
  3028. X
  3029. X    if (wb->w_nword == 0)
  3030. X    {
  3031. X    DELETE (wb);
  3032. X    return (char *)NULL;
  3033. X    }
  3034. X
  3035. X/* Get some space for the array and set it up */
  3036. X
  3037. X    wd = (char **)space (nb = sizeof (char *) * wb->w_nword);
  3038. X
  3039. X    memcpy ((char *)wd, (char *)wb->w_words, nb);
  3040. X    DELETE (wb);    /* perhaps should done by caller */
  3041. X    return wd;
  3042. X}
  3043. X
  3044. X/*
  3045. X * Is any character from s1 in s2?  Return a boolean.
  3046. X */
  3047. X
  3048. Xstatic bool    anys (s1, s2)
  3049. Xregister char    *s1, *s2;
  3050. X{
  3051. X    while (*s1)
  3052. X    {
  3053. X    if (any (*(s1++), s2))
  3054. X        return TRUE;
  3055. X    }
  3056. X
  3057. X    return FALSE;
  3058. X}
  3059. X
  3060. X/*
  3061. X * Is any character from s1 in s2? Yes - return a pointer to that
  3062. X * character.
  3063. X */
  3064. X
  3065. Xstatic char    *anys_p (s1, s2)
  3066. Xregister char    *s1, *s2;
  3067. X{
  3068. X    while (*s1)
  3069. X    {
  3070. X    if (any (*(s1++), s2))
  3071. X        return --s1;
  3072. X    }
  3073. X
  3074. X    return (char *)NULL;
  3075. X}
  3076. X
  3077. X/*
  3078. X * Expansion - check for multiple drive request
  3079. X *
  3080. X * If there is a multi-drive expansion (*:, ?: or []:), we have to check
  3081. X * out each existing drive and then expand.  So we check for a multi-drive
  3082. X * condition and then for each existing drive, we check that pattern
  3083. X * against the drive and then expand the rest of the pattern.
  3084. X *
  3085. X * Otherwise, we just expand the pattern.
  3086. X */
  3087. X
  3088. Xstatic void    Glob_MDrives (pattern, start)
  3089. Xchar        *pattern;
  3090. Xchar        *start;
  3091. X{
  3092. X    unsigned int    c_drive;    /* Current drive        */
  3093. X    unsigned int    m_drive;    /* Max drive            */
  3094. X    unsigned int    s_drive;    /* Selected drive        */
  3095. X    unsigned int    x_drive, y_drive;    /* Dummies        */
  3096. X    char        *multi;        /* Multi-drive flag        */
  3097. X    static char        *t_drive = "x";
  3098. X    char        *new_pattern;
  3099. X
  3100. X/* Search all drives ? */
  3101. X
  3102. X    if ((multi = Check_Multi_Drive (pattern)) != (char *)NULL)
  3103. X    {
  3104. X    _dos_getdrive (&c_drive);    /* Get number of drives        */
  3105. X    _dos_setdrive (c_drive, &m_drive);
  3106. X    new_pattern = space (strlen (multi) + 2);
  3107. X
  3108. X    strcpy (new_pattern + 1, multi);
  3109. X    *multi = 0;
  3110. X
  3111. X    for (s_drive = 1; s_drive <= m_drive; ++s_drive)
  3112. X    {
  3113. X        _dos_setdrive (s_drive, &x_drive);
  3114. X        _dos_getdrive (&y_drive);
  3115. X        _dos_setdrive (c_drive, &x_drive);
  3116. X
  3117. X/* Check to see if the second diskette drive is really there */
  3118. X
  3119. X        if (((_bios_equiplist () & 0x00c0) == 0x0000) && (s_drive == 2))
  3120. X        continue;
  3121. X
  3122. X/* If the drive exists and is in our list - process it */
  3123. X
  3124. X        *t_drive = (char)(s_drive + 'a' - 1);
  3125. X
  3126. X        if ((y_drive == s_drive) && gmatch (t_drive, pattern, TRUE))
  3127. X        {
  3128. X        *new_pattern = *t_drive;
  3129. X        globname (new_pattern, &new_pattern[2]);
  3130. X        }
  3131. X    }
  3132. X
  3133. X/* Restore and delete space */
  3134. X
  3135. X    *multi = ':';
  3136. X    DELETE (new_pattern);
  3137. X    }
  3138. X
  3139. X/* No drive specifier - just check it out */
  3140. X
  3141. X    else
  3142. X    globname (pattern, start);
  3143. X}
  3144. X
  3145. X/*
  3146. X * Check for multi_drive prefix - *:, ?: or []:
  3147. X *
  3148. X * Return NULL or the address of the colon character
  3149. X */
  3150. X
  3151. Xstatic char    *Check_Multi_Drive (pattern)
  3152. Xchar        *pattern;
  3153. X{
  3154. X    if (strlen (pattern) < 3)
  3155. X    return (char *)NULL;
  3156. X
  3157. X    if (((*pattern == '*') || (*pattern == '?')) && (pattern[1] == ':'))
  3158. X    return pattern + 1;
  3159. X
  3160. X    if (*pattern != '[')
  3161. X    return (char *)NULL;
  3162. X
  3163. X    while (*pattern && (*pattern != ']'))
  3164. X    {
  3165. X    if ((*pattern == '\\') && (*(pattern + 1)))
  3166. X        ++pattern;
  3167. X
  3168. X    ++pattern;
  3169. X    }
  3170. X
  3171. X    return (*pattern && (*(pattern + 1) == ':')) ? pattern + 1 : (char *)NULL;
  3172. X}
  3173. SHAR_EOF
  3174. chmod 0644 shell/sh4.c || echo "restore of shell/sh4.c fails"
  3175. set `wc -c shell/sh4.c`;Sum=$1
  3176. if test "$Sum" != "20630"
  3177. then echo original size 20630, current size $Sum;fi
  3178. echo "x - extracting shell/sh5.c (Text)"
  3179. sed 's/^X//' << 'SHAR_EOF' > shell/sh5.c &&
  3180. X/* MS-DOS SHELL - Main I/O Functions
  3181. X *
  3182. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  3183. X *
  3184. X * This code is based on (in part) the shell program written by Charles
  3185. X * Forsyth and is subject to the following copyright restrictions:
  3186. X *
  3187. X * 1.  Redistribution and use in source and binary forms are permitted
  3188. X *     provided that the above copyright notice is duplicated in the
  3189. X *     source form and the copyright notice in file sh6.c is displayed
  3190. X *     on entry to the program.
  3191. X *
  3192. X * 2.  The sources (or parts thereof) or objects generated from the sources
  3193. X *     (or parts of sources) cannot be sold under any circumstances.
  3194. X *
  3195. X *    $Header: sh5.c 1.1 90/01/25 13:41:50 MS_user Exp $
  3196. X *
  3197. X *    $Log:    sh5.c $
  3198. X * Revision 1.1  90/01/25  13:41:50  MS_user
  3199. X * Initial revision
  3200. X * 
  3201. X */
  3202. X
  3203. X#include <sys/types.h>
  3204. X#include <stdio.h>
  3205. X#include <signal.h>
  3206. X#include <errno.h>
  3207. X#include <setjmp.h>
  3208. X#include <stdlib.h>
  3209. X#include <string.h>
  3210. X#include <fcntl.h>
  3211. X#include <io.h>
  3212. X#include <limits.h>
  3213. X#include <unistd.h>
  3214. X#include "sh.h"
  3215. X
  3216. X/*
  3217. X * shell IO
  3218. X */
  3219. X
  3220. Xstatic IO_Buf        sharedbuf = {AFID_NOBUF};
  3221. Xstatic IO_Buf        mainbuf = {AFID_NOBUF};
  3222. Xstatic unsigned int    bufid = AFID_ID;    /* buffer id counter */
  3223. X                    /* list of hear docs while parsing */
  3224. Xstatic Here_D    *inhere = (Here_D *)NULL;
  3225. X                    /* list of active here documents */
  3226. Xstatic Here_D    *acthere = (Here_D *)NULL;
  3227. X
  3228. Xstatic int    dol1_char (IO_State *);
  3229. Xstatic void    readhere (char **, char *, int);
  3230. Xstatic int    herechar (IO_State *);
  3231. X
  3232. Xint        Getc (ec)
  3233. Xregister int    ec;
  3234. X{
  3235. X    register int    c;
  3236. X
  3237. X    if (e.linep > e.eline)
  3238. X    {
  3239. X    while (((c = readc ()) != NL) && c)
  3240. X        ;
  3241. X
  3242. X    print_error ("sh: input line too long\n");
  3243. X    gflg++;
  3244. X    return c;
  3245. X    }
  3246. X
  3247. X    c = readc();
  3248. X    if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE))
  3249. X    {
  3250. X    if (c == '\\')
  3251. X    {
  3252. X        if (((c = readc ()) == NL) && (ec != '\"'))
  3253. X        return Getc (ec);
  3254. X
  3255. X        c |= QUOTE;
  3256. X    }
  3257. X    }
  3258. X
  3259. X    return c;
  3260. X}
  3261. X
  3262. Xvoid    unget (c)
  3263. Xint    c;
  3264. X{
  3265. X    if (e.iop >= e.iobase)
  3266. X    e.iop->peekc = c;
  3267. X}
  3268. X
  3269. Xint    eofc ()
  3270. X{
  3271. X    return (e.iop < e.iobase) || ((e.iop->peekc == 0) && (e.iop->prev == 0));
  3272. X}
  3273. X
  3274. X/* Read the next character */
  3275. X
  3276. Xint    readc ()
  3277. X{
  3278. X    register int    c;
  3279. X    char        s_dflag = e.iop->dflag;
  3280. X
  3281. X/* The dflag is transfered from the higher level to the lower level at end
  3282. X * of input at the higher level.  This is part of the implementation of
  3283. X * $* and $@ processing.
  3284. X */
  3285. X
  3286. X    for (; e.iop >= e.iobase; e.iop--)
  3287. X    {
  3288. X
  3289. X/* Set up the current dflag */
  3290. X
  3291. X    e.iop->dflag = s_dflag;
  3292. X
  3293. X/* If there is an unget character, use it */
  3294. X
  3295. X    if ((c = e.iop->peekc) != '\0')
  3296. X    {
  3297. X        e.iop->peekc = 0;
  3298. X        return c;
  3299. X    }
  3300. X
  3301. X/* Some special processing for multi-line commands */
  3302. X
  3303. X    else
  3304. X    {
  3305. X        if (e.iop->prev != 0)
  3306. X        {
  3307. X
  3308. X/* Get the next character from the IO function */
  3309. X
  3310. X        if ((c = (*e.iop->iofn)(e.iop)) != '\0')
  3311. X        {
  3312. X
  3313. X/* End of current level, but continue at this level as another read
  3314. X * function has been put on the stack
  3315. X */
  3316. X
  3317. X            if (c == -1)
  3318. X            {
  3319. X            e.iop++;
  3320. X            continue;
  3321. X            }
  3322. X
  3323. X/* If we are at the bottom - echo the character */
  3324. X
  3325. X            if ((e.iop == iostack) && (FL_TEST ('v')))
  3326. X            S_putc ((char)c);
  3327. X
  3328. X/* Return the current character */
  3329. X
  3330. X            return (e.iop->prev = (char)c);
  3331. X        }
  3332. X
  3333. X        else if (e.iop->task == XIO && e.iop->prev != NL)
  3334. X        {
  3335. X            e.iop->prev = 0;
  3336. X
  3337. X            if ((e.iop == iostack) && (FL_TEST ('v')))
  3338. X            S_putc (NL);
  3339. X
  3340. X            return NL;
  3341. X        }
  3342. X
  3343. X        else
  3344. X            s_dflag = e.iop->dflag;
  3345. X        }
  3346. X
  3347. X        if (e.iop->task == XIO)
  3348. X        {
  3349. X        if (multiline)
  3350. X            return e.iop->prev = 0;
  3351. X
  3352. X        if (talking && e.iop == iostack + 1)
  3353. X            put_prompt (ps1->value);
  3354. X        }
  3355. X    }
  3356. X    }
  3357. X
  3358. X    if (e.iop >= iostack)
  3359. X    return 0;
  3360. X
  3361. X    leave();
  3362. X    /* NOTREACHED */
  3363. X}
  3364. X
  3365. X/* Add an Input channel to the input stack */
  3366. X
  3367. Xvoid        pushio (argp, fn)
  3368. XIO_Args        *argp;
  3369. Xint        (*fn)(IO_State *);
  3370. X{
  3371. X    if (++e.iop >= &iostack[NPUSH])
  3372. X    {
  3373. X    e.iop--;
  3374. X    print_error ("sh: Shell input nested too deeply\n");
  3375. X    gflg++;
  3376. X    return;
  3377. X    }
  3378. X
  3379. X    e.iop->iofn = fn;
  3380. X
  3381. X    if (argp->afid != AFID_NOBUF)
  3382. X    e.iop->argp = argp;
  3383. X
  3384. X    else
  3385. X    {
  3386. X    e.iop->argp  = ioargstack + (e.iop - iostack);
  3387. X    *e.iop->argp = *argp;
  3388. X    e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
  3389. X
  3390. X    if ((isatty (e.iop->argp->afile) == 0) &&
  3391. X        ((e.iop == &iostack[0]) ||
  3392. X         (lseek (e.iop->argp->afile, 0L, 1) != -1L)))
  3393. X    {
  3394. X        if (++bufid == AFID_NOBUF)
  3395. X        bufid = AFID_ID;
  3396. X
  3397. X        e.iop->argp->afid  = bufid;
  3398. X    }
  3399. X    }
  3400. X
  3401. X    e.iop->prev  = ~NL;
  3402. X    e.iop->peekc = 0;
  3403. X    e.iop->xchar = 0;
  3404. X    e.iop->nlcount = 0;
  3405. X
  3406. X    if ((fn == filechar) || (fn == linechar))
  3407. X    e.iop->task = XIO;
  3408. X
  3409. X    else if ((fn == gravechar) || (fn == qgravechar))
  3410. X    e.iop->task = XGRAVE;
  3411. X
  3412. X    else
  3413. X    e.iop->task = XOTHER;
  3414. X}
  3415. X
  3416. X/*
  3417. X * Input generating functions
  3418. X */
  3419. X
  3420. X/*
  3421. X * Produce the characters of a string, then a newline, then EOF.
  3422. X */
  3423. Xint            nlchar (iop)
  3424. Xregister IO_State    *iop;
  3425. X{
  3426. X    register int    c;
  3427. X
  3428. X    if (iop->argp->aword == (char *)NULL)
  3429. X    return 0;
  3430. X
  3431. X    if ((c = *iop->argp->aword++) == 0)
  3432. X    {
  3433. X    iop->argp->aword = (char *)NULL;
  3434. X    return NL;
  3435. X    }
  3436. X
  3437. X    return c;
  3438. X}
  3439. X
  3440. X/*
  3441. X * Given a list of words, produce the characters
  3442. X * in them, with a space after each word.
  3443. X */
  3444. X
  3445. Xint            wdchar (iop)
  3446. Xregister IO_State    *iop;
  3447. X{
  3448. X    register char    c;
  3449. X    register char    **wl;
  3450. X
  3451. X    if ((wl = iop->argp->awordlist) == (char **)NULL)
  3452. X    return 0;
  3453. X
  3454. X    if (*wl != (char *)NULL)
  3455. X    {
  3456. X    if ((c = *(*wl)++) != 0)
  3457. X        return (c & 0177);
  3458. X
  3459. X    iop->argp->awordlist++;
  3460. X    return SP;
  3461. X    }
  3462. X
  3463. X    iop->argp->awordlist = (char **)NULL;
  3464. X    return NL;
  3465. X}
  3466. X
  3467. X/*
  3468. X * Return the characters of a list of words, producing a space between them.
  3469. X */
  3470. X
  3471. Xint            dol_char (iop)
  3472. XIO_State        *iop;
  3473. X{
  3474. X    register char    *wp;
  3475. X    char        cflag;
  3476. X
  3477. X    if ((wp = *(iop->argp->awordlist)++) != (char *)NULL)
  3478. X    {
  3479. X    if (*iop->argp->awordlist == (char *)NULL)
  3480. X        iop->dflag |= DSA_END;
  3481. X
  3482. X    cflag = iop->dflag;
  3483. X    PUSHIO (aword, wp, dol1_char);
  3484. X    e.iop->dflag = cflag;
  3485. X    return -1;
  3486. X    }
  3487. X
  3488. X    return 0;
  3489. X}
  3490. X
  3491. X/* Return next character from the word with a space at the end */
  3492. X
  3493. Xstatic int        dol1_char (iop)
  3494. XIO_State        *iop;
  3495. X{
  3496. X    register int c;
  3497. X
  3498. X    if ((iop->dflag & DSA_MODE) == DSA_AMP)
  3499. X    {
  3500. X    if (!(iop->dflag & DSA_START))
  3501. X        iop->dflag |= DSA_START;
  3502. X
  3503. X/* Has the previous word ended */
  3504. X
  3505. X    else if (iop->dflag & DSA_START1)
  3506. X    {
  3507. X        iop->dflag &= ~DSA_START1;
  3508. X        return '"';
  3509. X    }
  3510. X    }
  3511. X
  3512. X    if (iop->argp->aword == (char *)NULL)
  3513. X    return 0;
  3514. X
  3515. X    if ((c = *iop->argp->aword) == '\0')
  3516. X    {
  3517. X    if ((iop->dflag & DSA_MODE) != DSA_AMP)
  3518. X    {
  3519. X        iop->argp->aword = (char *)NULL;
  3520. X        return (iop->dflag & DSA_END) ? 0 : SP;
  3521. X    }
  3522. X
  3523. X    if (!(iop->dflag & DSA_END1))
  3524. X    {
  3525. X        iop->dflag |= DSA_END1;
  3526. X        return '"';
  3527. X    }
  3528. X
  3529. X    iop->argp->aword = (char *)NULL;
  3530. X    iop->dflag &= ~DSA_END1;
  3531. X    iop->dflag |= DSA_START1;
  3532. X    return (iop->dflag & DSA_END) ? 0 : SP;
  3533. X    }
  3534. X
  3535. X    iop->argp->aword++;
  3536. X    if ((iop->dflag != DSA_NULL) && any ((char)c, ifs->value))
  3537. X    c |= QUOTE;
  3538. X
  3539. X    return c;
  3540. X}
  3541. X
  3542. X/*
  3543. X * Produce the characters from a single word (string).
  3544. X */
  3545. X
  3546. Xint        strchar (iop)
  3547. XIO_State    *iop;
  3548. X{
  3549. X    register int    c;
  3550. X
  3551. X    return ((iop->argp->aword == (char *)NULL) ||
  3552. X        ((c = *(iop->argp->aword++)) == 0)) ? 0 : c;
  3553. X}
  3554. X
  3555. X/*
  3556. X * Produce quoted characters from a single word (string).
  3557. X */
  3558. X
  3559. Xint        qstrchar (iop)
  3560. XIO_State    *iop;
  3561. X{
  3562. X    register int    c;
  3563. X
  3564. X    return ((iop->argp->aword == (char *)NULL) ||
  3565. X        ((c = *(iop->argp->aword++)) == 0)) ? 0 : (c | QUOTE);
  3566. X}
  3567. X
  3568. X/*
  3569. X * Return the characters from a file.
  3570. X */
  3571. X
  3572. Xint        filechar (iop)
  3573. XIO_State    *iop;
  3574. X{
  3575. X    register IO_Args    *ap = iop->argp;
  3576. X    register int    i;
  3577. X    char        c;
  3578. X    IO_Buf        *bp = ap->afbuf;
  3579. X
  3580. X    if (ap->afid != AFID_NOBUF)
  3581. X    {
  3582. X    if ((i = (ap->afid != bp->id)) || (bp->bufp == bp->ebufp))
  3583. X    {
  3584. X        if (i)
  3585. X        lseek (ap->afile, ap->afpos, SEEK_SET);
  3586. X
  3587. X        if ((i = read (ap->afile, bp->buf, sizeof (bp->buf))) <= 0)
  3588. X        {
  3589. X        if (ap->afile > STDERR_FILENO)
  3590. X            S_close (ap->afile, TRUE);
  3591. X
  3592. X        return 0;
  3593. X        }
  3594. X
  3595. X        bp->id = ap->afid;
  3596. X        bp->ebufp = (bp->bufp  = bp->buf) + i;
  3597. X    }
  3598. X
  3599. X    ap->afpos++;
  3600. X
  3601. X    return *bp->bufp++ & 0177;
  3602. X    }
  3603. X
  3604. X/* If this is the terminal, there is special input processing */
  3605. X
  3606. X    else if ((ap->afile == 0) && isatty (ap->afile))
  3607. X        return Get_stdin (ap);
  3608. X
  3609. X    if ((i = read (ap->afile, &c, sizeof(c))) == sizeof (c))
  3610. X    return (int)c & 0177;
  3611. X
  3612. X    if (ap->afile > STDERR_FILENO)
  3613. X    S_close (ap->afile, TRUE);
  3614. X
  3615. X    return 0;
  3616. X}
  3617. X
  3618. X/*
  3619. X * Return the characters from a here temp file.
  3620. X */
  3621. X
  3622. Xstatic int        herechar (iop)
  3623. Xregister IO_State    *iop;
  3624. X{
  3625. X    char            c;
  3626. X
  3627. X    if (read (iop->argp->afile, &c, sizeof(c)) != sizeof(c))
  3628. X    {
  3629. X    S_close (iop->argp->afile, TRUE);
  3630. X    c = 0;
  3631. X    }
  3632. X
  3633. X    return c;
  3634. X}
  3635. X
  3636. X/*
  3637. X * Return the characters produced by a process (`...`).
  3638. X * Quote them if required, and remove any trailing newline characters.
  3639. X */
  3640. X
  3641. Xint        gravechar (iop)
  3642. XIO_State    *iop;
  3643. X{
  3644. X    register int c;
  3645. X
  3646. X    if ((c = qgravechar (iop) & ~QUOTE) == NL)
  3647. X    c = SP;
  3648. X
  3649. X    return c;
  3650. X}
  3651. X
  3652. X/*
  3653. X * Process input from a `...` string
  3654. X */
  3655. X
  3656. Xint        qgravechar (iop)
  3657. XIO_State    *iop;
  3658. X{
  3659. X    register int    c;
  3660. X
  3661. X    if (iop->xchar)
  3662. X    {
  3663. X    if (iop->nlcount)
  3664. X    {
  3665. X        iop->nlcount--;
  3666. X        return (NL | QUOTE);
  3667. X    }
  3668. X
  3669. X    c = iop->xchar;
  3670. X    iop->xchar = 0;
  3671. X    }
  3672. X
  3673. X    else if ((c = filechar (iop)) == NL)
  3674. X    {
  3675. X    iop->nlcount = 1;
  3676. X
  3677. X    while ((c = filechar (iop)) == NL)
  3678. X        iop->nlcount++;
  3679. X
  3680. X    iop->xchar = (char)c;
  3681. X
  3682. X    if (c == 0)
  3683. X        return(c);
  3684. X
  3685. X    iop->nlcount--;
  3686. X    c = NL;
  3687. X    }
  3688. X
  3689. X    return (c != 0) ? (c | QUOTE): 0;
  3690. X}
  3691. X
  3692. X/*
  3693. X * Return a single command (usually the first line) from a file.
  3694. X */
  3695. X
  3696. Xint        linechar (iop)
  3697. XIO_State    *iop;
  3698. X{
  3699. X    register int    c;
  3700. X
  3701. X    if ((c = filechar (iop)) == NL)
  3702. X    {
  3703. X    if (!multiline)
  3704. X    {
  3705. X        if (iop->argp->afile > STDERR_FILENO)
  3706. X        S_close (iop->argp->afile, TRUE);
  3707. X
  3708. X        iop->argp->afile = -1;    /* illegal value */
  3709. X    }
  3710. X    }
  3711. X
  3712. X    return c;
  3713. X}
  3714. X
  3715. Xvoid    closeall ()
  3716. X{
  3717. X    register int    u;
  3718. X
  3719. X    for (u = NUFILE; u < NOFILE;)
  3720. X    S_close (u++, TRUE);
  3721. X}
  3722. X
  3723. X/*
  3724. X * remap fd into Shell's fd space
  3725. X */
  3726. X
  3727. Xint        remap (fd)
  3728. Xregister int    fd;
  3729. X{
  3730. X    register int    i;
  3731. X    register int    n_io = 0;
  3732. X    int            map[NOFILE];
  3733. X    int            o_fd = fd;
  3734. X
  3735. X    if (fd < e.iofd)
  3736. X    {
  3737. X    do
  3738. X    {
  3739. X        map[n_io++] = fd;
  3740. X        fd = dup (fd);
  3741. X
  3742. X    } while ((fd >= 0) && (fd < e.iofd));
  3743. X
  3744. X    for (i = 0; i < n_io; i++)
  3745. X        close (map[i]);
  3746. X
  3747. X    S_Remap (o_fd, fd);
  3748. X    S_close (o_fd, TRUE);
  3749. X
  3750. X    if (fd < 0)
  3751. X        print_error ("sh: too many files open\n");
  3752. X    }
  3753. X
  3754. X    return fd;
  3755. X}
  3756. X
  3757. X/*
  3758. X * here documents
  3759. X */
  3760. X
  3761. Xvoid        markhere (s, iop)
  3762. Xregister char    *s;
  3763. XIO_Actions     *iop;
  3764. X{
  3765. X    register Here_D    *h, *lh;
  3766. X
  3767. X    if ((h = (Here_D *) space(sizeof(Here_D))) == (Here_D *)NULL)
  3768. X    return;
  3769. X
  3770. X    if ((h->h_tag = evalstr (s, DOSUB)) == (char *)NULL)
  3771. X    return;
  3772. X
  3773. X    h->h_iop     = iop;
  3774. X    iop->io_name = (char *)NULL;
  3775. X    h->h_next    = (Here_D *)NULL;
  3776. X
  3777. X    if (inhere == (Here_D *)NULL)
  3778. X    inhere = h;
  3779. X
  3780. X    else
  3781. X    {
  3782. X    for (lh = inhere; lh != (Here_D *)NULL; lh = lh->h_next)
  3783. X    {
  3784. X        if (lh->h_next == (Here_D *)NULL)
  3785. X        {
  3786. X        lh->h_next = h;
  3787. X        break;
  3788. X        }
  3789. X    }
  3790. X    }
  3791. X
  3792. X    iop->io_flag |= IOHERE|IOXHERE;
  3793. X
  3794. X    for (s = h->h_tag; *s; s++)
  3795. X    {
  3796. X    if (*s & QUOTE)
  3797. X    {
  3798. X        iop->io_flag &= ~ IOXHERE;
  3799. X        *s &= ~ QUOTE;
  3800. X    }
  3801. X    }
  3802. X
  3803. X    h->h_dosub = iop->io_flag & IOXHERE;
  3804. X}
  3805. X
  3806. Xvoid    gethere ()
  3807. X{
  3808. X    register Here_D    *h, *hp;
  3809. X
  3810. X/* Scan here files first leaving inhere list in place */
  3811. X
  3812. X    for (hp = h = inhere; h != (Here_D *)NULL; hp = h, h = h->h_next)
  3813. X    readhere (&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
  3814. X
  3815. X/* Make inhere list active - keep list intact for scraphere */
  3816. X
  3817. X    if (hp != (Here_D *)NULL)
  3818. X    {
  3819. X    hp->h_next = acthere;
  3820. X    acthere    = inhere;
  3821. X    inhere     = (Here_D *)NULL;
  3822. X    }
  3823. X}
  3824. X
  3825. Xstatic void    readhere (name, s, ec)
  3826. Xchar        **name;
  3827. Xregister char    *s;
  3828. X{
  3829. X    int            tf;
  3830. X    register int    c;
  3831. X    jmp_buf        ev;
  3832. X    char        *line;
  3833. X    char        *next;
  3834. X
  3835. X    *name = strsave (g_tempname (), areanum);
  3836. X
  3837. X    if ((tf = S_open (FALSE, *name, O_CMASK | O_NOINHERIT, 0600)) < 0)
  3838. X    return;
  3839. X
  3840. X    if (newenv (setjmp (errpt = ev)) == TRUE)
  3841. X    S_Delete (tf);
  3842. X
  3843. X    else
  3844. X    {
  3845. X    line = space (LINE_MAX + 1);
  3846. X    pushio (e.iop->argp, e.iop->iofn);
  3847. X    e.iobase = e.iop;
  3848. X
  3849. X    while (1)
  3850. X    {
  3851. X        if (talking && e.iop <= iostack)
  3852. X        put_prompt (ps2->value);
  3853. X
  3854. X        next = line;
  3855. X        while ((c = Getc (ec)) != NL && c)
  3856. X        {
  3857. X        if (ec == '\'')
  3858. X            c &= ~ QUOTE;
  3859. X
  3860. X        if (next >= &line[LINE_MAX])
  3861. X        {
  3862. X            c = 0;
  3863. X            break;
  3864. X        }
  3865. X
  3866. X        *next++ = (char)c;
  3867. X        }
  3868. X
  3869. X        *next = 0;
  3870. X        if (strcmp (s, line) == 0 || c == 0)
  3871. X        break;
  3872. X
  3873. X        *next++ = NL;
  3874. X        write (tf, line, (int)(next-line));
  3875. X    }
  3876. X
  3877. X    if (c == 0)
  3878. X        print_error ("here document `%s' unclosed\n", s);
  3879. X
  3880. X    quitenv ();
  3881. X    }
  3882. X
  3883. X    S_close (tf, TRUE);
  3884. X}
  3885. X
  3886. X/*
  3887. X * open here temp file.
  3888. X * If unquoted here, expand here temp file into second temp file.
  3889. X */
  3890. X
  3891. Xint        herein (hname, xdoll)
  3892. Xchar        *hname;
  3893. Xint        xdoll;
  3894. X{
  3895. X    register int    hf, tf;
  3896. X
  3897. X    if (hname == (char *)NULL)
  3898. X    return -1;
  3899. X
  3900. X    if ((hf = S_open (FALSE, hname, O_RDONLY)) < 0)
  3901. X    return -1;
  3902. X
  3903. X    if (xdoll)
  3904. X    {
  3905. X    char        c;
  3906. X    char        *tname = g_tempname();
  3907. X    jmp_buf        ev;
  3908. X
  3909. X    if ((tf = S_open (FALSE, tname, O_CMASK | O_NOINHERIT, 0600)) < 0)
  3910. X        return -1;
  3911. X
  3912. X    if (newenv (setjmp (errpt = ev)) == FALSE)
  3913. X    {
  3914. X        PUSHIO (afile, hf, herechar);
  3915. X        e.iobase = e.iop;
  3916. X
  3917. X        while ((c = (char)subgetc(0, 0)) != 0)
  3918. X        {
  3919. X        c &= ~ QUOTE;
  3920. X        write (tf, &c, sizeof c);
  3921. X        }
  3922. X
  3923. X        quitenv ();
  3924. X    }
  3925. X
  3926. X    else
  3927. X        S_Delete (tf);
  3928. X
  3929. X    S_close (tf, TRUE);
  3930. X    return S_open (TRUE, tname, O_RDONLY);
  3931. X    }
  3932. X
  3933. X    else
  3934. X    return hf;
  3935. X}
  3936. X
  3937. Xvoid    scraphere()
  3938. X{
  3939. X    register Here_D    *h;
  3940. X
  3941. X    for (h = inhere; h != (Here_D *)NULL; h = h->h_next)
  3942. X    {
  3943. X    if ((h->h_iop != (IO_Actions *)NULL) &&
  3944. X        (h->h_iop->io_name != (char *)NULL))
  3945. X        unlink (h->h_iop->io_name);
  3946. X    }
  3947. X
  3948. X    inhere = (Here_D *)NULL;
  3949. X}
  3950. X
  3951. X/* unlink here temp files before a freearea (area) */
  3952. X
  3953. Xvoid    freehere (area)
  3954. Xint    area;
  3955. X{
  3956. X    register Here_D    *h;
  3957. X    register Here_D    *hl = (Here_D *)NULL;
  3958. X
  3959. X    for (h = acthere; h != (Here_D *)NULL; hl = h, h = h->h_next)
  3960. X    {
  3961. X    if (getarea ((char *)h) >= area)
  3962. X    {
  3963. X        if (h->h_iop->io_name != (char *)NULL)
  3964. X        unlink (h->h_iop->io_name);
  3965. X
  3966. X        if (hl == (Here_D *)NULL)
  3967. X        acthere = h->h_next;
  3968. X
  3969. X        else
  3970. X        hl->h_next = h->h_next;
  3971. X    }
  3972. X    }
  3973. X}
  3974. X
  3975. Xchar    *g_tempname ()
  3976. X{
  3977. X    static char    tmpfile[FFNAME_MAX];
  3978. X    char    *tmpdir;    /* Points to directory prefix of pipe    */
  3979. X    static int    temp_count = 0;
  3980. X
  3981. X/* Find out where we should put temporary files */
  3982. X
  3983. X    if ((tmpdir = lookup ("TMPDIR", FALSE)->value) == null)
  3984. X    tmpdir = lookup ("TMP", FALSE)->value;
  3985. X
  3986. X/* Get a unique temporary file name */
  3987. X
  3988. X    while (1)
  3989. X    {
  3990. X    sprintf (tmpfile, "%s/sht%.5u.tmp", tmpdir, temp_count++);
  3991. X
  3992. X    if (access (tmpfile, F_OK) != 0)
  3993. X        break;
  3994. X    }
  3995. X
  3996. X    return tmpfile;
  3997. X}
  3998. SHAR_EOF
  3999. chmod 0644 shell/sh5.c || echo "restore of shell/sh5.c fails"
  4000. set `wc -c shell/sh5.c`;Sum=$1
  4001. if test "$Sum" != "14249"
  4002. then echo original size 14249, current size $Sum;fi
  4003. echo "x - extracting shell/sh6.c (Text)"
  4004. sed 's/^X//' << 'SHAR_EOF' > shell/sh6.c &&
  4005. X/* MS-DOS SHELL - Data Declarations
  4006. X *
  4007. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  4008. X *
  4009. X * This code is based on (in part) the shell program written by Charles
  4010. X * Forsyth and is subject to the following copyright restrictions:
  4011. X *
  4012. X * 1.  Redistribution and use in source and binary forms are permitted
  4013. X *     provided that the above copyright notice is duplicated in the
  4014. X *     source form and the copyright notice in file sh6.c is displayed
  4015. X *     on entry to the program.
  4016. X *
  4017. X * 2.  The sources (or parts thereof) or objects generated from the sources
  4018. X *     (or parts of sources) cannot be sold under any circumstances.
  4019. X *
  4020. X *    $Header: sh6.c 1.1 90/01/25 13:42:04 MS_user Exp $
  4021. X *
  4022. X *    $Log:    sh6.c $
  4023. X * Revision 1.1  90/01/25  13:42:04  MS_user
  4024. X * Initial revision
  4025. X * 
  4026. X */
  4027. X
  4028. X#include <sys/types.h>
  4029. X#include <stddef.h>
  4030. X#include <signal.h>
  4031. X#include <errno.h>
  4032. X#include <setjmp.h>
  4033. X#include <stdlib.h>
  4034. X#include <limits.h>
  4035. X#include <unistd.h>
  4036. X#include "sh.h"
  4037. X
  4038. Xchar        *Copy_Right1 = "MS-DOS SH Version 1.4\341 (DOS %d.%d)\n";
  4039. Xchar        *Copy_Right2 = "Copyright (c) Data Logic Ltd and Charles Forsyth 1990\n";
  4040. Xchar        **dolv;        /* Parameter array            */
  4041. Xint        dolc;        /* Number of entries in parameter array    */
  4042. Xint        exstat;        /* Exit status                */
  4043. Xchar        gflg;
  4044. Xint        fn_area_number = -1;    /* Next function area number    */
  4045. Xint        talking;    /* interactive (talking-type wireless)    */
  4046. Xint        execflg;    /* Exec mode                */
  4047. Xint        multiline;    /* \n changed to ;            */
  4048. Xint        Current_Event = 0;    /* Current history event    */
  4049. Xint        *failpt;    /* Current fail point jump address    */
  4050. Xint        *errpt;        /* Current error point jump address    */
  4051. X                /* Swap mode                */
  4052. Xint        Swap_Mode = SWAP_EXPAND | SWAP_DISK;
  4053. XBreak_C        *Break_List;    /* Break list for FOR/WHILE        */
  4054. XBreak_C        *Return_List;    /* Return list for RETURN        */
  4055. XBreak_C        *SShell_List;    /* SubShell list for EXIT        */
  4056. Xbool        level0 = FALSE;    /* Level Zero flag            */
  4057. Xbool        r_flag = FALSE;    /* Restricted shell            */
  4058. X                /* History processing enabled flag    */
  4059. Xbool        History_Enabled = FALSE;
  4060. XFun_Ops        *fun_list = (Fun_Ops *)NULL;    /* Function list    */
  4061. XSave_IO        *SSave_IO;    /* Save IO array            */
  4062. Xint        NSave_IO_E = 0;    /* Number of entries in Save IO array    */
  4063. Xint        MSave_IO_E = 0;    /* Max Number of entries in SSave_IO    */
  4064. XS_SubShell    *SubShells;    /* Save Vars array            */
  4065. Xint        NSubShells = 0;    /* Number of entries in SubShells    */
  4066. Xint        MSubShells = 0;    /* Max Number of entries in SubShells    */
  4067. X
  4068. XWord_B        *wdlist;    /* Current Word List            */
  4069. XWord_B        *iolist;    /* Current IO List            */
  4070. Xlong        ourtrap = 0L;    /* Signal detected            */
  4071. Xint        trapset;    /* Trap pending                */
  4072. Xint        yynerrs;    /* yacc errors detected            */
  4073. Xint        Execute_stack_depth;    /* execute function recursion    */
  4074. X                    /* depth            */
  4075. XVar_List    *vlist = (Var_List *)NULL;    /* dictionary        */
  4076. SHAR_EOF
  4077. echo "End of part 3"
  4078. echo "File shell/sh6.c is continued in part 4"
  4079. echo "4" > s2_seq_.tmp
  4080. exit 0
  4081.  
  4082. -- 
  4083. Regards,
  4084.  
  4085. Ian Stewartson
  4086. Data Logic Ltd.
  4087.  
  4088.  
  4089.