home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume23 / rc / part02 < prev    next >
Text File  |  1991-10-18  |  57KB  |  2,566 lines

  1. Newsgroups: comp.sources.misc
  2. From: byron@archone.tamu.edu (Byron Rakitzis)
  3. Subject:  v23i062:  rc - A Plan 9 shell reimplementation, v1.2, Part02/06
  4. Message-ID: <1991Oct18.034306.2126@sparky.imd.sterling.com>
  5. X-Md4-Signature: e40b03bf1de892a0f76ae6f7a5d1c497
  6. Date: Fri, 18 Oct 1991 03:43:06 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
  10. Posting-number: Volume 23, Issue 62
  11. Archive-name: rc/part02
  12. Environment: UNIX
  13. Supersedes: rc: Volume 20, Issue 10-13
  14.  
  15. #!/bin/sh
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file execve.c continued
  18. #
  19. if test ! -r _shar_seq_.tmp; then
  20.     echo 'Please unpack part 1 first!'
  21.     exit 1
  22. fi
  23. (read Scheck
  24.  if test "$Scheck" != 2; then
  25.     echo Please unpack part "$Scheck" next!
  26.     exit 1
  27.  else
  28.     exit 0
  29.  fi
  30. ) < _shar_seq_.tmp || exit 1
  31. if test ! -f _shar_wnt_.tmp; then
  32.     echo 'x - still skipping execve.c'
  33. else
  34. echo 'x - continuing file execve.c'
  35. sed 's/^X//' << 'SHAR_EOF' >> 'execve.c' &&
  36. X
  37. /*
  38. X   NOTE: this file depends on a hack in footobar.c which places two free spots before
  39. X   av[][] so that execve does not have to call malloc.
  40. */
  41. X
  42. #include "rc.h"
  43. #include <errno.h>
  44. #include "lex.h"
  45. #include "open.h"
  46. X
  47. #define giveupif(x) { if (x) goto fail; }
  48. X
  49. int my_execve(const char *path, const char **av, const char **ev) {
  50. X    int fd, len, fst, snd, end;
  51. X    boolean noarg;
  52. X    char pb[256]; /* arbitrary but generous limit */
  53. X
  54. X    execve(path, av, ev);
  55. X
  56. X    if (errno != ENOEXEC)
  57. X        return -1;
  58. X
  59. X    fd = rc_open(path, FROM);
  60. X
  61. X    giveupif(fd < 0);
  62. X
  63. X    len = read(fd, pb, sizeof pb);
  64. X    close(fd);
  65. X
  66. X    /*
  67. X       This execve() rejects all scripts which don't begin with #!
  68. X       This may have to be changed on some systems.
  69. X    */
  70. X
  71. X    giveupif(len <= 0 || pb[0] != '#' || pb[1] != '!');
  72. X
  73. X    for (fst = 2; fst < len && (pb[fst] == ' ' || pb[fst] == '\t'); fst++)
  74. X        ; /* skip leading whitespace */
  75. X
  76. X    giveupif(fst == len);
  77. X
  78. X    for (snd = fst; snd < len && pb[snd] != ' ' && pb[snd] != '\t' && pb[snd] != '\n'; snd++)
  79. X        ; /* skip first arg */
  80. X
  81. X    giveupif(snd == len);
  82. X
  83. X    noarg = (pb[snd] == '\n');
  84. X
  85. X    pb[snd++] = '\0'; /* null terminate the first arg */
  86. X
  87. X    if (!noarg) {
  88. X        while (snd < len && (pb[snd] == ' ' || pb[snd] == '\t'))
  89. X            snd++; /* skip whitespace to second arg */
  90. X
  91. X        giveupif(snd == len);
  92. X
  93. X        noarg = (pb[snd] == '\n'); /* could have trailing whitespace after only one arg */
  94. X
  95. X        if (!noarg) {
  96. X            for (end = snd; end < len && pb[end] != ' ' && pb[end] != '\t' && pb[end] != '\n'; end++)
  97. X                ; /* skip to the end of the second arg */
  98. X
  99. X            giveupif(end == len);
  100. X
  101. X            if (pb[end] == '\n') {
  102. X                pb[end] = '\0'; /* null terminate the first arg */
  103. X            } else {        /* else check for a spurious third arg */
  104. X                pb[end++] = '\0';
  105. X
  106. X                while (end < len && (pb[end] == ' ' || pb[end] == '\t'))
  107. X                    end++;
  108. X
  109. X                giveupif(end == len || pb[end] != '\n');
  110. X            }
  111. X        }
  112. X    }
  113. X
  114. X    *av = path;
  115. X
  116. X    if (!noarg)
  117. X        *--av = pb + snd;
  118. X    *--av = pb + fst;
  119. X
  120. X    execve(*av, av, ev);
  121. X    return -1;
  122. X
  123. fail:    errno = ENOEXEC;
  124. X    return -1;
  125. }
  126. SHAR_EOF
  127. echo 'File execve.c is complete' &&
  128. chmod 0644 execve.c ||
  129. echo 'restore of execve.c failed'
  130. Wc_c="`wc -c < 'execve.c'`"
  131. test 2017 -eq "$Wc_c" ||
  132.     echo 'execve.c: original size 2017, current size' "$Wc_c"
  133. rm -f _shar_wnt_.tmp
  134. fi
  135. # ============= fn.c ==============
  136. if test -f 'fn.c' -a X"$1" != X"-c"; then
  137.     echo 'x - skipping fn.c (File already exists)'
  138.     rm -f _shar_wnt_.tmp
  139. else
  140. > _shar_wnt_.tmp
  141. echo 'x - extracting fn.c (Text)'
  142. sed 's/^X//' << 'SHAR_EOF' > 'fn.c' &&
  143. /*
  144. X   fn.c: functions for adding and deleting functions from the symbol table.
  145. X   Support for signal handlers is also found here.
  146. */
  147. X
  148. #include "rc.h"
  149. #include <signal.h>
  150. #ifdef PROTECT_JOB
  151. #include <sys/ioctl.h>
  152. #endif
  153. #include "utils.h"
  154. #include "status.h"
  155. #include "tree.h"
  156. #include "hash.h"
  157. #include "footobar.h"
  158. #include "walk.h"
  159. #include "nalloc.h"
  160. #include "sigmsgs.h"
  161. #include "builtins.h"
  162. #include "input.h"
  163. X
  164. static void fn_handler(int);
  165. X
  166. static Node *handlers[NUMOFSIGNALS], null_function;
  167. static boolean runexit = FALSE;
  168. X
  169. /* set signals to default values for rc. this means that interactive shells ignore SIGQUIT, etc. */
  170. X
  171. void inithandler() {
  172. X    if (interactive) {
  173. #ifdef PROTECT_JOB
  174. X        if (dashell) {
  175. X            extern int ioctl(int, long,...);
  176. X
  177. X            setpgrp(rc_pid, rc_pid);
  178. X            ioctl(2, TIOCSPGRP, &rc_pid);
  179. X        }
  180. #endif
  181. X
  182. X        signal(SIGINT, sig);
  183. X        if (!dashdee) {
  184. X            signal(SIGQUIT, SIG_IGN);
  185. X            handlers[SIGQUIT] = &null_function;
  186. X            signal(SIGTERM, SIG_IGN);
  187. X            handlers[SIGTERM] = &null_function;
  188. X        }
  189. X    }
  190. X    null_function.type = BODY;
  191. X    null_function.u[0].p = null_function.u[1].p = NULL;
  192. }
  193. X
  194. /* only run this in a child process! resets signals to their default values */
  195. X
  196. void setsigdefaults() {
  197. X    int i;
  198. X
  199. X    /*
  200. X       General housekeeping: (setsigdefaults happens after fork(), so it's a convenient
  201. X       place to clean up)
  202. X    */
  203. X
  204. X    interactive = FALSE;
  205. X    if (histstr != NULL) {    /* Close an open history file */
  206. X        close(histfd);
  207. X        histstr = NULL; /* But prevent re-closing of the same file-descriptor */
  208. X    }
  209. X
  210. X    /* Restore signals to SIG_DFL */
  211. X
  212. X    for (i = 1; i < NUMOFSIGNALS; i++) { /* signal 0 is never used (bogus) */
  213. X        if (handlers[i] != NULL) {
  214. X            handlers[i] = NULL;
  215. X            signal(i, SIG_DFL);
  216. X        }
  217. X    }
  218. X    signal(SIGINT, SIG_DFL); /* sigint is special because its handler is normally        */
  219. X                 /* set to NULL, which doesn't get caught in the above loop    */
  220. X    runexit = FALSE; /* No sigexit on subshells */
  221. }
  222. X
  223. /* rc's exit. if runexit is set, run the sigexit function. */
  224. X
  225. void rc_exit(int stat) {
  226. X    static char *sigexit[2] = { "sigexit", NULL };
  227. X
  228. X    if (runexit) {
  229. X        runexit = FALSE;
  230. X        funcall(sigexit);
  231. X        exit(getstatus());
  232. X    } else {
  233. X        exit(stat);
  234. X    }
  235. }
  236. X
  237. /* the signal handler for all functions. calls walk() */
  238. X
  239. static void fn_handler(int s) {
  240. X    if (s < 0 || s >= NUMOFSIGNALS)
  241. X        rc_error("unknown signal!?");
  242. X
  243. X    signal(s, fn_handler); /* sgi seems to require re-signalling */
  244. X    walk(handlers[s], TRUE);
  245. }
  246. X
  247. /*
  248. X   assign a function in Node form. Check to see if the function is also a signal, and set the
  249. X   signal vectors appropriately.
  250. */
  251. X
  252. void fnassign(char *name, Node *def) {
  253. X    Node *newdef = treecpy(def == NULL ? &null_function : def, ealloc); /* important to do the treecopy first */
  254. X    Function *new = get_fn_place(name);
  255. X    int i;
  256. X
  257. X    new->def = newdef;
  258. X    new->extdef = NULL;
  259. X
  260. X    if (strncmp(name, "sig", sizeof "sig" - 3) == 0) { /* slight optimization */
  261. #ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */
  262. X        if (streq(name, "sigcld"))
  263. X            rc_error("can't trap SIGCLD");
  264. #endif
  265. X        if (streq(name, "sigexit"))
  266. X            runexit = TRUE;
  267. X        for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
  268. X            if (streq(signals[i][0], name)) {
  269. X                if (newdef != NULL) {
  270. X                    handlers[i] = newdef;
  271. X                    signal(i, fn_handler);
  272. X                } else {
  273. X                    handlers[i] = &null_function;
  274. X                    signal(i, SIG_IGN);
  275. X                }
  276. X                break;
  277. X            }
  278. X    }
  279. }
  280. X
  281. /* assign a function from the environment. store just the external representation */
  282. X
  283. void fnassign_string(char *extdef) {
  284. X    char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
  285. X    Function *new;
  286. X
  287. X    if (name == NULL)
  288. X        return;
  289. X
  290. X    new = get_fn_place(name);
  291. X    new->def = NULL;
  292. X    new->extdef = ecpy(extdef);
  293. }
  294. X
  295. /* return a function in Node form, evaluating an entry from the environment if necessary */
  296. X
  297. Node *fnlookup(char *name) {
  298. X    Function *look = lookup_fn(name);
  299. X    Node *ret;
  300. X
  301. X    if (look == NULL)
  302. X        return NULL; /* not found */
  303. X    if (look->def != NULL)
  304. X        return look->def;
  305. X    if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
  306. X        return &null_function;
  307. X
  308. X    ret = parse_fn(name, look->extdef);
  309. X
  310. X    if (ret == NULL) {
  311. X        efree(look->extdef);
  312. X        look->extdef = NULL;
  313. X        return &null_function;
  314. X    } else {
  315. X        return look->def = treecpy(ret, ealloc); /* Need to take it out of talloc space */
  316. X    }
  317. }
  318. X
  319. /* return a function in string form (used by makeenv) */
  320. X
  321. char *fnlookup_string(char *name) {
  322. X    Function *look = lookup_fn(name);
  323. X
  324. X    if (look == NULL)
  325. X        return NULL;
  326. X    if (look->extdef != NULL)
  327. X        return look->extdef;
  328. X    return look->extdef = fun2str(name, look->def);
  329. }
  330. X
  331. /*
  332. X   remove a function from the symbol table. If it also defines a signal handler, restore the signal handler
  333. X   to its default value.
  334. */
  335. X
  336. void fnrm(char *name) {
  337. X    int i;
  338. X
  339. X    for (i = 1; i < NUMOFSIGNALS; i++) /* signal 0 unused */
  340. X        if (streq(signals[i][0], name)) {
  341. X            handlers[i] = NULL;
  342. X            if (i == SIGINT)
  343. X                signal(i, sig); /* restore default signal handler for rc */
  344. X            else if ((i == SIGQUIT || i == SIGTERM) && !dashdee) {
  345. X                handlers[i] = &null_function;
  346. X                signal(i, SIG_IGN);     /* ditto */
  347. X            } else {
  348. X                signal(i, SIG_DFL);
  349. X            }
  350. X        }
  351. X
  352. X    if (streq(name, "sigexit"))
  353. X        runexit = FALSE;
  354. X
  355. X    delete_fn(name);
  356. }
  357. X
  358. void whatare_all_signals() {
  359. X    int i;
  360. X
  361. X    for (i = 1; i < NUMOFSIGNALS; i++)
  362. X        if (*signals[i][0] != '\0')
  363. X            if (handlers[i] == NULL)
  364. X                fprint(1, "fn %s\n", signals[i][0]);
  365. X            else
  366. X                fprint(1, "fn %s {%s}\n", strprint(signals[i][0], FALSE, FALSE), ptree(handlers[i]));
  367. }
  368. X
  369. void prettyprint_fn(int fd, char *name, Node *n) {
  370. X    fprint(fd, "fn %s {%s}\n", strprint(name, FALSE, FALSE), ptree(n));
  371. }
  372. SHAR_EOF
  373. chmod 0644 fn.c ||
  374. echo 'restore of fn.c failed'
  375. Wc_c="`wc -c < 'fn.c'`"
  376. test 5485 -eq "$Wc_c" ||
  377.     echo 'fn.c: original size 5485, current size' "$Wc_c"
  378. rm -f _shar_wnt_.tmp
  379. fi
  380. # ============= footobar.c ==============
  381. if test -f 'footobar.c' -a X"$1" != X"-c"; then
  382.     echo 'x - skipping footobar.c (File already exists)'
  383.     rm -f _shar_wnt_.tmp
  384. else
  385. > _shar_wnt_.tmp
  386. echo 'x - extracting footobar.c (Text)'
  387. sed 's/^X//' << 'SHAR_EOF' > 'footobar.c' &&
  388. /*
  389. X   footobar.c: a collection of functions to convert internal representations of
  390. X   variables and functions to external representations, and vice versa
  391. */
  392. X
  393. #include "rc.h"
  394. #include "utils.h"
  395. #include "lex.h"
  396. #include "footobar.h"
  397. #include "nalloc.h"
  398. #include "input.h"
  399. #include "list.h"
  400. X
  401. #define FSCHAR '\1'
  402. #define FSSTRING "\1"
  403. X
  404. static char *getenvw(char *, boolean);
  405. static void funcat(char *);
  406. static void strtree(Node *);
  407. X
  408. static char *fun;
  409. static SIZE_T funsize, funpos;
  410. X
  411. #ifdef PROTECT_ENV
  412. /* octalize -- protect an exported name from brain-dead shells */
  413. X
  414. static char hexchar[] = "0123456789abcdef";
  415. X
  416. static char *octalize(char *name) {
  417. X    int c;
  418. X    static char namebuf[1000];
  419. X    char *s = namebuf;
  420. X
  421. X    while (1) {
  422. X        c = *(unsigned char *) name++;
  423. X        if (c == '\0') {
  424. X            *s++ = '\0';
  425. X            return namebuf;
  426. X        }
  427. X        if (!dnw[c] && c != '*') {
  428. X            if (c != '_')
  429. X                *s++ = c;
  430. X            else if (*name != '_')
  431. X                *s++ = c;
  432. X            else
  433. X                goto fallthrough;
  434. X        } else {
  435. X    fallthrough:    *s++ = '_';
  436. X            *s++ = '_';
  437. X            *s++ = hexchar[(c >> 4) & 0xf];
  438. X            *s++ = hexchar[c & 0xf];
  439. X        }
  440. X    }
  441. }
  442. #endif
  443. X
  444. /* a specialized strcat, used in strtree */
  445. X
  446. static void funcat(char *s) {
  447. X    SIZE_T l = strlen(s);
  448. X    char *new;
  449. X
  450. X    if (l + funpos > funsize) {
  451. X        new = nalloc(funsize *= 2);
  452. X        memcpy(new, fun, funpos);
  453. X        new[funpos] = 0;
  454. X        fun = new;
  455. X    }
  456. X    strcpy(fun + funpos, s);
  457. X    funpos += l;
  458. }
  459. X
  460. /* used to turn a function in Node * form into something we can export to the environment */
  461. X
  462. char *fun2str(char *name, Node *s) {
  463. #ifdef PROTECT_ENV
  464. X    name = octalize(name);
  465. #endif
  466. X    fun = nalloc(funsize = 512);
  467. X    funpos = 0;
  468. X    funcat("fn_");
  469. X    funcat(name);
  470. X    funcat("={");
  471. X    strtree(s);
  472. X    funcat("}");
  473. X    return ecpy(fun); /* put into malloc space */
  474. }
  475. X
  476. /* ptree is used by whatis in order to print the definition of a function to the terminal */
  477. X
  478. char *ptree(Node *s) {
  479. X    fun = nalloc(funsize = 512);
  480. X    funpos = 0;
  481. X    fun[0] = 0;
  482. X    strtree(s);
  483. X    return fun;
  484. }
  485. X
  486. /* save some code space by gathering this operation in a function */
  487. X
  488. static void catredir(int i) {
  489. X    switch (i) {
  490. X    case CREATE: funcat(">"); break;
  491. X    case APPEND: funcat(">>"); break;
  492. X    case HEREDOC: funcat("<<"); break;
  493. X    case HERESTRING: funcat("<<<"); break;
  494. X    case FROM: funcat("<"); break;
  495. X    }
  496. }
  497. X
  498. /* convert a function in Node * form into something rc can parse (and humans can read?) */
  499. X
  500. static void strtree(Node *n) {
  501. X    int defaultfd;
  502. X    char b[16];
  503. X
  504. X    if (n == NULL) {
  505. X        funcat("()");
  506. X        return;
  507. X    }
  508. X
  509. X    switch (n->type) {
  510. X    case rDUP:
  511. X        catredir(n->u[0].i);
  512. X        if (n->u[2].i != -1)
  513. X            sprint(b, "[%d=%d]", n->u[1].i, n->u[2].i);
  514. X        else
  515. X            sprint(b, "[%d=]", n->u[1].i);
  516. X        funcat(b);
  517. X        break;
  518. X    case rWORD:
  519. X        funcat(strprint(n->u[0].s, FALSE, FALSE));
  520. X        break;
  521. X    case QWORD:
  522. X        funcat(strprint(n->u[0].s, TRUE, FALSE));
  523. X        break;
  524. X    case BACKQ:
  525. X        if (n->u[0].p != NULL && n->u[0].p->type == VAR
  526. X            && n->u[0].p->u[0].p != NULL && n->u[0].p->u[0].p->type == rWORD
  527. X            && streq(n->u[0].p->u[0].p->u[0].s,"ifs")) {
  528. X            funcat("`{");
  529. X        } else {
  530. X            funcat("``");
  531. X            strtree(n->u[0].p);
  532. X            funcat("{");
  533. X        }
  534. X        strtree(n->u[1].p);
  535. X        funcat("}");
  536. X        break;
  537. X    case rBANG:
  538. X        funcat("! ");
  539. X        strtree(n->u[0].p);
  540. X        break;
  541. X    case rCASE:
  542. X        funcat("case ");
  543. X        strtree(n->u[0].p);
  544. X        break;
  545. X    case CBODY:
  546. X        if (n->u[0].p != NULL) {
  547. X            strtree(n->u[0].p);
  548. X            funcat(";");
  549. X        }
  550. X        if (n->u[1].p != NULL)
  551. X            strtree(n->u[1].p);
  552. X        break;
  553. X    case NOWAIT:
  554. X        strtree(n->u[0].p);
  555. X        funcat("&");
  556. X        break;
  557. X    case rCOUNT:
  558. X        funcat("$#");
  559. X        strtree(n->u[0].p);
  560. X        break;
  561. X    case rFLAT:
  562. X        funcat("$^");
  563. X        strtree(n->u[0].p);
  564. X        break;
  565. X    case RMFN:
  566. X        funcat("fn ");
  567. X        strtree(n->u[0].p);
  568. X        break;
  569. X    case rSUBSHELL:
  570. X        funcat("@ ");
  571. X        strtree(n->u[0].p);
  572. X        break;
  573. X    case VAR:
  574. X        funcat("$");
  575. X        strtree(n->u[0].p);
  576. X        break;
  577. X    case rANDAND:
  578. X        strtree(n->u[0].p);
  579. X        funcat("&&");
  580. X        strtree(n->u[1].p);
  581. X        break;
  582. X    case ASSIGN:
  583. X        strtree(n->u[0].p);
  584. X        funcat("=");
  585. X        strtree(n->u[1].p);
  586. X        break;
  587. X    case BODY:
  588. X        if (n->u[1].p != NULL)
  589. X            funcat("{");
  590. X        strtree(n->u[0].p);
  591. X        if (n->u[1].p != NULL) {
  592. X            funcat(";");
  593. X            strtree(n->u[1].p);
  594. X            funcat("}");
  595. X        }
  596. X        break;
  597. X    case BRACE:
  598. X        funcat("{");
  599. X        strtree(n->u[0].p);
  600. X        funcat("}");
  601. X        if (n->u[1].p != NULL)
  602. X            strtree(n->u[1].p);
  603. X        break;
  604. X    case CONCAT:
  605. X        strtree(n->u[0].p);
  606. X        funcat("^");
  607. X        strtree(n->u[1].p);
  608. X        break;
  609. X    case rELSE:
  610. X        funcat("{");
  611. X        strtree(n->u[0].p);
  612. X        funcat("}else ");
  613. X        strtree(n->u[1].p);
  614. X        break;
  615. X    case EPILOG:
  616. X    case PRE:
  617. X        strtree(n->u[0].p);
  618. X        if (n->u[1].p != NULL) {
  619. X            funcat(" ");
  620. X            strtree(n->u[1].p);
  621. X        }
  622. X        break;
  623. X    case NEWFN:
  624. X        funcat("fn ");
  625. X        strtree(n->u[0].p);
  626. X        funcat(" {");
  627. X        strtree(n->u[1].p);
  628. X        funcat("}");
  629. X        break;
  630. X    case rIF:
  631. X        funcat("if(");
  632. X        strtree(n->u[0].p);
  633. X        funcat(")");
  634. X        strtree(n->u[1].p);
  635. X        break;
  636. X    case rOROR:
  637. X        strtree(n->u[0].p);
  638. X        funcat("||");
  639. X        strtree(n->u[1].p);
  640. X        break;
  641. X    case ARGS:
  642. X        strtree(n->u[0].p);
  643. X        funcat(" ");
  644. X        strtree(n->u[1].p);
  645. X        break;
  646. X    case rSWITCH:
  647. X        funcat("switch(");
  648. X        strtree(n->u[0].p);
  649. X        funcat("){");
  650. X        strtree(n->u[1].p);
  651. X        funcat("}");
  652. X        break;
  653. X    case MATCH:
  654. X        funcat("~ ");
  655. X        strtree(n->u[0].p);
  656. X        funcat(" ");
  657. X        strtree(n->u[1].p);
  658. X        break;
  659. X    case VARSUB:
  660. X        funcat("$");
  661. X        strtree(n->u[0].p);
  662. X        funcat("(");
  663. X        strtree(n->u[1].p);
  664. X        funcat(")");
  665. X        break;
  666. X    case rWHILE:
  667. X        funcat("while(");
  668. X        strtree(n->u[0].p);
  669. X        funcat(")");
  670. X        strtree(n->u[1].p);
  671. X        break;
  672. X    case LAPPEND:
  673. X        funcat("(");
  674. X        strtree(n->u[0].p);
  675. X        funcat(" ");
  676. X        strtree(n->u[1].p);
  677. X        funcat(")");
  678. X        break;
  679. X    case FORIN:
  680. X        funcat("for(");
  681. X        strtree(n->u[0].p);
  682. X        funcat(" in ");
  683. X        strtree(n->u[1].p);
  684. X        funcat(")");
  685. X        strtree(n->u[2].p);
  686. X        break;
  687. X    case rPIPE:
  688. X        funcat("{");
  689. X        strtree(n->u[2].p);
  690. X        if (n->u[0].i == 1) {
  691. X            if (n->u[1].i == 0)
  692. X                sprint(b, "}|{");
  693. X            else
  694. X                sprint(b, "}|[1=%d]{", n->u[1].p);
  695. X        } else {
  696. X            if (n->u[1].i == 0)
  697. X                sprint(b, "}|[%d]{", n->u[0].p);
  698. X            else
  699. X                sprint(b, "}|[%d=%d]{", n->u[0].i, n->u[1].i);
  700. X        }
  701. X        funcat(b);
  702. X        strtree(n->u[3].p);
  703. X        funcat("}");
  704. X        break;
  705. X    case NMPIPE:
  706. X        defaultfd = (n->u[0].i == CREATE || n->u[0].i == APPEND);
  707. X        catredir(n->u[0].i);
  708. X        if (n->u[1].i != defaultfd) {
  709. X            sprint(b, "[%d]{", n->u[1].i);
  710. X            funcat(b);
  711. X        } else
  712. X            funcat("{");
  713. X        strtree(n->u[2].p);
  714. X        funcat("}");
  715. X        break;
  716. X    case rREDIR:
  717. X        defaultfd = (n->u[0].i == CREATE || n->u[0].i == APPEND);
  718. X        catredir(n->u[0].i);
  719. X        if (n->u[1].i != defaultfd) {
  720. X            sprint(b, "[%d]", n->u[1].i);
  721. X            funcat(b);
  722. X        }
  723. X        strtree(n->u[2].p);
  724. X        break;
  725. X     }
  726. }
  727. X
  728. /* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
  729. X
  730. char *list2str(char *name, List *s) {
  731. X    SIZE_T size;
  732. X    List *t;
  733. X    char *w;
  734. X
  735. #ifdef PROTECT_ENV
  736. X    name = octalize(name);
  737. #endif
  738. X    size = strlen(name) + listlen(s);
  739. X
  740. X    w = ealloc(size + 2);
  741. X    t = s;
  742. X    strcpy(w, name);
  743. X    strcat(w, "=");
  744. X    strcat(w, t->w);
  745. X    for (s = s->n; s != NULL; s = s->n) {
  746. X        strcat(w, FSSTRING);
  747. X        strcat(w, s->w);
  748. X    }
  749. X    return w;
  750. }
  751. X
  752. /* convert a List to an array, for execve() */
  753. X
  754. char **list2array(List *s, boolean print) {
  755. X    char **av;
  756. X    int i;
  757. X
  758. X    /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */
  759. X
  760. X    av = nalloc((listnel(s) + 4) * sizeof (char *));
  761. X
  762. X    av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */
  763. X
  764. X    if (print)
  765. X        fprint(2, "%l\n", s);
  766. X
  767. X    for (i = 0; s != NULL; i++) {
  768. X        av[i] = s->w;
  769. X        s = s->n;
  770. X    }
  771. X    av[i] = NULL;
  772. X    return av;
  773. }
  774. X
  775. /* figure out the name of a variable given an environment string. copy this into malloc space */
  776. X
  777. char *get_name(char *s) {
  778. X    int c;
  779. X    SIZE_T i;
  780. X    char *r, *namebuf;
  781. #ifdef PROTECT_ENV
  782. X    char *h1, *h2;
  783. #endif
  784. X
  785. X    for (i = 0; s[i] != '\0' && s[i] != '='; i++)
  786. X        ;
  787. X
  788. X    if (s[i] == '\0')
  789. X        return NULL;
  790. X
  791. X    r = namebuf = ealloc(i + 1);
  792. X
  793. X    while (1)
  794. X        switch (c = *s++) {
  795. X        case '=':
  796. X            *r++ = '\0';
  797. X            return namebuf;
  798. #ifdef PROTECT_ENV
  799. X        case '_':
  800. X            if (*s == '_' && (h1 = strchr(hexchar, s[1])) != NULL && (h2 = strchr(hexchar, s[2])) != NULL) {
  801. X                *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar);
  802. X                s += 3;
  803. X                break;
  804. X            }
  805. X            /* FALLTHROUGH */
  806. #endif
  807. X        default:
  808. X            *r++ = c;
  809. X            break;
  810. X        }
  811. }
  812. X
  813. /* get the next word from a variable's value as represented in the environment. */
  814. X
  815. static char *getenvw(char *s, boolean saw_alpha) {
  816. X    char *r;
  817. X    SIZE_T i,j;
  818. X
  819. X    for (i = j = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
  820. X        ;
  821. X
  822. X    if (i == 0)
  823. X        if(s[i] == '\0' && !saw_alpha)
  824. X            return NULL;
  825. X        else {
  826. X            r = enew(char);
  827. X            *r = '\0';
  828. X            return r;
  829. X        }
  830. X
  831. X    r = ealloc(i + j + 1);
  832. X
  833. X    r[i + j] = '\0';
  834. X
  835. X    while (i > 0) {
  836. X        --i;
  837. X        r[i + j] = s[i];
  838. X    }
  839. X    return r;
  840. }
  841. X
  842. /* take an environment entry for a variable (elements ^A separated) and turn it into a List */
  843. X
  844. List *parse_var(char *name, char *extdef) {
  845. X    List *r, *top;
  846. X    char *f;
  847. X    boolean saw_alpha;
  848. X
  849. X    top = r = enew(List);
  850. X    extdef = strchr(extdef, '=') + 1;
  851. X
  852. X
  853. X    if ((f = getenvw(extdef, FALSE)) == NULL)
  854. X        return NULL;
  855. X
  856. X    while (1) {
  857. X        r->w = f;
  858. X        r->m = NULL;
  859. X        extdef += strlen(f);
  860. X        if (*extdef == FSCHAR) {
  861. X            extdef++;
  862. X            saw_alpha = TRUE;
  863. X        } else {
  864. X            saw_alpha = FALSE;
  865. X        }
  866. X        if ((f = getenvw(extdef, saw_alpha)) == NULL) {
  867. X            r->n = NULL;
  868. X            break;
  869. X        }
  870. X        r = r->n = enew(List);
  871. X    }
  872. X    return top;
  873. }
  874. X
  875. /* get an environment entry for a function and have rc parse it. */
  876. X
  877. Node *parse_fn(char *name, char *extdef) {
  878. X    Node *def;
  879. X    int i;
  880. X    char *s, old[4];
  881. X
  882. X    s = strchr(extdef, '=');
  883. X
  884. X    if (s == NULL)
  885. X        return NULL;
  886. X
  887. X    s -= 3;
  888. X
  889. X    for (i = 0; i < 4; i++)
  890. X        old[i] = s[i];
  891. X    s[0] = 'f';
  892. X    s[1] = 'n';
  893. X    s[2] = ' ';
  894. X    s[3] = 'x';
  895. X
  896. X    def = parseline(s);
  897. X    for (i = 0; i < 4; i++)
  898. X        s[i] = old[i];
  899. X
  900. X    if (def == NULL || def->type != NEWFN)
  901. X        return NULL;
  902. X    else
  903. X        return def->u[1].p;
  904. }
  905. SHAR_EOF
  906. chmod 0644 footobar.c ||
  907. echo 'restore of footobar.c failed'
  908. Wc_c="`wc -c < 'footobar.c'`"
  909. test 9420 -eq "$Wc_c" ||
  910.     echo 'footobar.c: original size 9420, current size' "$Wc_c"
  911. rm -f _shar_wnt_.tmp
  912. fi
  913. # ============= footobar.h ==============
  914. if test -f 'footobar.h' -a X"$1" != X"-c"; then
  915.     echo 'x - skipping footobar.h (File already exists)'
  916.     rm -f _shar_wnt_.tmp
  917. else
  918. > _shar_wnt_.tmp
  919. echo 'x - extracting footobar.h (Text)'
  920. sed 's/^X//' << 'SHAR_EOF' > 'footobar.h' &&
  921. extern char *fun2str(char *, Node *);
  922. extern char *ptree(Node *);
  923. extern char *list2str(char *, List *);
  924. extern char **list2array(List *, boolean);
  925. extern char *get_name(char *);
  926. extern List *parse_var(char *, char *);
  927. extern Node *parse_fn(char *, char *);
  928. SHAR_EOF
  929. chmod 0644 footobar.h ||
  930. echo 'restore of footobar.h failed'
  931. Wc_c="`wc -c < 'footobar.h'`"
  932. test 258 -eq "$Wc_c" ||
  933.     echo 'footobar.h: original size 258, current size' "$Wc_c"
  934. rm -f _shar_wnt_.tmp
  935. fi
  936. # ============= getopt.c ==============
  937. if test -f 'getopt.c' -a X"$1" != X"-c"; then
  938.     echo 'x - skipping getopt.c (File already exists)'
  939.     rm -f _shar_wnt_.tmp
  940. else
  941. > _shar_wnt_.tmp
  942. echo 'x - extracting getopt.c (Text)'
  943. sed 's/^X//' << 'SHAR_EOF' > 'getopt.c' &&
  944. /* getopt routine courtesy of David Sanderson */
  945. #include "rc.h"
  946. #include "utils.h"
  947. #include "getopt.h"
  948. X
  949. int     opterr = 1;
  950. int     optind = 1;
  951. int     optopt;
  952. char    *optarg;
  953. int getopt(int argc, char **argv, char *opts) {
  954. X        static int sp = 1;
  955. X        int c;
  956. X        char *cp;
  957. X    if (optind == 0) /* reset getopt() */
  958. X        optind = sp = 1;
  959. X
  960. X        if (sp == 1)
  961. X                if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') {
  962. X                        return -1;
  963. X                } else if (strcmp(argv[optind], "--") == 0) {
  964. X                        optind++;
  965. X                        return -1;
  966. X                }
  967. X        optopt = c = argv[optind][sp];
  968. X        if (c == ':' || (cp=strchr(opts, c)) == 0) {
  969. X                fprint(2, "%s: illegal option -- %c\n", argv[0], c);
  970. X                if (argv[optind][++sp] == '\0') {
  971. X                        optind++;
  972. X                        sp = 1;
  973. X                }
  974. X                return '?';
  975. X        }
  976. X        if (*++cp == ':') {
  977. X                if(argv[optind][sp+1] != '\0') {
  978. X                        optarg = &argv[optind++][sp+1];
  979. X                } else if(++optind >= argc) {
  980. X                        fprint(2, "%s: option requires an argument -- %c\n", argv[0], c);
  981. X                        sp = 1;
  982. X                        return '?';
  983. X                } else
  984. X                        optarg = argv[optind++];
  985. X                sp = 1;
  986. X        } else {
  987. X                if (argv[optind][++sp] == '\0') {
  988. X                        sp = 1;
  989. X                        optind++;
  990. X                }
  991. X                optarg = 0;
  992. X        }
  993. X        return c;
  994. }
  995. SHAR_EOF
  996. chmod 0644 getopt.c ||
  997. echo 'restore of getopt.c failed'
  998. Wc_c="`wc -c < 'getopt.c'`"
  999. test 1619 -eq "$Wc_c" ||
  1000.     echo 'getopt.c: original size 1619, current size' "$Wc_c"
  1001. rm -f _shar_wnt_.tmp
  1002. fi
  1003. # ============= getopt.h ==============
  1004. if test -f 'getopt.h' -a X"$1" != X"-c"; then
  1005.     echo 'x - skipping getopt.h (File already exists)'
  1006.     rm -f _shar_wnt_.tmp
  1007. else
  1008. > _shar_wnt_.tmp
  1009. echo 'x - extracting getopt.h (Text)'
  1010. sed 's/^X//' << 'SHAR_EOF' > 'getopt.h' &&
  1011. extern int getopt(int, char **, char *);
  1012. X
  1013. extern int optind, opterr, optopt;
  1014. extern char *optarg;
  1015. SHAR_EOF
  1016. chmod 0644 getopt.h ||
  1017. echo 'restore of getopt.h failed'
  1018. Wc_c="`wc -c < 'getopt.h'`"
  1019. test 98 -eq "$Wc_c" ||
  1020.     echo 'getopt.h: original size 98, current size' "$Wc_c"
  1021. rm -f _shar_wnt_.tmp
  1022. fi
  1023. # ============= glob.c ==============
  1024. if test -f 'glob.c' -a X"$1" != X"-c"; then
  1025.     echo 'x - skipping glob.c (File already exists)'
  1026.     rm -f _shar_wnt_.tmp
  1027. else
  1028. > _shar_wnt_.tmp
  1029. echo 'x - extracting glob.c (Text)'
  1030. sed 's/^X//' << 'SHAR_EOF' > 'glob.c' &&
  1031. /* glob.c: rc's (ugly) globber. This code is not elegant, but it works */
  1032. X
  1033. #include <sys/types.h>
  1034. #include <sys/stat.h>
  1035. #include "rc.h"
  1036. #include "glob.h"
  1037. #include "glom.h"
  1038. #include "nalloc.h"
  1039. #include "utils.h"
  1040. #include "match.h"
  1041. #include "footobar.h"
  1042. #include "list.h"
  1043. #ifdef NODIRENT
  1044. #include <sys/dir.h>
  1045. #define dirent direct /* need to get the struct declaraction right */
  1046. #else
  1047. #include <dirent.h>
  1048. #endif
  1049. X
  1050. static List *dmatch(char *, char *, char *);
  1051. static List *doglob(char *, char *);
  1052. static List *lglob(List *, char *, char *, SIZE_T);
  1053. static List *sort(List *);
  1054. X
  1055. /*
  1056. X   matches a list of words s against a list of patterns p. Returns true iff
  1057. X   a pattern in p matches a word in s. null matches null, but otherwise null
  1058. X   patterns match nothing.
  1059. */
  1060. X
  1061. boolean lmatch(List *s, List *p) {
  1062. X    List *q;
  1063. X    int i;
  1064. X    boolean okay;
  1065. X
  1066. X    if (s == NULL) {
  1067. X        if (p == NULL) /* null matches null */
  1068. X            return TRUE;
  1069. X        for (; p != NULL; p = p->n) { /* one or more stars match null */
  1070. X            if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */
  1071. X                okay = TRUE;
  1072. X                for (i = 0; p->w[i] != '\0'; i++)
  1073. X                    if (p->w[i] != '*' || p->m[i] != 1) {
  1074. X                        okay = FALSE;
  1075. X                        break;
  1076. X                    }
  1077. X                if (okay)
  1078. X                    return TRUE;
  1079. X            }
  1080. X        }
  1081. X        return FALSE;
  1082. X    }
  1083. X
  1084. X    for (; s != NULL; s = s->n)
  1085. X        for (q = p; q != NULL; q = q->n)
  1086. X            if (match(q->w, q->m, s->w))
  1087. X                return TRUE;
  1088. X    return FALSE;
  1089. }
  1090. X
  1091. /* Matches a pattern p against the contents of directory d */
  1092. X
  1093. static List *dmatch(char *d, char *p, char *m) {
  1094. X    boolean matched = FALSE;
  1095. X    List *top, *r;
  1096. X    DIR *dirp;
  1097. X    struct dirent *dp;
  1098. X    struct stat s;
  1099. X    /* prototypes for XXXdir functions. comment out if necessary */
  1100. X    extern DIR *opendir(const char *);
  1101. X    extern struct dirent *readdir(DIR *);
  1102. X    extern int closedir(DIR *);
  1103. X
  1104. X    /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
  1105. X    if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR)
  1106. X        return NULL;
  1107. X    if ((dirp = opendir(d)) == NULL)
  1108. X        return NULL;
  1109. X
  1110. X    top = r = NULL;
  1111. X
  1112. X    while ((dp = readdir(dirp)) != NULL)
  1113. X        if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
  1114. X            matched = TRUE;
  1115. X            if (top == NULL)
  1116. X                top = r = nnew(List);
  1117. X            else
  1118. X                r = r->n = nnew(List);
  1119. X            r->w = ncpy(dp->d_name);
  1120. X            r->m = NULL;
  1121. X        }
  1122. X
  1123. X    closedir(dirp);
  1124. X
  1125. X    if (!matched)
  1126. X        return NULL;
  1127. X
  1128. X    r->n = NULL;
  1129. X    return top;
  1130. }
  1131. X
  1132. /*
  1133. X   lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*"
  1134. X   will return a list with all the files in /tmp, /usr, and /bin. NULL on no match.
  1135. X   slashcount indicates the number of slashes to stick between the directory and the
  1136. X   matched name. e.g., for matching ////tmp/////foo*
  1137. */
  1138. X
  1139. static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
  1140. X    List *q, *r, *top, foo;
  1141. X    static List slash;
  1142. X    static SIZE_T slashsize = 0;
  1143. X
  1144. X    if (slashcount + 1 > slashsize) {
  1145. X        slash.w = ealloc(slashcount + 1);
  1146. X        slashsize = slashcount;
  1147. X    }
  1148. X    slash.w[slashcount] = '\0';
  1149. X    while (slashcount > 0)
  1150. X        slash.w[--slashcount] = '/';
  1151. X
  1152. X    for (top = r = NULL; s != NULL; s = s->n) {
  1153. X        q = dmatch(s->w, p, m);
  1154. X        if (q != NULL) {
  1155. X            foo.w = s->w;
  1156. X            foo.m = NULL;
  1157. X            foo.n = NULL;
  1158. X            if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
  1159. X                q = concat(&slash, q);          /* dir/name with slash */
  1160. X            q = concat(&foo, q);
  1161. X            if (r == NULL)
  1162. X                top = r = q;
  1163. X            else
  1164. X                r->n = q;
  1165. X            while (r->n != NULL)
  1166. X                r = r->n;
  1167. X        }
  1168. X    }
  1169. X    return top;
  1170. }
  1171. X
  1172. /*
  1173. X   Doglob globs a pathname in pattern form against a unix path. Returns the original
  1174. X   pattern (cleaned of metacharacters) on failure, or the globbed string(s).
  1175. */
  1176. X
  1177. static List *doglob(char *w, char *m) {
  1178. X    static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
  1179. X    static SIZE_T dsize = 0;
  1180. X    char *d, *p, *md, *mp;
  1181. X    SIZE_T psize;
  1182. X    char *s = w;
  1183. X    List firstdir;
  1184. X    List *matched;
  1185. X    int slashcount;
  1186. X
  1187. X    if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
  1188. X        efree(dir); efree(pattern); efree(metadir); efree(metapattern);
  1189. X        dir = ealloc(psize);
  1190. X        pattern = ealloc(psize);
  1191. X        metadir = ealloc(psize);
  1192. X        metapattern = ealloc(psize);
  1193. X        dsize = psize;
  1194. X    }
  1195. X
  1196. X    d = dir;
  1197. X    p = pattern;
  1198. X    md = metadir;
  1199. X    mp = metapattern;
  1200. X
  1201. X    if (*s == '/') {
  1202. X        while (*s == '/')
  1203. X            *d++ = *s++, *md++ = *m++;
  1204. X    } else {
  1205. X        while (*s != '/' && *s != '\0')
  1206. X            *d++ = *s++, *md++ = *m++; /* get first directory component */
  1207. X    }
  1208. X    *d = '\0';
  1209. X
  1210. X    /*
  1211. X       Special case: no slashes in the pattern, i.e., open the current directory.
  1212. X       Remember that w cannot consist of slashes alone (the other way *s could be
  1213. X       zero) since doglob gets called iff there's a metacharacter to be matched
  1214. X    */
  1215. X    if (*s == '\0') {
  1216. X        matched = dmatch(".", dir, metadir);
  1217. X        goto end;
  1218. X    }
  1219. X
  1220. X    if (*w == '/') {
  1221. X        firstdir.w = dir;
  1222. X        firstdir.m = metadir;
  1223. X        firstdir.n = NULL;
  1224. X        matched = &firstdir;
  1225. X    } else {
  1226. X        /*
  1227. X           we must glob against current directory,
  1228. X           since the first character is not a slash.
  1229. X        */
  1230. X        matched = dmatch(".", dir, metadir);
  1231. X    }
  1232. X
  1233. X    do {
  1234. X        for (slashcount = 0; *s == '/'; s++, m++)
  1235. X            slashcount++; /* skip slashes */
  1236. X
  1237. X        while (*s != '/' && *s != '\0')
  1238. X            *p++ = *s++, *mp++ = *m++; /* get pattern */
  1239. X        *p = '\0';
  1240. X
  1241. X        matched = lglob(matched, pattern, metapattern, slashcount);
  1242. X
  1243. X        p = pattern, mp = metapattern;
  1244. X    } while (*s != '\0');
  1245. X
  1246. end:    if (matched == NULL) {
  1247. X        matched = nnew(List);
  1248. X        matched->w = w;
  1249. X        matched->m = NULL;
  1250. X        matched->n = NULL;
  1251. X    }
  1252. X    return matched;
  1253. }
  1254. X
  1255. /*
  1256. X   Globs a list; checks to see if each element in the list has a metacharacter. If it
  1257. X   does, it is globbed, and the output is sorted.
  1258. */
  1259. X
  1260. List *glob(List *s) {
  1261. X    List *top, *r;
  1262. X    boolean meta;
  1263. X
  1264. X    for (r = s, meta = FALSE; r != NULL; r = r->n)
  1265. X        if (r->m != NULL)
  1266. X            meta = TRUE;
  1267. X
  1268. X    if (!meta)
  1269. X        return s; /* don't copy lists with no metacharacters in them */
  1270. X
  1271. X    for (top = r = NULL; s != NULL; s = s->n) {
  1272. X        if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
  1273. X            if (top == NULL) {
  1274. X                top = r = nnew(List);
  1275. X            } else {
  1276. X                r->n = nnew(List);
  1277. X                r = r->n;
  1278. X            }
  1279. X            r->w = s->w;
  1280. X        } else {
  1281. X            if (top == NULL)
  1282. X                top = r = sort(doglob(s->w, s->m));
  1283. X            else
  1284. X                r->n = sort(doglob(s->w, s->m));
  1285. X            while (r->n != NULL)
  1286. X                r = r->n;
  1287. X        }
  1288. X    }
  1289. X
  1290. X    r->n = NULL;
  1291. X    return top;
  1292. }
  1293. X
  1294. static List *sort(List *s) {
  1295. X    SIZE_T nel = listnel(s);
  1296. X
  1297. X    if (nel > 1) {
  1298. X        char **a;
  1299. X        List *t;
  1300. X
  1301. X        qsort(a = list2array(s, FALSE), nel, sizeof(char *), starstrcmp);
  1302. X
  1303. X        for (t = s; t != NULL; t = t->n)
  1304. X            t->w = *a++;
  1305. X    }
  1306. X
  1307. X    return s;
  1308. }
  1309. SHAR_EOF
  1310. chmod 0644 glob.c ||
  1311. echo 'restore of glob.c failed'
  1312. Wc_c="`wc -c < 'glob.c'`"
  1313. test 6378 -eq "$Wc_c" ||
  1314.     echo 'glob.c: original size 6378, current size' "$Wc_c"
  1315. rm -f _shar_wnt_.tmp
  1316. fi
  1317. # ============= glob.h ==============
  1318. if test -f 'glob.h' -a X"$1" != X"-c"; then
  1319.     echo 'x - skipping glob.h (File already exists)'
  1320.     rm -f _shar_wnt_.tmp
  1321. else
  1322. > _shar_wnt_.tmp
  1323. echo 'x - extracting glob.h (Text)'
  1324. sed 's/^X//' << 'SHAR_EOF' > 'glob.h' &&
  1325. extern boolean lmatch(List *, List *);
  1326. extern List *glob(List *);
  1327. SHAR_EOF
  1328. chmod 0644 glob.h ||
  1329. echo 'restore of glob.h failed'
  1330. Wc_c="`wc -c < 'glob.h'`"
  1331. test 66 -eq "$Wc_c" ||
  1332.     echo 'glob.h: original size 66, current size' "$Wc_c"
  1333. rm -f _shar_wnt_.tmp
  1334. fi
  1335. # ============= glom.c ==============
  1336. if test -f 'glom.c' -a X"$1" != X"-c"; then
  1337.     echo 'x - skipping glom.c (File already exists)'
  1338.     rm -f _shar_wnt_.tmp
  1339. else
  1340. > _shar_wnt_.tmp
  1341. echo 'x - extracting glom.c (Text)'
  1342. sed 's/^X//' << 'SHAR_EOF' > 'glom.c' &&
  1343. /* glom.c: builds an argument list out of words, variables, etc. */
  1344. X
  1345. #include <sys/types.h>
  1346. #include <sys/stat.h>
  1347. #ifndef S_IFIFO
  1348. #ifndef DEVFD
  1349. #define NOCMDARG
  1350. #endif
  1351. #endif
  1352. #include "rc.h"
  1353. #include "utils.h"
  1354. #include "nalloc.h"
  1355. #include "glom.h"
  1356. #include "hash.h"
  1357. #include "walk.h"
  1358. #include "status.h"
  1359. #include "exec.h"
  1360. #include "lex.h"
  1361. #include "open.h"
  1362. #include "list.h"
  1363. #include "wait.h"
  1364. X
  1365. static List *backq(Node *, Node *);
  1366. static List *bqinput(List *, int);
  1367. static List *count(List *);
  1368. static List *mkcmdarg(Node *);
  1369. X
  1370. Rq *redirq = NULL;
  1371. Fq *fifoq = NULL;
  1372. X
  1373. List *word(char *w, char *m) {
  1374. X    List *s;
  1375. X
  1376. X    if (w == NULL)
  1377. X        return NULL;
  1378. X
  1379. X    s = nnew(List);
  1380. X    s->w = w;
  1381. X    s->m = m;
  1382. X    s->n = NULL;
  1383. X    return s;
  1384. }
  1385. X
  1386. /*
  1387. X   Append list s2 to list s1 by copying s1 and making the new copy
  1388. X   point at s2.
  1389. */
  1390. X
  1391. List *append(List *s1, List *s2) {
  1392. X    List *r, *top;
  1393. X
  1394. X    if (s1 == NULL)
  1395. X        return s2;
  1396. X    if (s2 == NULL)
  1397. X        return s1;
  1398. X
  1399. X    r = top = nnew(List);
  1400. X    while (1) {
  1401. X        r->w = s1->w;
  1402. X        r->m = s1->m;
  1403. X        if ((s1 = s1->n) == NULL)
  1404. X            break;
  1405. X        r = r->n = nnew(List);
  1406. X    }
  1407. X
  1408. X    r->n = s2;
  1409. X
  1410. X    return top;
  1411. }
  1412. X
  1413. List *concat(List *s1, List *s2) {
  1414. X    int n1, n2;
  1415. X    SIZE_T y,z;
  1416. X    List *n, *s;
  1417. X
  1418. X    if (s1 == NULL)
  1419. X        return s2;
  1420. X    if (s2 == NULL)
  1421. X        return s1;
  1422. X
  1423. X    n1 = listnel(s1);
  1424. X    n2 = listnel(s2);
  1425. X
  1426. X    if (n1 != n2 && n1 != 1 && n2 != 1)
  1427. X        rc_error("bad concatenation");
  1428. X
  1429. X    n = s = nnew(List);
  1430. X
  1431. X    while (1) {
  1432. X        z = strlen(s1->w) + strlen(s2->w) + 1;
  1433. X        n->w = nalloc(z);
  1434. X        strcpy(n->w,s1->w);
  1435. X        strcat(n->w,s2->w);
  1436. X        if (s1->m == NULL && s2->m == NULL) {
  1437. X            n->m = NULL;
  1438. X        } else {
  1439. X            n->m = nalloc(z);
  1440. X            y = strlen(s1->w);
  1441. X            if (s1->m == NULL)
  1442. X                clear(n->m, y);
  1443. X            else
  1444. X                memcpy(n->m, s1->m, y);
  1445. X            if (s2->m == NULL)
  1446. X                clear(n->m + y, strlen(s2->w));
  1447. X            else
  1448. X                memcpy(n->m + y, s2->m, strlen(s2->w));
  1449. X            n->m[z] = 0;
  1450. X        }
  1451. X        if (n1 > 1)
  1452. X            s1 = s1->n;
  1453. X        if (n2 > 1)
  1454. X            s2 = s2->n;
  1455. X        if (s1 == NULL || s2 == NULL || (n1 == 1  && n2 == 1)) {
  1456. X            n->n = NULL;
  1457. X            return s;
  1458. X        }
  1459. X        n->n = nnew(List);
  1460. X        n = n->n;
  1461. X    }
  1462. }
  1463. X
  1464. List *varsub(List *v, List *subs) {
  1465. X    int i,j;
  1466. X    int n;
  1467. X    List *r,*s;
  1468. X    List *top,*cat;
  1469. X
  1470. X    n = listnel(v);
  1471. X
  1472. X    top = cat = NULL;
  1473. X
  1474. X    for (s = subs; s != NULL; s = s->n) {
  1475. X        i = a2u(s->w);
  1476. X        if (i < 1)
  1477. X            rc_error("bad subscript");
  1478. X        if (i <= n) {
  1479. X            for (j = 1, r = v; j != i; j++, r = r->n)
  1480. X                ; /* loop until r == v(i) */
  1481. X            if (top == NULL) {
  1482. X                top = cat = nnew(List);
  1483. X            } else {
  1484. X                cat->n = nnew(List);
  1485. X                cat = cat->n;
  1486. X            }
  1487. X            cat->w = r->w;
  1488. X            cat->m = r->m;
  1489. X        }
  1490. X    }
  1491. X
  1492. X    if (top == NULL)
  1493. X        return NULL;
  1494. X
  1495. X    cat->n = NULL;
  1496. X    return top;
  1497. }
  1498. X
  1499. List *flatten(List *s) {
  1500. X    List *r;
  1501. X
  1502. X    if (s == NULL || s->n == NULL)
  1503. X        return s;
  1504. X
  1505. X    r = nnew(List);
  1506. X    r->w = nalloc(listlen(s) + 1);
  1507. X    r->m = NULL; /* flattened lists come from variables, so no meta */
  1508. X    r->n = NULL;
  1509. X
  1510. X    strcpy(r->w, s->w);
  1511. X
  1512. X    do {
  1513. X        s = s->n;
  1514. X        strcat(r->w, " ");
  1515. X        strcat(r->w, s->w);
  1516. X    } while (s->n != NULL);
  1517. X
  1518. X    return r;
  1519. }
  1520. X
  1521. static List *count(List *l) {
  1522. X    List *s = nnew(List);
  1523. X    char buf[16];
  1524. X
  1525. X    s->w = sprint(buf, "%d", listnel(l));
  1526. X    s->w = ncpy(s->w);
  1527. X    s->n = NULL;
  1528. X    s->m = NULL;
  1529. X    return s;
  1530. }
  1531. X
  1532. void assign(List *s1, List *s2, boolean stack) {
  1533. X    List *val = s2;
  1534. X
  1535. X    if (s1 == NULL)
  1536. X        rc_error("null variable name");
  1537. X    if (s1->n != NULL)
  1538. X        rc_error("multi-word variable name");
  1539. X    if (*s1->w == '\0')
  1540. X        rc_error("zero-length variable name");
  1541. X    if (a2u(s1->w) != -1)
  1542. X        rc_error("numeric variable name");
  1543. X    if (strchr(s1->w, '=') != NULL)
  1544. X        rc_error("'=' in variable name");
  1545. X    if (s1->w[0] == '*' && s1->w[1] == '\0')
  1546. X        val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
  1547. X
  1548. X
  1549. X    if (s2 != NULL || stack) {
  1550. X        if (dashex)
  1551. X            prettyprint_var(2, s1->w, val);
  1552. X        varassign(s1->w, val, stack);
  1553. X        alias(s1->w, val, stack);
  1554. X    } else {
  1555. X        if (dashex)
  1556. X            prettyprint_var(2, s1->w, NULL);
  1557. X        varrm(s1->w, stack);
  1558. X    }
  1559. }
  1560. X
  1561. /*
  1562. X   The following two functions are by the courtesy of Paul Haahr,
  1563. X   who could not stand the incompetence of my own backquote implementation.
  1564. */
  1565. X
  1566. #define BUFSIZE    ((SIZE_T) 1000)
  1567. X
  1568. static List *bqinput(List *ifs, int fd) {
  1569. X    char *end, *bufend, *s;
  1570. X    List *r, *top, *prev;
  1571. X    SIZE_T remain, bufsize;
  1572. X    char isifs[256];
  1573. X    int n;
  1574. X    int state; /* a simple FSA is used to read in data */
  1575. X
  1576. X    clear(isifs, sizeof isifs);
  1577. X    isifs['\0'] = 1;
  1578. X    for (r = ifs; r != NULL; r = r->n)
  1579. X        for (s = r->w; *s != '\0'; s++)
  1580. X            isifs[*(unsigned char *)s] = 1;
  1581. X
  1582. X    remain = bufsize = BUFSIZE;
  1583. X    top = r = nnew(List);
  1584. X    r->w = end = nalloc(bufsize + 1);
  1585. X    r->m = NULL;
  1586. X    state = 0;
  1587. X    prev = NULL;
  1588. X
  1589. X    while (1) {
  1590. X        if (remain == 0) { /* is the string bigger than the buffer? */
  1591. X            SIZE_T m = end - r->w;
  1592. X            char *buf;
  1593. X
  1594. X            while (bufsize < m + BUFSIZE)
  1595. X                bufsize *= 2;
  1596. X            buf = nalloc(bufsize + 1);
  1597. X            memcpy(buf, r->w, m);
  1598. X            r->w = buf;
  1599. X            end = &buf[m];
  1600. X            remain = bufsize - m;
  1601. X        }
  1602. X
  1603. X        n = read(fd, end, remain);
  1604. X
  1605. X        if (n <= 0) {
  1606. X            if (n == -1) {
  1607. X                uerror("backquote read");
  1608. X                rc_error(NULL);
  1609. X            }
  1610. X    /* break */    break;
  1611. X        }
  1612. X
  1613. X        remain -= n;
  1614. X
  1615. X        for (bufend = &end[n]; end < bufend; end++)
  1616. X            switch (state) {
  1617. X            case 0:
  1618. X                if (!isifs[*(unsigned char *)end]) {
  1619. X                    state = 1;
  1620. X                    r->w = end;
  1621. X                }
  1622. X                break;
  1623. X            case 1:
  1624. X                if (isifs[*(unsigned char *)end]) {
  1625. X                    state = 0;
  1626. X                    *end = '\0';
  1627. X                    prev = r;
  1628. X                    r = r->n = nnew(List);
  1629. X                    r->w = end+1;
  1630. X                    r->m = NULL;
  1631. X                }
  1632. X                break;
  1633. X            }
  1634. X    }
  1635. X
  1636. X    if (state == 1) { /* terminate last string */
  1637. X        *end = '\0';
  1638. X        r->n = NULL;
  1639. X    } else {
  1640. X        if (prev == NULL) /* no input at all? */
  1641. X            top = NULL;
  1642. X        else
  1643. X            prev->n = NULL; /* else terminate list */
  1644. X    }
  1645. X        
  1646. X    return top;
  1647. }
  1648. X
  1649. static List *backq(Node *ifsnode, Node *n) {
  1650. X    int p[2], pid, sp;
  1651. X    List *result, *ifs;
  1652. X
  1653. X    if (n == NULL)
  1654. X        return NULL;
  1655. X
  1656. X    if (pipe(p) < 0) {
  1657. X        uerror("pipe");
  1658. X        rc_error(NULL);
  1659. X    }
  1660. X
  1661. X    if ((pid = rc_fork()) == 0) {
  1662. X        setsigdefaults();
  1663. X        dup2(p[1],1);
  1664. X        close(p[0]);
  1665. X        close(p[1]);
  1666. X        redirq = NULL;
  1667. X        fifoq = NULL;
  1668. X        walk(n, FALSE);
  1669. X        exit(getstatus());
  1670. X    }
  1671. X
  1672. X    ifs = glom(ifsnode);
  1673. X    close(p[1]);
  1674. X    result = bqinput(ifs, p[0]);
  1675. X    close(p[0]);
  1676. X    rc_wait4(pid, &sp);
  1677. X    statprint(sp);
  1678. X    return result;
  1679. }
  1680. X
  1681. void qredir(Node *n) {
  1682. X    Rq *next;
  1683. X
  1684. X    if (redirq == NULL) {
  1685. X        next = redirq = nnew(Rq);
  1686. X    } else {
  1687. X        for (next = redirq; next->n != NULL; next = next->n)
  1688. X            ;
  1689. X        next->n = nnew(Rq);
  1690. X        next = next->n;
  1691. X    }
  1692. X
  1693. X    next->r = n;
  1694. X    next->n = NULL;
  1695. }
  1696. X
  1697. #ifdef NOCMDARG
  1698. static List *mkcmdarg(Node *n) {
  1699. X    rc_error("named pipes are not supported");
  1700. X    return NULL;
  1701. }
  1702. #else
  1703. #ifndef DEVFD
  1704. static List *mkcmdarg(Node *n) {
  1705. X    int fd, pid;
  1706. X    char *name, buf[32];
  1707. X    List *ret = nnew(List);
  1708. X    Fq *f = nnew(Fq);
  1709. X    static int fifonumber = 0;
  1710. X
  1711. X    name = sprint(buf,"/tmp/rc%d.%d", getpid(), fifonumber++);
  1712. X    name = ncpy(name);
  1713. X
  1714. X    if (mknod(name, S_IFIFO | 0644, 0) < 0) {
  1715. X        uerror("mknod");
  1716. X        return NULL;
  1717. X    }
  1718. X
  1719. X    if ((pid = rc_fork()) == 0) {
  1720. X        setsigdefaults();
  1721. X        /* fd = rc_open(name, CREATE); */
  1722. X        fd = rc_open(name, (n->u[0].i != FROM) ? FROM : CREATE); /* stupid hack */
  1723. X        if (fd < 0) {
  1724. X            uerror("open");
  1725. X            exit(1);
  1726. X        }
  1727. X        if (dup2(fd, (n->u[0].i == FROM)) < 0) { /* same stupid hack */
  1728. X            uerror("dup2");
  1729. X            exit(1);
  1730. X        }
  1731. X        close(fd);
  1732. X        redirq = NULL;
  1733. X        fifoq = NULL;
  1734. X        walk(n->u[2].p, FALSE);
  1735. X        exit(getstatus());
  1736. X    }
  1737. X
  1738. X    f->pid = pid;
  1739. X    f->name = name;
  1740. X    f->n = fifoq;
  1741. X    fifoq = f;
  1742. X
  1743. X    ret->w = name;
  1744. X    ret->m = NULL;
  1745. X    ret->n = NULL;
  1746. X
  1747. X    return ret;
  1748. }
  1749. #else
  1750. static List *mkcmdarg(Node *n) {
  1751. X    char *name, buf[32];
  1752. X    List *ret = nnew(List);
  1753. X    int p[2];
  1754. X
  1755. X    if (pipe(p) < 0) {
  1756. X        uerror("pipe");
  1757. X        return NULL;
  1758. X    }
  1759. X
  1760. X    if (rc_fork() == 0) {
  1761. X        setsigdefaults();
  1762. X
  1763. X        if (dup2(p[n->u[0].i == FROM], n->u[0].i == FROM) < 0) { /* stupid hack */
  1764. X            uerror("dup2");
  1765. X            exit(1);
  1766. X        }
  1767. X        close(p[n->u[0].i != FROM]);
  1768. X
  1769. X        redirq = NULL;
  1770. X        walk(n->u[2].p, FALSE);
  1771. X        exit(getstatus());
  1772. X    }
  1773. X
  1774. X    name = sprint(buf, "/dev/fd/%d", p[n->u[0].i != FROM]);
  1775. X    name = ncpy(name); /* ncpy evaluates the expression twice */
  1776. X    ret->w = name;
  1777. X    ret->m = NULL;
  1778. X    ret->n = NULL;
  1779. X
  1780. X    close(p[n->u[0].i == FROM]);
  1781. X
  1782. X    return ret;
  1783. }
  1784. #endif /* DEVFD */
  1785. #endif /* !NOCMDARG */
  1786. X
  1787. List *glom(Node *n) {
  1788. X    Node *words;
  1789. X    List *v, *first, *last;
  1790. X    boolean dollarstar;
  1791. X
  1792. X    if (n == NULL)
  1793. X        return NULL;
  1794. X
  1795. X    switch (n->type) {
  1796. X    case ARGS:
  1797. X    case LAPPEND:
  1798. X        words = n->u[0].p;
  1799. X        last = NULL;
  1800. X        while (words != NULL && (words->type == ARGS || words->type == LAPPEND)) {
  1801. X            if (words->u[1].p != NULL && words->u[1].p->type != rWORD && words->u[1].p->type != QWORD)
  1802. X                break;
  1803. X            first = glom(words->u[1].p);
  1804. X            if (first != NULL) {
  1805. X                first->n = last;
  1806. X                last = first;
  1807. X            }
  1808. X            words = words->u[0].p;
  1809. X        }
  1810. X        v = append(glom(words), last); /* force left to right evaluation */
  1811. X        return append(v, glom(n->u[1].p));
  1812. X    case BACKQ:
  1813. X        return backq(n->u[0].p,n->u[1].p);
  1814. X    case CONCAT:
  1815. X        first = glom(n->u[0].p); /* force left-to-right evaluation */
  1816. X        return concat(first, glom(n->u[1].p));
  1817. X    case rDUP:
  1818. X    case rREDIR:
  1819. X        qredir(n);
  1820. X        return NULL;
  1821. X    case rWORD: case QWORD:
  1822. X        return word(n->u[0].s,n->u[1].s);
  1823. X    case NMPIPE:
  1824. X        return mkcmdarg(n);
  1825. X    default:
  1826. X        break;
  1827. X    }
  1828. X
  1829. X    /*
  1830. X           the next three operations depend on the left-child of glom
  1831. X       to be a variable name. Therefore they are all treated here.
  1832. X       (previously each function looked up and checked the validity
  1833. X       of a variable name)
  1834. X    */
  1835. X
  1836. X    v = glom(n->u[0].p);
  1837. X    if (v == NULL)
  1838. X        rc_error("null variable name");
  1839. X    if (v->n != NULL)
  1840. X        rc_error("multi-word variable name");
  1841. X    if (*v->w == '\0')
  1842. X        rc_error("zero-length variable name");
  1843. X
  1844. X    dollarstar = (v->w[0] == '*' && v->w[1] == '\0');
  1845. X    v = varlookup(v->w);
  1846. X    if (dollarstar)
  1847. X        v = v->n;
  1848. X
  1849. X    switch (n->type) {
  1850. X    default:
  1851. X        fprint(2,"glom: this can't happen\n");
  1852. X        exit(1);
  1853. X        /* NOTREACHED */
  1854. X    case rCOUNT:
  1855. X        return count(v);
  1856. X    case rFLAT:
  1857. X        return flatten(v);
  1858. X    case VAR:
  1859. X        return v;
  1860. X    case VARSUB:
  1861. X        return varsub(v, glom(n->u[1].p));
  1862. X    }
  1863. X
  1864. }
  1865. SHAR_EOF
  1866. chmod 0644 glom.c ||
  1867. echo 'restore of glom.c failed'
  1868. Wc_c="`wc -c < 'glom.c'`"
  1869. test 9512 -eq "$Wc_c" ||
  1870.     echo 'glom.c: original size 9512, current size' "$Wc_c"
  1871. rm -f _shar_wnt_.tmp
  1872. fi
  1873. # ============= glom.h ==============
  1874. if test -f 'glom.h' -a X"$1" != X"-c"; then
  1875.     echo 'x - skipping glom.h (File already exists)'
  1876.     rm -f _shar_wnt_.tmp
  1877. else
  1878. > _shar_wnt_.tmp
  1879. echo 'x - extracting glom.h (Text)'
  1880. sed 's/^X//' << 'SHAR_EOF' > 'glom.h' &&
  1881. extern void assign(List *, List *, boolean);
  1882. extern void qredir(Node *);
  1883. extern List *append(List *, List*);
  1884. extern List *flatten(List *);
  1885. extern List *glom(Node *);
  1886. extern List *concat(List *, List *);
  1887. extern List *varsub(List *, List *);
  1888. extern List *word(char *, char *);
  1889. X
  1890. struct Fq {
  1891. X    int pid;
  1892. X    char *name;
  1893. X    Fq *n;
  1894. };
  1895. SHAR_EOF
  1896. chmod 0644 glom.h ||
  1897. echo 'restore of glom.h failed'
  1898. Wc_c="`wc -c < 'glom.h'`"
  1899. test 322 -eq "$Wc_c" ||
  1900.     echo 'glom.h: original size 322, current size' "$Wc_c"
  1901. rm -f _shar_wnt_.tmp
  1902. fi
  1903. # ============= hash.c ==============
  1904. if test -f 'hash.c' -a X"$1" != X"-c"; then
  1905.     echo 'x - skipping hash.c (File already exists)'
  1906.     rm -f _shar_wnt_.tmp
  1907. else
  1908. > _shar_wnt_.tmp
  1909. echo 'x - extracting hash.c (Text)'
  1910. sed 's/^X//' << 'SHAR_EOF' > 'hash.c' &&
  1911. /* hash.c: hash table support for functions and variables. */
  1912. X
  1913. /*
  1914. X   functions and variables are cached in both internal and external
  1915. X   form for performance. Thus a variable which is never "dereferenced"
  1916. X   with a $ is passed on to rc's children untouched. This is not so
  1917. X   important for variables, but is a big win for functions, where a call
  1918. X   to yyparse() is involved.
  1919. */
  1920. X
  1921. #include "rc.h"
  1922. #include "utils.h"
  1923. #include "hash.h"
  1924. #include "list.h"
  1925. #include "tree.h"
  1926. #include "footobar.h"
  1927. #include "sigmsgs.h"
  1928. X
  1929. static boolean var_exportable(char *);
  1930. static boolean fn_exportable(char *);
  1931. static int hash(char *, int);
  1932. static int find(char *, Htab *, int);
  1933. static void free_fn(Function *);
  1934. X
  1935. Htab *fp;
  1936. Htab *vp;
  1937. static int fused, fsize, vused, vsize;
  1938. static char **env;
  1939. static int bozosize;
  1940. static int envsize;
  1941. static boolean env_dirty = TRUE;
  1942. static char *dead = "";
  1943. X
  1944. #define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
  1945. X
  1946. void inithash() {
  1947. X    int i;
  1948. X    Htab *fpp, *vpp;
  1949. X
  1950. X    fp = ealloc(sizeof(Htab) * HASHSIZE);
  1951. X    vp = ealloc(sizeof(Htab) * HASHSIZE);
  1952. X    fused = vused = 0;
  1953. X    fsize = vsize = HASHSIZE;
  1954. X
  1955. X    for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++)
  1956. X        vpp->name = fpp->name = NULL;
  1957. }
  1958. X
  1959. #define ADV()   {if ((c = *s++) == '\0') break;}
  1960. X
  1961. /* hash function courtesy of paul haahr */
  1962. X
  1963. static int hash(char *s, int size) {
  1964. X    int n = 0;
  1965. X    int c;
  1966. X
  1967. X    while (1) {
  1968. X        ADV();
  1969. X        n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
  1970. X        ADV();
  1971. X        n ^= (c << 14) + (c << 7) + (c << 4) + c;
  1972. X        ADV();
  1973. X        n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
  1974. X        ADV();
  1975. X        n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
  1976. X    }
  1977. X
  1978. X    if (n < 0)
  1979. X        n = ~n;
  1980. X
  1981. X    return n & (size - 1); /* need power of 2 size */
  1982. }
  1983. X
  1984. static boolean rehash(Htab *ht) {
  1985. X    int i,j,size;
  1986. X    int newsize,newused;
  1987. X    Htab *newhtab;
  1988. X
  1989. X    if (ht == fp) {
  1990. X        if (fsize > 2 * fused)
  1991. X            return FALSE;
  1992. X        size = fsize;
  1993. X    } else {
  1994. X        if (vsize > 2 * vused)
  1995. X            return FALSE;
  1996. X        size = vsize;
  1997. X    }
  1998. X
  1999. X
  2000. X    newsize = 2 * size;
  2001. X    newhtab = ealloc(newsize * sizeof(Htab));
  2002. X    for (i = 0; i < newsize; i++)
  2003. X        newhtab[i].name = NULL;
  2004. X
  2005. X    for (i = newused = 0; i < size; i++)
  2006. X        if (ht[i].name != NULL && ht[i].name != dead) {
  2007. X            newused++;
  2008. X            j = hash(ht[i].name, newsize);
  2009. X            while (newhtab[j].name != NULL) {
  2010. X                j++;
  2011. X                j &= (newsize - 1);
  2012. X            }
  2013. X            newhtab[j].name = ht[i].name;
  2014. X            newhtab[j].p = ht[i].p;
  2015. X        }
  2016. X
  2017. X    if (ht == fp) {
  2018. X        fused = newused;
  2019. X        fp = newhtab;
  2020. X        fsize = newsize;
  2021. X    } else {
  2022. X        vused = newused;
  2023. X        vp = newhtab;
  2024. X        vsize = newsize;
  2025. X    }
  2026. X
  2027. X    efree(ht);
  2028. X    return TRUE;
  2029. }
  2030. X
  2031. #define varfind(s) find(s,vp,vsize)
  2032. #define fnfind(s) find(s,fp,fsize)
  2033. X
  2034. static int find(char *s, Htab *ht, int size) {
  2035. X    int h = hash(s, size);
  2036. X
  2037. X    while (ht[h].name != NULL && !streq(ht[h].name,s)) {
  2038. X        h++;
  2039. X        h &= size - 1;
  2040. X    }
  2041. X
  2042. X    return h;
  2043. }
  2044. X
  2045. void *lookup(char *s, Htab *ht) {
  2046. X    int h = find(s, ht, ht == fp ? fsize : vsize);
  2047. X
  2048. X    return (ht[h].name == NULL) ? NULL : ht[h].p;
  2049. }
  2050. X
  2051. Function *get_fn_place(char *s) {
  2052. X    int h = fnfind(s);
  2053. X
  2054. X    env_dirty = TRUE;
  2055. X
  2056. X    if (fp[h].name == NULL) {
  2057. X        if (rehash(fp))
  2058. X            h = fnfind(s);
  2059. X        fused++;
  2060. X        fp[h].name = ecpy(s);
  2061. X        fp[h].p = enew(Function);
  2062. X    } else
  2063. X        free_fn(fp[h].p);
  2064. X
  2065. X    return fp[h].p;
  2066. }
  2067. X
  2068. Variable *get_var_place(char *s, boolean stack) {
  2069. X    Variable *new;
  2070. X    int h = varfind(s);
  2071. X
  2072. X    env_dirty = TRUE;
  2073. X
  2074. X    if (vp[h].name == NULL) {
  2075. X        if (rehash(vp))
  2076. X            h = varfind(s);
  2077. X        vused++;
  2078. X        vp[h].name = ecpy(s);
  2079. X        vp[h].p = enew(Variable);
  2080. X        ((Variable *)vp[h].p)->n = NULL;
  2081. X        return vp[h].p;
  2082. X    } else {
  2083. X        if (stack) {    /* increase the stack by 1 */
  2084. X            new = enew(Variable);
  2085. X            new->n = vp[h].p;
  2086. X            return vp[h].p = new;
  2087. X        } else {    /* trample the top of the stack */
  2088. X            new = vp[h].p;
  2089. X            efree(new->extdef);
  2090. X            listfree(new->def);
  2091. X            return new;
  2092. X        }
  2093. X    }
  2094. }
  2095. X
  2096. void delete_fn(char *s) {
  2097. X    int h = fnfind(s);
  2098. X
  2099. X    if (fp[h].name == NULL)
  2100. X        return; /* not found */
  2101. X
  2102. X    env_dirty = TRUE;
  2103. X
  2104. X    free_fn(fp[h].p);
  2105. X    efree(fp[h].p);
  2106. X    efree(fp[h].name);
  2107. X    if (fp[(h+1)&(fsize-1)].name == NULL) {
  2108. X        --fused;
  2109. X        fp[h].name = NULL;
  2110. X    } else {
  2111. X        fp[h].name = dead;
  2112. X    }
  2113. }
  2114. X
  2115. void delete_var(char *s, boolean stack) {
  2116. X    int h = varfind(s);
  2117. X    Variable *v;
  2118. X
  2119. X    if (vp[h].name == NULL)
  2120. X        return; /* not found */
  2121. X
  2122. X    env_dirty = TRUE;
  2123. X
  2124. X    v = vp[h].p;
  2125. X    efree(v->extdef);
  2126. X    listfree(v->def);
  2127. X
  2128. X    if (v->n != NULL) { /* This is the top of a stack */
  2129. X        if (stack) { /* pop */
  2130. X            vp[h].p = v->n;
  2131. X            efree(v);
  2132. X        } else { /* else just empty */
  2133. X            v->extdef = NULL;
  2134. X            v->def = NULL;
  2135. X        }
  2136. X    } else { /* needs to be removed from the hash table */
  2137. X        efree(v);
  2138. X        efree(vp[h].name);
  2139. X        if (vp[(h+1)&(vsize-1)].name == NULL) {
  2140. X            --vused;
  2141. X            vp[h].name = NULL;
  2142. X        } else {
  2143. X            vp[h].name = dead;
  2144. X        }
  2145. X    }
  2146. }
  2147. X
  2148. static void free_fn(Function *f) {
  2149. X    treefree(f->def);
  2150. X    efree(f->extdef);
  2151. }
  2152. X
  2153. void initenv(char **envp) {
  2154. X    int n;
  2155. X
  2156. X    for (n = 0; envp[n] != NULL; n++)
  2157. X        ;
  2158. X    n++; /* one for the null terminator */
  2159. X
  2160. X    if (n < HASHSIZE)
  2161. X        n = HASHSIZE;
  2162. X
  2163. X    env = ealloc((envsize = 2 * n) * sizeof (char *));
  2164. X
  2165. X    for (; *envp != NULL; envp++)
  2166. X        if (strncmp(*envp, "fn_", sizeof("fn_") - 1) == 0)
  2167. X            fnassign_string(*envp);
  2168. X        else
  2169. X            if (!varassign_string(*envp)) /* add to bozo env */
  2170. X                env[bozosize++] = *envp;
  2171. }
  2172. X
  2173. static boolean var_exportable(char *s) {
  2174. X    int i;
  2175. X    static char *notforexport[] = {
  2176. X        "apid", "pid", "apids", "*", "ifs"
  2177. X    };
  2178. X
  2179. X    for (i = 0; i < arraysize(notforexport); i++)
  2180. X        if (streq(s,notforexport[i]))
  2181. X            return FALSE;
  2182. X
  2183. X    return TRUE;
  2184. }
  2185. X
  2186. static boolean fn_exportable(char *s) {
  2187. X    int i;
  2188. X
  2189. X    if (strncmp(s,"sig",3) == 0) { /* small speed hack */
  2190. X        for (i = 0; i < NUMOFSIGNALS; i++)
  2191. X            if (streq(s, signals[i][0]))
  2192. X                return FALSE;
  2193. X
  2194. X        if (streq(s, "sigexit"))
  2195. X            return FALSE;
  2196. X    }
  2197. X
  2198. X    return TRUE;
  2199. }
  2200. X
  2201. char **makeenv() {
  2202. X    int ep, i;
  2203. X    char *v;
  2204. X
  2205. X    if (!env_dirty)
  2206. X        return env;
  2207. X
  2208. X    env_dirty = FALSE;
  2209. X    ep = bozosize;
  2210. X
  2211. X    if (vsize + fsize + 1 + bozosize > envsize) {
  2212. X        envsize = 2 * (bozosize + vsize + fsize + 1);
  2213. X        env = erealloc(env, envsize * sizeof(char *));
  2214. X    }
  2215. X
  2216. X    for (i = 0; i < vsize; i++) {
  2217. X        if (vp[i].name == NULL || vp[i].name == dead || !var_exportable(vp[i].name))
  2218. X            continue;
  2219. X        v = varlookup_string(vp[i].name);
  2220. X        if (v != NULL)
  2221. X            env[ep++] = v;
  2222. X    }
  2223. X    for (i = 0; i < fsize; i++) {
  2224. X        if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name))
  2225. X            continue;
  2226. X        env[ep++] = fnlookup_string(fp[i].name);
  2227. X    }
  2228. X    env[ep] = NULL;
  2229. X    qsort(env, ep, sizeof(char *), starstrcmp);
  2230. X    return env;
  2231. }
  2232. X
  2233. void whatare_all_vars() {
  2234. X    int i;
  2235. X    List *s;
  2236. X
  2237. X    for (i = 0; i < vsize; i++)
  2238. X        if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
  2239. X            prettyprint_var(1, vp[i].name, s);
  2240. X
  2241. X    for (i = 0; i < fsize; i++)
  2242. X        if (fp[i].name != NULL)
  2243. X            prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
  2244. }
  2245. X
  2246. /* fake getenv() for readline() follows: */
  2247. X
  2248. #ifdef READLINE
  2249. char *getenv(const char *name) {
  2250. X    List *s;
  2251. X
  2252. X    if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL)
  2253. X        return NULL;
  2254. X
  2255. X    return s->w;
  2256. }
  2257. #endif
  2258. X
  2259. SHAR_EOF
  2260. chmod 0644 hash.c ||
  2261. echo 'restore of hash.c failed'
  2262. Wc_c="`wc -c < 'hash.c'`"
  2263. test 6760 -eq "$Wc_c" ||
  2264.     echo 'hash.c: original size 6760, current size' "$Wc_c"
  2265. rm -f _shar_wnt_.tmp
  2266. fi
  2267. # ============= hash.h ==============
  2268. if test -f 'hash.h' -a X"$1" != X"-c"; then
  2269.     echo 'x - skipping hash.h (File already exists)'
  2270.     rm -f _shar_wnt_.tmp
  2271. else
  2272. > _shar_wnt_.tmp
  2273. echo 'x - extracting hash.h (Text)'
  2274. sed 's/^X//' << 'SHAR_EOF' > 'hash.h' &&
  2275. typedef struct Function {
  2276. X    Node *def;
  2277. X    char *extdef;
  2278. } Function;
  2279. X
  2280. typedef struct Variable {
  2281. X    List *def;
  2282. X    char *extdef;
  2283. X    struct Variable *n;
  2284. } Variable;
  2285. X
  2286. typedef struct Htab {
  2287. X    char *name;
  2288. X    void *p;
  2289. } Htab;
  2290. X
  2291. extern Htab *fp, *vp;
  2292. X
  2293. #define lookup_fn(s) ((Function *) lookup(s,fp))
  2294. #define lookup_var(s) ((Variable *) lookup(s,vp))
  2295. X
  2296. extern void *lookup(char *, Htab *);
  2297. extern Function *get_fn_place(char *);
  2298. extern List *varlookup(char *);
  2299. extern Node *fnlookup(char *);
  2300. extern Variable *get_var_place(char *, boolean);
  2301. extern boolean varassign_string(char *);
  2302. extern char **makeenv(void);
  2303. extern char *fnlookup_string(char *);
  2304. extern char *varlookup_string(char *);
  2305. extern void alias(char *, List *, boolean);
  2306. extern void starassign(char *, char **, boolean);
  2307. extern void delete_fn(char *);
  2308. extern void delete_var(char *, boolean);
  2309. extern void fnassign(char *, Node *);
  2310. extern void fnassign_string(char *);
  2311. extern void fnrm(char *);
  2312. extern void initenv(char **);
  2313. extern void inithash(void);
  2314. extern void setsigdefaults(void);
  2315. extern void inithandler(void);
  2316. extern void varassign(char *, List *, boolean);
  2317. extern void varrm(char *, boolean);
  2318. extern void whatare_all_vars(void);
  2319. extern void whatare_all_signals(void);
  2320. extern void prettyprint_var(int, char *, List *);
  2321. extern void prettyprint_fn(int, char *, Node *);
  2322. SHAR_EOF
  2323. chmod 0644 hash.h ||
  2324. echo 'restore of hash.h failed'
  2325. Wc_c="`wc -c < 'hash.h'`"
  2326. test 1313 -eq "$Wc_c" ||
  2327.     echo 'hash.h: original size 1313, current size' "$Wc_c"
  2328. rm -f _shar_wnt_.tmp
  2329. fi
  2330. # ============= heredoc.c ==============
  2331. if test -f 'heredoc.c' -a X"$1" != X"-c"; then
  2332.     echo 'x - skipping heredoc.c (File already exists)'
  2333.     rm -f _shar_wnt_.tmp
  2334. else
  2335. > _shar_wnt_.tmp
  2336. echo 'x - extracting heredoc.c (Text)'
  2337. sed 's/^X//' << 'SHAR_EOF' > 'heredoc.c' &&
  2338. /* heredoc.c: heredoc slurping is done here */
  2339. X
  2340. #include "rc.h"
  2341. #include "lex.h"
  2342. #include "utils.h"
  2343. #include "nalloc.h"
  2344. #include "heredoc.h"
  2345. #include "tree.h"
  2346. #include "input.h"
  2347. #include "hash.h"
  2348. #include "glom.h"
  2349. X
  2350. struct Hq {
  2351. X    Node *doc;
  2352. X    char *name;
  2353. X    Hq *n;
  2354. X    boolean quoted;
  2355. } *hq;
  2356. X
  2357. static boolean dead = FALSE;
  2358. X
  2359. /*
  2360. X * read in a heredocument. A clever trick: skip over any partially matched end-of-file
  2361. X * marker storing only the number of characters matched. If the whole marker is matched,
  2362. X * return from readheredoc(). If only part of the marker is matched, copy that part into
  2363. X * the heredocument.
  2364. X *
  2365. X * BUG: if the eof string contains a newline, the state can get confused, and the
  2366. X * heredoc may continue past where it should.  on the other hand, /bin/sh seems to
  2367. X * never get out of its readheredoc() when the heredoc string contains a newline
  2368. X */
  2369. X
  2370. static char *readheredoc(char *eof) {
  2371. X    int c;
  2372. X    char *t, *buf, *bufend;
  2373. X    unsigned char *s;
  2374. X    SIZE_T bufsize;
  2375. X
  2376. X    t = buf = nalloc(bufsize = 512);
  2377. X    bufend = &buf[bufsize];
  2378. X    dead = FALSE;
  2379. X
  2380. #define    RESIZE(extra) { \
  2381. X        char *nbuf; \
  2382. X        bufsize = bufsize * 2 + extra; \
  2383. X        nbuf = nalloc(bufsize); \
  2384. X        memcpy(nbuf, buf, t - buf); \
  2385. X        t = nbuf + (t - buf); \
  2386. X        buf = nbuf; \
  2387. X        bufend = &buf[bufsize]; \
  2388. X    }
  2389. X    
  2390. X    for (;;) {
  2391. X        print_prompt2();
  2392. X        for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
  2393. X            ;
  2394. X        if (*s == '\0' && (c == '\n' || c == EOF)) {
  2395. X            *t++ = '\0';
  2396. X            return buf;
  2397. X        }
  2398. X        if (s != (unsigned char *) eof) {
  2399. X            SIZE_T len = s - (unsigned char *) eof;
  2400. X            if (t + len >= bufend)
  2401. X                RESIZE(len);
  2402. X            memcpy(t, eof, len);
  2403. X            t += len;
  2404. X        }
  2405. X        for (;; c = gchar()) {
  2406. X            if (c == EOF) {
  2407. X                yyerror("EOF inside heredoc");
  2408. X                dead = TRUE;
  2409. X                return NULL;
  2410. X            }
  2411. X            if (t + 1 >= bufend)
  2412. X                RESIZE(0);
  2413. X            *t++ = c;
  2414. X            if (c == '\n')
  2415. X                break;
  2416. X        }
  2417. X    }
  2418. }
  2419. X
  2420. /* parseheredoc -- turn a heredoc with variable references into a node chain */
  2421. X
  2422. static Node *parseheredoc(char *s) {
  2423. X    int c = *s;
  2424. X    Node *result = NULL;
  2425. X
  2426. X    while (TRUE) {
  2427. X        Node *node;
  2428. X
  2429. X        switch (c) {
  2430. X        default: {
  2431. X            char *begin = s;
  2432. X            while ((c = *s++) != '\0' && c != '$')
  2433. X                ;
  2434. X            *--s = '\0';
  2435. X            node = newnode(QWORD, begin, NULL);
  2436. X            break;
  2437. X        }
  2438. X        case '$': {
  2439. X            char *begin = ++s, *var;
  2440. X            c = *s++;
  2441. X            if (c == '$') {
  2442. X                node = newnode(QWORD, "$", NULL);
  2443. X                c = *s;
  2444. X            } else {
  2445. X                int len = 0;
  2446. X                do
  2447. X                    len++;
  2448. X                while (!dnw[c = *(unsigned char *) s++]);
  2449. X                if (c == '^')
  2450. X                    c = *s;
  2451. X                else
  2452. X                    s--;
  2453. X                var = nalloc(len + 1);
  2454. X                var[len] = '\0';
  2455. X                memcpy(var, begin, len);
  2456. X                node = newnode(rFLAT, newnode(rWORD, var, NULL));
  2457. X            }
  2458. X            break;
  2459. X        }
  2460. X        case '\0':
  2461. X            return result;
  2462. X        }
  2463. X
  2464. X        result = (result == NULL) ? node : newnode(CONCAT, result, node);
  2465. X    }
  2466. }
  2467. X
  2468. /* read in heredocs when yyparse hits a newline. called from yyparse */
  2469. X
  2470. int heredoc(int end) {
  2471. X    Hq *here;
  2472. X
  2473. X    if ((here = hq) != NULL) {
  2474. X        hq = NULL;
  2475. X        if (end) {
  2476. X            yyerror("EOF on command line with heredoc");
  2477. X            return FALSE;
  2478. X        }
  2479. X        do {
  2480. X            Node *n = here->doc;
  2481. X            char *s = readheredoc(here->name);
  2482. X            if (dead)
  2483. X                return FALSE;
  2484. X            n->u[2].p = here->quoted ? newnode(QWORD, s, NULL) : parseheredoc(s);
  2485. X            n->u[0].i = HERESTRING;
  2486. X        } while ((here = here->n) != NULL);
  2487. X    }
  2488. X    return TRUE;
  2489. }
  2490. X
  2491. /* queue pending heredocs into a queue. called from yyparse */
  2492. X
  2493. int qdoc(Node *name, Node *n) {
  2494. X    Hq *new, **prev;
  2495. X
  2496. X    if (name->type != rWORD && name->type != QWORD) {
  2497. X        yyerror("eof-marker must be a single literal word");
  2498. X        flushu();
  2499. X        return FALSE;
  2500. X    }
  2501. X
  2502. X    for (prev = &hq; (new = *prev) != NULL; prev = &new->n)
  2503. X        ;
  2504. X    *prev = new = nnew(Hq);
  2505. X
  2506. X    new->name = name->u[0].s;
  2507. X    new->quoted = (name->type == QWORD);
  2508. X    new->doc = n;
  2509. X    new->n = NULL;
  2510. X    return TRUE;
  2511. }
  2512. SHAR_EOF
  2513. chmod 0644 heredoc.c ||
  2514. echo 'restore of heredoc.c failed'
  2515. Wc_c="`wc -c < 'heredoc.c'`"
  2516. test 3622 -eq "$Wc_c" ||
  2517.     echo 'heredoc.c: original size 3622, current size' "$Wc_c"
  2518. rm -f _shar_wnt_.tmp
  2519. fi
  2520. # ============= heredoc.h ==============
  2521. if test -f 'heredoc.h' -a X"$1" != X"-c"; then
  2522.     echo 'x - skipping heredoc.h (File already exists)'
  2523.     rm -f _shar_wnt_.tmp
  2524. else
  2525. > _shar_wnt_.tmp
  2526. echo 'x - extracting heredoc.h (Text)'
  2527. sed 's/^X//' << 'SHAR_EOF' > 'heredoc.h' &&
  2528. extern int heredoc(int);
  2529. extern int qdoc(Node *, Node *);
  2530. X
  2531. typedef struct Hq Hq;
  2532. X
  2533. extern Hq *hq;
  2534. SHAR_EOF
  2535. chmod 0644 heredoc.h ||
  2536. echo 'restore of heredoc.h failed'
  2537. Wc_c="`wc -c < 'heredoc.h'`"
  2538. test 97 -eq "$Wc_c" ||
  2539.     echo 'heredoc.h: original size 97, current size' "$Wc_c"
  2540. rm -f _shar_wnt_.tmp
  2541. fi
  2542. # ============= hfix.awk ==============
  2543. if test -f 'hfix.awk' -a X"$1" != X"-c"; then
  2544.     echo 'x - skipping hfix.awk (File already exists)'
  2545.     rm -f _shar_wnt_.tmp
  2546. else
  2547. > _shar_wnt_.tmp
  2548. echo 'x - extracting hfix.awk (Text)'
  2549. sed 's/^X//' << 'SHAR_EOF' > 'hfix.awk' &&
  2550. /^extern void b_exec\(char \*\*\), funcall\(char \*\*\), b_dot\(char \*\*\), b_builtin\(char \*\*\);$/ {
  2551. SHAR_EOF
  2552. true || echo 'restore of hfix.awk failed'
  2553. fi
  2554. echo 'End of  part 2'
  2555. echo 'File hfix.awk is continued in part 3'
  2556. echo 3 > _shar_seq_.tmp
  2557. exit 0
  2558. exit 0 # Just in case...
  2559. -- 
  2560. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2561. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2562. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2563. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2564.