rc-list - mailing list for the rc(1) shell
 help / color / mirror / Atom feed
* rc patches halfway to 1.5
@ 1994-01-10  7:19 Byron Rakitzis
  0 siblings, 0 replies; 2+ messages in thread
From: Byron Rakitzis @ 1994-01-10  7:19 UTC (permalink / raw)
  To: rc

Here are a set of rc patches I have applied to rc-1.4. They reflect
the current state of my rc-1.5 development directory, and I am pushing
them out of the door since I do not know when I will be able to hack
in all the features I want for 1.5.

This "release" is called "rc-1.5betadev-1", which means that 1.5 is
still nominally under development. Any futher patches before a freeze
in features will be called "betadev-2", and so forth.

Things that are notably missing from this patch set: support for
builtin read, support for /dev/fd-like functionality via /tmp files.
Also, the man pages are possibly not quite up-to-date; I still need to
coordinate the feature changes with the man pages.

Please read the changes to the CHANGES file to see what has changed,
that should be an authoritative list.

Thanks,

Byron.

PS "patch" seems to fail on trip.rc, so I am reposting the new trip.rc;
it follows in the next message.  I will ask cks if he can apply all the
patches and leave the resulting archive for ftp on a toronto machine.

*** /tmp/T0a19009	Sun Jan  9 14:43:20 1994
--- history/history.c	Wed Dec  8 21:52:25 1993
***************
*** 246,252 ****
  
  	/*
  	 * if the command contains the "me" character at the start of the line
! 	 * or after any of [`{|()] then try again
  	 */
  
  	for (t = s; *t != '\0'; t++)
--- 246,252 ----
  
  	/*
  	 * if the command contains the "me" character at the start of the line
! 	 * or after any of [`{|()@] then try again
  	 */
  
  	for (t = s; *t != '\0'; t++)
***************
*** 254,261 ****
  			char *u = t - 1;
  			while (u >= s && (*u == ' ' || *u == '\t'))
  				--u;
! 			if (u < s || *u == '`' || *u == '{' || *u == '|' || *u == '(' || *u == ')')
  				goto again;
  		}
  	return s;
  }
--- 254,269 ----
  			char *u = t - 1;
  			while (u >= s && (*u == ' ' || *u == '\t'))
  				--u;
! 			if (u < s)
  				goto again;
+ 			switch (*u) {
+ 			case '`': case '@':
+ 			case '(': case ')':
+ 			case '{': case '|':
+ 				goto again;
+ 			default:
+ 				break;
+ 			}
  		}
  	return s;
  }
*** /tmp/T0a19638	Sun Jan  9 15:21:04 1994
--- CHANGES	Sun Jan  9 15:20:53 1994
***************
*** 169,171 ****
--- 169,263 ----
  
  A memory leak in treefree() was plugged up --- the root node of a
  function was not getting freed.
+ 
+ Changes since rc-1.4:
+ 
+ General changes:
+ 
+         Some small memory leaks/uninit references revealed by Purify.
+ 
+         $bqstatus for querying the exit status of a backquote.
+ 
+         Globbing through unreadable directories.
+ 
+         More options to whatis.
+ 
+         History append which always re-opens the file (avoids
+         inconsistencies over multiple NFS-mounted accesses to
+         $history).
+ 
+         Support "rc -s".
+ 
+ ---------
+ 
+ Makefile:	Added comment referring to README for yacc/malloc problem.
+ 
+ uiltins.c:	Added more options to whatis, protected rlimit prototypes
+ 		with #ifndef SYSVR4, renamed SIGCHK to sigchk.
+ 
+ except.c:	Patched nl_on_intr printing to happen only in interactive
+ 		shells.
+ 
+ exec.c:		Added comment explaining nl_on_intr variable, renamed SIGCHK
+ 		to sigchk.
+ 
+ fn.c:		Replaced by-hand consing of exception stack etc. for signal
+ 		handler execution with call to funcall(). Replaced fun2str
+ 		call with call on print routines.
+ 
+ footobar.c:	Got rid of memory leak in get_name(), parenthesize count,
+ 		flat and var nodes for correctness in unparsing, removed
+ 		list2str, made get_name use nalloc space, merge in a
+ 		better parse_var from es.
+ 
+ glob.c:		Split out a test so that closedir is called correctly, renamed
+ 		SIGCHK to sigchk.
+ 
+ glom.c:		Added bqstatus, renamed SIGCHK to sigchk, removed spurious
+ 		setsigdefaults, patched uninit memory reference, rename
+ 		"clear" to "memzero", wait for bq subproc to finish on EINTR.
+ 
+ hash.c:		Added options to function/variable print code.
+ 
+ history/history.c: Added '@' to the list of chars which can precede an
+ 		ignored '-'.
+ 
+ input.c:	Got rid of tiny memory leak in closefds, got rid of uninit
+ 		memory reference in popinput, moved nul ignored check into
+ 		realgchar(), changed history append to always reopen the
+ 		history file, replaced SIGCHK with sigchk. Freed memory
+ 		returned by call to readline().
+ 
+ lex.c:		Corrected typo in comment, moved nul character ignore code
+ 		to input routines.
+ 
+ main.c:		Added -s flag.
+ 
+ nalloc.c:	Added convenience feature to erealloc. (Allow NULL parameter)
+ 
+ print.c:	Changed use of va_start so broken compilers can compile
+ 		print code.
+ 
+ proto.h:	Added fake memset.
+ 
+ rc.h:		Replaced clear() function prototype with a macro call on
+ 		memset(), removed SIGCHK, fixed prototypes.
+ 
+ signal.c:	Removed unconditional exit in catcher code, renamed SIGCHK
+ 		to sigchk.
+ 
+ status.c:	Rewrite sgetstatus breaking out strstatus so that bqstatus
+ 		can be set from glom routines.
+ 
+ utils.c:	Got rid of clear() (use memset from C library), rename SIGCHK
+ 		to sigchk.
+ 
+ var.c:	 	Got rid of memory leak in listassign(), converted list2str()
+ 		call to something using the print routines.
+ 
+ version.c:	New version string.
+ 
+ wait.c:		Got rid of memory leak in rc_fork, renamed SIGCHK to sigchk.
+ 
+ walk.c:		Fixed pre-redirection bug, removed spurious setsigdefaults(),
+ 		renamed SIGCHK to sigchk.
*** /tmp/T0a19127	Sun Jan  9 14:45:35 1994
--- Makefile	Wed Dec  8 21:52:27 1993
***************
*** 21,27 ****
  LDFLAGS=
  
  # You may substitute "bison -y" for yacc. (You want to choose the one that
! # makes a smaller y.tab.c.)
  YACC=yacc
  
  OBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \
--- 21,27 ----
  LDFLAGS=
  
  # You may substitute "bison -y" for yacc. (You want to choose the one that
! # makes a smaller y.tab.c. Also see the README about Sun's yacc.)
  YACC=yacc
  
  OBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \
*** /tmp/T0a19127	Sun Jan  9 14:45:36 1994
--- README	Wed Dec  8 21:52:29 1993
***************
*** 1,4 ****
! This is release 1.4 of rc.
  
  Read COPYRIGHT for copying information. All files are
  
--- 1,4 ----
! This is release 1.5 of rc.
  
  Read COPYRIGHT for copying information. All files are
  
***************
*** 62,67 ****
--- 62,78 ----
  to get rc to work in a reasonable fashion on a real (i.e., commercial,
  non-Labs) UNIX system; a few were changes motivated by concern
  about some inadequacies in the original design.
+ 
+ YACC
+ 
+ The yacc that Sun ships with SunOS 4.1.1 calls malloc() to allocate
+ space for the state stack, and requires a call to YYACCEPT or YYABORT
+ to free this memory. This means that if rc takes an interrupt while
+ parsing a command (say, if ^C is typed), yacc will leak away this
+ memory. The solution is to use a yacc which statically allocates
+ this array, such as the yacc in the BSD distribution. Berkeley yacc-
+ generated y.tab.c and y.tab.h are shipped with rc in case you cannot
+ get hold of Berkeley yacc.
  
  OLD C
  
*** /tmp/T0a19127	Sun Jan  9 14:45:36 1994
--- builtins.c	Wed Dec  8 21:52:27 1993
***************
*** 12,17 ****
--- 12,18 ----
  #include <errno.h>
  #include "rc.h"
  #include "jbwrap.h"
+ #include "sigmsgs.h"
  #ifndef NOLIMITS
  #include <sys/time.h>
  #include <sys/resource.h>
***************
*** 266,272 ****
  		setstatus(pid, stat);
  	else
  		set(FALSE);
