home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume30 / rc / part05 < prev    next >
Encoding:
Text File  |  1992-05-29  |  60.6 KB  |  2,335 lines

  1. Newsgroups: comp.sources.misc
  2. From: byron@archone.tamu.edu (Byron Rakitzis)
  3. Subject:  v30i028:  rc - A Plan 9 shell reimplementation, v1.4, Part05/07
  4. Message-ID: <1992May30.031709.5529@sparky.imd.sterling.com>
  5. X-Md4-Signature: 474125028d94776fa000cf213810a3b6
  6. Date: Sat, 30 May 1992 03:17:09 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
  10. Posting-number: Volume 30, Issue 28
  11. Archive-name: rc/part05
  12. Environment: UNIX
  13. Supersedes: rc: Volume 23, Issue 61-66
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  20. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  21. # Contents:  CHANGES fn.c glob.c heredoc.c history/history.1
  22. #   history/history.c parse.y rc.h var.c version.c
  23. # Wrapped by kent@sparky on Fri May 29 20:55:24 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 5 (of 7)."'
  27. if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'CHANGES'\"
  29. else
  30.   echo shar: Extracting \"'CHANGES'\" \(5591 characters\)
  31.   sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
  32. XChanges since 1.2: (Too many to count!)
  33. X
  34. XA memory stomping bug was fixed (provoked by assigning a variable
  35. Xto its old value plus something else).
  36. X
  37. XBetter signal handling; a real signal handler which manages a queue
  38. Xof pending signals was added.
  39. X
  40. Xrc now ignores SIGQUIT and traps SIGINT even in non-interactive
  41. Xmode. Thus,
  42. X
  43. X    rc ed.sh
  44. X
  45. Xwill not do mysterious things if the shell script "ed.sh" calls a
  46. Xcommand like "ed" and then you hit ^C.
  47. X
  48. Xrc now opens 0, 1, 2 on /dev/null if they are inherited closed.
  49. Xrc -o prevents this.
  50. X
  51. XA couple of stupid O(n^2) string appends were replaced with O(n)
  52. Xloops. This should make foo=`{cat /etc/termcap} bar=$^foo a little
  53. Xfaster :-)
  54. X
  55. XReturning a list of signals from a function is now legal, so "return
  56. X$status" should always work.
  57. X
  58. XThe code has been revised, new printing routines have been added.
  59. X
  60. Xrc no longer uses redundant braces when exporting functions.
  61. X
  62. XA first stab at a verification suite has been added (trip.rc).
  63. X(someone, please help me make this comprehensive!)
  64. X
  65. Xrc -p now does not initialize functions from the environment. This
  66. Xshould make it easier to write shell scripts that don't need to
  67. Xassume anything about the environment.
  68. X
  69. XInherited ignored signals are now ignored in the current shell and
  70. Xpassed on ignored to the child processes. whatis -s also reflects
  71. Xthis information.
  72. X
  73. XA file descriptor leak in the /dev/fd implementation of >{} was
  74. Xfixed.
  75. X
  76. XA variable set to '' was not imported from the environment; this
  77. Xhas been fixed.
  78. X
  79. XChanges since 1.3beta:
  80. X
  81. XNew Makefile/config.h setup.
  82. X
  83. Xbuiltin echo may now be conditionally included out, to use a Goldwynism.
  84. X
  85. Xbuiltin exit takes any legal exit status. If the status is not all zeros,
  86. Xrc exits with 1. (having "exit sigiot" produce a core dump would be going
  87. Xa little far, I think.)
  88. X
  89. Xlimit does not append a unit after a zero limit; 0g was too confusing.
  90. X
  91. Xexec > /nonexistentfile does not cause rc to exit any more.
  92. X
  93. XIf a noninteractive rc is started with sigint ignored, rc does not install
  94. Xits own signal handler.
  95. X
  96. Xerror messages produced by rc in a subshell were cleaned up. (rc erroneously
  97. Xreset the 'interactive' flag after a fork)
  98. X
  99. Xprint.c was cleaned up a little; no functionality was changed, but should
  100. Xbe more portable now.
  101. X
  102. Xa bug in rc-1.3beta (not previous versions) was fixed: setting the first
  103. Xelement of $path to '' caused PATH to be exported as '':etc..
  104. X
  105. Xgetopt's "illegal option" message was gratuitously changed to something
  106. Xless abrupt.
  107. X
  108. Xsome dead code was removed from input.c
  109. X
  110. X%term was changed to %token in parse.y; apparently newer yacc's don't grok
  111. X%term any more.
  112. X
  113. Xa race condition in the signal handler was fixed.
  114. X
  115. Xthe variable in for() was getting evaluated each time through the loop
  116. X(e.g., for (`{echo i;date>[1=2]} in 1 2 3)echo $i would print the date
  117. Xthree times). This was cleaned up.
  118. X
  119. Xa redundant fork() was removed from walk.c; this showed up when running
  120. Xa braced command with a redirection in the background. e.g., {a;b}>c&
  121. X
  122. Xman pages for history and rc were cleaned up by david (thanks).
  123. X
  124. Xrc set SIGQUIT and SIGTERM to SIG_DFL on background jobs---even when
  125. Xtrying to do old-style backgrounding (i.e., don't use process groups,
  126. Xjust ignore SIGINT & SIGQUIT & SIGTERM).
  127. X
  128. X$0 is now changed to the name of the signal when entering a signal
  129. Xhandler. Thus it's possible to write code like
  130. X
  131. X    fn sigint sigterm sigquit {
  132. X        switch ($0) {
  133. X        case sigint
  134. X            ...
  135. X        case sigterm
  136. X            ...
  137. X
  138. Xwait with no arguments now prints the pid of any and all children
  139. Xthat died with a signal. e.g.,
  140. X
  141. X    ; wait
  142. X    25321: terminated
  143. X    25325: terminated
  144. X
  145. Xas opposed to
  146. X
  147. X    ; wait
  148. X    terminated
  149. X
  150. XAn error saving/restoring state in the input stream code would
  151. Xcause rc to exit with the (erroneous) command:
  152. X
  153. X    eval '|[a'
  154. X
  155. XFIFO's were not removed in a backgrounded command, e.g.,
  156. X
  157. X    cat <{echo hi}&
  158. X
  159. XChanges since rc-1.4beta:
  160. X
  161. Xgetopt was renamed to rc_getopt to avoid libc collisions.
  162. X
  163. X$cdpath with a / in it caused a cd to sometimes have two //'s at the
  164. Xfront of the path. This is reserved by POSIX, so I changed it to skip
  165. Xone of the /'s.
  166. X
  167. Xsignal handling now emulates sh in the way I described in a previous
  168. Xmessage: the race condition present in older rc's whereby some SIGINTs
  169. Xgot lost is now gone; any SIGINT received during a wait() is acted upon
  170. Xat the end of the wait(), unless of course SIGINT is being deliberately
  171. Xignored.
  172. X
  173. Xgetopt was renamed to avoid naming conflicts with libc. Also a sound
  174. Xmove since rc_getopt is no longer quite libc-getopt compatible; I had
  175. Xto add in a mechanism for resetting getopt.
  176. X
  177. Xsignal handler code in fn.c was cleaned up; there were several bugs
  178. Xin rc-1.4beta, notably the shell sometimes spawned background jobs
  179. Xwith SIGTERM ignored. I took the opportunity to make things a little
  180. Xcleaner here.
  181. X
  182. Xa quasi-memory leak in the code for while() was fixed: a long-running
  183. Xwhile that had rc commands allocating memory in it could cause the
  184. Xshell to grow without bounds. I fixed this by placing the while loop
  185. X(*and* test!) inside a new allocation arena each time through the loop.
  186. X
  187. XA new configuration parameter, NOJOB, was added to allow you to force
  188. Xv7-style backgrounding (no setpgrp, ignore SIGINT and SIGTERM).
  189. X
  190. XThe FIFO code was reworked a little. It should be more robust now---
  191. XFIFOs get removed at the end of the command of the argument list
  192. Xthat they were on:
  193. X
  194. X        fn foo {echo $*; cat $*}
  195. X        foo<{echo hi}
  196. X
  197. Xnow works as expected. Also FIFO names are pushed onto the exception
  198. Xstack so that their removal occurs in the face of exceptions and so
  199. Xon.
  200. X
  201. XA memory leak in treefree() was plugged up --- the root node of a
  202. Xfunction was not getting freed.
  203. END_OF_FILE
  204.   if test 5591 -ne `wc -c <'CHANGES'`; then
  205.     echo shar: \"'CHANGES'\" unpacked with wrong size!
  206.   fi
  207.   # end of 'CHANGES'
  208. fi
  209. if test -f 'fn.c' -a "${1}" != "-c" ; then 
  210.   echo shar: Will not clobber existing file \"'fn.c'\"
  211. else
  212.   echo shar: Extracting \"'fn.c'\" \(6644 characters\)
  213.   sed "s/^X//" >'fn.c' <<'END_OF_FILE'
  214. X/*
  215. X   fn.c: functions for adding and deleting functions from the symbol table.
  216. X   Support for signal handlers is also found here.
  217. X*/
  218. X
  219. X#include <signal.h>
  220. X#include <errno.h>
  221. X#include "rc.h"
  222. X#include "sigmsgs.h"
  223. X
  224. Xstatic void fn_handler(int), dud_handler(int);
  225. X
  226. Xstatic bool runexit = FALSE;
  227. Xstatic Node *handlers[NUMOFSIGNALS], null;
  228. Xstatic void (*def_sigint)(int) = SIG_DFL,
  229. X        (*def_sigquit)(int) = SIG_DFL,
  230. X        (*def_sigterm)(int) = SIG_DFL;
  231. X
  232. X/*
  233. X   Set signals to default values for rc. This means that interactive
  234. X   shells ignore SIGTERM, etc.
  235. X*/
  236. X
  237. Xextern void inithandler() {
  238. X    int i;
  239. X    null.type = nBody;
  240. X    null.u[0].p = null.u[1].p = NULL;
  241. X    for (i = 1; i < NUMOFSIGNALS; i++)
  242. X#ifdef NOSIGCLD
  243. X        if (i != SIGCLD)
  244. X#endif
  245. X        if (sighandlers[i] == SIG_IGN)
  246. X            fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */
  247. X    if (interactive || sighandlers[SIGINT] != SIG_IGN) {
  248. X        def_sigint = sigint;
  249. X        fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */
  250. X    }
  251. X    if (!dashdee) {
  252. X        if (interactive || sighandlers[SIGQUIT] != SIG_IGN) {
  253. X            def_sigquit = dud_handler;
  254. X            fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */
  255. X        }
  256. X        if (interactive) {
  257. X            def_sigterm = dud_handler;
  258. X            fnrm("sigterm"); /* ditto for SIGTERM */
  259. X        }
  260. X    }
  261. X}
  262. X
  263. X/* only run this in a child process! resets signals to their default values */
  264. X
  265. Xextern void setsigdefaults(bool sysvbackground) {
  266. X    int i;
  267. X    /*
  268. X       General housekeeping: setsigdefaults happens after fork(),
  269. X       so it's a convenient place to clean up open file descriptors.
  270. X       (history file, scripts, etc.)
  271. X    */
  272. X    closefds();
  273. X    /*
  274. X       Restore signals to SIG_DFL, paying close attention to
  275. X       a few quirks: SIGINT, SIGQUIT and are treated specially
  276. X       depending on whether we are doing v7-style backgrounding
  277. X       or not; the default action for SIGINT, SIGQUIT and SIGTERM
  278. X       must be set to the appropriate action; finally, care must
  279. X       be taken not to set to SIG_DFL any signals which are being
  280. X       ignored.
  281. X    */
  282. X    for (i = 1; i < NUMOFSIGNALS; i++)
  283. X        if (sighandlers[i] != SIG_IGN) {
  284. X            handlers[i] = NULL;
  285. X            switch (i) {
  286. X            case SIGINT:
  287. X                if (sysvbackground) {
  288. X                    def_sigint = SIG_IGN;
  289. X                    fnassign("sigint", NULL); /* ignore */
  290. X                } else {
  291. X                    def_sigint = SIG_DFL;
  292. X                    goto sigcommon;
  293. X                }
  294. X                break;
  295. X            case SIGQUIT:
  296. X                if (sysvbackground) {
  297. X                    def_sigquit = SIG_IGN;
  298. X                    fnassign("sigquit", NULL); /* ignore */
  299. X                } else {
  300. X                    def_sigquit = SIG_DFL;
  301. X                    goto sigcommon;
  302. X                }
  303. X                break;
  304. X            case SIGTERM:
  305. X                def_sigterm = SIG_DFL;
  306. X                /* FALLTHROUGH */
  307. X            sigcommon:
  308. X            default:
  309. X                if (sighandlers[i] != SIG_DFL) {
  310. X                    rc_signal(i, SIG_DFL);
  311. X                    delete_fn(signals[i].name);
  312. X                }
  313. X            }
  314. X        }
  315. X    delete_fn("sigexit");
  316. X    runexit = FALSE; /* No sigexit on subshells */
  317. X}
  318. X
  319. X/* rc's exit. if runexit is set, run the sigexit function. */
  320. X
  321. Xextern void rc_exit(int stat) {
  322. X    static char *sigexit[2] = {
  323. X        "sigexit",
  324. X        NULL
  325. X    };
  326. X    if (runexit) {
  327. X        runexit = FALSE;
  328. X        funcall(sigexit);
  329. X        stat = getstatus();
  330. X    }
  331. X    exit(stat);
  332. X}
  333. X
  334. X/* The signal handler for all functions. calls walk() */
  335. X
  336. Xstatic void fn_handler(int s) {
  337. X    List *dollarzero;
  338. X    Estack e;
  339. X    Edata star;
  340. X    int olderrno;
  341. X    if (s < 1 || s >= NUMOFSIGNALS)
  342. X        panic("unknown signal");
  343. X    olderrno = errno;
  344. X    dollarzero = nnew(List);
  345. X    dollarzero->w = signals[s].name;
  346. X    dollarzero->n = NULL;
  347. X    varassign("*", dollarzero, TRUE);
  348. X    star.name = "*";
  349. X    except(eVarstack, star, &e);
  350. X    walk(handlers[s], TRUE);
  351. X    varrm("*", TRUE);
  352. X    unexcept(); /* eVarstack */
  353. X    errno = olderrno;
  354. X}
  355. X
  356. X/* A dud signal handler for SIGQUIT and SIGTERM */
  357. X
  358. Xstatic void dud_handler(int s) {
  359. X}
  360. X
  361. X/*
  362. X   Assign a function in Node form. Check to see if the function is also
  363. X   a signal, and set the signal vectors appropriately.
  364. X*/
  365. X
  366. Xextern void fnassign(char *name, Node *def) {
  367. X    Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */
  368. X    Function *new = get_fn_place(name);
  369. X    int i;
  370. X    new->def = newdef;
  371. X    new->extdef = NULL;
  372. X    if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */
  373. X#ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */
  374. X        if (streq(name, "sigcld"))
  375. X            rc_error("can't trap SIGCLD");
  376. X#endif
  377. X        if (streq(name, "sigexit"))
  378. X            runexit = TRUE;
  379. X        for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
  380. X            if (streq(signals[i].name, name)) {
  381. X                handlers[i] = newdef;
  382. X                if (def == NULL)
  383. X                    rc_signal(i, SIG_IGN);
  384. X                else
  385. X                    rc_signal(i, fn_handler);
  386. X                break;
  387. X            }
  388. X    }
  389. X}
  390. X
  391. X/* Assign a function from the environment. Store just the external representation */
  392. X
  393. Xextern void fnassign_string(char *extdef) {
  394. X    char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
  395. X    Function *new;
  396. X    if (name == NULL)
  397. X        return;
  398. X    new = get_fn_place(name);
  399. X    new->def = NULL;
  400. X    new->extdef = ecpy(extdef);
  401. X}
  402. X
  403. X/* Return a function in Node form, evaluating an entry from the environment if necessary */
  404. X
  405. Xextern Node *fnlookup(char *name) {
  406. X    Function *look = lookup_fn(name);
  407. X    Node *ret;
  408. X    if (look == NULL)
  409. X        return NULL; /* not found */
  410. X    if (look->def != NULL)
  411. X        return look->def;
  412. X    if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
  413. X        return &null;
  414. X    ret = parse_fn(name, look->extdef);
  415. X    if (ret == NULL) {
  416. X        efree(look->extdef);
  417. X        look->extdef = NULL;
  418. X        return &null;
  419. X    } else {
  420. X        return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */
  421. X    }
  422. X}
  423. X
  424. X/* Return a function in string form (used by makeenv) */
  425. X
  426. Xextern char *fnlookup_string(char *name) {
  427. X    Function *look = lookup_fn(name);
  428. X
  429. X    if (look == NULL)
  430. X        return NULL;
  431. X    if (look->extdef != NULL)
  432. X        return look->extdef;
  433. X    return look->extdef = fun2str(name, look->def);
  434. X}
  435. X
  436. X/*
  437. X   Remove a function from the symbol table. If it also defines a signal
  438. X   handler, restore the signal handler to its default value.
  439. X*/
  440. X
  441. Xextern void fnrm(char *name) {
  442. X    int i;
  443. X    for (i = 1; i < NUMOFSIGNALS; i++)
  444. X        if (streq(signals[i].name, name)) {
  445. X            handlers[i] = NULL;
  446. X            switch (i) {
  447. X            case SIGINT:
  448. X                rc_signal(i, def_sigint);
  449. X                break;
  450. X            case SIGQUIT:
  451. X                rc_signal(i, def_sigquit);
  452. X                break;
  453. X            case SIGTERM:
  454. X                rc_signal(i, def_sigterm);
  455. X                break;
  456. X            default:
  457. X                rc_signal(i, SIG_DFL);
  458. X            }
  459. X        }
  460. X    if (streq(name, "sigexit"))
  461. X        runexit = FALSE;
  462. X    delete_fn(name);
  463. X}
  464. X
  465. Xextern void whatare_all_signals() {
  466. X    int i;
  467. X    for (i = 1; i < NUMOFSIGNALS; i++)
  468. X        if (*signals[i].name != '\0')
  469. X            if (sighandlers[i] == SIG_IGN)
  470. X                fprint(1, "fn %s {}\n", signals[i].name);
  471. X            else if (sighandlers[i] == fn_handler)
  472. X                fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]);
  473. X            else
  474. X                fprint(1, "fn %s\n", signals[i].name);
  475. X}
  476. X
  477. Xextern void prettyprint_fn(int fd, char *name, Node *n) {
  478. X    fprint(fd, "fn %S {%T}\n", name, n);
  479. X}
  480. END_OF_FILE
  481.   if test 6644 -ne `wc -c <'fn.c'`; then
  482.     echo shar: \"'fn.c'\" unpacked with wrong size!
  483.   fi
  484.   # end of 'fn.c'
  485. fi
  486. if test -f 'glob.c' -a "${1}" != "-c" ; then 
  487.   echo shar: Will not clobber existing file \"'glob.c'\"
  488. else
  489.   echo shar: Extracting \"'glob.c'\" \(6206 characters\)
  490.   sed "s/^X//" >'glob.c' <<'END_OF_FILE'
  491. X/* glob.c: rc's (ugly) globber. This code is not elegant, but it works */
  492. X
  493. X#include <sys/types.h>
  494. X#include <sys/stat.h>
  495. X#include "rc.h"
  496. X#ifdef NODIRENT
  497. X#include <sys/dir.h>
  498. X#define dirent direct /* need to get the struct declaraction right */
  499. X#else
  500. X#include <dirent.h>
  501. X#endif
  502. X
  503. Xstatic List *dmatch(char *, char *, char *);
  504. Xstatic List *doglob(char *, char *);
  505. Xstatic List *lglob(List *, char *, char *, SIZE_T);
  506. Xstatic List *sort(List *);
  507. X
  508. X/*
  509. X   Matches a list of words s against a list of patterns p. Returns true iff
  510. X   a pattern in p matches a word in s. () matches (), but otherwise null
  511. X   patterns match nothing.
  512. X*/
  513. X
  514. Xextern bool lmatch(List *s, List *p) {
  515. X    List *q;
  516. X    int i;
  517. X    bool okay;
  518. X    if (s == NULL) {
  519. X        if (p == NULL) /* null matches null */
  520. X            return TRUE;
  521. X        for (; p != NULL; p = p->n) { /* one or more stars match null */
  522. X            if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */
  523. X                okay = TRUE;
  524. X                for (i = 0; p->w[i] != '\0'; i++)
  525. X                    if (p->w[i] != '*' || p->m[i] != 1) {
  526. X                        okay = FALSE;
  527. X                        break;
  528. X                    }
  529. X                if (okay)
  530. X                    return TRUE;
  531. X            }
  532. X        }
  533. X        return FALSE;
  534. X    }
  535. X    for (; s != NULL; s = s->n)
  536. X        for (q = p; q != NULL; q = q->n)
  537. X            if (match(q->w, q->m, s->w))
  538. X                return TRUE;
  539. X    return FALSE;
  540. X}
  541. X
  542. X/*
  543. X   Globs a list; checks to see if each element in the list has a metacharacter. If it
  544. X   does, it is globbed, and the output is sorted.
  545. X*/
  546. X
  547. Xextern List *glob(List *s) {
  548. X    List *top, *r;
  549. X    bool meta;
  550. X    for (r = s, meta = FALSE; r != NULL; r = r->n)
  551. X        if (r->m != NULL)
  552. X            meta = TRUE;
  553. X    if (!meta)
  554. X        return s; /* don't copy lists with no metacharacters in them */
  555. X    for (top = r = NULL; s != NULL; s = s->n) {
  556. X        if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
  557. X            if (top == NULL)
  558. X                top = r = nnew(List);
  559. X            else
  560. X                r = r->n = nnew(List);
  561. X            r->w = s->w;
  562. X        } else {
  563. X            if (top == NULL)
  564. X                top = r = sort(doglob(s->w, s->m));
  565. X            else
  566. X                r->n = sort(doglob(s->w, s->m));
  567. X            while (r->n != NULL)
  568. X                r = r->n;
  569. X        }
  570. X    }
  571. X    r->n = NULL;
  572. X    return top;
  573. X}
  574. X
  575. X/* Matches a pattern p against the contents of directory d */
  576. X
  577. Xstatic List *dmatch(char *d, char *p, char *m) {
  578. X    bool matched = FALSE;
  579. X    List *top, *r;
  580. X    static DIR *dirp;
  581. X    static struct dirent *dp;
  582. X    static struct stat s;
  583. X    /* prototypes for XXXdir functions. comment out if necessary */
  584. X    extern DIR *opendir(const char *);
  585. X    extern struct dirent *readdir(DIR *);
  586. X    /*extern int closedir(DIR *);*/
  587. X
  588. X    top = r = NULL;
  589. X    /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
  590. X    if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR || (dirp = opendir(d)) == NULL)
  591. X        return NULL;
  592. X    while ((dp = readdir(dirp)) != NULL)
  593. X        if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
  594. X            matched = TRUE;
  595. X            if (top == NULL)
  596. X                top = r = nnew(List);
  597. X            else
  598. X                r = r->n = nnew(List);
  599. X            r->w = ncpy(dp->d_name);
  600. X            r->m = NULL;
  601. X        }
  602. X    closedir(dirp);
  603. X    if (!matched)
  604. X        return NULL;
  605. X    r->n = NULL;
  606. X    return top;
  607. X}
  608. X
  609. X/*
  610. X   lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*"
  611. X   will return a list with all the files in /tmp, /usr, and /bin. NULL on no match.
  612. X   slashcount indicates the number of slashes to stick between the directory and the
  613. X   matched name. e.g., for matching ////tmp/////foo*
  614. X*/
  615. X
  616. Xstatic List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
  617. X    List *q, *r, *top, foo;
  618. X    static List slash;
  619. X    static SIZE_T slashsize = 0;
  620. X    if (slashcount + 1 > slashsize) {
  621. X        slash.w = ealloc(slashcount + 1);
  622. X        slashsize = slashcount;
  623. X    }
  624. X    slash.w[slashcount] = '\0';
  625. X    while (slashcount > 0)
  626. X        slash.w[--slashcount] = '/';
  627. X    for (top = r = NULL; s != NULL; s = s->n) {
  628. X        q = dmatch(s->w, p, m);
  629. X        if (q != NULL) {
  630. X            foo.w = s->w;
  631. X            foo.m = NULL;
  632. X            foo.n = NULL;
  633. X            if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
  634. X                q = concat(&slash, q);          /* dir/name with slash */
  635. X            q = concat(&foo, q);
  636. X            if (r == NULL)
  637. X                top = r = q;
  638. X            else
  639. X                r->n = q;
  640. X            while (r->n != NULL)
  641. X                r = r->n;
  642. X        }
  643. X    }
  644. X    return top;
  645. X}
  646. X
  647. X/*
  648. X   Doglob globs a pathname in pattern form against a unix path. Returns the original
  649. X   pattern (cleaned of metacharacters) on failure, or the globbed string(s).
  650. X*/
  651. X
  652. Xstatic List *doglob(char *w, char *m) {
  653. X    static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
  654. X    static SIZE_T dsize = 0;
  655. X    char *d, *p, *md, *mp;
  656. X    SIZE_T psize;
  657. X    char *s = w;
  658. X    List firstdir;
  659. X    List *matched;
  660. X    if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
  661. X        efree(dir); efree(pattern); efree(metadir); efree(metapattern);
  662. X        dir = ealloc(psize);
  663. X        pattern = ealloc(psize);
  664. X        metadir = ealloc(psize);
  665. X        metapattern = ealloc(psize);
  666. X        dsize = psize;
  667. X    }
  668. X    d = dir;
  669. X    p = pattern;
  670. X    md = metadir;
  671. X    mp = metapattern;
  672. X    if (*s == '/')
  673. X        while (*s == '/')
  674. X            *d++ = *s++, *md++ = *m++;
  675. X    else
  676. X        while (*s != '/' && *s != '\0')
  677. X            *d++ = *s++, *md++ = *m++; /* get first directory component */
  678. X    *d = '\0';
  679. X    /*
  680. X       Special case: no slashes in the pattern, i.e., open the current directory.
  681. X       Remember that w cannot consist of slashes alone (the other way *s could be
  682. X       zero) since doglob gets called iff there's a metacharacter to be matched
  683. X    */
  684. X    if (*s == '\0') {
  685. X        matched = dmatch(".", dir, metadir);
  686. X        goto end;
  687. X    }
  688. X    if (*w == '/') {
  689. X        firstdir.w = dir;
  690. X        firstdir.m = metadir;
  691. X        firstdir.n = NULL;
  692. X        matched = &firstdir;
  693. X    } else {
  694. X        /*
  695. X           we must glob against current directory,
  696. X           since the first character is not a slash.
  697. X        */
  698. X        matched = dmatch(".", dir, metadir);
  699. X    }
  700. X    do {
  701. X        SIZE_T slashcount;
  702. X        SIGCHK;
  703. X        for (slashcount = 0; *s == '/'; s++, m++)
  704. X            slashcount++; /* skip slashes */
  705. X        while (*s != '/' && *s != '\0')
  706. X            *p++ = *s++, *mp++ = *m++; /* get pattern */
  707. X        *p = '\0';
  708. X        matched = lglob(matched, pattern, metapattern, slashcount);
  709. X        p = pattern, mp = metapattern;
  710. X    } while (*s != '\0');
  711. Xend:    if (matched == NULL) {
  712. X        matched = nnew(List);
  713. X        matched->w = w;
  714. X        matched->m = NULL;
  715. X        matched->n = NULL;
  716. X    }
  717. X    return matched;
  718. X}
  719. X
  720. Xstatic List *sort(List *s) {
  721. X    SIZE_T nel = listnel(s);
  722. X    if (nel > 1) {
  723. X        char **a;
  724. X        List *t;
  725. X        qsort(a = list2array(s, FALSE), nel, sizeof(char *), starstrcmp);
  726. X        for (t = s; t != NULL; t = t->n)
  727. X            t->w = *a++;
  728. X    }
  729. X    return s;
  730. X}
  731. END_OF_FILE
  732.   if test 6206 -ne `wc -c <'glob.c'`; then
  733.     echo shar: \"'glob.c'\" unpacked with wrong size!
  734.   fi
  735.   # end of 'glob.c'
  736. fi
  737. if test -f 'heredoc.c' -a "${1}" != "-c" ; then 
  738.   echo shar: Will not clobber existing file \"'heredoc.c'\"
  739. else
  740.   echo shar: Extracting \"'heredoc.c'\" \(3442 characters\)
  741.   sed "s/^X//" >'heredoc.c' <<'END_OF_FILE'
  742. X/* heredoc.c: heredoc slurping is done here */
  743. X
  744. X#include "rc.h"
  745. X
  746. Xstruct Hq {
  747. X    Node *doc;
  748. X    char *name;
  749. X    Hq *n;
  750. X    bool quoted;
  751. X} *hq;
  752. X
  753. Xstatic bool dead = FALSE;
  754. X
  755. X/*
  756. X * read in a heredocument. A clever trick: skip over any partially matched end-of-file
  757. X * marker storing only the number of characters matched. If the whole marker is matched,
  758. X * return from readheredoc(). If only part of the marker is matched, copy that part into
  759. X * the heredocument.
  760. X *
  761. X * BUG: if the eof string contains a newline, the state can get confused, and the
  762. X * heredoc may continue past where it should.  on the other hand, /bin/sh seems to
  763. X * never get out of its readheredoc() when the heredoc string contains a newline
  764. X */
  765. X
  766. Xstatic char *readheredoc(char *eof) {
  767. X    int c;
  768. X    char *t, *buf, *bufend;
  769. X    unsigned char *s;
  770. X    SIZE_T bufsize;
  771. X    t = buf = nalloc(bufsize = 512);
  772. X    bufend = &buf[bufsize];
  773. X    dead = FALSE;
  774. X#define    RESIZE(extra) { \
  775. X        char *nbuf; \
  776. X        bufsize = bufsize * 2 + extra; \
  777. X        nbuf = nalloc(bufsize); \
  778. X        memcpy(nbuf, buf, (SIZE_T) (t - buf)); \
  779. X        t = nbuf + (t - buf); \
  780. X        buf = nbuf; \
  781. X        bufend = &buf[bufsize]; \
  782. X    }
  783. X    for (;;) {
  784. X        print_prompt2();
  785. X        for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
  786. X            ;
  787. X        if (*s == '\0' && (c == '\n' || c == EOF)) {
  788. X            *t++ = '\0';
  789. X            return buf;
  790. X        }
  791. X        if (s != (unsigned char *) eof) {
  792. X            SIZE_T len = s - (unsigned char *) eof;
  793. X            if (t + len >= bufend)
  794. X                RESIZE(len);
  795. X            memcpy(t, eof, len);
  796. X            t += len;
  797. X        }
  798. X        for (;; c = gchar()) {
  799. X            if (c == EOF) {
  800. X                yyerror("heredoc incomplete");
  801. X                dead = TRUE;
  802. X                return NULL;
  803. X            }
  804. X            if (t + 1 >= bufend)
  805. X                RESIZE(0);
  806. X            *t++ = c;
  807. X            if (c == '\n')
  808. X                break;
  809. X        }
  810. X    }
  811. X}
  812. X
  813. X/* parseheredoc -- turn a heredoc with variable references into a node chain */
  814. X
  815. Xstatic Node *parseheredoc(char *s) {
  816. X    int c = *s;
  817. X    Node *result = NULL;
  818. X    while (TRUE) {
  819. X        Node *node;
  820. X        switch (c) {
  821. X        default: {
  822. X            char *begin = s;
  823. X            while ((c = *s++) != '\0' && c != '$')
  824. X                ;
  825. X            *--s = '\0';
  826. X            node = mk(nQword, begin, NULL);
  827. X            break;
  828. X        }
  829. X        case '$': {
  830. X            char *begin = ++s, *var;
  831. X            c = *s++;
  832. X            if (c == '$') {
  833. X                node = mk(nQword, "$", NULL);
  834. X                c = *s;
  835. X            } else {
  836. X                SIZE_T len = 0;
  837. X                do
  838. X                    len++;
  839. X                while (!dnw[c = *(unsigned char *) s++]);
  840. X                if (c == '^')
  841. X                    c = *s;
  842. X                else
  843. X                    s--;
  844. X                var = nalloc(len + 1);
  845. X                var[len] = '\0';
  846. X                memcpy(var, begin, len);
  847. X                node = mk(nFlat, mk(nWord, var, NULL));
  848. X            }
  849. X            break;
  850. X        }
  851. X        case '\0':
  852. X            return result;
  853. X        }
  854. X        result = (result == NULL) ? node : mk(nConcat, result, node);
  855. X    }
  856. X}
  857. X
  858. X/* read in heredocs when yyparse hits a newline. called from yyparse */
  859. X
  860. Xextern int heredoc(int end) {
  861. X    Hq *here;
  862. X    if ((here = hq) != NULL) {
  863. X        hq = NULL;
  864. X        if (end) {
  865. X            yyerror("heredoc incomplete");
  866. X            return FALSE;
  867. X        }
  868. X        do {
  869. X            Node *n = here->doc;
  870. X            char *s = readheredoc(here->name);
  871. X            if (dead)
  872. X                return FALSE;
  873. X            n->u[2].p = here->quoted ? mk(nQword, s, NULL) : parseheredoc(s);
  874. X            n->u[0].i = rHerestring;
  875. X        } while ((here = here->n) != NULL);
  876. X    }
  877. X    return TRUE;
  878. X}
  879. X
  880. X/* queue pending heredocs into a queue. called from yyparse */
  881. X
  882. Xextern int qdoc(Node *name, Node *n) {
  883. X    Hq *new, **prev;
  884. X    if (name->type != nWord && name->type != nQword) {
  885. X        yyerror("eof-marker not a single literal word");
  886. X        flushu();
  887. X        return FALSE;
  888. X    }
  889. X    for (prev = &hq; (new = *prev) != NULL; prev = &new->n)
  890. X        ;
  891. X    *prev = new = nnew(Hq);
  892. X    new->name = name->u[0].s;
  893. X    new->quoted = (name->type == nQword);
  894. X    new->doc = n;
  895. X    new->n = NULL;
  896. X    return TRUE;
  897. X}
  898. END_OF_FILE
  899.   if test 3442 -ne `wc -c <'heredoc.c'`; then
  900.     echo shar: \"'heredoc.c'\" unpacked with wrong size!
  901.   fi
  902.   # end of 'heredoc.c'
  903. fi
  904. if test -f 'history/history.1' -a "${1}" != "-c" ; then 
  905.   echo shar: Will not clobber existing file \"'history/history.1'\"
  906. else
  907.   echo shar: Extracting \"'history/history.1'\" \(5923 characters\)
  908.   sed "s/^X//" >'history/history.1' <<'END_OF_FILE'
  909. X.\" history.1
  910. X.\"-------
  911. X.\" See rc.1 for man page portability notes.
  912. X.\"-------
  913. X.\" Dd    distance to space vertically before a "display"
  914. X.\" These are what n/troff use for interparagraph distance
  915. X.\"-------
  916. X.if t .nr Dd .4v
  917. X.if n .nr Dd 1v
  918. X.\"-------
  919. X.\" Ds    begin a display, indented .5 inches from the surrounding text.
  920. X.\"
  921. X.\" Note that uses of Ds and De may NOT be nested.
  922. X.\"-------
  923. X.de Ds
  924. X.\" .RS \\$1
  925. X.sp \\n(Ddu
  926. X.in +0.5i
  927. X.nf
  928. X..
  929. X.\"-------
  930. X.\" De    end a display (no trailing vertical spacing)
  931. X.\"-------
  932. X.de De
  933. X.fi
  934. X.in
  935. X.\" .RE
  936. X..
  937. X.\"-------
  938. X.\" I stole the Xf macro from the -man macros on my machine (originally
  939. X.\" "}S", I renamed it so that it won't conflict).
  940. X.\"-------
  941. X.\" Set Cf to the name of the constant width font.
  942. X.\" It will be "C" or "(CW", typically.
  943. X.\" NOTEZ BIEN the lines defining Cf must have no trailing white space:
  944. X.\"-------
  945. X.if t .ds Cf C
  946. X.if n .ds Cf R
  947. X.\"-------
  948. X.\" Rc - Alternate Roman and Courier
  949. X.\"-------
  950. X.de Rc
  951. X.Xf R \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  952. X..
  953. X.\"-------
  954. X.\" Ic - Alternate Italic and Courier
  955. X.\"-------
  956. X.de Ic
  957. X.Xf I \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  958. X..
  959. X.\"-------
  960. X.\" Bc - Alternate Bold and Courier
  961. X.\"-------
  962. X.de Bc
  963. X.Xf B \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  964. X..
  965. X.\"-------
  966. X.\" Cr - Alternate Courier and Roman
  967. X.\"-------
  968. X.de Cr
  969. X.Xf \\*(Cf R \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  970. X..
  971. X.\"-------
  972. X.\" Ci - Alternate Courier and Italic
  973. X.\"-------
  974. X.de Ci
  975. X.Xf \\*(Cf I \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  976. X..
  977. X.\"-------
  978. X.\" Cb - Alternate Courier and Bold
  979. X.\"-------
  980. X.de Cb
  981. X.Xf \\*(Cf B \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  982. X..
  983. X.\"-------
  984. X.\" Xf - Alternate fonts
  985. X.\"
  986. X.\" \$1 - first font
  987. X.\" \$2 - second font
  988. X.\" \$3 - desired word with embedded font changes, built up by recursion
  989. X.\" \$4 - text for first font
  990. X.\" \$5 - \$9 - remaining args
  991. X.\"
  992. X.\" Every time we are called:
  993. X.\"
  994. X.\" If        there is something in \$4
  995. X.\" then    Call ourself with the fonts switched,
  996. X.\"        with a new word made of the current word (\$3) and \$4
  997. X.\"        rendered in the first font,
  998. X.\"        and with the remaining args following \$4.
  999. X.\" else    We are done recursing.  \$3 holds the desired output
  1000. X.\"        word.  We emit \$3, change to Roman font, and restore
  1001. X.\"        the point size to the default.
  1002. X.\" fi
  1003. X.\"
  1004. X.\" Use Xi to add a little bit of space after italic text.
  1005. X.\"-------
  1006. X.de Xf
  1007. X.ds Xi
  1008. X.\"-------
  1009. X.\" I used to test for the italic font both by its font position
  1010. X.\" and its name.  Now just test by its name.
  1011. X.\"
  1012. X.\" .if "\\$1"2" .if !"\\$5"" .ds Xi \^
  1013. X.\"-------
  1014. X.if "\\$1"I" .if !"\\$5"" .ds Xi \^
  1015. X.\"-------
  1016. X.\" This is my original code to deal with the recursion.
  1017. X.\" Evidently some nroffs can't deal with it.
  1018. X.\"-------
  1019. X.\" .ie !"\\$4"" \{\
  1020. X.\" .    Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9"
  1021. X.\" .\}
  1022. X.\" .el \{\\$3
  1023. X.\" .    ft R    \" Restore the default font, since we don't know
  1024. X.\" .        \" what the last font change was.
  1025. X.\" .    ps 10    \" Restore the default point size, since it might
  1026. X.\" .        \" have been changed by an argument to this macro.
  1027. X.\" .\}
  1028. X.\"-------
  1029. X.\" Here is more portable (though less pretty) code to deal with
  1030. X.\" the recursion.
  1031. X.\"-------
  1032. X.if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9"
  1033. X.if "\\$4"" \\$3\fR\s10
  1034. X..
  1035. X.TH HISTORY 1 "30 July 1991"
  1036. X.SH NAME
  1037. X\-, \-\|\-, \-p, \-\|\-p \- shell history programs
  1038. X.SH SYNOPSIS
  1039. X.B \-
  1040. X.RI [ pattern ...]
  1041. X.RI [ substitution ...]
  1042. X.SH DESCRIPTION
  1043. XThis set of programs provides a crude history mechanism for the shell
  1044. X.IR rc (1).
  1045. XIt is based on the v8 UNIX programs
  1046. X.IR = ,
  1047. X.IR == ,
  1048. Xetc.
  1049. X.PP
  1050. XThe program
  1051. X.RI `` \- ''
  1052. Xruns the shell on the command it is requested to find.
  1053. XThe program
  1054. X.RI `` \-\|\- ''
  1055. Xedits that command first.
  1056. XThe programs
  1057. X.RI `` \-p ''
  1058. Xand
  1059. X.RI `` \-\|\-p ''
  1060. Xare similar, except that they print the final command on their standard
  1061. Xoutput instead of running the shell.
  1062. X.PP
  1063. XThe commands work by looking for a file
  1064. Xnamed by the environment variable
  1065. X.Cr $history ,
  1066. Xand by searching for previous commands in this file.
  1067. XOld commands can be edited,
  1068. Xor simply re-executed according to the rules below:
  1069. X.PP
  1070. XA command is searched for by examining the lines in
  1071. X.Cr $history
  1072. Xin reverse order.
  1073. XLines which contain a previous invocation of the history
  1074. Xprogram itself are ignored.
  1075. XIf one or more
  1076. X.I pattern
  1077. Xis supplied on the command line,
  1078. Xthen the patterns are used as a means of
  1079. Xlimiting the search.
  1080. XPatterns match any substring of a previous command,
  1081. Xand if more than one pattern is present then all patterns must be
  1082. Xmatched before a command is selected.
  1083. X.PP
  1084. XSubstitutions may also be specified on the command line.
  1085. XThese have the syntax:
  1086. X.Ds
  1087. X.Ic old : new
  1088. X.De
  1089. X.PP
  1090. X(Note that the
  1091. X.I old
  1092. Xpattern is used as a search-limiting pattern also.)
  1093. XSubstitutions happen on the first match.
  1094. X.PP
  1095. XFinally, a command may be edited in a crude line-mode fashion:
  1096. XThe line to be edited is printed out, and below it the user
  1097. Xsupplies modifications to the command:
  1098. X.TP
  1099. X.B any character
  1100. XReplaces the character above.
  1101. X.TP
  1102. X.B space or tab
  1103. XSkips over the above character(s).
  1104. X.TP
  1105. X.B #
  1106. XDeletes one character.
  1107. X.TP
  1108. X.B %
  1109. XReplaces one character with a space.
  1110. X.TP
  1111. X.B ^
  1112. XInserts the rest of the typed line just before the character.
  1113. X.TP
  1114. X.B $
  1115. XDeletes the rest of the line from that character on, and replaces
  1116. Xit with the rest of the typed line.
  1117. X.TP
  1118. X.B +
  1119. XAppends the rest of the typed line.
  1120. X.TP
  1121. X.B \-
  1122. XBacks up to a previous command satisfying the same matching
  1123. Xconstraints.
  1124. X.TP
  1125. X.B end of file
  1126. XIf an end-of-file is read from the keyboard by the editor,
  1127. Xit aborts with exit status 1 and does not produce any output.
  1128. X.SH EXAMPLES
  1129. XThe history programs work best when their output is reinterpreted by
  1130. Xthe shell using an
  1131. X.Cr eval
  1132. Xcommand.
  1133. XThis can be achieved by writing a shell function to perform the
  1134. Xreinterpretation:
  1135. X.Ds
  1136. X.Cr "fn - -- {"
  1137. X.Cr "    comm = \`{$0^p $*}"
  1138. X.Cr "    if (! ~ $#comm 0) {"
  1139. X.Cr "        echo $comm >[1=2]"
  1140. X.Cr "        eval $comm"
  1141. X.Cr "    }"
  1142. X.Cr "}"
  1143. END_OF_FILE
  1144.   if test 5923 -ne `wc -c <'history/history.1'`; then
  1145.     echo shar: \"'history/history.1'\" unpacked with wrong size!
  1146.   fi
  1147.   # end of 'history/history.1'
  1148. fi
  1149. if test -f 'history/history.c' -a "${1}" != "-c" ; then 
  1150.   echo shar: Will not clobber existing file \"'history/history.c'\"
  1151. else
  1152.   echo shar: Extracting \"'history/history.c'\" \(6472 characters\)
  1153.   sed "s/^X//" >'history/history.c' <<'END_OF_FILE'
  1154. X/*
  1155. X    history.c -- primitive history mechanism
  1156. X
  1157. X    Paul Haahr & Byron Rakitzis, July 1991.
  1158. X
  1159. X    This program mimics the att v8 = and == history programs.
  1160. X    The edit() algorithm was adapted from a similar program
  1161. X    that Boyd Roberts wrote, but otherwise all the code has
  1162. X    been written from scratch.
  1163. X
  1164. X    edit() was subsequently redone by Hugh Redelmeier in order
  1165. X    to correctly deal with tab characters in the source line.
  1166. X
  1167. X    BUGS:
  1168. X    There is an implicit assumption that commands are no
  1169. X    more than 1k characters long. 
  1170. X*/
  1171. X
  1172. X#include <stdio.h>
  1173. X#include <stdlib.h>
  1174. X#include <string.h>
  1175. X
  1176. Xstatic char *id = "@(#) history.c  8/91";
  1177. X
  1178. X#undef FALSE
  1179. X#undef TRUE
  1180. Xtypedef enum { FALSE, TRUE } bool;
  1181. X
  1182. X#define CHUNKSIZE 65536
  1183. X
  1184. Xstatic struct {
  1185. X    char *old, *new;
  1186. X} *replace;
  1187. X
  1188. Xstatic char **search, *progname, *history;
  1189. Xstatic char me;    /* typically ':' or '-' */
  1190. Xstatic bool editit = FALSE, printit = FALSE;
  1191. Xstatic int nreplace = 0, nsearch = 0;
  1192. Xstatic FILE *fp;
  1193. X
  1194. Xstatic void *ealloc(size_t n) {
  1195. X    void *p = (void *) malloc(n);
  1196. X    if (p == NULL) {
  1197. X        perror("malloc");
  1198. X        exit(1);
  1199. X    }
  1200. X    return p;
  1201. X}
  1202. X
  1203. Xstatic void *erealloc(void *p, size_t n) {
  1204. X    p = (void *) realloc(p, n);
  1205. X    if (p == NULL) {
  1206. X        perror("realloc");
  1207. X        exit(1);
  1208. X    }
  1209. X    return p;
  1210. X}
  1211. X
  1212. Xstatic char *newstr() {
  1213. X    return ealloc((size_t)1024);
  1214. X}
  1215. X
  1216. Xstatic char *basename(char *s) {
  1217. X    char *t = strrchr(s, '/');
  1218. X    return (t == NULL) ? s : t + 1;
  1219. X}
  1220. X
  1221. X/* stupid O(n^2) substring matching routine */
  1222. X
  1223. Xstatic char *isin(char *target, char *pattern) {
  1224. X    size_t plen = strlen(pattern);
  1225. X    size_t tlen = strlen(target);
  1226. X    for (; tlen >= plen; target++, --tlen)
  1227. X        if (strncmp(target, pattern, plen) == 0)
  1228. X            return target;
  1229. X    return NULL;
  1230. X}
  1231. X
  1232. X/* replace the first match in the string with "new" */
  1233. Xstatic char *sub(char *s, char *old, char *new) {
  1234. X    char *t, *u;
  1235. X
  1236. X    t = isin(s, old);
  1237. X    u = newstr();
  1238. X
  1239. X    *t = '\0';
  1240. X    while (*old != '\0')
  1241. X        old++, t++;
  1242. X    strcpy(u, s);
  1243. X    strcat(u, new);
  1244. X    strcat(u, t);
  1245. X    return u;
  1246. X}
  1247. X
  1248. Xstatic char *edit(char *s) {
  1249. X    char *final, *f, *end;
  1250. X    int col;
  1251. X    bool ins;
  1252. X    
  1253. Xstart:
  1254. X    fprintf(stderr, "%s\n", s);    
  1255. X    f = final = newstr();
  1256. X    end = s + strlen(s);
  1257. X    col = 0;
  1258. X    ins = FALSE;
  1259. X    
  1260. X    for (;; col++) {
  1261. X        int    c = getchar();
  1262. X
  1263. X        if (c == me && col == 0) {
  1264. X            int    peekc = getchar();
  1265. X            if (peekc == '\n')
  1266. X                return NULL;
  1267. X            ungetc(peekc, stdin);
  1268. X        }
  1269. X        if (c == '\n') {
  1270. X            if (col == 0)
  1271. X                return s;
  1272. X            
  1273. X            while (s < end) /* copy remainder of string */
  1274. X                *f++ = *s++;
  1275. X            *f = '\0';
  1276. X            s = final;
  1277. X            goto start;
  1278. X        } else if (ins || s>=end) {
  1279. X            /* col need not be accurate -- tabs need not be interpreted */
  1280. X            *f++ = c;
  1281. X        } else {
  1282. X            switch (c) {
  1283. X            case '+':
  1284. X                while (s < end)
  1285. X                    *f++ = *s++;
  1286. X                *f = '\0';
  1287. X                continue;
  1288. X            case '%':
  1289. X                c = ' ';
  1290. X                /* FALLTHROUGH */
  1291. X            default:
  1292. X                *f++ = c;
  1293. X                break;    
  1294. X            case EOF:
  1295. X                exit(1);
  1296. X                /* NOTREACHED */
  1297. X            case ' ':
  1298. X                if (*s == '\t') {
  1299. X                    int    oldcol = col;
  1300. X
  1301. X                    for (;; col++) {
  1302. X                        int    peekc;
  1303. X
  1304. X                        if ((col&07) == 07) {
  1305. X                            *f++ = '\t';    /* we spaced past a tab */
  1306. X                            break;
  1307. X                        }
  1308. X                        peekc = getchar();
  1309. X                        if (peekc != ' ') {
  1310. X                            ungetc(peekc, stdin);
  1311. X                            if (peekc != '\n') {
  1312. X                                /* we spaced partially into a tab */
  1313. X                                do {
  1314. X                                    *f++ = ' ';
  1315. X                                    oldcol++;
  1316. X                                } while (oldcol <= col);
  1317. X                            }
  1318. X                            break;
  1319. X                        }
  1320. X                    }
  1321. X                } else {
  1322. X                    *f++ = *s;
  1323. X                }
  1324. X                break;
  1325. X            case '#':
  1326. X                break;
  1327. X            case '$':
  1328. X                end = s;    /* truncate s */
  1329. X                continue;    /* skip incrementing s */
  1330. X            case '^':
  1331. X                ins = TRUE;
  1332. X                continue;    /* skip incrementing s */
  1333. X            case '\t':
  1334. X                for (;; col++) {
  1335. X                    if ((*f++ = s<end? *s++ : '\t') == '\t') {
  1336. X                        col = col | 07;    /* advance to before next tabstop */
  1337. X                    }
  1338. X                    if ((col&07) == 07)    /* stop before tabstop */
  1339. X                        break;
  1340. X                }
  1341. X                continue;    /* skip incrementing s */
  1342. X            }
  1343. X            if (s<end && (*s!='\t' || (col&07)==07))
  1344. X                s++;
  1345. X        }
  1346. X    }
  1347. X}
  1348. X
  1349. Xstatic char *readhistoryfile(char **last) {
  1350. X    char *buf;
  1351. X    size_t count, size;
  1352. X    long nread;
  1353. X
  1354. X    if ((history = getenv("history")) == NULL) {
  1355. X        fprintf(stderr, "$history not set\n");
  1356. X        exit(1);
  1357. X    }
  1358. X    fp = fopen(history, "r+");
  1359. X    if (fp == NULL) {
  1360. X        perror(history);
  1361. X        exit(1);
  1362. X    }
  1363. X
  1364. X    size = 0;
  1365. X    count = 0;
  1366. X    buf = ealloc(size = CHUNKSIZE);
  1367. X    while ((nread = fread(buf + count, sizeof (char), size - count, fp)) > 0) {
  1368. X        count += nread;
  1369. X        if (size - count == 0)
  1370. X            buf = erealloc(buf, size *= 4);
  1371. X    }
  1372. X    if (nread == -1) {
  1373. X        perror(history);
  1374. X        exit(1);
  1375. X    }
  1376. X    *last = buf + count;
  1377. X    return buf;
  1378. X}
  1379. X
  1380. Xstatic char *getcommand() {
  1381. X    char *s, *t;
  1382. X    static char *hist = NULL, *last;
  1383. X
  1384. X    if (hist == NULL) {
  1385. X        hist = readhistoryfile(&last);
  1386. X        *--last = '\0';        /* trim final newline */
  1387. X    }
  1388. X
  1389. Xagain:    s = last;
  1390. X    if (s < hist)
  1391. X        return NULL;
  1392. X    while (*--s != '\n')
  1393. X        if (s <= hist) {
  1394. X            last = hist - 1;
  1395. X            return hist;
  1396. X        }
  1397. X    *s = '\0';
  1398. X    last = s++;
  1399. X
  1400. X    /*
  1401. X     * if the command contains the "me" character at the start of the line
  1402. X     * or after any of [`{|()] then try again
  1403. X     */
  1404. X
  1405. X    for (t = s; *t != '\0'; t++)
  1406. X        if (*t == me) {
  1407. X            char *u = t - 1;
  1408. X            while (u >= s && (*u == ' ' || *u == '\t'))
  1409. X                --u;
  1410. X            if (u < s || *u == '`' || *u == '{' || *u == '|' || *u == '(' || *u == ')')
  1411. X                goto again;
  1412. X        }
  1413. X    return s;
  1414. X}
  1415. X
  1416. Xint main(int argc, char **argv) {
  1417. X    int i;
  1418. X    char *s;
  1419. X
  1420. X    s = progname = basename(argv[0]);
  1421. X    me = *s++;
  1422. X    if (*s == me) {
  1423. X        s++;
  1424. X        editit = TRUE;
  1425. X    }
  1426. X    if (*s == 'p') {
  1427. X        s++;
  1428. X        printit = TRUE;
  1429. X    }
  1430. X/* Nahh...
  1431. X    if (*s != '\0') {
  1432. X        fprintf(stderr, "\"%s\": bad name for history program\n", progname);
  1433. X        exit(1);
  1434. X    }
  1435. X*/
  1436. X
  1437. X    if (argc > 1) {
  1438. X        replace = ealloc((argc - 1) * sizeof *replace);
  1439. X        search = ealloc((argc - 1) * sizeof *search);
  1440. X    }
  1441. X    for (i = 1; i < argc; i++)
  1442. X        if ((s = strchr(argv[i], ':')) == NULL)
  1443. X            search[nsearch++] = argv[i];
  1444. X        else {
  1445. X            *(char *)s = '\0';    /* do we confuse ps too much? */
  1446. X            replace[nreplace].old = argv[i];
  1447. X            replace[nreplace].new = s + 1;
  1448. X            nreplace++;
  1449. X        }
  1450. X
  1451. Xnext:    s = getcommand();
  1452. X    if (s == NULL) {
  1453. X        fprintf(stderr, "command not matched\n");
  1454. X        return 1;
  1455. X    }
  1456. X    for (i = 0; i < nsearch; i++)
  1457. X        if (!isin(s, search[i]))
  1458. X            goto next;
  1459. X    for (i = 0; i < nreplace; i++)
  1460. X        if (!isin(s, replace[i].old))
  1461. X            goto next;
  1462. X        else
  1463. X            s = sub(s, replace[i].old, replace[i].new);
  1464. X    if (editit) {
  1465. X        s = edit(s);
  1466. X        if (s == NULL)
  1467. X            goto next;
  1468. X    }
  1469. X    fseek(fp, 0, 2); /* 2 == end of file. i.e., append command to $history */
  1470. X    fprintf(fp, "%s\n", s);
  1471. X    fclose(fp);
  1472. X    if (printit)
  1473. X        printf("%s\n", s);
  1474. X    else {
  1475. X        char *shell = getenv("SHELL");
  1476. X
  1477. X        if (!editit)
  1478. X            fprintf(stderr, "%s\n", s);
  1479. X        if (shell == NULL)
  1480. X            shell = "/bin/sh";
  1481. X        execl(shell, basename(shell), "-c", s, NULL);
  1482. X        perror(shell);
  1483. X        exit(1);
  1484. X    }
  1485. X    return 0;
  1486. X}
  1487. END_OF_FILE
  1488.   if test 6472 -ne `wc -c <'history/history.c'`; then
  1489.     echo shar: \"'history/history.c'\" unpacked with wrong size!
  1490.   fi
  1491.   # end of 'history/history.c'
  1492. fi
  1493. if test -f 'parse.y' -a "${1}" != "-c" ; then 
  1494.   echo shar: Will not clobber existing file \"'parse.y'\"
  1495. else
  1496.   echo shar: Extracting \"'parse.y'\" \(5348 characters\)
  1497.   sed "s/^X//" >'parse.y' <<'END_OF_FILE'
  1498. X/* parse.y */
  1499. X
  1500. X/*
  1501. X * Adapted from rc grammar, v10 manuals, volume 2.
  1502. X */
  1503. X
  1504. X%{
  1505. X#include "rc.h"
  1506. X#ifndef lint
  1507. X#define lint        /* hush up gcc -Wall, leave out the dumb sccsid's. */
  1508. X#endif
  1509. Xstatic Node *star, *nolist;
  1510. XNode *parsetree;    /* not using yylval because bison declares it as an auto */
  1511. X%}
  1512. X
  1513. X%token ANDAND BACKBACK BANG CASE COUNT DUP ELSE END FLAT FN FOR IF IN
  1514. X%token OROR PIPE REDIR SREDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH
  1515. X
  1516. X%left WHILE ')' ELSE
  1517. X%left ANDAND OROR '\n'
  1518. X%left BANG SUBSHELL
  1519. X%left PIPE
  1520. X%right '$' 
  1521. X%left SUB
  1522. X/*
  1523. X*/
  1524. X
  1525. X%union {
  1526. X    struct Node *node;
  1527. X    struct Redir redir;
  1528. X    struct Pipe pipe;
  1529. X    struct Dup dup;
  1530. X    struct Word word;
  1531. X    char *keyword;
  1532. X}
  1533. X
  1534. X%type <redir> REDIR SREDIR
  1535. X%type <pipe> PIPE
  1536. X%type <dup> DUP
  1537. X%type <word> WORD
  1538. X%type <keyword> keyword
  1539. X%type <node> assign body brace case cbody cmd cmdsa cmdsan comword epilog
  1540. X         first line nlwords paren redir sword simple iftail word words
  1541. X
  1542. X%start rc
  1543. X
  1544. X%%
  1545. X
  1546. Xrc    : line end        { parsetree = $1; YYACCEPT; }
  1547. X    | error end        { yyerrok; parsetree = NULL; YYABORT; }
  1548. X
  1549. X/* an rc line may end in end-of-file as well as newline, e.g., rc -c 'ls' */
  1550. Xend    : END    /* EOF */    { if (!heredoc(1)) YYABORT; } /* flag error if there is a heredoc in the queue */
  1551. X    | '\n'            { if (!heredoc(0)) YYABORT; } /* get heredoc on \n */
  1552. X
  1553. X/* a cmdsa is a command followed by ampersand or newline (used in "line" and "body") */
  1554. Xcmdsa    : cmd ';'
  1555. X    | cmd '&'        { $$ = ($1 != NULL ? mk(nNowait,$1) : $1); }
  1556. X
  1557. X/* a line is a single command, or a command terminated by ; or & followed by a line (recursive) */
  1558. Xline    : cmd
  1559. X    | cmdsa line        { $$ = ($1 != NULL ? mk(nBody,$1,$2) : $2); }
  1560. X
  1561. X/* a body is like a line, only commands may also be terminated by newline */
  1562. Xbody    : cmd
  1563. X    | cmdsan body        { $$ = ($1 == NULL ? $2 : $2 == NULL ? $1 : mk(nBody,$1,$2)); }
  1564. X
  1565. Xcmdsan    : cmdsa
  1566. X    | cmd '\n'        { $$ = $1; if (!heredoc(0)) YYABORT; } /* get h.d. on \n */
  1567. X
  1568. Xbrace    : '{' body '}'        { $$ = $2; }
  1569. X
  1570. Xparen    : '(' body ')'        { $$ = $2; }
  1571. X
  1572. Xassign    : first '=' word    { $$ = mk(nAssign,$1,$3); }
  1573. X
  1574. Xepilog    :            { $$ = NULL; }
  1575. X    | redir epilog        { $$ = mk(nEpilog,$1,$2); }
  1576. X
  1577. X/* a redirection is a dup (e.g., >[1=2]) or a file redirection. (e.g., > /dev/null) */
  1578. Xredir    : DUP            { $$ = mk(nDup,$1.type,$1.left,$1.right); }
  1579. X    | REDIR word        { $$ = mk(nRedir,$1.type,$1.fd,$2);
  1580. X                  if ($1.type == rHeredoc && !qdoc($2, $$)) YYABORT; /* queue heredocs up */
  1581. X                }
  1582. X    | SREDIR word        { $$ = mk(nRedir,$1.type,$1.fd,$2);
  1583. X                  if ($1.type == rHeredoc && !qdoc($2, $$)) YYABORT; /* queue heredocs up */
  1584. X                }
  1585. X
  1586. Xcase    : CASE words ';'             { $$ = mk(nCase, $2); }
  1587. X    | CASE words '\n'             { $$ = mk(nCase, $2); }
  1588. X
  1589. Xcbody    : cmd                    { $$ = mk(nCbody, $1, NULL); }
  1590. X    | case cbody                { $$ = mk(nCbody, $1, $2); }
  1591. X    | cmdsan cbody                { $$ = mk(nCbody, $1, $2); }
  1592. X
  1593. Xiftail    : cmd        %prec ELSE
  1594. X    | brace ELSE optnl cmd            { $$ = mk(nElse,$1,$4); }
  1595. X
  1596. Xcmd    : /* empty */    %prec WHILE        { $$ = NULL; }
  1597. X    | simple
  1598. X    | brace epilog                { $$ = mk(nBrace,$1,$2); }
  1599. X    | IF paren optnl iftail            { $$ = mk(nIf,$2,$4); }
  1600. X    | FOR '(' word IN words ')' optnl cmd    { $$ = mk(nForin,$3,$5,$8); }
  1601. X    | FOR '(' word ')' optnl cmd        { $$ = mk(nForin,$3,star,$6); }
  1602. X    | WHILE paren optnl cmd            { $$ = mk(nWhile,$2,$4); }
  1603. X    | SWITCH '(' word ')' optnl '{' cbody '}' { $$ = mk(nSwitch,$3,$7); }
  1604. X    | TWIDDLE optcaret word words        { $$ = mk(nMatch,$3,$4); }
  1605. X    | cmd ANDAND optnl cmd            { $$ = mk(nAndalso,$1,$4); }
  1606. X    | cmd OROR optnl cmd            { $$ = mk(nOrelse,$1,$4); }
  1607. X     | cmd PIPE optnl cmd            { $$ = mk(nPipe,$2.left,$2.right,$1,$4); }
  1608. X    | redir cmd    %prec BANG        { $$ = ($2 != NULL ? mk(nPre,$1,$2) : $1); }
  1609. X    | assign cmd    %prec BANG        { $$ = ($2 != NULL ? mk(nPre,$1,$2) : $1); }
  1610. X    | BANG optcaret cmd            { $$ = mk(nBang,$3); }
  1611. X    | SUBSHELL optcaret cmd            { $$ = mk(nSubshell,$3); }
  1612. X    | FN words brace            { $$ = mk(nNewfn,$2,$3); }
  1613. X    | FN words                { $$ = mk(nRmfn,$2); }
  1614. X
  1615. Xoptcaret : /* empty */
  1616. X    | '^'
  1617. X
  1618. Xsimple    : first
  1619. X    | simple word            { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); }
  1620. X    | simple redir            { $$ = mk(nArgs,$1,$2); }
  1621. X
  1622. Xfirst    : comword
  1623. X    | first '^' sword        { $$ = mk(nConcat,$1,$3); }
  1624. X
  1625. Xsword    : comword
  1626. X    | keyword            { $$ = mk(nWord,$1, NULL); }
  1627. X
  1628. Xword    : sword
  1629. X    | word '^' sword        { $$ = mk(nConcat,$1,$3); }
  1630. X
  1631. Xcomword    : '$' sword            { $$ = mk(nVar,$2); }
  1632. X    | '$' sword SUB words ')'    { $$ = mk(nVarsub,$2,$4); }
  1633. X    | COUNT sword            { $$ = mk(nCount,$2); }
  1634. X    | FLAT sword            { $$ = mk(nFlat, $2); }
  1635. X    | '`' sword            { $$ = mk(nBackq,nolist,$2); }
  1636. X    | '`' brace            { $$ = mk(nBackq,nolist,$2); }
  1637. X    | BACKBACK word    brace        { $$ = mk(nBackq,$2,$3); }
  1638. X    | BACKBACK word    sword        { $$ = mk(nBackq,$2,$3); }
  1639. X    | '(' nlwords ')'        { $$ = $2; }
  1640. X    | REDIR brace            { $$ = mk(nNmpipe,$1.type,$1.fd,$2); }
  1641. X    | WORD                { $$ = ($1.w[0] == '\'') ? mk(nQword, $1.w+1, NULL) : mk(nWord,$1.w, $1.m); }
  1642. X
  1643. Xkeyword    : FOR        { $$ = "for"; }
  1644. X    | IN        { $$ = "in"; }
  1645. X    | WHILE        { $$ = "while"; }
  1646. X    | IF        { $$ = "if"; }
  1647. X    | SWITCH    { $$ = "switch"; }
  1648. X    | FN        { $$ = "fn"; }
  1649. X    | ELSE        { $$ = "else"; }
  1650. X    | CASE        { $$ = "case"; }
  1651. X    | TWIDDLE    { $$ = "~"; }
  1652. X    | BANG        { $$ = "!"; }
  1653. X    | SUBSHELL    { $$ = "@"; }
  1654. X
  1655. Xwords    :        { $$ = NULL; }
  1656. X    | words word    { $$ = ($1 != NULL ? ($2 != NULL ? mk(nLappend,$1,$2) : $1) : $2); }
  1657. X
  1658. Xnlwords :        { $$ = NULL; }
  1659. X    | nlwords '\n'
  1660. X    | nlwords word    { $$ = ($1 != NULL ? ($2 != NULL ? mk(nLappend,$1,$2) : $1) : $2); }
  1661. X
  1662. Xoptnl    : /* empty */
  1663. X    | optnl '\n'
  1664. X
  1665. X%%
  1666. X
  1667. Xvoid initparse() {
  1668. X    star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc);
  1669. X    nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc);
  1670. X}
  1671. X
  1672. END_OF_FILE
  1673.   if test 5348 -ne `wc -c <'parse.y'`; then
  1674.     echo shar: \"'parse.y'\" unpacked with wrong size!
  1675.   fi
  1676.   # end of 'parse.y'
  1677. fi
  1678. if test -f 'rc.h' -a "${1}" != "-c" ; then 
  1679.   echo shar: Will not clobber existing file \"'rc.h'\"
  1680. else
  1681.   echo shar: Extracting \"'rc.h'\" \(9028 characters\)
  1682.   sed "s/^X//" >'rc.h' <<'END_OF_FILE'
  1683. X#include "config.h"
  1684. X#include "proto.h"
  1685. X
  1686. X/* datatypes */
  1687. X
  1688. X/* braindamaged IBM header files #define true and false */
  1689. X#undef FALSE
  1690. X#undef TRUE
  1691. X
  1692. X#include <stdarg.h>
  1693. X
  1694. Xtypedef void builtin_t(char **);
  1695. Xtypedef struct Block Block;
  1696. Xtypedef struct Dup Dup;
  1697. Xtypedef struct Estack Estack;
  1698. Xtypedef struct Function Function;
  1699. Xtypedef struct Hq Hq;
  1700. Xtypedef struct Htab Htab;
  1701. Xtypedef struct Jbwrap Jbwrap;
  1702. Xtypedef struct List List;
  1703. Xtypedef struct Node Node;
  1704. Xtypedef struct Pipe Pipe;
  1705. Xtypedef struct Redir Redir;
  1706. Xtypedef struct Rq Rq;
  1707. Xtypedef struct Variable Variable;
  1708. Xtypedef struct Word Word;
  1709. Xtypedef struct Format Format;
  1710. Xtypedef union Edata Edata;
  1711. X
  1712. Xtypedef enum nodetype {
  1713. X    nAndalso, nAssign, nBackq, nBang, nBody, nCbody, nNowait, nBrace, nConcat,
  1714. X    nCount, nElse, nFlat, nDup, nEpilog, nNewfn, nForin, nIf, nQword,
  1715. X    nOrelse, nPipe, nPre, nRedir, nRmfn, nArgs, nSubshell, nCase,
  1716. X    nSwitch, nMatch, nVar, nVarsub, nWhile, nWord, nLappend, nNmpipe
  1717. X} nodetype;
  1718. X
  1719. Xtypedef enum ecodes {
  1720. X    eError, eBreak, eReturn, eVarstack, eArena, eFifo, eFd
  1721. X} ecodes;
  1722. X
  1723. Xtypedef enum bool {
  1724. X    FALSE, TRUE
  1725. X} bool;
  1726. X
  1727. Xtypedef enum inputtype {
  1728. X    iFd, iString
  1729. X} inputtype;
  1730. X
  1731. Xtypedef enum redirtype {
  1732. X    rFrom, rCreate, rAppend, rHeredoc, rHerestring
  1733. X} redirtype;
  1734. X
  1735. Xtypedef bool (*Conv)(Format *, int);
  1736. X
  1737. Xunion Edata {
  1738. X    Jbwrap *jb;
  1739. X    Block *b;
  1740. X    char *name;
  1741. X    int fd;
  1742. X};
  1743. X
  1744. Xstruct Estack {
  1745. X    ecodes e;
  1746. X    bool interactive;
  1747. X    Edata data;
  1748. X    Estack *prev;
  1749. X};
  1750. X
  1751. Xstruct List {
  1752. X    char *w, *m;
  1753. X    List *n;
  1754. X};
  1755. X
  1756. Xstruct Node {
  1757. X    nodetype type;
  1758. X    union {
  1759. X        char *s;
  1760. X        int i;
  1761. X        Node *p;
  1762. X    } u[4];
  1763. X};
  1764. X
  1765. Xstruct Pipe {
  1766. X    int left, right;
  1767. X};
  1768. X
  1769. Xstruct Dup {
  1770. X    redirtype type;
  1771. X    int left, right;
  1772. X};
  1773. X
  1774. Xstruct Redir {
  1775. X    redirtype type;
  1776. X    int fd;
  1777. X};
  1778. X
  1779. Xstruct Word {
  1780. X    char *w, *m;
  1781. X};
  1782. X
  1783. Xstruct Rq {
  1784. X    Node *r;
  1785. X    struct Rq *n;
  1786. X};
  1787. X
  1788. Xstruct Function {
  1789. X    Node *def;
  1790. X    char *extdef;
  1791. X};
  1792. X
  1793. Xstruct Variable {
  1794. X    List *def;
  1795. X    char *extdef;
  1796. X    Variable *n;
  1797. X};
  1798. X
  1799. Xstruct Htab {
  1800. X    char *name;
  1801. X    void *p;
  1802. X};
  1803. X
  1804. Xstruct Format {
  1805. X    /* for the formatting routines */
  1806. X    va_list args;
  1807. X    long flags, f1, f2;
  1808. X    /* for the buffer maintainence routines */
  1809. X    char *buf, *bufbegin, *bufend;
  1810. X    int flushed;
  1811. X    void (*grow)(Format *, SIZE_T);
  1812. X    union { int n; void *p; } u;
  1813. X};
  1814. X
  1815. X/* Format->flags values */
  1816. Xenum {
  1817. X    FMT_long    = 1,        /* %l */
  1818. X    FMT_short    = 2,        /* %h */
  1819. X    FMT_unsigned    = 4,        /* %u */
  1820. X    FMT_zeropad    = 8,        /* %0 */
  1821. X    FMT_leftside    = 16,        /* %- */
  1822. X    FMT_altform    = 32,        /* %# */
  1823. X    FMT_f1set    = 64,        /* %<n> */
  1824. X    FMT_f2set    = 128        /* %.<n> */
  1825. X};
  1826. X
  1827. X/* macros */
  1828. X#define EOF (-1)
  1829. X#ifndef NULL
  1830. X#define NULL 0
  1831. X#endif
  1832. X#define a2u(x) n2u(x, 10)
  1833. X#define o2u(x) n2u(x, 8)
  1834. X#define arraysize(a) ((int)(sizeof(a)/sizeof(*a)))
  1835. X#define enew(x) ((x *) ealloc(sizeof(x)))
  1836. X#define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1), x)
  1837. X#define lookup_fn(s) ((Function *) lookup(s, fp))
  1838. X#define lookup_var(s) ((Variable *) lookup(s, vp))
  1839. X#define nnew(x) ((x *) nalloc(sizeof(x)))
  1840. X#define ncpy(x) (strcpy((char *) nalloc(strlen(x) + 1), x))
  1841. X#ifndef offsetof
  1842. X#define offsetof(t, m) ((SIZE_T) (((char *) &((t *) 0)->m) - (char *)0))
  1843. X#endif
  1844. X#define streq(x, y) (*(x) == *(y) && strcmp(x, y) == 0)
  1845. X#define conststrlen(x) (sizeof (x) - 1)
  1846. X
  1847. X/* rc prototypes */
  1848. X
  1849. X/* main.c */
  1850. Xextern char *prompt, *prompt2;
  1851. Xextern Rq *redirq;
  1852. Xextern bool dashdee, dashee, dashvee, dashex, dashell,
  1853. X    dasheye, dashen, dashpee, interactive;
  1854. Xextern int rc_pid;
  1855. Xextern int lineno;
  1856. X
  1857. X/* builtins.c */
  1858. Xextern builtin_t *isbuiltin(char *);
  1859. Xextern void b_exec(char **), funcall(char **), b_dot(char **), b_builtin(char **);
  1860. Xextern char *which(char *, bool);
  1861. X
  1862. X/* except.c */
  1863. Xextern bool nl_on_intr;
  1864. Xextern bool outstanding_cmdarg(void);
  1865. Xextern void pop_cmdarg(bool);
  1866. Xextern void rc_raise(ecodes);
  1867. Xextern void except(ecodes, Edata, Estack *);
  1868. Xextern void unexcept(void);
  1869. Xextern void rc_error(char *);
  1870. Xextern void sigint(int);
  1871. X
  1872. X/* exec.c */
  1873. Xextern void exec(List *, bool);
  1874. Xextern void doredirs(void);
  1875. X
  1876. X/* footobar.c */
  1877. Xextern char *fun2str(char *, Node *);
  1878. Xextern char *list2str(char *, List *);
  1879. Xextern char **list2array(List *, bool);
  1880. Xextern char *get_name(char *);
  1881. Xextern List *parse_var(char *, char *);
  1882. Xextern Node *parse_fn(char *, char *);
  1883. Xextern void initprint(void);
  1884. Xextern void rc_exit(int); /* here for odd reasons; user-defined signal handlers are kept in fn.c */
  1885. X
  1886. X/* getopt.c */
  1887. Xextern int rc_getopt(int, char **, char *);
  1888. X
  1889. Xextern int rc_optind, rc_opterr, rc_optopt;
  1890. Xextern char *rc_optarg;
  1891. X
  1892. X/* glob.c */
  1893. Xextern bool lmatch(List *, List *);
  1894. Xextern List *glob(List *);
  1895. X
  1896. X/* glom.c */
  1897. Xextern void assign(List *, List *, bool);
  1898. Xextern void qredir(Node *);
  1899. Xextern List *append(List *, List*);
  1900. Xextern List *flatten(List *);
  1901. Xextern List *glom(Node *);
  1902. Xextern List *concat(List *, List *);
  1903. Xextern List *varsub(List *, List *);
  1904. Xextern List *word(char *, char *);
  1905. X
  1906. X/* hash.c */
  1907. Xextern Htab *fp, *vp;
  1908. Xextern void *lookup(char *, Htab *);
  1909. Xextern Function *get_fn_place(char *);
  1910. Xextern List *varlookup(char *);
  1911. Xextern Node *fnlookup(char *);
  1912. Xextern Variable *get_var_place(char *, bool);
  1913. Xextern bool varassign_string(char *);
  1914. Xextern char **makeenv(void);
  1915. Xextern char *fnlookup_string(char *);
  1916. Xextern char *varlookup_string(char *);
  1917. Xextern void alias(char *, List *, bool);
  1918. Xextern void starassign(char *, char **, bool);
  1919. Xextern void delete_fn(char *);
  1920. Xextern void delete_var(char *, bool);
  1921. Xextern void fnassign(char *, Node *);
  1922. Xextern void fnassign_string(char *);
  1923. Xextern void fnrm(char *);
  1924. Xextern void initenv(char **);
  1925. Xextern void inithash(void);
  1926. Xextern void setsigdefaults(bool);
  1927. Xextern void inithandler(void);
  1928. Xextern void varassign(char *, List *, bool);
  1929. Xextern void varrm(char *, bool);
  1930. Xextern void whatare_all_vars(void);
  1931. Xextern void whatare_all_signals(void);
  1932. Xextern void prettyprint_var(int, char *, List *);
  1933. Xextern void prettyprint_fn(int, char *, Node *);
  1934. X
  1935. X/* heredoc.c */
  1936. Xextern int heredoc(int);
  1937. Xextern int qdoc(Node *, Node *);
  1938. Xextern Hq *hq;
  1939. X
  1940. X/* input.c */
  1941. Xextern void initinput(void);
  1942. Xextern Node *parseline(char *);
  1943. Xextern int gchar(void);
  1944. Xextern void ugchar(int);
  1945. Xextern Node *doit(bool);
  1946. Xextern void flushu(void);
  1947. Xextern void pushfd(int);
  1948. Xextern void pushstring(char **, bool);
  1949. Xextern void popinput(void);
  1950. Xextern void closefds(void);
  1951. Xextern int last;
  1952. Xextern bool rcrc;
  1953. X
  1954. X/* lex.c */
  1955. Xextern int yylex(void);
  1956. Xextern void inityy(void);
  1957. Xextern void yyerror(const char *);
  1958. Xextern void scanerror(char *);
  1959. Xextern void print_prompt2(void);
  1960. Xextern const char nw[], dnw[];
  1961. X
  1962. X/* list.c */
  1963. Xextern void listfree(List *);
  1964. Xextern List *listcpy(List *, void *(*)(SIZE_T));
  1965. Xextern SIZE_T listlen(List *);
  1966. Xextern int listnel(List *);
  1967. X
  1968. X/* match.c */
  1969. Xextern bool match(char *, char *, char *);
  1970. X
  1971. X/* alloc.c */
  1972. Xextern void *ealloc(SIZE_T);
  1973. Xextern void *erealloc(void *, SIZE_T);
  1974. Xextern void efree(void *);
  1975. Xextern Block *newblock(void);
  1976. Xextern void *nalloc(SIZE_T);
  1977. Xextern void nfree(void);
  1978. Xextern void restoreblock(Block *);
  1979. X
  1980. X/* open.c */
  1981. Xextern int rc_open(const char *, redirtype);
  1982. X
  1983. X/* print.c */
  1984. X/*
  1985. X   The following prototype should be:
  1986. Xextern Conv fmtinstall(int, Conv);
  1987. X   but this freaks out SGI's compiler under IRIX3.3.2
  1988. X*/
  1989. Xextern bool (*fmtinstall(int, bool (*)(Format *, int)))(Format *, int);
  1990. Xextern int printfmt(Format *, const char *);
  1991. Xextern int fmtprint(Format *, const char *,...);
  1992. Xextern void fmtappend(Format *, const char *, SIZE_T);
  1993. Xextern void fmtcat(Format *, const char *);
  1994. Xextern int fprint(int fd, const char *fmt,...);
  1995. Xextern char *mprint(const char *fmt,...);
  1996. Xextern char *nprint(const char *fmt,...);
  1997. X/*
  1998. X   the following macro should by rights be coded as an expression, not
  1999. X   a statement, but certain compilers (notably DEC) have trouble with
  2000. X   void expressions inside the ?: operator. (sheesh, give me a break!)
  2001. X*/
  2002. X#define    fmtputc(f, c) {\
  2003. X    if ((f)->buf >= (f)->bufend)\
  2004. X        (*(f)->grow)((f), (SIZE_T)1);\
  2005. X    *(f)->buf++ = (c);\
  2006. X}
  2007. X
  2008. X/* y.tab.c (parse.y) */
  2009. Xextern Node *parsetree;
  2010. Xextern int yyparse(void);
  2011. Xextern void initparse(void);
  2012. X
  2013. X/* redir.c */
  2014. Xextern void doredirs(void);
  2015. X
  2016. X/* signal.c */
  2017. Xextern void initsignal(void);
  2018. Xextern void catcher(int);
  2019. Xextern void sigchk(void);
  2020. Xextern void (*rc_signal(int, void (*)(int)))(int);
  2021. Xextern void (*sighandlers[])(int);
  2022. Xextern volatile SIG_ATOMIC_T slow, interrupt_happened;
  2023. X#define SIGCHK sigchk()
  2024. X
  2025. X/* status.c */
  2026. Xextern int istrue(void);
  2027. Xextern int getstatus(void);
  2028. Xextern void set(bool);
  2029. Xextern void setstatus(int, int);
  2030. Xextern List *sgetstatus(void);
  2031. Xextern void setpipestatus(int [], int);
  2032. Xextern void statprint(int, int);
  2033. Xextern void ssetstatus(char **);
  2034. X
  2035. X/* tree.c */
  2036. Xextern Node *mk(int /*nodetype*/,...);
  2037. Xextern Node *treecpy(Node *, void *(*)(SIZE_T));
  2038. Xextern void treefree(Node *);
  2039. X
  2040. X/* utils.c */
  2041. Xextern bool isabsolute(char *);
  2042. Xextern int n2u(char *, unsigned int);
  2043. Xextern int rc_read(int, char *, SIZE_T);
  2044. Xextern int mvfd(int, int);
  2045. Xextern int starstrcmp(const void *, const void *);
  2046. Xextern void pr_error(char *);
  2047. Xextern char *clear(char *, SIZE_T);
  2048. Xextern void panic(char *);
  2049. Xextern void uerror(char *);
  2050. Xextern void writeall(int, char *, SIZE_T);
  2051. X
  2052. X/* wait.c */
  2053. Xextern int rc_fork(void);
  2054. Xextern int rc_wait4(int, int *, bool);
  2055. Xextern List *sgetapids(void);
  2056. Xextern void waitforall(void);
  2057. Xextern bool forked;
  2058. X
  2059. X/* walk.c */
  2060. Xextern bool walk(Node *, bool);
  2061. Xextern bool cond;
  2062. X
  2063. END_OF_FILE
  2064.   if test 9028 -ne `wc -c <'rc.h'`; then
  2065.     echo shar: \"'rc.h'\" unpacked with wrong size!
  2066.   fi
  2067.   # end of 'rc.h'
  2068. fi
  2069. if test -f 'var.c' -a "${1}" != "-c" ; then 
  2070.   echo shar: Will not clobber existing file \"'var.c'\"
  2071. else
  2072.   echo shar: Extracting \"'var.c'\" \(5988 characters\)
  2073.   sed "s/^X//" >'var.c' <<'END_OF_FILE'
  2074. X/* var.c: provide "public" functions for adding and removing variables from the symbol table */
  2075. X
  2076. X#include "rc.h"
  2077. X
  2078. Xstatic void colonassign(char *, List *, bool);
  2079. Xstatic void listassign(char *, List *, bool);
  2080. Xstatic int hasalias(char *);
  2081. X
  2082. Xstatic char *const aliases[] = {
  2083. X    "home", "HOME", "path", "PATH", "cdpath", "CDPATH"
  2084. X};
  2085. X
  2086. X/* assign a variable in List form to a name, stacking if appropriate */
  2087. X
  2088. Xextern void varassign(char *name, List *def, bool stack) {
  2089. X    Variable *new;
  2090. X    List *newdef = listcpy(def, ealloc); /* important to do the listcpy first; get_var_place() frees old values */
  2091. X    new = get_var_place(name, stack);
  2092. X    new->def = newdef;
  2093. X    new->extdef = NULL;
  2094. X#ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
  2095. X    if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) {
  2096. X        extern void rl_reset_terminal(char *);
  2097. X        rl_reset_terminal(NULL);
  2098. X    }
  2099. X#endif
  2100. X}
  2101. X
  2102. X/* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
  2103. X
  2104. Xextern bool varassign_string(char *extdef) {
  2105. X    static bool aliasset[arraysize(aliases)] = {
  2106. X        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
  2107. X    };
  2108. X    char *name = get_name(extdef);
  2109. X    Variable *new;
  2110. X    int i;
  2111. X    if (name == NULL)
  2112. X        return FALSE; /* add it to bozo env */
  2113. X    if ((i = hasalias(name)) != -1) {
  2114. X        aliasset[i] = TRUE;
  2115. X        i ^= 1;                 /* set i to the "opposite" case subscript and */
  2116. X        if (i&1 && aliasset[i])        /* don't alias variables that are already set in upper case */
  2117. X            return TRUE;
  2118. X    }
  2119. X    new = get_var_place(name, FALSE);
  2120. X    new->def = NULL;
  2121. X    new->extdef = ealloc(strlen(extdef) + 1);
  2122. X    strcpy(new->extdef, extdef);
  2123. X    if (i != -1)
  2124. X        alias(name, varlookup(name), FALSE);
  2125. X    return TRUE;
  2126. X}
  2127. X
  2128. X/*
  2129. X   Return a List based on a name lookup. If the list is in external (string) form,
  2130. X   convert it to internal (List) form. Treat $n (n is an integer) specially as $*(n).
  2131. X   Also check to see if $status is being dereferenced. (we lazily evaluate the List
  2132. X   associated with $status)
  2133. X*/
  2134. X
  2135. Xextern List *varlookup(char *name) {
  2136. X    Variable *look;
  2137. X    List *ret, *l;
  2138. X    int sub;
  2139. X    if (streq(name, "status"))
  2140. X        return sgetstatus();
  2141. X    if (streq(name, "apids"))
  2142. X        return sgetapids();
  2143. X    if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
  2144. X        for (l = varlookup("*"); l != NULL && sub != 0; --sub)
  2145. X            l = l->n;
  2146. X        if (l == NULL)
  2147. X            return NULL;
  2148. X        ret = nnew(List);
  2149. X        ret->w = l->w;
  2150. X        ret->m = NULL;
  2151. X        ret->n = NULL;
  2152. X        return ret;
  2153. X    }
  2154. X    look = lookup_var(name);
  2155. X    if (look == NULL)
  2156. X        return NULL; /* not found */
  2157. X    if (look->def != NULL)
  2158. X        return look->def;
  2159. X    if (look->extdef == NULL)
  2160. X        return NULL; /* variable was set to null, e.g., a=() echo foo */
  2161. X    ret = parse_var(name, look->extdef);
  2162. X    if (ret == NULL) {
  2163. X        look->extdef = NULL;
  2164. X        return NULL;
  2165. X    }
  2166. X    return look->def = ret;
  2167. X}
  2168. X
  2169. X/* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */
  2170. X
  2171. Xextern char *varlookup_string(char *name) {
  2172. X    Variable *look;
  2173. X    look = lookup_var(name);
  2174. X    if (look == NULL)
  2175. X        return NULL;
  2176. X    if (look->extdef != NULL)
  2177. X        return look->extdef;
  2178. X    if (look->def == NULL)
  2179. X        return NULL;
  2180. X    return look->extdef = list2str(name, look->def);
  2181. X}
  2182. X
  2183. X/* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
  2184. X
  2185. Xextern void varrm(char *name, bool stack) {
  2186. X    int i = hasalias(name);
  2187. X    if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
  2188. X        varassign("*", varlookup("0"), FALSE);
  2189. X        return;
  2190. X    }
  2191. X    delete_var(name, stack);
  2192. X    if (i != -1)
  2193. X        delete_var(aliases[i^1], stack);
  2194. X}
  2195. X
  2196. X/* assign a value (List) to a variable, using array "a" as input. Used to assign $* */
  2197. X
  2198. Xextern void starassign(char *dollarzero, char **a, bool stack) {
  2199. X    List *s, *var;
  2200. X    var = nnew(List);
  2201. X    var->w = dollarzero;
  2202. X    if (*a == NULL) {
  2203. X        var->n = NULL;
  2204. X        varassign("*", var, stack);
  2205. X        return;
  2206. X    }
  2207. X    var->n = s = nnew(List);
  2208. X    while (1) {
  2209. X        s->w = *a++;
  2210. X        if (*a == NULL) {
  2211. X            s->n = NULL;
  2212. X            break;
  2213. X        } else
  2214. X            s = s->n = nnew(List);
  2215. X    }
  2216. X    varassign("*", var, stack);
  2217. X}
  2218. X
  2219. X/* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */
  2220. X
  2221. Xstatic void colonassign(char *name, List *def, bool stack) {
  2222. X    List dud;
  2223. X    if (def == NULL) {
  2224. X        varassign(name, NULL, stack);
  2225. X        return;
  2226. X    }
  2227. X    dud.w = nprint("%-L", def, ":");
  2228. X    dud.n = NULL;
  2229. X    varassign(name, &dud, stack);
  2230. X}
  2231. X
  2232. X/* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */
  2233. X
  2234. Xstatic void listassign(char *name, List *def, bool stack) {
  2235. X    List *val, *r;
  2236. X    char *v, *w;
  2237. X    if (def == NULL) {
  2238. X        varassign(name, NULL, stack);
  2239. X        return;
  2240. X    }
  2241. X    v = def->w;
  2242. X    r = val = enew(List);
  2243. X    while ((w = strchr(v, ':')) != NULL) {
  2244. X        *w = '\0';
  2245. X        r->w = ecpy(v);
  2246. X        *w = ':';
  2247. X        v = w + 1;
  2248. X        r->n = enew(List);
  2249. X        r = r->n;
  2250. X    }
  2251. X    r->w = ecpy(v);
  2252. X    r->n = NULL;
  2253. X    varassign(name, val, stack);
  2254. X}
  2255. X
  2256. X/* check to see if a particular variable is aliased; return -1 on failure, or the index */
  2257. X
  2258. Xstatic int hasalias(char *name) {
  2259. X    int i;
  2260. X    for (i = 0; i < arraysize(aliases); i++)
  2261. X        if (streq(name, aliases[i]))
  2262. X            return i;
  2263. X    return -1;
  2264. X}
  2265. X
  2266. X/* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */
  2267. X
  2268. Xextern void alias(char *name, List *s, bool stack) {
  2269. X    static void (*vectors[])(char *, List *, bool) = {
  2270. X        varassign, varassign, colonassign, listassign, colonassign, listassign
  2271. X    };
  2272. X    int i = hasalias(name);
  2273. X    if (i != -1)
  2274. X        (*vectors[i])(aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
  2275. X}
  2276. X
  2277. Xextern void prettyprint_var(int fd, char *name, List *s) {
  2278. X    int i;
  2279. X    static const char * const keywords[] = {
  2280. X        "if", "in", "fn", "for", "else", "switch", "while", "case"
  2281. X    };
  2282. X    if (s == NULL) {
  2283. X        fprint(fd, "%S=()\n", name);
  2284. X        return;
  2285. X    }
  2286. X    if (streq(name, "*")) {
  2287. X        s = s->n;
  2288. X        if (s == NULL)
  2289. X            return; /* Don't print $0, and if $* is not set, skip it */
  2290. X    }
  2291. X    for (i = 0; i < arraysize(keywords); i++)
  2292. X        if (streq(keywords[i], name)) {
  2293. X            fprint(fd, "%#S=", name);
  2294. X            goto value;
  2295. X        }
  2296. X    fprint(fd, "%S=", name);
  2297. Xvalue:
  2298. X    fprint(fd, s->n == NULL ? "%L\n" : "(%L)\n", s, " ");
  2299. X}
  2300. END_OF_FILE
  2301.   if test 5988 -ne `wc -c <'var.c'`; then
  2302.     echo shar: \"'var.c'\" unpacked with wrong size!
  2303.   fi
  2304.   # end of 'var.c'
  2305. fi
  2306. if test -f 'version.c' -a "${1}" != "-c" ; then 
  2307.   echo shar: Will not clobber existing file \"'version.c'\"
  2308. else
  2309.   echo shar: Extracting \"'version.c'\" \(50 characters\)
  2310.   sed "s/^X//" >'version.c' <<'END_OF_FILE'
  2311. Xconst char id[] = "@(#)rc version 1.4, 5/26/92.";
  2312. END_OF_FILE
  2313.   if test 50 -ne `wc -c <'version.c'`; then
  2314.     echo shar: \"'version.c'\" unpacked with wrong size!
  2315.   fi
  2316.   # end of 'version.c'
  2317. fi
  2318. echo shar: End of archive 5 \(of 7\).
  2319. cp /dev/null ark5isdone
  2320. MISSING=""
  2321. for I in 1 2 3 4 5 6 7 ; do
  2322.     if test ! -f ark${I}isdone ; then
  2323.     MISSING="${MISSING} ${I}"
  2324.     fi
  2325. done
  2326. if test "${MISSING}" = "" ; then
  2327.     echo You have unpacked all 7 archives.
  2328.     rm -f ark[1-9]isdone
  2329. else
  2330.     echo You still must unpack the following archives:
  2331.     echo "        " ${MISSING}
  2332. fi
  2333. exit 0
  2334. exit 0 # Just in case...
  2335.