home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume10 / sh_dos / part04 < prev    next >
Encoding:
Text File  |  1990-02-13  |  79.6 KB  |  4,097 lines

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