! 	SIGCHK;
  }
  
  /*
--- 267,273 ----
  		setstatus(pid, stat);
  	else
  		set(FALSE);
! 	sigchk();
  }
  
  /*
***************
*** 274,282 ****
     is defined as a variable, function or pathname.
  */
  
  static void b_whatis(char **av) {
  	bool f, found;
- 	bool ess = FALSE;
  	int i, ac, c;
  	List *s;
  	Node *n;
--- 275,294 ----
     is defined as a variable, function or pathname.
  */
  
+ #define not(b)	((b)^TRUE)
+ #define show(b)	(not(eff|vee|pee|bee|ess)|(b))
+ 
+ static bool issig(char *s) {
+ 	int i;
+ 	for (i = 0; i < NUMOFSIGNALS; i++)
+ 		if (streq(s, signals[i].name))
+ 			return TRUE;
+ 	return FALSE;
+ }
+ 
  static void b_whatis(char **av) {
+ 	bool ess, eff, vee, pee, bee;
  	bool f, found;
  	int i, ac, c;
  	List *s;
  	Node *n;
***************
*** 283,319 ****
  	char *e;
  	for (rc_optind = ac = 0; av[ac] != NULL; ac++)
  		; /* count the arguments for getopt */
! 	while ((c = rc_getopt(ac, av, "s")) == 's')
! 		ess = TRUE;
! 	if (c != -1) {
! 		set(FALSE);
! 		return;
! 	}
  	av += rc_optind;
! 	if (*av == NULL && !ess) {
! 		whatare_all_vars();
  		set(TRUE);
  		return;
  	}
- 	if (ess)
- 		whatare_all_signals();
  	found = TRUE;
  	for (i = 0; av[i] != NULL; i++) {
  		f = FALSE;
  		errno = ENOENT;
! 		if ((s = varlookup(av[i])) != NULL) {
  			f = TRUE;
  			prettyprint_var(1, av[i], s);
  		}
! 		if ((n = fnlookup(av[i])) != NULL) {
  			f = TRUE;
  			prettyprint_fn(1, av[i], n);
! 		} else if (isbuiltin(av[i]) != NULL) {
  			f = TRUE;
  			fprint(1, "builtin %s\n", av[i]);
! 		} else if ((e = which(av[i], FALSE)) != NULL) {
  			f = TRUE;
! 			fprint(1, "%s\n", e);
  		}
  		if (!f) {
  			found = FALSE;
--- 295,343 ----
  	char *e;
  	for (rc_optind = ac = 0; av[ac] != NULL; ac++)
  		; /* count the arguments for getopt */
! 	ess = eff = vee = pee = bee = FALSE;
! 	while ((c = rc_getopt(ac, av, "sfvpb")) != -1)
! 		switch (c) {
! 		default: set(FALSE); return;
! 		case 's': ess = TRUE; break;
! 		case 'f': eff = TRUE; break;
! 		case 'v': vee = TRUE; break;
! 		case 'p': pee = TRUE; break;
! 		case 'b': bee = TRUE; break;
! 		}
  	av += rc_optind;
! 	if (*av == NULL) {
! 		if (vee|eff)
! 			whatare_all_vars(eff, vee);
! 		if (ess)
! 			whatare_all_signals();
! 		if (bee)
! 			for (i = 0; i < arraysize(builtins); i++)
! 				fprint(1, "builtin %s\n", builtins[i].name);
! 		if (pee)
! 			fprint(2, "whatis -p: must specify argument\n");
! 		if (show(FALSE)) /* no options? */
! 			whatare_all_vars(TRUE, TRUE);
  		set(TRUE);
  		return;
  	}
  	found = TRUE;
  	for (i = 0; av[i] != NULL; i++) {
  		f = FALSE;
  		errno = ENOENT;
! 		if (show(vee) && (s = varlookup(av[i])) != NULL) {
  			f = TRUE;
  			prettyprint_var(1, av[i], s);
  		}
! 		if (((show(ess)&&issig(av[i])) || show(eff)) && (n = fnlookup(av[i])) != NULL) {
  			f = TRUE;
  			prettyprint_fn(1, av[i], n);
! 		} else if (show(bee) && isbuiltin(av[i]) != NULL) {
  			f = TRUE;
  			fprint(1, "builtin %s\n", av[i]);
! 		} else if (show(pee) && (e = which(av[i], FALSE)) != NULL) {
  			f = TRUE;
! 			fprint(1, "%S\n", e);
  		}
  		if (!f) {
  			found = FALSE;
***************
*** 440,447 ****
--- 464,473 ----
  	{ NULL, 0, NULL }
  };
  
+ #ifndef SYSVR4
  extern int getrlimit(int, struct rlimit *);
  extern int setrlimit(int, struct rlimit *);
+ #endif
  
  static void printlimit(const Limit *limit, bool hard) {
  	struct rlimit rlim;
*** /tmp/T0a19127	Sun Jan  9 14:45:38 1994
--- except.c	Fri Dec 10 20:25:37 1993
***************
*** 131,137 ****
  	if (s != SIGINT)
  		panic("s != SIGINT in sigint catcher");
  	/* this is the newline you see when you hit ^C while typing a command */
! 	if (nl_on_intr)
  		fprint(2, "\n");
  	nl_on_intr = TRUE;
  	redirq = NULL;
--- 131,137 ----
  	if (s != SIGINT)
  		panic("s != SIGINT in sigint catcher");
  	/* this is the newline you see when you hit ^C while typing a command */
! 	if (interactive && nl_on_intr)
  		fprint(2, "\n");
  	nl_on_intr = TRUE;
  	redirq = NULL;
*** /tmp/T0a19127	Sun Jan  9 14:45:38 1994
--- exec.c	Wed Dec  8 21:59:43 1993
***************
*** 110,118 ****
  		redirq = NULL;
  		rc_wait4(pid, &stat, TRUE);
  		setstatus(-1, stat);
  		if ((stat & 0xff) == 0)
  			nl_on_intr = FALSE;
! 		SIGCHK;
  		nl_on_intr = TRUE;
  		pop_cmdarg(TRUE);
  	}
--- 110,129 ----
  		redirq = NULL;
  		rc_wait4(pid, &stat, TRUE);
  		setstatus(-1, stat);
+ 		/*
+ 		   There is a very good reason for having this weird
+ 		   nl_on_intr variable: when rc and its child both
+ 		   process a SIGINT, (i.e., the child has a SIGINT
+ 		   catcher installed) then you don't want rc to print
+ 		   a newline when the child finally exits. Here's an
+ 		   example: ed, <type ^C>, <type "q">. rc does not
+ 		   and should not print a newline before the next
+ 		   prompt, even though there's a SIGINT in its signal
+ 		   vector.
+ 		*/
  		if ((stat & 0xff) == 0)
  			nl_on_intr = FALSE;
! 		sigchk();
  		nl_on_intr = TRUE;
  		pop_cmdarg(TRUE);
  	}
*** /tmp/T0a19127	Sun Jan  9 14:45:38 1994
--- fn.c	Wed Dec  8 21:52:27 1993
***************
*** 12,20 ****
  
  static bool runexit = FALSE;
  static Node *handlers[NUMOFSIGNALS], null;
! static void (*def_sigint)(int) = SIG_DFL,
! 	    (*def_sigquit)(int) = SIG_DFL,
! 	    (*def_sigterm)(int) = SIG_DFL;
  
  /*
     Set signals to default values for rc. This means that interactive
--- 12,20 ----
  
  static bool runexit = FALSE;
  static Node *handlers[NUMOFSIGNALS], null;
! static void (*def_sigint)(int) = SIG_DFL;
! static void (*def_sigquit)(int) = SIG_DFL;
! static void (*def_sigterm)(int) = SIG_DFL;
  
  /*
     Set signals to default values for rc. This means that interactive
***************
*** 106,118 ****
  /* rc's exit. if runexit is set, run the sigexit function. */
  
  extern void rc_exit(int stat) {
- 	static char *sigexit[2] = {
- 		"sigexit",
- 		NULL
- 	};
  	if (runexit) {
  		runexit = FALSE;
! 		funcall(sigexit);
  		stat = getstatus();
  	}
  	exit(stat);
--- 106,117 ----
  /* rc's exit. if runexit is set, run the sigexit function. */
  
  extern void rc_exit(int stat) {
  	if (runexit) {
+ 		char *sig[2];
+ 		sig[0] = "sigexit";
+ 		sig[1] = NULL;
  		runexit = FALSE;
! 		funcall(sig);
  		stat = getstatus();
  	}
  	exit(stat);
***************
*** 121,142 ****
  /* The signal handler for all functions. calls walk() */
  
  static void fn_handler(int s) {
! 	List *dollarzero;
! 	Estack e;
! 	Edata star;
  	int olderrno;
  	if (s < 1 || s >= NUMOFSIGNALS)
  		panic("unknown signal");
  	olderrno = errno;
! 	dollarzero = nnew(List);
! 	dollarzero->w = signals[s].name;
! 	dollarzero->n = NULL;
! 	varassign("*", dollarzero, TRUE);
! 	star.name = "*";
! 	except(eVarstack, star, &e);
! 	walk(handlers[s], TRUE);
! 	varrm("*", TRUE);
! 	unexcept(); /* eVarstack */
  	errno = olderrno;
  }
  
--- 120,133 ----
  /* The signal handler for all functions. calls walk() */
  
  static void fn_handler(int s) {
! 	char *sig[2];
  	int olderrno;
  	if (s < 1 || s >= NUMOFSIGNALS)
  		panic("unknown signal");
  	olderrno = errno;
! 	sig[0] = signals[s].name;
! 	sig[1] = NULL;
! 	funcall(sig);
  	errno = olderrno;
  }
  
***************
*** 217,223 ****
  		return NULL;
  	if (look->extdef != NULL)
  		return look->extdef;
! 	return look->extdef = fun2str(name, look->def);
  }
  
  /*
--- 208,214 ----
  		return NULL;
  	if (look->extdef != NULL)
  		return look->extdef;
! 	return look->extdef = mprint("fn_%F={%T}", name, look->def);
  }
  
  /*
*** /tmp/T0a19127	Sun Jan  9 14:45:39 1994
--- footobar.c	Wed Dec  8 21:52:29 1993
***************
*** 5,19 ****
  
  #include "rc.h"
  
! #define FSCHAR '\1'
! #define FSSTRING "\1"
  
- static char *getenvw(char *, bool);
- 
  #ifdef PROTECT_ENV
! static bool Fconv(Format *f, int ignore) {	/* protect an exported name from brain-dead shells */
! 	int c;
  	unsigned const char *s = va_arg(f->args, unsigned const char *);
  
  	while ((c = *s++) != '\0')
  		if (dnw[c] || c == '*' || (c == '_' && *s == '_'))
--- 5,16 ----
  
  #include "rc.h"
  
! /* protect an exported name from brain-dead shells */
  
  #ifdef PROTECT_ENV
! static bool Fconv(Format *f, int ignore) {
  	unsigned const char *s = va_arg(f->args, unsigned const char *);
+ 	int c;
  
  	while ((c = *s++) != '\0')
  		if (dnw[c] || c == '*' || (c == '_' && *s == '_'))
***************
*** 24,35 ****
  }
  #endif
  
- /* used to turn a function in Node * form into something we can export to the environment */
- 
- extern char *fun2str(char *name, Node *n) {
- 	return mprint("fn_%F={%T}", name, n);
- }
- 
  /* convert a redirection to a printable form */
  
  static bool Dconv(Format *f, int ignore) {
--- 21,26 ----
***************
*** 63,76 ****
  	switch (n->type) {
  	case nWord:	fmtprint(f, "%S", n->u[0].s);				break;
  	case nQword:	fmtprint(f, "%#S", n->u[0].s);				break;
! 	case nBang:	fmtprint(f, "! %T", n->u[0].p);				break;
  	case nCase:	fmtprint(f, "case %T", n->u[0].p);			break;
  	case nNowait:	fmtprint(f, "%T&", n->u[0].p);				break;
- 	case nCount:	fmtprint(f, "$#%T", n->u[0].p);				break;
- 	case nFlat:	fmtprint(f, "$^%T", n->u[0].p);				break;
  	case nRmfn:	fmtprint(f, "fn %T", n->u[0].p);			break;
  	case nSubshell:	fmtprint(f, "@ %T", n->u[0].p);				break;
- 	case nVar:	fmtprint(f, "$%T", n->u[0].p);				break;
  	case nAndalso:	fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p);		break;
  	case nAssign:	fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p);		break;
  	case nConcat:	fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p);		break;
--- 54,64 ----
  	switch (n->type) {
  	case nWord:	fmtprint(f, "%S", n->u[0].s);				break;
  	case nQword:	fmtprint(f, "%#S", n->u[0].s);				break;
! 	case nBang:	fmtprint(f, "!%T", n->u[0].p);				break;
  	case nCase:	fmtprint(f, "case %T", n->u[0].p);			break;
  	case nNowait:	fmtprint(f, "%T&", n->u[0].p);				break;
  	case nRmfn:	fmtprint(f, "fn %T", n->u[0].p);			break;
  	case nSubshell:	fmtprint(f, "@ %T", n->u[0].p);				break;
  	case nAndalso:	fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p);		break;
  	case nAssign:	fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p);		break;
  	case nConcat:	fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p);		break;
***************
*** 81,90 ****
  	case nArgs:	fmtprint(f, "%T %T", n->u[0].p, n->u[1].p);		break;
  	case nSwitch:	fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p);	break;
  	case nMatch:	fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p);		break;
