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

  1. Newsgroups: comp.sources.misc
  2. From: byron@archone.tamu.edu (Byron Rakitzis)
  3. Subject:  v30i029:  rc - A Plan 9 shell reimplementation, v1.4, Part06/07
  4. Message-ID: <1992May30.031727.5606@sparky.imd.sterling.com>
  5. X-Md4-Signature: 966e76fd65ade8700d2d3682daadb8d3
  6. Date: Sat, 30 May 1992 03:17:27 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
  10. Posting-number: Volume 30, Issue 29
  11. Archive-name: rc/part06
  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:  COPYRIGHT Makefile config.h-dist except.c exec.c execve.c
  22. #   getopt.c jbwrap.h list.c main.c match.c mksignal nalloc.c proto.h
  23. #   redir.c signal.c status.c tree.c utils.c wait.c which.c
  24. # Wrapped by kent@sparky on Fri May 29 20:55:24 1992
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. echo If this archive is complete, you will see the following message:
  27. echo '          "shar: End of archive 6 (of 7)."'
  28. if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'COPYRIGHT'\"
  30. else
  31.   echo shar: Extracting \"'COPYRIGHT'\" \(1106 characters\)
  32.   sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
  33. X/*
  34. X * Copyright 1991 Byron Rakitzis.  All rights reserved.
  35. X *
  36. X * This software is not subject to any license of the American Telephone
  37. X * and Telegraph Company or of the Regents of the University of California.
  38. X *
  39. X * Permission is granted to anyone to use this software for any purpose on
  40. X * any computer system, and to alter it and redistribute it freely, subject
  41. X * to the following restrictions:
  42. X *
  43. X * 1. The author is not responsible for the consequences of use of this
  44. X *    software, no matter how awful, even if they arise from flaws in it.
  45. X *
  46. X * 2. The origin of this software must not be misrepresented, either by
  47. X *    explicit claim or by omission.  Since few users ever read sources,
  48. X *    credits must appear in the documentation.
  49. X *
  50. X * 3. Altered versions must be plainly marked as such, and must not be
  51. X *    misrepresented as being the original software.  Since few users
  52. X *    ever read sources, credits must appear in the documentation.
  53. X *
  54. X * 4. This notice may not be removed or altered.
  55. X *
  56. X *    [this copyright notice is adapted from Henry Spencer's
  57. X *    "awf" copyright notice.]
  58. X */
  59. END_OF_FILE
  60.   if test 1106 -ne `wc -c <'COPYRIGHT'`; then
  61.     echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
  62.   fi
  63.   # end of 'COPYRIGHT'
  64. fi
  65. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  66.   echo shar: Will not clobber existing file \"'Makefile'\"
  67. else
  68.   echo shar: Extracting \"'Makefile'\" \(1699 characters\)
  69.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  70. X# Makefile for rc.
  71. X
  72. X# Please check the configuration parameters in config.h (and if you want
  73. X# to make sure, the definitions in proto.h) to make sure they are correct
  74. X# for your system.
  75. X
  76. XSHELL=/bin/sh
  77. X
  78. X# Uncomment this line if you have defined the NOEXECVE macro in config.h
  79. X#EXECVE=execve.o
  80. X
  81. X# Define this macro if you wish to extend rc via locally-defined builtins.
  82. X# An interface is provided in addon.[ch]. Note that the author does not
  83. X# endorse any such extensions, rather hopes that this way rc will become
  84. X# useful to more people.
  85. X#ADDON=addon.o
  86. X
  87. X# Use an ANSI compiler (or at least one that groks prototypes and void *):
  88. XCC=gcc -g -O
  89. XCFLAGS=
  90. XLDFLAGS=
  91. X
  92. X# You may substitute "bison -y" for yacc. (You want to choose the one that
  93. X# makes a smaller y.tab.c.)
  94. XYACC=yacc
  95. X
  96. XOBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \
  97. X    glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \
  98. X    nalloc.o open.o print.o redir.o sigmsgs.o signal.o status.o tree.o \
  99. X    utils.o var.o version.o wait.o walk.o which.o y.tab.o
  100. X
  101. X# If rc is compiled with READLINE defined, you must supply the correct
  102. X# arguments to ld on this line. Typically this would be something like:
  103. X#
  104. X#    $(CC) -o $@ $(OBJS) -lreadline -ltermcap
  105. X
  106. Xrc: $(OBJS)
  107. X    $(CC) -o $@ $(OBJS) $(LDFLAGS)
  108. X
  109. Xsigmsgs.c: mksignal
  110. X    sh mksignal /usr/include/sys/signal.h
  111. X
  112. Xy.tab.c: parse.y
  113. X    $(YACC) -d parse.y
  114. X
  115. Xconfig.h: config.h-dist
  116. X    cp config.h-dist config.h
  117. X
  118. Xtrip: rc
  119. X    ./rc -p < trip.rc
  120. X
  121. Xclean: force
  122. X    rm -f *.o *.tab.* sigmsgs.*
  123. X
  124. Xhistory: force
  125. X    cd history; make CC="$(CC)" $(HISTORYMAKEFLAGS)
  126. X
  127. Xforce:
  128. X
  129. X# dependencies:
  130. X
  131. X$(OBJS): config.h
  132. Xsigmsgs.h: sigmsgs.c
  133. Xlex.o y.tab.o: y.tab.c
  134. Xbuiltins.c fn.c status.c hash.c: sigmsgs.h
  135. END_OF_FILE
  136.   if test 1699 -ne `wc -c <'Makefile'`; then
  137.     echo shar: \"'Makefile'\" unpacked with wrong size!
  138.   fi
  139.   # end of 'Makefile'
  140. fi
  141. if test -f 'config.h-dist' -a "${1}" != "-c" ; then 
  142.   echo shar: Will not clobber existing file \"'config.h-dist'\"
  143. else
  144.   echo shar: Extracting \"'config.h-dist'\" \(5082 characters\)
  145.   sed "s/^X//" >'config.h-dist' <<'END_OF_FILE'
  146. X/* Copy config.h-dist to config.h and edit config.h, don't edit this file */
  147. X
  148. X/*
  149. X * Configuration parameters for rc. Suggested defaults are at the bottom
  150. X * of this file (you should probably look at those first to see if your
  151. X * system matches one of them; you can search for the beginning of the
  152. X * defaults section by looking for the string "#ifndef CUSTOM"). If you
  153. X * want to override the suggested defaults, define the macro CUSTOM.
  154. X#define CUSTOM
  155. X */
  156. X
  157. X/*
  158. X * (Note that certain default settings redefine this macro)
  159. X * DEFAULTPATH the default search path that rc uses when it is started
  160. X * without either a $PATH or $path environment variable. You must pick
  161. X * something sensible for your system if you don't like the path shown
  162. X * below.
  163. X */
  164. X#define DEFAULTPATH "/usr/ucb", "/usr/bin", "/bin", "."
  165. X
  166. X/*
  167. X * Define the macro NODIRENT if your system has <sys/dir.h> but not
  168. X * <dirent.h>. (e.g., NeXT-OS and RISCos)
  169. X#define NODIRENT
  170. X */
  171. X
  172. X/*
  173. X * Define the macro SVSIGS if your system has System V signal semantics,
  174. X * i.e., if "slow" system calls are interrupted rather than resumed
  175. X * after returning from an interrupt handler. (If you are not sure what
  176. X * this means, see the man page for signal(2). In any case, it is probably
  177. X * safe to leave this macro undefined.)
  178. X#define SVSIGS
  179. X */
  180. X
  181. X/*
  182. X * Define the macro NOCMDARG if you do not have /dev/fd or fifos on your
  183. X * system. You may also want to define this if you have broken fifos.
  184. X#define NOCMDARG
  185. X */
  186. X
  187. X/*
  188. X * Define TMPDIR if you need to have rc create its fifos in a directory
  189. X * other than /tmp. For example, if you have a Sun with /tmp mounted
  190. X * as a ramdisk (type "tmpfs") then you cannot use fifos in /tmp (sigh).
  191. X#define TMPDIR "/var/tmp"
  192. X */
  193. X
  194. X/*
  195. X * Define the macro DEVFD if your system supports /dev/fd.
  196. X#define DEVFD
  197. X */
  198. X
  199. X/*
  200. X * Define the macro NOLIMITS if your system does not support Berkeley
  201. X * limits.
  202. X#define NOLIMITS
  203. X */
  204. X
  205. X/*
  206. X * Define the macro NOSIGCLD if your system uses SIGCLD in the System
  207. X * V way. (e.g., sgi's Irix)
  208. X#define NOSIGCLD
  209. X */
  210. X
  211. X/*
  212. X * Define the macro READLINE if you want rc to call GNU readline
  213. X * instead of read(2) on interactive shells.
  214. X#define READLINE
  215. X */
  216. X
  217. X/*
  218. X * Define the macro NOEXECVE if your Unix does not interpret #! in the
  219. X * kernel, and uncomment the EXECVE variable in the Makefile.
  220. X#define NOEXECVE
  221. X */
  222. X
  223. X/*
  224. X * If you want rc to default to some interpreter for files which don't
  225. X * have a legal #! on the first line, define the macro DEFAULTINTERP.
  226. X#define DEFAULTINTERP "/bin/sh"
  227. X */
  228. X
  229. X/*
  230. X * If your /bin/sh (or another program you care about) rejects environment
  231. X * variables with special characters in them (such as ':' or '-'), rc can
  232. X * put out ugly variable names using [_0-9a-zA-Z] that encode the real name;
  233. X * define PROTECT_ENV for this hack. (Known offenders: every sh I have tried;
  234. X * SunOS (silently discards), NeXT (aborts with error), SGI (aborts with
  235. X * error), Ultrix (sh seems to work, sh5 aborts with error))
  236. X#define PROTECT_ENV
  237. X */
  238. X
  239. X/*
  240. X * Define the macro NOECHO if you wish to omit rc's echo builtin from the
  241. X * compile.
  242. X#define NOECHO
  243. X */
  244. X
  245. X/*
  246. X * Define the NOJOB if you do *not* wish rc to perform backgrounding
  247. X * as if it were a job-control shell; that is, if you do *not* wish
  248. X * it to put a command spawned in the background into a new process
  249. X * group. Since most systems support job control and since there are
  250. X * many broken programs that do not behave correctly when backgrounded
  251. X * in a v7 non-job-control fashion, rc by default performs a job-
  252. X * control-like backgrounding.
  253. X#define NOJOB
  254. X */
  255. X
  256. X/* Beginning of defaults section: */
  257. X
  258. X#ifndef CUSTOM
  259. X
  260. X/*
  261. X * Suggested settings for Sun, NeXT and sgi (machines here at TAMU):
  262. X */
  263. X
  264. X#ifdef NeXT        /* Used on NextOS 2.1 */
  265. X#define NODIRENT
  266. X#define    PROTECT_ENV
  267. X#define NOCMDARG
  268. X#endif
  269. X
  270. X#ifdef sgi        /* Used on Irix 3.3.[12] */
  271. X#define SVSIGS
  272. X#define NOSIGCLD
  273. X#define    PROTECT_ENV
  274. X#undef DEFAULTPATH
  275. X#define DEFAULTPATH "/usr/bsd", "/usr/sbin", "/usr/bin", "/bin", "."
  276. X#endif
  277. X
  278. X#ifdef sun        /* Used on SunOS 4.1.1 */
  279. X#define PROTECT_ENV
  280. X#undef DEFAULTPATH
  281. X#define DEFAULTPATH "/usr/ucb", "/usr/bin", "."
  282. X#endif
  283. X
  284. X/*
  285. X * Suggested settings for HP300 running 4.3BSD-utah (DWS):
  286. X */
  287. X
  288. X#if defined(hp300) && !defined(hpux)
  289. X#define NODIRENT
  290. X#define NOCMDARG
  291. X#define DEFAULTINTERP "/bin/sh"
  292. X#define PROTECT_ENV
  293. X#endif
  294. X
  295. X/*
  296. X * Suggested settings for Ultrix
  297. X */
  298. X
  299. X#ifdef ultrix
  300. X#define PROTECT_ENV
  301. X#define DEFAULTINTERP "/bin/sh"    /* so /bin/true can work */
  302. X#endif
  303. X
  304. X/*
  305. X * Suggested settings for RISCos 4.52
  306. X */
  307. X
  308. X/*
  309. X   This doesn't work without interfering with other MIPS-based
  310. X   systems' configuration. Please do it by hand.
  311. X*/
  312. X
  313. X#if defined(host_mips) && defined(MIPSEB) && defined(SYSTYPE_BSD43)
  314. X#define NODIRENT
  315. X#define PROTECT_ENV
  316. X#endif
  317. X
  318. X/*
  319. X * Suggested settings for AIX
  320. X */
  321. X
  322. X#ifdef _AIX
  323. X#define PROTECT_ENV
  324. X#endif
  325. X
  326. X/*
  327. X * Suggested settings for OSF/1 1.0
  328. X */
  329. X
  330. X#ifdef OSF1
  331. X#define PROTECT_ENV
  332. X#endif
  333. X
  334. X/*
  335. X * Suggested settings for Unicos XXX
  336. X */
  337. X
  338. X#ifdef cray
  339. X#define PROTECT_ENV
  340. X#define NOLIMITS
  341. X#define word _word
  342. X#define DEFAULTINTERP "/bin/sh"
  343. X#endif
  344. X
  345. X#endif /* CUSTOM */
  346. X
  347. X#ifndef TMPDIR
  348. X#define TMPDIR "/tmp"
  349. X#endif
  350. END_OF_FILE
  351.   if test 5082 -ne `wc -c <'config.h-dist'`; then
  352.     echo shar: \"'config.h-dist'\" unpacked with wrong size!
  353.   fi
  354.   # end of 'config.h-dist'
  355. fi
  356. if test -f 'except.c' -a "${1}" != "-c" ; then 
  357.   echo shar: Will not clobber existing file \"'except.c'\"
  358. else
  359.   echo shar: Extracting \"'except.c'\" \(3330 characters\)
  360.   sed "s/^X//" >'except.c' <<'END_OF_FILE'
  361. X#include <setjmp.h>
  362. X#include <signal.h>
  363. X#include "rc.h"
  364. X#include "jbwrap.h"
  365. X
  366. X/*
  367. X   A return goes back stack frames to the last return. A break does
  368. X   not. A signal goes to the last interactive level. (see below)
  369. X*/
  370. X
  371. Xbool nl_on_intr = TRUE;
  372. X
  373. Xstatic Estack *estack;
  374. X
  375. X/* add an exception to the input stack. */
  376. X
  377. Xextern void except(ecodes e, Edata data, Estack *ex) {
  378. X    ex->prev = estack;
  379. X    estack = ex;
  380. X    estack->e = e;
  381. X    estack->data = data;
  382. X    if (e == eError || e == eBreak || e == eReturn)
  383. X        estack->interactive = interactive;
  384. X}
  385. X
  386. X/* remove an exception, restore last interactive value */
  387. X
  388. Xextern void unexcept() {
  389. X    switch (estack->e) {
  390. X    default:
  391. X        break;
  392. X    case eError:
  393. X        interactive = estack->interactive;
  394. X        break;
  395. X    case eArena:
  396. X        restoreblock(estack->data.b);
  397. X        break;
  398. X    case eFifo:
  399. X        unlink(estack->data.name);
  400. X        break;
  401. X    case eFd:
  402. X        close(estack->data.fd);
  403. X        break;
  404. X    }
  405. X    estack = estack->prev;
  406. X}
  407. X
  408. X/*
  409. X   Raise an exception. The rules are pretty complicated: you can return
  410. X   from a loop inside a function, but you can't break from a function
  411. X   inside of a loop. On errors, rc_raise() goes back to the LAST
  412. X   INTERACTIVE stack frame. If no such frame exists, then rc_raise()
  413. X   exits the shell.  This is what happens, say, when there is a syntax
  414. X   error in a noninteractive shell script. While traversing the
  415. X   exception stack backwards, rc_raise() also removes input sources
  416. X   (closing file-descriptors, etc.) and pops instances of variables
  417. X   that have been pushed onto the variable stack (e.g., for a function
  418. X   call (for $*) or a local assignment).
  419. X*/
  420. X
  421. Xextern void rc_raise(ecodes e) {
  422. X    if (e == eError && rc_pid != getpid())
  423. X        exit(1); /* child processes exit on an error/signal */
  424. X    for (; estack != NULL; estack = estack->prev)
  425. X        if (estack->e != e) {
  426. X            if (e == eBreak && estack->e != eArena)
  427. X                rc_error("break outside of loop");
  428. X            else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */
  429. X                rc_error("return outside of function");
  430. X            switch (estack->e) {
  431. X            default:
  432. X                break;
  433. X            case eVarstack:
  434. X                varrm(estack->data.name, TRUE);
  435. X                break;
  436. X            case eArena:
  437. X                restoreblock(estack->data.b);
  438. X                break;
  439. X            case eFifo:
  440. X                unlink(estack->data.name);
  441. X                break;
  442. X            case eFd:
  443. X                close(estack->data.fd);
  444. X                break;
  445. X            }
  446. X        } else {
  447. X            if (e == eError && !estack->interactive) {
  448. X                popinput();
  449. X            } else {
  450. X                Jbwrap *j = estack->data.jb;
  451. X
  452. X                interactive = estack->interactive;
  453. X                estack = estack->prev;
  454. X                longjmp(j->j, 1);
  455. X            }
  456. X        }
  457. X    rc_exit(1); /* top of exception stack */
  458. X}
  459. X
  460. Xextern bool outstanding_cmdarg() {
  461. X    return estack->e == eFifo || estack->e == eFd;
  462. X}
  463. X
  464. Xextern void pop_cmdarg(bool remove) {
  465. X    for (; estack != NULL; estack = estack->prev)
  466. X        switch (estack->e) {
  467. X        case eFifo:
  468. X            if (remove)
  469. X                unlink(estack->data.name);
  470. X            break;
  471. X        case eFd:
  472. X            if (remove)
  473. X                close(estack->data.fd);
  474. X            break;
  475. X        default:
  476. X            return;
  477. X        }
  478. X}
  479. X
  480. X/* exception handlers */
  481. X
  482. Xextern void rc_error(char *s) {
  483. X    pr_error(s);
  484. X    set(FALSE);
  485. X    redirq = NULL;
  486. X    cond = FALSE; /* no longer inside conditional */
  487. X    rc_raise(eError);
  488. X}
  489. X
  490. Xextern void sigint(int s) {
  491. X    if (s != SIGINT)
  492. X        panic("s != SIGINT in sigint catcher");
  493. X    /* this is the newline you see when you hit ^C while typing a command */
  494. X    if (nl_on_intr)
  495. X        fprint(2, "\n");
  496. X    nl_on_intr = TRUE;
  497. X    redirq = NULL;
  498. X    cond = FALSE;
  499. X    rc_raise(eError);
  500. X}
  501. END_OF_FILE
  502.   if test 3330 -ne `wc -c <'except.c'`; then
  503.     echo shar: \"'except.c'\" unpacked with wrong size!
  504.   fi
  505.   # end of 'except.c'
  506. fi
  507. if test -f 'exec.c' -a "${1}" != "-c" ; then 
  508.   echo shar: Will not clobber existing file \"'exec.c'\"
  509. else
  510.   echo shar: Extracting \"'exec.c'\" \(2668 characters\)
  511.   sed "s/^X//" >'exec.c' <<'END_OF_FILE'
  512. X/* exec.c */
  513. X#include <signal.h>
  514. X#include <errno.h>
  515. X#include <setjmp.h>
  516. X#include "rc.h"
  517. X#include "jbwrap.h"
  518. X
  519. X/*
  520. X   Takes an argument list and does the appropriate thing (calls a
  521. X   builtin, calls a function, etc.)
  522. X*/
  523. X
  524. Xextern void exec(List *s, bool parent) {
  525. X    char **av, **ev = NULL;
  526. X    int pid, stat;
  527. X    builtin_t *b;
  528. X    char *path = NULL;
  529. X    bool didfork, returning, saw_exec, saw_builtin;
  530. X    av = list2array(s, dashex);
  531. X    saw_builtin = saw_exec = FALSE;
  532. X    do {
  533. X        if (*av == NULL    || isabsolute(*av))
  534. X            b = NULL;
  535. X        else if (!saw_builtin && fnlookup(*av) != NULL)
  536. X            b = funcall;
  537. X        else
  538. X            b = isbuiltin(*av);
  539. X
  540. X        /*
  541. X           a builtin applies only to the immmediately following
  542. X           command, e.g., builtin exec echo hi
  543. X        */
  544. X        saw_builtin = FALSE;
  545. X
  546. X        if (b == b_exec) {
  547. X            av++;
  548. X            saw_exec = TRUE;
  549. X            parent = FALSE;
  550. X        } else if (b == b_builtin) {
  551. X            av++;
  552. X            saw_builtin = TRUE;
  553. X        }
  554. X    } while (b == b_exec || b == b_builtin);
  555. X    if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
  556. X        doredirs();
  557. X        return;
  558. X    }
  559. X    /* force an exit on exec with any rc_error, but not for null commands as above */
  560. X    if (saw_exec)
  561. X        rc_pid = -1;
  562. X    if (b == NULL) {
  563. X        path = which(*av, TRUE);
  564. X        if (path == NULL && *av != NULL) { /* perform null commands for redirections */
  565. X            set(FALSE);
  566. X            redirq = NULL;
  567. X            if (parent)
  568. X                return;
  569. X            rc_exit(1);
  570. X        }
  571. X        ev = makeenv(); /* environment only needs to be built for execve() */
  572. X    }
  573. X    /*
  574. X       If parent & the redirq is nonnull, builtin or not it has to fork.
  575. X       If the fifoq is nonnull, then it must be emptied at the end so we
  576. X       must fork no matter what.
  577. X     */
  578. X    if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) {
  579. X        pid = rc_fork();
  580. X        didfork = TRUE;
  581. X    } else {
  582. X        pid = 0;
  583. X        didfork = FALSE;
  584. X    }
  585. X    returning = (!didfork && parent);
  586. X    switch (pid) {
  587. X    case -1:
  588. X        uerror("fork");
  589. X        rc_error(NULL);
  590. X        /* NOTREACHED */
  591. X    case 0:
  592. X        if (!returning)
  593. X            setsigdefaults(FALSE);
  594. X        pop_cmdarg(FALSE);
  595. X        doredirs();
  596. X
  597. X        /* null commands performed for redirections */
  598. X        if (*av == NULL || b != NULL) {
  599. X            if (b != NULL)
  600. X                (*b)(av);
  601. X            if (returning)
  602. X                return;
  603. X            rc_exit(getstatus());
  604. X        }
  605. X#ifdef NOEXECVE
  606. X        my_execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */
  607. X#else
  608. X        execve(path, (const char **) av, (const char **) ev);
  609. X#endif
  610. X#ifdef DEFAULTINTERP
  611. X        if (errno == ENOEXEC) {
  612. X            *av = path;
  613. X            *--av = DEFAULTINTERP;
  614. X            execve(*av, (const char **) av, (const char **) ev);
  615. X        }
  616. X#endif
  617. X        uerror(*av);
  618. X        rc_exit(1);
  619. X        /* NOTREACHED */
  620. X    default:
  621. X        redirq = NULL;
  622. X        rc_wait4(pid, &stat, TRUE);
  623. X        setstatus(-1, stat);
  624. X        if ((stat & 0xff) == 0)
  625. X            nl_on_intr = FALSE;
  626. X        SIGCHK;
  627. X        nl_on_intr = TRUE;
  628. X        pop_cmdarg(TRUE);
  629. X    }
  630. X}
  631. END_OF_FILE
  632.   if test 2668 -ne `wc -c <'exec.c'`; then
  633.     echo shar: \"'exec.c'\" unpacked with wrong size!
  634.   fi
  635.   # end of 'exec.c'
  636. fi
  637. if test -f 'execve.c' -a "${1}" != "-c" ; then 
  638.   echo shar: Will not clobber existing file \"'execve.c'\"
  639. else
  640.   echo shar: Extracting \"'execve.c'\" \(1889 characters\)
  641.   sed "s/^X//" >'execve.c' <<'END_OF_FILE'
  642. X/* execve.c: an execve() for geriatric unices without #! */
  643. X
  644. X/*
  645. X   NOTE: this file depends on a hack in footobar.c which places two free spots before
  646. X   av[][] so that execve does not have to call malloc.
  647. X*/
  648. X
  649. X#include <errno.h>
  650. X#include "rc.h"
  651. X
  652. X#define giveupif(x) { if (x) goto fail; }
  653. X
  654. Xextern int my_execve(const char *path, const char **av, const char **ev) {
  655. X    int fd, len, fst, snd, end;
  656. X    bool noarg;
  657. X    char pb[256]; /* arbitrary but generous limit */
  658. X    execve(path, av, ev);
  659. X    if (errno != ENOEXEC)
  660. X        return -1;
  661. X    fd = rc_open(path, rFrom);
  662. X    giveupif(fd < 0);
  663. X    len = read(fd, pb, sizeof pb);
  664. X    close(fd);
  665. X    /* reject scripts which don't begin with #! */
  666. X    giveupif(len <= 0 || pb[0] != '#' || pb[1] != '!');
  667. X    for (fst = 2; fst < len && (pb[fst] == ' ' || pb[fst] == '\t'); fst++)
  668. X        ; /* skip leading whitespace */
  669. X    giveupif(fst == len);
  670. X    for (snd = fst; snd < len && pb[snd] != ' ' && pb[snd] != '\t' && pb[snd] != '\n'; snd++)
  671. X        ; /* skip first arg */
  672. X    giveupif(snd == len);
  673. X    noarg = (pb[snd] == '\n');
  674. X    pb[snd++] = '\0'; /* null terminate the first arg */
  675. X    if (!noarg) {
  676. X        while (snd < len && (pb[snd] == ' ' || pb[snd] == '\t'))
  677. X            snd++; /* skip whitespace to second arg */
  678. X        giveupif(snd == len);
  679. X        noarg = (pb[snd] == '\n'); /* could have trailing whitespace after only one arg */
  680. X        if (!noarg) {
  681. X            for (end = snd; end < len && pb[end] != ' ' && pb[end] != '\t' && pb[end] != '\n'; end++)
  682. X                ; /* skip to the end of the second arg */
  683. X            giveupif(end == len);
  684. X            if (pb[end] == '\n') {
  685. X                pb[end] = '\0'; /* null terminate the first arg */
  686. X            } else {        /* else check for a spurious third arg */
  687. X                pb[end++] = '\0';
  688. X                while (end < len && (pb[end] == ' ' || pb[end] == '\t'))
  689. X                    end++;
  690. X                giveupif(end == len || pb[end] != '\n');
  691. X            }
  692. X        }
  693. X    }
  694. X    *av = path;
  695. X    if (!noarg)
  696. X        *--av = pb + snd;
  697. X    *--av = pb + fst;
  698. X    execve(*av, av, ev);
  699. X    return -1;
  700. Xfail:    errno = ENOEXEC;
  701. X    return -1;
  702. X}
  703. END_OF_FILE
  704.   if test 1889 -ne `wc -c <'execve.c'`; then
  705.     echo shar: \"'execve.c'\" unpacked with wrong size!
  706.   fi
  707.   # end of 'execve.c'
  708. fi
  709. if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  710.   echo shar: Will not clobber existing file \"'getopt.c'\"
  711. else
  712.   echo shar: Extracting \"'getopt.c'\" \(1664 characters\)
  713.   sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
  714. X#include "rc.h"
  715. X
  716. Xint     rc_opterr = 1;
  717. Xint     rc_optind = 1;
  718. Xint     rc_optopt;
  719. Xchar    *rc_optarg;
  720. X
  721. X/* getopt routine courtesy of David Sanderson */
  722. Xextern int rc_getopt(int argc, char **argv, char *opts) {
  723. X        static int sp = 1;
  724. X        int c;
  725. X        char *cp;
  726. X    if (rc_optind == 0) /* reset rc_getopt() */
  727. X        rc_optind = sp = 1;
  728. X        if (sp == 1)
  729. X                if (rc_optind >= argc || argv[rc_optind][0] != '-' || argv[rc_optind][1] == '\0') {
  730. X                        return -1;
  731. X                } else if (strcmp(argv[rc_optind], "--") == 0) {
  732. X                        rc_optind++;
  733. X                        return -1;
  734. X                }
  735. X        rc_optopt = c = argv[rc_optind][sp];
  736. X        if (c == ':' || (cp=strchr(opts, c)) == 0) {
  737. X                fprint(2, "%s: bad option: -%c\n", argv[0], c);
  738. X                if (argv[rc_optind][++sp] == '\0') {
  739. X                        rc_optind++;
  740. X                        sp = 1;
  741. X                }
  742. X                return '?';
  743. X        }
  744. X        if (*++cp == ':') {
  745. X                if (argv[rc_optind][sp+1] != '\0') {
  746. X                        rc_optarg = &argv[rc_optind++][sp+1];
  747. X                } else if (++rc_optind >= argc) {
  748. X                        fprint(2, "%s: option requires an argument -- %c\n", argv[0], c);
  749. X                        sp = 1;
  750. X                        return '?';
  751. X                } else
  752. X                        rc_optarg = argv[rc_optind++];
  753. X                sp = 1;
  754. X        } else {
  755. X                if (argv[rc_optind][++sp] == '\0') {
  756. X                        sp = 1;
  757. X                        rc_optind++;
  758. X                }
  759. X                rc_optarg = NULL;
  760. X        }
  761. X        return c;
  762. X}
  763. END_OF_FILE
  764.   if test 1664 -ne `wc -c <'getopt.c'`; then
  765.     echo shar: \"'getopt.c'\" unpacked with wrong size!
  766.   fi
  767.   # end of 'getopt.c'
  768. fi
  769. if test -f 'jbwrap.h' -a "${1}" != "-c" ; then 
  770.   echo shar: Will not clobber existing file \"'jbwrap.h'\"
  771. else
  772.   echo shar: Extracting \"'jbwrap.h'\" \(269 characters\)
  773.   sed "s/^X//" >'jbwrap.h' <<'END_OF_FILE'
  774. X/* certain braindamaged environments don't define jmp_buf as an array, so... */
  775. X
  776. Xstruct Jbwrap {
  777. X    jmp_buf j;
  778. X};
  779. X
  780. Xextern Jbwrap slowbuf; /* for getting out of interrupts while performing slow i/o on BSD */
  781. X
  782. Xextern int setjmp(jmp_buf);
  783. Xextern void longjmp(jmp_buf, int);
  784. END_OF_FILE
  785.   if test 269 -ne `wc -c <'jbwrap.h'`; then
  786.     echo shar: \"'jbwrap.h'\" unpacked with wrong size!
  787.   fi
  788.   # end of 'jbwrap.h'
  789. fi
  790. if test -f 'list.c' -a "${1}" != "-c" ; then 
  791.   echo shar: Will not clobber existing file \"'list.c'\"
  792. else
  793.   echo shar: Extracting \"'list.c'\" \(1160 characters\)
  794.   sed "s/^X//" >'list.c' <<'END_OF_FILE'
  795. X/* list.c: routines for manipulating the List type */
  796. X
  797. X#include "rc.h"
  798. X
  799. X/*
  800. X   These list routines assign meta values of null to the resulting lists;
  801. X   it is impossible to glob with the value of a variable unless this value
  802. X   is rescanned with eval---therefore it is safe to throw away the meta-ness
  803. X   of the list.
  804. X*/
  805. X
  806. X/* free a list from malloc space */
  807. X
  808. Xextern void listfree(List *p) {
  809. X    while (p != NULL) {
  810. X        List *n = p->n;
  811. X        efree(p->w);
  812. X        efree(p);
  813. X        p = n;
  814. X    }
  815. X}
  816. X
  817. X/* Copy list into malloc space (for storing a variable) */
  818. X
  819. Xextern List *listcpy(List *s, void *(*alloc)(SIZE_T)) {
  820. X    List *top, *r;
  821. X    for (top = r = NULL; s != NULL; s = s->n) {
  822. X        if (top == NULL)
  823. X            r = top = (*alloc)(sizeof (List));
  824. X        else
  825. X            r = r->n = (*alloc)(sizeof (List));
  826. X        r->w = (*alloc)(strlen(s->w) + 1);
  827. X        strcpy(r->w, s->w);
  828. X        r->m = NULL;
  829. X    }
  830. X    if (r != NULL)
  831. X        r->n = NULL;
  832. X    return top;
  833. X}
  834. X
  835. X/* Length of list */
  836. X
  837. Xextern SIZE_T listlen(List *s) {
  838. X    SIZE_T size;
  839. X    for (size = 0; s != NULL; s = s->n)
  840. X        size += strlen(s->w) + 1;
  841. X    return size;
  842. X}
  843. X
  844. X/* Number of elements in list */
  845. X
  846. Xextern int listnel(List *s) {
  847. X    int nel;
  848. X    for (nel = 0; s != NULL; s = s->n)
  849. X        nel++;
  850. X    return nel;
  851. X}
  852. END_OF_FILE
  853.   if test 1160 -ne `wc -c <'list.c'`; then
  854.     echo shar: \"'list.c'\" unpacked with wrong size!
  855.   fi
  856.   # end of 'list.c'
  857. fi
  858. if test -f 'main.c' -a "${1}" != "-c" ; then 
  859.   echo shar: Will not clobber existing file \"'main.c'\"
  860. else
  861.   echo shar: Extracting \"'main.c'\" \(2559 characters\)
  862.   sed "s/^X//" >'main.c' <<'END_OF_FILE'
  863. X/* main.c: handles initialization of rc and command line options */
  864. X
  865. X#include "rc.h"
  866. X
  867. Xbool dashdee, dashee, dashvee, dashex, dashell, dasheye,
  868. X    dashen, dashpee, interactive;
  869. Xint rc_pid;
  870. X
  871. Xstatic bool dashoh;
  872. X
  873. Xstatic void assigndefault(char *,...);
  874. Xstatic void checkfd(int, enum redirtype);
  875. X
  876. Xextern void main(int argc, char *argv[], char *envp[]) {
  877. X    char *dashsee[2], *dollarzero, *null[1];
  878. X    int c;
  879. X    initprint();
  880. X    dashsee[0] = dashsee[1] = NULL;
  881. X    dollarzero = argv[0];
  882. X    rc_pid = getpid();
  883. X    dashell = (*argv[0] == '-'); /* Unix tradition */
  884. X    while ((c = rc_getopt(argc, argv, "nolpeivdxc:")) != -1)
  885. X        switch (c) {
  886. X        case 'l':
  887. X            dashell = TRUE;
  888. X            break;
  889. X        case 'e':
  890. X            dashee = TRUE;
  891. X            break;
  892. X        case 'i':
  893. X            dasheye = interactive = TRUE;
  894. X            break;
  895. X        case 'v':
  896. X            dashvee = TRUE;
  897. X            break;
  898. X        case 'x':
  899. X            dashex = TRUE;
  900. X            break;
  901. X        case 'd':
  902. X            dashdee = TRUE;
  903. X            break;
  904. X        case 'c':
  905. X            dashsee[0] = rc_optarg;
  906. X            goto quitopts;
  907. X        case 'n':
  908. X            dashen = TRUE;
  909. X            break;
  910. X        case 'p':
  911. X            dashpee = TRUE;
  912. X            break;
  913. X        case 'o':
  914. X            dashoh = TRUE;
  915. X            break;
  916. X        case '?':
  917. X            exit(1);
  918. X        }
  919. Xquitopts:
  920. X    argv += rc_optind;
  921. X    /* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */
  922. X    if (!dasheye && dashsee[0] == NULL && *argv == NULL)
  923. X        interactive = isatty(0);
  924. X    if (!dashoh) {
  925. X        checkfd(0, rFrom);
  926. X        checkfd(1, rCreate);
  927. X        checkfd(2, rCreate);
  928. X    }
  929. X    initsignal();
  930. X    inithash();
  931. X    initparse();
  932. X    assigndefault("prompt", "; ", "", (void *)0);
  933. X#ifdef DEFAULTPATH
  934. X    assigndefault("path", DEFAULTPATH, (void *)0);
  935. X#endif
  936. X    assigndefault("ifs", " ", "\t", "\n", (void *)0);
  937. X    assigndefault("pid", nprint("%d", rc_pid), (void *)0);
  938. X    initenv(envp);
  939. X    initinput();
  940. X    null[0] = NULL;
  941. X    starassign(dollarzero, null, FALSE); /* assign $0 to $* */
  942. X    inithandler();
  943. X    if (dashsee[0] != NULL) {    /* input from the -c flag? */
  944. X        if (*argv != NULL)
  945. X            starassign(dollarzero, argv, FALSE);
  946. X        pushstring(dashsee, TRUE);
  947. X    } else if (*argv != NULL) {    /* else from a file? */
  948. X        b_dot(--argv);
  949. X        rc_exit(getstatus());
  950. X    } else {            /* else stdin */
  951. X        pushfd(0);
  952. X    }
  953. X    dasheye = FALSE;
  954. X    doit(TRUE);
  955. X    rc_exit(getstatus());
  956. X}
  957. X
  958. Xstatic void assigndefault(char *name,...) {
  959. X    va_list ap;
  960. X    List *l;
  961. X    char *v;
  962. X    va_start(ap, name);
  963. X    for (l = NULL; (v = va_arg(ap, char *)) != NULL;)
  964. X        l = append(l, word(v, NULL));
  965. X    varassign(name, l, FALSE);
  966. X    if (streq(name, "path"))
  967. X        alias(name, l, FALSE);
  968. X    va_end(ap);
  969. X}
  970. X
  971. X/* open an fd on /dev/null if it is inherited closed */
  972. X
  973. Xstatic void checkfd(int fd, enum redirtype r) {
  974. X    int new = rc_open("/dev/null", r);
  975. X    if (new != fd && new != -1)
  976. X        close(new);
  977. X}
  978. END_OF_FILE
  979.   if test 2559 -ne `wc -c <'main.c'`; then
  980.     echo shar: \"'main.c'\" unpacked with wrong size!
  981.   fi
  982.   # end of 'main.c'
  983. fi
  984. if test -f 'match.c' -a "${1}" != "-c" ; then 
  985.   echo shar: Will not clobber existing file \"'match.c'\"
  986. else
  987.   echo shar: Extracting \"'match.c'\" \(2166 characters\)
  988.   sed "s/^X//" >'match.c' <<'END_OF_FILE'
  989. X/* match.c: pattern matching routines */
  990. X
  991. X#include "rc.h"
  992. X
  993. Xstatic int rangematch(char *, char);
  994. X
  995. Xenum { RANGE_FAIL = -1, RANGE_ERROR = -2 };
  996. X
  997. X/* match() matches a single pattern against a single string. */
  998. X
  999. Xextern bool match(char *p, char *m, char *s) {
  1000. X    int i, j;
  1001. X    if (m == NULL)
  1002. X        return streq(p, s);
  1003. X    i = 0;
  1004. X    while (1) {
  1005. X        if (p[i] == '\0')
  1006. X            return *s == '\0';
  1007. X        else if (m[i]) {
  1008. X            switch (p[i++]) {
  1009. X            case '?':
  1010. X                if (*s++ == '\0')
  1011. X                    return FALSE;
  1012. X                break;
  1013. X            case '*':
  1014. X                while (p[i] == '*' && m[i] == 1)    /* collapse multiple stars */
  1015. X                    i++;
  1016. X                if (p[i] == '\0')     /* star at end of pattern? */
  1017. X                    return TRUE;
  1018. X                while (*s != '\0')
  1019. X                    if (match(p + i, m + i, s++))
  1020. X                        return TRUE;
  1021. X                return FALSE;
  1022. X            case '[':
  1023. X                if (*s == '\0')
  1024. X                    return FALSE;
  1025. X                switch (j = rangematch(p + i, *s)) {
  1026. X                default:
  1027. X                    i += j;
  1028. X                    break;
  1029. X                case RANGE_FAIL:
  1030. X                    return FALSE;
  1031. X                case RANGE_ERROR:
  1032. X                    if (*s != '[')
  1033. X                        return FALSE;
  1034. X                }
  1035. X                s++;
  1036. X                break;
  1037. X            default:
  1038. X                panic("bad metacharacter in match");
  1039. X                /* NOTREACHED */
  1040. X                return FALSE; /* hush up gcc -Wall */
  1041. X            }
  1042. X        } else if (p[i++] != *s++)
  1043. X            return FALSE;
  1044. X    }
  1045. X}
  1046. X
  1047. X/*
  1048. X   From the ed(1) man pages (on ranges):
  1049. X
  1050. X    The `-' is treated as an ordinary character if it occurs first
  1051. X    (or first after an initial ^) or last in the string.
  1052. X
  1053. X    The right square bracket does not terminate the enclosed string
  1054. X    if it is the first character (after an initial `^', if any), in
  1055. X    the bracketed string.
  1056. X
  1057. X   rangematch() matches a single character against a class, and returns
  1058. X   an integer offset to the end of the range on success, or -1 on
  1059. X   failure.
  1060. X*/
  1061. X
  1062. Xstatic int rangematch(char *p, char c) {
  1063. X    char *orig = p;
  1064. X    bool neg = (*p == '~');
  1065. X    bool matched = FALSE;
  1066. X    if (neg)
  1067. X        p++;
  1068. X    if (*p == ']') {
  1069. X        p++;
  1070. X        matched = (c == ']');
  1071. X    }
  1072. X    for (; *p != ']'; p++) {
  1073. X        if (*p == '\0')
  1074. X            return RANGE_ERROR;    /* bad syntax */
  1075. X        if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */
  1076. X            if (c >= *p)
  1077. X                matched |= (c <= p[2]);
  1078. X            p += 2;
  1079. X        } else {
  1080. X            matched |= (*p == c);
  1081. X        }
  1082. X    }
  1083. X    if (matched ^ neg)
  1084. X        return p - orig + 1; /* skip the right-bracket */
  1085. X    else
  1086. X        return RANGE_FAIL;
  1087. X}
  1088. END_OF_FILE
  1089.   if test 2166 -ne `wc -c <'match.c'`; then
  1090.     echo shar: \"'match.c'\" unpacked with wrong size!
  1091.   fi
  1092.   # end of 'match.c'
  1093. fi
  1094. if test -f 'mksignal' -a "${1}" != "-c" ; then 
  1095.   echo shar: Will not clobber existing file \"'mksignal'\"
  1096. else
  1097.   echo shar: Extracting \"'mksignal'\" \(1821 characters\)
  1098.   sed "s/^X//" >'mksignal' <<'END_OF_FILE'
  1099. X#!/bin/sh
  1100. X# generate rc's internal signal table from signal.h
  1101. X
  1102. Xexec > sigmsgs.c
  1103. X
  1104. Xecho '#include "sigmsgs.h"'
  1105. Xecho
  1106. Xecho 'Sigmsgs signals[] = {'
  1107. X
  1108. Xsed '    s/\/\*[     ]*//
  1109. X    s/[     ]*\*\///
  1110. X    s/([@*+!]) //
  1111. X    s/[     ]*([a-zA-Z,->& ]*)[     ]*//
  1112. X    s/^[     ]*\#[     ]*define/\#define/
  1113. X    s/[     ]*signal$//' $1 |
  1114. Xawk '
  1115. X    BEGIN {
  1116. X        # assign to nomesg["SIGNAME"] to suppress a long message
  1117. X        nomesg["SIGINT"] = 1
  1118. X        nomesg["SIGPIPE"] = 1
  1119. X        # assign to mesg["SIGNAME"] to override a message
  1120. X        mesg["SIGHUP"] = "hangup"
  1121. X        mesg["SIGKILL"] = "killed"
  1122. X        mesg["SIGQUIT"] = "quit"
  1123. X        mesg["SIGTERM"] = "terminated"
  1124. X        mesg["SIGURG"] = "urgent condition on i/o channel"
  1125. X        mesg["SIGSTOP"] = "stop signal not from tty"
  1126. X        mesg["SIGTSTP"] = "stopped"
  1127. X        mesg["SIGCONT"] = "continue"
  1128. X        mesg["SIGCHLD"] = "child stop or exit"
  1129. X        mesg["SIGTTIN"] = "background tty read"
  1130. X        mesg["SIGTTOU"] = "background tty write"
  1131. X        # assign to ignore["SIGNAME"] to explicitly ignore a named signal
  1132. X        ignore["SIGMAX"] = 1
  1133. X    }
  1134. X    $1 == "#define" && $2 == "NSIG" && $3 ~ /^[0-9]+$/ { nsig = $3 }
  1135. X    $1 == "#define" && $2 ~ /^SIG/ && $3 ~ /^[0-9]+$/ && sig[$3] == "" && ignore[$2] == 0 {
  1136. X        sig[$3] = $2
  1137. X        if ($3 > max)
  1138. X            max = $3
  1139. X        if (mesg[$2] == "" && nomesg[$2] == 0) {
  1140. X            str = $4
  1141. X            for (i = 5; i <= NF; i++)
  1142. X                str = str " " $i
  1143. X            mesg[$2] = str
  1144. X        }
  1145. X    }
  1146. X    END {
  1147. X        if (nsig == 0)
  1148. X            nsig = max + 1
  1149. X        printf "    {!!,        !!},\n"
  1150. X        for (i = 1; i < nsig; i++) {
  1151. X            if (sig[i] == "")
  1152. X                printf "    {!!,        !!},\n"
  1153. X            else
  1154. X                printf "    {!%s!,    !%s!},\n", sig[i], mesg[sig[i]]
  1155. X        }
  1156. X    }
  1157. X' |
  1158. Xtr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!' 'abcdefghijklmnopqrstuvwxyz"'
  1159. X
  1160. Xecho '};'
  1161. X
  1162. Xexec > sigmsgs.h
  1163. X
  1164. Xecho 'typedef struct {'
  1165. Xecho '    char *name, *msg;'
  1166. Xecho '} Sigmsgs;'
  1167. Xecho 'extern Sigmsgs signals[];'
  1168. X
  1169. Xgrep '^    ' sigmsgs.c |        # the thing in quotes is ^<tab>
  1170. Xawk '
  1171. X        { sum = sum + 1; }
  1172. X    END    { print "#define NUMOFSIGNALS", sum }
  1173. X'
  1174. END_OF_FILE
  1175.   if test 1821 -ne `wc -c <'mksignal'`; then
  1176.     echo shar: \"'mksignal'\" unpacked with wrong size!
  1177.   fi
  1178.   chmod +x 'mksignal'
  1179.   # end of 'mksignal'
  1180. fi
  1181. if test -f 'nalloc.c' -a "${1}" != "-c" ; then 
  1182.   echo shar: Will not clobber existing file \"'nalloc.c'\"
  1183. else
  1184.   echo shar: Extracting \"'nalloc.c'\" \(3180 characters\)
  1185.   sed "s/^X//" >'nalloc.c' <<'END_OF_FILE'
  1186. X/* nalloc.c: a simple single-arena allocator for command-line-lifetime allocation */
  1187. X#include "rc.h"
  1188. X
  1189. Xstatic struct Block {
  1190. X    SIZE_T used, size;
  1191. X    char *mem;
  1192. X    Block *n;
  1193. X} *fl, *ul;
  1194. X
  1195. X/* alignto() works only with power of 2 blocks and assumes 2's complement arithmetic */
  1196. X#define alignto(m, n)   ((m + n - 1) & ~(n - 1))
  1197. X#define BLOCKSIZE ((SIZE_T) 4096)
  1198. X
  1199. X/* Allocate a block from the free list or malloc one if none in the fl fit */
  1200. X
  1201. Xstatic void getblock(SIZE_T n) {
  1202. X    Block *r, *p;
  1203. X    for (r = fl, p = NULL; r != NULL; p = r, r = r->n)
  1204. X        if (n <= r->size)
  1205. X            break;    /* look for a block which fits the request */
  1206. X    if (r != NULL) {    /* if one is found, take it off the free list */    
  1207. X        if (p != NULL)
  1208. X            p->n = r->n;
  1209. X        else
  1210. X            fl = r->n;
  1211. X    } else {        /* else allocate a new block */
  1212. X        r = enew(Block);
  1213. X        r->mem = ealloc(r->size = alignto(n, BLOCKSIZE));
  1214. X    }
  1215. X    r->used = 0;
  1216. X    r->n = ul;
  1217. X    ul = r;
  1218. X}
  1219. X
  1220. X/*
  1221. X   A fast single-arena allocator. Looks at the current block, and if
  1222. X   there is not enough room, it goes to getblock() for more. "ul"
  1223. X   stands for "used list", and the head of the list is the current
  1224. X   block. "ulp" is a register cache for "ul"; this routine is hacked
  1225. X   for speed. (sigh, optimizing RISC compilers still can't cache the
  1226. X   address of a global in a register)
  1227. X*/
  1228. X
  1229. Xextern void *nalloc(SIZE_T n) {
  1230. X    SIZE_T base;
  1231. X    Block *ulp;
  1232. X        n = alignto(n, sizeof (ALIGN_T));
  1233. X    ulp = ul;
  1234. X    if (ulp != NULL && n + (base = ulp->used) < ulp->size) {
  1235. X        ulp->used = base + n;
  1236. X        return &ulp->mem[base];
  1237. X    } else {
  1238. X        getblock(n); /* assert(ul->used) == 0 */
  1239. X        (ulp = ul)->used = n;
  1240. X        return &ulp->mem[0];
  1241. X    }
  1242. X}
  1243. X
  1244. X/*
  1245. X   Frees memory from nalloc space by putting it on the free list.
  1246. X   Returns free blocks to the system, retaining at least MAXMEM bytes
  1247. X   worth of blocks for nalloc.
  1248. X*/
  1249. X
  1250. X#define MAXMEM 500000
  1251. X
  1252. Xextern void nfree() {
  1253. X    SIZE_T count;
  1254. X    Block *r;
  1255. X    if (ul == NULL)
  1256. X        return;
  1257. X    for (r = ul; r->n != NULL; r = r->n)
  1258. X        ;    /* get to end of used list */
  1259. X    r->n = fl;    /* tack free list onto it */
  1260. X    fl = ul;    /* and make it the free list */
  1261. X    ul = NULL;    /* finally, zero out the used list */
  1262. X    for (r = fl, count = r->size; r->n != NULL; r = r->n, count += r->size) {
  1263. X        if (count >= MAXMEM) {
  1264. X            Block *tmp = r;
  1265. X            r = r->n;
  1266. X            tmp->n = NULL;        /* terminate the free list */
  1267. X            while (r != NULL) {    /* free memory off the tail of the free list */
  1268. X                tmp = r->n;
  1269. X                efree(r->mem);
  1270. X                efree(r);
  1271. X                r = tmp;
  1272. X            }
  1273. X        return;
  1274. X        }
  1275. X    }
  1276. X}
  1277. X
  1278. X/*
  1279. X   "Allocates" a new arena by zeroing out the old one. Up to the
  1280. X   calling routine to keep the old value of the block around.
  1281. X*/
  1282. X
  1283. Xextern Block *newblock() {
  1284. X    Block *old = ul;
  1285. X    ul = NULL;
  1286. X    return old;
  1287. X}
  1288. X
  1289. X/* "Restores" an arena to its saved value. */
  1290. X
  1291. Xextern void restoreblock(Block *old) {
  1292. X    nfree();
  1293. X    ul = old;
  1294. X}
  1295. X
  1296. X/* generic memory allocation functions */
  1297. X
  1298. Xextern void *ealloc(SIZE_T n) {
  1299. X    extern void *malloc(SIZE_T);
  1300. X    void *p = malloc(n);
  1301. X    if (p == NULL) {
  1302. X        uerror("malloc");
  1303. X        rc_exit(1);
  1304. X    }
  1305. X    return p;
  1306. X}
  1307. X
  1308. Xextern void *erealloc(void *p, SIZE_T n) {
  1309. X    extern void *realloc(void *, SIZE_T);
  1310. X    if ((p = realloc(p, n)) == NULL) {
  1311. X        uerror("realloc");
  1312. X        rc_exit(1);
  1313. X    }
  1314. X    return p;
  1315. X}
  1316. X
  1317. Xextern void efree(void *p) {
  1318. X    extern void free(void *);
  1319. X    if (p != NULL)
  1320. X        free(p);
  1321. X}
  1322. X
  1323. END_OF_FILE
  1324.   if test 3180 -ne `wc -c <'nalloc.c'`; then
  1325.     echo shar: \"'nalloc.c'\" unpacked with wrong size!
  1326.   fi
  1327.   # end of 'nalloc.c'
  1328. fi
  1329. if test -f 'proto.h' -a "${1}" != "-c" ; then 
  1330.   echo shar: Will not clobber existing file \"'proto.h'\"
  1331. else
  1332.   echo shar: Extracting \"'proto.h'\" \(2510 characters\)
  1333.   sed "s/^X//" >'proto.h' <<'END_OF_FILE'
  1334. X/* proto.h
  1335. X    This file provides a definition for size_t and align_t that
  1336. X    should work for your system. If it does not, it is up to you to
  1337. X    make it the right thing. The problem is that I cannot rely upon
  1338. X    <sys/params.h> to do the right thing on machines which don't
  1339. X    yet have ansi header files. Note that on many RISC machines,
  1340. X    align_t must be at least 32 bits wide, and sparc doubles are
  1341. X    aligned on 64 bit boundaries, but of course rc does not use
  1342. X    doubles in its code, so the "typedef long ALIGN_T" is good
  1343. X    enough in the sparc's case. Also for performance reasons on a
  1344. X    VAX one would probably want align_t to be 32 bits wide.
  1345. X
  1346. X    You can override these definitions with compile-line definitions
  1347. X    of the same macros.
  1348. X*/
  1349. X
  1350. X#ifndef ALIGN_T
  1351. Xtypedef long ALIGN_T;
  1352. X#endif
  1353. X#ifndef SIZE_T
  1354. Xtypedef unsigned int SIZE_T;
  1355. X#endif
  1356. X#ifndef MODE_T
  1357. Xtypedef short int MODE_T;
  1358. X#endif
  1359. X#ifndef PID_T
  1360. Xtypedef int PID_T;
  1361. X#endif
  1362. X#ifndef SIG_ATOMIC_T
  1363. Xtypedef int SIG_ATOMIC_T;
  1364. X#endif
  1365. X
  1366. X/* fake stdlib.h */
  1367. X
  1368. Xextern void exit(int);
  1369. Xextern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *));
  1370. X
  1371. X/* fake string.h */
  1372. X
  1373. Xextern int strncmp(const char *, const char *, SIZE_T);
  1374. Xextern int strcmp(const char *, const char *);
  1375. Xextern SIZE_T strlen(const char *);
  1376. Xextern char *strchr(const char *, int);
  1377. Xextern char *strrchr(const char *, int);
  1378. Xextern char *strcpy(char *, const char *);
  1379. Xextern char *strncpy(char *, const char *, SIZE_T);
  1380. Xextern char *strcat(char *, const char *);
  1381. Xextern char *strncat(char *, const char *, SIZE_T);
  1382. Xextern void *memcpy(void *, const void *, SIZE_T);
  1383. X
  1384. X/* fake unistd.h */
  1385. X
  1386. Xextern PID_T fork(void);
  1387. Xextern PID_T getpid(void);
  1388. Xextern char *getenv(const char *);
  1389. Xextern int chdir(const char *);
  1390. Xextern int close(int);
  1391. Xextern int dup(int);
  1392. Xextern int dup2(int, int);
  1393. Xextern int execve(const char *, const char **, const char **);
  1394. Xextern int execl(const char *,...);
  1395. Xextern int getegid(void);
  1396. Xextern int geteuid(void);
  1397. Xextern int getgroups(int, int *);
  1398. X/*extern int ioctl(int, long,...);*/ /* too much trouble leaving this uncommented */
  1399. Xextern int isatty(int);
  1400. X#ifndef SYSVR4 /* declares AND defines this in sys/stat.h!! */
  1401. Xextern int mknod(const char *, int, int);
  1402. X#endif
  1403. Xextern int pipe(int *);
  1404. Xextern int read(int, void *, unsigned int);
  1405. Xextern int setpgrp(int, PID_T);
  1406. Xextern int unlink(const char *);
  1407. Xextern int wait(int *);
  1408. Xextern int write(int, const void *, unsigned int);
  1409. X
  1410. X/* fake errno.h for mips (which doesn't declare errno in errno.h!?!?) */
  1411. X
  1412. X#ifdef host_mips
  1413. Xextern int errno;
  1414. X#endif
  1415. END_OF_FILE
  1416.   if test 2510 -ne `wc -c <'proto.h'`; then
  1417.     echo shar: \"'proto.h'\" unpacked with wrong size!
  1418.   fi
  1419.   # end of 'proto.h'
  1420. fi
  1421. if test -f 'redir.c' -a "${1}" != "-c" ; then 
  1422.   echo shar: Will not clobber existing file \"'redir.c'\"
  1423. else
  1424.   echo shar: Extracting \"'redir.c'\" \(2097 characters\)
  1425.   sed "s/^X//" >'redir.c' <<'END_OF_FILE'
  1426. X/* redir.c: code for opening files and piping heredocs after fork but before exec. */
  1427. X
  1428. X#include "rc.h"
  1429. X
  1430. X/*
  1431. X   Walk the redirection queue, and open files and dup2 to them. Also,
  1432. X   here-documents are treated here by dumping them down a pipe. (this
  1433. X   should make here-documents fast on systems with lots of memory which
  1434. X   do pipes right. Under sh, a file is copied to /tmp, and then read
  1435. X   out of /tmp again. I'm interested in knowing how much faster, say,
  1436. X   shar runs when unpacking when invoked with rc instead of sh. On my
  1437. X   sun4/280, it runs in about 60-75% of the time of sh for unpacking
  1438. X   the rc source distribution.)
  1439. X*/
  1440. X
  1441. Xextern void doredirs() {
  1442. X    List *fname;
  1443. X    int fd, p[2];
  1444. X    Rq *r;
  1445. X    for (r = redirq; r != NULL; r = r->n) {
  1446. X        switch(r->r->type) {
  1447. X        default:
  1448. X            panic("unexpected node in doredirs");
  1449. X            /* NOTREACHED */
  1450. X        case nRedir:
  1451. X            if (r->r->u[0].i == rHerestring) {
  1452. X                fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */
  1453. X                if (pipe(p) < 0) {
  1454. X                    uerror("pipe");
  1455. X                    rc_error(NULL);
  1456. X                }
  1457. X                if (rc_fork() == 0) { /* child writes to pipe */
  1458. X                    setsigdefaults(FALSE);
  1459. X                    close(p[0]);
  1460. X                    if (fname != NULL)
  1461. X                        writeall(p[1], fname->w, strlen(fname->w));
  1462. X                    exit(0);
  1463. X                } else {
  1464. X                    close(p[1]);
  1465. X                    if (mvfd(p[0], r->r->u[1].i) < 0)
  1466. X                        rc_error(NULL);
  1467. X                }
  1468. X            } else {
  1469. X                fname = glob(glom(r->r->u[2].p));
  1470. X                if (fname == NULL)
  1471. X                    rc_error("null filename in redirection");
  1472. X                if (fname->n != NULL)
  1473. X                    rc_error("multi-word filename in redirection");
  1474. X                switch (r->r->u[0].i) {
  1475. X                default:
  1476. X                    panic("unexpected node in doredirs");
  1477. X                    /* NOTREACHED */
  1478. X                case rCreate: case rAppend: case rFrom:
  1479. X                    fd = rc_open(fname->w, r->r->u[0].i);
  1480. X                    break;
  1481. X                }
  1482. X                if (fd < 0) {
  1483. X                    uerror(fname->w);
  1484. X                    rc_error(NULL);
  1485. X                }
  1486. X                if (mvfd(fd, r->r->u[1].i) < 0)
  1487. X                    rc_error(NULL);
  1488. X            }
  1489. X            break;
  1490. X        case nDup:
  1491. X            if (r->r->u[2].i == -1)
  1492. X                close(r->r->u[1].i);
  1493. X            else if (r->r->u[2].i != r->r->u[1].i) {
  1494. X                if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) {
  1495. X                    uerror("dup2");
  1496. X                    rc_error(NULL);
  1497. X                }
  1498. X            }
  1499. X        }
  1500. X    }
  1501. X    redirq = NULL;
  1502. X}
  1503. END_OF_FILE
  1504.   if test 2097 -ne `wc -c <'redir.c'`; then
  1505.     echo shar: \"'redir.c'\" unpacked with wrong size!
  1506.   fi
  1507.   # end of 'redir.c'
  1508. fi
  1509. if test -f 'signal.c' -a "${1}" != "-c" ; then 
  1510.   echo shar: Will not clobber existing file \"'signal.c'\"
  1511. else
  1512.   echo shar: Extracting \"'signal.c'\" \(1559 characters\)
  1513.   sed "s/^X//" >'signal.c' <<'END_OF_FILE'
  1514. X/* signal.c: a Hugh-approved signal handler. */
  1515. X
  1516. X#include <signal.h>
  1517. X#include <setjmp.h>
  1518. X#include "rc.h"
  1519. X#include "sigmsgs.h"
  1520. X#include "jbwrap.h"
  1521. X
  1522. XJbwrap slowbuf;
  1523. Xvolatile SIG_ATOMIC_T slow, interrupt_happened;
  1524. Xvoid (*sighandlers[NUMOFSIGNALS])(int);
  1525. X
  1526. Xstatic volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS];
  1527. X
  1528. Xextern void catcher(int s) {
  1529. X    if (forked)
  1530. X        exit(1); /* exit unconditionally on a signal in a child process */
  1531. X    if (caught[s] == 0) {
  1532. X        sigcount++;
  1533. X        caught[s] = 1;
  1534. X    }
  1535. X    signal(s, catcher);
  1536. X    interrupt_happened = TRUE;
  1537. X#ifndef SVSIGS
  1538. X    if (slow)
  1539. X        longjmp(slowbuf.j, 1);
  1540. X#endif
  1541. X}
  1542. X
  1543. Xextern void sigchk() {
  1544. X    void (*h)(int);
  1545. X    int s, i;
  1546. X    if (sigcount == 0)
  1547. X        return; /* ho hum; life as usual */
  1548. X    if (forked)
  1549. X        exit(1); /* exit unconditionally on a signal in a child process */
  1550. X    for (i = 0, s = -1; i < NUMOFSIGNALS; i++)
  1551. X        if (caught[i] != 0) {
  1552. X            s = i;
  1553. X            --sigcount;
  1554. X            caught[s] = 0;
  1555. X            break;
  1556. X        }
  1557. X    if (s == -1)
  1558. X        panic("all-zero sig vector with nonzero sigcount");
  1559. X    if ((h = sighandlers[s]) == SIG_DFL)
  1560. X        panic("caught signal set to SIG_DFL");
  1561. X    if (h == SIG_IGN)
  1562. X        panic("caught signal set to SIG_IGN");
  1563. X    (*h)(s);
  1564. X}
  1565. X
  1566. Xextern void (*rc_signal(int s, void (*h)(int)))(int) {
  1567. X    void (*old)(int);
  1568. X    SIGCHK;
  1569. X    old = sighandlers[s];
  1570. X    if (h == SIG_DFL || h == SIG_IGN) {
  1571. X        signal(s, h);
  1572. X        sighandlers[s] = h;
  1573. X    } else {
  1574. X        sighandlers[s] = h;
  1575. X        signal(s, catcher);
  1576. X    }
  1577. X    return old;
  1578. X}
  1579. X
  1580. Xextern void initsignal() {
  1581. X    void (*h)(int);
  1582. X    int i;
  1583. X    for (i = 1; i < NUMOFSIGNALS; i++) {
  1584. X        if ((h = signal(i, SIG_DFL)) != SIG_DFL)
  1585. X            signal(i, h);
  1586. X        sighandlers[i] = h;
  1587. X    }
  1588. X}
  1589. END_OF_FILE
  1590.   if test 1559 -ne `wc -c <'signal.c'`; then
  1591.     echo shar: \"'signal.c'\" unpacked with wrong size!
  1592.   fi
  1593.   # end of 'signal.c'
  1594. fi
  1595. if test -f 'status.c' -a "${1}" != "-c" ; then 
  1596.   echo shar: Will not clobber existing file \"'status.c'\"
  1597. else
  1598.   echo shar: Extracting \"'status.c'\" \(3281 characters\)
  1599.   sed "s/^X//" >'status.c' <<'END_OF_FILE'
  1600. X/* status.c: functions for printing fancy status messages in rc */
  1601. X
  1602. X#include "rc.h"
  1603. X#include "sigmsgs.h"
  1604. X
  1605. X/* status == the wait() value of the last command in the pipeline, or the last command */
  1606. X
  1607. Xstatic int statuses[512];
  1608. Xstatic int pipelength = 1;
  1609. X
  1610. X/*
  1611. X   Test to see if rc's status is true. According to td, status is true
  1612. X   if and only if every pipe-member has an exit status of zero.
  1613. X*/
  1614. X
  1615. Xextern int istrue() {
  1616. X    int i;
  1617. X    for (i = 0; i < pipelength; i++)
  1618. X        if (statuses[i] != 0)
  1619. X            return FALSE;
  1620. X    return TRUE;
  1621. X}
  1622. X
  1623. X/*
  1624. X   Return the status as an integer. A status which has low-bits set is
  1625. X   a signal number, whereas a status with high bits set is a value set
  1626. X   from exit(). The presence of a signal just sets status to 1. Also,
  1627. X   a pipeline with nonzero exit statuses in it just sets status to 1.
  1628. X*/
  1629. X
  1630. Xextern int getstatus() {
  1631. X    int s;
  1632. X    if (pipelength > 1)
  1633. X        return !istrue();
  1634. X    s = statuses[0];
  1635. X    return (s&0xff) ? 1 : (s >> 8) & 0xff;
  1636. X}
  1637. X
  1638. Xextern void set(bool code) {
  1639. X    setstatus(-1, (!code) << 8); /* exit status 1 == 0x100 */
  1640. X}
  1641. X
  1642. X/* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */
  1643. X
  1644. Xextern void setpipestatus(int stats[], int num) {
  1645. X    int i;
  1646. X    for (i = 0; i < (pipelength = num); i++) {
  1647. X        statprint(-1, stats[i]);
  1648. X        statuses[i] = stats[i];
  1649. X    }
  1650. X}
  1651. X
  1652. X/* set a simple status, as opposed to a pipeline */
  1653. X
  1654. Xextern void setstatus(int pid, int i) {
  1655. X    pipelength = 1;
  1656. X    statuses[0] = i;
  1657. X    statprint(pid, i);
  1658. X}
  1659. X
  1660. X/* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */
  1661. X
  1662. Xextern void statprint(int pid, int i) {
  1663. X    if (i & 0xff) {
  1664. X        char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f].msg : "");
  1665. X        if (pid != -1)
  1666. X            fprint(2, "%d: ", pid);
  1667. X        if (i & 0x80) {
  1668. X            if (*msg == '\0')
  1669. X                fprint(2, "core dumped\n");
  1670. X            else
  1671. X                fprint(2, "%s--core dumped\n", msg);
  1672. X        } else if (*msg != '\0')
  1673. X            fprint(2, "%s\n", msg);
  1674. X    }
  1675. X    if (i != 0 && dashee && !cond)
  1676. X        rc_exit(getstatus());
  1677. X}
  1678. X
  1679. X/* prepare a list to be passed back. Used whenever $status is dereferenced */
  1680. X
  1681. Xextern List *sgetstatus() {
  1682. X    List *r;
  1683. X    int i;
  1684. X    for (r = NULL, i = 0; i < pipelength; i++) {
  1685. X        List *q = nnew(List);
  1686. X        int s = statuses[i];
  1687. X        int t;
  1688. X        q->n = r;
  1689. X        r = q;
  1690. X        if ((t = s & 0x7f) != 0) {
  1691. X            const char *core = (s & 0x80) ? "+core" : "";
  1692. X            if (t < NUMOFSIGNALS && *signals[t].name != '\0')
  1693. X                r->w = nprint("%s%s", signals[t].name, core);
  1694. X            else
  1695. X                r->w = nprint("-%d%s", t, core); /* unknown signals are negated */
  1696. X        } else
  1697. X            r->w = nprint("%d", (s >> 8) & 0xff);
  1698. X        r->m = NULL;
  1699. X    }
  1700. X    return r;
  1701. X}
  1702. X
  1703. Xextern void ssetstatus(char **av) {
  1704. X    int i, j, k, l;
  1705. X    bool found;
  1706. X    for (l = 0; av[l] != NULL; l++)
  1707. X        ; /* count up array length */
  1708. X    --l;
  1709. X    for (i = 0; av[i] != NULL; i++) {
  1710. X        j = a2u(av[i]);
  1711. X        if (j >= 0) {
  1712. X            statuses[l - i] = j << 8;
  1713. X            continue;
  1714. X        }
  1715. X        found = FALSE;
  1716. X        for (k = 0; k < NUMOFSIGNALS; k++) {
  1717. X            if (streq(signals[k].name, av[i])) {
  1718. X                statuses[l - i] = k;
  1719. X                found = TRUE;
  1720. X                break;
  1721. X            } 
  1722. X            else {
  1723. X                SIZE_T len = strlen(signals[k].name);
  1724. X                if (strncmp(signals[k].name, av[i], len) == 0 && streq(av[i] + len, "+core")) {
  1725. X                    statuses[l - i] = k + 0x80;
  1726. X                    found = TRUE;
  1727. X                    break;
  1728. X                }
  1729. X            }
  1730. X        }
  1731. X        if (!found) {
  1732. X            fprint(2, "bad status\n");
  1733. X            set(FALSE);
  1734. X            return;
  1735. X        }
  1736. X    }
  1737. X    pipelength = i;
  1738. X}
  1739. END_OF_FILE
  1740.   if test 3281 -ne `wc -c <'status.c'`; then
  1741.     echo shar: \"'status.c'\" unpacked with wrong size!
  1742.   fi
  1743.   # end of 'status.c'
  1744. fi
  1745. if test -f 'tree.c' -a "${1}" != "-c" ; then 
  1746.   echo shar: Will not clobber existing file \"'tree.c'\"
  1747. else
  1748.   echo shar: Extracting \"'tree.c'\" \(4574 characters\)
  1749.   sed "s/^X//" >'tree.c' <<'END_OF_FILE'
  1750. X/* tree.c: functions for manipulating parse-trees. (create, copy, delete) */
  1751. X
  1752. X#include "rc.h"
  1753. X
  1754. X/* make a new node, pass it back to yyparse. Used to generate the parsetree. */
  1755. X
  1756. Xextern Node *mk(int /*nodetype*/ t,...) {
  1757. X    va_list ap;
  1758. X    Node *n;
  1759. X    va_start(ap, t);
  1760. X    switch (t) {
  1761. X    default:
  1762. X        panic("unexpected node in mk");
  1763. X        /* NOTREACHED */
  1764. X    case nDup:
  1765. X        n = nalloc(offsetof(Node, u[3]));
  1766. X        n->u[0].i = va_arg(ap, int);
  1767. X        n->u[1].i = va_arg(ap, int);
  1768. X        n->u[2].i = va_arg(ap, int);
  1769. X        break;
  1770. X    case nWord: case nQword:
  1771. X        n = nalloc(offsetof(Node, u[2]));
  1772. X        n->u[0].s = va_arg(ap, char *);
  1773. X        n->u[1].s = va_arg(ap, char *);
  1774. X        break;
  1775. X    case nBang: case nNowait:
  1776. X    case nCount: case nFlat: case nRmfn: case nSubshell:
  1777. X    case nVar: case nCase:
  1778. X        n = nalloc(offsetof(Node, u[1]));
  1779. X        n->u[0].p = va_arg(ap, Node *);
  1780. X        break;
  1781. X    case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
  1782. X    case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
  1783. X    case nOrelse: case nPre: case nArgs: case nSwitch:
  1784. X    case nMatch: case nVarsub: case nWhile: case nLappend:
  1785. X        n = nalloc(offsetof(Node, u[2]));
  1786. X        n->u[0].p = va_arg(ap, Node *);
  1787. X        n->u[1].p = va_arg(ap, Node *);
  1788. X        break;
  1789. X    case nForin:
  1790. X        n = nalloc(offsetof(Node, u[3]));
  1791. X        n->u[0].p = va_arg(ap, Node *);
  1792. X        n->u[1].p = va_arg(ap, Node *);
  1793. X        n->u[2].p = va_arg(ap, Node *);
  1794. X        break;
  1795. X    case nPipe:
  1796. X        n = nalloc(offsetof(Node, u[4]));
  1797. X        n->u[0].i = va_arg(ap, int);
  1798. X        n->u[1].i = va_arg(ap, int);
  1799. X        n->u[2].p = va_arg(ap, Node *);
  1800. X        n->u[3].p = va_arg(ap, Node *);
  1801. X        break;
  1802. X    case nRedir:
  1803. X    case nNmpipe:
  1804. X        n = nalloc(offsetof(Node, u[3]));
  1805. X        n->u[0].i = va_arg(ap, int);
  1806. X        n->u[1].i = va_arg(ap, int);
  1807. X        n->u[2].p = va_arg(ap, Node *);
  1808. X        break;
  1809. X     }
  1810. X    n->type = t;
  1811. X    va_end(ap);
  1812. X    return n;
  1813. X}
  1814. X
  1815. X/* copy a tree to malloc space. Used when storing the definition of a function */
  1816. X
  1817. Xextern Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) {
  1818. X    Node *n;
  1819. X    if (s == NULL)
  1820. X        return NULL;
  1821. X    switch (s->type) {
  1822. X    default:
  1823. X        panic("unexpected node in treecpy");
  1824. X        /* NOTREACHED */
  1825. X    case nDup:
  1826. X        n = (*alloc)(offsetof(Node, u[3]));
  1827. X        n->u[0].i = s->u[0].i;
  1828. X        n->u[1].i = s->u[1].i;
  1829. X        n->u[2].i = s->u[2].i;
  1830. X        break;
  1831. X    case nWord: case nQword:
  1832. X        n = (*alloc)(offsetof(Node, u[2]));
  1833. X        n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s);
  1834. X        if (s->u[1].s != NULL) {
  1835. X            SIZE_T i = strlen(s->u[0].s);
  1836. X            n->u[1].s = (*alloc)(i);
  1837. X            memcpy(n->u[1].s, s->u[1].s, i);
  1838. X        } else
  1839. X            n->u[1].s = NULL;
  1840. X        break;
  1841. X    case nBang: case nNowait: case nCase:
  1842. X    case nCount: case nFlat: case nRmfn: case nSubshell: case nVar:
  1843. X        n = (*alloc)(offsetof(Node, u[1]));
  1844. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  1845. X        break;
  1846. X    case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
  1847. X    case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
  1848. X    case nOrelse: case nPre: case nArgs: case nSwitch:
  1849. X    case nMatch: case nVarsub: case nWhile: case nLappend:
  1850. X        n = (*alloc)(offsetof(Node, u[2]));
  1851. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  1852. X        n->u[1].p = treecpy(s->u[1].p, alloc);
  1853. X        break;
  1854. X    case nForin:
  1855. X        n = (*alloc)(offsetof(Node, u[3]));
  1856. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  1857. X        n->u[1].p = treecpy(s->u[1].p, alloc);
  1858. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  1859. X        break;
  1860. X    case nPipe:
  1861. X        n = (*alloc)(offsetof(Node, u[4]));
  1862. X        n->u[0].i = s->u[0].i;
  1863. X        n->u[1].i = s->u[1].i;
  1864. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  1865. X        n->u[3].p = treecpy(s->u[3].p, alloc);
  1866. X        break;
  1867. X    case nRedir:
  1868. X    case nNmpipe:
  1869. X        n = (*alloc)(offsetof(Node, u[3]));
  1870. X        n->u[0].i = s->u[0].i;
  1871. X        n->u[1].i = s->u[1].i;
  1872. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  1873. X        break;
  1874. X    }
  1875. X    n->type = s->type;
  1876. X    return n;
  1877. X}
  1878. X
  1879. X/* free a function definition that is no longer needed */
  1880. X
  1881. Xextern void treefree(Node *s) {
  1882. X    if (s == NULL)
  1883. X        return;
  1884. X    switch (s->type) {
  1885. X    default:
  1886. X        panic("unexpected node in treefree");
  1887. X        /* NOTREACHED */
  1888. X    case nDup:
  1889. X        break;
  1890. X    case nWord: case nQword:
  1891. X        efree(s->u[0].s);
  1892. X        efree(s->u[1].s);
  1893. X        break;
  1894. X    case nBang: case nNowait:
  1895. X    case nCount: case nFlat: case nRmfn:
  1896. X    case nSubshell: case nVar: case nCase:
  1897. X        treefree(s->u[0].p);
  1898. X        break;
  1899. X    case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
  1900. X    case nElse: case nEpilog: case nIf: case nNewfn:
  1901. X    case nOrelse: case nPre: case nArgs: case nCbody:
  1902. X    case nSwitch: case nMatch:  case nVarsub: case nWhile:
  1903. X    case nLappend:
  1904. X        treefree(s->u[1].p);
  1905. X        treefree(s->u[0].p);
  1906. X        break;
  1907. X    case nForin:
  1908. X        treefree(s->u[2].p);
  1909. X        treefree(s->u[1].p);
  1910. X        treefree(s->u[0].p);
  1911. X        break;
  1912. X    case nPipe:
  1913. X        treefree(s->u[2].p);
  1914. X        treefree(s->u[3].p);
  1915. X        break;
  1916. X    case nRedir:
  1917. X    case nNmpipe:
  1918. X        treefree(s->u[2].p);
  1919. X    }
  1920. X    efree(s);
  1921. X}
  1922. END_OF_FILE
  1923.   if test 4574 -ne `wc -c <'tree.c'`; then
  1924.     echo shar: \"'tree.c'\" unpacked with wrong size!
  1925.   fi
  1926.   # end of 'tree.c'
  1927. fi
  1928. if test -f 'utils.c' -a "${1}" != "-c" ; then 
  1929.   echo shar: Will not clobber existing file \"'utils.c'\"
  1930. else
  1931.   echo shar: Extracting \"'utils.c'\" \(2676 characters\)
  1932.   sed "s/^X//" >'utils.c' <<'END_OF_FILE'
  1933. X/* utils.c: functions of general utility */
  1934. X
  1935. X#include <errno.h>
  1936. X#include <setjmp.h>
  1937. X#include "rc.h"
  1938. X#include "jbwrap.h"
  1939. X
  1940. X/* print error with line number on noninteractive shells (i.e., scripts) */
  1941. X
  1942. Xextern void pr_error(char *s) {
  1943. X    if (s != NULL) {
  1944. X        if (interactive)
  1945. X            fprint(2, "%s\n", s);
  1946. X        else
  1947. X            fprint(2, "line %d: %s\n", lineno - 1, s);
  1948. X    }
  1949. X}
  1950. X
  1951. X/* our perror */
  1952. X
  1953. Xextern void uerror(char *s) {
  1954. X    extern int sys_nerr;
  1955. X    extern char *sys_errlist[];
  1956. X    if (errno > sys_nerr)
  1957. X        return;
  1958. X    if (s != NULL)
  1959. X        fprint(2, "%s: %s\n", s, sys_errlist[errno]);
  1960. X    else
  1961. X        fprint(2, "%s\n", sys_errlist[errno]);
  1962. X}
  1963. X
  1964. X/* Die horribly. This should never get called. Please let me know if it does. */
  1965. X
  1966. X#define PANICMSG "rc panic: "
  1967. X
  1968. Xextern void panic(char *s) {
  1969. X    write(2, PANICMSG, conststrlen(PANICMSG));
  1970. X    write(2, s, strlen(s));
  1971. X    write(2, "!\n", 2);
  1972. X    exit(1);
  1973. X}
  1974. X
  1975. X/* ascii -> unsigned conversion routines. -1 indicates conversion error. */
  1976. X
  1977. Xextern int n2u(char *s, unsigned int base) {
  1978. X    unsigned int i;
  1979. X    for (i = 0; *s != '\0'; s++) {
  1980. X        unsigned int j = (unsigned int) *s - '0';
  1981. X        if (j >= base) /* small hack with unsigned ints -- one compare for range test */
  1982. X            return -1;
  1983. X        i = i * base + j;
  1984. X    }
  1985. X    return (int) i;
  1986. X}
  1987. X
  1988. X/* The last word in portable ANSI: a strcmp wrapper for qsort */
  1989. X
  1990. Xextern int starstrcmp(const void *s1, const void *s2) {
  1991. X    return strcmp(*(char **)s1, *(char **)s2);
  1992. X}
  1993. X
  1994. X/* tests to see if pathname begins with "/", "./", or "../" */
  1995. X
  1996. Xextern bool isabsolute(char *path) {
  1997. X    return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
  1998. X}
  1999. X
  2000. X/* signal-safe read and write (for BSD slow devices). writeall also allows partial writes */
  2001. X
  2002. Xextern void writeall(int fd, char *buf, SIZE_T remain) {
  2003. X    int i;
  2004. X    for (i = 0; remain > 0; buf += i, remain -= i) {
  2005. X        interrupt_happened = FALSE;
  2006. X        if (!setjmp(slowbuf.j)) {
  2007. X            slow = TRUE;
  2008. X            if (interrupt_happened)
  2009. X                break;
  2010. X            else if ((i = write(fd, buf, remain)) <= 0)
  2011. X                break; /* abort silently on errors in write() */
  2012. X        } else
  2013. X            break;
  2014. X        slow = FALSE;
  2015. X    }
  2016. X    slow = FALSE;
  2017. X    SIGCHK;
  2018. X}
  2019. X
  2020. Xextern int rc_read(int fd, char *buf, SIZE_T n) {
  2021. X    long /*ssize_t*/ r;
  2022. X    interrupt_happened = FALSE;
  2023. X    if (!setjmp(slowbuf.j)) {
  2024. X        slow = TRUE;
  2025. X        if (!interrupt_happened)
  2026. X            r = read(fd, buf, n);
  2027. X        else
  2028. X            r = -2;
  2029. X    } else
  2030. X        r = -2;
  2031. X    slow = FALSE;
  2032. X    if (r == -2) {
  2033. X        errno = EINTR;
  2034. X        r = -1;
  2035. X    }
  2036. X    SIGCHK;
  2037. X    return r;
  2038. X}
  2039. X
  2040. X/* clear out z bytes from character string s */
  2041. X
  2042. Xextern char *clear(char *s, SIZE_T z) {
  2043. X    while (z != 0)
  2044. X        s[--z] = 0;
  2045. X    return s;
  2046. X}
  2047. X
  2048. X/* duplicate a fd and close the old one only if necessary */
  2049. X
  2050. Xextern int mvfd(int i, int j) {
  2051. X    if (i != j) {
  2052. X        int s = dup2(i, j);
  2053. X        close(i);
  2054. X        return s;
  2055. X    }
  2056. X    return 0;
  2057. X}
  2058. END_OF_FILE
  2059.   if test 2676 -ne `wc -c <'utils.c'`; then
  2060.     echo shar: \"'utils.c'\" unpacked with wrong size!
  2061.   fi
  2062.   # end of 'utils.c'
  2063. fi
  2064. if test -f 'wait.c' -a "${1}" != "-c" ; then 
  2065.   echo shar: Will not clobber existing file \"'wait.c'\"
  2066. else
  2067.   echo shar: Extracting \"'wait.c'\" \(2158 characters\)
  2068.   sed "s/^X//" >'wait.c' <<'END_OF_FILE'
  2069. X#include <errno.h>
  2070. X#include <setjmp.h>
  2071. X#include "rc.h"
  2072. X#include "jbwrap.h"
  2073. X
  2074. Xbool forked = FALSE;
  2075. X
  2076. Xstatic int rc_wait(int *);
  2077. X
  2078. Xtypedef struct Pid Pid;
  2079. X
  2080. Xstatic struct Pid {
  2081. X    int pid, stat;
  2082. X    bool alive;
  2083. X    Pid *n;
  2084. X} *plist = NULL;
  2085. X
  2086. Xextern int rc_fork() {
  2087. X    Pid *new = enew(Pid);
  2088. X    int pid = fork();
  2089. X    switch (pid) {
  2090. X    case -1:
  2091. X        uerror("fork");
  2092. X        rc_error(NULL);
  2093. X        /* NOTREACHED */
  2094. X    case 0:
  2095. X        forked = TRUE;
  2096. X        SIGCHK;
  2097. X        return 0;
  2098. X    default:
  2099. X        new->pid = pid;
  2100. X        new->alive = TRUE;
  2101. X        new->n = plist;
  2102. X        plist = new;
  2103. X        return pid;
  2104. X    }
  2105. X}
  2106. X
  2107. Xextern int rc_wait4(int pid, int *stat, bool nointr) {
  2108. X    Pid *r, *prev;
  2109. X    int ret;
  2110. X    /* first look for a child which may already have exited */
  2111. Xagain:    for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n)
  2112. X        if (r->pid == pid)
  2113. X            break;
  2114. X    if (r == NULL) {
  2115. X        errno = ECHILD; /* no children */
  2116. X        uerror("wait");
  2117. X        *stat = 0x100; /* exit(1) */
  2118. X        return -1;
  2119. X    }
  2120. X    if (r->alive) {
  2121. X        while (pid != (ret = rc_wait(stat))) {
  2122. X            Pid *q;
  2123. X            if (ret < 0) {
  2124. X                if (nointr)
  2125. X                    goto again;
  2126. X                return ret;
  2127. X            }
  2128. X            for (q = plist; q != NULL; q = q->n)
  2129. X                if (q->pid == ret) {
  2130. X                    q->alive = FALSE;
  2131. X                    q->stat = *stat;
  2132. X                    break;
  2133. X                }
  2134. X        }
  2135. X    } else
  2136. X        *stat = r->stat;
  2137. X    if (prev == NULL)
  2138. X        plist = r->n; /* remove element from head of list */
  2139. X    else
  2140. X        prev->n = r->n;
  2141. X    efree(r);
  2142. X    return pid;
  2143. X}
  2144. X
  2145. Xextern List *sgetapids() {
  2146. X    List *r;
  2147. X    Pid *p;
  2148. X    for (r = NULL, p = plist; p != NULL; p = p->n) {
  2149. X        List *q;
  2150. X        if (!p->alive)
  2151. X            continue;
  2152. X        q = nnew(List);
  2153. X        q->w = nprint("%d", p->pid);
  2154. X        q->m = NULL;
  2155. X        q->n = r;
  2156. X        r = q;
  2157. X    }
  2158. X    return r;
  2159. X}
  2160. X
  2161. Xextern void waitforall() {
  2162. X    int stat;
  2163. X    while (plist != NULL) {
  2164. X        int pid = rc_wait4(plist->pid, &stat, FALSE);
  2165. X        if (pid > 0)
  2166. X            setstatus(pid, stat);
  2167. X        else
  2168. X            set(FALSE);
  2169. X        SIGCHK;
  2170. X    }
  2171. X}
  2172. X
  2173. X/*
  2174. X   rc_wait: a wait() wrapper that interfaces wait() w/rc signals.
  2175. X   Note that the signal queue is not checked in this fn; someone
  2176. X   may want to resume the wait() without delivering any signals.
  2177. X*/
  2178. X
  2179. Xstatic int rc_wait(int *stat) {
  2180. X    int r;
  2181. X    interrupt_happened = FALSE;
  2182. X    if (!setjmp(slowbuf.j)) {
  2183. X        slow = TRUE;
  2184. X        if (!interrupt_happened)
  2185. X            r = wait(stat);
  2186. X        else
  2187. X            r = -1;
  2188. X    } else
  2189. X        r = -1;
  2190. X    slow = FALSE;
  2191. X    return r;
  2192. X}
  2193. END_OF_FILE
  2194.   if test 2158 -ne `wc -c <'wait.c'`; then
  2195.     echo shar: \"'wait.c'\" unpacked with wrong size!
  2196.   fi
  2197.   # end of 'wait.c'
  2198. fi
  2199. if test -f 'which.c' -a "${1}" != "-c" ; then 
  2200.   echo shar: Will not clobber existing file \"'which.c'\"
  2201. else
  2202.   echo shar: Extracting \"'which.c'\" \(2794 characters\)
  2203.   sed "s/^X//" >'which.c' <<'END_OF_FILE'
  2204. X/* which.c: check to see if a file is executable.
  2205. X
  2206. X   This function was originally written with Maarten Litmaath's which.c as
  2207. X   a template, but was changed in order to accomodate the possibility of
  2208. X   rc's running setuid or the possibility of executing files not in the
  2209. X   primary group. Much of this file has been re-vamped by Paul Haahr.
  2210. X   I re-re-vamped the functions that Paul supplied to correct minor bugs
  2211. X   and to strip out unneeded functionality.
  2212. X*/
  2213. X
  2214. X#include <sys/types.h>
  2215. X#include <sys/stat.h>
  2216. X#include <sys/param.h>
  2217. X#include <errno.h>
  2218. X#include "rc.h"
  2219. X
  2220. X#define X_USR 0100
  2221. X#define X_GRP 0010
  2222. X#define X_OTH 0001
  2223. X#define X_ALL (X_USR|X_GRP|X_OTH)
  2224. X
  2225. Xextern int stat(const char *, struct stat *);
  2226. X
  2227. Xstatic bool initialized = FALSE;
  2228. Xstatic int uid, gid;
  2229. X
  2230. X#ifdef NGROUPS
  2231. Xstatic int ngroups, gidset[NGROUPS];
  2232. X
  2233. X/* determine whether gid lies in gidset */
  2234. X
  2235. Xstatic int ingidset(int g) {
  2236. X    int i;
  2237. X    for (i = 0; i < ngroups; i++)
  2238. X        if (g == gidset[i])
  2239. X            return 1;
  2240. X    return 0;
  2241. X}
  2242. X#endif
  2243. X
  2244. X/*
  2245. X   A home-grown access/stat. Does the right thing for group-executable files.
  2246. X   Returns a bool instead of this -1 nonsense.
  2247. X*/
  2248. X
  2249. Xstatic bool rc_access(char *path, bool verbose) {
  2250. X    struct stat st;
  2251. X    int mask;
  2252. X    if (stat(path, &st) != 0) {
  2253. X        if (verbose) /* verbose flag only set for absolute pathname */
  2254. X            uerror(path);
  2255. X        return FALSE;
  2256. X    }
  2257. X    if (uid == 0)
  2258. X        mask = X_ALL;
  2259. X    else if (uid == st.st_uid)
  2260. X        mask = X_USR;
  2261. X#ifdef NGROUPS
  2262. X    else if (gid == st.st_gid || ingidset(st.st_gid))
  2263. X#else
  2264. X    else if (gid == st.st_gid)
  2265. X#endif
  2266. X        mask = X_GRP;
  2267. X    else
  2268. X        mask = X_OTH;
  2269. X    if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask))
  2270. X        return TRUE;
  2271. X    errno = EACCES;
  2272. X    if (verbose)
  2273. X        uerror(path);
  2274. X    return FALSE;
  2275. X}
  2276. X
  2277. X/* return a full pathname by searching $path, and by checking the status of the file */
  2278. X
  2279. Xextern char *which(char *name, bool verbose) {
  2280. X    static char *test = NULL;
  2281. X    static SIZE_T testlen = 0;
  2282. X    List *path;
  2283. X    int len;
  2284. X    if (name == NULL)    /* no filename? can happen with "> foo" as a command */
  2285. X        return NULL;
  2286. X    if (!initialized) {
  2287. X        initialized = TRUE;
  2288. X        uid = geteuid();
  2289. X        gid = getegid();
  2290. X#ifdef NGROUPS
  2291. X        ngroups = getgroups(NGROUPS, gidset);
  2292. X#endif
  2293. X    }
  2294. X    if (isabsolute(name)) /* absolute pathname? */
  2295. X        return rc_access(name, verbose) ? name : NULL;
  2296. X    len = strlen(name);
  2297. X    for (path = varlookup("path"); path != NULL; path = path->n) {
  2298. X        SIZE_T need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
  2299. X        if (testlen < need) {
  2300. X            efree(test);
  2301. X            test = ealloc(testlen = need);
  2302. X        }
  2303. X        if (*path->w == '\0') {
  2304. X            strcpy(test, name);
  2305. X        } else {
  2306. X            strcpy(test, path->w);
  2307. X            if (!streq(test, "/")) /* "//" is special to POSIX */
  2308. X                strcat(test, "/");
  2309. X            strcat(test, name);
  2310. X        }
  2311. X        if (rc_access(test, FALSE))
  2312. X            return test;
  2313. X    }
  2314. X    if (verbose)
  2315. X        fprint(2, "%s not found\n", name);
  2316. X    return NULL;
  2317. X}
  2318. END_OF_FILE
  2319.   if test 2794 -ne `wc -c <'which.c'`; then
  2320.     echo shar: \"'which.c'\" unpacked with wrong size!
  2321.   fi
  2322.   # end of 'which.c'
  2323. fi
  2324. echo shar: End of archive 6 \(of 7\).
  2325. cp /dev/null ark6isdone
  2326. MISSING=""
  2327. for I in 1 2 3 4 5 6 7 ; do
  2328.     if test ! -f ark${I}isdone ; then
  2329.     MISSING="${MISSING} ${I}"
  2330.     fi
  2331. done
  2332. if test "${MISSING}" = "" ; then
  2333.     echo You have unpacked all 7 archives.
  2334.     rm -f ark[1-9]isdone
  2335. else
  2336.     echo You still must unpack the following archives:
  2337.     echo "        " ${MISSING}
  2338. fi
  2339. exit 0
  2340. exit 0 # Just in case...
  2341.