- 	case nVarsub:	fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p);		break;
  	case nWhile:	fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p);	break;
  	case nLappend:	fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p);		break;
  	case nForin:	fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
  	case nDup:
  		if (n->u[2].i != -1)
  			fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
--- 69,93 ----
  	case nArgs:	fmtprint(f, "%T %T", n->u[0].p, n->u[1].p);		break;
  	case nSwitch:	fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p);	break;
  	case nMatch:	fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p);		break;
  	case nWhile:	fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p);	break;
  	case nLappend:	fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p);		break;
  	case nForin:	fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
+ 	case nVarsub:	fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p);		break;
+ 	case nCount: case nFlat: case nVar: {
+ 		char *lp = "", *rp = "";
+ 		Node *n0 = n->u[0].p;
+ 
+ 		if (n0->type != nWord && n0->type != nQword)
+ 			lp = "(", rp = ")";
+ 
+ 		switch (n->type) {
+ 		default:	panic("this can't happen");		break;
+ 		case nCount:	fmtprint(f, "$#%s%T%s", lp, n0, rp);	break;
+ 		case nFlat:	fmtprint(f, "$^%s%T%s", lp, n0, rp);	break;
+ 		case nVar:	fmtprint(f, "$%s%T%s", lp, n0, rp);	break;
+ 		}
+ 		break;
+ 	}
  	case nDup:
  		if (n->u[2].i != -1)
  			fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
***************
*** 154,218 ****
  	return FALSE;
  }
  
- /* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
- 
- extern char *list2str(char *name, List *s) {
- 	SIZE_T size, step;
- 	List *t;
- 	char *w, *x;
- 	name = nprint("%F", name);
- 	size = strlen(name) + listlen(s);
- 	w = ealloc(size + 2);
- 	t = s;
- 	x = w;
- 	strcpy(x, name);
- 	strcpy(x += strlen(name), "=");
- 	strcpy(x += conststrlen("="), t->w);
- 	for (x += strlen(t->w), s = s->n; s != NULL; s = s->n) {
- 		memcpy(x, FSSTRING, step = conststrlen(FSSTRING));
- 		x += step;
- 		memcpy(x, s->w, step = strlen(s->w));
- 		x += step;
- 	}
- 	*x = '\0';
- 	return w;
- }
- 
  /* convert a List to an array, for execve() */
  
  extern char **list2array(List *s, bool print) {
! 	char **av;
! 	int i;
  
- 	/* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */
- 	av = nalloc((listnel(s) + 4) * sizeof (char *));
- 	av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */
  	if (print)
  		fprint(2, "%L\n", s, " ");
! 	for (i = 0; s != NULL; i++) {
! 		av[i] = s->w;
  		s = s->n;
  	}
! 	av[i] = NULL;
! 	return av;
  }
  
! /* figure out the name of a variable given an environment string. copy this into malloc space */
  
  extern char *get_name(char *s) {
  	int c;
! 	SIZE_T i;
! 	char *r, *namebuf;
! 	for (i = 0; s[i] != '\0' && s[i] != '='; i++)
! 		;
! 	if (s[i] == '\0')
  		return NULL;
! 	r = namebuf = ealloc(i + 1);
  	while (1)
  		switch (c = *s++) {
  		case '=':
  			*r++ = '\0';
! 			return namebuf;
  #ifdef PROTECT_ENV
  		case '_':
  			if (*s == '_') {
--- 157,197 ----
  	return FALSE;
  }
  
  /* convert a List to an array, for execve() */
  
  extern char **list2array(List *s, bool print) {
! 	char **argv, **av;
  
  	if (print)
  		fprint(2, "%L\n", s, " ");
! 	/*
! 	   Allocate 3 extra spots (2 for the fake execve & 1 for defaulting to
! 	   sh) and hide these from exec().
! 	*/
! 	argv = av = (char **) nalloc((listnel(s) + 4) * sizeof *av) + 3;
! 	while (s != NULL) {
! 		*av++ = s->w;
  		s = s->n;
  	}
! 	*av = NULL;
! 	return argv;
  }
  
! /* figure out the name of a variable given an environment string. */
  
  extern char *get_name(char *s) {
+ 	char *eq = strchr(s, '=');
+ 	char *r, *result;
  	int c;
! 	
! 	if (eq == NULL)
  		return NULL;
! 	r = result = nalloc(eq - s + 1);
  	while (1)
  		switch (c = *s++) {
  		case '=':
  			*r++ = '\0';
! 			return result;
  #ifdef PROTECT_ENV
  		case '_':
  			if (*s == '_') {
***************
*** 233,287 ****
  		}
  }
  
! /* get the next word from a variable's value as represented in the environment. */
  
! static char *getenvw(char *s, bool saw_alpha) {
! 	SIZE_T i;
! 	char *r;
! 	for (i = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
! 		;
! 	if (i == 0) {
! 		if (s[i] == '\0' && !saw_alpha)
! 			return NULL;
! 		else
! 			return clear(enew(char), (SIZE_T) 1);
! 	}
! 	r = strncpy(ealloc(i + 1), s, i);
! 	r[i] = '\0';
! 	return r;
! }
  
- /* take an environment entry for a variable (elements ^A separated) and turn it into a List */
- 
  extern List *parse_var(char *name, char *extdef) {
! 	List *r, *top;
! 	char *f;
! 	bool saw_alpha;
! 	top = r = enew(List);
! 	extdef = strchr(extdef, '=') + 1;
! 	if ((f = getenvw(extdef, FALSE)) == NULL) {
! 		r->w = "";
! 		r->m = NULL;
! 		r->n = NULL;
! 	} else {
! 		while (1) {
! 			r->w = f;
! 			r->m = NULL;
! 			extdef += strlen(f);
! 			if (*extdef == FSCHAR) {
! 				extdef++;
! 				saw_alpha = TRUE;
! 			} else {
! 				saw_alpha = FALSE;
! 			}
! 			if ((f = getenvw(extdef, saw_alpha)) == NULL) {
! 				r->n = NULL;
! 				break;
! 			}
! 			r = r->n = enew(List);
! 		}
  	}
! 	return top;
  }
  
  /* get an environment entry for a function and have rc parse it. */
--- 212,256 ----
  		}
  }
  
! /*
!    Hacky routine to split a ^A-separated environment variable. Scans
!    backwards. Be VERY CAREFUL with the loop boundary conditions. e.g.,
!    notice what happens when there is no ^A in the extdef. (It does
!    the right thing, of course :-)
! */
  
! #define skipleft(p) do --p; while (*p != '\0' && *p != '\001');
  
  extern List *parse_var(char *name, char *extdef) {
! 	char *endp, *realend, *sepp;
! 	List *tailp, *new;
! 
! 	extdef = strchr(extdef, '=');
! 	*extdef++ = '\0'; /* null "initiate" the string for rtol scanning */
! 
! 	sepp = realend = strchr(extdef, '\0');
! 	tailp = NULL;
! 
! 	while (1) {
! 		endp = sepp;	/* set endp to end of current mebmer */
! 		skipleft(sepp);	/* advance sepp to the previous \1,  */
! 		*endp = '\0';   /* and null terminate the member.    */
! 
! 		new = enew(List);
! 		new->w = ecpy(sepp+1);
! 		new->m = NULL;
! 		new->n = tailp;
! 		tailp = new;
! 
! 		if (sepp < extdef)	/* break when sepp hits the null "initiator" */
! 			break;
! 		if (endp != realend)	/* else restore the \1 in between members */
! 			*endp = '\001';
  	}
! 	if (endp != realend)
! 		*endp = '\001';
! 	*--extdef = '='; /* restore extdef '=' */
! 	return tailp;
  }
  
  /* get an environment entry for a function and have rc parse it. */
*** /tmp/T0a19127	Sun Jan  9 14:45:39 1994
--- glob.c	Sun Dec 12 17:01:20 1993
***************
*** 94,104 ****
  	extern DIR *opendir(const char *);
  	extern struct dirent *readdir(DIR *);
  	/*extern int closedir(DIR *);*/
  
  	top = r = NULL;
  	/* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
! 	if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR || (dirp = opendir(d)) == NULL)
  		return NULL;
  	while ((dp = readdir(dirp)) != NULL)
  		if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
  			matched = TRUE;
--- 94,132 ----
  	extern DIR *opendir(const char *);
  	extern struct dirent *readdir(DIR *);
  	/*extern int closedir(DIR *);*/
+ 	int i;
  
+ 	/*
+  	   return a match if there are no metacharacters; allows globbing through
+ 	   directories with no read permission. make sure the file exists, though.
+ 	 */
+ 	matched = TRUE;
+ 	if (m != NULL)
+ 		for (i = 0; p[i] != '\0'; i++)
+ 			if (m[i]) {
+ 				matched = FALSE;
+ 				break;
+ 			}
+ 
+ 	if (matched) {
+ 		char *path = nprint("%s/%s", d, p);
+ 		if (stat(path, &s) < 0)
+ 			return NULL;
+ 		r = nnew(List);
+ 		r->w = ncpy(p);
+ 		r->m = NULL;
+ 		r->n = NULL;
+ 		return r;
+ 	}
+ 
  	top = r = NULL;
+ 	if ((dirp = opendir(d)) == NULL)
+ 		return NULL;
  	/* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
! 	if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR) {
! 		closedir(dirp);
  		return NULL;
+ 	}
  	while ((dp = readdir(dirp)) != NULL)
  		if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
  			matched = TRUE;
***************
*** 125,139 ****
  
  static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
  	List *q, *r, *top, foo;
! 	static List slash;
! 	static SIZE_T slashsize = 0;
! 	if (slashcount + 1 > slashsize) {
! 		slash.w = ealloc(slashcount + 1);
! 		slashsize = slashcount;
  	}
! 	slash.w[slashcount] = '\0';
  	while (slashcount > 0)
! 		slash.w[--slashcount] = '/';
  	for (top = r = NULL; s != NULL; s = s->n) {
  		q = dmatch(s->w, p, m);
  		if (q != NULL) {
--- 153,169 ----
  
  static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
  	List *q, *r, *top, foo;
! 	static struct {
! 		List l;
! 		SIZE_T size;
! 	} slash;
! 	if (slashcount+1 > slash.size) {
! 		slash.size = 2*(slashcount+1);
! 		slash.l.w = erealloc(slash.l.w, slash.size);
  	}
! 	slash.l.w[slashcount] = '\0';
  	while (slashcount > 0)
! 		slash.l.w[--slashcount] = '/';
  	for (top = r = NULL; s != NULL; s = s->n) {
  		q = dmatch(s->w, p, m);
  		if (q != NULL) {
***************
*** 141,147 ****
  			foo.m = NULL;
  			foo.n = NULL;
  			if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
! 				q = concat(&slash, q);		  /* dir/name with slash */
  			q = concat(&foo, q);
  			if (r == NULL)
  				top = r = q;
--- 171,177 ----
  			foo.m = NULL;
  			foo.n = NULL;
  			if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
! 				q = concat(&slash.l, q);	  /* dir/name with slash */
  			q = concat(&foo, q);
  			if (r == NULL)
  				top = r = q;
***************
*** 209,215 ****
  	}
  	do {
  		SIZE_T slashcount;
! 		SIGCHK;
  		for (slashcount = 0; *s == '/'; s++, m++)
  			slashcount++; /* skip slashes */
  		while (*s != '/' && *s != '\0')
--- 239,245 ----
  	}
  	do {
  		SIZE_T slashcount;
! 		sigchk();
  		for (slashcount = 0; *s == '/'; s++, m++)
  			slashcount++; /* skip slashes */
  		while (*s != '/' && *s != '\0')
*** /tmp/T0a19127	Sun Jan  9 14:45:40 1994
--- glom.c	Fri Dec 10 20:20:31 1993
***************
*** 3,8 ****
--- 3,9 ----
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <signal.h>
+ #include <errno.h>
  #include "rc.h"
  #if !defined(S_IFIFO) && !defined(DEVFD)
  #define NOCMDARG
***************
*** 68,78 ****
  		} else {
  			r->m = nalloc(z);
  			if (s1->m == NULL)
! 				clear(r->m, x);
  			else
  				memcpy(r->m, s1->m, x);
  			if (s2->m == NULL)
! 				clear(&r->m[x], y);
  			else
  				memcpy(&r->m[x], s2->m, y);
  			r->m[z] = 0;
--- 69,79 ----
  		} else {
  			r->m = nalloc(z);
  			if (s1->m == NULL)
! 				memzero(r->m, x);
  			else
  				memcpy(r->m, s1->m, x);
  			if (s2->m == NULL)
! 				memzero(&r->m[x], y);
  			else
  				memcpy(&r->m[x], s2->m, y);
  			r->m[z] = 0;
***************
*** 183,189 ****
  	char isifs[256];
  	int n, state; /* a simple FSA is used to read in data */
  
! 	clear(isifs, sizeof isifs);
  	for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n)
  		for (s = ifs->w; *s != '\0'; s++)
  			isifs[*(unsigned char *)s] = TRUE;
--- 184,190 ----
  	char isifs[256];
  	int n, state; /* a simple FSA is used to read in data */
  
! 	memzero(isifs, sizeof isifs);
  	for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n)
  		for (s = ifs->w; *s != '\0'; s++)
  			isifs[*(unsigned char *)s] = TRUE;
***************
*** 209,216 ****
  		if ((n = rc_read(fd, end, remain)) <= 0) {
  			if (n == 0)
  	/* break */		break;
! 			uerror("backquote read");
! 			rc_error(NULL);
  		}
  		remain -= n;
  		for (bufend = &end[n]; end < bufend; end++)
--- 210,221 ----
  		if ((n = rc_read(fd, end, remain)) <= 0) {
  			if (n == 0)
  	/* break */		break;
! 			else if (errno == EINTR)
! 				return NULL; /* interrupted, wait for subproc */
! 			else {
! 				uerror("backquote read");
! 				rc_error(NULL);
! 			}
  		}
  		remain -= n;
  		for (bufend = &end[n]; end < bufend; end++)
***************
*** 218,223 ****
--- 223,229 ----
  				if (!isifs[*(unsigned char *)end]) {
  					state = 1;
  					r->w = end;
+ 					r->m = NULL;
  				}
  			} else {
  				if (isifs[*(unsigned char *)end]) {
***************
*** 252,258 ****
  		rc_error(NULL);
  	}
  	if ((pid = rc_fork()) == 0) {
- 		setsigdefaults(FALSE);
  		mvfd(p[1], 1);
  		close(p[0]);
  		redirq = NULL;
--- 258,263 ----
***************
*** 264,270 ****
  	close(p[0]);
  	rc_wait4(pid, &sp, TRUE);
  	statprint(-1, sp);
! 	SIGCHK;
  	return bq;
  }
  
--- 269,276 ----
  	close(p[0]);
  	rc_wait4(pid, &sp, TRUE);
  	statprint(-1, sp);
! 	varassign("bqstatus", word(strstatus(sp), NULL), FALSE);
! 	sigchk();
  	return bq;
  }
  
*** /tmp/T0a19127	Sun Jan  9 14:45:40 1994
--- hash.c	Wed Dec  8 21:52:28 1993
***************
*** 279,293 ****
  	return env;
  }
  
! extern void whatare_all_vars() {
  	int i;
  	List *s;
! 	for (i = 0; i < vsize; i++)
! 		if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
! 			prettyprint_var(1, vp[i].name, s);
! 	for (i = 0; i < fsize; i++)
! 		if (fp[i].name != NULL && fp[i].name != dead)
! 			prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
  }
  
  /* fake getenv() for readline() follows: */
--- 279,295 ----
  	return env;
  }
  
! extern void whatare_all_vars(bool showfn, bool showvar) {
  	int i;
  	List *s;
! 	if (showvar)
! 		for (i = 0; i < vsize; i++)
! 			if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
! 				prettyprint_var(1, vp[i].name, s);
! 	if (showfn)
! 		for (i = 0; i < fsize; i++)
! 			if (fp[i].name != NULL && fp[i].name != dead)
! 				prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
  }
  
  /* fake getenv() for readline() follows: */
*** /tmp/T0a19127	Sun Jan  9 14:45:41 1994
--- input.c	Sun Jan  9 13:51:20 1994
***************
*** 40,47 ****
  static SIZE_T istacksize, chars_out, chars_in;
  static bool eofread = FALSE, save_lineno = TRUE;
  static Input *istack, *itop;
- static char *histstr;
- static int histfd;
  
  static int (*realgchar)(void);
  static void (*realugchar)(int);
--- 40,45 ----
***************
*** 49,59 ****
  int last;
  
  extern int gchar() {
  	if (eofread) {
  		eofread = FALSE;
  		return last = EOF;
  	}
! 	return (*realgchar)();
  }
  
  extern void ugchar(int c) {
--- 47,63 ----
  int last;
  
  extern int gchar() {
+ 	int c;
+ 
  	if (eofread) {
  		eofread = FALSE;
  		return last = EOF;
  	}
! 
! 	while ((c = (*realgchar)()) == '\0')
! 		pr_error("warning: null character ignored");
! 
! 	return c;
  }
  
  extern void ugchar(int c) {
***************
*** 99,105 ****
  	slow = FALSE;
  	if (r == NULL)
  		errno = EINTR;
! 	SIGCHK;
  	return r;
  }
  #else
--- 103,109 ----
  	slow = FALSE;
  	if (r == NULL)
  		errno = EINTR;
! 	sigchk();
  	return r;
  }
  #else
***************
*** 128,141 ****
  					inbuf = ealloc(chars_in + 3);
  					strcpy(inbuf+2, rlinebuf);
  					strcat(inbuf+2, "\n");
  				}
  			} else
  #endif
  				{
  				long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE);
  				if (r < 0) {
- 					if (errno == EINTR)
- 						continue; /* Suppose it was interrupted by a signal */
  					uerror("read");
  					rc_exit(1);
  				}
--- 132,145 ----
  					inbuf = ealloc(chars_in + 3);
  					strcpy(inbuf+2, rlinebuf);
  					strcat(inbuf+2, "\n");
+ 					efree(rlinebuf);
  				}
  			} else
  #endif
  				{
  				long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE);
+ 				sigchk();
  				if (r < 0) {
  					uerror("read");
  					rc_exit(1);
  				}
***************
*** 214,220 ****
  	efree(inbuf);
  	--istack;
  	realgchar = (istack->t == iString ? stringgchar : fdgchar);
! 	if (istack->fd == -1) { /* top of input stack */
  		realgchar = dead;
  		realugchar = ugdead;
  	}
--- 218,224 ----
  	efree(inbuf);
  	--istack;
  	realgchar = (istack->t == iString ? stringgchar : fdgchar);
! 	if (istack->t == iFd && istack->fd == -1) { /* top of input stack */
  		realgchar = dead;
  		realugchar = ugdead;
  	}
***************
*** 258,264 ****
  		Edata block;
  		block.b = newblock();
  		except(eArena, block, &e2);
! 		SIGCHK;
  		if (dashell) {
  			char *fname[3];
  			fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w;
--- 262,268 ----
  		Edata block;
  		block.b = newblock();
  		except(eArena, block, &e2);
! 		sigchk();
  		if (dashell) {
  			char *fname[3];
  			fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w;
***************
*** 314,360 ****
  	return fun;
  }
  
! /* write last command out to a file. Check to see if $history has changed, also */
  
  static void history() {
! 	List *histlist;
  	SIZE_T a;
! 	if (!interactive)
  		return;
! 	if ((histlist = varlookup("history")) == NULL) {
! 		if (histstr != NULL) {
! 			efree(histstr);
! 			close(histfd);
! 			histstr = NULL;
  		}
- 		return;
  	}
- 	if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */
- 		if (histstr != NULL) {
- 			efree(histstr);
- 			close(histfd);
- 		}
- 		histstr = ecpy(histlist->w);
- 		histfd = rc_open(histstr, rAppend);
- 		if (histfd < 0) {
- 			uerror(histstr);
- 			efree(histstr);
- 			histstr = NULL;
- 			varrm("history", FALSE);
- 		}
- 	}
- 	/*
- 	   Small unix hack: since read() reads only up to a newline
- 	   from a terminal, then presumably this write() will write at
- 	   most only one input line at a time.
- 	*/
- 	for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */
- 		if (inbuf[a] == '#' || inbuf[a] == '\n')
- 			return;
- 		if (inbuf[a] != ' ' && inbuf[a] != '\t')
- 			break;
- 	}
- 	writeall(histfd, inbuf + 2, chars_in);
  }
  
  /* close file descriptors after a fork() */
--- 318,353 ----
  	return fun;
  }
  
! /* write last command out to a file if interactive && $history is set */
  
  static void history() {
! 	List *hist;
  	SIZE_T a;
! 
! 	if (!interactive || (hist = varlookup("history")) == NULL)
  		return;
! 
! 	for (a = 0; a < chars_in; a++) {
! 		char c = inbuf[a+2];
! 
! 		/* skip empty lines and comments */
! 		if (c == '#' || c == '\n')
! 			break;
! 
! 		/* line matches [ \t]*[^#\n] so it's ok to write out */
! 		if (c != ' ' && c != '\t') {
! 			char *name = hist->w;
! 			int fd = rc_open(name, rAppend);
! 			if (fd < 0) {
! 				uerror(name);
! 				varrm(name, TRUE);
! 			} else {
! 				writeall(fd, inbuf + 2, chars_in);
! 				close(fd);
! 			}
! 			break;
  		}
  	}
  }
  
  /* close file descriptors after a fork() */
***************
*** 361,370 ****
  
  extern void closefds() {
  	Input *i;
- 	if (histstr != NULL) {			/* Close an open history file */
- 		close(histfd);
- 		histstr = NULL;			/* But prevent re-closing of the same file-descriptor */
- 	}
  	for (i = istack; i != itop; --i)	/* close open scripts */
  		if (i->t == iFd && i->fd > 2) {
  			close(i->fd);
--- 354,359 ----
*** /tmp/T0a19127	Sun Jan  9 14:45:42 1994
--- lex.c	Wed Dec  8 21:52:29 1993
***************
*** 10,16 ****
  	The lexical analyzer is fairly straightforward. The only really
  	unclean part concerns backslash continuation and "double
  	backslashes". A backslash followed by a newline is treated as a
! 	space, otherwise backslash is not a special characeter (i.e.,
  	it can be part of a word).  This introduces a host of unwanted
  	special cases. In our case, \ cannot be a word character, since
  	we wish to read in all word characters in a tight loop.
--- 10,16 ----
  	The lexical analyzer is fairly straightforward. The only really
  	unclean part concerns backslash continuation and "double
  	backslashes". A backslash followed by a newline is treated as a
! 	space, otherwise backslash is not a special character (i.e.,
  	it can be part of a word).  This introduces a host of unwanted
  	special cases. In our case, \ cannot be a word character, since
  	we wish to read in all word characters in a tight loop.
***************
*** 155,163 ****
  			w = KW;
  	}
  	switch (c) {
- 	case '\0':
- 		pr_error("warning: null character ignored");
- 		goto top;
  	case '!':
  		return BANG;
  	case '@':
--- 155,160 ----
*** /tmp/T0a19127	Sun Jan  9 14:45:43 1994
--- main.c	Wed Dec  8 21:52:28 1993
***************
*** 3,9 ****
  #include "rc.h"
  
  bool dashdee, dashee, dashvee, dashex, dashell, dasheye,
! 	dashen, dashpee, interactive;
  int rc_pid;
  
  static bool dashoh;
--- 3,9 ----
  #include "rc.h"
  
  bool dashdee, dashee, dashvee, dashex, dashell, dasheye,
! 	dashen, dashpee, dashess, interactive;
  int rc_pid;
  
  static bool dashoh;
***************
*** 19,25 ****
  	dollarzero = argv[0];
  	rc_pid = getpid();
  	dashell = (*argv[0] == '-'); /* Unix tradition */
! 	while ((c = rc_getopt(argc, argv, "nolpeivdxc:")) != -1)
  		switch (c) {
  		case 'l':
  			dashell = TRUE;
--- 19,25 ----
  	dollarzero = argv[0];
  	rc_pid = getpid();
  	dashell = (*argv[0] == '-'); /* Unix tradition */
! 	while ((c = rc_getopt(argc, argv, "nolpeivdxsc:")) != -1)
  		switch (c) {
  		case 'l':
  			dashell = TRUE;
***************
*** 39,44 ****
--- 39,47 ----
  		case 'd':
  			dashdee = TRUE;
  			break;
+ 		case 's':
+ 			dashess = dasheye = interactive = TRUE;
+ 			break;
  		case 'c':
  			dashsee[0] = rc_optarg;
  			goto quitopts;
***************
*** 56,63 ****
  		}
  quitopts:
  	argv += rc_optind;
! 	/* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */
! 	if (!dasheye && dashsee[0] == NULL && *argv == NULL)
  		interactive = isatty(0);
  	if (!dashoh) {
  		checkfd(0, rFrom);
--- 59,66 ----
  		}
  quitopts:
  	argv += rc_optind;
! 	/* use isatty() iff -i is not set, and iff the input is not from a script or -c or -s flags */
! 	if (!dasheye && !dashess && dashsee[0] == NULL && *argv == NULL)
  		interactive = isatty(0);
  	if (!dashoh) {
  		checkfd(0, rFrom);
***************
*** 78,87 ****
  	null[0] = NULL;
  	starassign(dollarzero, null, FALSE); /* assign $0 to $* */
  	inithandler();
! 	if (dashsee[0] != NULL) {	/* input from the -c flag? */
  		if (*argv != NULL)
  			starassign(dollarzero, argv, FALSE);
! 		pushstring(dashsee, TRUE);
  	} else if (*argv != NULL) {	/* else from a file? */
  		b_dot(--argv);
  		rc_exit(getstatus());
--- 81,93 ----
  	null[0] = NULL;
  	starassign(dollarzero, null, FALSE); /* assign $0 to $* */
  	inithandler();
! 	if (dashsee[0] != NULL || dashess) {	/* input from  -c or -s? */
  		if (*argv != NULL)
  			starassign(dollarzero, argv, FALSE);
! 		if (dashess)
! 			pushfd(0);
! 		else
! 			pushstring(dashsee, TRUE);
  	} else if (*argv != NULL) {	/* else from a file? */
  		b_dot(--argv);
  		rc_exit(getstatus());
*** /tmp/T0a19127	Sun Jan  9 14:45:44 1994
--- nalloc.c	Wed Dec  8 21:52:28 1993
***************
*** 122,127 ****
--- 122,129 ----
  
  extern void *erealloc(void *p, SIZE_T n) {
  	extern void *realloc(void *, SIZE_T);
+ 	if (p == NULL)		/* convenience feature */
+ 		return ealloc(n);
  	if ((p = realloc(p, n)) == NULL) {
  		uerror("realloc");
  		rc_exit(1);
*** /tmp/T0a19127	Sun Jan  9 14:45:45 1994
--- print.c	Wed Dec  8 21:52:29 1993
***************
*** 270,278 ****
  
  extern int fmtprint(Format *format, const char *fmt,...) {
  	int n = -format->flushed;
! 	va_list saveargs = format->args;
  
! 	va_start(format->args, fmt);
  	n += printfmt(format, fmt);
  	va_end(format->args);
  	format->args = saveargs;
--- 270,280 ----
  
  extern int fmtprint(Format *format, const char *fmt,...) {
  	int n = -format->flushed;
! 	va_list ap, saveargs;
  
! 	va_start(ap, fmt);
! 	saveargs = format->args;
! 	format->args = ap;
  	n += printfmt(format, fmt);
  	va_end(format->args);
  	format->args = saveargs;
***************
*** 292,297 ****
--- 294,300 ----
  extern int fprint(int fd, const char *fmt,...) {
  	char buf[1024];
  	Format format;
+ 	va_list ap;
  
  	format.buf	= buf;
  	format.bufbegin	= buf;
***************
*** 300,306 ****
  	format.flushed	= 0;
  	format.u.n	= fd;
  
! 	va_start(format.args, fmt);
  	printfmt(&format, fmt);
  	va_end(format.args);
  
--- 303,310 ----
  	format.flushed	= 0;
  	format.u.n	= fd;
  
! 	va_start(ap, fmt);
! 	format.args = ap;
  	printfmt(&format, fmt);
  	va_end(format.args);
  
***************
*** 340,347 ****
  extern char *mprint(const char *fmt,...) {
  	Format format;
  	char *result;
  	format.u.n = 1;
! 	va_start(format.args, fmt);
  	result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
  	va_end(format.args);
  	return result;
--- 344,354 ----
  extern char *mprint(const char *fmt,...) {
  	Format format;
  	char *result;
+ 	va_list ap;
+ 
  	format.u.n = 1;
! 	va_start(ap, fmt);
! 	format.args = ap;
  	result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
  	va_end(format.args);
  	return result;
***************
*** 350,357 ****
  extern char *nprint(const char *fmt,...) {
  	Format format;
  	char *result;
  	format.u.n = 0;
! 	va_start(format.args, fmt);
  	result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
  	va_end(format.args);
  	return result;
--- 357,367 ----
  extern char *nprint(const char *fmt,...) {
  	Format format;
  	char *result;
+ 	va_list ap;
+ 
  	format.u.n = 0;
! 	va_start(ap, fmt);
! 	format.args = ap;
  	result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
  	va_end(format.args);
  	return result;
*** /tmp/T0a19127	Sun Jan  9 14:45:45 1994
--- proto.h	Wed Dec  8 21:52:27 1993
***************
*** 47,52 ****
--- 47,53 ----
  extern char *strcat(char *, const char *);
  extern char *strncat(char *, const char *, SIZE_T);
  extern void *memcpy(void *, const void *, SIZE_T);
+ extern void *memset(void *, int, SIZE_T);
  
  /* fake unistd.h */
  
*** /tmp/T0a19127	Sun Jan  9 14:45:45 1994
--- rc.1	Wed Dec  8 21:52:28 1993
***************
*** 490,495 ****
--- 490,496 ----
  .Ds
  .Cr $variable^follow
  .De
+ .PP
  To include a literal
  .Cr $
  in a here document when an unquoted end-of-file marker is being used,
***************
*** 683,690 ****
  .Cr "command || command"
  .De
  .PP
! executes the first command executing the second command if and only if
! the second command exits with a nonzero exit status (``false'' in Unix).
  .Ds
  .Cr "! command"
  .De
--- 684,691 ----
  .Cr "command || command"
  .De
  .PP
! executes the first command and then executes the second command if and only if
! the first command exits with a nonzero exit status (``false'' in Unix).
  .Ds
  .Cr "! command"
  .De
***************
*** 1625,1631 ****
  .I pid
  is specified,
  .I rc
! waits for any child process to exit.
  .TP
  \fBwhatis \fR[\fB\-s\fR] [\fB\-\|\-\fR] [\fIname ...\fR]
  Prints a definition of the named objects.
--- 1626,1632 ----
  .I pid
  is specified,
  .I rc
! waits for all child processes to exit.
  .TP
  \fBwhatis \fR[\fB\-s\fR] [\fB\-\|\-\fR] [\fIname ...\fR]
  Prints a definition of the named objects.
*** /tmp/T0a19127	Sun Jan  9 14:45:46 1994
--- rc.h	Fri Dec 10 20:26:11 1993
***************
*** 150,155 ****
--- 150,156 ----
  #define a2u(x) n2u(x, 10)
  #define o2u(x) n2u(x, 8)
  #define arraysize(a) ((int)(sizeof(a)/sizeof(*a)))
+ #define memzero(s, n) memset(s, 0, n)
  #define enew(x) ((x *) ealloc(sizeof(x)))
  #define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1), x)
  #define lookup_fn(s) ((Function *) lookup(s, fp))
***************
*** 192,199 ****
  extern void doredirs(void);
  
  /* footobar.c */
- extern char *fun2str(char *, Node *);
- extern char *list2str(char *, List *);
  extern char **list2array(List *, bool);
  extern char *get_name(char *);
  extern List *parse_var(char *, char *);
--- 193,198 ----
***************
*** 245,251 ****
  extern void inithandler(void);
  extern void varassign(char *, List *, bool);
  extern void varrm(char *, bool);
! extern void whatare_all_vars(void);
  extern void whatare_all_signals(void);
  extern void prettyprint_var(int, char *, List *);
  extern void prettyprint_fn(int, char *, Node *);
--- 244,250 ----
  extern void inithandler(void);
  extern void varassign(char *, List *, bool);
  extern void varrm(char *, bool);
! extern void whatare_all_vars(bool, bool);
  extern void whatare_all_signals(void);
  extern void prettyprint_var(int, char *, List *);
  extern void prettyprint_fn(int, char *, Node *);
***************
*** 338,344 ****
  extern void (*rc_signal(int, void (*)(int)))(int);
  extern void (*sighandlers[])(int);
  extern volatile SIG_ATOMIC_T slow, interrupt_happened;
- #define SIGCHK sigchk()
  
  /* status.c */
  extern int istrue(void);
--- 337,342 ----
***************
*** 349,354 ****
--- 347,353 ----
  extern void setpipestatus(int [], int);
  extern void statprint(int, int);
  extern void ssetstatus(char **);
+ extern char *strstatus(int s);
  
  /* tree.c */
  extern Node *mk(int /*nodetype*/,...);
***************
*** 362,368 ****
  extern int mvfd(int, int);
  extern int starstrcmp(const void *, const void *);
  extern void pr_error(char *);
- extern char *clear(char *, SIZE_T);
  extern void panic(char *);
  extern void uerror(char *);
  extern void writeall(int, char *, SIZE_T);
--- 361,366 ----
*** /tmp/T0a19127	Sun Jan  9 14:45:47 1994
--- signal.c	Wed Dec  8 21:52:29 1993
***************
*** 13,20 ****
  static volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS];
  
  extern void catcher(int s) {
- 	if (forked)
- 		exit(1); /* exit unconditionally on a signal in a child process */
  	if (caught[s] == 0) {
  		sigcount++;
  		caught[s] = 1;
--- 13,18 ----
***************
*** 52,58 ****
  
  extern void (*rc_signal(int s, void (*h)(int)))(int) {
  	void (*old)(int);
! 	SIGCHK;
  	old = sighandlers[s];
  	if (h == SIG_DFL || h == SIG_IGN) {
  		signal(s, h);
--- 50,56 ----
  
  extern void (*rc_signal(int s, void (*h)(int)))(int) {
  	void (*old)(int);
! 	sigchk();
  	old = sighandlers[s];
  	if (h == SIG_DFL || h == SIG_IGN) {
  		signal(s, h);
*** /tmp/T0a19127	Sun Jan  9 14:45:47 1994
--- status.c	Wed Dec  8 21:52:28 1993
***************
*** 80,104 ****
  /* prepare a list to be passed back. Used whenever $status is dereferenced */
  
  extern List *sgetstatus() {
! 	List *r;
  	int i;
! 	for (r = NULL, i = 0; i < pipelength; i++) {
  		List *q = nnew(List);
! 		int s = statuses[i];
! 		int t;
  		q->n = r;
  		r = q;
- 		if ((t = s & 0x7f) != 0) {
- 			const char *core = (s & 0x80) ? "+core" : "";
- 			if (t < NUMOFSIGNALS && *signals[t].name != '\0')
- 				r->w = nprint("%s%s", signals[t].name, core);
- 			else
- 				r->w = nprint("-%d%s", t, core); /* unknown signals are negated */
- 		} else
- 			r->w = nprint("%d", (s >> 8) & 0xff);
- 		r->m = NULL;
  	}
  	return r;
  }
  
  extern void ssetstatus(char **av) {
--- 80,112 ----
  /* prepare a list to be passed back. Used whenever $status is dereferenced */
  
  extern List *sgetstatus() {
! 	List *r = NULL;
  	int i;
! 
! 	for (i = 0; i < pipelength; i++) {
  		List *q = nnew(List);
! 		q->w = strstatus(statuses[i]);
! 		q->m = NULL;
  		q->n = r;
  		r = q;
  	}
+ 
  	return r;
+ }
+ 
+ /* return status as a string (used above and for bqstatus) */
+ 
+ extern char *strstatus(int s) {
+ 	int t = s & 0x7f;
+ 
+ 	if (t != 0) {
+ 		const char *core = (s & 0x80) ? "+core" : "";
+ 		if (t < NUMOFSIGNALS && *signals[t].name != '\0')
+ 			return nprint("%s%s", signals[t].name, core);
+ 		else
+ 			return nprint("-%d%s", t, core); /* unknown signals are negated */
+ 	} else
+ 		return nprint("%d", (s >> 8) & 0xff);
  }
  
  extern void ssetstatus(char **av) {
*** /tmp/T0a19127	Sun Jan  9 14:45:48 1994
--- utils.c	Wed Dec  8 23:56:04 1993
***************
*** 82,88 ****
  		slow = FALSE;
  	}
  	slow = FALSE;
! 	SIGCHK;
  }
  
  extern int rc_read(int fd, char *buf, SIZE_T n) {
--- 82,88 ----
  		slow = FALSE;
  	}
  	slow = FALSE;
! 	sigchk();
  }
  
  extern int rc_read(int fd, char *buf, SIZE_T n) {
***************
*** 101,116 ****
  		errno = EINTR;
  		r = -1;
  	}
- 	SIGCHK;
  	return r;
- }
- 
- /* clear out z bytes from character string s */
- 
- extern char *clear(char *s, SIZE_T z) {
- 	while (z != 0)
- 		s[--z] = 0;
- 	return s;
  }
  
  /* duplicate a fd and close the old one only if necessary */
--- 101,107 ----
*** /tmp/T0a19127	Sun Jan  9 14:45:49 1994
--- var.c	Wed Dec  8 21:52:27 1993
***************
*** 104,110 ****
  		return look->extdef;
  	if (look->def == NULL)
  		return NULL;
! 	return look->extdef = list2str(name, look->def);
  }
  
  /* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
--- 104,110 ----
  		return look->extdef;
  	if (look->def == NULL)
  		return NULL;
! 	return look->extdef = mprint("%F=%-L", name, look->def, "\001");
  }
  
  /* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
***************
*** 166,181 ****
  		return;
  	}
  	v = def->w;
! 	r = val = enew(List);
  	while ((w = strchr(v, ':')) != NULL) {
  		*w = '\0';
! 		r->w = ecpy(v);
  		*w = ':';
  		v = w + 1;
! 		r->n = enew(List);
! 		r = r->n;
  	}
! 	r->w = ecpy(v);
  	r->n = NULL;
  	varassign(name, val, stack);
  }
--- 166,180 ----
  		return;
  	}
  	v = def->w;
! 	r = val = nnew(List);
  	while ((w = strchr(v, ':')) != NULL) {
  		*w = '\0';
! 		r->w = ncpy(v);
  		*w = ':';
  		v = w + 1;
! 		r = r->n = nnew(List);
  	}
! 	r->w = ncpy(v);
  	r->n = NULL;
  	varassign(name, val, stack);
  }
*** /tmp/T0a19127	Sun Jan  9 14:45:49 1994
--- version.c	Wed Dec  8 23:02:38 1993
***************
*** 1 ****
! const char id[] = "@(#)rc version 1.4, 5/26/92.";
--- 1 ----
! const char id[] = "@(#)rc version 1.5betadev-1, 1/9/94.";
*** /tmp/T0a19127	Sun Jan  9 14:45:49 1994
--- wait.c	Wed Dec  8 21:52:29 1993
***************
*** 16,22 ****
  } *plist = NULL;
  
  extern int rc_fork() {
! 	Pid *new = enew(Pid);
  	int pid = fork();
  	switch (pid) {
  	case -1:
--- 16,22 ----
  } *plist = NULL;
  
  extern int rc_fork() {
! 	Pid *new;
  	int pid = fork();
  	switch (pid) {
  	case -1:
***************
*** 25,33 ****
  		/* NOTREACHED */
  	case 0:
  		forked = TRUE;
! 		SIGCHK;
  		return 0;
  	default:
  		new->pid = pid;
  		new->alive = TRUE;
  		new->n = plist;
--- 25,34 ----
  		/* NOTREACHED */
  	case 0:
  		forked = TRUE;
! 		sigchk();
  		return 0;
  	default:
+ 		new = enew(Pid);
  		new->pid = pid;
  		new->alive = TRUE;
  		new->n = plist;
***************
*** 98,104 ****
  			setstatus(pid, stat);
  		else
  			set(FALSE);
! 		SIGCHK;
  	}
  }
  
--- 99,105 ----
  			setstatus(pid, stat);
  		else
  			set(FALSE);
! 		sigchk();
  	}
  }
  
*** /tmp/T0a19127	Sun Jan  9 14:45:49 1994
--- walk.c	Wed Dec  8 21:52:29 1993
***************
*** 11,16 ****
--- 11,17 ----
  */
  bool cond = FALSE;
  
+ static bool haspreredir(Node *);
  static bool isallpre(Node *);
  static bool dofork(bool);
  static void dopipe(Node *);
***************
*** 22,28 ****
  /* walk the parse-tree. "obvious". */
  
  extern bool walk(Node *n, bool parent) {
! top:	SIGCHK;
  	if (n == NULL) {
  		if (!parent)
  			exit(0);
--- 23,29 ----
  /* walk the parse-tree. "obvious". */
  
  extern bool walk(Node *n, bool parent) {
! top:	sigchk();
  	if (n == NULL) {
  		if (!parent)
  			exit(0);
***************
*** 147,153 ****
  	}
  	case nSubshell:
  		if (dofork(TRUE)) {
- 			setsigdefaults(FALSE);
  			walk(n->u[0].p, FALSE);
  			rc_exit(getstatus());
  		}
--- 148,153 ----
***************
*** 214,221 ****
  	case nPre: {
  		List *v;
  		if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) {
  			qredir(n->u[0].p);
! 			walk(n->u[1].p, parent);
  		} else if (n->u[0].p->type == nAssign) {
  			if (isallpre(n->u[1].p)) {
  				walk(n->u[0].p, TRUE);
--- 214,227 ----
  	case nPre: {
  		List *v;
  		if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) {
+ 			if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */
+ 				break;
  			qredir(n->u[0].p);
! 			if (!haspreredir(n->u[1].p))
! 				doredirs(); /* no more preredirs, empty queue */
! 			walk(n->u[1].p, FALSE);
! 			rc_exit(getstatus());
! 			/* NOTREACHED */
  		} else if (n->u[0].p->type == nAssign) {
  			if (isallpre(n->u[1].p)) {
  				walk(n->u[0].p, TRUE);
***************
*** 239,245 ****
  		if (n->u[1].p == NULL) {
  			WALK(n->u[0].p, parent);
  		} else if (dofork(parent)) {
- 			setsigdefaults(FALSE);
  			walk(n->u[1].p, TRUE); /* Do redirections */
  			redirq = NULL;   /* Reset redirection queue */
  			walk(n->u[0].p, FALSE); /* Do commands */
--- 245,250 ----
***************
*** 265,270 ****
--- 270,286 ----
  	return istrue();
  }
  
+ /* checks to see whether there are any pre-redirections left in the tree */
+ 
+ static bool haspreredir(Node *n) {
+ 	while (n != NULL && n->type == nPre) {
+ 		if (n->u[0].p->type == nDup || n->u[0].p->type == nRedir)
+ 			return TRUE;
+ 		n = n->u[1].p;
+ 	}
+ 	return FALSE;
+ }
+ 
  /* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
  
  static bool isallpre(Node *n) {
***************
*** 286,292 ****
  	redirq = NULL; /* clear out the pre-redirection queue in the parent */
  	rc_wait4(pid, &sp, TRUE);
  	setstatus(-1, sp);
! 	SIGCHK;
  	return FALSE;
  }
  
--- 302,308 ----
  	redirq = NULL; /* clear out the pre-redirection queue in the parent */
  	rc_wait4(pid, &sp, TRUE);
  	setstatus(-1, sp);
! 	sigchk();
  	return FALSE;
  }
  
***************
*** 304,310 ****
  			rc_error(NULL);
  		}
  		if ((pid = rc_fork()) == 0) {
- 			setsigdefaults(FALSE);
  			redirq = NULL; /* clear preredir queue */
  			mvfd(p[0], r->u[1].i);
  			if (fd_prev != 1)
--- 320,325 ----
***************
*** 321,327 ****
  		close(p[0]);
  	}
  	if ((pid = rc_fork()) == 0) {
- 		setsigdefaults(FALSE);
  		mvfd(fd_prev, fd_out);
  		walk(r, FALSE);
  		exit(getstatus());
--- 336,341 ----
***************
*** 340,344 ****
  		intr |= (sp == SIGINT);
  	}
  	setpipestatus(stats, i);
! 	SIGCHK;
  }
--- 354,358 ----
  		intr |= (sp == SIGINT);
  	}
  	setpipestatus(stats, i);
! 	sigchk();
  }


^ permalink raw reply	[flat|nested] 2+ messages in thread
* Re: rc patches halfway to 1.5
@ 1994-01-10 17:50 Tom Culliton x2278
  0 siblings, 0 replies; 2+ messages in thread
From: Tom Culliton x2278 @ 1994-01-10 17:50 UTC (permalink / raw)
  To: byron, rc

Just quickly looking these patches over it looks like there are a couple
of things that slipped by.  1) In main.c -s implies -i, memory says the
consensus was that this isn't right.  2) Some of the fixes for correct
readline handling are missing.

Tom


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~1994-01-10 18:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1994-01-10  7:19 rc patches halfway to 1.5 Byron Rakitzis
1994-01-10 17:50 Tom Culliton x2278

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).