[mod.sources] Bourne shell history + tilde + job control + more

sources-request@genrad.UUCP (06/09/85)

From: Arnold Robbins <gatech!arnold>

This and the following eight postings consist of files and context diffs
to add many long-desired features into the Bourne shell. The details of
the new features are listed below in README.gt.sh.  This is a list of
what each article contains

Part 1	-- README.gt.sh, new .c files needed for the shell, miscellany

Part 2	-- Context diffs of C code for 4.2 BSD /bin/sh
Part 3	-- Context diffs of C code for 4.2 BSD /bin/sh
Part 4	-- Context diffs of sh.1 for 4.2 BSD /bin/sh

Part 5	-- Context diffs of C code for System V Release 2 /bin/sh
Part 6	-- Context diffs of C code for System V Release 2 /bin/sh
Part 7	-- Context diffs of sh.1 for System V Release 2 /bin/sh

Part 8	-- Context diffs of C code for BRL Unix /usr/5bin/sh
Part 9	-- Context diffs of sh.1 for BRL Unix /usr/5bin/sh

I am sorry that there are so many articles; I had to do it this way to
insure that each one would be less that 64K in size.

Arnold Robbins
arnold@gatech.{CSNET, UUCP}
------------------ tear along perforations ------------
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README.gt.sh
#	Bugs
#	signal.c
#	ulimit.c
#	jobs.c
#	homedir.c
#	history.c
#	sample.shrc
#	aliases.sh
# This archive created: Fri Jun  7 13:49:23 1985
# By:	Arnold Robbins (Pr1mebusters!)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README.gt.sh'" '(7022 characters)'
if test -f 'README.gt.sh'
then
	echo shar: over-writing existing file "'README.gt.sh'"
fi
cat << \SHAR_EOF > 'README.gt.sh'
README.gt.sh --- README file for Georgia Tech mods to the shell

This and the following eight postings should be all you need to add the
following features to the Bourne shell:

1.  BSD style job control on Berkeley Systems. Code to outwit symbolic
    links for shells which have 'pwd' built in.  Also code to print a
    resource usage summary after every command on BSD systems.  These are
    courtesy of the folks at BRL, who gave me permission to post their
    code.

2.  The ability to catch Control-D's, and force you to use "exit", also
    courtesy of BRL.  This will work whether or not you are on a BSD system.

3.  The <> I/O redirecter is now documented, and also works (courtesy of
    ihnp4!trwrb!lcc!brian's recent posting in net.unix-wizards).

4.  The shell parameter $+ gives you the parent process id of the shell.
    It will track the value of the getppid() system call.

5.  The shell will read in $HOME/.shrc on startup, if that file exists.
    This file is read *after* /etc/profile and $HOME/.profile (unlike the
    csh, which readc ~/.cshrc before ~/.login).

6.  The ~ and ~person notation is understood, both for command line arguments,
    and in the PATH and CDPATH shell variables.
 
7.  Special sequences in PS1 (the shell's prompt string) will print useful
    info at the prompt.  Currently, you can get or all or some or none of:
	the time of day
	your current directory (if the shell has pwd is built in)
	your machine's hostname
	your login name
	the current 'event' number for the ...

8.  History mechanism.  The history mechanism is powerful, yet easy to use.
    Although different from the csh's, it is somewhat more general and
    orthogonal.  The shell will save history across login sessions,
    automatically restoring on login, and saving on exit or on the exec builtin.

On a Pyramid, the shell has some additional capabilities:

9.  The 'att', 'ucb' and 'universe' commands are built in.

10. The $UNIVERSE shell variable tracks the current universe.

11. An additional sequence for the prompt to print the current universe.

*****************

I am posting diffs for the versions of the Bourne shell listed below.
Here are the instructions for setting up the makefile for each shell,
depending on your target machine and OS.  For all versions, you will need
the files history.c and homedir.c; these have been added to the makefile,
but will only be posted once.

It will help if you have the 'patch' program.  It was just reposted around
the middle of May, 1985 (Version 1.3). If you don't have it, someone at your
site or someone you know probably does.

First, unshar this article.  You wil have the following files:

README.gt.sh		# this file
Bugs			# some known bugs in what I've added
signal.c		# courtesy of BRL
ulimit.c		# courtesy of BRL
jobs.c			# courtesy of BRL
homedir.c
history.c
sample.shrc
aliases.sh

Next, make a new directory, and copy the source for the version of the shell
that you are going to modify, into it.
Copy the *unformatted* man page for that shell into the directory also.
Move history.c and homedir.c into the directory.

Find which version of the shell you have, and follow the supplementary
instructions below.

1. The Berkeley /bin/sh as distributed with 4.2, for 4.2BSD.
	Add the files signal.c and jobs.c to the directory.
	Get parts 2, 3 and 4, and run patch on them.
	Run make.

	On a Pyramid, follow the previous paragraph but don't run make yet.
	First, make sure you are in the 'ucb' universe.
	Remove all references to signal.c and signal.o from the makefile.
	Now run make.

2. The System V Release 2 shell as distributed from ATT (for the vax).
	On System V systems, the job stuff is conditionally compiled in.
	Get parts 5, 6, and 7, and run patch on them.
	Remove the -DJOBS and all references to signal.c, ulimit.c,
	jobs.c, and their .o files, from the makefile (sh.mk).
	Run make (make -f sh.mk).
	The sh.1 file will need editing to remove any reference to the 'J'
	flag, the 'I' flag, and to all the job control features.

	On BSD systems, copy signal.c, ulimit.c, and jobs.c into the directory.
	Get parts 5, 6, and 7, and run patch on them.
	Run make. (make -f sh.mk)

	On a Pyramid, copy ulimit.c, and jobs.c into the directory.
	Run patch.  Remove signal.o and signal.c from the makefile,
	and the testing for u370 for xec.c. Be sure to be in the ucb
	universe, and then run make. (make -f sh.mk)

3. The System V Release 2 shell as modified at BRL, for BRL Unix.
	Get parts 8 and 9, and run patch on them.

	There are two ways to compile this version under BRL Unix.

	A. Use the standard BSD make and cc. In this case, all you will need
	   is history.c and homedir.c.  Run make.

	B. Use the System V emulation, /usr/5bin/make and /usr/5bin/cc.
	   In this case, make sure your PATH is set properly. Remove the
	   -DBSD from the makefile, and also any references to signal.c,
	   and ulimit.c, and their .o files.  Now run /usr/5bin/make.
	
	On a Pyramid, run patch.  Edit the makefile to exclude signal.c
	and signal.o.  Be sure to be in the ucb universe, and then run make.

**********

Aliases.sh is a bunch of useful shell functions --- only of value for one
or the other of the System V Release 2 Versions of the shell.

Sample.shrc is a sample .shrc file.  In particular, it gives you some
compatibility with the Korn shell.  It sets PPID=$+, and if the ENV
environment variable is set to a file name, it will source that file
(that is how the ksh does ~/.shrc).

If you want job control to be turned on automatically (on a BSD system),
add the line
	set -J
to /etc/profile (or /usr/5lib/profile, depending).  This will turn job
control on for login shells.

***************************************

I have tested the shells on the following systems:

		Vax (BRL Unix) |  Pyramid  | 3B2 (S5R2)  | 3B20A (S5R2)
BSD shell		x	     x
S5R2 shell		x	     x		x		x
BRL/S5R2 shell		x	     x		x

As should be clear from the above table, I have only had access to four
different kinds of machines.  If you are running on some other kind of
hardware, and/or another flavor of Unix (V7, Xenix, Perkin Elmer, whatever),
and you successfully add these mods to the shell, please let me know.  Also
send me any diff listings you may have had to generate.  I am particularly
interested to know if it will still fit on a PDP-11.

***************************************

Please don't send me any flames to the effect "You should use the C-shell".
Here is a case where I can have my cake and eat it too, and this should be
a big win for people who only have System V and don't have the ksh.

I hope that these modifications to the shell help to meet a need out there
in the real world.  If you find any bugs, please let me know.

Arnold Robbins
CSNET:	arnold@gatech	ARPA:	arnold%gatech.csnet@csnet-relay.arpa
UUCP:	{ akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold

School of Information and Computer Science
Georgia Institute of Technology
225 North Avenue, N.W.
Atlanta, Georgia  30332
(404) 894-3658
SHAR_EOF
echo shar: extracting "'Bugs'" '(2013 characters)'
if test -f 'Bugs'
then
	echo shar: over-writing existing file "'Bugs'"
fi
cat << \SHAR_EOF > 'Bugs'
Bugs -- known problems in the shell.

The "suspend" built-in command is *very* naive.  E.g. cranking up a
subshell from vi, and then suspending it, will leave you sort of in limbo.
A control-Z will then suspend the vi.  Then a 'fg' command foregrounds the
stopped sub-shell. Control-D'ing the subshell puts you back in vi.

If the shell is being run from a terminal, and you interrupt it in the
middle of doing a here document (cat << FOO ..., interrupt before the FOO),
then if history was turned on, you will be left with history turned off.
Use set +H to turn it back on.

I do not have access to a PDP-11, so there will probably be problems
trying to move this stuff to a small address space machine.  Let me know
what you encounter, and I will encorporate any diffs that people send back
to me.

A recent posting in net.micro.att indicated that the Unix PC's window
manager uses $HOME/.history to save things. This is also the default for
where this history mechanism keeps things -- change the value of HISTFILE in
your .profile to be something different, and export it, if you're on a Unix PC.

****************

There are probably bugs in the code I have added to the shell.
I think I have caught everything, but I can't guarantee.  If you discover
any problems, please let me know, so that I can track them down and fix
them.

I regard this as a "first iteration."  In other words, I will not be suprised
if there are bugs.  I am counting on the net to be friendly enough to let
me know about any that may be discovered.  I am also open to suggestions for
other fixes or additions to the shell.  As things come in to me, I will
incorporate what I can, and hopefully post a new set of revisions.

Meanwhile, enjoy!

Arnold Robbins
CSNET:	arnold@gatech	ARPA:	arnold%gatech.csnet@csnet-relay.arpa
UUCP:	{ akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold

School of Information and Computer Science
Georgia Institute of Technology
225 North Avenue, N.W.
Atlanta, Georgia  30332
(404) 894-3658
SHAR_EOF
echo shar: extracting "'signal.c'" '(3896 characters)'
if test -f 'signal.c'
then
	echo shar: over-writing existing file "'signal.c'"
fi
cat << \SHAR_EOF > 'signal.c'
/*
	signal -- old system call emulation for 4.2BSD (VAX version)
		(adapted from BRL UNIX System V emulation for 4.2BSD)

	last edit:	25-Aug-1984	D A Gwyn

	NOTE:  Although this module is VAX-specific, it should be
	possible to adapt it to other fairly clean implementations of
	4.2BSD.  The difficulty lies in avoiding the automatic restart
	of certain system calls when the signal handler returns.  I use
	here a trick first described by Donn Seeley of UCSD Chem. Dept.
*/

#include	<errno.h>
#include	<signal.h>
#include	<syscall.h>

extern int	sigvec();
extern int	sigsetmask();

extern		etext;
extern int	errno;

static int	(*handler[NSIG])() =	/* "current handler" memory */
	{
	BADSIG				/* initially, unknown state */
	};
static int	inited = 0;		/* for initializing above */

static int	catchsig();
static int	ret_eintr();

int	(*
signal( sig, func )			/* returns previous handler */
	)()
	register int	sig;		/* signal affected */
	register int	(*func)();	/* new handler */
	{
	register int	(*retval)();	/* previous handler value */
	struct sigvec	oldsv;		/* previous state */
	struct sigvec	newsv;		/* state being set */

	if ( func >= (int (*)())&etext )	/* "lint" hates this */
		{
		errno = EFAULT;
		return BADSIG;		/* error */
		}

	/* cancel pending signals */
	newsv.sv_handler = SIG_IGN;
	newsv.sv_mask = newsv.sv_onstack = 0;
	if ( sigvec( sig, &newsv, &oldsv ) != 0 )
		return BADSIG;		/* error */

	/* C language provides no good way to initialize handler[] */
	if ( !inited )			/* once only */
		{
		register int	i;

		for ( i = 1; i < NSIG; ++i )
			handler[i] = BADSIG;	/* initialize */

		++inited;
		}

	/* the first time for this sig, get state from the system */
	if ( (retval = handler[sig-1]) == BADSIG )
		retval = oldsv.sv_handler;

	handler[sig-1] = func;	/* keep track of state */

	if ( func == SIG_DFL )
		newsv.sv_handler = SIG_DFL;
	else if ( func != SIG_IGN )
		newsv.sv_handler = catchsig;	/* actual sig catcher */

	if ( func != SIG_IGN		/* sig already being ignored */
	  && sigvec( sig, &newsv, (struct sigvec *)0 ) != 0
	   )
		return BADSIG;		/* error */

	return retval;			/* previous handler */
	}


/* # bytes to skip at the beginning of C ret_eintr() function code: */
#define	OFFSET	2			/* for VAX .word reg_mask */

/* PC will be pointing at a syscall if it is to be restarted: */
typedef unsigned char	opcode;		/* one byte long */
#define	SYSCALL		((opcode)0xBC)	/* VAX CHMK instruction */
#define	IMMEDIATE	((opcode)0x8F)	/* VAX immediate addressing */


/*ARGSUSED*/
static int
catchsig( sig, code, scp )		/* signal interceptor */
	register int		sig;	/* signal number */
	int			code;	/* code for SIGILL, SIGFPE */
	register struct sigcontext	*scp;	/* -> interrupted context */
	{
	register int		(*uhandler)();	/* user handler */
	register opcode		*pc;	/* for snooping instructions */
	struct sigvec		newsv;	/* state being set */

	/* at this point, sig is blocked */

	uhandler = handler[sig - 1];

	/* most UNIXes usually want the state reset to SIG_DFL */
	if ( sig != SIGILL && sig != SIGTRAP )
		{
		handler[sig-1] = newsv.sv_handler = SIG_DFL;
		newsv.sv_mask = newsv.sv_onstack = 0;
		(void)sigvec( sig, &newsv, (struct sigvec *)0 );
		}

	(void)sigsetmask( scp->sc_mask );	/* restore old mask */

	/* at this point, sig is not blocked, usually have SIG_DFL;
	   a longjmp may safely be taken by the user signal handler */

	(void)(*uhandler)( sig );	/* user signal handler */

	/* must now avoid restarting certain system calls */
	pc = (opcode *)scp->sc_pc;
	if ( *pc++ == SYSCALL
	  && (*pc == SYS_read || *pc == SYS_write || *pc == SYS_ioctl
	   || *pc++ == IMMEDIATE
	   && (*pc == SYS_wait || *pc == SYS_readv || *pc == SYS_writev)
	     )
	   )
		scp->sc_pc = (int)ret_eintr + OFFSET;

	/* return here restores interrupted context */
	}


static int
ret_eintr()				/* substitute for system call */
{
	errno = EINTR;
	return -1;
}
SHAR_EOF
echo shar: extracting "'ulimit.c'" '(855 characters)'
if test -f 'ulimit.c'
then
	echo shar: over-writing existing file "'ulimit.c'"
fi
cat << \SHAR_EOF > 'ulimit.c'
/*
	ulimit -- system call emulation for Bourne shell on 4.2BSD

	last edit:	22-Aug-1983	D A Gwyn
*/

#include	<errno.h>

extern int	getrlimit(), setrlimit();
extern int	errno;

long
ulimit( cmd, newlimit )
	int	cmd;			/* subcommand */
	long	newlimit;		/* desired new limit */
	{
	struct	{
		long	rlim_cur;
		long	rlim_max;
		}	limit;		/* data being gotten/set */

	switch ( cmd )
		{
	case 1: 			/* get file size limit */
		if ( getrlimit( 1, &limit ) != 0 )
			return -1L;	/* errno is already set */
		return limit.rlim_max / 512L;

	case 2: 			/* set file size limit */
		limit.rlim_cur = limit.rlim_max = newlimit * 512L;
		return setrlimit( 1, &limit );

	case 3: 			/* get maximum break value */
		if ( getrlimit( 2, &limit ) != 0 )
			return -1L;	/* errno is already set */
		return limit.rlim_max;

	default:
		errno = EINVAL;
		return -1L;
		}
	}
SHAR_EOF
echo shar: extracting "'jobs.c'" '(11717 characters)'
if test -f 'jobs.c'
then
	echo shar: over-writing existing file "'jobs.c'"
fi
cat << \SHAR_EOF > 'jobs.c'
/*
 *  JOBS.C -- job control for Bourne shell
 *
 *  created by Ron Natalie, BRL
 *  slight changes by Doug Gwyn
 *  some more slight changes by Arnold Robbins (mainly for the BSD /bin/sh)
 */

#include "defs.h"
#include "sym.h"

#ifndef TAB	/* very original, early /bin/sh */
#include <signal.h>
#define comptr(x)	((COMPTR) x)
#define lstptr(x)	((LSTPTR) x)
#define forkptr(x)	((FORKPTR) x)
#define parptr(x)	((PARPTR) x)
#define forptr(x)	((FORPTR) x)
#define whptr(x)	((WHPTR) x)
#define ifptr(x)	((IFPTR) x)
#define swptr(x)	((SWPTR) x)
#endif

#if BSD || (JOBS && ! BRL)	/* native /bin/sh */
#include <sys/ioctl.h>
#else	/* /usr/5bin/sh */
#include	<sys/_ioctl.h>
#define	ioctl	_ioctl
#define	killpg	_killpg
#define	setpgrp	_setpgrp
#define	TIOCSETD	_IOW( 't', 1, int )
#define	TIOCSPGRP	_IOW( 't', 118, int )
#define	NTTYDISC	2
#endif

#define	NJCH	30
#define	JCOMSIZE 50
static struct	j_child  {
	int	j_pgid;
	int	j_status;
	int	j_info;
	char	j_com[JCOMSIZE];
	int	j_jobnum;
} j_children[NJCH];

static int	j_number = 1;
static int	j_current = 0;

#define	JEMPTY	0
#define	JALIVE	1
#define	JSTOP	2
#define	JBG	3

BOOL		j_top_level = TRUE;
int		j_default_pg = 0;
int		j_original_pg = 0;
static int	j_last_pgrp = 0;
static int	j_do(), j_getnumber(), j_stuff();
static void	j_backoff(), j_print_ent(), j_really_reset_pg(), j_setcommand();
	
j_child_post(p, bg, pin, t)
	int		p;
	int		bg;
	register int	pin;
	struct trenod	***t;
{
	register struct j_child *j = j_children;

	if((flags & jobflg) == 0)
		return;
	if(!j_top_level)
		return;

	if(!pin)  {
		setpgrp(p, p);
		j_last_pgrp = p;
		if(!bg)  {
			ioctl(1, TIOCSPGRP, &p);
			setpgrp(0, p);
		}
	}
	else
		setpgrp(p, j_last_pgrp);

	for(j=j_children; j < &j_children[NJCH]; j++)  {
		if(pin && j->j_pgid == j_last_pgrp)  {
			j_setcommand(j, t);
			return;
		}

		if(!pin &&j->j_status == JEMPTY)  {
			j->j_com[0] = 0;
			j->j_status = bg ? JBG : JALIVE;
			j->j_pgid = p;
			j_setcommand(j, t);
			if(bg)  {
				post(p);
				j->j_jobnum = j_getnumber();
				j_print_ent(j);
			}
			else
				j->j_jobnum = 0;
			return;
		}
	}
	prn(p);
	prs(cjpostr);			/* DAG -- made strings sharable */
}

j_child_clear(p)
	register int	p;
{
	register struct j_child *j = j_children;

	if(p == 0 || p == -1)
		return;

	for(; j < &j_children[NJCH]; j++)
		if(j->j_status == JALIVE && j->j_pgid == p)  {
			j->j_status = JEMPTY;
			if(j->j_jobnum && j->j_jobnum == j_current)
				j_backoff();
			break;
		}
}

j_child_stop(p, sig)
	register int	p;
	int		sig;
{
	register struct j_child *j = j_children; 

	for(; j < &j_children[NJCH]; j++)
		if((j->j_status == JALIVE || j->j_status == JBG) && j->j_pgid == p)  {
			j->j_status = JSTOP;
			j->j_info = sig;
			if(j->j_jobnum == 0)
				j->j_jobnum = j_getnumber();
			j_current = j->j_jobnum;
			prc(NL);
			j_print_ent(j);
			fault(SIGSTOP);
			break;
		}
}

j_child_die(p)
	register int	p;
{
	register struct j_child *j = j_children; 

	if(p == 0 || p == -1)
		return;

	for(; j < &j_children[NJCH]; j++)
		if( j->j_status != JEMPTY && j->j_pgid == p)  {
			j->j_status = JEMPTY;
			if(j->j_jobnum && j->j_jobnum == j_current)
				j_backoff();
			break;
		}
}

j_print()
{
	register struct j_child *j = j_children; 

	if((flags & jobflg) == 0)  {
		prs(jcoffstr);		/* DAG */
		return;
	}

	await(-2, 1);
	for(; j < &j_children[NJCH]; j++)
		j_print_ent(j);
}

static void
j_print_ent(j)
	register struct j_child *j;
{
	if(j->j_status == JEMPTY)
		return;

	if(j->j_jobnum == 0) {
		prs(jpanstr);		/* DAG */
		prn(j->j_pgid);
		prc(NL);
	}
	prc('[');
	prn(j->j_jobnum);
	prs(rsqbrk);			/* DAG */
	if(j_current == j->j_jobnum)
		prs(execpmsg);		/* DAG */
	else
		prs(spspstr);		/* DAG */
	prn(j->j_pgid);
	prc(' ');

	switch(j->j_status)  {
	case JALIVE:
		prs(fgdstr);		/* DAG */
		break;
	case JSTOP:
		prs(stpdstr);		/* DAG */
		switch(j->j_info)  {
		case SIGTSTP:
			prs(lotspstr);	/* DAG */
			break;
		case SIGSTOP:
			prs(psgpstr);	/* DAG */
			break;
		case SIGTTIN:
			prs(ptinstr);	/* DAG */
			break;
		case SIGTTOU:
			prs(ptoustr);	/* DAG */
			break;
		}
		break;
	case JBG:
		prs(bgdstr);		/* DAG */
		break;
	}
	prc(' ');
	prs(j->j_com);
	prc(NL);
}

j_resume(cp, bg)
	char	*cp;
	BOOL	bg;
{
	register struct j_child *j = j_children; 
	int	p;
	
	if((flags & jobflg) == 0)  {
		prs(jcoffstr);		/* DAG */
		return;
	}

	if(cp)  {
		p = atoi(cp);
		if(p == 0)  {
			prs(jinvstr);	/* DAG */
			return;
		}
	}
	else
		p = 0;
		
	await(-2, 1);
	if(p == 0 && j_current == 0)  {
		prs(ncjstr);		/* DAG */
		return;
	}

	for(; j < &j_children[NJCH]; j++)
		if(j->j_status != JEMPTY)
			if(
			   (p != 0 && j->j_pgid == p) ||
			   (p == 0 && j->j_jobnum == j_current)
			)  {
				p = j->j_pgid;
				if(!bg)  {
					ioctl(1, TIOCSPGRP, &p);
					setpgrp(0, p);
				}
				j->j_status = bg ? JBG : JALIVE;
				j_print_ent(j);
				if(killpg(p, SIGCONT) == -1)  {
					j->j_status = JEMPTY;
					break;
				}
				if(bg)
					post(p);
				else
					await(p, 0);
				j_reset_pg();
				return;
			}
	prn(p);
	prs(nstpstr);			/* DAG */
}

char	*
j_macro()
{
	static char	digbuf[40];
	register char	*c;
	register int	i;
	register struct j_child *j = j_children; 

	c = digbuf;
	*c++ = '%';

	for(;;) {
		*c = readc();
		if( c==(digbuf+1) && *c == '%')  {
			i = j_current;
			break;
		}
		if(!digchar(*c))  {
			peekc = *c | MARK;
			*c = 0;
			i = stoi(digbuf+1);
			break;
		}
		c++;
	}

	if(i != 0)
		for(; j < &j_children[NJCH]; j++)
			if(j->j_status != JEMPTY && j->j_jobnum == i)  {
				itos(j->j_pgid);
				movstr(numbuf, digbuf);	/* DAG */
				break;
			}

	return digbuf;
}

j_reset_pg()
{
	if((flags & jobflg) == 0)
		return;
	if(j_top_level)  {
		ioctl(0, TIOCSPGRP, &j_default_pg);
		setpgrp(0, j_default_pg);
	}
}

static void
j_really_reset_pg()
{
	ioctl(0, TIOCSPGRP, &j_original_pg);
	setpgrp(0, j_original_pg);
}


#include "ctype.h"
extern BOOL trapflg[];

j_init()
{
	static int	ldisc = NTTYDISC;	/* BSD ioctl brain damage */

	if(flags & jobflg)
		return;
	j_reset_pg();
	trapflg[SIGTTIN] = SIGMOD | 1;
	trapflg[SIGTTOU] = SIGMOD | 1;
	trapflg[SIGTSTP] = SIGMOD | 1;
	trapflg[SIGSTOP] = SIGMOD | 1;
	ignsig(SIGTSTP);
	ignsig(SIGSTOP);	/*  Just to make sure  */
	(void)ioctl( 0, TIOCSETD, &ldisc );	/* DAG -- require "new tty" handler */
/*	flags |= jobflg;	*/
}

BOOL
j_finish(force)
	BOOL	force;
{
	register struct j_child *j = j_children; 

	if((flags & jobflg) == 0)
		return FALSE;

	await(-2, 1);
	for(; j < &j_children[NJCH]; j++)
		if(j->j_status == JSTOP )
			if(force)  {
				killpg(j->j_pgid, SIGHUP);
				killpg(j->j_pgid, SIGCONT);
			}
			else  {
				prs(tasjstr);	/* DAG */
				return TRUE;
			}
	if(force)  {
		await(-2, 1);		
		return FALSE;
	}
	trapflg[SIGTTIN] = SIGMOD;
	trapflg[SIGTTOU] = SIGMOD;
	trapflg[SIGTSTP] = SIGMOD;
	trapflg[SIGSTOP] = SIGMOD;
	flags &= ~jobflg;
	j_really_reset_pg();
	return FALSE;
}


static int	j_numbers = 0;

static int
j_getnumber()
{
	register struct j_child *j = j_children; 
	
	for(; j < &j_children[NJCH]; j++)
		if(j->j_status != JEMPTY && j->j_jobnum)
			return j_numbers++;
	j_numbers = 2;
	return 1;
}

static void
j_backoff()
{
	register struct j_child *j = j_children; 
	
	j_current = 0;
	for(; j < &j_children[NJCH]; j++)
		if(j->j_status != JEMPTY && j->j_jobnum)
			if(j->j_jobnum > j_current)
				j_current = j->j_jobnum;
}

static	int	jcleft;
static  char	*jcp;

static void
j_setcommand(j, t)
	register struct j_child	*j;
	struct trenod		*t;
{
	jcleft = strlen(j->j_com);
	jcp = j->j_com + jcleft;
	jcleft = JCOMSIZE - 1  - jcleft;

	if(j->j_com[0] == '\0' || !j_stuff(pipestr))	/* DAG */
		j_do(t);
}

static int
j_do_chain(a)
	register struct argnod *a;
{
	while(a)  {
		if(j_stuff(a->argval))
			return 1;
		a = a->argnxt;
		if(a)
			j_stuff(spcstr);	/* DAG */
	}
	return 0;
}

#define IOGET 0
static int
j_do_redir(t)
	register struct ionod	*t;
{
	register int	iof;	/* DAG -- added for speed */
	register int	i;

	while(t)  {
		if(t->ioname)  {
			if(j_stuff(spcstr))	/* DAG */
				return 1;
			iof = t->iofile;
			i = iof & IOUFD;
			if(
			    ((iof&IOPUT) && (i != 1)) ||
			    (((iof&IOPUT)==0) && (i!= 0))
			)  {
				itos(i);
				if(j_stuff(numbuf))
					return 1;
			}
			switch(iof & (IODOC|IOPUT|IOMOV|IOAPP|IORDW))  {
			case IOGET:
				if(j_stuff(rdinstr))	/* DAG */
					return 1;
				break;
			case IOPUT:
				if(j_stuff(readmsg))	/* DAG */
					return 1;
				break;
			case IOAPP|IOPUT:
				if(j_stuff(appdstr))	/* DAG */
					return 1;
				break;
			case IODOC:
				if(j_stuff(inlnstr))	/* DAG */
					return 1;
				break;
			case IOMOV|IOPUT:
				if(j_stuff(toastr))	/* DAG */
					return 1;
				break; 
			case IOMOV|IOGET:
				if(j_stuff(fromastr))	/* DAG */
					return 1;
				break;
			case IORDW:
				if(j_stuff(rdwstr))	/* ADR */
					return 1;
				break;
			}
			if(j_stuff(t->ioname))
				return 1;
		}
		t = t->ionxt;
	}
	return 0;
}
				
				
static int
j_do(t)	
	register struct trenod *t;
{
	int	type;

	if (t == (struct trenod *)0)	/* DAG -- added safety check */
		return 0;

	type = t->tretyp & COMMSK;
	switch(type)  {
#ifdef TFND	/* ADR --- don't put this stuff in the plain BSD /bin/sh */
	case	TFND:	/* added by DAG for System V Release 2 shell */
		return j_stuff(fndptr(t)->fndnam)
		    || j_stuff(sfnstr)	/* DAG */
		    || j_do(fndptr(t)->fndval)
		    || j_stuff(efnstr);	/* DAG */
#endif

	case	TCOM:
		if(comptr(t)->comset)  {
			if(j_do_chain(comptr(t)->comset)
			|| j_stuff(spcstr))
				return 1;			
		}
		return j_do_chain(comptr(t)->comarg)
		    || j_do_redir(comptr(t)->comio);

	case	TLST:
	case	TAND:
	case	TORF:
	case	TFIL:	/* DAG -- merged */
		if(j_do(lstptr(t)->lstlef))
			return 1;
		switch(type)  {
		case TLST:
			if(j_stuff(semspstr))	/* DAG */
				return 1;
			break;
		case TAND:
			if(j_stuff(andstr))	/* DAG */
				return 1;
			break;
		case TORF:
			if(j_stuff(orstr))	/* DAG */
				return 1;
			break;
		case TFIL:
			if(j_stuff(pipestr))	/* DAG */
				return 1;
			break;
		}
		return j_do(lstptr(t)->lstrit);

	case	TFORK:
		return j_do(forkptr(t)->forktre)
		    || j_do_redir(forkptr(t)->forkio)
		    || (forkptr(t)->forktyp & FAMP) && j_stuff(amperstr);	/* DAG */

	case	TPAR:
		return j_stuff(lpnstr)	/* DAG */
		    || j_do(parptr(t)->partre)
		    || j_stuff(rpnstr);	/* DAG */

	case	TFOR:
	case	TWH:
	case	TUN:
	{
		struct trenod *c;

		switch(type)  {
		case TFOR:
			if(j_stuff(forstr)	/* DAG */
			|| j_stuff(forptr(t)->fornam))
				return 1;
			if(forptr(t)->forlst)  {
				if(j_stuff(insstr)	/* DAG */
				|| j_do_chain(forptr(t)->forlst->comarg))
					return 1;
			}
			c = forptr(t)->fortre;
			break;

		case TWH:
			if(j_stuff(whilestr)	/* DAG */
			|| j_do(whptr(t)->whtre))
				return 1;
			c = whptr(t)->dotre;
			break;

		case TUN:
			if(j_stuff(untilstr)	/* DAG */
			|| j_do(whptr(t)->whtre))
				return 1;
			c = whptr(t)->dotre;
			break;
		}
		return j_stuff(sdostr)	/* DAG */
		    || j_do(c)
		    || j_stuff(sdonstr);	/* DAG */
	}
	case	TIF:
		if(j_stuff(ifstr)	/* DAG */
		|| j_do(ifptr(t)->iftre)
		|| j_stuff(sthnstr)	/* DAG */
		|| j_do(ifptr(t)->thtre))
			return 1;
		if(ifptr(t)->eltre)  {
			if(j_stuff(selsstr)	/* DAG */
			|| j_do(ifptr(t)->eltre))
				return 1;
		}
		return j_stuff(sfistr);	/* DAG -- bug fix (was "; done") */

	case	TSW:
		return j_stuff(casestr)	/* DAG */
		    || j_stuff(swptr(t)->swarg)
		    || j_stuff(iesacstr);	/* DAG */

	default:
/*		printf("sh bug: j_do--unknown type %d\n", type);	*/
		return 0;
	}
}

static int
j_stuff(f)
	char	*f;
{
	register int	i;
	register int	runover;

	i = strlen(f);
	runover = i > jcleft;
	if(runover)
		i = jcleft;
	strncpy(jcp, f, i);
	jcleft -= i;
	jcp += i;
	*jcp = 0;
	if(runover)  {
		jcp[-1] = '.';
		jcp[-2] = '.';
		jcp[-3] = '.';
	}
	return runover;
}
SHAR_EOF
echo shar: extracting "'homedir.c'" '(3036 characters)'
if test -f 'homedir.c'
then
	echo shar: over-writing existing file "'homedir.c'"
fi
cat << \SHAR_EOF > 'homedir.c'
/*
 * homedir.c
 *
 * find a person's login directory, for use by the shell
 * also find the current user's login name.
 *
 * Arnold Robbins
 */

#include "defs.h"

/* validtilde --- indicate whether or not a ~ is valid */

int validtilde (start, argp)
register char *start, *argp;
{
	return (
	start == argp - 1 ||			/* ~ at beginning of argument */
	argp[-2] == '=' ||			/* ~ after an assignment */
	(*start == '-' && argp - 3 == start)	/* in middle of an option */
						/* CSH does not do that one */
	);
}

/* homedir --- return the person's login directory */

char *homedir (person)
register char *person;
{
	register int count, i, j, fd;
	static char dir[150];
	char buf[300], name[100], rest[100];

	if (person[0] == '\0')	/* just a plain ~ */
		return (homenod.namval);
	else if (person[0] == '/')	/* e.g. ~/bin */
	{
		/* sprintf (dir, "%s%s", homenod.namval, person); */
		movstr (movstr (homenod.namval, dir), person);
		return (dir);
	}

	if ((fd = open ("/etc/passwd", 0)) < 0)
		return (nullstr);
	
	/*
	 * this stuff is to handle the ~person/bin sort of thing
	 * for catpath()
	 */
	movstr (person, name);
	*rest = '\0';
	for (i = 0; person[i]; i++)
		if (person[i] == '/')
		{
			movstr (& person[i], rest);
			name[i] = '\0';
			break;
		}

	while ((count = read (fd, buf, sizeof(buf))) > 0)
	{
		for (i = 0; i < count; i++)
			if (buf[i] == '\n')
			{
				i++;
				lseek (fd, (long) (- (count - i)), 1);
				break;
			}
		buf[i] = '\0';
		for (j = 0; name[j] && buf[j] == name[j]; j++)
			;
		if (buf[j] == ':' && name[j] == '\0')
			break;	/* found it */
	}
	if (count == 0)
	{
		close (fd);
		return (nullstr);
	}

	j--;
	for (i = 1; i <= 5; i++)
	{
		for (; buf[j] != ':'; j++)
			;
		j++;
	}
	for (i = 0; buf[j] != ':'; i++, j++)
		dir[i] = buf[j];
	if (rest[0])
		for (j = 0; rest[j]; j++)
			dir[i++] = rest[j];
	dir[i] = '\0';
	close (fd);
	return (dir);
}

/* username --- return the user's login name */

/*
 * this routine returns the first user name in /etc/passwd that matches the
 * real uid.  This could be a problem on some systems, but we don't want to
 * call getlogin(), since it uses stdio, and the shell does not.
 */

char *username ()
{
	register int count, i, j, fd;
	static char logname[50];
	static int foundname = FALSE;
	char buf[300];

	if (foundname)
		return (logname);

	if ((fd = open ("/etc/passwd", 0)) < 0)
		return (nullstr);
	
	itos (getuid());
	while ((count = read (fd, buf, sizeof(buf))) > 0)
	{
		for (i = 0; i < count; i++)
			if (buf[i] == '\n')
			{
				i++;
				lseek (fd, (long) (- (count - i)), 1);
				break;
			}
		buf[i] = '\0';
		for (j = 0, i = 1; i <= 2; i++)
		{
			for (; buf[j] != ':'; j++)
				;	/* skip name && passwd */
			j++;
		}
			
		for (i = 0; numbuf[i] && buf[j] == numbuf[i]; i++, j++)
			;
		if (buf[j] == ':' && numbuf[i] == '\0')
			break;	/* found it */
	}
	if (count == 0)
	{
		close (fd);
		return (nullstr);
	}

	for (i = 0; buf[i] != ':'; i++)
		logname[i] = buf[i];
	logname[i] = '\0';
	foundname = TRUE;
	close (fd);
	return (logname);
}
SHAR_EOF
echo shar: extracting "'history.c'" '(23486 characters)'
if test -f 'history.c'
then
	echo shar: over-writing existing file "'history.c'"
fi
cat << \SHAR_EOF > 'history.c'
/* history.c --- interacterive history mechanism for the Bourne shell */

/*
 * Original design by Jeff Lee for the Software Tools Subsystem,
 * This implementation by Arnold Robbins, based on Jeff's, but
 * a little bit more capable.
 */

#include "defs.h"	/* defines HISTSIZE */
#include "sym.h"

#define MAXHIST		256		/* max no. saved commands */
#define MAXLINE		257
#define BIGBUF		(MAXLINE * 2)

#define HISTCHAR	'!'		/* history flag character */
#define HISTLOOK	'?'		/* history global search command */
#define HISTARG		'`'		/* history argument character */
#define HISTSUB		'^'		/* history substitution character */

#define YES	(1)
#define NO	(0)

#ifndef TAB	/* earlier version of the shell */
#define	TAB	'\t'
#endif

static char	Histbuf[HISTSIZE];	/* queue holding actual history */
static int	Histptr[MAXHIST];	/* queue of pointers into buffer */
static int	Hbuffirst = 0;		/* First pointer into Histbuf */
static int	Hbuflast = 0;		/* Last pointer into Histbuf */
static int	Hptrfirst = 0;		/* First pointer into Histptr */
static int	Hptrlast = 0;		/* Last pointer into Histptr */
static int	Histline = 0;		/* no. of cmd pointed to by Histptr[Hptrlast] */

static char h_badopt[] =	" unrecognized history option";
static char badarg[] =	" illegal argument history";
static char nohist[] =	" no history exists, yet";
static char h_illegal[] =	" illegal history construct";
static char bufover[] =	" history buffer overflow";
static char bigtok[] =	" history token too large";
static char internal[] =	" history internal error";
static char badtoken[] =	" illegal history token";
static char h_notfound[] =	" history item not found";
static char bigexp[] =	" history expansion too big";

extern int	histsub ();		/* do a history substitution */
static void	histinit ();		/* reinitialize history mechanism */
static int	histexp ();		/* do a history expansion */
static int	histque ();		/* save a command in the buffers */
static void	histfree ();		/* free up some buffer storage */
static int	histfind ();		/* find a history command */
static int	histlook ();		/* get a previous command */
static int	histget ();		/* get a string from the buffers */
static void	histarg ();		/* get individual arguments */
extern int	histrest ();		/* restore saved history */
extern int	histsave ();		/* save current history */

static int	Bquote = 0;		/* count grave accents */
static int	Dquote = 0;		/* count single quotes */
static int	Squote = 0;		/* count double quotes */

#define errmsg(x, s)	{ prs(x); prc(COLON); prs(s); newline(); return (FALSE); }

#define repeat		do	/* repeat ... until is easier to read */
#define until(cond)	while (!(cond))

/* histsub --- perform a history substitution */

int histsub (in, out, outsize)
char *in, *out;
int outsize;
{
	if ((flags&prompt) == 0 || in == 0 || *in == '\0')
		return (TRUE);	/* no history, pretend all ok */
	
	return (histexp (in, out, outsize) && histque (out));
}

/* histexp --- perform history expansion on a command line */

static int histexp (in, out, outsize)
char *in, *out;
int outsize;
{
	int i;
	int istart, ilen, ostart;
	char buf[MAXLINE], result[BIGBUF];
	auto int bangseen = NO;

	if (in[0] == NL || in[0] == '\0')
		return (FALSE);

	istart = ostart = ilen = 0;
	while (in[istart] && in[istart] != HISTCHAR)
	{
		if (ostart >= outsize)
			errmsg (in, bigexp);
		switch (in[istart]) {
		case ESCAPE:
			out[ostart++] = in[istart++];
			if (in[istart] == HISTCHAR)
			{
				bangseen = YES;
				if (Squote)
					out[ostart++] = in[istart++];
				else
					out[ostart - 1] = in[istart++];
					/* no quotes, nuke \ */
				continue;
			}
			break;
		case '`':
			if (Dquote == 0 && Squote == 0)
				Bquote = 1 - Bquote;
			break;
		case '\'':
			if (Bquote == 0 && Dquote == 0)
				Squote = 1 - Squote;
			break;
		case '"':
			if (Bquote == 0 && Squote == 0)
				Dquote = 1 - Dquote;
			break;
		}
		if (ostart >= outsize)
			errmsg (in, bigexp);
		out[ostart++] = in[istart++];
		if (Squote && in[istart] == HISTCHAR)
			if (ostart >= outsize)
			{
				errmsg (in, bigexp);
			}
			else
				out[ostart++] = in[istart++];
	}

	if (in[istart] == '\0')
	{
		out[ostart] = '\0';
		if (bangseen)
			expanded = YES;		/* see comment below */
		return (TRUE);	/* no history to do */
	}

	expanded = NO;	/* this is a global flag */
	while (histfind (in, &istart, &ilen))	/* we found something to do */
	{
		if (ilen >= MAXLINE)
			errmsg (&in[istart], bigtok);

		/* save the history part */
		strncpy (buf, & in[istart], ilen);
		buf[ilen] = '\0';
		istart += ilen;
		if (buf[ilen-1] == HISTCHAR)
			buf[--ilen] = '\0';
		
		/* actually make the substitution */
		if (! histlook (buf, result))
			return (FALSE);
		
		/* put it into generated line */
		i = length (result) - 2;
		if (result[i] == NL)
			result[i] = '\0';
		if (ostart + i + 1 >= outsize)
			errmsg (&in[istart], bigexp);
		movstr (result, & out[ostart]);
		ostart += length (result) - 1;
		expanded = YES;
		while (in[istart] && in[istart] != HISTCHAR)
		{
			if (ostart >= outsize)
				errmsg (&in[istart], bigexp);
			switch (in[istart]) {
			case ESCAPE:
				out[ostart++] = in[istart++];
				if (in[istart] == HISTCHAR)
				{
					bangseen = YES;
					if (Squote)
						out[ostart++] = in[istart++];
					else
						out[ostart - 1] = in[istart++];
						/* no quotes, nuke \ */
					continue;
				}
				break;
			case '`':
				if (Dquote == 0 && Squote == 0)
					Bquote = 1 - Bquote;
				break;
			case '\'':
				if (Bquote == 0 && Dquote == 0)
					Squote = 1 - Squote;
				break;
			case '"':
				if (Bquote == 0 && Squote == 0)
					Dquote = 1 - Dquote;
				break;
			}
			if (ostart >= outsize)
				errmsg (&in[istart], bigexp);
			out[ostart++] = in[istart++];
			if (Squote && in[istart] == HISTCHAR)
				if (ostart >= outsize)
				{
					errmsg (&in[istart], bigexp);
				}
				else
					out[ostart++] = in[istart++];
		}
	}

	out[ostart] = '\0';

	if (expanded)
		prs (out);	/* should contain newline */
	else if (bangseen)
		expanded = YES;

	/*
	 * This is a KLUDGE, so that escaped !s work;
	 * it depends on knowledge of how readb() in word.c
	 * works, i.e., if expanded, use the generated buffer.
	 * This way, only expanded is needed as a global variable.
	 */

	return (TRUE);
}

/* histque --- place the given command in the history queue */

static int histque (command)
char *command;
{
	int c;
	char *p;
	static int Inaquote = FALSE;	/* in a quote across commands */

	for (; *command && (*command == SP || *command == TAB); command++)
		; /* skip leading white space */

	if (*command == NL && *(command+1) == '\0')
		return (TRUE);	/* don't queue empty commands */
				/* or increment event_count */

	if (Inaquote)
	{
		/* clobber trailing \0 */
		if (Hbuffirst == 0)
			Hbuffirst = HISTSIZE - 1;
		else
			Hbuffirst--;

		event_count--;
	}

	Histptr[Hptrfirst] = Hbuffirst;
	if (! Inaquote)
		Hptrfirst = (Hptrfirst + 1) % MAXHIST;

	if (Hptrfirst == Hptrlast)
		histfree ();

	p = command;
	c = *p++;
	while (c != '\0' && Hptrfirst != Hptrlast)
	{
		repeat
		{
			Histbuf[Hbuffirst] = c;
			c = *p++;
			Hbuffirst = (Hbuffirst + 1) % HISTSIZE;
		} until (c == '\0' || Hbuffirst == Hbuflast);

		if (Hbuffirst == Hbuflast)
			histfree ();
	}

	if (Hptrfirst != Hptrlast)
	{
		Histbuf[Hbuffirst] = '\0';
		Hbuffirst = (Hbuffirst + 1) % HISTSIZE;

		if (Hbuffirst == Hbuflast)
			histfree ();
	}

	Inaquote = (Bquote || Dquote || Squote);

	if (Hptrfirst == Hptrlast)
	{
		histinit ();
		errmsg (nullstr, bufover);
		/* errmsg returns FALSE */
	}

	event_count++;
	return (TRUE);
}

/* histfree --- free the next queue pointer */

static void histfree ()
{
	Hptrlast = (Hptrlast + 1) % MAXHIST;

	Hbuflast = Histptr[Hptrlast];
	Histline++;
}

/* histfind --- find the start and length of a history pattern */

static int histfind (command, start, len)
char *command;
int *start, *len;
{
	char *p, c;
	int subseen;

	p = command + *start;
	c = *p++;

	*len = 0;
	if (c == NL || c == '\0')
		return (FALSE);

	/* skip leading non-history */
	while (c && c != HISTCHAR)
	{
		if (c == ESCAPE)
		{
			c = *p++;
			*start += 1;
		}

		if (c != '\0')
		{
			c = *p++;
			*start += 1;
		}
	}

	if (c == NL || c == '\0')
		return (FALSE);
	
	*len = 1;
	c = *p++;
	if (c == HISTLOOK)	/* !?...? */
	{
		*len += 1;
		c = *p++;
		while (c && c != HISTLOOK && c != NL)
		{
			if (c == ESCAPE)
			{
				c = *p++;
				*len += 1;
			}

			if (c != '\0')
			{
				c = *p++;
				*len += 1;
			}
		}
		if (c == HISTLOOK)
		{
			c = *p++;
			*len += 1;
		}
	}
	else if (digit (c) || c == '-')	/* !<num> */
	{
		if (c == '-')
		{
			c = *p++;
			*len += 1;

			if (! digit(c))
				errmsg (command + *start, h_illegal);
		}

		while (digit (c))
		{
			c = *p++;
			*len += 1;
		}
	}
	else	/* !<str> */
		while (c && c != HISTARG && c != HISTSUB && c != SP &&
				c != TAB && c != NL && c != HISTCHAR)
		{
			if (c == ESCAPE)
			{
				c = *p++;
				*len += 1;
			}

			if (c != '\0')
			{
				c = *p++;
				*len += 1;
			}
		}

	if (c == HISTARG)
	{
		*len += 1;
		c = *p++;
		while (c && digit (c))
		{
			*len += 1;
			c = *p++;
		}
		if (c == '-')
		{
			*len += 1;
			c = *p++;
		}
		if (c == '$')
		{
			*len += 1;
			c = *p++;
		}
		else
		{
			while (c && digit (c))
			{
				*len += 1;
				c = *p++;
			}
		}
	}

	while (c == HISTSUB)
	{
		*len += 1;
		subseen = 0;
		c = *p++;

		while (subseen < 2 && c != NL && c != '\0')
		{
			if (c == ESCAPE)
			{
				c = *p++;
				*len += 1;
			}

			if (c != '\0')
			{
				c = *p++;
				*len += 1;
			}

			if (c == HISTSUB)
				subseen++;
		}

		if (c == HISTSUB)
		{
			*len += 1;
			c = *p++;
			if (c == 'g' || c == 'G')
			{
				*len += 1;
				c = *p++;
			}
		}
	}

	if (c == HISTCHAR)
		*len += 1;
	
	return (TRUE);
}

/* histlook --- lookup the value of a history string */

static int histlook (str, sub)
char *str, *sub;
{
	char c;
	char *save, *p, *sp;
	char buf[BIGBUF], rep[BIGBUF];
	char new[BIGBUF];
	int i, j, val, si, flag, len, last;
	static int ctoi();

	save = sub;
	/*
	 * first attempt to find which command on which we are to operate
	 *
	 * the entire hstory format is as follows
	 *
	 * ! [<str> | <num> | ?<str>?] [`<num> [- [<num>]]] {^<str>^<str>^ [g]}
	 */
	
	si = 0;

	if (str[si] == HISTCHAR)
		si++;

	switch (str[si]) {
	case '\0':	/* ! */
	case NL:
	case HISTARG:	/* on these, retrive previous line, then break */
	case HISTSUB:
		if (Hptrfirst == Hptrlast)
			errmsg (nullstr, nohist);

		val = (Hptrfirst - Hptrlast + MAXHIST) % MAXHIST + Histline - 1;
		if (! histget (val, sub))
			errmsg (nullstr, internal);
		break;

	case '-':
	case '0':	/* !<num> */
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		val = ctoi (str, &si) - 1;	/* for 0-based indexing */
		if (! histget(val, sub))
			errmsg (str, h_notfound);
		break;
	
	case HISTLOOK:	/* ?<str>? */
		i = 0;
		si++;
		while (str[si] && str[si] != HISTLOOK)
		{
			if (str[si] == ESCAPE)
				si++;
			
			if (str[si])
				buf[i++] = str[si++];
		}
		buf [i] = '\0';
		if (str[si] == HISTLOOK)
			si++;
		if (buf[i-1] == NL)
			buf[--i] = '\0';
		
		flag = FALSE;
		val = (Hptrfirst - Hptrlast + MAXHIST) % MAXHIST + Histline - 1;
		*sub = '\0';
		while (histget (val, sub))
		{
			p = sub;
			c = *p++;
			while (c)
			{
				i = 0;
				while (c != '\0' && buf[i] != '\0' && c != buf[i])
				{
					/* skip non matching */
					c = *p++;
					if (*p == '\0')
						break;
				}
				
				sp = p;

				while (c && buf[i] && c == buf[i])
				{
					/* possibly matching */
					c = *p++;
					i++;
				}

				if (buf[i] == '\0')
				{
					/* did match */
					flag = TRUE;
					goto out;
				}

				p = sp;
				c = *p++;
			}
			val--;	/* search further back, next time around */
			*sub = '\0';
		}

	out:
		if (flag == FALSE)
			errmsg (str, h_notfound);
		break;

	default:	/* !<str> */
		i = 0;
		while (str[si] && str[si] != HISTARG && str[si] != HISTSUB)
		{
			if (str[si] == ESCAPE)
				si++;
			
			if (str[si])
				buf[i++] = str[si++];
		}
		buf[i] = '\0';

		flag = FALSE;
		val = (Hptrfirst - Hptrlast + MAXHIST) % MAXHIST + Histline - 1;
		while (histget (val, sub))
		{
			p = sub;
			c = *p++;
			while (c == SP || c == TAB)
				c = *p++;

			i = 0;
			while (buf[i] && buf[i] == c)
			{
				c = *p++;
				i++;
			}

			if (buf[i] == '\0')
			{
				flag = TRUE;	/* found it */
				break;	/* while */
			}
			val--;
		}
		if (flag == FALSE)
			errmsg (str, h_notfound);
		break;
	} /* end switch */

	j = length (sub) - 2;
	if (sub[j] == NL)
		sub[j] = '\0';

	/*
	 * ! [<str> | <num> | ? <str> ?] has now been parsed and the command
	 * line has been placed in "sub". Now see if the next character is a
	 * legal following character
	 */
	
	if (str[si] && str[si] != HISTARG && str[si] != HISTSUB && str[si] != NL)
		errmsg (str, badtoken);

	/* if there is no more to the history string, we are done */
	if (str[si] == NL || str[si] == '\0')
		return (TRUE);
	
	/*
	 * now check for possible argument substitution. This section parses
	 * [` <num>] and turns "sub" into the appropriate argument
	 */
	
	if (str[si] == HISTARG)		/* `<num>-<num> */
	{
		si++;

		if (! digit(str[si]) && str[si] != '-' && str[si] != '$')
			errmsg (str, badarg);
		
		/* determine the last argument */
		p = sub;
		last = -1;
		/* count arguments, last will be val of $ */
		histarg (p, &len);
		while (len > 0)
		{
			last++;
			p += len;
			histarg (p, &len);
		}

		if (str[si] == '-')	/* default to arg 1 */
			val = 1;
		else if (digit(str[si]))
			val = min (ctoi(str, &si), last + 1);
		else
		{
			/* $ */
			val = last;

			if (str[si] != '$')
			{
				errmsg (str, internal);
			}
			else
				si++;
		}

		p = sub;
		for (i = val; i > 0; i--)	/* delete preceding arguments */
		{
			histarg (p, & len);
			p += len;
		}

		/* p points to beginning of first wanted arg */
		/* remove leading blanks */
		c = *p++;
		while (c == SP || c == TAB)
			c = *p++;
		
		sub = p - 1;


		if (str[si] == '-')
		{
			si++;
			if (digit(str[si]))
				val = min (ctoi (str, &si), last) - val + 1;
			else
			{
				val = last - val + 1;

				if (str[si] != '\0')
					si++;
			}

			p = sub;
			histarg (p, & len);
			while (val > 0 && len > 0)
			{
				val--;
				p += len;
				histarg (p, &len);
			}
			*p = '\0';
		}
		else
		{
			histarg (sub, & len);
			sub [len] = '\0';
		}
	}

	/* move everything to beginning of buffer */
	if (save != sub)
	{
		movstr (sub, save);
		sub = save;
	}


	/*
	 * check that the remaining characters represent
	 * legal following characters
	 */

	if (str[si] && str[si] != HISTSUB && str[si] != NL)
		errmsg (str, badtoken);
	
	/* check for no substitutions and return if we are done */
	if (str[si] && str[si] != HISTSUB)
		return (TRUE);
	
	/* keep performing substitutions until there are no more */

	while (str[si] == HISTSUB)
	{
		i = 0;
		si++;
		flag = FALSE;
		/* buf is what to look for */
		while (str[si] && str[si] != HISTSUB)
		{
			if (str[si] == ESCAPE)
				si++;
			
			if (str[si])
				buf[i++] = str[si++];
		}
		buf[i] = '\0';

		i = 0;
		if (str[si])
			si++;
		
		/* rep is replacement */
		while (str[si] && str[si] != HISTSUB)
		{
			if (str[si] == ESCAPE)
				si++;
			
			if (str[si])
				rep[i++] = str[si++];
		}
		rep[i] = '\0';

		if (str[si] == HISTSUB)
			si++;
		
		if (str[si] == 'g' || str[si] == 'G')
		{
			flag = TRUE;
			si++;
		}

		j = 0;		/* j indexes new */
		p = sub;
		c = *p++;
		sp = p;		/* save position for backing up */
		while (c != '\0')
		{
			i = 0;
			while (c && c != buf[i])
			{
				/* copy what doesn't match */
				new[j++] = c;
				c = *p++;
				sp = p;
			}

			while (c && buf[i] && c == buf[i])
			{
				/* partial matching */
				c = *p++;
				i++;
			}

			if (buf[i] == '\0')
			{
				/* successful match */
				char *cp = rep;

				while (*cp)
					new[j++] = *cp++;
					/* put in replacement text */

				if (flag == FALSE)	/* just 1 replacement */
				{
					new[j++] = c;
					while (*p)
						new[j++] = *p++;
						/* copy the rest */
					break;
				}
			}
			else if (c != '\0')
			{
				/* back up and try again */
				new[j++] = *(sp - 1);
				p = sp;
				c = *p++;
				sp = p;
			}
		}
		new[j] = '\0';
		movstr (new, sub);
		/* now look for next substitution */
	}

	if (save != sub)
	{
		movstr (sub, save);
		sub = save;
	}
	
	j = length (sub) - 2;
	if (sub[j] == NL)
		sub[j] = '\0';

	return (TRUE);
}

/* histget --- get a specified string from the history buffers */

static int histget (hp, sub)
int hp;
char *sub;
{
	char buf[BIGBUF];
	int i, j, maxinx, hval;

	*sub = '\0';
	maxinx = (Hptrfirst - Hptrlast + MAXHIST) % MAXHIST + Histline - 1;
	if (hp < Histline || hp > maxinx)		/* out of range */
		return (FALSE);
	
	hval = ((hp - Histline + Hptrlast - 1) % MAXHIST) + 1;
	for (i = Histptr[hval]; Histbuf[i] != '\0'; )
	{
		int k; 

		j = 0;
		while (Histbuf[i] != '\0' && j < sizeof(buf) - 1)
		{
			buf[j] = Histbuf[i];
			i = (i + 1) % HISTSIZE;
			j++;
		}

		buf[j] = '\0';
		/* strcat (sub, buf); */
		movstr (buf,
			sub + (((k = length (sub) - 1) <= 0 ? 0 : k)));
	}

	return (TRUE);
}

/* histarg --- return the last position of the next argument */

static void histarg (ptr, len)
char *ptr;
int *len;
{
	char *p;
	char c;
	int bracket, paren, brace, squote, dquote, bquote, skip;

	p = ptr;
	*len = 0;
	skip = FALSE;
	bracket = paren = brace = squote = dquote = bquote = 0;

	repeat
	{
		*len += 1;
		c = *p++;
		while (skip == FALSE && (c == SP || c == TAB))
		{
			c = *p++;
			*len += 1;
		}

		skip = TRUE;
		switch (c) {
		case ESCAPE:
			c = *p++;
			*len += 1;
			break;

		case '[':
			if (squote == 0 && dquote == 0 && bquote == 0)
				bracket++;
			break;

		case ']':
			if (squote == 0 && dquote == 0 && bquote == 0)
				bracket--;
			break;

		case '(':
			if (squote == 0 && dquote == 0 && bquote == 0)
				paren++;
			break;

		case ')':
			if (squote == 0 && dquote == 0 && bquote == 0)
				paren--;
			break;

		case '{':
			if (squote == 0 && dquote == 0 && bquote == 0)
				brace++;
			break;

		case '}':
			if (squote == 0 && dquote == 0 && bquote == 0)
				brace--;
			break;

		case '\'':
			if (dquote == 0 && bquote == 0)
				squote = 1 - squote;
			break;

		case '"':
			if (squote == 0 && bquote == 0)
				dquote = 1 - dquote;
			break;

		case '`':
			if (dquote == 0 && squote == 0)
				bquote = 1 - bquote;
			break;

		}
	} until (c == '\0' ||
		((c == SP || c == TAB) && paren == 0 && brace == 0 &&
		bracket == 0 && squote == 0 && dquote == 0 && bquote == 0));

	*len -= 1;
	return;
}

/* ctoi --- character to integer conversion, updates indices ala Fortrash */

static int ctoi (str, inx)
register char *str;
register int *inx;
{
	register int ret = 0;
	int neg = 0;

	if (str[*inx] == '-')
	{
		neg = 1;
		*inx += 1;
	}

	while (digit (str[*inx]))
	{
		ret = 10 * ret + str[*inx] - '0';
		*inx += 1;
	}

	return (neg ? -ret : ret);
}

/* min --- real function to return min of two numbers */

static int min (a, b)
register int a, b;
{
	return (a < b ? a : b);
}

/* histinit --- reinitialize history buffers */

static void histinit ()
{
	Hbuffirst = Hbuflast = Hptrfirst = Hptrlast = Histline = 0;
	event_count = 1;
}

/* histsave --- save history command lines */

histsave (file)
char *file;
{
	int fd, status, junk;

	if ((flags&nohistflg) != 0)
		return (FALSE);

	if ((flags&prompt) == 0)
		return (FALSE);

	if ((fd = creat (file, 0600)) < 0)	/* delete previous contents */
		return (FALSE);
	
	status = TRUE;

	junk = MAXHIST;
	if (write (fd, & junk, sizeof (junk)) != sizeof (junk))
		status = FALSE;

	junk = HISTSIZE;
	if (status == TRUE &&
		write (fd, & junk, sizeof (junk)) != sizeof (junk))
		status = FALSE;

	if (status == TRUE &&
		write (fd, &Hbuffirst, sizeof(Hbuffirst)) != sizeof (Hbuffirst))
		status = FALSE;

	if (status == TRUE &&
		write (fd, & Hbuflast, sizeof (Hbuflast)) != sizeof (Hbuflast))
		status = FALSE;

	if (status == TRUE &&
		write (fd, &Hptrfirst, sizeof(Hptrfirst)) != sizeof (Hptrfirst))
		status = FALSE;

	if (status == TRUE &&
		write (fd, & Hptrlast, sizeof (Hptrlast)) != sizeof (Hptrlast))
		status = FALSE;

	if (status == TRUE &&
		write (fd, Histptr, sizeof(Histptr)) != sizeof (Histptr))
		status = FALSE;

	if (status == TRUE &&
		write (fd, Histbuf, sizeof(Histbuf)) != sizeof (Histbuf))
		status = FALSE;
	
	close (fd);

	if (status == FALSE)
		unlink (file);	/* remove entirely */
	
	return (status);
}

/* histrest --- restore a history save file */

int histrest (file)
char *file;
{
	int fd, status, junk;

	if (flags&nohistflg)
		return (FALSE);

	if ((flags&prompt) == 0)
		return (FALSE);

	if ((fd = open (file, 0)) < 0)	/* open for reading */
		return (FALSE);

	status = TRUE;
	if (read (fd, & junk, sizeof (junk)) != sizeof (junk) ||
			junk != MAXHIST)
		status = FALSE;

	if (status == TRUE && read (fd, & junk, sizeof (junk)) != sizeof (junk)
			|| junk != HISTSIZE)
		status = FALSE;

	if (status == TRUE &&
		read (fd, &Hbuffirst, sizeof (Hbuffirst)) != sizeof (Hbuffirst))
		status = FALSE;

	if (status == TRUE &&
		read (fd, & Hbuflast, sizeof (Hbuflast)) != sizeof (Hbuflast))
		status = FALSE;

	if (status == TRUE &&
		read (fd, &Hptrfirst, sizeof (Hptrfirst)) != sizeof (Hptrfirst))
		status = FALSE;

	if (status == TRUE &&
		read (fd, & Hptrlast, sizeof (Hptrlast)) != sizeof (Hptrlast))
		status = FALSE;

	if (status == TRUE &&
		read (fd, Histptr, sizeof(Histptr)) != sizeof (Histptr))
		status = FALSE;

	if (status == TRUE &&
		read (fd, Histbuf, sizeof(Histbuf)) != sizeof (Histbuf))
		status = FALSE;
	
	Histline = - (Hptrfirst - Hptrlast + MAXHIST) % MAXHIST;
	event_count = 1;
	close (fd);
	return (status);
}

/* history --- print history buffer, or save or restore buffer to file */

int history (argc, argv)
int argc;
char **argv;
{
	int i;
	char *hf;
	int (*hfp)();

	if ((flags&nohistflg) != 0)
	{
		if (flags&prompt)
			prs ("history processing not enabled\n");
		return 1;	/* failure */
	}

	if ((flags & prompt) == 0)	/* shell file */
		return 1;

	if (argc == 1)
	{
		int j = Histline + 1;
		int k, l, m; 
		int neg;
		char *cp;

#define outstr(s)	for (cp = s; *cp; cp++) \
				if (*cp == NL && *(cp+1))  \
					prs_buff ("\\n"); \
				else \
					prc_buff (*cp)


		for (i = Hptrlast; i != Hptrfirst; i = (i + 1) % MAXHIST)
		{
			neg = FALSE;

			k = j++;
			if (k < 0)
			{
				neg = TRUE;
				k = -k;
			}
			itos (k);
			l = length (numbuf) - 1;
			for (m = 3 - l; m > 0; m--)
				prc_buff (SP);
			prc_buff (neg ? '-' : SP);
			prs_buff (numbuf);
			prc_buff (COLON);
			prc_buff (SP);
			/*
			 * make sure that what we're printing
			 * doesn't wrap around the history buffer.
			 */
			k = (i % MAXHIST) + 1;
			if ((k != Hptrfirst && Histptr[i] < Histptr[k]) ||
				(k == Hptrfirst && Histptr[i] < Hbuffirst))
				outstr (& Histbuf[Histptr[i]]);
			else
			{
				/* saved text wraps around */
				for (l = Histptr[i]; l <= HISTSIZE - 1 &&
						Histbuf[l] != '\0'; l++)
					if (Histbuf[l] == NL
			&& Histbuf[l + 1 <= HISTSIZE - 1 ? l + 1 : 0] != '\0')
						prs_buff ("\\n");
					else
						prc_buff (Histbuf[l]);
				
				if (Histbuf[HISTSIZE - 1] != '\0')
					outstr (Histbuf);
			}
		}
		return 0;
	}
	else if (eq (argv[1], dashi))
	{
		histinit ();
		return 0;
	}
	else if (eq (argv[1], dashr))
		hfp = histrest;
	else if (eq (argv[1], dashs))
		hfp = histsave;
	else
	{
		prs(argv[1]);
		prc(COLON);
		prs(h_badopt);
		newline();
		return 1;
	}

	if (argc >= 3)
		hf = argv[2];
	else
		hf = histfnod.namval;
	
	return ((*hfp)(hf) != 0);	/* do a save or restore */
}
SHAR_EOF
echo shar: extracting "'sample.shrc'" '(443 characters)'
if test -f 'sample.shrc'
then
	echo shar: over-writing existing file "'sample.shrc'"
fi
cat << \SHAR_EOF > 'sample.shrc'
# .shrc file --- this file will be read every time the shell cranks up
# if it is in the $HOME directory

# this is a sample, currently set up to do some Korn shell emulation

PPID=$+			# set the Parent Process Id

# source file name given by ENV environment variable
# and only if $ENV is not this file.

if [ "$ENV" != "" -a "$ENV" != "$HOME/.shrc" ]
then
	. $ENV
fi

# put any useful shell functions here, or source a file with them in it.
SHAR_EOF
echo shar: extracting "'aliases.sh'" '(1027 characters)'
if test -f 'aliases.sh'
then
	echo shar: over-writing existing file "'aliases.sh'"
fi
cat << \SHAR_EOF > 'aliases.sh'
# aliases.sh --- sample shell functions which do some of what the csh does

# pushd, popd, and dirs --- written by Chris Bertin
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
# as modified by Patrick Elam of GTRI

pushd () {
	SAVE=`pwd`
	DSTACK="$SAVE $DSTACK"
	if [ "$1" = "" ] 
	then
		if [ "$DSTACK" = "$SAVE " ]
		then
			echo "pushd: directory stack empty."
			DSTACK=""
			return 1
		fi
		set $DSTACK
		cd $2
		shift 2
		DSTACK="$SAVE $*"
	else
		if (cd $1)
		then
			cd $1 >&-
		else
			popd > /dev/null
			return 1
		fi
	fi
	dirs
	return 0
}

popd () {
	if [ "$DSTACK" = "" ] 
	then
		echo "popd: Directory statck empty"
		return 1
	fi
	set $DSTACK
	cd $1
	shift
	DSTACK=$*
	dirs
	return 0
}

dirs () {
	echo "`pwd` $DSTACK"
	return 0
}

xchng () {	# exchanged top two entries on the stack
	if [ "$DSTACK" = "" ]
	then
		echo exchange directory stack empty
		return 1
	else
		pushd
		return 0
	fi
}

source () {	# have the shell read a file in the current shell
	. $*
}

bye () { logout ; }

logout () { exit 0 ; }
SHAR_EOF
#	End of shell archive
exit 0

sources-request@genrad.UUCP (06/09/85)

From: Arnold Robbins <gatech!arnold>

This is part 2 of 9.  It contains the first set of code diffs for the BSD
Bourne shell.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
------------------- tear here --------------------
:::::::: Makefile :::::::
*** ../orig.u/Makefile	Wed May 15 17:13:43 1985
--- Makefile	Tue Jun  4 17:30:08 1985
***************
*** 1,6
  #	Makefile	4.5	83/07/01
  #
! CFLAGS = -O -w
  
  all:	sh
  

--- 1,6 -----
  #	Makefile	4.5	83/07/01
  #
! CFLAGS = -O -w -DJOBS
  
  all:	sh
  
***************
*** 12,17
  	cmp sh /bin/sh
  	rm sh *.o
  
  sh:	setbrk.o
  sh:	builtin.o blok.o stak.o
  sh:	cmd.o fault.o main.o

--- 12,21 -----
  	cmp sh /bin/sh
  	rm sh *.o
  
+ expand.o:	expand.c
+ 	@echo ignore the redefiniton of MAX
+ 	$(CC) $(CFLAGS) -c expand.c
+ 
  sh:	setbrk.o
  sh:	builtin.o blok.o stak.o
  sh:	cmd.o fault.o main.o
***************
*** 19,24
  sh:	xec.o service.o error.o io.o
  sh:	print.o macro.o expand.o
  sh:	ctype.o msg.o
  blok.o:		brkincr.h
  fault.o:	brkincr.h
  main.o:		brkincr.h

--- 23,29 -----
  sh:	xec.o service.o error.o io.o
  sh:	print.o macro.o expand.o
  sh:	ctype.o msg.o
+ sh:	history.o homedir.o jobs.o signal.o # remove signal.o on pyramid
  blok.o:		brkincr.h
  fault.o:	brkincr.h
  main.o:		brkincr.h
:::::::: args.c :::::::
*** ../orig.u/args.c	Wed May 15 17:13:43 1985
--- args.c	Tue Jun  4 13:20:43 1985
***************
*** 16,22
  PROC STRING *copyargs();
  LOCAL DOLPTR	dolh;
  
! CHAR	flagadr[10];
  
  CHAR	flagchar[] = {
  	'x',	'n',	'v',	't',	's',	'i',	'e',	'r',	'k',	'u',	0

--- 16,26 -----
  PROC STRING *copyargs();
  LOCAL DOLPTR	dolh;
  
! #if JOBS
! CHAR	flagadr[15];
! #else
! CHAR	flagadr[13];
! #endif
  
  CHAR	flagchar[] = {
  	'x',	'n',	'v',	't',	's',	'i',	'e',	'r',	'k',	'u',
***************
*** 19,25
  CHAR	flagadr[10];
  
  CHAR	flagchar[] = {
! 	'x',	'n',	'v',	't',	's',	'i',	'e',	'r',	'k',	'u',	0
  };
  INT	flagval[]  = {
  	execpr,	noexec,	readpr,	oneflg,	stdflg,	intflg,	errflg,	rshflg,	keyflg,	setflg,	0

--- 23,37 -----
  #endif
  
  CHAR	flagchar[] = {
! 	'x',	'n',	'v',	't',	's',	'i',	'e',	'r',	'k',	'u',
! #if JOBS
! 	'I',
! 	'J',
! #endif
! 	'E',
! 	'H',
! 	'q',
! 	0
  };
  INT	flagval[]  = {
  	execpr,	noexec,	readpr,	oneflg,	stdflg,	intflg,	errflg,	rshflg,	keyflg,	setflg,
***************
*** 22,28
  	'x',	'n',	'v',	't',	's',	'i',	'e',	'r',	'k',	'u',	0
  };
  INT	flagval[]  = {
! 	execpr,	noexec,	readpr,	oneflg,	stdflg,	intflg,	errflg,	rshflg,	keyflg,	setflg,	0
  };
  
  /* ========	option handling	======== */

--- 34,48 -----
  	0
  };
  INT	flagval[]  = {
! 	execpr,	noexec,	readpr,	oneflg,	stdflg,	intflg,	errflg,	rshflg,	keyflg,	setflg,
! #if JOBS
! 	infoflg,
! 	jobflg,
! #endif
! 	noeotflg,
! 	nohistflg,
! 	quickflg,
! 	0
  };
  
  /* ========	option handling	======== */
***************
*** 38,45
  	STRING		flagp;
  
  	IF argc>1 ANDF *argp[1]=='-'
! 	THEN	cp=argp[1];
! 		flags &= ~(execpr|readpr);
  		WHILE *++cp
  		DO	flagc=flagchar;
  

--- 58,77 -----
  	STRING		flagp;
  
  	IF argc>1 ANDF *argp[1]=='-'
! 	THEN
! 		IF argp[1][1] == '-'
! 		THEN	/* if first argument is "--" then options are not
! 			   to be changed.  fix for problems getting $1
! 			   starting with a "-"
! 			*/
! 			argp[1] = argp[0]; argc--;
! 			return (argc);
! 		FI
! 		cp=argp[1];
! 		IF cp[1] == '\0' THEN flags &= ~(execpr|readpr) FI
! 		/* step along 'flagchar[]' looking for matches.
! 		   'sicrq' are not legal with 'set' command.
! 		*/
  		WHILE *++cp
  		DO	flagc=flagchar;
  
***************
*** 45,51
  
  			WHILE *flagc ANDF *flagc != *cp DO flagc++ OD
  			IF *cp == *flagc
! 			THEN	flags |= flagval[flagc-flagchar];
  			ELIF *cp=='c' ANDF argc>2 ANDF comdiv==0
  			THEN	comdiv=argp[2];
  				argp[1]=argp[0]; argp++; argc--;

--- 77,91 -----
  
  			WHILE *flagc ANDF *flagc != *cp DO flagc++ OD
  			IF *cp == *flagc
! 			THEN	IF eq(argv[0], "set") ANDF any(*cp, "sicrq")
! 				THEN	failed(argv[1], badopt);
! 				ELSE
! #if JOBS
! 					IF *cp == 'J' THEN j_init() FI
! #endif
! 					flags |= flagval[flagc-flagchar];
! 					IF flags & errflg THEN eflag = errflg FI
! 				FI
  			ELIF *cp=='c' ANDF argc>2 ANDF comdiv==0
  			THEN	comdiv=argp[2];
  				argp[1]=argp[0]; argp++; argc--;
***************
*** 53,58
  			FI
  		OD
  		argp[1]=argp[0]; argc--;
  	FI
  
  	/* set up $- */

--- 93,123 -----
  			FI
  		OD
  		argp[1]=argp[0]; argc--;
+ 	ELIF argc > 1 ANDF *argp[1] == '+'	/* unset flags x, k , t, n, v, e, u */
+ 	THEN	cp = argp[1];			/* or any other flags */
+ 		WHILE *++cp
+ 		DO
+ 			flagc = flagchar;
+ 			WHILE *flagc ANDF *flagc != *cp DO flagc++ OD
+ 				/* step through flags */
+ 			IF !any(*cp, "sicrq") ANDF *cp == *flagc
+ 			THEN
+ 				IF (flags&flagval[flagc-flagchar])
+ 				/* only turn off if already on */
+ 				THEN
+ #if JOBS
+ 					IF *cp != 'J' ORF !j_finish(FALSE)
+ 					THEN
+ #endif
+ 					flags &= ~(flagval[flagc-flagchar]);
+ #if JOBS
+ 					FI
+ #endif
+ 					IF *cp == 'e' THEN eflag = 0 FI
+ 				FI
+ 			FI
+ 		OD
+ 		argp[1]=argp[0]; argc--;
  	FI
  
  	/* set up $- */
***************
*** 126,131
  
  	/* clean up io files */
  	WHILE pop() DONE
  }
  
  DOLPTR	useargs()

--- 191,198 -----
  
  	/* clean up io files */
  	WHILE pop() DONE
+ 	/* clean up temp files */
+ 	WHILE poptemp() DONE
  }
  
  DOLPTR	useargs()
:::::::: blok.c :::::::
No differences encountered
:::::::: brkincr.h :::::::
No differences encountered
:::::::: builtin.c :::::::
No differences encountered
:::::::: cmd.c :::::::
*** ../orig.u/cmd.c	Wed May 15 17:13:44 1985
--- cmd.c	Thu May 30 13:53:25 1985
***************
*** 93,98
  	    case ';':
  		IF e=cmd(sym,flg|MTFLG)
  		THEN	i=makelist(TLST, i, e);
  		FI
  		break;
  

--- 93,100 -----
  	    case ';':
  		IF e=cmd(sym,flg|MTFLG)
  		THEN	i=makelist(TLST, i, e);
+ 		ELIF	i == 0
+ 		THEN	synbad();
  		FI
  		break;
  
***************
*** 326,332
  
  	SWITCH wdval IN
  
! 	    case DOCSYM:
  		iof |= IODOC; break;
  
  	    case APPSYM:

--- 328,334 -----
  
  	SWITCH wdval IN
  
! 	    case DOCSYM:	/* << */
  		iof |= IODOC; break;
  
  	    case APPSYM:	/* >> */
***************
*** 329,335
  	    case DOCSYM:
  		iof |= IODOC; break;
  
! 	    case APPSYM:
  	    case '>':
  		IF wdnum==0 THEN iof |= 1 FI
  		iof |= IOPUT;

--- 331,337 -----
  	    case DOCSYM:	/* << */
  		iof |= IODOC; break;
  
! 	    case APPSYM:	/* >> */
  	    case '>':
  		IF wdnum==0 THEN iof |= 1 FI
  		iof |= IOPUT;
***************
*** 341,346
  		IF (c=nextc(0))=='&'
  		THEN	iof |= IOMOV;
  		ELIF c=='>'
  		THEN	iof |= IORDW;
  		ELSE	peekc=c|MARK;
  		FI

--- 343,350 -----
  		IF (c=nextc(0))=='&'
  		THEN	iof |= IOMOV;
  		ELIF c=='>'
+ 		/*	<> is open for read and write */
+ 		/*	previously unadvertised feature */
  		THEN	iof |= IORDW;
  		ELSE	peekc=c|MARK;
  		FI
:::::::: ctype.c :::::::
*** ../orig.u/ctype.c	Wed May 15 17:13:44 1985
--- ctype.c	Thu May 30 13:59:18 1985
***************
*** 13,19
  
  #include	"defs.h"
  
! char	_ctype1[] {
  /*	000	001	002	003	004	005	006	007	*/
  	_EOF,	0,	0,	0,	0,	0,	0,	0,
  

--- 13,19 -----
  
  #include	"defs.h"
  
! char	_ctype1[] = {
  /*	000	001	002	003	004	005	006	007	*/
  	_EOF,	0,	0,	0,	0,	0,	0,	0,
  
***************
*** 25,30
  	0,	0,	0,	0,	0,	0,	0,	0,
  
  /*	sp	!	"	#	$	%	&	'	*/
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
  
  /*	(	)	*	+	,	-	.	/	*/

--- 25,33 -----
  	0,	0,	0,	0,	0,	0,	0,	0,
  
  /*	sp	!	"	#	$	%	&	'	*/
+ #if JOBS
+ 	_SPC,	0,	_DQU,	0,	_DOL1,	_PCT,	_AMP,	0,
+ #else
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
  #endif
  
***************
*** 26,31
  
  /*	sp	!	"	#	$	%	&	'	*/
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
  
  /*	(	)	*	+	,	-	.	/	*/
  	_BRA,	_KET,	0,	0,	0,	0,	0,	0,

--- 29,35 -----
  	_SPC,	0,	_DQU,	0,	_DOL1,	_PCT,	_AMP,	0,
  #else
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
+ #endif
  
  /*	(	)	*	+	,	-	.	/	*/
  	_BRA,	_KET,	0,	0,	0,	0,	0,	0,
***************
*** 62,68
  };
  
  
! char	_ctype2[] {
  /*	000	001	002	003	004	005	006	007	*/
  	0,	0,	0,	0,	0,	0,	0,	0,
  

--- 66,72 -----
  };
  
  
! char	_ctype2[] = {
  /*	000	001	002	003	004	005	006	007	*/
  	0,	0,	0,	0,	0,	0,	0,	0,
  
***************
*** 95,101
  	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,
  
  /*	X	Y	Z	[	\	]	^	_	*/
! 	_UPC,	_UPC,	_UPC,	_SQB,	0,	0,	0,	_UPC,
  
  /*	`	a	b	c	d	e	f	g	*/
  	0,	_LPC,	_LPC,	_LPC,	_LPC,	_LPC,	_LPC,	_LPC,

--- 99,105 -----
  	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,	_UPC,
  
  /*	X	Y	Z	[	\	]	^	_	*/
! 	_UPC,	_UPC,	_UPC,	0,	0,	0,	0,	_UPC,
  
  /*	`	a	b	c	d	e	f	g	*/
  	0,	_LPC,	_LPC,	_LPC,	_LPC,	_LPC,	_LPC,	_LPC,
:::::::: ctype.h :::::::
*** ../orig.u/ctype.h	Wed May 15 17:13:44 1985
--- ctype.h	Thu May 30 14:01:21 1985
***************
*** 51,56
  #define _BSL	(T_ESC)
  #define _DQU	(T_QOT)
  #define _DOL1	(T_SUB|T_ESC)
  
  #define _CBR	T_BRC
  #define _CKT	T_DEF

--- 51,59 -----
  #define _BSL	(T_ESC)
  #define _DQU	(T_QOT)
  #define _DOL1	(T_SUB|T_ESC)
+ #if JOBS
+ #define _PCT	(T_SUB|T_ESC)
+ #endif
  
  #define _CBR	T_BRC
  #define _CKT	T_DEF
***************
*** 68,74
  #define _IDCH	(T_IDC|T_DIG)
  #define _META	(T_SPC|T_DIP|T_MET|T_EOR)
  
! char	_ctype1[];
  
  /* nb these args are not call by value !!!! */
  #define	space(c)	(((c)&QUOTE)==0 ANDF _ctype1[c]&(T_SPC))

--- 71,77 -----
  #define _IDCH	(T_IDC|T_DIG)
  #define _META	(T_SPC|T_DIP|T_MET|T_EOR)
  
! extern char	_ctype1[];
  
  /* nb these args are not call by value !!!! */
  #define	space(c)	(((c)&QUOTE)==0 ANDF _ctype1[c]&(T_SPC))
***************
*** 79,85
  #define subchar(c)	(((c)&QUOTE)==0 ANDF _ctype1[c]&(T_SUB|T_QOT))
  #define escchar(c)	(((c)&QUOTE)==0 ANDF _ctype1[c]&(T_ESC))
  
! char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DIG))
  #define fngchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_FNG))

--- 82,88 -----
  #define subchar(c)	(((c)&QUOTE)==0 ANDF _ctype1[c]&(T_SUB|T_QOT))
  #define escchar(c)	(((c)&QUOTE)==0 ANDF _ctype1[c]&(T_ESC))
  
! extern char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DIG))
  #define dolchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS))
***************
*** 82,89
  char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DIG))
! #define fngchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_FNG))
! #define dolchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN))
  #define defchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DEF))
  #define setchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_SET))
  #define digchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_DIG))

--- 85,91 -----
  extern char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DIG))
! #define dolchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS))
  #define defchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DEF))
  #define setchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_SET))
  #define digchar(c)	(((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_DIG))
:::::::: defs.h :::::::
*** ../orig.u/defs.h	Wed May 15 17:13:44 1985
--- defs.h	Wed Jun  5 12:11:27 1985
***************
*** 8,15
  /* error exits from various parts of shell */
  #define ERROR	1
  #define SYNBAD	2
! #define SIGFAIL 3
! #define SIGFLG	0200
  
  /* command tree */
  #define FPRS	020

--- 8,15 -----
  /* error exits from various parts of shell */
  #define ERROR	1
  #define SYNBAD	2
! #define SIGFAIL 2000
! #define SIGFLG	1000
  
  /* command tree */
  #define FPRS	020
***************
*** 54,59
  #define SYSREAD 17
  #define SYSTST	18
  #define	SYSUMASK	19
  
  /* used for input and output of shell */
  #define INIO 10

--- 54,73 -----
  #define SYSREAD 17
  #define SYSTST	18
  #define	SYSUMASK	19
+ #if JOBS
+ #define SYSJOBS	20
+ #define SYSFG	21
+ #define SYSBG	22
+ #define SYSSUSPEND	23
+ #endif
+ #if pyr
+ #define SYSATT	24
+ #define SYSUCB	25
+ #define SYSUNIVERSE	26
+ #define U_ATT	1	/* ATT is Universe Number 1 */
+ #define U_UCB	2	/* UCB is Universe Number 2 */
+ #endif
+ #define SYSHISTORY	27
  
  /* used for input and output of shell */
  #define INIO 18
***************
*** 56,63
  #define	SYSUMASK	19
  
  /* used for input and output of shell */
! #define INIO 10
! #define OTIO 11
  
  /*io nodes*/
  #define USERIO	10

--- 70,77 -----
  #define SYSHISTORY	27
  
  /* used for input and output of shell */
! #define INIO 18
! #define OTIO 19
  
  /*io nodes*/
  #define USERIO	10
***************
*** 78,83
  #include	"name.h"
  
  
  /* result type declarations */
  #define alloc malloc
  ADDRESS		alloc();

--- 92,100 -----
  #include	"name.h"
  
  
+ /* error catching */
+ extern	INT	errno;
+ 
  /* result type declarations */
  #define alloc malloc
  ADDRESS		alloc();
***************
*** 108,113
  VOID		prc();
  VOID		getenv();
  STRING		*setenv();
  
  #define attrib(n,f)	(n->namflg |= f)
  #define round(a,b)	(((int)((ADR(a)+b)-1))&~((b)-1))

--- 125,147 -----
  VOID		prc();
  VOID		getenv();
  STRING		*setenv();
+ extern STRING	simple();
+ extern STRING	homedir();
+ extern STRING	username();
+ extern INT	history();
+ #if JOBS
+ extern BOOL	unpost();
+ extern VOID	j_init();
+ extern BOOL	j_finish();
+ extern VOID	j_child_clear();
+ extern VOID	j_child_die();
+ extern VOID	j_child_stop();
+ extern VOID	j_print();
+ extern VOID	j_resume();
+ extern VOID	j_child_post();
+ extern VOID	j_reset_pg();
+ extern STRING	j_macro();
+ #endif
  
  #define attrib(n,f)	(n->namflg |= f)
  #define round(a,b)	(((int)((ADR(a)+b)-1))&~((b)-1))
***************
*** 122,127
  IOPTR		iotemp;		/* files to be deleted sometime */
  IOPTR		iopend;		/* documents waiting to be read at NL */
  
  /* substitution */
  INT		dolc;
  STRING		*dolv;

--- 156,175 -----
  IOPTR		iotemp;		/* files to be deleted sometime */
  IOPTR		iopend;		/* documents waiting to be read at NL */
  
+ /* history stuff */
+ INT		event_count;
+ INT		expanded;
+ 
+ /* keep track of the parent process id */
+ INT		ppid;
+ 
+ #if pyr
+ /* keep track of the current universe */
+ INT			cur_univ;
+ extern STRING		univ_name[];	/* from <universe.h> */
+ extern STRING		univ_longname[];
+ #endif
+ 
  /* substitution */
  INT		dolc;
  STRING		*dolv;
***************
*** 147,152
  MSG		unexpected;
  MSG		endoffile;
  MSG		synmsg;
  
  /* name tree and words */
  SYSTAB		reserved;

--- 195,252 -----
  MSG		unexpected;
  MSG		endoffile;
  MSG		synmsg;
+ extern MSG		dashi;	/* ADR */
+ #if pyr
+ extern MSG		dashl;	/* ADR */
+ #endif
+ extern MSG		dashr;	/* ADR */
+ extern MSG		dashs;	/* ADR */
+ #if JOBS
+ extern MSG	appdstr;
+ extern MSG	bgdstr;
+ extern MSG	cjpostr;
+ extern MSG	fgdstr;
+ extern MSG	fromastr;	/* DAG */
+ extern MSG	inlnstr;
+ extern MSG	jcoffstr;
+ extern MSG	jinvstr;
+ extern MSG	jpanstr;
+ extern MSG	lotspstr;
+ extern MSG	ncjstr;
+ extern MSG	nstpstr;
+ extern MSG	pipestr;	/* DAG */
+ extern MSG	psgpstr;
+ extern MSG	ptinstr;
+ extern MSG	ptoustr;
+ extern MSG	rdinstr;
+ extern MSG	rsqbrk;
+ extern MSG	spcstr;
+ extern MSG	spspstr;
+ extern MSG	stpdstr;
+ extern MSG	tasjstr;
+ extern MSG	toastr;	/* DAG */
+ extern MSG	amperstr;	/* DAG */
+ extern MSG	andstr;	/* DAG */
+ extern MSG	casestr;	/* DAG */
+ extern MSG	forstr;	/* DAG */
+ extern MSG	iesacstr;
+ extern MSG	ifstr;	/* DAG */
+ extern MSG	insstr;
+ extern MSG	lpnstr;
+ extern MSG	orstr;	/* DAG */
+ extern MSG	forstr;	/* DAG */
+ extern MSG	rpnstr;
+ extern MSG	sdonstr;
+ extern MSG	sdostr;
+ extern MSG	selsstr;
+ extern MSG	semspstr;
+ extern MSG	sfistr;
+ extern MSG	sthnstr;
+ extern MSG	untilstr;	/* DAG */
+ extern MSG	whilestr;	/* DAG */
+ extern MSG	rdwstr;		/* ADR */
+ extern MSG	nosusp;		/* ADR */
+ #endif
  
  /* name tree and words */
  SYSTAB		reserved;
***************
*** 160,165
  MSG		stdprompt;
  MSG		supprompt;
  MSG		profile;
  
  /* built in names */
  NAMNOD		fngnod;

--- 260,267 -----
  MSG		stdprompt;
  MSG		supprompt;
  MSG		profile;
+ extern MSG		shrc;
+ extern MSG		savehist;
  
  /* built in names */
  NAMNOD		fngnod;
***************
*** 169,174
  NAMNOD		pathnod;
  NAMNOD		ps1nod;
  NAMNOD		ps2nod;
  
  /* special names */
  MSG		flagadr;

--- 271,280 -----
  NAMNOD		pathnod;
  NAMNOD		ps1nod;
  NAMNOD		ps2nod;
+ #if pyr
+ extern NAMNOD		univnod;
+ #endif
+ extern NAMNOD		histfnod;
  
  
  /* special names */
***************
*** 170,175
  NAMNOD		ps1nod;
  NAMNOD		ps2nod;
  
  /* special names */
  MSG		flagadr;
  STRING		cmdadr;

--- 276,282 -----
  #endif
  extern NAMNOD		histfnod;
  
+ 
  /* special names */
  MSG		flagadr;
  STRING		cmdadr;
***************
*** 177,182
  STRING		dolladr;
  STRING		pcsadr;
  STRING		pidadr;
  
  MSG		defpath;
  

--- 284,290 -----
  STRING		dolladr;
  STRING		pcsadr;
  STRING		pidadr;
+ STRING		ppidadr;
  
  MSG		defpath;
  
***************
*** 188,193
  MSG		ifsname;
  MSG		ps1name;
  MSG		ps2name;
  
  /* transput */
  CHAR		tmpout[];

--- 296,305 -----
  MSG		ifsname;
  MSG		ps1name;
  MSG		ps2name;
+ #if pyr
+ extern MSG		univname;	/* UNIVERSE */
+ #endif
+ extern MSG		histfilename;
  
  /* transput */
  CHAR		tmpout[];
***************
*** 200,205
  INT		peekc;
  STRING		comdiv;
  MSG		devnull;
  
  /* flags */
  #define		noexec	01

--- 312,323 -----
  INT		peekc;
  STRING		comdiv;
  MSG		devnull;
+ extern BOOL		catcheof;	/* set to catch EOF in reac() */
+ #if JOBS
+ extern	INT		j_original_pg;
+ extern	INT		j_default_pg;
+ extern 	BOOL		j_top_level;
+ #endif
  
  /* flags */
  #define		noexec	01
***************
*** 203,208
  
  /* flags */
  #define		noexec	01
  #define		intflg	02
  #define		prompt	04
  #define		setflg	010

--- 321,327 -----
  
  /* flags */
  #define		noexec	01
+ #define		sysflg	01
  #define		intflg	02
  #define		prompt	04
  #define		setflg	010
***************
*** 216,222
  #define		execpr	04000
  #define		readpr	010000
  #define		keyflg	020000
! INT		flags;
  
  /* error exits from various parts of shell */
  #include	<setjmp.h>

--- 335,349 -----
  #define		execpr	04000
  #define		readpr	010000
  #define		keyflg	020000
! #if JOBS
! #define		infoflg		040000
! #define		jobflg		0100000
! #endif
! #define		noeotflg	0200000
! #define		dotflg		0400000
! #define		quickflg	01000000
! #define		nohistflg	02000000
! L_INT		flags;	/* assure more than 16 bits */
  
  /* error exits from various parts of shell */
  #include	<setjmp.h>
***************
*** 220,225
  
  /* error exits from various parts of shell */
  #include	<setjmp.h>
  jmp_buf		subshell;
  jmp_buf		errshell;
  jmp_buf		INTbuf;

--- 347,356 -----
  
  /* error exits from various parts of shell */
  #include	<setjmp.h>
+ #if JOBS && !defined(pyr)
+ #define	setjmp(env)		_setjmp(env)
+ #define longjmp(env, val)	_longjmp(env, val)
+ #endif
  jmp_buf		subshell;
  jmp_buf		errshell;
  
***************
*** 222,228
  #include	<setjmp.h>
  jmp_buf		subshell;
  jmp_buf		errshell;
- jmp_buf		INTbuf;
  
  /* fault handling */
  #include	"brkincr.h"

--- 353,358 -----
  #endif
  jmp_buf		subshell;
  jmp_buf		errshell;
  
  /* fault handling */
  #include	"brkincr.h"
***************
*** 229,235
  POS		brkincr;
  
  #define MINTRAP	0
! #define MAXTRAP	17
  
  #define INTR	2
  #define QUIT	3

--- 359,369 -----
  POS		brkincr;
  
  #define MINTRAP	0
! #if JOBS
! #define MAXTRAP	32
! #else
! #define MAXTRAP	20
! #endif
  
  #define HANGUP	1
  #define INTR	2
***************
*** 231,236
  #define MINTRAP	0
  #define MAXTRAP	17
  
  #define INTR	2
  #define QUIT	3
  #define MEMF	11

--- 365,371 -----
  #define MAXTRAP	20
  #endif
  
+ #define HANGUP	1
  #define INTR	2
  #define QUIT	3
  #define MEMF	11
***************
*** 236,241
  #define MEMF	11
  #define ALARM	14
  #define KILL	15
  #define TRAPSET	2
  #define SIGSET	4
  #define SIGMOD	8

--- 371,382 -----
  #define MEMF	11
  #define ALARM	14
  #define KILL	15
+ #if JOBS
+ #define STOP	17
+ #define TSTP	18
+ #define TTIN	21
+ #define	TTOU	22
+ #endif
  #define TRAPSET	2
  #define SIGSET	4
  #define SIGMOD	8
***************
*** 239,244
  #define TRAPSET	2
  #define SIGSET	4
  #define SIGMOD	8
  
  VOID		fault();
  BOOL		trapnote;

--- 380,386 -----
  #define TRAPSET	2
  #define SIGSET	4
  #define SIGMOD	8
+ #define SIGCAUGHT	16
  
  #define HISTSIZE	4096
  
***************
*** 240,245
  #define SIGSET	4
  #define SIGMOD	8
  
  VOID		fault();
  BOOL		trapnote;
  STRING		trapcom[];

--- 382,389 -----
  #define SIGMOD	8
  #define SIGCAUGHT	16
  
+ #define HISTSIZE	4096
+ 
  VOID		fault();
  BOOL		trapnote;
  STRING		trapcom[];
***************
*** 244,250
  BOOL		trapnote;
  STRING		trapcom[];
  BOOL		trapflg[];
- BOOL		trapjmp[];
  
  /* name tree and words */
  STRING		*environ;

--- 388,393 -----
  BOOL		trapnote;
  STRING		trapcom[];
  BOOL		trapflg[];
  
  /* name tree and words */
  STRING		*environ;
***************
*** 289,291
  
  #include	"ctype.h"
  

--- 432,438 -----
  
  #include	"ctype.h"
  
+ INT		wasintr;
+ INT		eflag;
+ INT		stripflg;
+ INT		rwait;
:::::::: dup.h :::::::
No differences encountered
:::::::: error.c :::::::
*** ../orig.u/error.c	Wed May 15 17:13:44 1985
--- error.c	Thu May 30 15:55:20 1985
***************
*** 28,34
  	 * no trap has been set.
  	 */
  	IF trapnote&SIGSET
! 	THEN	exitsh(SIGFAIL);
  	FI
  }
  

--- 28,34 -----
  	 * no trap has been set.
  	 */
  	IF trapnote&SIGSET
! 	THEN	exitsh(exitval ? exitval : SIGFAIL);
  	FI
  }
  
***************
*** 59,64
  	 * Action is to return to command level or exit.
  	 */
  	exitval=xno;
  	IF (flags & (forked|errflg|ttyflg)) != ttyflg
  	THEN	done();
  	ELSE	clearup();

--- 59,65 -----
  	 * Action is to return to command level or exit.
  	 */
  	exitval=xno;
+ 	flags |= eflag;
  	IF (flags & (forked|errflg|ttyflg)) != ttyflg
  	THEN	done();
  	ELSE	clearup();
***************
*** 62,67
  	IF (flags & (forked|errflg|ttyflg)) != ttyflg
  	THEN	done();
  	ELSE	clearup();
  		longjmp(errshell,1);
  	FI
  }

--- 63,69 -----
  	IF (flags & (forked|errflg|ttyflg)) != ttyflg
  	THEN	done();
  	ELSE	clearup();
+ 		execbrk = breakcnt = 0;
  		longjmp(errshell,1);
  	FI
  }
***************
*** 74,79
  		execexp(t,0);
  	FI
  	rmtemp(0);
  	exit(exitval);
  }
  

--- 76,82 -----
  		execexp(t,0);
  	FI
  	rmtemp(0);
+ 	histsave (histfnod.namval);
  	exit(exitval);
  }
  
:::::::: expand.c :::::::
*** ../orig.u/expand.c	Wed May 15 17:13:44 1985
--- expand.c	Tue Jun  4 17:29:43 1985
***************
*** 48,61
  
  	/* check for meta chars */
  	BEGIN
! 	   REG BOOL slash; slash=0;
! 	   WHILE !fngchar(*cs)
! 	   DO	IF *cs++==0
! 		THEN	IF rflg ANDF slash THEN break; ELSE return(0) FI
! 		ELIF *cs=='/'
! 		THEN	slash++;
! 		FI
! 	   OD
  	END
  
  	LOOP	IF cs==s

--- 48,79 -----
  
  	/* check for meta chars */
  	BEGIN
! 	   REG BOOL slash, open; open=slash=0;
! 	   REP
! 		SWITCH *cs++ IN
! 		case 0:		IF rflg ANDF slash THEN break;
! 				ELSE return 0;
! 				FI
! 		
! 		case '/':	slash++;
! 				open = 0;
! 				continue;
! 		
! 		case '[':	open++;
! 				continue;
! 
! 		case ']':	IF open THEN break FI
! 				continue;
! 		
! 		case '?':
! 		case '*':
! 				cs--;
! 				break;
! 		
! 		default:	continue;
! 		ENDSW
! 		break;
! 	   PER TRUE DONE
  	END
  
  	LOOP	IF cs==s
***************
*** 67,73
  			break;
  		FI
  	POOL
! 	IF stat(s,&statb)>=0
  	    ANDF (statb.st_mode&S_IFMT)==S_IFDIR
  	    ANDF (dirf=opendir(s)) != NULL
  	THEN	dir++;

--- 85,92 -----
  			break;
  		FI
  	POOL
! 	chgquot(s, 0);
! 	IF stat(*s ? s : ".",&statb)>=0	/* DAG */
  	    ANDF (statb.st_mode&S_IFMT)==S_IFDIR
  	    ANDF (dirf=opendir(*s ? s : ".")) != NULL	/* DAG -- fixed Berkeley bug */
  	THEN	dir++;
***************
*** 69,75
  	POOL
  	IF stat(s,&statb)>=0
  	    ANDF (statb.st_mode&S_IFMT)==S_IFDIR
! 	    ANDF (dirf=opendir(s)) != NULL
  	THEN	dir++;
  	FI
  	count=0;

--- 88,94 -----
  	chgquot(s, 0);
  	IF stat(*s ? s : ".",&statb)>=0	/* DAG */
  	    ANDF (statb.st_mode&S_IFMT)==S_IFDIR
! 	    ANDF (dirf=opendir(*s ? s : ".")) != NULL	/* DAG -- fixed Berkeley bug */
  	THEN	dir++;
  	FI
  	chgquot(s, 1);
***************
*** 72,77
  	    ANDF (dirf=opendir(s)) != NULL
  	THEN	dir++;
  	FI
  	count=0;
  	IF *cs==0 THEN *cs++=0200 FI
  	IF dir

--- 91,97 -----
  	    ANDF (dirf=opendir(*s ? s : ".")) != NULL	/* DAG -- fixed Berkeley bug */
  	THEN	dir++;
  	FI
+ 	chgquot(s, 1);
  	count=0;
  	IF *cs==0 THEN *cs++=0200 FI
  	IF dir
***************
*** 81,89
  		REP	IF *rs=='/' THEN rescan=rs; *rs=0; gchain=0 FI
  		PER	*rs++ DONE
  
! 		IF setjmp(INTbuf) == 0 THEN trapjmp[INTR] = 1; FI
! 		WHILE (trapnote&SIGSET) == 0 ANDF (dp = readdir(dirf)) != NULL
! 		DO	IF (*dp->d_name=='.' ANDF *cs!='.')
  			THEN	continue;
  			FI
  			IF gmatch(dp->d_name, cs)

--- 101,108 -----
  		REP	IF *rs=='/' THEN rescan=rs; *rs=0; gchain=0 FI
  		PER	*rs++ DONE
  
! 		WHILE (dp = readdir(dirf)) ANDF (trapnote&SIGSET) == 0
! 		DO	IF *dp->d_name=='.' ANDF *cs!='.'
  			THEN	continue;
  			FI
  /*
***************
*** 86,91
  		DO	IF (*dp->d_name=='.' ANDF *cs!='.')
  			THEN	continue;
  			FI
  			IF gmatch(dp->d_name, cs)
  			THEN	addg(s,dp->d_name,rescan); count++;
  			FI

--- 105,115 -----
  		DO	IF *dp->d_name=='.' ANDF *cs!='.'
  			THEN	continue;
  			FI
+ /*
+  *	Here lies the fix for the "echo * /." problem when
+  *	there are files with metacharacters in their names.
+  */
+ 			chgquot(dp->d_name, 1);
  			IF gmatch(dp->d_name, cs)
  			THEN	addg(s,dp->d_name,rescan); count++;
  			FI
***************
*** 89,94
  			IF gmatch(dp->d_name, cs)
  			THEN	addg(s,dp->d_name,rescan); count++;
  			FI
  		OD
  		closedir(dirf); trapjmp[INTR] = 0;
  

--- 113,119 -----
  			IF gmatch(dp->d_name, cs)
  			THEN	addg(s,dp->d_name,rescan); count++;
  			FI
+ 			chgquot(dp->d_name, 0);
  		OD
  		closedir(dirf);
  
***************
*** 90,96
  			THEN	addg(s,dp->d_name,rescan); count++;
  			FI
  		OD
! 		closedir(dirf); trapjmp[INTR] = 0;
  
  		IF rescan
  		THEN	REG ARGPTR	rchain;

--- 115,121 -----
  			FI
  			chgquot(dp->d_name, 0);
  		OD
! 		closedir(dirf);
  
  		IF rescan
  		THEN	REG ARGPTR	rchain;
***************
*** 129,135
  	SWITCH c = *p++ IN
  
  	    case '[':
! 		{BOOL ok; INT lc;
  		ok=0; lc=077777;
  		WHILE c = *p++
  		DO	IF c==']'

--- 154,160 -----
  	SWITCH c = *p++ IN
  
  	    case '[':
! 		{BOOL ok; INT lc; INT notflag=0;
  		ok=0; lc=077777;
  		IF *p == '!' THEN notflag=1; p++; FI
  		WHILE c = *p++
***************
*** 131,136
  	    case '[':
  		{BOOL ok; INT lc;
  		ok=0; lc=077777;
  		WHILE c = *p++
  		DO	IF c==']'
  			THEN	return(ok?gmatch(s,p):0);

--- 156,162 -----
  	    case '[':
  		{BOOL ok; INT lc; INT notflag=0;
  		ok=0; lc=077777;
+ 		IF *p == '!' THEN notflag=1; p++; FI
  		WHILE c = *p++
  		DO	IF c==']'
  			THEN	return(ok?gmatch(s,p):0);
***************
*** 135,142
  		DO	IF c==']'
  			THEN	return(ok?gmatch(s,p):0);
  			ELIF c==MINUS
! 			THEN	IF lc<=scc ANDF scc<=(*p++) THEN ok++ FI
! 			ELSE	IF scc==(lc=(c&STRIP)) THEN ok++ FI
  			FI
  		OD
  		return(0);

--- 161,180 -----
  		DO	IF c==']'
  			THEN	return(ok?gmatch(s,p):0);
  			ELIF c==MINUS
! 			THEN	IF notflag
! 				THEN	IF lc>scc ORF scc>*(p++)
! 					THEN ok++;
! 					ELSE return(0)
! 					FI
! 				ELSE IF lc<=scc ANDF scc<=(*p++) THEN ok++ FI
! 				FI
! 			ELSE	IF notflag
! 				THEN	IF scc!=(lc=(c&STRIP))
! 					THEN ok++;
! 					ELSE return(0)
! 					FI
! 				ELSE IF scc==(lc=(c&STRIP)) THEN ok++ FI
! 				FI
  			FI
  		OD
  		return(0);
***************
*** 192,194
  	gchain=args;
  }
  

--- 230,258 -----
  	gchain=args;
  }
  
+ chgquot(str, flg)
+ REG STRING	str;
+ REG INT		flg;
+ {
+ 	REG INT i;
+ 
+ 	FOR i = 0 ; ; i++
+ 	DO
+ 		SWITCH str[i] IN
+ 		case '\0':
+ 			return;
+ 		case '*':
+ 		case '?':
+ 		case '[':
+ 		case '*'|0200:
+ 		case '?'|0200:
+ 		case '['|0200:
+ 			IF flg==0
+ 			THEN
+ 				str[i] &= (~QUOTE);
+ 			ELSE
+ 				str[i] |= QUOTE;
+ 			FI
+ 		ENDSW
+ 	OD
+ }
:::::::: fault.c :::::::
*** ../orig.u/fault.c	Wed May 15 17:13:44 1985
--- fault.c	Tue Jun  4 13:44:16 1985
***************
*** 15,22
  
  
  STRING		trapcom[MAXTRAP];
! BOOL		trapflg[MAXTRAP];
! BOOL		trapjmp[MAXTRAP];
  
  /* ========	fault handling routines	   ======== */
  

--- 15,42 -----
  
  
  STRING		trapcom[MAXTRAP];
! BOOL	trapflg[MAXTRAP] = {
! 				0,
! 				SIGCAUGHT,	/* hangup */
! 				SIGCAUGHT,	/* interrupt */
! 				SIGCAUGHT,	/* quit */
! 				0,		/* illegal instr */
! 				0,		/* trace trap */
! 				0,		/* IOT */
! 				0,		/* EMT */
! 				0,		/* float pt. exp */
! 				0,		/* kill */
! 				0,		/* bus error */
! 				0,		/* memory faults */
! 				0,		/* bad sys call */
! 				0,		/* bad pipe call */
! 				SIGCAUGHT,	/* alarm */
! 				SIGCAUGHT,	/* software termination */
! 				0,		/* unassigned */
! 				0,		/* unassigned */
! 				0,		/* death of a child */
! 				0,		/* power fail */
! 				};
  
  /* ========	fault handling routines	   ======== */
  
***************
*** 26,31
  {
  	REG INT		flag;
  
  	IF sig==MEMF
  	THEN	IF setbrk(brkincr) == -1
  		THEN	error(nospace);

--- 46,52 -----
  {
  	REG INT		flag;
  
+ 	signal(sig, fault);
  	IF sig==MEMF
  	THEN	IF setbrk(brkincr) == -1
  		THEN	error(nospace);
***************
*** 32,38
  		FI
  	ELIF sig==ALARM
  	THEN	IF flags&waiting
! 		THEN	done();
  		FI
  	ELSE	flag = (trapcom[sig] ? TRAPSET : SIGSET);
  		trapnote |= flag;

--- 53,59 -----
  		FI
  	ELIF sig==ALARM
  	THEN	IF flags&waiting
! 		THEN	newline(); done();
  		FI
  	ELSE	flag = (trapcom[sig] ? TRAPSET : SIGSET);
  		trapnote |= flag;
***************
*** 37,42
  	ELSE	flag = (trapcom[sig] ? TRAPSET : SIGSET);
  		trapnote |= flag;
  		trapflg[sig] |= flag;
  	FI
  	IF trapjmp[sig] ANDF sig==INTR
  	THEN

--- 58,64 -----
  	ELSE	flag = (trapcom[sig] ? TRAPSET : SIGSET);
  		trapnote |= flag;
  		trapflg[sig] |= flag;
+ 		IF sig == INTR THEN wasintr++; FI
  	FI
  }
  
***************
*** 38,48
  		trapnote |= flag;
  		trapflg[sig] |= flag;
  	FI
- 	IF trapjmp[sig] ANDF sig==INTR
- 	THEN
- 		trapjmp[sig] = 0;
- 		longjmp(INTbuf, 1);
- 	FI
  }
  
  stdsigs()

--- 60,65 -----
  		trapflg[sig] |= flag;
  		IF sig == INTR THEN wasintr++; FI
  	FI
  }
  
  stdsigs()
***************
*** 47,52
  
  stdsigs()
  {
  	ignsig(QUIT);
  	getsig(INTR);
  	getsig(MEMF);

--- 64,70 -----
  
  stdsigs()
  {
+ 	signal(MEMF, fault);
  	ignsig(QUIT);
  	getsig(INTR);
  	getsig(ALARM);
***************
*** 49,55
  {
  	ignsig(QUIT);
  	getsig(INTR);
- 	getsig(MEMF);
  	getsig(ALARM);
  }
  

--- 67,72 -----
  	signal(MEMF, fault);
  	ignsig(QUIT);
  	getsig(INTR);
  	getsig(ALARM);
  }
  
***************
*** 57,63
  {
  	REG INT		s, i;
  
! 	IF (s=signal(i=n,1)&01)==0
  	THEN	trapflg[i] |= SIGMOD;
  	FI
  	return(s);

--- 74,83 -----
  {
  	REG INT		s, i;
  
! 	IF (i=n)==MEMF
! 	THEN	clrsig(i);
! 		failed(badtrap, "cannot trap 11");
! 	ELIF (s=signal(i,1)&01)==0
  	THEN	trapflg[i] |= SIGMOD;
  	FI
  	return(s);
***************
*** 93,99
  {
  	free(trapcom[i]); trapcom[i]=0;
  	IF trapflg[i]&SIGMOD
! 	THEN	signal(i,fault);
  		trapflg[i] &= ~SIGMOD;
  	FI
  }

--- 113,122 -----
  {
  	free(trapcom[i]); trapcom[i]=0;
  	IF trapflg[i]&SIGMOD
! 	THEN	IF trapflg[i]&SIGCAUGHT
! 		THEN signal(i,fault);
! 		ELSE signal(i,0);
! 		FI
  		trapflg[i] &= ~SIGMOD;
  	FI
  }
:::::::: io.c :::::::
*** ../orig.u/io.c	Wed May 15 17:13:45 1985
--- io.c	Mon Jun  3 17:03:11 1985
***************
*** 22,28
  {
  	REG FILE	f=standin;
  
! 	f->fdes=fd; f->fsiz=((flags&(oneflg|ttyflg))==0 ? BUFSIZ : 1);
  	f->fnxt=f->fend=f->fbuf; f->feval=0; f->flin=1;
  	f->feof=FALSE;
  }

--- 22,28 -----
  {
  	REG FILE	f=standin;
  
! 	f->fdes=fd; f->fsiz=((flags&oneflg)==0 ? BUFSIZ : 1);
  	f->fnxt=f->fend=f->fbuf; f->feval=0; f->flin=1;
  	f->feof=FALSE;
  }
***************
*** 60,65
  	FI
  }
  
  chkpipe(pv)
  	INT		*pv;
  {

--- 60,86 -----
  	FI
  }
  
+ TEMPBPTR	tmpfptr;
+ 
+ pushtemp(fd, tb)
+ 	UFD	fd;
+ 	TEMPBPTR	tb;
+ {
+ 	tb->fdes = fd;
+ 	tb->fstak = tmpfptr;
+ 	tmpfptr = tb;
+ }
+ 
+ poptemp()
+ {
+ 	IF tmpfptr
+ 	THEN	close(tmpfptr->fdes);
+ 		tmpfptr = tmpfptr->fstak;
+ 		return(TRUE);
+ 	ELSE	return (FALSE);
+ 	FI
+ }
+ 
  chkpipe(pv)
  	INT		*pv;
  {
***************
*** 100,106
  	FI
  }
  
! tmpfil()
  {
  	itos(serial++); movstr(numbuf,tmpnam);
  	return(create(tmpout));

--- 121,128 -----
  	FI
  }
  
! tmpfil(tb)
! 	TEMPBPTR tb;
  {
  	INT fd;
  
***************
*** 102,107
  
  tmpfil()
  {
  	itos(serial++); movstr(numbuf,tmpnam);
  	return(create(tmpout));
  }

--- 124,131 -----
  tmpfil(tb)
  	TEMPBPTR tb;
  {
+ 	INT fd;
+ 
  	itos(serial++); movstr(numbuf,tmpnam);
  	fd = create(tmpout);
  	pushtemp(fd, tb);
***************
*** 103,109
  tmpfil()
  {
  	itos(serial++); movstr(numbuf,tmpnam);
! 	return(create(tmpout));
  }
  
  /* set by trim */

--- 127,135 -----
  	INT fd;
  
  	itos(serial++); movstr(numbuf,tmpnam);
! 	fd = create(tmpout);
! 	pushtemp(fd, tb);
! 	return (fd);
  }
  
  /* set by trim */
***************
*** 118,124
  	REG IOPTR	iop;
  
  	IF iop=ioparg
! 	THEN	copy(iop->iolst);
  		ends=mactrim(iop->ioname); IF nosubst THEN iop->iofile &= ~IODOC FI
  		fd=tmpfil();
  		iop->ioname=cpystak(tmpout);

--- 144,151 -----
  	REG IOPTR	iop;
  
  	IF iop=ioparg
! 	THEN	TEMPBLK	tb;
! 		copy(iop->iolst);
  		ends=mactrim(iop->ioname); IF nosubst THEN iop->iofile &= ~IODOC FI
  		fd=tmpfil(&tb);
  		iop->ioname=cpystak(tmpout);
***************
*** 120,126
  	IF iop=ioparg
  	THEN	copy(iop->iolst);
  		ends=mactrim(iop->ioname); IF nosubst THEN iop->iofile &= ~IODOC FI
! 		fd=tmpfil();
  		iop->ioname=cpystak(tmpout);
  		iop->iolst=iotemp; iotemp=iop;
  		cline=locstak();

--- 147,153 -----
  	THEN	TEMPBLK	tb;
  		copy(iop->iolst);
  		ends=mactrim(iop->ioname); IF nosubst THEN iop->iofile &= ~IODOC FI
! 		fd=tmpfil(&tb);
  		iop->ioname=cpystak(tmpout);
  		iop->iolst=iotemp; iotemp=iop;
  		cline=locstak();
***************
*** 125,130
  		iop->iolst=iotemp; iotemp=iop;
  		cline=locstak();
  
  		LOOP	clinep=cline; chkpr(NL);
  			WHILE (c = (nosubst ? readc() :  nextc(*ends)),  !eolchar(c)) DO *clinep++ = c OD
  			*clinep=0;

--- 152,160 -----
  		iop->iolst=iotemp; iotemp=iop;
  		cline=locstak();
  
+ 		IF stripflg
+ 		THEN	WHILE *ends=='\t' DO ends++ OD
+ 		FI
  		LOOP	clinep=cline; chkpr(NL);
  			IF stripflg
  			THEN
***************
*** 126,132
  		cline=locstak();
  
  		LOOP	clinep=cline; chkpr(NL);
! 			WHILE (c = (nosubst ? readc() :  nextc(*ends)),  !eolchar(c)) DO *clinep++ = c OD
  			*clinep=0;
  			IF eof ORF eq(cline,ends) THEN break FI
  			*clinep++=NL;

--- 156,172 -----
  		THEN	WHILE *ends=='\t' DO ends++ OD
  		FI
  		LOOP	clinep=cline; chkpr(NL);
! 			IF stripflg
! 			THEN
! 				WHILE (c=(nosubst ? readc() : nextc(*ends)), !eolchar(c))
! 				&& cline == clinep && c == '\t' DONE
! 				WHILE (!eolchar(c))
! 				DO
! 					*clinep++=c;
! 					c=(nosubst ? readc() : nextc(*ends));
! 				OD
! 			ELSE WHILE (c = (nosubst ? readc() :  nextc(*ends)),  !eolchar(c)) DO *clinep++ = c OD
! 			FI
  			*clinep=0;
  			IF eof ORF eq(cline,ends) THEN break FI
  			*clinep++=NL;
***************
*** 132,137
  			*clinep++=NL;
  			write(fd,cline,clinep-cline);
  		POOL
! 		close(fd);
  	FI
  }

--- 172,179 -----
  			*clinep++=NL;
  			write(fd,cline,clinep-cline);
  		POOL
! 		IF stripflg THEN stripflg-- FI
! 		poptemp();	/* pushed in tmpfil -- bug fix for problem
! 				   deleting in-line scripts */
  	FI
  }
:::::::: mac.h :::::::
*** ../orig.u/mac.h	Wed May 15 17:13:45 1985
--- mac.h	Thu May 30 16:54:52 1985
***************
*** 59,63
  #define RQ	'\''
  #define MINUS	'-'
  #define COLON	':'
  
  #define MAX(a,b)	((a)>(b)?(a):(b))

--- 59,64 -----
  #define RQ	'\''
  #define MINUS	'-'
  #define COLON	':'
+ #define SQUIGGLE	'~'	/* BSD tty driver defines TILDE */
  
  #define MAX(a,b)	((a)>(b)?(a):(b))
:::::::: macro.c :::::::
*** ../orig.u/macro.c	Wed May 15 17:13:45 1985
--- macro.c	Tue Jun  4 10:25:36 1985
***************
*** 60,65
  	IF !subchar(d)
  	THEN	return(d);
  	FI
  	IF d==DOLLAR
  	THEN	REG INT	c;
  		IF (c=readc(), dolchar(c))

--- 60,79 -----
  	IF !subchar(d)
  	THEN	return(d);
  	FI
+ #if JOBS
+ 	IF d==PERCENT ANDF (flags&jobflg)
+ 	THEN	REG INT c;
+ 		IF (peekc = (c=readc())|MARK, digchar(c) ORF c==PERCENT)
+ 		THEN	REG STRING v;
+ 
+ 			IF v=j_macro()	/* %number or %% handled */
+ 			THEN	WHILE c = *v++ DO pushstak(c|quote); OD
+ 			/* else expands to nothingness */
+ 			FI
+ 			goto retry;
+ 		FI
+ 	ELIF d==DOLLAR
+ #else
  	IF d==DOLLAR
  #endif
  	THEN	REG INT	c;
***************
*** 61,66
  	THEN	return(d);
  	FI
  	IF d==DOLLAR
  	THEN	REG INT	c;
  		IF (c=readc(), dolchar(c))
  		THEN	NAMPTR		n=NIL;

--- 75,81 -----
  	ELIF d==DOLLAR
  #else
  	IF d==DOLLAR
+ #endif
  	THEN	REG INT	c;
  		IF (c=readc(), dolchar(c))
  		THEN	NAMPTR		n=NIL;
***************
*** 66,71
  		THEN	NAMPTR		n=NIL;
  			INT		dolg=0;
  			BOOL		bra;
  			REG STRING	argp, v;
  			CHAR		idb[2];
  			STRING		id=idb;

--- 81,87 -----
  		THEN	NAMPTR		n=NIL;
  			INT		dolg=0;
  			BOOL		bra;
+ 			BOOL		nulflg;
  			REG STRING	argp, v;
  			CHAR		idb[2];
  			STRING		id=idb;
***************
*** 87,92
  				v=((c==0) ? cmdadr : (c<=dolc) ? dolv[c] : (dolg=0));
  			ELIF c=='$'
  			THEN	v=pidadr;
  			ELIF c=='!'
  			THEN	v=pcsadr;
  			ELIF c=='#'

--- 103,114 -----
  				v=((c==0) ? cmdadr : (c<=dolc) ? dolv[c] : (dolg=0));
  			ELIF c=='$'
  			THEN	v=pidadr;
+ 			ELIF c=='+'
+ 			THEN	IF ppid != getppid()	/* parent died */
+ 				THEN	ppid = getppid();
+ 					assnum (&ppidadr, ppid);
+ 				FI
+ 				v = ppidadr;
  			ELIF c=='!'
  			THEN	v=pcsadr;
  			ELIF c=='#'
***************
*** 99,104
  			ELSE	goto retry;
  			FI
  			c = readc();
  			IF !defchar(c) ANDF bra
  			THEN	error(badsub);
  			FI

--- 121,130 -----
  			ELSE	goto retry;
  			FI
  			c = readc();
+ 			IF c==':' ANDF bra	/* null and unset fix */
+ 			THEN	nulflg=1; c=readc();
+ 			ELSE	nulflg=0;
+ 			FI
  			IF !defchar(c) ANDF bra
  			THEN	error(badsub);
  			FI
***************
*** 106,112
  			IF bra
  			THEN	IF c!='}'
  				THEN	argp=relstak();
! 					IF (v==0)NEQ(setchar(c))
  					THEN	copyto('}');
  					ELSE	skipto('}');
  					FI

--- 132,138 -----
  			IF bra
  			THEN	IF c!='}'
  				THEN	argp=relstak();
! 					IF (v==0 ORF (nulflg ANDF *v==0))NEQ(setchar(c))
  					THEN	copyto('}');
  					ELSE	skipto('}');
  					FI
***************
*** 114,120
  				FI
  			ELSE	peekc = c|MARK; c = 0;
  			FI
! 			IF v
  			THEN	IF c!='+'
  				THEN	LOOP WHILE c = *v++
  					     DO pushstak(c|quote); OD

--- 140,146 -----
  				FI
  			ELSE	peekc = c|MARK; c = 0;
  			FI
! 			IF v ANDF (!nulflg ORF *v)
  			THEN	IF c!='+'
  				THEN	LOOP WHILE c = *v++
  					     DO pushstak(c|quote); OD
***************
*** 129,135
  				THEN	failed(id,*argp?argp:badparam);
  				ELIF c=='='
  				THEN	IF n
! 					THEN	assign(n,argp);
  					ELSE	error(badsub);
  					FI
  				FI

--- 155,162 -----
  				THEN	failed(id,*argp?argp:badparam);
  				ELIF c=='='
  				THEN	IF n
! 					THEN	trim(argp);
! 						assign(n,argp);
  					ELSE	error(badsub);
  					FI
  				FI
***************
*** 185,190
  	   trim(argc=fixstak());
  	   push(&cb); estabf(argc);
  	END
  	BEGIN
  	   REG TREPTR	t = makefork(FPOU,cmd(EOFSYM,MTFLG|NLFLG));
  	   INT		pv[2];

--- 212,220 -----
  	   trim(argc=fixstak());
  	   push(&cb); estabf(argc);
  	END
+ #if JOBS
+ 	set_wfence();
+ #endif
  	BEGIN
  	   REG TREPTR	t = makefork(FPOU,cmd(EOFSYM,MTFLG|NLFLG));
  	   INT		pv[2];
***************
*** 194,200
  	    */
  	   chkpipe(pv);
  	   initf(pv[INPIPE]);
! 	   execute(t, 0, 0, pv);
  	   close(pv[OTPIPE]);
  	END
  	tdystak(savptr); staktop=movstr(savptr,stakbot);

--- 224,230 -----
  	    */
  	   chkpipe(pv);
  	   initf(pv[INPIPE]);
! 	   execute(t, 0, flags & errflg, 0, pv);
  	   close(pv[OTPIPE]);
  	END
  	tdystak(savptr); staktop=movstr(savptr,stakbot);
***************
*** 198,205
  	   close(pv[OTPIPE]);
  	END
  	tdystak(savptr); staktop=movstr(savptr,stakbot);
! 	WHILE d=readc() DO locstak(); pushstak(d|quote) OD
! 	await(0);
  	WHILE stakbot!=staktop
  	DO	IF (*--staktop&STRIP)!=NL
  		THEN	++staktop; break;

--- 228,235 -----
  	   close(pv[OTPIPE]);
  	END
  	tdystak(savptr); staktop=movstr(savptr,stakbot);
! 	WHILE d=readc() DO pushstak(d|quote) OD
! 	await(0, 0);
  	WHILE stakbot!=staktop
  	DO	IF (*--staktop&STRIP)!=NL
  		THEN	++staktop; break;
:::::::: main.c :::::::
*** ../orig.u/main.c	Wed May 15 17:13:45 1985
--- main.c	Tue Jun  4 14:32:21 1985
***************
*** 24,29
  CHAR		tmpout[20] = "/tmp/sh-";
  FILEBLK		stdfile;
  FILE		standin = &stdfile;
  #ifdef stupid
  #include	<execargs.h>
  #endif

--- 24,30 -----
  CHAR		tmpout[20] = "/tmp/sh-";
  FILEBLK		stdfile;
  FILE		standin = &stdfile;
+ BOOL		catcheof = FALSE;
  #ifdef stupid
  #include	<execargs.h>
  #endif
***************
*** 33,39
  
  
  
! main(c, v)
  	INT		c;
  	STRING		v[];
  {

--- 34,40 -----
  
  
  
! main(c, v, e)
  	INT		c;
  	STRING		v[];
  	STRING		e[];
***************
*** 36,41
  main(c, v)
  	INT		c;
  	STRING		v[];
  {
  	REG INT		rflag=ttyflg;
  

--- 37,43 -----
  main(c, v, e)
  	INT		c;
  	STRING		v[];
+ 	STRING		e[];
  {
  	REG INT		rflag=ttyflg;
  	STRING	sim;
***************
*** 38,43
  	STRING		v[];
  {
  	REG INT		rflag=ttyflg;
  
  	/* initialise storage allocation */
  	stdsigs();

--- 40,46 -----
  	STRING		e[];
  {
  	REG INT		rflag=ttyflg;
+ 	STRING	sim;
  
  	/* initialise storage allocation */
  	stdsigs();
***************
*** 58,63
  	FI
  	dolv=v+c-dolc; dolc--;
  
  	/* return here for shell file execution */
  	setjmp(subshell);
  

--- 61,84 -----
  	FI
  	dolv=v+c-dolc; dolc--;
  
+ #if JOBS
+ 	j_default_pg = getpid();
+ 	j_original_pg = getpgrp();
+ 	/* enable job control if argv[0] has a 'j' in its simple name */
+ 
+ 	IF (flags & jobflg) == 0 ANDF c > 0 ANDF any('j', simple(*v))
+ 		ANDF comdiv == 0 ANDF flags & stdflg
+ 	THEN
+ 		STRING	pointer;
+ 
+ 		j_init();
+ 		flags |= jobflg;
+ 		pointer = flagadr;
+ 		WHILE *pointer DO pointer++; OD
+ 		*pointer++ = 'J'; *pointer = 0;
+ 	FI
+ #endif
+ 
  	/* return here for shell file execution */
  	/* but not for parenthesis subshells	*/
  	setjmp(subshell);
***************
*** 59,64
  	dolv=v+c-dolc; dolc--;
  
  	/* return here for shell file execution */
  	setjmp(subshell);
  
  	/* number of positional parameters */

--- 80,86 -----
  #endif
  
  	/* return here for shell file execution */
+ 	/* but not for parenthesis subshells	*/
  	setjmp(subshell);
  
  	/* number of positional parameters */
***************
*** 63,69
  
  	/* number of positional parameters */
  	assnum(&dolladr,dolc);
! 	cmdadr=dolv[0];
  
  	/* set pidname */
  	assnum(&pidadr, getpid());

--- 85,91 -----
  
  	/* number of positional parameters */
  	assnum(&dolladr,dolc);
! 	cmdadr=dolv[0];	/* cmdadr is $0 */
  
  	/* set pidname */
  	assnum(&pidadr, getpid());
***************
*** 68,73
  	/* set pidname */
  	assnum(&pidadr, getpid());
  
  	/* set up temp file names */
  	settmp();
  

--- 90,99 -----
  	/* set pidname */
  	assnum(&pidadr, getpid());
  
+ 	/* set ppidname */
+ 	ppid = getppid();
+ 	assnum(&ppidadr, ppid);
+ 
  	/* set up temp file names */
  	settmp();
  
***************
*** 74,80
  	/* default ifs */
  	dfault(&ifsnod, sptbnl);
  
! 	IF (beenhere++)==FALSE
  	THEN	/* ? profile */
  		IF *cmdadr=='-'
  		    ANDF (input=pathopen(nullstr, profile))>=0

--- 100,129 -----
  	/* default ifs */
  	dfault(&ifsnod, sptbnl);
  
! #if pyr
! 	/* find out current universe, initialize $UNIVERSE */
! 	cur_univ = setuniverse (U_UCB);	/* retrieve old and set to UCB */
! 	IF cur_univ == -1
! 	THEN	/* unknown current default to UCB */
! 		cur_univ = U_UCB;
! 		setuniverse (U_UCB);
! 	ELIF cur_univ != U_UCB
! 	THEN	setuniverse (cur_univ);	/* restore to what it was */
! 	FI
! 
! 	/* force value of UNIVERSE, ignore environment */
! 	univnod.namflg &= ~N_RDONLY;	/* for subshells ... */
! 	assign (&univnod, univ_name[cur_univ - 1]);
! 	attrib ((&univnod), N_RDONLY);
! #endif
! 
! 	/* assign default value to HISTFILE */
! 	(VOID) catpath("~", savehist);
! 	dfault (& histfnod, curstak());
! 
! 	event_count = 1;
! 
! 	IF beenhere==FALSE
  	THEN	/* ? profile */
  		beenhere++;	/* DAG -- only increment once */
  		IF *(sim = simple(cmdadr))=='-'
***************
*** 76,83
  
  	IF (beenhere++)==FALSE
  	THEN	/* ? profile */
! 		IF *cmdadr=='-'
! 		    ANDF (input=pathopen(nullstr, profile))>=0
  		THEN	exfile(rflag); flags &= ~ttyflg;
  		FI
  		IF rflag==0 THEN flags |= rshflg FI

--- 125,139 -----
  
  	IF beenhere==FALSE
  	THEN	/* ? profile */
! 		beenhere++;	/* DAG -- only increment once */
! 		IF *(sim = simple(cmdadr))=='-'
! 		THEN	IF getuid() != geteuid() THEN setuid(getuid()) FI
! 			IF getgid() != getegid() THEN setgid(getgid()) FI
! 		FI
! 
! 		/* to read /etc/profile, add code here */
! 
! 		IF *sim=='-' ANDF (input=pathopen(nullstr, profile))>=0
  		THEN	exfile(rflag); flags &= ~ttyflg;
  		FI
  		IF rflag==0 THEN flags |= rshflg FI
***************
*** 82,87
  		FI
  		IF rflag==0 THEN flags |= rshflg FI
  
  		/* open input file if specified */
  		IF comdiv
  		THEN	estabf(comdiv); input = -1;

--- 138,156 -----
  		FI
  		IF rflag==0 THEN flags |= rshflg FI
  
+ 		/* if all OK, process $HOME/.shrc */
+ 		IF geteuid() == getuid() ANDF getegid() == getgid()
+ 			ANDF (flags&(rshflg|quickflg)) == 0
+ 			ANDF (input = pathopen("~", shrc)) >= 0
+ 		THEN
+ 			INT promptflags = (flags & (ttyflg|intflg|prompt));
+ 
+ 			/* turn off anything that will cause prompting */
+ 			flags &= ~promptflags;
+ 			exfile(rflag);
+ 			flags |= promptflags;
+ 		FI
+ 
  		/* open input file if specified */
  		IF comdiv
  		THEN	estabf(comdiv); input = -1;
***************
*** 119,125
  	userid=getuid();
  
  	/* decide whether interactive */
! 	IF (flags&intflg) ORF ((flags&oneflg)==0 ANDF gtty(output,&statb)==0 ANDF gtty(input,&statb)==0)
  	THEN	dfault(&ps1nod, (userid?stdprompt:supprompt));
  		dfault(&ps2nod, readmsg);
  		flags |= ttyflg|prompt; ignsig(KILL);

--- 188,194 -----
  	userid=getuid();
  
  	/* decide whether interactive */
! 	IF (flags&intflg) ORF ((flags&oneflg)==0 ANDF isatty(output) ANDF isatty(input))
  	THEN	dfault(&ps1nod, (userid?stdprompt:supprompt));
  		dfault(&ps2nod, readmsg);
  		flags |= ttyflg|prompt; ignsig(KILL);
***************
*** 123,136
  	THEN	dfault(&ps1nod, (userid?stdprompt:supprompt));
  		dfault(&ps2nod, readmsg);
  		flags |= ttyflg|prompt; ignsig(KILL);
! /*
! 		{
! 	#include <signal.h>
! 		signal(SIGTTIN, SIG_IGN);
! 		signal(SIGTTOU, SIG_IGN);
! 		signal(SIGTSTP, SIG_IGN);
! 		}
! */
  	ELSE	flags |= prof; flags &= ~prompt;
  	FI
  

--- 192,199 -----
  	THEN	dfault(&ps1nod, (userid?stdprompt:supprompt));
  		dfault(&ps2nod, readmsg);
  		flags |= ttyflg|prompt; ignsig(KILL);
! 		/* restore previous history */
! 		histrest (histfnod.namval);
  	ELSE	flags |= prof; flags &= ~prompt;
  	FI
  
***************
*** 148,157
  		exitset();
  		IF (flags&prompt) ANDF standin->fstak==0 ANDF !eof
  		THEN	IF mailnod.namval
! 			    ANDF stat(mailnod.namval,&statb)>=0 ANDF statb.st_size
! 			    ANDF (statb.st_mtime != mailtime)
! 			    ANDF mailtime
! 			THEN	prs(mailmsg)
  			FI
  			mailtime=statb.st_mtime;
  			prs(ps1nod.namval);

--- 211,225 -----
  		exitset();
  		IF (flags&prompt) ANDF standin->fstak==0 ANDF !eof
  		THEN	IF mailnod.namval
! 			    ANDF *mailnod.namval
! 			THEN IF stat(mailnod.namval,&statb)>=0 ANDF statb.st_size
! 					ANDF mailtime
! 					ANDF (statb.st_mtime != mailtime)
! 				THEN	prs(mailmsg)
! 				FI
! 				mailtime=statb.st_mtime;
! 			ELIF mailtime==0
! 			THEN mailtime=1
  			FI
  			pr_prompt(ps1nod.namval);
  			IF userid==0 ANDF !eq(ps1nod.namval, supprompt)
***************
*** 153,160
  			    ANDF mailtime
  			THEN	prs(mailmsg)
  			FI
! 			mailtime=statb.st_mtime;
! 			prs(ps1nod.namval);
  		FI
  
  		trapnote=0; peekc=readc();

--- 221,230 -----
  			ELIF mailtime==0
  			THEN mailtime=1
  			FI
! 			pr_prompt(ps1nod.namval);
! 			IF userid==0 ANDF !eq(ps1nod.namval, supprompt)
! 			THEN	prs(supprompt);
! 			FI
  		FI
  
  		catcheof = TRUE;
***************
*** 157,162
  			prs(ps1nod.namval);
  		FI
  
  		trapnote=0; peekc=readc();
  		IF eof
  		THEN	return;

--- 227,233 -----
  			FI
  		FI
  
+ 		catcheof = TRUE;
  		trapnote=0; peekc=readc();
  		catcheof = FALSE;
  		IF eof
***************
*** 158,163
  		FI
  
  		trapnote=0; peekc=readc();
  		IF eof
  		THEN	return;
  		FI

--- 229,235 -----
  
  		catcheof = TRUE;
  		trapnote=0; peekc=readc();
+ 		catcheof = FALSE;
  		IF eof
  		THEN	return;
  		FI
***************
*** 161,167
  		IF eof
  		THEN	return;
  		FI
! 		execute(cmd(NL,MTFLG),0);
  		eof |= (flags&oneflg);
  	POOL
  }

--- 233,239 -----
  		IF eof
  		THEN	return;
  		FI
! 		execute(cmd(NL,MTFLG),0, eflag);
  		eof |= (flags&oneflg);
  	POOL
  }
:::::::: mode.h :::::::
*** ../orig.u/mode.h	Wed May 15 17:13:45 1985
--- mode.h	Thu May 30 17:59:10 1985
***************
*** 26,31
  STRUCT stat	STATBUF;	/* defined in /usr/sys/stat.h */
  STRUCT blk	*BLKPTR;
  STRUCT fileblk	FILEBLK;
  STRUCT filehdr	FILEHDR;
  STRUCT fileblk	*FILE;
  STRUCT trenod	*TREPTR;

--- 26,33 -----
  STRUCT stat	STATBUF;	/* defined in /usr/sys/stat.h */
  STRUCT blk	*BLKPTR;
  STRUCT fileblk	FILEBLK;
+ STRUCT tempblk	TEMPBLK;
+ STRUCT tempblk	*TEMPBPTR;
  STRUCT filehdr	FILEHDR;
  STRUCT fileblk	*FILE;
  STRUCT trenod	*TREPTR;
***************
*** 96,101
  	STRING	*feval;
  	FILE	fstak;
  	CHAR	fbuf[BUFSIZ];
  };
  
  /* for files not used with file descriptors */

--- 98,108 -----
  	STRING	*feval;
  	FILE	fstak;
  	CHAR	fbuf[BUFSIZ];
+ };
+ 
+ struct tempblk {
+ 	UFD	fdes;
+ 	struct	tempblk *fstak;
  };
  
  /* for files not used with file descriptors */
:::::::: msg.c :::::::
*** ../orig.u/msg.c	Wed May 15 17:13:45 1985
--- msg.c	Tue Jun  4 18:01:36 1985
***************
*** 15,20
  #include	"defs.h"
  #include	"sym.h"
  
  MSG		version = "\nVERSION sys137	DATE 1978 Nov 6 14:29:22\n";
  
  /* error messages */

--- 15,23 -----
  #include	"defs.h"
  #include	"sym.h"
  
+ #if JOBS
+ MSG	version = "@(#)Bourne shell, BRL + GT mods\t30-May-1985";
+ #else
  MSG		version = "\nVERSION sys137	DATE 1978 Nov 6 14:29:22\n";
  #endif
  
***************
*** 16,21
  #include	"sym.h"
  
  MSG		version = "\nVERSION sys137	DATE 1978 Nov 6 14:29:22\n";
  
  /* error messages */
  MSG	badopt		= "bad option(s)";

--- 19,25 -----
  MSG	version = "@(#)Bourne shell, BRL + GT mods\t30-May-1985";
  #else
  MSG		version = "\nVERSION sys137	DATE 1978 Nov 6 14:29:22\n";
+ #endif
  
  /* error messages */
  MSG	badopt		= "bad option(s)";
***************
*** 19,24
  
  /* error messages */
  MSG	badopt		= "bad option(s)";
  MSG	mailmsg		= "you have mail\n";
  MSG	nospace		= "no space";
  MSG	synmsg		= "syntax error";

--- 23,31 -----
  
  /* error messages */
  MSG	badopt		= "bad option(s)";
+ #if JOBS
+ MSG	mailmsg		= "You have new mail.\n";
+ #else
  MSG	mailmsg		= "you have mail\n";
  #endif
  MSG	nospace		= "no space";
***************
*** 20,25
  /* error messages */
  MSG	badopt		= "bad option(s)";
  MSG	mailmsg		= "you have mail\n";
  MSG	nospace		= "no space";
  MSG	synmsg		= "syntax error";
  

--- 27,33 -----
  MSG	mailmsg		= "You have new mail.\n";
  #else
  MSG	mailmsg		= "you have mail\n";
+ #endif
  MSG	nospace		= "no space";
  MSG	synmsg		= "syntax error";
  
***************
*** 52,57
  MSG	ifsname		= "IFS";
  MSG	ps1name		= "PS1";
  MSG	ps2name		= "PS2";
  
  /* string constants */
  MSG	nullstr		= "";

--- 60,69 -----
  MSG	ifsname		= "IFS";
  MSG	ps1name		= "PS1";
  MSG	ps2name		= "PS2";
+ #if pyr
+ MSG	univname	= "UNIVERSE";
+ #endif
+ MSG	histfilename	= "HISTFILE";
  
  /* string constants */
  MSG	nullstr		= "";
***************
*** 68,73
  MSG	stdprompt	= "$ ";
  MSG	supprompt	= "# ";
  MSG	profile		= ".profile";
  
  
  /* tables */

--- 80,138 -----
  MSG	stdprompt	= "$ ";
  MSG	supprompt	= "# ";
  MSG	profile		= ".profile";
+ MSG	shrc		= ".shrc";
+ MSG	savehist	= ".history";
+ MSG	dashi		= "-i";
+ #if pyr
+ MSG	dashl		= "-l";
+ #endif
+ MSG	dashr		= "-r";
+ MSG	dashs		= "-s";
+ #if JOBS
+ MSG	amperstr	= " &";				/* DAG */
+ MSG	andstr		= " && ";			/* DAG */
+ MSG	appdstr		= ">> ";
+ MSG	bgdstr		= "background \ \ \ \ \ \ ";
+ MSG	casestr		= "case ";			/* DAG */
+ MSG	cjpostr		= ": couldn't jpost\n";
+ MSG	fgdstr		= "foreground \ \ \ \ \ \ ";
+ MSG	forstr		= "for ";			/* DAG */
+ MSG	fromastr	= "<&";				/* DAG */
+ MSG	iesacstr	= " in ... esac";
+ MSG	ifstr		= "if ";			/* DAG */
+ MSG	inlnstr		= "<< ";
+ MSG	insstr		= " in ";
+ MSG	jcoffstr	= "job control not enabled\n";
+ MSG	jinvstr		= "invalid job number\n";
+ MSG	jpanstr		= "sh bug: j_print_ent--no number ";
+ MSG	lotspstr	= " \ \ \ \ \ \ \ \ \ ";
+ MSG	lpnstr		= "(";
+ MSG	ncjstr		= "no current job\n";
+ MSG	nstpstr		= ": not stopped\n";
+ MSG	orstr		= " || ";			/* DAG */
+ MSG	pipestr		= " | ";			/* DAG */
+ MSG	psgpstr		= " (signal) ";
+ MSG	ptinstr		= " (tty in) ";
+ MSG	ptoustr		= " (tty out)";
+ MSG	rdinstr		= "< ";
+ MSG	rpnstr		= ")";
+ MSG	rsqbrk		= "] ";
+ MSG	sdonstr		= "; done";
+ MSG	sdostr		= "; do ";
+ MSG	selsstr		= "; else ";
+ MSG	semspstr	= "; ";
+ MSG	sfistr		= "; fi";
+ MSG	spcstr		= " ";
+ MSG	spspstr		= " \ ";
+ MSG	sthnstr		= "; then ";
+ MSG	stpdstr		= "stopped";
+ MSG	tasjstr		= "There are stopped jobs.\n";
+ MSG	toastr		= ">&";				/* DAG */
+ MSG	untilstr	= "until ";			/* DAG */
+ MSG	whilestr	= "while ";			/* DAG */
+ MSG	rdwstr		= "<> ";			/* ADR */
+ MSG	nosusp		= "cannot suspend a login shell\n";	/* yet... */
+ #endif
  
  
  /* tables */
***************
*** 71,77
  
  
  /* tables */
! SYSTAB reserved {
  		{"in",		INSYM},
  		{"esac",	ESSYM},
  		{"case",	CASYM},

--- 136,142 -----
  
  
  /* tables */
! SYSTAB reserved  = {
  		{"in",		INSYM},
  		{"esac",	ESSYM},
  		{"case",	CASYM},
***************
*** 90,96
  		{0,	0},
  };
  
! STRING	sysmsg[] {
  		0,
  		"Hangup",
  		0,	/* Interrupt */

--- 155,161 -----
  		{0,	0},
  };
  
! STRING	sysmsg[] = {
  		0,
  		"Hangup",
  		0,	/* Interrupt */
***************
*** 97,103
  		"Quit",
  		"Illegal instruction",
  		"Trace/BPT trap",
! 		"IOT trap",
  		"EMT trap",
  		"Floating exception",
  		"Killed",

--- 162,168 -----
  		"Quit",
  		"Illegal instruction",
  		"Trace/BPT trap",
! 		"abort",
  		"EMT trap",
  		"Floating exception",
  		"Killed",
***************
*** 108,113
  		"Alarm call",
  		"Terminated",
  		"Signal 16",
  };
  
  MSG		export = "export";

--- 173,200 -----
  		"Alarm call",
  		"Terminated",
  		"Signal 16",
+ #if JOBS
+ 		"Stop",
+ 		"Stop from keyboard",
+ 		"Continue",
+ 		"Child status change",
+ 		"Background read",
+ 		"Background write",
+ 		"I/O possible",
+ 		"CPU time limit",
+ 		"File size limit",
+ 		"Virtual time alarm",
+ 		"Profiling timer alarm",
+ 		"Signal 28",
+ 		"Signal 29",
+ 		"Signal 30",
+ 		"Signal 31",
+ 		"Signal 32",
+ #else
+ 		"Signal 17",
+ 		"Signal 18",
+ 		"Signal 19",
+ #endif
  };
  
  MSG		export = "export";
***************
*** 112,118
  
  MSG		export = "export";
  MSG		readonly = "readonly";
! SYSTAB	commands {
  		{"cd",		SYSCD},
  		{"read",	SYSREAD},
  /*

--- 199,205 -----
  
  MSG		export = "export";
  MSG		readonly = "readonly";
! SYSTAB	commands = {
  		{"cd",		SYSCD},
  		{"read",	SYSREAD},
  /*
***************
*** 135,139
  		{"exec",	SYSEXEC},
  		{"times",	SYSTIMES},
  		{"umask",	SYSUMASK},
  		{0,	0},
  };

--- 222,239 -----
  		{"exec",	SYSEXEC},
  		{"times",	SYSTIMES},
  		{"umask",	SYSUMASK},
+ #if JOBS
+ 		{"jobs",	SYSJOBS},
+ 		{"fg",		SYSFG},
+ 		{"bg",		SYSBG},
+ 		{"suspend",	SYSSUSPEND},
+ #endif
+ #if pyr
+ 		{"att",		SYSATT},
+ 		{"ucb",		SYSUCB},
+ 		{"universe",	SYSUNIVERSE},
+ #endif
+ 		{"history",	SYSHISTORY},
  		{0,	0},
  };
  
***************
*** 137,139
  		{"umask",	SYSUMASK},
  		{0,	0},
  };

--- 236,244 -----
  		{"history",	SYSHISTORY},
  		{0,	0},
  };
+ 
+ #if pyr
+ #include <sys/types.h>	/* to get sys/inode.h to work (sigh) */
+ #include <sys/inode.h>	/* NUMUNIV is defined to be NCLNK */
+ #include <universe.h>	/* gets char *univ_name[] && char *univ_longname[] */
+ #endif

sources-request@genrad.UUCP (06/10/85)

From: Arnold Robbins <gatech!arnold>

This is part 3 of 9.  It contains the second set of code diffs for the BSD
Bourne shell.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
------------------- tear here --------------------
:::::::: name.c :::::::
*** ../orig.u/name.c	Wed May 15 17:13:45 1985
--- name.c	Tue Jun  4 14:43:24 1985
***************
*** 16,21
  PROC BOOL	chkid();
  
  
  NAMNOD	ps2nod	= {	NIL,		NIL,		ps2name},
  	fngnod	= {	NIL,		NIL,		fngname},
  	pathnod = {	NIL,		NIL,		pathname},

--- 16,25 -----
  PROC BOOL	chkid();
  
  
+ #if pyr
+ NAMNOD	ps2nod	= {	NIL,		&univnod,	ps2name},
+ 	univnod = {	NIL,		NIL,		univname},
+ #else
  NAMNOD	ps2nod	= {	NIL,		NIL,		ps2name},
  #endif
  	fngnod	= {	NIL,		NIL,		fngname},
***************
*** 17,22
  
  
  NAMNOD	ps2nod	= {	NIL,		NIL,		ps2name},
  	fngnod	= {	NIL,		NIL,		fngname},
  	pathnod = {	NIL,		NIL,		pathname},
  	ifsnod	= {	NIL,		NIL,		ifsname},

--- 21,27 -----
  	univnod = {	NIL,		NIL,		univname},
  #else
  NAMNOD	ps2nod	= {	NIL,		NIL,		ps2name},
+ #endif
  	fngnod	= {	NIL,		NIL,		fngname},
  	pathnod = {	NIL,		NIL,		pathname},
  	ifsnod	= {	NIL,		NIL,		ifsname},
***************
*** 21,28
  	pathnod = {	NIL,		NIL,		pathname},
  	ifsnod	= {	NIL,		NIL,		ifsname},
  	ps1nod	= {	&pathnod,	&ps2nod,	ps1name},
! 	homenod = {	&fngnod,	&ifsnod,	homename},
! 	mailnod = {	&homenod,	&ps1nod,	mailname};
  
  NAMPTR		namep = &mailnod;
  

--- 26,34 -----
  	pathnod = {	NIL,		NIL,		pathname},
  	ifsnod	= {	NIL,		NIL,		ifsname},
  	ps1nod	= {	&pathnod,	&ps2nod,	ps1name},
! 	homenod = {	&histfnod,	&ifsnod,	homename},
! 	mailnod = {	&homenod,	&ps1nod,	mailname},
! 	histfnod = {	&fngnod,	NIL,		histfilename};
  
  NAMPTR		namep = &mailnod;
  
***************
*** 38,43
  	REG SYSPTR	syscan;
  
  	syscan=syswds; first = *w;
  
  	WHILE s=syscan->sysnam
  	DO  IF first == *s

--- 44,50 -----
  	REG SYSPTR	syscan;
  
  	syscan=syswds; first = *w;
+ 	IF *w == 0 THEN return (0) FI
  
  	WHILE s=syscan->sysnam
  	DO  IF first == *s
***************
*** 129,135
  	THEN	f->fsiz=1;
  	FI
  
! 	LOOP	c=nextc(0);
  		IF (*names ANDF any(c, ifsnod.namval)) ORF eolchar(c)
  		THEN	zerostak();
  			assign(n,absstak(rel)); setstak(rel);

--- 136,145 -----
  	THEN	f->fsiz=1;
  	FI
  
! 
! 	/*	strip any leading IFS characters	*/
! 	WHILE	(any((c=nextc(0)), ifsnod.namval)) ANDF !(eolchar(c)) DONE
! 	LOOP
  		IF (*names ANDF any(c, ifsnod.namval)) ORF eolchar(c)
  		THEN	zerostak();
  			assign(n,absstak(rel)); setstak(rel);
***************
*** 139,144
  			FI
  			IF eolchar(c)
  			THEN	break;
  			FI
  		ELSE	pushstak(c);
  		FI

--- 149,157 -----
  			FI
  			IF eolchar(c)
  			THEN	break;
+ 			ELSE	/* strip imbedded IFS characters */
+ 				WHILE (any((c=nextc(0)), ifsnod.namval)) ANDF
+ 					!(eolchar(c)) DONE
  			FI
  		ELSE	pushstak(c);
  			c = nextc(0);
***************
*** 141,146
  			THEN	break;
  			FI
  		ELSE	pushstak(c);
  		FI
  	POOL
  	WHILE n

--- 154,166 -----
  					!(eolchar(c)) DONE
  			FI
  		ELSE	pushstak(c);
+ 			c = nextc(0);
+ 			IF eolchar(c)
+ 			THEN
+ 				STKPTR top = staktop;
+ 				WHILE any (*(--top), ifsnod.namval) DONE
+ 				staktop = top + 1;
+ 			FI
  		FI
  	POOL
  	WHILE n
:::::::: name.h :::::::
No differences encountered
:::::::: print.c :::::::
*** ../orig.u/print.c	Wed May 15 17:13:45 1985
--- print.c	Mon Jun  3 11:05:42 1985
***************
*** 15,20
  
  CHAR		numbuf[6];
  
  
  /* printing and io conversion */
  

--- 15,27 -----
  
  CHAR		numbuf[6];
  
+ #ifndef TAB
+ /* emulate buffered i/o in later versions of the shell (sigh) */
+ prc_buff(c)
+ char c;
+ {
+ 	prc(c);
+ }
  
  prs_buff (s)
  char *s;
***************
*** 16,21
  CHAR		numbuf[6];
  
  
  /* printing and io conversion */
  
  newline()

--- 23,45 -----
  	prc(c);
  }
  
+ prs_buff (s)
+ char *s;
+ {
+ 	prs (s);
+ }
+ 
+ prn_buff (n)
+ int n;
+ {
+ 	prn (n);
+ }
+ 
+ flushb ()
+ {
+ }
+ #endif
+ 
  /* printing and io conversion */
  
  newline()
***************
*** 99,101
  	FI
  }
  

--- 123,229 -----
  	FI
  }
  
+ void
+ pr_prompt (str)
+ register char *str;
+ {
+ 	for (; *str; str++)
+ 	{
+ 		if (*str != '%')
+ 			prc_buff (*str);
+ #ifdef notdef
+ 		/* BSD does not have pwd built in, sorry */
+ 		else if (*(str+1) == 'd')
+ 		{
+ 			/* current directory */
+ 			str++;
+ 			prs_buff (retcwd());
+ 		}
+ #endif
+ 		else if (*(str+1) == 'e')
+ 		{
+ 			/* event count */
+ 			str++;
+ 			if ((flags & nohistflg) == 0)
+ 				prn_buff (event_count);
+ 		}
+ 		else if (*(str+1) == 'h')
+ 		{
+ 			/* hostname */
+ 			static char *cp = 0;
+ 			static int didhost = FALSE;
+ 			static int didgt = FALSE;
+ 			static char buf[257];
+ 
+ 			if (! didhost)
+ 			{
+ 				gethostname (buf, sizeof buf);
+ 				didhost = TRUE;
+ 				cp = buf;
+ 			}
+ #ifdef GATECH
+ 			/*
+ 			 * this is to get rid of the dumb gt- convention.
+ 			 * a gt w/out the - is also removed.
+ 			 */
+ 			if (! didgt)
+ 			{
+ 				didgt = TRUE;
+ 				if (cp[0] == 'g' && cp[1] == 't' && cp[2])
+ 				{
+ 					cp += 2;
+ 					if (cp[0] == '-' && cp[1])
+ 						cp++;
+ 				}
+ 			}
+ #endif
+ 			prs_buff (cp);
+ 			str++;
+ 		}
+ 		else if (*(str+1) == 'l')
+ 		{
+ 			/* login name */
+ 			static char *cp = 0;
+ 			static int didname = FALSE;
+ 
+ 			str++;
+ 			if (! didname)
+ 			{
+ 				cp = username ();
+ 				didname = TRUE;
+ 			}
+ 
+ 			if (cp)
+ 				prs_buff (cp);
+ 		}
+ 		else if (*(str+1) == 't')
+ 		{
+ 			/* current time, HH:MM */
+ 			long l;
+ 			char *cp, *ctime ();
+ 
+ 			str++;
+ 			time (& l);
+ 			cp = ctime (& l);
+ 			cp[16] = '\0';
+ 			cp += 11;
+ 			prs_buff (cp);
+ 		}
+ #if pyr
+ 		else if (*(str+1) == 'u')
+ 		{
+ 			/* current univeserse */
+ 			str++;
+ 			prs_buff (univ_name[cur_univ-1]);
+ 		}
+ #endif
+ 		else if (*(str+1) == '\0')	/* % was last char in string */
+ 		{
+ 			prc_buff (*str);
+ 			continue;
+ 		}
+ 		else
+ 			prc_buff (*(++str));
+ 	}
+ 	flushb();
+ }
:::::::: service.c :::::::
*** ../orig.u/service.c	Wed May 15 17:13:46 1985
--- service.c	Tue Jun  4 15:06:44 1985
***************
*** 12,17
   */
  
  #include	"defs.h"
  
  
  PROC VOID	gsort();

--- 12,20 -----
   */
  
  #include	"defs.h"
+ #if JOBS
+ #include	<sys/wait.h>
+ #endif
  
  
  PROC VOID	gsort();
***************
*** 43,50
  		ion=mactrim(iop->ioname);
  		IF *ion ANDF (flags&noexec)==0
  		THEN	IF iof&IODOC
! 			THEN	subst(chkopen(ion),(fd=tmpfil()));
! 				close(fd); fd=chkopen(tmpout); unlink(tmpout);
  			ELIF iof&IOMOV
  			THEN	IF eq(minus,ion)
  				THEN	fd = -1;

--- 46,57 -----
  		ion=mactrim(iop->ioname);
  		IF *ion ANDF (flags&noexec)==0
  		THEN	IF iof&IODOC
! 			THEN	TEMPBLK	tb;
! 				subst(chkopen(ion),(fd=tmpfil(&tb)));
! 				poptemp();	/* pushed in tmpfil --
! 						   bug fix for problems with
! 						   in-line scripts */
! 				fd=chkopen(tmpout); unlink(tmpout);
  			ELIF iof&IOMOV
  			THEN	IF eq(minus,ion)
  				THEN	fd = -1;
***************
*** 53,58
  				THEN	failed(ion,badfile);
  				ELSE	fd=dup(fd);
  				FI
  			ELIF (iof&IOPUT)==0
  			THEN	fd=chkopen(ion);
  			ELIF flags&rshflg

--- 60,69 -----
  				THEN	failed(ion,badfile);
  				ELSE	fd=dup(fd);
  				FI
+ 			ELIF iof&IORDW
+ 			THEN	IF (fd=open(ion, 2)) < 0
+ 				THEN	failed(ion, badopen);
+ 				FI
  			ELIF (iof&IOPUT)==0
  			THEN	fd=chkopen(ion);
  			ELIF flags&rshflg
***************
*** 69,74
  	FI
  }
  
  STRING	getpath(s)
  	STRING		s;
  {

--- 80,96 -----
  	FI
  }
  
+ STRING	simple (s)
+ 	REG STRING s;
+ {
+ 	STRING save = s;
+ 
+ 	FOR ; *s; s++
+ 	DO	IF *s == '/' THEN save = s; FI
+ 	OD
+ 	return (*save == '/' ? ++save : save);
+ }
+ 
  STRING	getpath(s)
  	STRING		s;
  {
***************
*** 73,79
  	STRING		s;
  {
  	REG STRING	path;
! 	IF any('/',s)
  	THEN	IF flags&rshflg
  		THEN	failed(s, restricted);
  		ELSE	return(nullstr);

--- 95,101 -----
  	STRING		s;
  {
  	REG STRING	path;
! 	IF any('/',s) ORF any(('/'|QUOTE), s)
  	THEN	IF flags&rshflg
  		THEN	failed(s, restricted);
  		ELSE	return(nullstr);
***************
*** 101,106
  	/* leaves result on top of stack */
  	REG STRING	scanp = path,
  			argp = locstak();
  
  	WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
  	IF scanp!=path THEN *argp++='/' FI

--- 123,129 -----
  	/* leaves result on top of stack */
  	REG STRING	scanp = path,
  			argp = locstak();
+ 	STRING	save = argp, cp;
  
  	WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
  	*argp = '\0';
***************
*** 103,108
  			argp = locstak();
  
  	WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
  	IF scanp!=path THEN *argp++='/' FI
  	IF *scanp==COLON THEN scanp++ FI
  	path=(*scanp ? scanp : 0); scanp=name;

--- 126,137 -----
  	STRING	save = argp, cp;
  
  	WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
+ 	*argp = '\0';
+ 	/* try a tilde expansion */
+ 	IF *save == SQUIGGLE ANDF (cp = homedir(save+1)) != nullstr
+ 	THEN	movstr(cp, save);
+ 		argp = save + length (save) - 1;
+ 	FI
  	IF scanp!=path THEN *argp++='/' FI
  	IF *scanp==COLON THEN scanp++ FI
  	path=(*scanp ? scanp : 0); scanp=name;
***************
*** 149,165
  		close(output); output=2;
  		input=chkopen(p);
  
- 		/* band aid to get csh... 2/26/79 */
- 		{
- 			char c;
- 			if (!isatty(input)) {
- 				read(input, &c, 1);
- 				if (c == '#')
- 					gocsh(t, p, xecenv);
- 				lseek(input, (long) 0, 0);
- 			}
- 		}
- 
  		/* set up new args */
  		setargs(t);
  		longjmp(subshell,1);

--- 178,183 -----
  		close(output); output=2;
  		input=chkopen(p);
  
  		/* set up new args */
  		setargs(t);
  		longjmp(subshell,1);
***************
*** 180,200
  	ENDSW
  }
  
- gocsh(t, cp, xecenv)
- 	register char **t, *cp, **xecenv;
- {
- 	char **newt[1000];
- 	register char **p;
- 	register int i;
- 
- 	for (i = 0; t[i]; i++)
- 		newt[i+1] = t[i];
- 	newt[i+1] = 0;
- 	newt[0] = "/bin/csh";
- 	newt[1] = cp;
- 	execve("/bin/csh", newt, xecenv);
- }
- 
  /* for processes to be waited for */
  #define MAXP 20
  LOCAL INT	pwlist[MAXP];

--- 198,203 -----
  	ENDSW
  }
  
  /* for processes to be waited for */
  #define MAXP 20
  LOCAL INT	pwlist[MAXP];
***************
*** 200,205
  LOCAL INT	pwlist[MAXP];
  LOCAL INT	pwc;
  
  postclr()
  {
  	REG INT		*pw = pwlist;

--- 203,247 -----
  LOCAL INT	pwlist[MAXP];
  LOCAL INT	pwc;
  
+ #if JOBS
+ LOCAL INT	*wf_pwlist;
+ LOCAL INT	wf_pwc;
+ 
+ VOID set_wfence()
+ {
+ 	wf_pwlist = &pwlist[pwc];
+ 	wf_pwc = 0;
+ }
+ 
+ BOOL unpost (pcsid)
+ 	INT pcsid;
+ {
+ 	REG INT *pw = pwlist;
+ 
+ 	IF pcsid
+ 	THEN	WHILE pw <= &pwlist[pwc]
+ 		DO	IF pcsid == *pw
+ 			THEN
+ 				IF pw >= wf_pwlist
+ 				THEN	wf_pwc--;	/* DAG -- bug fix */
+ 				ELSE	wf_pwlist--;
+ 				FI
+ 				WHILE pw <= &pwlist[pwc]
+ 				DO	*pw = pw[1];
+ 					pw++;
+ 				OD
+ 				pw[pwc] = 0;
+ 				pwc--;
+ 				return TRUE;
+ 			FI
+ 			pw++;
+ 		OD
+ 		return FALSE;
+ 	ELSE	return TRUE;
+ 	FI
+ }
+ #endif
+ 
  postclr()
  {
  	REG INT		*pw = pwlist;
***************
*** 205,211
  	REG INT		*pw = pwlist;
  
  	WHILE pw <= &pwlist[pwc]
! 	DO *pw++ = 0 OD
  	pwc=0;
  }
  

--- 247,258 -----
  	REG INT		*pw = pwlist;
  
  	WHILE pw <= &pwlist[pwc]
! 	DO
! #if JOBS
! 		j_child_clear(*pw);
! #endif
! 		*pw++ = 0;
! 	OD
  	pwc=0;
  }
  
***************
*** 215,221
  	REG INT		*pw = pwlist;
  
  	IF pcsid
! 	THEN	WHILE *pw DO pw++ OD
  		IF pwc >= MAXP-1
  		THEN	pw--;
  		ELSE	pwc++;

--- 262,274 -----
  	REG INT		*pw = pwlist;
  
  	IF pcsid
! 	THEN	WHILE *pw
! 		DO
! #if JOBS
! 			IF pcsid == *pw THEN return FI
! #endif
! 			pw++;
! 		OD
  		IF pwc >= MAXP-1
  		THEN	pw--;
  		ELSE	pwc++;
***************
*** 219,224
  		IF pwc >= MAXP-1
  		THEN	pw--;
  		ELSE	pwc++;
  		FI
  		*pw = pcsid;
  	FI

--- 272,280 -----
  		IF pwc >= MAXP-1
  		THEN	pw--;
  		ELSE	pwc++;
+ #if JOBS
+ 			wf_pwc++;
+ #endif
  		FI
  		*pw = pcsid;
  	FI
***************
*** 224,231
  	FI
  }
  
! VOID	await(i)
! 	INT		i;
  {
  	INT		rc=0, wx=0;
  	INT		w;

--- 280,287 -----
  	FI
  }
  
! VOID	await(i, bckg)
! 	INT		i, bckg;
  {
  #if JOBS
  #include <sys/time.h>
***************
*** 227,232
  VOID	await(i)
  	INT		i;
  {
  	INT		rc=0, wx=0;
  	INT		w;
  	INT		ipwc = pwc;

--- 283,293 -----
  VOID	await(i, bckg)
  	INT		i, bckg;
  {
+ #if JOBS
+ #include <sys/time.h>
+ #include <sys/resource.h>
+ 	struct rusage	ru;
+ #endif
  	INT		rc=0, wx=0;
  	INT		w;
  	INT		ipwc = pwc;
***************
*** 230,235
  	INT		rc=0, wx=0;
  	INT		w;
  	INT		ipwc = pwc;
  
  	post(i);
  	WHILE pwc

--- 291,298 -----
  	INT		rc=0, wx=0;
  	INT		w;
  	INT		ipwc = pwc;
+ #if JOBS
+ 	BOOL		update_only = i == -2;
  
  	IF update_only THEN i = -1 FI
  	IF (flags&jobflg) == 0 ORF i != -1
***************
*** 231,236
  	INT		w;
  	INT		ipwc = pwc;
  
  	post(i);
  	WHILE pwc
  	DO	REG INT		p;

--- 294,303 -----
  #if JOBS
  	BOOL		update_only = i == -2;
  
+ 	IF update_only THEN i = -1 FI
+ 	IF (flags&jobflg) == 0 ORF i != -1
+ 	THEN
+ #endif
  	post(i);
  #if JOBS
  	FI
***************
*** 232,237
  	INT		ipwc = pwc;
  
  	post(i);
  	WHILE pwc
  	DO	REG INT		p;
  		REG INT		sig;

--- 299,308 -----
  	THEN
  #endif
  	post(i);
+ #if JOBS
+ 	FI
+ #endif
+ 
  	WHILE pwc
  #if JOBS
  	ORF (flags&jobflg)
***************
*** 233,238
  
  	post(i);
  	WHILE pwc
  	DO	REG INT		p;
  		REG INT		sig;
  		INT		w_hi;

--- 304,312 -----
  #endif
  
  	WHILE pwc
+ #if JOBS
+ 	ORF (flags&jobflg)
+ #endif
  	DO	REG INT		p;
  		REG INT		sig;
  		INT		w_hi;
***************
*** 236,241
  	DO	REG INT		p;
  		REG INT		sig;
  		INT		w_hi;
  
  		BEGIN
  		   REG INT	*pw=pwlist;

--- 310,316 -----
  	DO	REG INT		p;
  		REG INT		sig;
  		INT		w_hi;
+ 		INT	found = 0;
  
  		BEGIN
  #ifndef JOBS
***************
*** 238,243
  		INT		w_hi;
  
  		BEGIN
  		   REG INT	*pw=pwlist;
   		   IF setjmp(INTbuf) == 0
   		   THEN	trapjmp[INTR] = 1; p=wait(&w);

--- 313,319 -----
  		INT	found = 0;
  
  		BEGIN
+ #ifndef JOBS
  		   REG INT	*pw=pwlist;
  #else
  		   IF (i == 0) ANDF (flags & jobflg) ANDF wf_pwc == 0
***************
*** 239,249
  
  		BEGIN
  		   REG INT	*pw=pwlist;
!  		   IF setjmp(INTbuf) == 0
!  		   THEN	trapjmp[INTR] = 1; p=wait(&w);
!  		   ELSE	p = -1;
!  		   FI
!  		   trapjmp[INTR] = 0;
  		   WHILE pw <= &pwlist[ipwc]
  		   DO IF *pw==p
  		      THEN *pw=0; pwc--;

--- 315,346 -----
  		BEGIN
  #ifndef JOBS
  		   REG INT	*pw=pwlist;
! #else
! 		   IF (i == 0) ANDF (flags & jobflg) ANDF wf_pwc == 0
! 		   THEN	break;
! 		   FI
! 		   IF (pwc == 0 ANDF (flags&jobflg)) ORF update_only
! 		   THEN	IF (p = wait3(&w, WUNTRACED|WNOHANG, &ru)) == 0
! 			THEN	unpost(i);
! 				break;
! 			FI
! 			IF pwc == 0 ANDF p == -1 THEN break FI
! 		   ELSE
! #endif
! 			p = wait3(&w, WUNTRACED, &ru);
! #if JOBS
! 		   FI
! #endif
! 
! 		   IF wasintr THEN
! 			wasintr = 0;
! 			IF bckg THEN
! 				break;
! 			FI
! 		   FI
! #if JOBS
! 		   IF unpost(p) THEN found++ FI
! #else
  		   WHILE pw <= &pwlist[ipwc]
  		   DO IF *pw==p
  		      THEN *pw=0; pwc--;
***************
*** 247,252
  		   WHILE pw <= &pwlist[ipwc]
  		   DO IF *pw==p
  		      THEN *pw=0; pwc--;
  		      ELSE pw++;
  		      FI
  		   OD

--- 344,350 -----
  		   WHILE pw <= &pwlist[ipwc]
  		   DO IF *pw==p
  		      THEN *pw=0; pwc--;
+ 			found++;
  		      ELSE pw++;
  		      FI
  		   OD
***************
*** 250,255
  		      ELSE pw++;
  		      FI
  		   OD
  		END
  
  		IF p == -1 THEN continue FI

--- 348,354 -----
  		      ELSE pw++;
  		      FI
  		   OD
+ #endif
  		END
  
  		IF p == -1 THEN
***************
*** 252,258
  		   OD
  		END
  
! 		IF p == -1 THEN continue FI
  
  		w_hi = (w>>8)&LOBYTE;
  

--- 351,370 -----
  #endif
  		END
  
! 		IF p == -1 THEN
! 			IF bckg THEN
! #if JOBS
! 				j_child_clear(i);
! 				unpost(i);
! #else
! 				REG INT *pw=pwlist;
! 				WHILE pw <= &pwlist[ipwc] ANDF i != *pw
! 				DO	pw++; OD
! 				IF i == *pw THEN *pw = 0; pwc-- FI
! #endif
! 			FI
! 			continue;
! 		FI
  
  		w_hi = (w>>8)&LOBYTE;
  
***************
*** 258,265
  
  		IF sig = w&0177
  		THEN	IF sig == 0177	/* ptrace! return */
! 			THEN	prs("ptrace: ");
! 				sig = w_hi;
  			FI
  			IF sysmsg[sig]
  			THEN	IF i!=p ORF (flags&prompt)==0 THEN prp(); prn(p); blank() FI

--- 370,384 -----
  
  		IF sig = w&0177
  		THEN	IF sig == 0177	/* ptrace! return */
! 			THEN	sig = w_hi;
! #if JOBS
! 				IF (flags&jobflg) ANDF
! 				(sig==STOP ORF sig==TSTP ORF sig==TTOU ORF sig==TTIN)
! 				THEN	j_child_stop(p, sig);
! 					goto j_bypass;
! 				FI
! #endif
! 				prs("ptrace: ");
  			FI
  			IF sysmsg[sig]
  			THEN	IF i!=p ORF (flags&prompt)==0 THEN prp(); prn(p); blank() FI
***************
*** 269,275
  			newline();
  		FI
  
! 		IF rc==0
  		THEN	rc = (sig ? sig|SIGFLG : w_hi);
  		FI
  		wx |= w;

--- 388,425 -----
  			newline();
  		FI
  
! #if JOBS
! 		IF flags&infoflg
! 		THEN
! 			register int	k;
! 			long		l;
! 
! 			prc('[');
! 			l = ru.ru_utime.tv_sec * 1000000L + ru.ru_utime.tv_usec
! 			  + ru.ru_stime.tv_sec * 1000000L + ru.ru_stime.tv_usec;
! 			prn((int)(l / 1000000));	/* integral seconds */
! 			k = (int)(l % 1000000L) / 1000;	/* thousandths */
! 			prc('.');
! 			if (k < 100)
! 				prc('0');
! 			if (k < 10)
! 				prc('0');
! 			prn(k);
! 			blank();
! 			prn((int)ru.ru_inblock);
! 			blank();
! 			prn((int)ru.ru_oublock);
! 			blank();
! 			prn((int)ru.ru_minflt);
! 			blank();
! 			prn((int)ru.ru_majflt);
! 			prc(']');
! 			newline();
! 		FI
! 		j_child_die(p);
!     j_bypass:
! #endif
! 		IF rc == 0 ANDF found != 0
  		THEN	rc = (sig ? sig|SIGFLG : w_hi);
  		FI
  		wx |= w;
***************
*** 273,278
  		THEN	rc = (sig ? sig|SIGFLG : w_hi);
  		FI
  		wx |= w;
  	OD
  
  	IF wx ANDF flags&errflg

--- 423,429 -----
  		THEN	rc = (sig ? sig|SIGFLG : w_hi);
  		FI
  		wx |= w;
+ 		IF p == i THEN break FI
  	OD
  
  	IF wx ANDF flags&errflg
***************
*** 278,283
  	IF wx ANDF flags&errflg
  	THEN	exitsh(rc);
  	FI
  	exitval=rc; exitset();
  }
  

--- 429,435 -----
  	IF wx ANDF flags&errflg
  	THEN	exitsh(rc);
  	FI
+ 	flags |= eflag;
  	exitval=rc; exitset();
  }
  
:::::::: setbrk.c :::::::
No differences encountered
:::::::: stak.c :::::::
No differences encountered
:::::::: stak.h :::::::
No differences encountered
:::::::: string.c :::::::
No differences encountered
:::::::: sym.h :::::::
*** ../orig.u/sym.h	Wed May 15 17:13:46 1985
--- sym.h	Mon Jun  3 12:51:24 1985
***************
*** 46,48
  #define DOLLAR	'$'
  #define ESCAPE	'\\'
  #define BRACE	'{'

--- 46,51 -----
  #define DOLLAR	'$'
  #define ESCAPE	'\\'
  #define BRACE	'{'
+ #if JOBS
+ #define PERCENT	'%'
+ #endif
:::::::: timeout.h :::::::
No differences encountered
:::::::: word.c :::::::
*** ../orig.u/word.c	Wed May 15 17:13:46 1985
--- word.c	Thu Jun  6 14:38:18 1985
***************
*** 23,28
  	REG CHAR	c, d;
  	REG CHAR	*argp=locstak()+BYTESPERWORD;
  	INT		alpha=1;
  
  	wdnum=0; wdset=0;
  

--- 23,29 -----
  	REG CHAR	c, d;
  	REG CHAR	*argp=locstak()+BYTESPERWORD;
  	INT		alpha=1;
+ 	STRING		save;
  
  	wdnum=0; wdset=0;
  
***************
*** 26,32
  
  	wdnum=0; wdset=0;
  
! 	WHILE (c=nextc(0), space(c)) DONE
  
  	IF c=='#'
  	THEN	WHILE (c=readc()) ANDF c!=NL DONE

--- 27,43 -----
  
  	wdnum=0; wdset=0;
  
! 	catcheof = TRUE;
! 	WHILE TRUE
! 	DO
! 		WHILE (c=nextc(0), space(c)) DONE
! 		IF c=='#'
! 		THEN	WHILE (c=nextc(0)) !=NL ANDF c != EOF DONE
! 			peekc = c;
! 		ELSE	break;	/* out of comment - white space loop */
! 		FI
! 	OD
! 	save = argp;
  
  	IF !eofmeta(c)
  	THEN	REP	IF c==LITERAL
***************
*** 28,37
  
  	WHILE (c=nextc(0), space(c)) DONE
  
- 	IF c=='#'
- 	THEN	WHILE (c=readc()) ANDF c!=NL DONE
- 	FI
- 
  	IF !eofmeta(c)
  	THEN	REP	IF c==LITERAL
  			THEN	*argp++=(DQUOTE);

--- 39,44 -----
  	OD
  	save = argp;
  
  	IF !eofmeta(c)
  	THEN	REP	IF c==LITERAL
  			THEN	*argp++=(DQUOTE);
***************
*** 46,51
  				THEN	d=c;
  					WHILE (*argp++=(c=nextc(d))) ANDF c!=d
  					DO chkpr(c) OD
  				FI
  			FI
  		PER (c=nextc(0), !eofmeta(c)) DONE

--- 53,73 -----
  				THEN	d=c;
  					WHILE (*argp++=(c=nextc(d))) ANDF c!=d
  					DO chkpr(c) OD
+ 				ELIF c == SQUIGGLE
+ 				THEN	/* try ~login name */
+ 					STRING name, home;
+ 
+ 					name = argp;
+ 					WHILE (c = nextc(0)) != '/' ANDF
+ 						!eofmeta(c)
+ 					DO
+ 						*name++ = c;
+ 					OD
+ 					peekc = c;
+ 					*name = '\0';
+ 					home = homedir(argp);
+ 					IF *home THEN movstr(home, --argp) FI
+ 					argp += length(argp) - 1;
  				FI
  			FI
  		PER (c=nextc(0), !eofmeta(c)) DONE
***************
*** 64,69
  	ELIF dipchar(c)
  	THEN	IF (d=nextc(0))==c
  		THEN	wdval = c|SYMREP;
  		ELSE	peekc = d|MARK; wdval = c;
  		FI
  	ELSE	IF (wdval=c)==EOF

--- 86,97 -----
  	ELIF dipchar(c)
  	THEN	IF (d=nextc(0))==c
  		THEN	wdval = c|SYMREP;
+ 			IF c == '<'
+ 			THEN	IF (d=nextc(0))=='-'
+ 				THEN stripflg++;
+ 				ELSE peekc = d|MARK;
+ 				FI
+ 			FI
  		ELSE	peekc = d|MARK; wdval = c;
  		FI
  	ELSE	IF (wdval=c)==EOF
***************
*** 70,76
  		THEN	wdval=EOFSYM;
  		FI
  		IF iopend ANDF eolchar(c)
! 		THEN	copy(iopend); iopend=0;
  		FI
  	FI
  	reserv=FALSE;

--- 98,109 -----
  		THEN	wdval=EOFSYM;
  		FI
  		IF iopend ANDF eolchar(c)
! 		THEN	INT histon = (flags&nohistflg) == 0;
! 
! 			flags |= nohistflg;	/* no history for here docs */
! 			copy(iopend);
! 			IF histon THEN flags &= ~nohistflg FI	/* restore */
! 			iopend=0;
  		FI
  	FI
  	catcheof = FALSE;
***************
*** 73,78
  		THEN	copy(iopend); iopend=0;
  		FI
  	FI
  	reserv=FALSE;
  	return(wdval);
  }

--- 106,112 -----
  			iopend=0;
  		FI
  	FI
+ 	catcheof = FALSE;
  	reserv=FALSE;
  	return(wdval);
  }
***************
*** 94,99
  
  readc()
  {
  	REG CHAR	c;
  	REG INT		len;
  	REG FILE	f;

--- 128,134 -----
  
  readc()
  {
+ 	LOCAL INT	eofcount = 0;	/* to break endless catcheof loop */
  	REG CHAR	c;
  	REG INT		len;
  	REG FILE	f;
***************
*** 116,123
  	ELIF f->feof ORF f->fdes<0
  	THEN	c=EOF; f->feof++;
  	ELIF (len=readb())<=0
! 	THEN	close(f->fdes); f->fdes = -1; c=EOF; f->feof++;
! 	ELSE	f->fend = (f->fnxt = f->fbuf)+len;
  		goto retry;
  	FI
  	return(c);

--- 151,185 -----
  	ELIF f->feof ORF f->fdes<0
  	THEN	c=EOF; f->feof++;
  	ELIF (len=readb())<=0
! 	THEN
! 	    IF catcheof
! #if JOBS
! 	    ANDF (flags&(ttyflg|prompt|dotflg)) == (ttyflg|prompt)
! 	    ANDF ( (flags&noeotflg) ORF j_finish(FALSE) )
! #else
! 	    ANDF (flags&(ttyflg|prompt|noeotflg|dotflg)) == (ttyflg|prompt|noeotflg)
! #endif
! 	    ANDF ++eofcount < 10	/* in case terminal is disconnected */
! 	    THEN
! #if JOBS
! 		IF (flags&(ttyflg|prompt|noeotflg)) == (ttyflg|prompt|noeotflg)
! 		THEN
! #endif
! 		    prs("use \"exit\"\n");
! #if JOBS
! 		/* else "there are stopped jobs" was printed */
! 		FI
! #endif
! 		c = NL;
! 	    ELSE
! 		close(f->fdes); f->fdes = -1; c=EOF; f->feof++;
! #if JOBS
! 		j_finish(TRUE);
! #endif
! 	    FI
! 	ELSE	f->fend = f->fnxt+len;
! 		/* was f->fend = (f->fnxt = f->fbuf) + len */
! 		eofcount = 0;
  		goto retry;
  	FI
  	return(c);
***************
*** 123,129
  	return(c);
  }
  
! LOCAL	readb()
  {
  	REG FILE	f=standin;
  	REG INT		len;

--- 185,191 -----
  	return(c);
  }
  
! LOCAL	readblock()	/* ADR --- changed the name */
  {
  	REG FILE	f=standin;
  	REG INT		len;
***************
*** 128,135
  	REG FILE	f=standin;
  	REG INT		len;
  
! 	IF setjmp(INTbuf) == 0 THEN trapjmp[INTR] = 1; FI
! 	REP	IF trapnote&SIGSET THEN newline(); sigchk() FI
  	PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
  	trapjmp[INTR] = 0;
  	return(len);

--- 190,201 -----
  	REG FILE	f=standin;
  	REG INT		len;
  
! 	REP
! 		IF trapnote&SIGSET
! 		THEN	newline(); sigchk();
! 		ELIF (trapnote&TRAPSET) ANDF (rwait>0)
! 		THEN	newline(); chktrap(); clearup();
! 		FI
  	PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
  	return(len);
  }
***************
*** 131,136
  	IF setjmp(INTbuf) == 0 THEN trapjmp[INTR] = 1; FI
  	REP	IF trapnote&SIGSET THEN newline(); sigchk() FI
  	PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
- 	trapjmp[INTR] = 0;
  	return(len);
  }

--- 197,202 -----
  		THEN	newline(); chktrap(); clearup();
  		FI
  	PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
  	return(len);
  }
  
***************
*** 133,136
  	PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
  	trapjmp[INTR] = 0;
  	return(len);
  }

--- 198,398 -----
  		FI
  	PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
  	return(len);
+ }
+ 
+ /* readb --- read a block from the outside world, and history process it */
+ 
+ /*
+  * In BSD systems, using the literal next capability of the tty driver, it
+  * is actually possible to put a newline in the middle of the input line,
+  * and then hit return, so that the shell sees two lines of input.
+  *
+  * As a design decision, if there is a \n in the middle of what we've read
+  * from a terminal, treat the commands as two separately typed commands. I.e.
+  *
+  *	echo hi ^J echo there
+  *
+  * is the same as
+  *
+  *	echo hi
+  *	echo there
+  *
+  * The major reason for doing it this way is that the history mechanism knows
+  * that a \n is the end of a line.
+  *
+  * Finally, on USG systems, we just leave this code alone, since it won't
+  * get executed anyway.
+  */
+ 
+ /*
+  * In word.c, the readc() function keeps a pointer to what standin pointed to
+  * when readc first gets called.  Therefore, where standin points to can not 
+  * not change across calls to readb().  To get around this, we change the
+  * contents of the structure pointed to by standin, saving and restoring
+  * it as necessary.
+  */
+ 
+ #define LARGEBUF	(HISTSIZE / 2)	/* size of expanded history */
+ 
+ static
+ readb()
+ {
+ 	int ilen, i, j;
+ 	char ibuf[BUFSIZ];	/* input into scratch area, pass to history */
+ 	static char expansion[LARGEBUF];
+ 	static int moreinbuf = FALSE;
+ 	static int saved_ilen = 0;
+ 	static int start_here = 0;
+ 	static struct fileblk *f = 0;
+ 	auto int gotoutofbuf = 0;
+ 
+ 	if (expanded)	/* just did a history substitution */
+ 		expanded = 0;
+ 
+ 	if ((flags & nohistflg) || (flags & prompt) == 0 || ! isatty (input)
+ 			|| standin->fstak != 0)
+ 	{
+ 		ilen = readblock ();
+ 		if (ilen > 0)
+ 			standin->fnxt = standin->fbuf;
+ 		return (ilen);
+ 		/* not doing history expansion at all */
+ 	}
+ 
+ 	if (f == 0)
+ 		f = standin;
+ 
+ 	ilen = 0;
+ 
+ 	/*
+ 	 * First, if there was more stuff in the last buffer, go and get it.
+ 	 * If not get some more from the outside world.
+ 	 *
+ 	 * Then, make sure we've read up to a newline.
+ 	 * This is basically in case someone has done something bizarre
+ 	 * like 'stty raw', and input is coming in one character at a time.
+ 	 *
+ 	 * We use a heuristic.  If amount read is just 1, keep reading till
+ 	 * we get a newline.  Else, read in a complete line from the terminal.
+ 	 * Once we're in raw mode, can't reset it until a newline is typed.
+ 	 *
+ 	 * If not reading one character at a time, then do the stuff for
+ 	 * embedded newlines.
+ 	 */
+ 
+ 	if (moreinbuf)
+ 	{
+ 		for (i = 0, j = start_here; f->fbuf[j] != NL && j < saved_ilen; i++, j++)
+ 			ibuf[i] = f->fbuf[j];
+ 
+ #ifdef notdef
+ 		if (f->fbuf[j] != NL)
+ 		{
+ 			prs ("internal i/o error C in readb\n");
+ 			return (0);
+ 		}
+ #endif
+ 
+ 		if (f->fbuf[j] == NL)
+ 			ibuf[i++] = NL;
+ 		ibuf[i] = '\0';
+ 		ilen = i;
+ 		/* embedded newline */
+ 		moreinbuf = (++j < saved_ilen - 1);
+ 		if (moreinbuf)
+ 			start_here = j;	/* where to start next time */
+ 		gotoutofbuf = 1;
+ 	}
+ 	else	/* wasn't an embedded \n last time */
+ 	{
+ 		ilen = readblock ();
+ 	
+ 		if (ilen <= 0)	/* EOF or error */
+ 			return (ilen);
+ 
+ 		if (ilen == 1)	/* either in raw mode, or an empty line */
+ 		{
+ 			i = 0;
+ 			ibuf[i++] = f->fbuf[0];
+ 			if (f->fbuf[0] == NL)
+ 			{
+ 				ibuf[i] = '\0';
+ 				goto dohist;
+ 			}
+ 
+ 			while ((ilen = readblock()) > 0)
+ 			{
+ 				if (ilen != 1)
+ 				{
+ 					prs ("internal i/o error A in readb\n");
+ 					return (0);
+ 				}
+ 				ibuf[i++] = f->fbuf[0];
+ 				if (f->fbuf[0] == NL)
+ 				{
+ 					ibuf[i] = '\0';
+ 					break;	/* while */
+ 				}
+ 			}
+ 			ilen = i;
+ 			gotoutofbuf = TRUE;
+ 			/* force code below to use collected string */
+ 		}
+ 		else
+ 		{
+ 			/* reading bunches of characters at once */
+ 			for (i = 0; f->fbuf[i] != NL && i < ilen; i++)
+ 				ibuf[i] = f->fbuf[i];
+ 
+ #ifdef notdef
+ 			if (f->fbuf[i] != NL)
+ 			{
+ 				prs ("internal i/o error B in readb\n");
+ 				return (0);
+ 			}
+ #endif
+ 
+ 			ibuf[i++] = NL;
+ 			ibuf[i] = '\0';
+ 			/* ilen was set by readblock() */
+ 			/* embedded newline */
+ 			moreinbuf = (i < ilen - 1);
+ 			if (moreinbuf)
+ 			{
+ 				saved_ilen = ilen;
+ 				start_here = i;
+ 				/* where to start next time */
+ 				gotoutofbuf = 1;
+ 			}
+ 		}
+ 	}
+ 
+ dohist:
+ 	/* quick heuristic */
+ 	if (! gotoutofbuf && ilen == 1 && f->fbuf[0] == NL)
+ 	{
+ 		f->fnxt = f->fbuf;
+ 		return (ilen);
+ 	}
+ 
+ 	if (histsub (ibuf, expansion, sizeof expansion))
+ 	{
+ 		int olen = length (expansion) - 1;
+ 		if (! expanded && ! gotoutofbuf)
+ 		{
+ 			standin->fnxt = standin->fbuf;
+ 			return (ilen);
+ 		}
+ 		/* else
+ 			expanded == TRUE or from buffer */
+ 		standin->fnxt = expansion;
+ 		return (olen);
+ 	}
+ 	else
+ 	{
+ 		/* hist expansion failed, return an empty line */
+ 		standin->fnxt = standin->fbuf;
+ 		standin->fbuf[0] = NL;
+ 		return (1);
+ 	}
  }
:::::::: xec.c :::::::
*** ../orig.u/xec.c	Wed May 15 17:13:46 1985
--- xec.c	Tue Jun  4 17:58:16 1985
***************
*** 12,17
   */
  
  #include	"defs.h"
  #include	"sym.h"
  
  LOCAL INT	parent;

--- 12,18 -----
   */
  
  #include	"defs.h"
+ #include	<errno.h>
  #include	"sym.h"
  
  LOCAL INT	parent;
***************
*** 23,29
  /* ========	command execution	========*/
  
  
! execute(argt, execflg, pf1, pf2)
  	TREPTR		argt;
  	INT		*pf1, *pf2;
  {

--- 24,30 -----
  /* ========	command execution	========*/
  
  
! execute(argt, execflg, errorflg, pf1, pf2)
  	TREPTR		argt;
  	INT		*pf1, *pf2;
  {
***************
*** 30,35
  	/* `stakbot' is preserved by this routine */
  	REG TREPTR	t;
  	STKPTR		sav=savstak();
  
  	sigchk();
  

--- 31,46 -----
  	/* `stakbot' is preserved by this routine */
  	REG TREPTR	t;
  	STKPTR		sav=savstak();
+ #if pyr
+ 	auto INT	change_univ = FALSE;
+ 	auto INT	new_univ = 0;
+ 	/*
+ 	 * universes run from 1 to NUMUNIV: We start out at 0
+ 	 * and increment new_univ in the swtich for internal
+ 	 * commands, below. new_univ nust *not* be assigned to, directly
+ 	 * or via side effects, any place else
+ 	 */
+ #endif
  
  	sigchk();
  
***************
*** 33,38
  
  	sigchk();
  
  	IF (t=argt) ANDF execbrk==0
  	THEN	REG INT		treeflgs;
  		INT		oldexit, type;

--- 44,50 -----
  
  	sigchk();
  
+ 	IF ! errorflg THEN flags &= ~errflg FI
  	IF (t=argt) ANDF execbrk==0
  	THEN	REG INT		treeflgs;
  		INT		oldexit, type;
***************
*** 54,60
  			com=scan(argn);
  			a1=com[1]; gchain=schain;
  
! 			IF argn==0 ORF (internal=syslook(com[0],commands))
  			THEN	setlist(t->comset, 0);
  			FI
  

--- 66,72 -----
  			com=scan(argn);
  			a1=com[1]; gchain=schain;
  
! 			IF (internal=syslook(com[0],commands)) ORF argn==0
  			THEN	setlist(t->comset, 0);
  			FI
  
***************
*** 75,81
  	
  						IF (f=pathopen(getpath(a1), a1)) < 0
  						THEN failed(a1,notfound);
! 						ELSE execexp(0,f);
  						FI
  					FI
  					break;

--- 87,99 -----
  	
  						IF (f=pathopen(getpath(a1), a1)) < 0
  						THEN failed(a1,notfound);
! 						ELSE
! 							INT savedot = flags&dotflg;
! 
! 							flags |= dotflg;
! 							execexp(0,f);
! 							flags &= ~dotflg;
! 							flags |= savedot;
  						FI
  					FI
  					break;
***************
*** 88,93
  					break;
  	
  				case SYSEXIT:
  					exitsh(a1?stoi(a1):oldexit);
  	
  				case SYSNULL:

--- 106,116 -----
  					break;
  	
  				case SYSEXIT:
+ #if JOBS
+ 					IF j_finish(FALSE) THEN break; FI
+ #endif
+ 					histsave (histfnod.namval);
+ 					flags |= forked;	/* force exit */
  					exitsh(a1?stoi(a1):oldexit);
  	
  				case SYSNULL:
***************
*** 95,101
  					break;
  	
  				case SYSCONT:
! 					execbrk = -loopcnt; break;
  	
  				case SYSBREAK:
  					IF (execbrk=loopcnt) ANDF a1

--- 118,127 -----
  					break;
  	
  				case SYSCONT:
! 					IF (execbrk = -loopcnt) ANDF a1
! 					THEN	breakcnt = stoi (a1); 
! 					FI
! 					break;
  	
  				case SYSBREAK:
  					IF (execbrk=loopcnt) ANDF a1
***************
*** 139,144
  					IF a1==0 THEN break FI
  	
  				case SYSLOGIN:
  					flags |= forked;
  					oldsigs(); execa(com); done();
  	

--- 165,171 -----
  					IF a1==0 THEN break FI
  	
  				case SYSLOGIN:
+ 					histsave (histfnod.namval);
  					flags |= forked;
  					oldsigs(); execa(com); done();
  	
***************
*** 151,160
  					break;
  	
  				case SYSSHFT:
! 					IF dolc<1
! 					THEN	error(badshift);
! 					ELSE	dolv++; dolc--;
! 					FI
  					assnum(&dolladr, dolc);
  					break;
  	

--- 178,193 -----
  					break;
  	
  				case SYSSHFT:
! 					BEGIN
! 						INT places;
! 						places = a1 ? stoi(a1) : 1;
! 						FOR ; places--;
! 						DO	IF dolc<1
! 							THEN	error(badshift);
! 							ELSE	dolv++; dolc--;
! 							FI
! 						OD
! 					END
  					assnum(&dolladr, dolc);
  					break;
  	
***************
*** 159,164
  					break;
  	
  				case SYSWAIT:
  					await(-1);
  					break;
  	

--- 192,198 -----
  					break;
  	
  				case SYSWAIT:
+ 					/*
  					await(-1);
  					*/
  					await(a1?stoi(a1):-1,1);
***************
*** 160,165
  	
  				case SYSWAIT:
  					await(-1);
  					break;
  	
  				case SYSREAD:

--- 194,201 -----
  				case SYSWAIT:
  					/*
  					await(-1);
+ 					*/
+ 					await(a1?stoi(a1):-1,1);
  					break;
  	
  				case SYSREAD:
***************
*** 163,168
  					break;
  	
  				case SYSREAD:
  					exitval=readvar(&com[1]);
  					break;
  

--- 199,205 -----
  					break;
  	
  				case SYSREAD:
+ 					rwait=1;
  					exitval=readvar(&com[1]);
  					break;
  
***************
*** 222,227
                                          }
                                          break;
  	
  				default:
  					internal=builtin(argn,com);
  	

--- 259,327 -----
                                          }
                                          break;
  	
+ #if JOBS
+ 				case SYSJOBS:
+ 
+ 					j_print();
+ 					break;
+ 
+ 				case SYSFG:
+ 
+ 					j_resume(a1, FALSE);
+ 					break;
+ 
+ 				case SYSBG:
+ 
+ 					j_resume(a1, TRUE);
+ 					break;
+ 
+ 				case SYSSUSPEND:
+ 					exitval = 1;
+ 					IF getppid() == 1
+ 					THEN	prs (nosusp);
+ 					ELSE	exitval = 0;
+ 						kill (getpid(), STOP);
+ 					FI
+ 					break;
+ #endif
+ 
+ #if pyr
+ 				/*
+ 				 * UCB is Universe 2
+ 				 * ATT is Universe 1
+ 				 * new_univ == 0
+ 				 */
+ 				case SYSUCB:
+ 					new_univ++;
+ 					/* fall thru */
+ 				case SYSATT:
+ 					new_univ++;
+ 					IF argn > 1
+ 					THEN
+ 						change_univ = TRUE;
+ 						com++;
+ 						goto doit;
+ 					ELSE
+ 						setuniverse (cur_univ = new_univ);
+ 						univnod.namflg &= ~N_RDONLY;
+ 						assign (& univnod, univ_name[cur_univ - 1]);
+ 						attrib ((& univnod), N_RDONLY);
+ 						break;
+ 					FI
+ 
+ 				case SYSUNIVERSE:
+ 					IF eq(com[1], dashl)
+ 					THEN	prs_buff (univ_longname[cur_univ - 1]);
+ 					ELSE	prs_buff (univ_name[cur_univ - 1]);
+ 					FI
+ 					prc_buff (NL);
+ 					break;
+ #endif
+ 
+ 				case SYSHISTORY:
+ 					exitval = history (argn, com);
+ 					break;
+ 
  				default:
  					internal=builtin(argn,com);
  	
***************
*** 233,239
  					break;
  				FI
  			ELIF t->treio==0
! 			THEN	break;
  			FI
  			END
  	

--- 333,340 -----
  					break;
  				FI
  			ELIF t->treio==0
! 			THEN	chktrap();
! 				break;
  			FI
  			END
  	
***************
*** 238,243
  			END
  	
  		case TFORK:
  			IF execflg ANDF (treeflgs&(FAMP|FPOU))==0
  			THEN	parent=0;
  			ELSE	WHILE (parent=fork()) == -1

--- 339,347 -----
  			END
  	
  		case TFORK:
+ #if pyr
+ 		doit:
+ #endif
  			IF execflg ANDF (treeflgs&(FAMP|FPOU))==0
  			THEN	parent=0;
  			ELSE	WHILE (parent=fork()) == -1
***************
*** 242,247
  			THEN	parent=0;
  			ELSE	WHILE (parent=fork()) == -1
  				DO sigchk(); alarm(10); pause() OD
  			FI
  
  			IF parent

--- 346,354 -----
  			THEN	parent=0;
  			ELSE	WHILE (parent=fork()) == -1
  				DO sigchk(); alarm(10); pause() OD
+ #if JOBS
+ 				IF parent == 0 THEN j_top_level = FALSE; FI
+ #endif
  			FI
  
  			IF parent
***************
*** 248,253
  			THEN	/* This is the parent branch of fork;    */
  				/* it may or may not wait for the child. */
  				IF treeflgs&FPRS ANDF flags&ttyflg
  				THEN	prn(parent); newline();
  				FI
  				IF treeflgs&FPCL THEN closepipe(pf1) FI

--- 355,363 -----
  			THEN	/* This is the parent branch of fork;    */
  				/* it may or may not wait for the child. */
  				IF treeflgs&FPRS ANDF flags&ttyflg
+ #if JOBS
+ 				ANDF (flags&jobflg) == 0
+ #endif
  				THEN	prn(parent); newline();
  				FI
  				IF treeflgs&FPCL THEN closepipe(pf1) FI
***************
*** 251,256
  				THEN	prn(parent); newline();
  				FI
  				IF treeflgs&FPCL THEN closepipe(pf1) FI
  				IF (treeflgs&(FAMP|FPOU))==0
  				THEN	await(parent);
  				ELIF (treeflgs&FAMP)==0

--- 361,369 -----
  				THEN	prn(parent); newline();
  				FI
  				IF treeflgs&FPCL THEN closepipe(pf1) FI
+ #if JOBS
+ 				j_child_post(parent, treeflgs&FAMP, treeflgs&FPIN, t);
+ #endif
  				IF (treeflgs&(FAMP|FPOU))==0
  				THEN	await(parent, 0);
  #if JOBS
***************
*** 252,258
  				FI
  				IF treeflgs&FPCL THEN closepipe(pf1) FI
  				IF (treeflgs&(FAMP|FPOU))==0
! 				THEN	await(parent);
  				ELIF (treeflgs&FAMP)==0
  				THEN	post(parent);
  				ELSE	assnum(&pcsadr, parent);

--- 365,374 -----
  				j_child_post(parent, treeflgs&FAMP, treeflgs&FPIN, t);
  #endif
  				IF (treeflgs&(FAMP|FPOU))==0
! 				THEN	await(parent, 0);
! #if JOBS
! 					j_reset_pg();
! #endif
  				ELIF (treeflgs&FAMP)==0
  				THEN	post(parent);
  				ELSE	assnum(&pcsadr, parent);
***************
*** 263,268
  
  
  			ELSE	/* this is the forked branch (child) of execute */
  				flags |= forked; iotemp=0;
  				postclr();
  				settmp();

--- 379,393 -----
  
  
  			ELSE	/* this is the forked branch (child) of execute */
+ #if pyr
+ 				IF change_univ
+ 				THEN	setuniverse (new_univ);
+ 					univnod.namflg &= ~N_RDONLY;
+ 					assign (&univnod, univ_name[cur_univ - 1]);
+ 					attrib ((&univnod), N_RDONLY);
+ 				FI
+ #endif
+ 
  				flags |= forked; iotemp=0;
  				postclr();
  				settmp();
***************
*** 268,274
  				settmp();
  
  				/* Turn off INTR and QUIT if `FINT'  */
! 				/* Reset ramaining signals to parent */
  				/* except for those `lost' by trap   */
  				oldsigs();
  				IF treeflgs&FINT

--- 393,399 -----
  				settmp();
  
  				/* Turn off INTR and QUIT if `FINT'  */
! 				/* Reset remaining signals to parent */
  				/* except for those `lost' by trap   */
  				oldsigs();
  				IF treeflgs&FINT
***************
*** 272,277
  				/* except for those `lost' by trap   */
  				oldsigs();
  				IF treeflgs&FINT
  				THEN	signal(INTR,1); signal(QUIT,1);
  				FI
  

--- 397,405 -----
  				/* except for those `lost' by trap   */
  				oldsigs();
  				IF treeflgs&FINT
+ #if JOBS
+ 				ANDF (flags&jobflg) == 0
+ #endif
  				THEN	signal(INTR,1); signal(QUIT,1);
  				FI
  
***************
*** 287,292
  
  				/* default std input for & */
  				IF treeflgs&FINT ANDF ioset==0
  				THEN	rename(chkopen(devnull),0);
  				FI
  

--- 415,423 -----
  
  				/* default std input for & */
  				IF treeflgs&FINT ANDF ioset==0
+ #if JOBS
+ 				ANDF (flags&jobflg) == 0
+ #endif
  				THEN	rename(chkopen(devnull),0);
  				FI
  
***************
*** 293,299
  				/* io redirection */
  				initio(t->treio);
  				IF type!=TCOM
! 				THEN	execute(t->forktre,1);
  				ELIF com[0]!=ENDARGS
  				THEN	setlist(t->comset,N_EXPORT);
  					execa(com);

--- 424,430 -----
  				/* io redirection */
  				initio(t->treio);
  				IF type!=TCOM
! 				THEN	execute(t->forktre,1, errorflg);
  				ELIF com[0]!=ENDARGS
  				THEN
  					eflag = 0;
***************
*** 295,301
  				IF type!=TCOM
  				THEN	execute(t->forktre,1);
  				ELIF com[0]!=ENDARGS
! 				THEN	setlist(t->comset,N_EXPORT);
  					execa(com);
  				FI
  				done();

--- 426,438 -----
  				IF type!=TCOM
  				THEN	execute(t->forktre,1, errorflg);
  				ELIF com[0]!=ENDARGS
! 				THEN
! 					eflag = 0;
! 					/* eflag must be set to zero so commands
! 					   implemented as shell scripts do not
! 					   exit if set -e and some command in
! 					   the script returns non zero */
! 					setlist(t->comset,N_EXPORT);
  					execa(com);
  				FI
  				done();
***************
*** 303,309
  
  		case TPAR:
  			rename(dup(2),output);
! 			execute(t->partre,execflg);
  			done();
  
  		case TFIL:

--- 440,446 -----
  
  		case TPAR:
  			rename(dup(2),output);
! 			execute(t->partre,execflg, errorflg);
  			done();
  
  		case TFIL:
***************
*** 309,316
  		case TFIL:
  			BEGIN
  			   INT pv[2]; chkpipe(pv);
! 			   IF execute(t->lstlef, 0, pf1, pv)==0
! 			   THEN	execute(t->lstrit, execflg, pv, pf2);
  			   ELSE	closepipe(pv);
  			   FI
  			END

--- 446,453 -----
  		case TFIL:
  			BEGIN
  			   INT pv[2]; chkpipe(pv);
! 			   IF execute(t->lstlef, 0, errorflg, pf1, pv)==0
! 			   THEN	execute(t->lstrit, execflg, errorflg, pv, pf2);
  			   ELSE	closepipe(pv);
  			   FI
  			END
***************
*** 317,324
  			break;
  
  		case TLST:
! 			execute(t->lstlef,0);
! 			execute(t->lstrit,execflg);
  			break;
  
  		case TAND:

--- 454,461 -----
  			break;
  
  		case TLST:
! 			execute(t->lstlef,0, errorflg);
! 			execute(t->lstrit,execflg, errorflg);
  			break;
  
  		case TAND:
***************
*** 322,329
  			break;
  
  		case TAND:
! 			IF execute(t->lstlef,0)==0
! 			THEN	execute(t->lstrit,execflg);
  			FI
  			break;
  

--- 459,466 -----
  			break;
  
  		case TAND:
! 			IF execute(t->lstlef,0, 0)==0
! 			THEN	execute(t->lstrit,execflg, errorflg);
  			FI
  			break;
  
***************
*** 328,335
  			break;
  
  		case TORF:
! 			IF execute(t->lstlef,0)!=0
! 			THEN	execute(t->lstrit,execflg);
  			FI
  			break;
  

--- 465,472 -----
  			break;
  
  		case TORF:
! 			IF execute(t->lstlef,0, 0)!=0
! 			THEN	execute(t->lstrit,execflg, errorflg);
  			FI
  			break;
  
***************
*** 350,357
  			   loopcnt++;
  			   WHILE *args!=ENDARGS ANDF execbrk==0
  			   DO	assign(n,*args++);
! 				execute(t->fortre,0);
! 				IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
  			   execbrk=breakcnt; loopcnt--;

--- 487,499 -----
  			   loopcnt++;
  			   WHILE *args!=ENDARGS ANDF execbrk==0
  			   DO	assign(n,*args++);
! 				execute(t->fortre,0, errorflg);
! 				IF execbrk
! 				THEN	IF breakcnt > 1 ORF execbrk > 0
! 					THEN break;
! 					ELSE execbrk = breakcnt = 0;
! 					FI
! 				FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
  			   execbrk = (execbrk < 0 ? -breakcnt : breakcnt);
***************
*** 354,360
  				IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
! 			   execbrk=breakcnt; loopcnt--;
  			   argfor=freeargs(argsav);
  			END
  			break;

--- 496,503 -----
  				FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
! 			   execbrk = (execbrk < 0 ? -breakcnt : breakcnt);
! 			   loopcnt--;
  			   argfor=freeargs(argsav);
  			END
  			break;
***************
*** 365,373
  			   INT		i=0;
  
  			   loopcnt++;
! 			   WHILE execbrk==0 ANDF (execute(t->whtre,0)==0)==(type==TWH)
! 			   DO i=execute(t->dotre,0);
! 			      IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
  			   execbrk=breakcnt; loopcnt--; exitval=i;

--- 508,521 -----
  			   INT		i=0;
  
  			   loopcnt++;
! 			   WHILE execbrk<=0 ANDF (execute(t->whtre,0,0)==0)==(type==TWH)
! 			   DO i=execute(t->dotre,0, errorflg);
! 			      IF execbrk
! 			      THEN	IF breakcnt > 1 ORF execbrk > 0
! 					THEN break;
! 					ELSE execbrk = breakcnt = 0;
! 					FI
! 			      FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
  			   execbrk=(execbrk < 0 ? -breakcnt : breakcnt);
***************
*** 370,376
  			      IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
! 			   execbrk=breakcnt; loopcnt--; exitval=i;
  			END
  			break;
  

--- 518,525 -----
  			      FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
! 			   execbrk=(execbrk < 0 ? -breakcnt : breakcnt);
! 			   loopcnt--; exitval=i;
  			END
  			break;
  
***************
*** 375,383
  			break;
  
  		case TIF:
! 			IF execute(t->iftre,0)==0
! 			THEN	execute(t->thtre,execflg);
! 			ELSE	execute(t->eltre,execflg);
  			FI
  			break;
  

--- 524,534 -----
  			break;
  
  		case TIF:
! 			IF execute(t->iftre,0,0)==0
! 			THEN	execute(t->thtre,execflg, errorflg);
! 			ELIF	t->eltre
! 			THEN	execute(t->eltre,execflg, errorflg);
! 			ELSE	exitval = 0; /* force zero exit for if-then-fi */
  			FI
  			break;
  
***************
*** 390,396
  				WHILE rex
  				DO	REG STRING	s;
  					IF gmatch(r,s=macro(rex->argval)) ORF (trim(s), eq(r,s))
! 					THEN	execute(t->regcom,0);
  						t=0; break;
  					ELSE	rex=rex->argnxt;
  					FI

--- 541,547 -----
  				WHILE rex
  				DO	REG STRING	s;
  					IF gmatch(r,s=macro(rex->argval)) ORF (trim(s), eq(r,s))
! 					THEN	execute(t->regcom,0,errorflg);
  						t=0; break;
  					ELSE	rex=rex->argnxt;
  					FI
***************
*** 405,410
  
  	sigchk();
  	tdystak(sav);
  	return(exitval);
  }
  

--- 556,562 -----
  
  	sigchk();
  	tdystak(sav);
+ 	flags |= eflag;
  	return(exitval);
  }
  
***************
*** 420,425
  	ELIF f>=0
  	THEN	initf(f);
  	FI
! 	execute(cmd(NL, NLFLG|MTFLG),0);
  	pop();
  }

--- 572,577 -----
  	ELIF f>=0
  	THEN	initf(f);
  	FI
! 	execute(cmd(NL, NLFLG|MTFLG),0, flags&errflg);
  	pop();
  }

sources-request@genrad.UUCP (06/10/85)

From: Arnold Robbins <gatech!arnold>

This is part 4 of 9.  It contains the diffs for the BSD Bourne shell's
man page, sh.1.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
------------------- tear here --------------------
*** ../orig.u/sh.1	Wed May 15 17:25:17 1985
--- sh.1	Wed Jun  5 11:10:39 1985
***************
*** 1,4
! .TH SH 1 "7 February 1983"
  .SH NAME
  sh, for, case, if, while, \fB:\fP, \fB.\fP, break, continue, cd, eval, exec, exit, export, login, read, readonly, set, shift, times, trap, umask, wait \- command language
  .SH SYNOPSIS

--- 1,4 -----
! .TH SH 1 "BRL + GT Modifications"
  .SH NAME
  sh \- shell, the standard command programming language
  .SH SYNOPSIS
***************
*** 1,6
  .TH SH 1 "7 February 1983"
  .SH NAME
! sh, for, case, if, while, \fB:\fP, \fB.\fP, break, continue, cd, eval, exec, exit, export, login, read, readonly, set, shift, times, trap, umask, wait \- command language
  .SH SYNOPSIS
  .B sh
  [

--- 1,6 -----
  .TH SH 1 "BRL + GT Modifications"
  .SH NAME
! sh \- shell, the standard command programming language
  .SH SYNOPSIS
  .B sh
  [
***************
*** 4,10
  .SH SYNOPSIS
  .B sh
  [
! .B \-ceiknrstuvx
  ] [ arg ] ...
  .ds OK [\|
  .ds CK \|]

--- 4,10 -----
  .SH SYNOPSIS
  .B sh
  [
! .B \-ceiknrqstuvxEHIJ
  ] [ arg ] ...
  .ds OK [\|
  .ds CK \|]
***************
*** 16,22
  .I Sh
  is a command programming language that executes commands read from a terminal
  or a file.  See
! .B invocation
  for the meaning of arguments to the shell.
  .PP
  .B Commands.

--- 16,23 -----
  .I Sh
  is a command programming language that executes commands read from a terminal
  or a file.  See
! .I Invocation
! below
  for the meaning of arguments to the shell.
  .SS Commands.
  A
***************
*** 18,26
  or a file.  See
  .B invocation
  for the meaning of arguments to the shell.
! .PP
! .B Commands.
! .br
  A
  .I simple-command
  is a sequence of non blank

--- 19,25 -----
  .I Invocation
  below
  for the meaning of arguments to the shell.
! .SS Commands.
  A
  .I simple-command
  is a sequence of non blank
***************
*** 37,43
  The
  .I value
  of a simple-command is its exit status
! if it terminates normally or 200+\fIstatus\fP if it terminates abnormally (see
  .IR sigvec (2)
  for a list of status values).
  .LP

--- 36,42 -----
  The
  .I value
  of a simple-command is its exit status
! if it terminates normally or (octal) 200+\fIstatus\fP if it terminates abnormally (see
  .IR sigvec (2)
  for a list of status values).
  .PP
***************
*** 40,46
  if it terminates normally or 200+\fIstatus\fP if it terminates abnormally (see
  .IR sigvec (2)
  for a list of status values).
! .LP
  A
  .I pipeline
  is a sequence of one or more

--- 39,45 -----
  if it terminates normally or (octal) 200+\fIstatus\fP if it terminates abnormally (see
  .IR sigvec (2)
  for a list of status values).
! .PP
  A
  .I pipeline
  is a sequence of one or more
***************
*** 46,52
  is a sequence of one or more
  .I commands
  separated by
! .B \(or.
  The standard output of each command but the last is connected by a
  .IR pipe (2)
  to the standard input of the next command.

--- 45,52 -----
  is a sequence of one or more
  .I commands
  separated by
! .B \(or
! (or, for historical compatibility, by \fB^\fP).
  The standard output of each command but the last is connected by a
  .IR pipe (2)
  to the standard input of the next command.
***************
*** 52,58
  to the standard input of the next command.
  Each command is run as a separate process;
  the shell waits for the last command to terminate.
! .LP
  A
  .I list
  is a sequence of one or more

--- 52,58 -----
  to the standard input of the next command.
  Each command is run as a separate process;
  the shell waits for the last command to terminate.
! .PP
  A
  .I list
  is a sequence of one or more
***************
*** 60,66
  separated by
  .BR ; ,
  .BR & ,
! .B &&
  or
  .B \(or\|\(or
  and optionally terminated by

--- 60,66 -----
  separated by
  .BR ; ,
  .BR & ,
! .B && ,
  or
  .B \(or\|\(or
  and optionally terminated by
***************
*** 67,72
  .B ;
  or
  .BR & .
  .B ;
  and
  .B &

--- 67,73 -----
  .B ;
  or
  .BR & .
+ Of these four symbols,
  .B ;
  and
  .B &
***************
*** 90,96
  returns a zero (non zero) value.  Newlines may appear in a
  .I list,
  instead of semicolons, to delimit commands.
! .LP
  A
  .I command
  is either a simple-command or one of the following.

--- 91,97 -----
  returns a zero (non zero) value.  Newlines may appear in a
  .I list,
  instead of semicolons, to delimit commands.
! .PP
  A
  .I command
  is either a simple-command or one of the following.
***************
*** 143,148
  .B else
  .I list
  is executed.
  .TP
  \fBwhile \fIlist\fR \*(OK\fBdo \fIlist\fR\*(CK \fBdone\fR
  A

--- 144,158 -----
  .B else
  .I list
  is executed.
+ If no
+ .B else
+ .I list
+ or
+ .B then
+ .I list
+ is executed, then the
+ .B if
+ command returns a zero exit status.
  .TP
  \fBwhile \fIlist\fR \*(OK\fBdo \fIlist\fR\*(CK \fBdone\fR
  A
***************
*** 171,177
  .BI { " list " }
  .I list
  is simply executed.
! .LP
  The following words are only recognized as the first word of a command
  and when not quoted.
  .IP

--- 181,187 -----
  .BI { " list " }
  .I list
  is simply executed.
! .PP
  The following words are only recognized as the first word of a command
  and when not quoted.
  .IP
***************
*** 177,185
  .IP
  .B
  if then else elif fi case in esac for while until do done { }
! .PP
! .B Command substitution.
! .br
  The standard output from a command enclosed in a pair of back quotes 
  .RB ( \`\|\` )
  may be used as part or all of a word; trailing newlines are removed.

--- 187,198 -----
  .IP
  .B
  if then else elif fi case in esac for while until do done { }
! .SS Comments
! A word beginning with
! .B #
! causes that word and all the following characters up to a new-line
! to be ignored.
! .SS Command substitution.
  The standard output from a command enclosed in a pair of back quotes 
  .RB ( \`\|\` )
  may be used as part or all of a word; trailing newlines are removed.
***************
*** 183,191
  The standard output from a command enclosed in a pair of back quotes 
  .RB ( \`\|\` )
  may be used as part or all of a word; trailing newlines are removed.
! .PP
! .B Parameter substitution.
! .br
  The character
  .B $
  is used to introduce substitutable parameters.

--- 196,202 -----
  The standard output from a command enclosed in a pair of back quotes 
  .RB ( \`\|\` )
  may be used as part or all of a word; trailing newlines are removed.
! .SS Parameter substitution.
  The character
  .B $
  is used to introduce substitutable parameters.
***************
*** 194,200
  Variables may be set by writing
  .IP
  .IB name = value
! [
  .IB name = value
  ] ...
  .TP

--- 205,211 -----
  Variables may be set by writing
  .IP
  .IB name = value
! \*(OK
  .IB name = value
  \*(CK ...
  .PP
***************
*** 196,202
  .IB name = value
  [
  .IB name = value
! ] ...
  .TP
  $\fB\|{\fIparameter\fB\|}\fR
  A

--- 207,216 -----
  .IB name = value
  \*(OK
  .IB name = value
! \*(CK ...
! .PP
! Pattern matching is not performed on
! .IR value .
  .TP
  $\fB\|{\fIparameter\fB\|}\fR
  A
***************
*** 205,211
  .IR name ),
  a digit, or any of the characters
  .B
! * @ # ? \- $ !\|.
  The value, if any, of the parameter is substituted.
  The braces are required only when
  .I parameter

--- 219,225 -----
  .IR name ),
  a digit, or any of the characters
  .B
! * @ # ? \- $ + !\|.
  The value, if any, of the parameter is substituted.
  The braces are required only when
  .I parameter
***************
*** 210,216
  The braces are required only when
  .I parameter
  is followed by a letter, digit, or underscore
! that is not to be interpreted as part of its name.  If
  .I parameter
  is a digit, it is a positional parameter.  If
  .I parameter

--- 224,234 -----
  The braces are required only when
  .I parameter
  is followed by a letter, digit, or underscore
! that is not to be interpreted as part of its name.
! A
! .I name
! must begin with a letter or underscore.
! If
  .I parameter
  is a digit, it is a positional parameter.  If
  .I parameter
***************
*** 253,259
  is set, substitute
  .I word;
  otherwise substitute nothing.
! .LP
  In the above
  .I word
  is not evaluated unless it is to be used as the substituted string.

--- 271,277 -----
  is set, substitute
  .I word;
  otherwise substitute nothing.
! .PP
  In the above
  .I word
  is not evaluated unless it is to be used as the substituted string.
***************
*** 282,287
  .B $
  The process number of this shell.
  .TP
  .B !
  The process number of the last background command invoked.
  .PD

--- 300,317 -----
  .B $
  The process number of this shell.
  .TP
+ .B +
+ The process number of the partent of this shell.  In particular,
+ the value of
+ .B $+
+ will track the value of the
+ .IR getppid (2)
+ system call.  I.e. if
+ .I init
+ should inherit this shell,
+ .B $+
+ will become 1.
+ .TP
  .B !
  The process number of the last background command invoked.
  .PD
***************
*** 286,292
  The process number of the last background command invoked.
  .PD
  .RE
! .LP
  The following
  .I parameters
  are used but not set by the shell.

--- 316,322 -----
  The process number of the last background command invoked.
  .PD
  .RE
! .PP
  The following
  .I parameters
  are used but not set by the shell.
***************
*** 302,308
  .B
  .SM PATH
  The search path for commands (see
! .BR execution ).
  .TP
  .B
  .SM MAIL

--- 332,339 -----
  .B
  .SM PATH
  The search path for commands (see
! .I Execution
! below).
  .TP
  .B
  .SM MAIL
***************
*** 325,330
  .BR tab ,
  and
  .BR newline .
  .PD
  .RE
  .PP

--- 356,366 -----
  .BR tab ,
  and
  .BR newline .
+ .TP
+ .B HISTFILE
+ The file where command history is saved across login sessions.
+ The default value is
+ .BR $HOME/.history .
  .PD
  .RE
  .SS Tilde Substitution
***************
*** 327,332
  .BR newline .
  .PD
  .RE
  .PP
  .B Blank interpretation.
  .br

--- 363,375 -----
  .BR $HOME/.history .
  .PD
  .RE
+ .SS Tilde Substitution
+ An unquoted tilde character
+ .RB ( ~ )
+ will cause the shell to attempt a tilde substituion.  Tilde substitutions
+ are used to automatically determine home directories.  Both the current
+ user's home directory, and the home directory of any other user on
+ the system may be found.
  .PP
  A
  .B ~
***************
*** 328,336
  .PD
  .RE
  .PP
! .B Blank interpretation.
! .br
! After parameter and command substitution,
  any results of substitution are scanned for internal field separator
  characters (those found in
  .SM

--- 371,588 -----
  user's home directory, and the home directory of any other user on
  the system may be found.
  .PP
! A
! .B ~
! by itself is equivalent to using
! .BR \s-1$HOME\s+1 .
! E.g.
! .B ~/bin
! is the same as saying
! .BR \s-1$HOME\s+1/bin .
! The notation
! .B ~person
! will cause the shell to look up
! .BR person 's
! home directory in the
! .B /etc/passwd
! file, and substitute it in.  For example, if user
! .BR arnold 's
! home directory is
! .BR /user/arnold ,
! the shell would replace
! .BR ~arnold/bin
! with
! .BR /user/arnold/bin .
! .PP
! Tilde substitutions are recognized at the beginning of words, after
! equal signs (for shell variable assignment), in the middle of single letter
! flag arguments to commands (e.g. \fBecho \-t~arnold\fP), and after
! colons inside the
! .B
! .SM PATH
! shell parameter.
! .PP
! If
! .B /etc/passwd
! cannot be read, or if
! no user can be found to match the attempted tilde substitution,
! the text is left unmodified.
! .SS History Substitution
! When reading input from an interactive terminal, a
! .RB `` ! ''
! character, anywhere on the line,
! signals the shell that it should attempt
! to perform a history substitution.
! A history substitution is a shorthand method which allows the user
! to recall all or part of a previous command, possibly editing the
! recalled portion.
! The recalled (and possibly changed) command line is then placed into
! the current command line,
! to be passed on to the rest of the shell for normal processing.
! A history substitution takes the form:
! .PP
! .if t .RS
! \fB!\fP\^[ \fIstr\fP | \fB?\fIstr\fB?\fR | \fInum\fP ]\c
! [ \fB\(ga\fInum\fR [ \- [ \fInum\fP ] ]\c
! { \fB^\fIstr\fB^\fIstr\fB^\fR [\fBg\fP] }
! .if t .RE
! .PP
! A history substitution contains three parts;
! command selection, argument selection, and editing.
! .I Command selection
! chooses what command will be retrieved from the stored
! history.
! .I Argument selection
! chooses which arguments from that command will be extracted.
! .I Editing
! allows the user to change spelling or make a substitution.
! .PP
! The history substitution is triggered by the
! .RB `` ! '',
! and continues until another
! .RB `` ! ''
! is encountered, or until
! something that could not be part of a history substitution is seen.
! This is so that the
! history substitution will be properly concatenated with the following text.
! Whenever a history substitution is encountered and properly performed,
! the shell echoes the resulting line to the terminal and then executes the
! command.
! .PP
! History substitution occurs inside double quotes and grave accents, but will
! not occur inside single quotes.  To get a literal
! .RB `` ! ''
! character, outside of single quotes, precede it with a
! .BR \e .
! The
! .BR ? ,
! .BR \(ga ,
! and
! .B ^
! characters are treated specially by the history mechanism only when preceded
! by a
! .RB `` ! '',
! otherwise they have their normal meaning
! of ``match a single character'',
! ``enclose a command substitution'',
! and as a synonym for the \fB\(bv\fP
! character.
! .PP
! The full meaning of the history syntax is as follows:
! .RS
! .TP
! \fB!\fP\^[ \fIstr\fP | \fB?\fIstr\fB?\fR | \fInum\fP ]
! The first thing in a history substitution is
! .IR "command selection" .
! This is used to retrieve a given command line for use, or for further
! processing.  In a history command selection, \fB!\fIstr\fR
! will find the most recent command line that started with the
! characters in
! .IR str .
! \fB!?\fIstr\fB?\fR will find the most recent command line that contained
! .I str
! anywhere on the line.  It also allows
! .I str
! to contain blanks and tabs, whereas the first form does not.
! \fB!\fInum\fR allows the user to specify the number of a command, according
! to the output of the
! .B history
! command (see the section on special commands, below).
! .TP
! \fB\(ga\fInum\fR [ \- [ \fInum\fP ]
! The next portion of a history substitution is an optional
! .IR "argument selection" .
! This chooses which portions of the command are to be kept.
! History arguments are not exactly the same as the arguments the rest of
! the shell uses, since history expansion occurs before argument collection.
! Arguments in this context are blank or tab separated words on the command line.
! Single or double quoted strings, strings inside grave accents, shell regular
! expressions, commands in parentheses (which get executed in a subshell),
! and commands enclosed in braces,
! are all treated as single arguments for the history mechanism, even though
! they may have white space in them.
! .sp
! Arguments are numbered from zero, starting at the leftmost portion of the
! line.  In an argument selection, \fB\(ga\fInum\fR specifies that only argument
! .I num
! is to be extracted and kept for further processing or use, and the rest
! of the command line is to be dropped.
! \fB\(ga\fInum\fB\-\fInum\fR
! specifies that the arguments from the first
! .I num
! to the last
! .I num
! are to be kept. In place of any
! .IR num ,
! .B $
! may be specified to obtain the last argument on the line.
! The form \fB\(ga\-\fInum\fR is a shorthand for \fB\(ga\fP1\fB\-\fInum\fR
! and
! \fB\(ga\fInum\fB\-\fR
! is a short form for
! \fB\(ga\fInum\fB\-$\fR.
! Finally, the notation
! \fB\(ga\-\fP
! indicates all the arguments.  That is, \fB\(ga\-\fP implies
! \fB\(ga1\-$\fP.
! .TP
! \fB^\fIstr\fB^\fIstr\fB^\fR [\fBg\fP]
! The last portion of a history substitution is also optional, and is the
! .I editing
! phase.  This allows the remaining portions of the retrieved
! command line to modified, like the substitute command in
! .IR ed (1),
! although in a much more limited fashion.
! In the history mechanism,
! .I str
! is not a regular expression, as in
! .IR ed,
! but just a simple string.
! The history mechanism does not recognize
! either the shell's pattern matching characters or the editor's
! regular expression characters.
! Each substitution happens only once on a line, unless a trailing ``g''
! is appended to the substitution.  In this case, the substitution occurs
! globally (everywhere) on the line.
! Substitutions may be strung together,
! so that more than one can be done at once.
! The trailing ``g'' may be in either upper or lower case.
! .RE
! .PP
! Some examples of history substitution are given below.
! Should a history substitution fail, the errant command will
! .I not
! be added to the history buffers.
! .PP
! The history mechanism recognizes lines that end with unbalanced quotes.
! When the quotes are balanced on the next line(s), 
! It will join this line with the one that opened the quotes, keeping the
! embedded newline(s). So, e.g.,
! .RS
! .sp
! .nf
! .RB "$ " "echo 'open"
! .RB "> " "close'"
! .fi
! .RE
! .sp
! will be saved as one history ``event.''
! This does
! .I not
! extend to other shell constructs, like balancing parentheses across
! newlines.
! .PP
! The history mechanism keeps a maximum of
! 256
! stored commands at any one time, and the total text of the
! stored history may occupy no more than
! 4096
! characters.
! Experience indicates that it is not necessary to store more than this,
! and the extra history buffers should not make the shell too large for
! machines with small address spaces (e.g. PDP-11's).
! .SS Blank Interpretation
! After history, tilde, parameter and command substitution,
  any results of substitution are scanned for internal field separator
  characters (those found in
  .SM
***************
*** 340,348
  Implicit null arguments (those resulting from
  .I parameters
  that have no values) are removed.
! .PP
! .B File name generation.
! .br
  Following substitution, each command word is scanned for the characters
  .BR * ,
  .B ?

--- 592,598 -----
  Implicit null arguments (those resulting from
  .I parameters
  that have no values) are removed.
! .SS File name generation.
  Following substitution, each command word is scanned for the characters
  .BR * ,
  .B ?
***************
*** 370,376
  Matches any one of the characters enclosed.
  A pair of characters separated by
  .B \-
! matches any character lexically between the pair.
  .PD
  .PP
  .B Quoting.

--- 620,636 -----
  Matches any one of the characters enclosed.
  A pair of characters separated by
  .B \-
! matches any character lexically between the pair, inclusive.
! If the first character floolowing the opening
! .RB `` \*(OK ''
! is a
! .RB `` ! ''
! then any character not enclosed is matched.
! Note that when typing input from the terminal, the
! .RB `` ! ''
! should be preceded by a
! .BR \e ,
! so that the shell does not attempt to perform a history substitution.
  .PD
  .SS Quoting.
  The following characters have a special meaning to the shell
***************
*** 372,380
  .B \-
  matches any character lexically between the pair.
  .PD
! .PP
! .B Quoting.
! .br
  The following characters have a special meaning to the shell
  and cause termination of a word unless quoted.
  .LP

--- 632,638 -----
  .BR \e ,
  so that the shell does not attempt to perform a history substitution.
  .PD
! .SS Quoting.
  The following characters have a special meaning to the shell
  and cause termination of a word unless quoted.
  .LP
***************
*** 389,395
  is ignored.
  All characters enclosed between a pair of quote marks (\fB\'\|\'\fP),
  except a single quote, are quoted.  Inside double quotes (\fB"\|"\fP)
! parameter and command substitution occurs and
  .B
  \\
  quotes the characters

--- 647,653 -----
  is ignored.
  All characters enclosed between a pair of quote marks (\fB\'\|\'\fP),
  except a single quote, are quoted.  Inside double quotes (\fB"\|"\fP)
! history, parameter, and command substitution occurs and
  .B
  \\
  quotes the characters
***************
*** 394,400
  \\
  quotes the characters
  .B
! \\ \' "
  and
  .BR $ \|.
  .LP

--- 652,658 -----
  \\
  quotes the characters
  .B
! \\ \' " !
  and
  .BR $ \|.
  .PP
***************
*** 397,403
  \\ \' "
  and
  .BR $ \|.
! .LP
  .B
  "$*"
  is equivalent to

--- 655,661 -----
  \\ \' " !
  and
  .BR $ \|.
! .PP
  .B
  "$*"
  is equivalent to
***************
*** 412,421
  .SM
  .B
  "$1" "$2" ... .
! .PP
! .B Prompting.
! .br
! When used interactively, the shell prompts with the value of
  .SM
  PS1
  before reading a command.

--- 670,678 -----
  .SM
  .B
  "$1" "$2" ... .
! .SS Prompting
! When used interactively,
! the shell prompts with the value of
  .SM
  .B PS1
  before reading a command.
***************
*** 417,423
  .br
  When used interactively, the shell prompts with the value of
  .SM
! PS1
  before reading a command.
  If at any time a newline is typed and further input is needed
  to complete a command, the secondary prompt

--- 674,680 -----
  When used interactively,
  the shell prompts with the value of
  .SM
! .B PS1
  before reading a command.
  If the user is super-user and
  .SM
***************
*** 419,425
  .SM
  PS1
  before reading a command.
! If at any time a newline is typed and further input is needed
  to complete a command, the secondary prompt
  .RB ( \s-2$PS2\s0 )
  is issued.

--- 676,693 -----
  .SM
  .B PS1
  before reading a command.
! If the user is super-user and
! .SM
! .B PS1
! is not set to
! .RB `` "# \|" ''
! already, the
! .SM
! .B PS1
! prompt is followed by
! .RB `` "# \|" ''
! as a BRL-supplied safety reminder.
! If at any time a new-line is typed and further input is needed
  to complete a command, the secondary prompt
  (i.e., the value of
  .BR \s-1PS2\s+1 )
***************
*** 421,427
  before reading a command.
  If at any time a newline is typed and further input is needed
  to complete a command, the secondary prompt
! .RB ( \s-2$PS2\s0 )
  is issued.
  .PP
  .B Input output.

--- 689,696 -----
  as a BRL-supplied safety reminder.
  If at any time a new-line is typed and further input is needed
  to complete a command, the secondary prompt
! (i.e., the value of
! .BR \s-1PS2\s+1 )
  is issued.
  .PP
  Many people like to have the shell provide them with useful information
***************
*** 424,431
  .RB ( \s-2$PS2\s0 )
  is issued.
  .PP
! .B Input output.
! .br
  Before a command is executed its input and output
  may be redirected using a special notation interpreted by the shell.
  The following may appear anywhere in a simple-command

--- 693,752 -----
  .BR \s-1PS2\s+1 )
  is issued.
  .PP
! Many people like to have the shell provide them with useful information
! in their prompt.  To accomadate this, the shell will recognize special
! sequences of characters in the value of
! .BR PS1 ,
! and substitute the appropriate information for them.
! The special sequences and what they signify are:
! .RS
! .TP
! .B %e
! Place the current event number (as defined by the
! .B history
! command) into the prompt.
! If history evaluation has been turned off (via
! .BR "set -H" ),
! no number will be substituted in (i.e. the
! .B %e
! will be removed).
! .TP
! .B %h
! Place the machine's host name into the prompt.  The host name is usually
! the name by which the machine is known to the outside world for electronic
! mail addressing.
! .TP
! .B %l
! Place the user's login name into the prompt.
! The login name selected is the first entry in the
! .B /etc/passwd
! file whose
! .I uid
! matches the value of the
! .IR getuid (2)
! system call.
! This will be a problem on systems where multiple users share the same
! user-id number.
! .TP
! .B %t
! Place the current time of day, in the form \s-1HH:MM\s+1 into the prompt.
! The time is on a 24 hour clock, i.e. 1:30 in the afternoon will be 13:30.
! .TP
! .BI % x
! Place the character
! .I x
! into the prompt.
! If the user wishes to put a literal
! .B %
! into the prompt, then
! .B PS1
! should have
! .B %%
! in it.
! .RE
! .PP
! Some of these facilities are of more use than others.
! .SS Input/Output.
  Before a command is executed its input and output
  may be redirected using a special notation interpreted by the shell.
  The following may appear anywhere in a simple-command
***************
*** 458,464
  If the file exists, output is appended (by seeking to the end);
  otherwise the file is created.
  .TP
! \*(LT\*(LT\fI\|word\fP
  The shell input is read up to a line the same as
  .IR word ,
  or end of file.

--- 779,785 -----
  If the file exists, output is appended (by seeking to the end);
  otherwise the file is created.
  .TP
! \*(LT\*(LT\*(OK\fB\-\fP\*(CK\fI\|word\fP
  The shell input is read up to a line the same as
  .IR word ,
  or end of file.
***************
*** 477,482
  \\ $ \'
  and the first character of
  .I word.
  .TP
  \*(LT\|&\|\fIdigit\fP
  The standard input is duplicated from file descriptor

--- 798,810 -----
  \\ $ \'
  and the first character of
  .I word.
+ If
+ .B \-
+ is appended to \*(LT\|\*(LT, all leading tabs are stripped from
+ .I word
+ and from the document.
+ History substitution is turned off
+ while processing the document.
  .TP
  \*(LT\|&\|\fIdigit\fP
  The standard input is duplicated from file descriptor
***************
*** 488,493
  \*(LT\|&\|\-
  The standard input is closed.
  Similarly for the standard output using \*(GT\|.
  .PD
  .LP
  If one of the above is preceded by a digit, the

--- 816,829 -----
  \*(LT\|&\|\-
  The standard input is closed.
  Similarly for the standard output using \*(GT\|.
+ .TP
+ \*(LT\|\*(GTword
+ Use file
+ .I word
+ for standard input (file descriptor 0),
+ but open it for reading
+ .I and
+ writing.
  .PD
  .LP
  If one of the above is preceded by a digit, the
***************
*** 498,504
  .LP
  creates file descriptor 2 to be a duplicate
  of file descriptor 1.
! .LP
  If a command is followed by
  .B &
  then the default standard input for the command is the empty file

--- 834,840 -----
  .LP
  creates file descriptor 2 to be a duplicate
  of file descriptor 1.
! .PP
  If a command is followed by
  .B &
  then the default standard input for the command is the empty file
***************
*** 506,514
  Otherwise, the environment for the execution of a command contains the
  file descriptors of the invoking shell as modified by input
  output specifications.
! .PP
! .B Environment.
! .br
  The environment is a list of name-value pairs that is passed to
  an executed program in the same way as a normal argument list; see
  .IR execve (2)

--- 842,848 -----
  Otherwise, the environment for the execution of a command contains the
  file descriptors of the invoking shell as modified by input
  output specifications.
! .SS Environment.
  The environment is a list of name-value pairs that is passed to
  an executed program in the same way as a normal argument list; see
  .IR execve (2)
***************
*** 531,537
  plus any modifications or additions, all of which must be noted in
  .B export
  commands.
! .LP
  The environment for any
  .I simple-command
  may be augmented by prefixing it with one or more assignments to

--- 865,871 -----
  plus any modifications or additions, all of which must be noted in
  .B export
  commands.
! .PP
  The environment for any
  .I simple-command
  may be augmented by prefixing it with one or more assignments to
***************
*** 554,562
  set \-k
  echo a=b c
  .fi
! .PP
! .B Signals.
! .br
  The INTERRUPT and QUIT signals for an invoked
  command are ignored if the command is followed by
  .BR & ;

--- 888,894 -----
  set \-k
  echo a=b c
  .fi
! .SS Signals.
  The INTERRUPT and QUIT signals for an invoked
  command are ignored if the command is followed by
  .BR & ;
***************
*** 562,571
  .BR & ;
  otherwise signals have the values inherited by the shell from its parent.
  (But see also
! .BR trap. )
! .PP
! .B Execution.
! .br
  Each time a command is executed the above substitutions are carried out.
  Except for the 'special commands' listed below a new process is created and
  an attempt is made to execute the command via an

--- 894,904 -----
  .BR & ;
  otherwise signals have the values inherited by the shell from its parent.
  (But see also
! .BR trap .)
! When job control is enabled,
! .SM SIGTSTP
! causes a foreground command to be stopped.
! .SS Execution.
  Each time a command is executed the above substitutions are carried out.
  Except for the 'special commands' listed below a new process is created and
  an attempt is made to execute the command via an
***************
*** 570,576
  Except for the 'special commands' listed below a new process is created and
  an attempt is made to execute the command via an
  .IR execve (2).
! .LP
  The shell parameter
  .B
  .SM $PATH

--- 903,909 -----
  Except for the 'special commands' listed below a new process is created and
  an attempt is made to execute the command via an
  .IR execve (2).
! .PP
  The shell parameter
  .B
  .SM $PATH
***************
*** 586,594
  file, it is assumed to be a file containing shell commands.
  A subshell (i.e., a separate process) is spawned to read it.
  A parenthesized command is also executed in a subshell.
! .PP
! .B Special commands.
! .br
  The following commands are executed in the shell process
  and except where specified
  no input output redirection is permitted for such commands.

--- 919,925 -----
  file, it is assumed to be a file containing shell commands.
  A subshell (i.e., a separate process) is spawned to read it.
  A parenthesized command is also executed in a subshell.
! .SS Special commands.
  The following commands are executed in the shell process
  and except where specified
  no input output redirection is permitted for such commands.
***************
*** 595,600
  .TP
  .B :
  No effect; the command does nothing.
  .PD 0
  .TP
  .BI . \ file

--- 926,932 -----
  .TP
  .B :
  No effect; the command does nothing.
+ A zero exit code is returned.
  .PD 0
  .TP
  .BI . \ file
***************
*** 662,667
  of subsequently-executed commands.
  If no arguments are given, a list of exportable names is printed.
  .TP
  \fBlogin\fR \*(OK\fIarg\fR ...\*(CK
  Equivalent to 'exec login arg ...'.
  .TP

--- 994,1042 -----
  of subsequently-executed commands.
  If no arguments are given, a list of exportable names is printed.
  .TP
+ \fBhistory\fP \*(OK \fB\-irs\fP \*(OK \fIfilename\fP \*(CK \*(CK
+ The \fBhistory\fP command, with no arguments, will print all the commands that
+ are currently saved in the shell's history buffers.  As new commands are
+ executed, and space in the buffers runs out, old commands will be deleted.  The
+ .B history
+ commands prints out the stored commands with sequence numbers.  Negative
+ numbered commands, through command number zero, are commands that were
+ retrieved from the saved history file.  Commands starting at one were
+ entered during the current login session.
+ If a saved command contains embedded newlines, these will be printed out
+ as the sequence
+ .BR \en ,
+ so that individual command stay on one line.
+ .sp
+ The \fBhistory\fP command takes two optional arguments.  If the first
+ argument is \fB\-s\fP, the shell will save its current history buffers
+ in the file named as the third argument. If no file is given, it will
+ use the value of
+ .BR \s-1HISTFILE\s+1 .
+ .sp
+ Similarly, if the first argument is \fB\-r\fP, the shell will reset its
+ history buffers from the saved history in the file given as the third argument.
+ Again, if no file name is given,
+ .B \s-1$HISTFILE\s+1
+ will be used.
+ .sp
+ The command
+ .B history -i
+ will cause the shell to reinitialize its history buffers.  In other words,
+ all the shell's saved history will be thrown away, and the shell will
+ start from scratch.
+ .sp
+ The \fBhistory\fP command will have absolutely no effect at all if input
+ is not coming from a terminal.  I.e., inside shell files, the
+ .B history
+ command is effectively a null operation.
+ .sp
+ The
+ .B history
+ command will always have an exit status of 1 inside a shell file.
+ If input is coming from a terminal, then the exit status wil be 0
+ if the command succeeds, 1 otherwise.
+ .TP
  \fBlogin\fR \*(OK\fIarg\fR ...\*(CK
  Equivalent to 'exec login arg ...'.
  .TP
***************
*** 678,684
  by subsequent assignment.
  If no arguments are given, a list of all readonly names is printed.
  .TP
! \fBset\fR \*(OK\fB\-eknptuvx\fR \*(OK\fIarg \fR...\*(CK\*(CK
  .RS
  .PD 0
  .TP 3m

--- 1053,1059 -----
  by subsequent assignment.
  If no arguments are given, a list of all readonly names is printed.
  .TP
! \fBset\fR \*(OK\fB\-eknptuvxEHIJ\fR \*(OK\fIarg \fR...\*(CK\*(CK
  .RS
  .PD 0
  .TP 3m
***************
*** 704,709
  .B \-x
  Print commands and their arguments as they are executed.
  .TP
  .B \-
  Turn off the
  .B \-x

--- 1079,1128 -----
  .B \-x
  Print commands and their arguments as they are executed.
  .TP
+ .B \-E
+ Prevents an EOT
+ .RI ( control-D\^ )
+ from terminating an interactive shell.
+ Added by BRL mostly for use in
+ .IR .profile\^ s
+ to avoid accidental logout.
+ .TP
+ .B \-H
+ Disable history processing.  If the shell is invoked with this option,
+ it will not bother trying to restore its saved history from the
+ contents of
+ .BR \s-1$HISTFILE\s+1 .
+ While this flag is in effect, the shell will not save any commands in
+ its history buffers.
+ The sequence
+ .B %e
+ in the value of
+ .B \s-1PS1\s+1
+ will also have no effect on the generated prompt string.
+ If
+ .B set +H
+ is used to turn history processing back on, the shell will start saving
+ subsequent commands from that point on.
+ .TP
+ .B \-I
+ (BRL addition)
+ Prints a resource usage summary
+ (system plus user time, blocks input and output, page reclaims and faults)
+ for each command after it terminates.
+ .TP
+ .B \-J
+ (BRL addition)
+ Enables ``job control'' features (see below).
+ .TP
+ .B \-\-
+ Do not change any of the flags; useful in setting
+ .B $1
+ to
+ .BR \- .
+ .PP
+ Using
+ .B \+
+ rather than
  .B \-
  causes these flags to be turned off.
  .PP
***************
*** 705,717
  Print commands and their arguments as they are executed.
  .TP
  .B \-
! Turn off the
! .B \-x
! and
! .B \-v
! options.
! .PD
! .LP
  These flags can also be used upon invocation of the shell.
  The current set of flags may be found in
  .BR $\- .

--- 1124,1131 -----
  .B \+
  rather than
  .B \-
! causes these flags to be turned off.
! .PP
  These flags can also be used upon invocation of the shell.
  The current set of flags may be found in
  .BR $\- .
***************
*** 715,721
  These flags can also be used upon invocation of the shell.
  The current set of flags may be found in
  .BR $\- .
! .LP
  Remaining arguments are positional
  parameters and are assigned, in order, to
  .SM

--- 1129,1135 -----
  These flags can also be used upon invocation of the shell.
  The current set of flags may be found in
  .BR $\- .
! .PP
  Remaining arguments are positional
  parameters and are assigned, in order, to
  .SM
***************
*** 743,749
  (Note that
  .I arg
  is scanned once when the trap is set and once when the trap is taken.)
! Trap commands are executed in order of signal number.  If
  .I arg
  is absent, all trap(s)
  .I n

--- 1157,1168 -----
  (Note that
  .I arg
  is scanned once when the trap is set and once when the trap is taken.)
! Trap commands are executed in order of signal number.
! Any attempt to set a trap on a signal that
! was ignored on entry to the current shell
! is ineffective.
! An attempt to trap on signal 11 (memory fault) produces an error.
! If
  .I arg
  is absent, all trap(s)
  .I n
***************
*** 778,788
  is not given, all currently active child processes are waited for.
  The return code from this command is that of the process waited for.
  .PD
! .LP
! .PP
! .B Invocation.
! .br
! If the first character of argument zero is
  .BR \- ,
  commands are read from
  .BR \s-2$HOME\s0/.\|profile ,

--- 1197,1207 -----
  is not given, all currently active child processes are waited for.
  The return code from this command is that of the process waited for.
  .PD
! .SS Invocation
! If the shell is invoked through
! .IR execve (2)
! and the first character of argument zero
! is
  .BR \- ,
  commands are initially read from
  .BR \s-1$HOME\s+1/.profile ,
***************
*** 784,791
  .br
  If the first character of argument zero is
  .BR \- ,
! commands are read from
! .BR \s-2$HOME\s0/.\|profile ,
  if such a file exists.
  Commands are then read as described below.
  The following flags are interpreted by the shell when it is invoked.

--- 1203,1210 -----
  and the first character of argument zero
  is
  .BR \- ,
! commands are initially read from
! .BR \s-1$HOME\s+1/.profile ,
  if such a file exists.
  Next, whether or not the first character of argument zero was a
  .BR \- ,
***************
*** 787,793
  commands are read from
  .BR \s-2$HOME\s0/.\|profile ,
  if such a file exists.
! Commands are then read as described below.
  The following flags are interpreted by the shell when it is invoked.
  .PD 0
  .TP 11n

--- 1206,1231 -----
  commands are initially read from
  .BR \s-1$HOME\s+1/.profile ,
  if such a file exists.
! Next, whether or not the first character of argument zero was a
! .BR \- ,
! and no matter how the shell was invoked,
! the shell will read commands from the file
! .BR \s-1$HOME\s+1/.shrc ,
! if it exists.
! Then, if the shell is interactive, is not a forked subshell,
! and the
! .B \-H
! flag is not in effect,
! it will attempt to restore its saved history from
! .BR \s-1$HISTFILE\s+1 .
! Thereafter, commands are read as described below, which
! is also the case when the shell is invoked as
! .BR /bin/sh .
! If any character of argument zero past the last slash (if any) is
! .BR j ,
! the
! .B \-J
! (job control) flag is automatically set.
  The following flags are interpreted by the shell when it is invoked.
  .PD 0
  .TP 11n
***************
*** 820,825
  .B wait
  is interruptible).
  In all cases SIGQUIT is ignored by the shell.
  .PD
  .LP
  The remaining flags and arguments are described under the

--- 1258,1279 -----
  .B wait
  is interruptible).
  In all cases SIGQUIT is ignored by the shell.
+ .TP
+ .B \-r
+ If the
+ .B \-r
+ flag is present, the shell is a restricted shell.
+ .TP
+ .B \-q
+ If the
+ .B \-q
+ flag is present, the shell will do a ``quick'' startup.
+ This means that the shell will
+ .I not
+ read the contents of the
+ .B \s-1$HOME\s+1/.shrc
+ file.
+ The shell will also not try to read this file if it is a restricted shell.
  .PD
  .PP
  The remaining flags and arguments are described under the
***************
*** 821,827
  is interruptible).
  In all cases SIGQUIT is ignored by the shell.
  .PD
! .LP
  The remaining flags and arguments are described under the
  .B set
  command.

--- 1275,1281 -----
  file.
  The shell will also not try to read this file if it is a restricted shell.
  .PD
! .PP
  The remaining flags and arguments are described under the
  .B set
  command.
***************
*** 825,830
  The remaining flags and arguments are described under the
  .B set
  command.
  .SH FILES
  .RB $HOME/ . \^profile
  .br

--- 1279,1366 -----
  The remaining flags and arguments are described under the
  .B set
  command.
+ .SS Job Control.
+ Job control features are enabled by the
+ .B \-J
+ flag.
+ When job control is enabled,
+ background commands and foreground commands that have been stopped
+ (usually by a \s-1SIGTSTP\s0 signal generated by typing
+ .IR ^Z\^ )
+ are placed into separate individual
+ .IR "process groups"\^ .
+ The following commands are used to manipulate these process groups:
+ .PP
+ .PD 0
+ .TP
+ \f3jobs\fP
+ Display information about the controlled jobs.
+ The job number is given in brackets,
+ followed by a plus sign if it is the ``current job'',
+ then the process group number for the job,
+ then the command.
+ .TP
+ \f3fg\fP \*(OK \f2n\^\fP \*(CK
+ Resume the stopped foreground job in the foreground.
+ If the process group
+ .I n\^
+ is not specified then the ``current job'' is resumed.
+ .TP
+ \f3bg\fP \*(OK \f2n\^\fP \*(CK
+ Resume the stopped foreground job in the background.
+ If the process group
+ .I n\^
+ is not specified then the ``current job'' is resumed.
+ .TP
+ .B suspend
+ Suspend the shell process itself in the background.
+ The shell will complain
+ if it is a login shell, and will not suspend itself.
+ Otherwise, it does not matter whether or not job control is enabled.
+ .PD
+ .PP
+ With job control enabled,
+ there are the following additional substitutable parameters:
+ .PP
+ .PD 0
+ .TP
+ .BR %%
+ If there is a ``current job'',
+ then this expression is replaced by
+ its process group number.
+ .TP
+ .BI % n\^
+ If the specified job number is one of the known jobs,
+ then this expression is replaced by
+ the corresponding process group number.
+ .SS Saving and Restoring History
+ When an interactive shell starts up, if the
+ .B \-H
+ flag is not in effect, it will attempt to read the contents of
+ .B \s-1$HISTFILE\s+1
+ into its history buffers.  This allows the user to recall commands
+ executed during a previous login session.
+ When the shell exits or executes an
+ .B exec
+ (again, if
+ .B \-H
+ is not in effect), it will attempt to write its current history
+ buffers into
+ .BR \s-1$HISTFILE\s+1 ,
+ for use in a future login session.
+ .PP
+ The
+ .B history
+ command allows the user to save the current history buffers into
+ a file of his or her own choosing, or to restore them from a given file.
+ If
+ .B \-H
+ has been set, the
+ .B history
+ command will give a warning that history processing is not
+ available, and will
+ .I not
+ save or restore the shell's history buffers.
  .SH FILES
  .RB $HOME/ . \^profile
  .br
***************
*** 828,833
  .SH FILES
  .RB $HOME/ . \^profile
  .br
  /tmp/sh*
  .br
  /dev/null

--- 1364,1371 -----
  .SH FILES
  .RB $HOME/ . \^profile
  .br
+ .RB $HOME/ . \^shrc
+ .br
  /tmp/sh*
  .br
  /dev/null
***************
*** 833,838
  /dev/null
  .SH SEE ALSO
  csh(1),
  test(1),
  execve(2),
  environ(7)

--- 1371,1377 -----
  /dev/null
  .SH SEE ALSO
  csh(1),
+ ed(1),
  test(1),
  execve(2),
  getppid(2),
***************
*** 835,840
  csh(1),
  test(1),
  execve(2),
  environ(7)
  .SH DIAGNOSTICS
  Errors detected by the shell, such as syntax errors cause the shell

--- 1374,1380 -----
  ed(1),
  test(1),
  execve(2),
+ getppid(2),
  environ(7)
  .SH DIAGNOSTICS
  Errors detected by the shell, such as syntax errors cause the shell
***************
*** 849,851
  process invoked by &, the shell gets mixed up about naming the input document.
  A garbage file /tmp/sh* is created, and the shell complains about
  not being able to find the file by another name.

--- 1389,1505 -----
  process invoked by &, the shell gets mixed up about naming the input document.
  A garbage file /tmp/sh* is created, and the shell complains about
  not being able to find the file by another name.
+ .SH PYRAMID SPECIFIC
+ .PP
+ On computers manufactured by the Pyramid Corporation, which support
+ both the University of California at Berkeley 4.2BSD version of \s-1UNIX\s+1,
+ and the AT&T System V version of \s-1UNIX\s+1,
+ the shell has several additional capabilities.
+ .SS Special Commands
+ .PP
+ There are three additional commands built in to the shell. They are:
+ .RS
+ .TP
+ \fBatt\fP \*(OK command \*(CK
+ Switch the current ``universe'' to be ATT System V.
+ If a command is specified, that command will be run in the ``att''
+ universe, without affecting the shell's current universe.
+ The
+ .B \-t
+ option of
+ .B /bin/att
+ is not (yet) supported.
+ .TP
+ \fBucb\fP \*(OK command \*(CK
+ Switch the current ``universe'' to be University of California at
+ Berkeley 4.2BSD.
+ If a command is specified, that command will be run in the ``ucb''
+ universe, without affecting the shell's current universe.
+ The
+ .B \-t
+ option of
+ .B /bin/ucb
+ is not (yet) supported.
+ .TP
+ \fBuniverse\fP \*(OK \fB\-l\fP \*(CK
+ Print the current universe, either ``att'' or ``ucb''. The
+ .B \-l
+ option will print a longer, more explanative name for the current universe.
+ .RE
+ .PP
+ If the shell cannot determine the current universe when it starts up,
+ it will default to
+ .BR ucb .
+ .SS Shell Variables
+ .PP
+ There is an additional pre-defined shell parameter,
+ .BR \s-1UNIVERSE\s+1 .
+ The value of
+ .B \s-1UNIVERSE\s+1
+ .I always
+ tracks that of the current universe.  Using it is equivalent to a
+ \*`universe\` command substitution,
+ except that a new process will not be created.
+ This variable cannot be set by the user (it is \fBreadonly\fP),
+ and any inherited value from the environment will be ignored.
+ .SS Special Sequences for \s-1PS1\s+1
+ .PP
+ Finally, the sequence
+ .B %u
+ in the value of
+ .B \s-1PS1\s-1
+ will cause the shell to subsitute in the name of the current universe,
+ either ``att'' or ``ucb''.
+ .SH HISTORY EXAMPLES
+ Command history provides a powerful method for easily redoing previous
+ commands, or for quicly fixing typing mistakes.
+ Here are some annotated examples.  User input is in
+ .BR boldface .
+ .sp
+ .nf
+ # first, list some files
+ .RB "$ " lf
+ hello.c		echo.c
+ # now, make a typing mistake
+ .RB "$ " "cat hello"
+ hello: No such file or directory
+ # fix it.  The trailing ! ends the history substitution,
+ # in order to correctly concatenate it with the following .c
+ .RB "$ " "!!.c"
+ cat hello.c
+ main () { printf ("hello world\en"); }
+ # now look at echo.c instead
+ .RB "$ " "!^hello^echo"
+ cat echo.c
+ main () { printf ("echo: no arguments\en"); }
+ # do it again, just for fun
+ .RB "$ " "!"
+ cat echo.c
+ main () { printf ("echo: no arguments\en"); }
+ # now we'll rearrange some arguments
+ .RB "$ " "echo 1 2 3 4 5"
+ 1 2 3 4 5
+ # print last argument, first and second arguments, then change 4 to four
+ .RB "$ " "echo !\(ga$ !\(ga1-2 !\(ga4^4^four"
+ echo 5 1 2 four
+ 5 1 2 four
+ # do something with all the previous arguments at once
+ .RB "$ " "echo the previous arguments were !\(ga\-"
+ echo the previous arguments were 5 1 2 four
+ the previous arguments were 5 1 2 four
+ # now do some substitutions.  first get something to work with.
+ .RB "$ " "echo aa bb cc"
+ aa bb cc
+ # change the first 'a' to a 'b', and change all c's to d's
+ .RB "$ " "!^a^b^^c^d^g"
+ echo ba bb dd
+ ba bb dd
+ .fi
+ .PP
+ These few brief examples should provide a general feel for the
+ history mechanism.  The quickest way to learn it is to experiment
+ with it for a while, using the
+ .B echo
+ command, which can do very little damage.
+ While it looks cryptic when being typed, it is very general and
+ orthogonal, and quickly becomes natural.

sources-request@genrad.UUCP (06/11/85)

From: Arnold Robbins <gatech!arnold>

This is part 5 of 9.  It contains the first set of code diffs for the System V
Release 2 Bourne shell.

BSD users who happen to also have source for System V Release 2 will probably
want to use this version of the shell, since it has many bug fixes and
improvements over the (much) earlier version that comes with Berkeley Unix.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
----------- pretend your screen is really a paper towel ------------
:::::::: :fix :::::::
No differences encountered
:::::::: args.c :::::::
*** ../orig.u/args.c	Wed May 15 17:08:06 1985
--- args.c	Mon May 20 15:20:33 1985
***************
*** 13,19
  extern struct dolnod *freeargs();
  static struct dolnod *dolh;
  
! char	flagadr[14];
  
  char	flagchar[] =
  {

--- 13,23 -----
  extern struct dolnod *freeargs();
  static struct dolnod *dolh;
  
! #if JOBS
! char	flagadr[19];
! #else
! char	flagadr[17];
! #endif
  
  char	flagchar[] =
  {
***************
*** 30,35
  	'h',
  	'f',
  	'a',
  	 0
  };
  

--- 34,46 -----
  	'h',
  	'f',
  	'a',
+ #if JOBS
+ 	'J',
+ 	'I',
+ #endif
+ 	'E',
+ 	'q',	/* ADR --- -q to not read ~/.shrc */
+ 	'H',	/* ADR --- -H to turn off history mechanism */
  	 0
  };
  
***************
*** 48,53
  	hashflg,
  	nofngflg,
  	exportflg,
  	  0
  };
  

--- 59,71 -----
  	hashflg,
  	nofngflg,
  	exportflg,
+ #if JOBS
+ 	jobflg,
+ 	infoflg,
+ #endif
+ 	noeotflg,
+ 	quickflg,
+ 	nohistflg,
  	  0
  };
  
***************
*** 83,89
  
  		/*
  		 * Step along 'flagchar[]' looking for matches.
! 		 * 'sicr' are not legal with 'set' command.
  		 */
  
  		while (*++cp)

--- 101,107 -----
  
  		/*
  		 * Step along 'flagchar[]' looking for matches.
! 		 * 'sicrq' are not legal with 'set' command.
  		 */
  
  		while (*++cp)
***************
*** 93,99
  				flagc++;
  			if (*cp == *flagc)
  			{
! 				if (eq(argv[0], "set") && any(*cp, "sicr"))
  					failed(argv[1], badopt);
  				else
  				{

--- 111,117 -----
  				flagc++;
  			if (*cp == *flagc)
  			{
! 				if (eq(argv[0], "set") && any(*cp, "sicrq"))
  					failed(argv[1], badopt);
  				else
  				{
***************
*** 97,102
  					failed(argv[1], badopt);
  				else
  				{
  					flags |= flagval[flagc-flagchar];
  					if (flags & errflg)
  						eflag = errflg;

--- 115,124 -----
  					failed(argv[1], badopt);
  				else
  				{
+ #if JOBS
+ 					if (*cp == 'J')
+ 						j_init();
+ #endif
  					flags |= flagval[flagc-flagchar];
  					if (flags & errflg)
  						eflag = errflg;
***************
*** 116,121
  		argc--;
  	}
  	else if (argc > 1 && *argp[1] == '+')	/* unset flags x, k, t, n, v, e, u */
  	{
  		cp = argp[1];
  		while (*++cp)

--- 138,144 -----
  		argc--;
  	}
  	else if (argc > 1 && *argp[1] == '+')	/* unset flags x, k, t, n, v, e, u */
+ 						/* or jobs or history flag */
  	{
  		cp = argp[1];
  		while (*++cp)
***************
*** 126,132
  			/*
  			 * step through flags
  			 */
! 			if (!any(*cp, "sicr") && *cp == *flagc)
  			{
  				/*
  				 * only turn off if already on

--- 149,155 -----
  			/*
  			 * step through flags
  			 */
! 			if (!any(*cp, "sicrq") && *cp == *flagc)
  			{
  				/*
  				 * only turn off if already on
***************
*** 133,139
  				 */
  				if ((flags & flagval[flagc-flagchar]))
  				{
! 					flags &= ~(flagval[flagc-flagchar]);
  					if (*cp == 'e')
  						eflag = 0;
  				}

--- 156,165 -----
  				 */
  				if ((flags & flagval[flagc-flagchar]))
  				{
! #if JOBS
! 					if (*cp != 'J' || !j_finish(FALSE))
! #endif
! 						flags &= ~(flagval[flagc-flagchar]);
  					if (*cp == 'e')
  						eflag = 0;
  				}
:::::::: blok.c :::::::
*** ../orig.u/blok.c	Wed May 15 17:08:06 1985
--- blok.c	Thu May 16 16:56:01 1985
***************
*** 102,107
  {
  	register struct blk *p;
  
  	if ((p = ap) && p < bloktop)
  	{
  #ifdef DEBUG

--- 102,116 -----
  {
  	register struct blk *p;
  
+ #if gould
+ /*
+  *	On Vax, <bloktop skips things on stack, doesn't on Gould
+  *	where stack is below text.
+  */
+ 	int csrt();
+ 
+ 	if ((p = ap) && p < bloktop && p > (struct blk *)csrt)
+ #else
  	if ((p = ap) && p < bloktop)
  #endif
  	{
***************
*** 103,108
  	register struct blk *p;
  
  	if ((p = ap) && p < bloktop)
  	{
  #ifdef DEBUG
  		chkbptr(p);

--- 112,118 -----
  	if ((p = ap) && p < bloktop && p > (struct blk *)csrt)
  #else
  	if ((p = ap) && p < bloktop)
+ #endif
  	{
  #ifdef DEBUG
  		chkbptr(p);
:::::::: brkincr.h :::::::
*** ../orig.u/brkincr.h	Wed May 15 17:08:07 1985
--- brkincr.h	Thu May 16 16:57:06 1985
***************
*** 1,4
  /*	@(#)brkincr.h	1.2	*/
  /*	3.0 SID #	1.1	*/
  #define BRKINCR 01000
  #define BRKMAX 04000

--- 1,9 -----
  /*	@(#)brkincr.h	1.2	*/
  /*	3.0 SID #	1.1	*/
+ #if gould
+ #define BRKINCR 0x1000
+ #define BRKMAX 0x2000
+ #else
  #define BRKINCR 01000
  #define BRKMAX 04000
  #endif
***************
*** 2,4
  /*	3.0 SID #	1.1	*/
  #define BRKINCR 01000
  #define BRKMAX 04000

--- 6,9 -----
  #else
  #define BRKINCR 01000
  #define BRKMAX 04000
+ #endif
:::::::: cmd.c :::::::
No differences encountered
:::::::: ctype.c :::::::
*** ../orig.u/ctype.c	Wed May 15 17:08:09 1985
--- ctype.c	Mon May 20 16:14:46 1985
***************
*** 21,26
  	0,	0,	0,	0,	0,	0,	0,	0,
  
  /*	sp	!	"	#	$	%	&	'	*/
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
  
  /*	(	)	*	+	,	-	.	/	*/

--- 21,29 -----
  	0,	0,	0,	0,	0,	0,	0,	0,
  
  /*	sp	!	"	#	$	%	&	'	*/
+ #if JOBS
+ 	_SPC,	0,	_DQU,	0,	_DOL1,	_PCT,	_AMP,	0,
+ #else
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
  #endif
  
***************
*** 22,27
  
  /*	sp	!	"	#	$	%	&	'	*/
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
  
  /*	(	)	*	+	,	-	.	/	*/
  	_BRA,	_KET,	0,	0,	0,	0,	0,	0,

--- 25,31 -----
  	_SPC,	0,	_DQU,	0,	_DOL1,	_PCT,	_AMP,	0,
  #else
  	_SPC,	0,	_DQU,	0,	_DOL1,	0,	_AMP,	0,
+ #endif
  
  /*	(	)	*	+	,	-	.	/	*/
  	_BRA,	_KET,	0,	0,	0,	0,	0,	0,
:::::::: ctype.h :::::::
*** ../orig.u/ctype.h	Wed May 15 17:08:09 1985
--- ctype.h	Thu May 16 16:59:28 1985
***************
*** 46,51
  #define _BSL	(T_ESC)
  #define _DQU	(T_QOT)
  #define _DOL1	(T_SUB|T_ESC)
  
  #define _CBR	T_BRC
  #define _CKT	T_DEF

--- 46,54 -----
  #define _BSL	(T_ESC)
  #define _DQU	(T_QOT)
  #define _DOL1	(T_SUB|T_ESC)
+ #if JOBS
+ #define _PCT	(T_SUB|T_ESC)
+ #endif
  
  #define _CBR	T_BRC
  #define _CKT	T_DEF
***************
*** 77,83
  extern char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DIG))
! #define dolchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN))
  #define defchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DEF))
  #define setchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_SET))
  #define digchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_DIG))

--- 80,86 -----
  extern char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DIG))
! #define dolchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS))
  #define defchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DEF))
  #define setchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_SET))
  #define digchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_DIG))
:::::::: defs.c :::::::
*** ../orig.u/defs.c	Wed May 15 17:08:10 1985
--- defs.c	Mon May 20 15:56:37 1985
***************
*** 17,22
  struct ionod	*iopend;	/* documents waiting to be read at NL */
  struct fdsave	fdmap[NOFILE];
  
  /* substitution */
  int				dolc;
  char			**dolv;

--- 17,34 -----
  struct ionod	*iopend;	/* documents waiting to be read at NL */
  struct fdsave	fdmap[NOFILE];
  
+ /* history stuff */
+ int	event_count = 1;	/* event counting for the prompt */
+ int	expanded;		/* did a history expansion occur */
+ 
+ /* keep track of the parent pid */
+ int	ppid;
+ 
+ #if pyr
+ /* keep track of the current universe */
+ int	cur_univ;
+ #endif
+ 
  /* substitution */
  int				dolc;
  char			**dolv;
***************
*** 36,41
  /* special names */
  char			*pcsadr;
  char			*pidadr;
  char			*cmdadr;
  
  /* transput */ 

--- 48,54 -----
  /* special names */
  char			*pcsadr;
  char			*pidadr;
+ char			*ppidadr;
  char			*cmdadr;
  
  /* transput */ 
***************
*** 58,63
  /* execflgs */
  int				exitval;
  int				retval;
  BOOL			execbrk;
  int				loopcnt;
  int				breakcnt;

--- 71,79 -----
  /* execflgs */
  int				exitval;
  int				retval;
+ #if gould
+ int			execbrk;
+ #else
  BOOL			execbrk;
  #endif
  int				loopcnt;
***************
*** 59,64
  int				exitval;
  int				retval;
  BOOL			execbrk;
  int				loopcnt;
  int				breakcnt;
  int 			funcnt;

--- 75,81 -----
  int			execbrk;
  #else
  BOOL			execbrk;
+ #endif
  int				loopcnt;
  int				breakcnt;
  int 			funcnt;
:::::::: defs.h :::::::
*** ../orig.u/defs.h	Wed May 15 17:08:11 1985
--- defs.h	Wed Jun  5 15:20:27 1985
***************
*** 3,8
   *	UNIX shell
   */
  
  
  /* error exits from various parts of shell */
  #define 	ERROR		1

--- 3,11 -----
   *	UNIX shell
   */
  
+ #if JOBS || gould || pyr
+ #define		void	int	/* avoid compiler bug */
+ #endif
  
  /* error exits from various parts of shell */
  #define 	ERROR		1
***************
*** 74,79
  #define		SYSMEM		27
  #define		SYSTYPE  	28
  
  /* used for input and output of shell */
  #define 	INIO 		19
  

--- 77,99 -----
  #define		SYSMEM		27
  #define		SYSTYPE  	28
  
+ #if JOBS
+ #define		SYSJOBS		29
+ #define		SYSFG		30
+ #define		SYSBG		31
+ #define		SYSSUSPEND	32
+ #endif
+ 
+ #if pyr
+ #define		SYSATT		33
+ #define		SYSUCB		34
+ #define		SYSUNIVERSE	35
+ #define		U_ATT		1	/* ATT is Universe number 1 */
+ #define		U_UCB		2	/* UCB is Universe number 2 */
+ #endif
+ 
+ #define		SYSHISTORY	36
+ 
  /* used for input and output of shell */
  #define 	INIO 		19
  
***************
*** 96,101
  #include	"mode.h"
  #include	"name.h"
  #include	<signal.h>
  
  
  /*	error catching */

--- 116,133 -----
  #include	"mode.h"
  #include	"name.h"
  #include	<signal.h>
+ #if defined(JOBS) && ! defined (pyr)	/* avoid dual universe problems */
+ #define		SIGUSR1 16
+ #define		SIGUSR2	17
+ #else
+ #if ! defined (pyr)	/* avoid dual universe problems */
+ #define		SIGSTOP	17
+ #define		SIGTSTP	18
+ #define		SIGCONT	19
+ #define		SIGTTIN	21
+ #define		SIGTTOU	22
+ #endif
+ #endif
  
  #define		HISTSIZE	4096
  
***************
*** 97,102
  #include	"name.h"
  #include	<signal.h>
  
  
  /*	error catching */
  extern int 		errno;

--- 129,135 -----
  #endif
  #endif
  
+ #define		HISTSIZE	4096
  
  /*	error catching */
  extern int 		errno;
***************
*** 122,127
  extern char				*mactrim();
  extern char				*macro();
  extern char				*execs();
  extern char				*copyto();
  extern int				exname();
  extern char				*staknam();

--- 155,163 -----
  extern char				*mactrim();
  extern char				*macro();
  extern char				*execs();
+ extern char				*homedir();
+ extern char				*username();
+ extern char				*retcwd();
  extern char				*copyto();
  extern int				exname();
  extern char				*staknam();
***************
*** 130,135
  extern int				printexp();
  extern char				**setenv();
  extern long				time();
  
  #define 	attrib(n,f)		(n->namflg |= f)
  #define 	round(a,b)		(((int)(((char *)(a)+b)-1))&~((b)-1))

--- 166,178 -----
  extern int				printexp();
  extern char				**setenv();
  extern long				time();
+ #if JOBS
+ extern int				cwdir();	/* chdir() interface */
+ extern BOOL				unpost();
+ extern BOOL				j_finish();
+ extern char				*j_macro();
+ #endif
+ extern int				history();
  
  #define 	attrib(n,f)		(n->namflg |= f)
  #define 	round(a,b)		(((int)(((char *)(a)+b)-1))&~((b)-1))
***************
*** 146,151
  extern struct ionod		*iopend;	/* documents waiting to be read at NL */
  extern struct fdsave	fdmap[];
  
  
  /* substitution */
  extern int				dolc;

--- 189,197 -----
  extern struct ionod		*iopend;	/* documents waiting to be read at NL */
  extern struct fdsave	fdmap[];
  
+ /* history stuff */
+ extern int	event_count;	/* event counting for the prompt */
+ extern int	expanded;	/* did a history expansion occur? */
  
  /* keep track of the parent pid */
  extern int	ppid;
***************
*** 147,152
  extern struct fdsave	fdmap[];
  
  
  /* substitution */
  extern int				dolc;
  extern char				**dolv;

--- 193,208 -----
  extern int	event_count;	/* event counting for the prompt */
  extern int	expanded;	/* did a history expansion occur? */
  
+ /* keep track of the parent pid */
+ extern int	ppid;
+ 
+ #if pyr
+ /* keep track of the current universe */
+ extern int	cur_univ;
+ extern char	*univ_name[];		/* from <universe.h> */
+ extern char	*univ_longname[];
+ #endif
+ 
  /* substitution */
  extern int				dolc;
  extern char				**dolv;
***************
*** 166,171
  extern char				unexpected[];
  extern char				endoffile[];
  extern char				synmsg[];
  
  /* name tree and words */
  extern struct sysnod	reserved[];

--- 222,274 -----
  extern char				unexpected[];
  extern char				endoffile[];
  extern char				synmsg[];
+ extern char				dashi[];	/* ADR -- for history */
+ extern char				dashr[];	/* ADR */
+ extern char				dashs[];	/* ADR */
+ extern char				rdwstr[];	/* ADR */
+ #if JOBS
+ extern char				rsqbrk[];
+ extern char				spspstr[];
+ extern char				fgdstr[];
+ extern char				stpdstr[];
+ extern char				lotspstr[];
+ extern char				psgpstr[];
+ extern char				ptinstr[];
+ extern char				ptoustr[];
+ extern char				bgdstr[];
+ extern char				spcstr[];
+ extern char				rdinstr[];
+ extern char				appdstr[];
+ extern char				inlnstr[];
+ extern char				sfnstr[];
+ extern char				efnstr[];
+ extern char				semspstr[];
+ extern char				lpnstr[];
+ extern char				rpnstr[];
+ extern char				insstr[];
+ extern char				sdostr[];
+ extern char				sdonstr[];
+ extern char				sthnstr[];
+ extern char				selsstr[];
+ extern char				sfistr[];
+ extern char				iesacstr[];
+ extern char				casestr[];
+ extern char				pipestr[];
+ extern char				toastr[];
+ extern char				fromastr[];
+ extern char				andstr[];
+ extern char				orstr[];
+ extern char				forstr[];
+ extern char				amperstr[];
+ extern char				forstr[];
+ extern char				whilestr[];
+ extern char				untilstr[];
+ extern char				ifstr[];
+ extern char				casestr[];
+ #endif
+ #if SYMLINK
+ extern char				nolstat[];
+ #endif
  
  /* name tree and words */
  extern struct sysnod	reserved[];
***************
*** 186,191
  extern char				supprompt[];
  extern char				profile[];
  extern char				sysprofile[];
  
  /* built in names */
  extern struct namnod	fngnod;

--- 289,296 -----
  extern char				supprompt[];
  extern char				profile[];
  extern char				sysprofile[];
+ extern char				shrc[];
+ extern char				savehist[];
  
  /* built in names */
  extern struct namnod	fngnod;
***************
*** 199,204
  extern struct namnod	mchknod;
  extern struct namnod	acctnod;
  extern struct namnod	mailpnod;
  
  /* special names */
  extern char				flagadr[];

--- 304,313 -----
  extern struct namnod	mchknod;
  extern struct namnod	acctnod;
  extern struct namnod	mailpnod;
+ #if pyr
+ extern struct namnod	univnod;
+ #endif
+ extern struct namnod	histfnod;
  
  /* special names */
  extern char				flagadr[];
***************
*** 204,209
  extern char				flagadr[];
  extern char				*pcsadr;
  extern char				*pidadr;
  extern char				*cmdadr;
  
  extern char				defpath[];

--- 313,319 -----
  extern char				flagadr[];
  extern char				*pcsadr;
  extern char				*pidadr;
+ extern char				*ppidadr;
  extern char				*cmdadr;
  
  extern char				defpath[];
***************
*** 219,224
  extern char				mchkname[];
  extern char				acctname[];
  extern char				mailpname[];
  
  /* transput */
  extern char				tmpout[];

--- 329,338 -----
  extern char				mchkname[];
  extern char				acctname[];
  extern char				mailpname[];
+ #if pyr
+ extern char				univname[];	/* UNIVERSE */
+ #endif
+ extern char				histfilename[];	/* HISTFILE */
  
  /* transput */
  extern char				tmpout[];
***************
*** 236,241
  extern int				peekn;
  extern char				*comdiv;
  extern char				devnull[];
  
  /* flags */
  #define		noexec		01

--- 350,361 -----
  extern int				peekn;
  extern char				*comdiv;
  extern char				devnull[];
+ extern BOOL		catcheof;	/* set to catch EOF in readc() */
+ #if JOBS
+ extern int		j_original_pg;
+ extern int		j_default_pg;
+ extern BOOL		j_top_level;
+ #endif
  
  /* flags */
  #define		noexec		01
***************
*** 257,262
  #define		hashflg		040000
  #define		nofngflg	0200000
  #define		exportflg	0400000
  
  extern long				flags;
  extern int				rwait;	/* flags read waiting */

--- 377,390 -----
  #define		hashflg		040000
  #define		nofngflg	0200000
  #define		exportflg	0400000
+ #if JOBS
+ #define		jobflg		01000000
+ #define		infoflg		02000000
+ #endif
+ #define		dotflg		04000000
+ #define		noeotflg	010000000
+ #define		quickflg	020000000
+ #define		nohistflg	040000000
  
  extern long				flags;
  extern int				rwait;	/* flags read waiting */
***************
*** 265,270
  #include	<setjmp.h>
  extern jmp_buf			subshell;
  extern jmp_buf			errshell;
  
  /* fault handling */
  #include	"brkincr.h"

--- 393,402 -----
  #include	<setjmp.h>
  extern jmp_buf			subshell;
  extern jmp_buf			errshell;
+ #if defined(JOBS) && !defined(pyr)
+ #define setjmp(env)	_setjmp(env)
+ #define longjmp(env, val)	_longjmp(env, val)
+ #endif
  
  /* fault handling */
  #include	"brkincr.h"
***************
*** 271,276
  
  extern unsigned			brkincr;
  #define 	MINTRAP		0
  #define 	MAXTRAP		20
  
  #define 	TRAPSET		2

--- 403,411 -----
  
  extern unsigned			brkincr;
  #define 	MINTRAP		0
+ #if defined (JOBS)
+ #define		MAXTRAP		32
+ #else
  #define 	MAXTRAP		20
  #endif
  
***************
*** 272,277
  extern unsigned			brkincr;
  #define 	MINTRAP		0
  #define 	MAXTRAP		20
  
  #define 	TRAPSET		2
  #define 	SIGSET		4

--- 407,413 -----
  #define		MAXTRAP		32
  #else
  #define 	MAXTRAP		20
+ #endif
  
  #define 	TRAPSET		2
  #define 	SIGSET		4
***************
*** 278,284
  #define 	SIGMOD		8
  #define 	SIGCAUGHT	16
  
! extern int				fault();
  extern BOOL				trapnote;
  extern char				*trapcom[];
  extern BOOL				trapflg[];

--- 414,421 -----
  #define 	SIGMOD		8
  #define 	SIGCAUGHT	16
  
! extern void				fault();
! extern void				done();
  extern BOOL				trapnote;
  extern char				*trapcom[];
  extern BOOL				trapflg[];
***************
*** 293,298
  /* execflgs */
  extern int				exitval;
  extern int				retval;
  extern BOOL				execbrk;
  extern int				loopcnt;
  extern int				breakcnt;

--- 430,438 -----
  /* execflgs */
  extern int				exitval;
  extern int				retval;
+ #if gould
+ extern int				execbrk;
+ #else
  extern BOOL				execbrk;
  #endif
  extern int				loopcnt;
***************
*** 294,299
  extern int				exitval;
  extern int				retval;
  extern BOOL				execbrk;
  extern int				loopcnt;
  extern int				breakcnt;
  extern int				funcnt;

--- 434,440 -----
  extern int				execbrk;
  #else
  extern BOOL				execbrk;
+ #endif
  extern int				loopcnt;
  extern int				breakcnt;
  extern int				funcnt;
***************
*** 332,337
  extern char				badunset[];
  extern char				nohome[];
  extern char				badperm[];
  
  /*	'builtin' error messages	*/
  

--- 473,487 -----
  extern char				badunset[];
  extern char				nohome[];
  extern char				badperm[];
+ #if JOBS
+ extern char				cjpostr[];
+ extern char				jcoffstr[];
+ extern char				jpanstr[];
+ extern char				jinvstr[];
+ extern char				ncjstr[];
+ extern char				nstpstr[];
+ extern char				tasjstr[];
+ #endif
  
  /*	'builtin' error messages	*/
  
:::::::: dup.h :::::::
No differences encountered
:::::::: echo.c :::::::
*** ../orig.u/echo.c	Wed May 15 17:08:12 1985
--- echo.c	Tue May 21 18:05:45 1985
***************
*** 4,9
   *
   *	Bell Telephone Laboratories
   *
   */
  #include	"defs.h"
  

--- 4,11 -----
   *
   *	Bell Telephone Laboratories
   *
+  *	DAG -- changed to support 7th Edition "-n" option;
+  *	still not fully compatible since \ escapes are interpreted
   */
  #include	"defs.h"
  
***************
*** 17,22
  	register char	*cp;
  	register int	i, wd;
  	int	j;
  	
  	if(--argc == 0) {
  		prc_buff('\n');

--- 19,27 -----
  	register char	*cp;
  	register int	i, wd;
  	int	j;
+ #if JOBS
+ 	int	no_nl;
+ #endif
  	
  	if(--argc == 0) {
  		prc_buff('\n');
***************
*** 23,28
  		exit(0);
  	}
  
  	for(i = 1; i <= argc; i++) 
  	{
  		sigchk();

--- 28,40 -----
  		exit(0);
  	}
  
+ #if JOBS
+ 	if (no_nl = eq(argv[1], "-n"))	/* old-style no-newline flag */
+ 	{
+ 		--argc;			/* skip over "-n" argument */
+ 		++argv;
+ 	}
+ #endif
  	for(i = 1; i <= argc; i++) 
  	{
  		sigchk();
***************
*** 76,82
  			}
  			prc_buff(*cp);
  		}
! 		prc_buff(i == argc? '\n': ' ');
  	}
  	exit(0);
  }

--- 88,95 -----
  			}
  			prc_buff(*cp);
  		}
! 		if (i != argc)
! 			prc_buff(' ');
  	}
  #if JOBS
  	if (!no_nl)
***************
*** 78,83
  		}
  		prc_buff(i == argc? '\n': ' ');
  	}
  	exit(0);
  }
  

--- 91,100 -----
  		if (i != argc)
  			prc_buff(' ');
  	}
+ #if JOBS
+ 	if (!no_nl)
+ #endif
+ 		prc_buff ('\n');
  	exit(0);
  }
  
:::::::: error.c :::::::
*** ../orig.u/error.c	Wed May 15 17:08:12 1985
--- error.c	Tue May 21 18:04:08 1985
***************
*** 56,61
  	}
  }
  
  done()
  {
  	register char	*t;

--- 56,62 -----
  	}
  }
  
+ void
  done()
  {
  	register char	*t;
***************
*** 75,80
  #ifdef ACCT
  	doacct();
  #endif
  	exit(exitval);
  }
  

--- 76,82 -----
  #ifdef ACCT
  	doacct();
  #endif
+ 	histsave (histfnod.namval);
  	exit(exitval);
  }
  
:::::::: expand.c :::::::
*** ../orig.u/expand.c	Wed May 15 17:08:13 1985
--- expand.c	Thu May 16 17:46:53 1985
***************
*** 9,14
  #include	"defs.h"
  #include	<sys/types.h>
  #include	<sys/stat.h>
  #include	<sys/dir.h>
  
  #define MAXDIR	64

--- 9,17 -----
  #include	"defs.h"
  #include	<sys/types.h>
  #include	<sys/stat.h>
+ #if JOBS
+ #include	<dir.h>
+ #else
  #include	<sys/dir.h>
  #endif
  
***************
*** 10,15
  #include	<sys/types.h>
  #include	<sys/stat.h>
  #include	<sys/dir.h>
  
  #define MAXDIR	64
  struct direct		*getdir();

--- 13,19 -----
  #include	<dir.h>
  #else
  #include	<sys/dir.h>
+ #endif
  
  #if JOBS
  #define		getdir(dirf)	readdir(dirf)
***************
*** 11,16
  #include	<sys/stat.h>
  #include	<sys/dir.h>
  
  #define MAXDIR	64
  struct direct		*getdir();
  

--- 15,24 -----
  #include	<sys/dir.h>
  #endif
  
+ #if JOBS
+ #define		getdir(dirf)	readdir(dirf)
+ #define		entry		e->d_name
+ #else
  #define MAXDIR	64
  struct direct		*getdir();
  
***************
*** 18,23
  static int		nxtdir = -1;
  static int		maxdir = 0;
  static char		entry[DIRSIZ+1];
  
  /*
   * globals (file name generation)

--- 26,32 -----
  static int		nxtdir = -1;
  static int		maxdir = 0;
  static char		entry[DIRSIZ+1];
+ #endif
  
  /*
   * globals (file name generation)
***************
*** 34,40
  expand(as, rcnt)
  	char	*as;
  {
! 	int	count, dirf;
  	BOOL	dir = 0;
  	char	*rescan = 0;
  	register char	*s, *cs;

--- 43,54 -----
  expand(as, rcnt)
  	char	*as;
  {
! 	int	count;
! #if JOBS
! 	DIR	*dirf;
! #else
! 	int	dirf;
! #endif
  	BOOL	dir = 0;
  	char	*rescan = 0;
  	register char	*s, *cs;
***************
*** 109,114
  		}
  	}
  
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
  	{
  		if (fstat(dirf, &statb) != -1 &&

--- 123,131 -----
  		}
  	}
  
+ #if JOBS
+ 	if (dirf = opendir(*s ? s : ".", 0))
+ #else
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
  #endif
  	{
***************
*** 110,115
  	}
  
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
  	{
  		if (fstat(dirf, &statb) != -1 &&
  		    (statb.st_mode & S_IFMT) == S_IFDIR)

--- 127,133 -----
  	if (dirf = opendir(*s ? s : ".", 0))
  #else
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
+ #endif
  	{
  #if JOBS
  		if (fstat(dirf->dd_fd, &statb) != -1 &&
***************
*** 111,116
  
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
  	{
  		if (fstat(dirf, &statb) != -1 &&
  		    (statb.st_mode & S_IFMT) == S_IFDIR)
  			dir++;

--- 129,137 -----
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
  #endif
  	{
+ #if JOBS
+ 		if (fstat(dirf->dd_fd, &statb) != -1 &&
+ #else
  		if (fstat(dirf, &statb) != -1 &&
  #endif
  		    (statb.st_mode & S_IFMT) == S_IFDIR)
***************
*** 112,117
  	if ((dirf = open(*s ? s : ".", 0)) > 0)
  	{
  		if (fstat(dirf, &statb) != -1 &&
  		    (statb.st_mode & S_IFMT) == S_IFDIR)
  			dir++;
  		else

--- 133,139 -----
  		if (fstat(dirf->dd_fd, &statb) != -1 &&
  #else
  		if (fstat(dirf, &statb) != -1 &&
+ #endif
  		    (statb.st_mode & S_IFMT) == S_IFDIR)
  			dir++;
  		else
***************
*** 115,120
  		    (statb.st_mode & S_IFMT) == S_IFDIR)
  			dir++;
  		else
  			close(dirf);
  	}
  

--- 137,145 -----
  		    (statb.st_mode & S_IFMT) == S_IFDIR)
  			dir++;
  		else
+ #if JOBS
+ 			closedir(dirf);
+ #else
  			close(dirf);
  #endif
  	}
***************
*** 116,121
  			dir++;
  		else
  			close(dirf);
  	}
  
  	count = 0;

--- 141,147 -----
  			closedir(dirf);
  #else
  			close(dirf);
+ #endif
  	}
  
  	count = 0;
***************
*** 139,144
  
  		while ((e = getdir(dirf)) && (trapnote & SIGSET) == 0)
  		{
  			*(movstrn(e->d_name, entry, DIRSIZ)) = 0;
  
  			if (entry[0] == '.' && *cs != '.')

--- 165,171 -----
  
  		while ((e = getdir(dirf)) && (trapnote & SIGSET) == 0)
  		{
+ #if !defined (JOBS)
  			*(movstrn(e->d_name, entry, DIRSIZ)) = 0;
  #endif
  
***************
*** 140,145
  		while ((e = getdir(dirf)) && (trapnote & SIGSET) == 0)
  		{
  			*(movstrn(e->d_name, entry, DIRSIZ)) = 0;
  
  			if (entry[0] == '.' && *cs != '.')
  #ifndef BOURNE

--- 167,173 -----
  		{
  #if !defined (JOBS)
  			*(movstrn(e->d_name, entry, DIRSIZ)) = 0;
+ #endif
  
  			if (entry[0] == '.' && *cs != '.')
  #ifndef BOURNE
***************
*** 159,164
  				count++;
  			}
  		}
  		close(dirf);
  
  		if (rescan)

--- 187,195 -----
  				count++;
  			}
  		}
+ #if JOBS
+ 		closedir(dirf);
+ #else
  		close(dirf);
  #endif
  
***************
*** 160,165
  			}
  		}
  		close(dirf);
  
  		if (rescan)
  		{

--- 191,197 -----
  		closedir(dirf);
  #else
  		close(dirf);
+ #endif
  
  		if (rescan)
  		{
***************
*** 191,196
  }
  
  
  reset_dir()
  {
  	nxtdir = -1;

--- 223,229 -----
  }
  
  
+ #if !defined (JOBS)
  reset_dir()
  {
  	nxtdir = -1;
***************
*** 231,236
  		return(&dirbuf[nxtdir]);
  	}
  }
  
  
  gmatch(s, p)

--- 264,270 -----
  		return(&dirbuf[nxtdir]);
  	}
  }
+ #endif
  
  
  gmatch(s, p)
:::::::: fault.c :::::::
*** ../orig.u/fault.c	Wed May 15 17:08:14 1985
--- fault.c	Wed May 22 11:50:16 1985
***************
*** 8,14
  
  #include	"defs.h"
  
! extern int	done();
  
  char	*trapcom[MAXTRAP];
  BOOL	trapflg[MAXTRAP] =

--- 8,14 -----
  
  #include	"defs.h"
  
! extern void	done();
  
  char	*trapcom[MAXTRAP];
  BOOL	trapflg[MAXTRAP] =
***************
*** 31,37
  	0, 	/* software termination */
  	0,	/* unassigned */
  	0,	/* unassigned */
! 	0,	/* death of child */
  	0,	/* power fail */
  };
  

--- 31,37 -----
  	0, 	/* software termination */
  	0,	/* unassigned */
  	0,	/* unassigned */
! 	0,	/* death of child (if not BSD) */
  	0,	/* power fail */
  };
  
***************
*** 35,41
  	0,	/* power fail */
  };
  
! int 	(*(sigval[]))() = 
  {
  	0,
  	done,

--- 35,41 -----
  	0,	/* power fail */
  };
  
! void 	(*(sigval[MAXTRAP]))() = 	/* DAG -- make sure ther are MAXTRAP */
  {
  	0,
  	done,
***************
*** 54,59
  	fault,
  	fault,
  	done,
  	done,
  	done,
  	done

--- 54,62 -----
  	fault,
  	fault,
  	done,
+ #if JOBS
+ 	0,	/* SIGSTOP */
+ #else
  	done,
  #endif
  	done,
***************
*** 55,60
  	fault,
  	done,
  	done,
  	done,
  	done
  };

--- 58,64 -----
  	0,	/* SIGSTOP */
  #else
  	done,
+ #endif
  	done,
  	done,
  #if JOBS
***************
*** 56,61
  	done,
  	done,
  	done,
  	done
  };
  

--- 60,78 -----
  	done,
  #endif
  	done,
+ 	done,
+ #if JOBS
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
+ 	done,
  	done
  #endif
  };
***************
*** 57,62
  	done,
  	done,
  	done
  };
  
  /* ========	fault handling routines	   ======== */

--- 74,80 -----
  	done,
  	done,
  	done
+ #endif
  };
  
  /* ========	fault handling routines	   ======== */
***************
*** 62,67
  /* ========	fault handling routines	   ======== */
  
  
  fault(sig)
  register int	sig;
  {

--- 80,86 -----
  /* ========	fault handling routines	   ======== */
  
  
+ void	/* DAG */
  fault(sig)
  register int	sig;
  {
***************
*** 105,111
  	setsig(SIGALRM);
  	setsig(SIGTERM);
  	setsig(SIGUSR1);
! 	setsig(SIGUSR2);
  }
  
  ignsig(n)

--- 124,132 -----
  	setsig(SIGALRM);
  	setsig(SIGTERM);
  	setsig(SIGUSR1);
! #ifndef JOBS
! 	setsig(SIGUSR2);	/* aka SIGSTOP */
! #endif
  }
  
  ignsig(n)
:::::::: func.c :::::::
*** ../orig.u/func.c	Wed May 15 17:08:15 1985
--- func.c	Wed Jun  5 16:04:53 1985
***************
*** 305,310
  					{
  						struct argnod	*arg = swl->regptr;
  
  						if (arg)
  						{
  							prs_buff(arg->argval);

--- 305,311 -----
  					{
  						struct argnod	*arg = swl->regptr;
  
+ 						prc_buff (NL);	/* DAG (was missing) */
  						if (arg)
  						{
  							prs_buff(arg->argval);
***************
*** 323,328
  						prs_buff(";;");
  						swl = swl->regnxt;
  					}
  				}
  				break;
  			} 

--- 324,330 -----
  						prs_buff(";;");
  						swl = swl->regnxt;
  					}
+ 					prs_buff ("\nesac");	/* DAG (was missing) */
  				}
  				break;
  			} 
***************
*** 354,360
  		iof = iop->iofile;
  		ion = iop->ioname;
  
! 		if (*ion)
  		{
  			prn_buff(iof & IOUFD);
  

--- 356,362 -----
  		iof = iop->iofile;
  		ion = iop->ioname;
  
! 		if (ion && *ion)	/* DAG -- added safety check */
  		{
  			prn_buff(iof & IOUFD);
  
***************
*** 368,373
  					prs_buff("<&");
  
  			}
  			else if ((iof & IOPUT) == 0)
  				prc_buff('<');
  			else if (iof & IOAPP)

--- 370,377 -----
  					prs_buff("<&");
  
  			}
+ 			else if (iof & IORDW)
+ 				prs_buff(rdwstr);	/* ADR */
  			else if ((iof & IOPUT) == 0)
  				prc_buff('<');
  			else if (iof & IOAPP)
:::::::: hash.c :::::::
*** ../orig.u/hash.c	Wed May 15 17:08:16 1985
--- hash.c	Tue May 21 18:08:16 1985
***************
*** 86,91
  	int 			res;		
  
  	i = hash(str);
  
  	if(table[i] == 0)
  	{			

--- 86,94 -----
  	int 			res;		
  
  	i = hash(str);
+ #if gould
+ 	i &= ~(0x80000000 >> (shift - 1));	/* work around compiler bug */
+ #endif
  
  	if(table[i] == 0)
  	{			
:::::::: hash.h :::::::
No differences encountered
:::::::: hashserv.c :::::::
No differences encountered
:::::::: io.c :::::::
*** ../orig.u/io.c	Wed May 15 17:08:19 1985
--- io.c	Thu May 16 18:03:36 1985
***************
*** 7,12
   */
  
  #include	"defs.h"
  #include	"dup.h"
  #include	<fcntl.h>
  

--- 7,13 -----
   */
  
  #include	"defs.h"
+ #ifdef RES	/* DAG -- conditionalize */
  #include	"dup.h"
  #include	<sys/types.h>
  #include	<sys/stat.h>
***************
*** 8,13
  
  #include	"defs.h"
  #include	"dup.h"
  #include	<fcntl.h>
  
  short topfd;

--- 9,17 -----
  #include	"defs.h"
  #ifdef RES	/* DAG -- conditionalize */
  #include	"dup.h"
+ #include	<sys/types.h>
+ #include	<sys/stat.h>
+ #else
  #include	<fcntl.h>
  #endif
  
***************
*** 9,14
  #include	"defs.h"
  #include	"dup.h"
  #include	<fcntl.h>
  
  short topfd;
  

--- 13,19 -----
  #include	<sys/stat.h>
  #else
  #include	<fcntl.h>
+ #endif
  
  short topfd;
  
***************
*** 293,298
  {
  	register int	f;
  
  	f = fcntl(fd, F_DUPFD, 10);
  	return(f);
  }

--- 298,316 -----
  {
  	register int	f;
  
+ #ifdef RES	/* DAG -- bug fix */
+ 	for ( f = 10; f <= INIO; ++f )
+ 	{
+ 		struct stat	statb;
+ 
+ 		if (fstat(fd, &statb) != 0)	/* if already in use, try another */
+ 		{
+ 			dup (fd | DUPFLG, f);
+ 			return f;
+ 		}
+ 	}
+ 	return -1;	/* no free file descriptors */
+ #else
  	f = fcntl(fd, F_DUPFD, 10);
  #endif
  	return(f);
***************
*** 294,299
  	register int	f;
  
  	f = fcntl(fd, F_DUPFD, 10);
  	return(f);
  }
  

--- 312,318 -----
  	return -1;	/* no free file descriptors */
  #else
  	f = fcntl(fd, F_DUPFD, 10);
+ #endif
  	return(f);
  }
  
:::::::: mac.h :::::::
*** ../orig.u/mac.h	Wed May 15 17:08:19 1985
--- mac.h	Thu May 16 18:04:59 1985
***************
*** 19,24
  #define RQ	'\''
  #define MINUS	'-'
  #define COLON	':'
  #define TAB	'\t'
  
  

--- 19,25 -----
  #define RQ	'\''
  #define MINUS	'-'
  #define COLON	':'
+ #define SQUIGGLE	'~'	/* TILDE defined in BSD tty handler */
  #define TAB	'\t'
  
  
:::::::: macro.c :::::::
*** ../orig.u/macro.c	Wed May 15 17:08:20 1985
--- macro.c	Thu May 16 18:13:16 1985
***************
*** 67,73
  	d = readc();
  	if (!subchar(d))
  		return(d);
! 	if (d == DOLLAR)
  	{
  		register int	c;
  

--- 67,74 -----
  	d = readc();
  	if (!subchar(d))
  		return(d);
! #if JOBS
! 	if (d == PERCENT && (flags&jobflg))
  	{
  		register int	c;
  
***************
*** 71,76
  	{
  		register int	c;
  
  		if ((c = readc(), dolchar(c)))
  		{
  			struct namnod *n = (struct namnod *)NIL;

--- 72,95 -----
  	{
  		register int	c;
  
+ 		peekc = (c = readc()) | MARK;
+ 		if (digchar(c) || c == PERCENT)
+ 		{
+ 			register char *v;
+ 
+ 			if (v = j_macro())	/* %number or %% handled */
+ 				while (c = *v++)
+ 					pushstak(c | quote);
+ 			/* else expands to nothingness */
+ 			goto retry;
+ 		}
+ 	}
+ 	else
+ #endif
+ 	    if (d == DOLLAR)
+ 	    {
+ 		register int	c;
+ 
  		if ((c = readc(), dolchar(c)))
  		{
  			struct namnod *n = (struct namnod *)NIL;
***************
*** 114,119
  			}
  			else if (c == '$')
  				v = pidadr;
  			else if (c == '!')
  				v = pcsadr;
  			else if (c == '#')

--- 133,147 -----
  			}
  			else if (c == '$')
  				v = pidadr;
+ 			else if (c == '+')
+ 			{
+ 				if (ppid != getppid())	/* parent died */
+ 				{
+ 					ppid = getppid();
+ 					assnum (&ppidadr, ppid);
+ 				}
+ 				v = ppidadr;
+ 			}
  			else if (c == '!')
  				v = pcsadr;
  			else if (c == '#')
***************
*** 207,213
  		}
  		else
  			peekc = c | MARK;
! 	}
  	else if (d == endch)
  		return(d);
  	else if (d == SQUOTE)

--- 235,241 -----
  		}
  		else
  			peekc = c | MARK;
! 	    }
  	else if (d == endch)
  		return(d);
  	else if (d == SQUOTE)
***************
*** 273,278
  		push(&cb);
  		estabf(argc);
  	}
  	{
  		register struct trenod *t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG));
  		int		pv[2];

--- 301,309 -----
  		push(&cb);
  		estabf(argc);
  	}
+ #if JOBS
+ 	set_wfence();
+ #endif
  	{
  		register struct trenod *t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG));
  		int		pv[2];
:::::::: main.c :::::::
*** ../orig.u/main.c	Wed May 15 17:08:21 1985
--- main.c	Thu Jun  6 09:41:44 1985
***************
*** 11,16
  #include	"timeout.h"
  #include	<sys/types.h>
  #include	<sys/stat.h>
  #include        "dup.h"
  
  #ifdef RES

--- 11,17 -----
  #include	"timeout.h"
  #include	<sys/types.h>
  #include	<sys/stat.h>
+ #ifdef RES	/* DAG -- conditionalize */
  #include        "dup.h"
  #endif
  
***************
*** 12,17
  #include	<sys/types.h>
  #include	<sys/stat.h>
  #include        "dup.h"
  
  #ifdef RES
  #include	<sgtty.h>

--- 13,19 -----
  #include	<sys/stat.h>
  #ifdef RES	/* DAG -- conditionalize */
  #include        "dup.h"
+ #endif
  
  #ifdef RES
  #include	<sgtty.h>
***************
*** 15,20
  
  #ifdef RES
  #include	<sgtty.h>
  #endif
  
  static BOOL	beenhere = FALSE;

--- 17,24 -----
  
  #ifdef RES
  #include	<sgtty.h>
+ #else
+ #include	<fcntl.h>	/* DAG -- for defines */
  #endif
  
  BOOL		catcheof = FALSE;	/* not yet */
***************
*** 17,22
  #include	<sgtty.h>
  #endif
  
  static BOOL	beenhere = FALSE;
  char		tmpout[20] = "/tmp/sh-";
  struct fileblk	stdfile;

--- 21,27 -----
  #include	<fcntl.h>	/* DAG -- for defines */
  #endif
  
+ BOOL		catcheof = FALSE;	/* not yet */
  static BOOL	beenhere = FALSE;
  char		tmpout[20] = "/tmp/sh-";
  struct fileblk	stdfile;
***************
*** 43,48
  	register int	rflag = ttyflg;
  	int		rsflag = 1;	/* local restricted flag */
  	struct namnod	*n;
  
  	stdsigs();
  

--- 48,56 -----
  	register int	rflag = ttyflg;
  	int		rsflag = 1;	/* local restricted flag */
  	struct namnod	*n;
+ #if JOBS
+ 	char *sim;	/* BRL security, for better checking of restricted */
+ #endif
  
  	stdsigs();
  
***************
*** 77,82
  
  #ifndef RES
  
  	if (c > 0 && any('r', simple(*v)))
  		rflag = 0;
  

--- 85,94 -----
  
  #ifndef RES
  
+ #ifdef JOBS
+ 	/* smarter check for restricted shell, courtesy of BRL */
+ 	if (c > 0 && (eq(sim = simple(*v), "rsh") || eq(sim,"-rsh")))
+ #else
  	if (c > 0 && any('r', simple(*v)))
  #endif
  		rflag = 0;
***************
*** 78,83
  #ifndef RES
  
  	if (c > 0 && any('r', simple(*v)))
  		rflag = 0;
  
  #endif

--- 90,96 -----
  	if (c > 0 && (eq(sim = simple(*v), "rsh") || eq(sim,"-rsh")))
  #else
  	if (c > 0 && any('r', simple(*v)))
+ #endif
  		rflag = 0;
  
  #endif
***************
*** 108,113
  	dolv = v + c - dolc;
  	dolc--;
  
  	/*
  	 * return here for shell file execution
  	 * but not for parenthesis subshells

--- 121,147 -----
  	dolv = v + c - dolc;
  	dolc--;
  
+ #if JOBS
+ 	j_default_pg = getpid();
+ 	j_original_pg = getpgrp();
+ 
+ 	/* enable job control if argv[0] has a 'j' in its simple name */
+ 	if ((flags & jobflg) == 0 && c > 0 && any('j', simple(*v))
+ 		&& comdiv == 0 /* set by options */ && (flags & stdflg))
+ 	{
+ 		j_init();
+ 		flags |= jobflg;
+ 		{			/* append 'J' to $- string */
+ 		register char *flagc = flagadr;
+ 
+ 		while (*flagc)
+ 			flagc++;
+ 		*flagc++ = 'J';
+ 		*flagc = 0;
+ 		}
+ 	}
+ #endif
+ 
  	/*
  	 * return here for shell file execution
  	 * but not for parenthesis subshells
***************
*** 125,130
  	assnum(&pidadr, getpid());
  
  	/*
  	 * set up temp file names
  	 */
  	settmp();

--- 159,170 -----
  	assnum(&pidadr, getpid());
  
  	/*
+ 	 * set ppidname '$+'
+ 	 */
+ 	ppid = getppid();
+ 	assnum (& ppidadr, ppid);
+ 
+ 	/*
  	 * set up temp file names
  	 */
  	settmp();
***************
*** 137,143
  	dfault(&mchknod, MAILCHECK);
  	mailchk = stoi(mchknod.namval);
  
! 	if ((beenhere++) == FALSE)	/* ? profile */
  	{
  		if (*(simple(cmdadr)) == '-')
  		{			/* system profile */

--- 177,188 -----
  	dfault(&mchknod, MAILCHECK);
  	mailchk = stoi(mchknod.namval);
  
! #if pyr
! 	/*
! 	 * find out current universe, initialize $UNIVERSE
! 	 */
! 	cur_univ = setuniverse (U_UCB);	/* retrieve old and set to UCB */
! 	if (cur_univ == -1)
  	{
  		/* unknown current, default to UCB */
  		cur_univ = U_UCB;
***************
*** 139,144
  
  	if ((beenhere++) == FALSE)	/* ? profile */
  	{
  		if (*(simple(cmdadr)) == '-')
  		{			/* system profile */
  

--- 184,214 -----
  	cur_univ = setuniverse (U_UCB);	/* retrieve old and set to UCB */
  	if (cur_univ == -1)
  	{
+ 		/* unknown current, default to UCB */
+ 		cur_univ = U_UCB;
+ 		setuniverse (cur_univ);
+ 	}
+ 	else if (cur_univ != U_UCB)
+ 		setuniverse (cur_univ);	/* reset to what it was */
+ 	
+ 	/*
+ 	 * force value, ignore whatever was in environment
+ 	 */
+ 	assign (& univnod, univ_name[cur_univ - 1]);
+ 	attrib ((&univnod), N_RDONLY);	/* user can not set $UNIVERSE */
+ #endif
+ 
+ 	/*
+ 	 * assign default value of $HOME/.history to $HISTFILE
+ 	 */
+ 	(void) catpath ("~", savehist);
+ 	dfault (& histfnod, curstak());
+ 
+ 	if (beenhere == FALSE)		/* ? profile */
+ 	{
+ 		static struct statb;
+ 
+ 		++beenhere;		/* DAG */
  		if (*(simple(cmdadr)) == '-')
  		{			/* system profile */
  			struct stat statb;
***************
*** 141,147
  	{
  		if (*(simple(cmdadr)) == '-')
  		{			/* system profile */
! 
  #ifndef RES
  
  			if ((input = pathopen(nullstr, sysprofile)) >= 0)

--- 211,217 -----
  		++beenhere;		/* DAG */
  		if (*(simple(cmdadr)) == '-')
  		{			/* system profile */
! 			struct stat statb;
  #ifndef RES
  
  			if ((input = pathopen(nullstr, sysprofile)) >= 0)
***************
*** 149,155
  
  #endif
  
! 			if ((input = pathopen(nullstr, profile)) >= 0)
  			{
  				exfile(rflag);
  				flags &= ~ttyflg;

--- 219,230 -----
  
  #endif
  
! 			if ((input = pathopen(nullstr, profile)) >= 0
! 				&& geteuid() == 0
! 				&& (fstat(input, &statb) != 0
! 					|| statb.st_uid != 0))
! 				close (input);	/* protect superuser, c/o BRL */
! 			else
  			{
  				exfile(rflag);
  				flags &= ~ttyflg;
***************
*** 157,162
  		}
  		if (rsflag == 0 || rflag == 0)
  			flags |= rshflg;
  		/*
  		 * open input file if specified
  		 */

--- 232,251 -----
  		}
  		if (rsflag == 0 || rflag == 0)
  			flags |= rshflg;
+ 		
+ 		/* if all ok, process $HOME/.shrc */
+ 		if (geteuid() == getuid() && getegid() == getgid()
+ 			&& (flags & (rshflg|quickflg)) == 0
+ 			&& (input = pathopen("~", shrc)) >= 0)
+ 		{
+ 			int promptflags = flags & (ttyflg|intflg|prompt);
+ 
+ 			/* turn off anything that will cause prompting */
+ 			flags &= ~promptflags;
+ 			exfile (rflag);
+ 			flags |= promptflags;
+ 		}
+ 
  		/*
  		 * open input file if specified
  		 */
***************
*** 221,226
  			setmail(mailpnod.namval);
  		else
  			setmail(mailnod.namval);
  	}
  	else
  	{

--- 310,318 -----
  			setmail(mailpnod.namval);
  		else
  			setmail(mailnod.namval);
+ 
+ 		/* restore previous history */
+ 		histrest (histfnod.namval);
  	}
  	else
  	{
***************
*** 256,262
  		if ((flags & prompt) && standin->fstak == 0 && !eof)
  		{
  
! 			if (mailp)
  			{
  				time(&curtime);
  

--- 348,354 -----
  		if ((flags & prompt) && standin->fstak == 0 && !eof)
  		{
  
! 			if (mailp && *mailp)	/* BRL to check for *mailp */
  			{
  				time(&curtime);
  
***************
*** 267,273
  				}
  			}
  
! 			prs(ps1nod.namval);
  
  #ifdef TIME_OUT
  			alarm(TIMEOUT);

--- 359,368 -----
  				}
  			}
  
! 			/* do special handling for $PS1 */
! 			pr_prompt(ps1nod.namval);
! 			if (userid == 0 && ! eq(ps1nod.namval, supprompt))
! 				prs(supprompt);	/* append "# " */
  
  #ifdef TIME_OUT
  			alarm(TIMEOUT);
***************
*** 276,281
  			flags |= waiting;
  		}
  
  		trapnote = 0;
  		peekc = readc();
  		if (eof)

--- 371,377 -----
  			flags |= waiting;
  		}
  
+ 		catcheof = TRUE;
  		trapnote = 0;
  		peekc = readc();
  		catcheof = FALSE;
***************
*** 278,283
  
  		trapnote = 0;
  		peekc = readc();
  		if (eof)
  			return;
  

--- 374,380 -----
  		catcheof = TRUE;
  		trapnote = 0;
  		peekc = readc();
+ 		catcheof = FALSE;
  		if (eof)
  			return;
  
:::::::: mode.h :::::::
No differences encountered
:::::::: msg.c :::::::
*** ../orig.u/msg.c	Wed May 15 17:08:23 1985
--- msg.c	Wed Jun  5 15:20:45 1985
***************
*** 48,53
  char	nohome[]	= "no home directory";
  char 	badperm[]	= "execute permission denied";
  char	longpwd[]	= "sh error: pwd too long";
  /*
   * messages for 'builtin' functions
   */

--- 48,66 -----
  char	nohome[]	= "no home directory";
  char 	badperm[]	= "execute permission denied";
  char	longpwd[]	= "sh error: pwd too long";
+ #if JOBS
+ char	cjpostr[]	= ": couldn't jpost\n";
+ char	jcoffstr[]	= "job control not enabled\n";
+ char	jpanstr[]	= "sh bug: j_print_ent--no number ";
+ char	jinvstr[]	= "invalid job number\n";
+ char	ncjstr[]	= "no current job\n";
+ char	nstpstr[]	= ": not stopped\n";
+ char	tasjstr[]	= "There are stopped jobs.\n";
+ #endif
+ #if SYMLINK
+ char	nolstat[]	= ": can't lstat component";
+ #endif
+ 
  /*
   * messages for 'builtin' functions
   */
***************
*** 66,71
  char	mchkname[]	= "MAILCHECK";
  char	acctname[]  	= "SHACCT";
  char	mailpname[]	= "MAILPATH";
  
  /*
   * string constants

--- 79,88 -----
  char	mchkname[]	= "MAILCHECK";
  char	acctname[]  	= "SHACCT";
  char	mailpname[]	= "MAILPATH";
+ #if pyr
+ char	univname[]	= "UNIVERSE";
+ #endif
+ char	histfilename[]	= "HISTFILE";
  
  /*
   * string constants
***************
*** 85,90
  char	supprompt[]	= "# ";
  char	profile[]	= ".profile";
  char	sysprofile[]	= "/etc/profile";
  
  /*
   * tables

--- 102,151 -----
  char	supprompt[]	= "# ";
  char	profile[]	= ".profile";
  char	sysprofile[]	= "/etc/profile";
+ char	shrc[]		= ".shrc";
+ char	savehist[]	= ".history";
+ char	dashi[]		= "-i";		/* for history.c */
+ char	dashr[]		= "-r";
+ char	dashs[]		= "-s";
+ char	rdwstr[]	= "<> ";
+ #if JOBS
+ char	rsqbrk[]	= "] ";
+ char	spspstr[]	= " \ ";
+ char	fgdstr[]	= "foreground \ \ \ \ \ \ ";
+ char	stpdstr[]	= "stopped";
+ char	lotspstr[]	= " \ \ \ \ \ \ \ \ \ ";
+ char	psgpstr[]	= " (signal) ";
+ char	ptinstr[]	= " (tty in) ";
+ char	ptoustr[]	= " (tty out)";
+ char	bgdstr[]	= "background \ \ \ \ \ \ ";
+ char	spcstr[]	= " ";
+ char	rdinstr[]	= "< ";
+ char	appdstr[]	= ">> ";
+ char	inlnstr[]	= "<< ";
+ char	sfnstr[]	= "(){ ";
+ char	efnstr[]	= " }";
+ char	semspstr[]	= "; ";
+ char	lpnstr[]	= "(";
+ char	rpnstr[]	= ")";
+ char	insstr[]	= " in ";
+ char	sdostr[]	= "; do ";
+ char	sdonstr[]	= "; done";
+ char	sthnstr[]	= "; then ";
+ char	selsstr[]	= "; else ";
+ char	sfistr[]	= "; fi";
+ char	iesacstr[]	= " in ... esac";
+ char	casestr[]	= "case ";
+ char	pipestr[]	= " | ";
+ char	toastr[]	= ">&";
+ char	fromastr[]	= "<&";
+ char	andstr[]	= " && ";
+ char	orstr[]		= " || ";
+ char	forstr[]	= "for ";
+ char	amperstr[]	= " &";	
+ char	whilestr[]	= "while ";
+ char	untilstr[]	= "until ";
+ char	ifstr[]		= "if ";
+ #endif
  
  /*
   * tables
***************
*** 130,135
  	"Alarm call",
  	"Terminated",
  	"Signal 16",
  	"Signal 17",
  	"Child death",
  	"Power Fail"

--- 191,218 -----
  	"Alarm call",
  	"Terminated",
  	"Signal 16",
+ #if JOBS
+ 	"Stop",
+ 	"Stop from keyboard",
+ 	"Continue",
+ 	"Child status change",
+ 	"Background read",
+ 	"Background write",
+ 	"I/O possible",
+ 	"CPU time lmit",
+ 	"File size limit",
+ 	"Virtual time alarm",
+ 	"Profiling timer alarm",
+ #if gould
+ 	"Stack overflow",
+ #else
+ 	"Signal 28",
+ #endif
+ 	"Signal 29",
+ 	"Signal 30",
+ 	"Signal 31",
+ 	"Signal 32",
+ #else
  	"Signal 17",
  	"Child death",
  	"Power Fail"
***************
*** 133,138
  	"Signal 17",
  	"Child death",
  	"Power Fail"
  };
  
  char	export[] = "export";

--- 216,222 -----
  	"Signal 17",
  	"Child death",
  	"Power Fail"
+ #endif
  };
  
  char	export[] = "export";
***************
*** 149,154
  	{ "[",		SYSTST },
  #endif
  
  	{ "break",	SYSBREAK },
  	{ "cd",		SYSCD	},
  	{ "continue",	SYSCONT	},

--- 233,246 -----
  	{ "[",		SYSTST },
  #endif
  
+ #if pyr
+ 	{ "att",	SYSATT },
+ #endif
+ 
+ #if JOBS
+ 	{ "bg",		SYSBG },
+ #endif
+ 
  	{ "break",	SYSBREAK },
  	{ "cd",		SYSCD	},
  	{ "continue",	SYSCONT	},
***************
*** 157,162
  	{ "exec",	SYSEXEC	},
  	{ "exit",	SYSEXIT	},
  	{ "export",	SYSXPORT },
  	{ "hash",	SYSHASH	},
  
  #ifdef RES

--- 249,259 -----
  	{ "exec",	SYSEXEC	},
  	{ "exit",	SYSEXIT	},
  	{ "export",	SYSXPORT },
+ 
+ #if JOBS
+ 	{ "fg",		SYSFG },
+ #endif
+ 
  	{ "hash",	SYSHASH	},
  	{ "history",	SYSHISTORY },
  
***************
*** 158,163
  	{ "exit",	SYSEXIT	},
  	{ "export",	SYSXPORT },
  	{ "hash",	SYSHASH	},
  
  #ifdef RES
  	{ "login",	SYSLOGIN },

--- 255,261 -----
  #endif
  
  	{ "hash",	SYSHASH	},
+ 	{ "history",	SYSHISTORY },
  
  #if JOBS
  	{ "jobs",	SYSJOBS },
***************
*** 159,164
  	{ "export",	SYSXPORT },
  	{ "hash",	SYSHASH	},
  
  #ifdef RES
  	{ "login",	SYSLOGIN },
  	{ "newgrp",	SYSLOGIN },

--- 257,266 -----
  	{ "hash",	SYSHASH	},
  	{ "history",	SYSHISTORY },
  
+ #if JOBS
+ 	{ "jobs",	SYSJOBS },
+ #endif
+ 
  #ifdef RES
  	{ "login",	SYSLOGIN },
  	{ "newgrp",	SYSLOGIN },
***************
*** 172,177
  	{ "return",	SYSRETURN },
  	{ "set",	SYSSET	},
  	{ "shift",	SYSSHFT	},
  	{ "test",	SYSTST },
  	{ "times",	SYSTIMES },
  	{ "trap",	SYSTRAP	},

--- 274,282 -----
  	{ "return",	SYSRETURN },
  	{ "set",	SYSSET	},
  	{ "shift",	SYSSHFT	},
+ #if JOBS
+ 	{ "suspend",	SYSSUSPEND },
+ #endif
  	{ "test",	SYSTST },
  	{ "times",	SYSTIMES },
  	{ "trap",	SYSTRAP	},
***************
*** 177,182
  	{ "trap",	SYSTRAP	},
  	{ "type",	SYSTYPE },
  
  
  #ifndef RES		
  	{ "ulimit",	SYSULIMIT },

--- 282,290 -----
  	{ "trap",	SYSTRAP	},
  	{ "type",	SYSTYPE },
  
+ #if pyr
+ 	{ "ucb",	SYSUCB },
+ #endif
  
  #ifndef RES		
  	{ "ulimit",	SYSULIMIT },
***************
*** 183,188
  	{ "umask",	SYSUMASK },
  #endif
  
  	{ "unset", 	SYSUNS },
  	{ "wait",	SYSWAIT	}
  };

--- 291,300 -----
  	{ "umask",	SYSUMASK },
  #endif
  
+ #if pyr
+ 	{ "universe",	SYSUNIVERSE },
+ #endif
+ 
  	{ "unset", 	SYSUNS },
  	{ "wait",	SYSWAIT	}
  };
***************
*** 187,194
  	{ "wait",	SYSWAIT	}
  };
  
! #ifdef RES
! 	int no_commands = 26;
! #else
! 	int no_commands = 27;
  #endif

--- 299,308 -----
  	{ "wait",	SYSWAIT	}
  };
  
! int no_commands = sizeof commands / sizeof(struct sysnod);	/* DAG -- improved */
! 
! #if pyr
! #include <sys/types.h>		/* to get <sys/inode.h> to work (sigh) */
! #include <sys/inode.h>		/* NUMUNIV defined to be NUMCLNK */
! #include <universe.h>	/* gets char *univ_name[] && cha *univ_longname[] */
  #endif

sources-request@genrad.UUCP (06/11/85)

From: Arnold Robbins <gatech!arnold>

This is part 6 of 9.  It contains the second set of code diffs for the System V
Release 2 Bourne shell.

BSD users who happen to also have source for System V Release 2 will probably
want to use this version of the shell, since it has many bug fixes and
improvements over the (much) earlier version that comes with Berkeley Unix.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
----------- pretend your screen is really a paper towel ------------
:::::::: name.c :::::::
*** ../orig.u/name.c	Wed May 15 17:08:24 1985
--- name.c	Tue May 21 19:02:42 1985
***************
*** 15,21
  struct namnod ps2nod =
  {
  	(struct namnod *)NIL,
! 	&acctnod,
  	ps2name
  };
  struct namnod cdpnod = 

--- 15,21 -----
  struct namnod ps2nod =
  {
  	(struct namnod *)NIL,
! 	(struct namnod *)NIL,
  	ps2name
  };
  struct namnod cdpnod = 
***************
*** 32,38
  };
  struct namnod ifsnod =
  {
! 	&homenod,
  	&mailnod,
  	ifsname
  };

--- 32,38 -----
  };
  struct namnod ifsnod =
  {
! 	&histfnod,
  	&mailnod,
  	ifsname
  };
***************
*** 39,45
  struct namnod ps1nod =
  {
  	&pathnod,
! 	&ps2nod,
  	ps1name
  };
  struct namnod homenod =

--- 39,45 -----
  struct namnod ps1nod =
  {
  	&pathnod,
! 	&acctnod,
  	ps1name
  };
  struct namnod homenod =
***************
*** 44,50
  };
  struct namnod homenod =
  {
- 	&cdpnod,
  	(struct namnod *)NIL,
  	homename
  };

--- 44,49 -----
  };
  struct namnod homenod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	homename
***************
*** 46,51
  {
  	&cdpnod,
  	(struct namnod *)NIL,
  	homename
  };
  struct namnod mailnod =

--- 45,51 -----
  struct namnod homenod =
  {
  	(struct namnod *)NIL,
+ 	(struct namnod *)NIL,
  	homename
  };
  struct namnod mailnod =
***************
*** 62,67
  };
  struct namnod acctnod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	acctname

--- 62,71 -----
  };
  struct namnod acctnod =
  {
+ 	&ps2nod,
+ #if pyr
+ 	&univnod,
+ #else
  	(struct namnod *)NIL,
  #endif
  	acctname
***************
*** 63,69
  struct namnod acctnod =
  {
  	(struct namnod *)NIL,
! 	(struct namnod *)NIL,
  	acctname
  };
  struct namnod mailpnod =

--- 67,73 -----
  	&univnod,
  #else
  	(struct namnod *)NIL,
! #endif
  	acctname
  };
  struct namnod mailpnod =
***************
*** 72,77
  	(struct namnod *)NIL,
  	mailpname
  };
  
  
  struct namnod *namep = &mchknod;

--- 76,95 -----
  	(struct namnod *)NIL,
  	mailpname
  };
+ struct namnod histfnod =
+ {
+ 	&cdpnod,
+ 	&homenod,
+ 	histfilename
+ };
+ #if pyr
+ struct namnod univnod =
+ {
+ 	(struct namnod *)NIL,
+ 	(struct namnod *)NIL,
+ 	univname
+ };
+ #endif
  
  
  struct namnod *namep = &mchknod;
***************
*** 86,91
  	int	low;
  	int	high;
  	int	mid;
  	register int cond;
  
  	if (w == 0 || *w == 0)

--- 104,112 -----
  	int	low;
  	int	high;
  	int	mid;
+ #if gould
+ 	int	cond;	/* DAG -- avoid optimizer bug */
+ #else
  	register int cond;
  #endif
  
***************
*** 87,92
  	int	high;
  	int	mid;
  	register int cond;
  
  	if (w == 0 || *w == 0)
  		return(0);

--- 108,114 -----
  	int	cond;	/* DAG -- avoid optimizer bug */
  #else
  	register int cond;
+ #endif
  
  	if (w == 0 || *w == 0)
  		return(0);
***************
*** 228,233
  readvar(names)
  char	**names;
  {
  	struct fileblk	fb;
  	register struct fileblk *f = &fb;
  	register char	c;

--- 250,256 -----
  readvar(names)
  char	**names;
  {
+ 	extern long lseek();	/* DAG -- bug fix (was missing) */
  	struct fileblk	fb;
  	register struct fileblk *f = &fb;
  	register char	c;
***************
*** 238,244
  	push(f);
  	initf(dup(0));
  
! 	if (lseek(0, 0L, 1) == -1)
  		f->fsiz = 1;
  
  	/*

--- 261,267 -----
  	push(f);
  	initf(dup(0));
  
! 	if (lseek(0, 0L, 1) == -1L)	/* DAG */
  		f->fsiz = 1;
  
  	/*
:::::::: name.h :::::::
No differences encountered
:::::::: print.c :::::::
*** ../orig.u/print.c	Wed May 15 17:08:25 1985
--- print.c	Mon May 20 15:32:21 1985
***************
*** 7,12
   */
  
  #include	"defs.h"
  #include	<sys/param.h>
  
  #define		BUFLEN		256

--- 7,15 -----
   */
  
  #include	"defs.h"
+ #if JOBS
+ #define		HZ	60
+ #else
  #include	<sys/param.h>
  #endif
  
***************
*** 8,13
  
  #include	"defs.h"
  #include	<sys/param.h>
  
  #define		BUFLEN		256
  

--- 11,17 -----
  #define		HZ	60
  #else
  #include	<sys/param.h>
+ #endif
  
  #define		BUFLEN		256
  
***************
*** 66,73
  		prc_buff('h');
  	}
  
! 	prn_buff(min);
! 	prc_buff('m');
  	prn_buff(sec);
  	prc_buff('s');
  }

--- 70,80 -----
  		prc_buff('h');
  	}
  
! 	if (min)	/* BRL... for consistency */
! 	{
! 		prn_buff(min);
! 		prc_buff('m');
! 	}
  	prn_buff(sec);
  	prc_buff('s');
  }
***************
*** 230,233
  	itos(n);
  
  	prs_buff(numbuf);
  }

--- 237,357 -----
  	itos(n);
  
  	prs_buff(numbuf);
+ }
+ 
+ void
+ pr_prompt (str)
+ register char *str;
+ {
+ 	for (; *str; str++)
+ 	{
+ 		if (*str != '%')
+ 			prc_buff (*str);
+ 		else if (*(str+1) == 'd')
+ 		{
+ 			/* current directory */
+ 			str++;
+ 			prs_buff (retcwd());
+ 		}
+ 		else if (*(str+1) == 'e')
+ 		{
+ 			/* event count */
+ 			str++;
+ 			if ((flags & nohistflg) == 0)
+ 				prn_buff (event_count);
+ 		}
+ 		else if (*(str+1) == 'h')
+ 		{
+ 			/* hostname */
+ 			static char *cp = 0;
+ 			static int didhost = FALSE;
+ 			static int didgt = FALSE;
+ #ifdef JOBS
+ 			static char buf[257];
+ 
+ 			if (! didhost)
+ 			{
+ 				gethostname (buf, sizeof buf);
+ 				didhost = TRUE;
+ 				cp = buf;
+ 			}
+ #else
+ #include <sys/utsname.h>	/* has an extern declaration in it */
+ 			static struct utsname name;
+ 
+ 			if (! didhost)
+ 			{
+ 				uname (& name);
+ 				/* avoid emulation bug */
+ 				name.sysname[sizeof(name.sysname)-1] = '\0';
+ 				didhost = TRUE;
+ 				cp = name.sysname;
+ 			}
+ #endif
+ 
+ #ifdef GATECH
+ 			/*
+ 			 * this is to get rid of the dumb gt- convention.
+ 			 * a gt w/out the - is also removed.
+ 			 */
+ 			if (! didgt)
+ 			{
+ 				didgt = TRUE;
+ 				if (cp[0] == 'g' && cp[1] == 't' && cp[2])
+ 				{
+ 					cp += 2;
+ 					if (cp[0] == '-' && cp[1])
+ 						cp++;
+ 				}
+ 			}
+ #endif
+ 			prs_buff (cp);
+ 			str++;
+ 		}
+ 		else if (*(str+1) == 'l')
+ 		{
+ 			/* login name */
+ 			static char *cp = 0;
+ 			static int didname = FALSE;
+ 
+ 			str++;
+ 			if (! didname)
+ 			{
+ 				cp = username ();
+ 				didname = TRUE;
+ 			}
+ 
+ 			if (cp)
+ 				prs_buff (cp);
+ 		}
+ 		else if (*(str+1) == 't')
+ 		{
+ 			/* current time, HH:MM */
+ 			long l;
+ 			char *cp, *ctime ();
+ 
+ 			str++;
+ 			time (& l);
+ 			cp = ctime (& l);
+ 			cp[16] = '\0';
+ 			cp += 11;
+ 			prs_buff (cp);
+ 		}
+ #if pyr
+ 		else if (*(str+1) == 'u')
+ 		{
+ 			/* current univeserse */
+ 			str++;
+ 			prs_buff (univ_name[cur_univ-1]);
+ 		}
+ #endif
+ 		else if (*(str+1) == '\0')	/* % was last char in string */
+ 		{
+ 			prc_buff (*str);
+ 			continue;
+ 		}
+ 		else
+ 			prc_buff (*(++str));
+ 	}
+ 	flushb();
  }
:::::::: profile.c :::::::
No differences encountered
:::::::: pwd.c :::::::
*** ../orig.u/pwd.c	Wed May 15 17:08:27 1985
--- pwd.c	Mon May 20 17:20:51 1985
***************
*** 4,9
   *
   *	Bell Telephone Laboratories
   *
   */
  
  #include		"mac.h"

--- 4,14 -----
   *
   *	Bell Telephone Laboratories
   *
+  *	DAG -- Two ways of handling symbolic links in directory paths:
+  *		Define SYMLINK if you want "cd .." to do just that.
+  *		Otherwise, "cd .." takes you back the way you came.
+  *	The first method was implemented by Ron Natalie and the
+  *	second method was implemented by Douglas Gwyn, both of BRL.
   */
  
  #include		"defs.h"	/* DAG -- was just "mac.h" */
***************
*** 6,12
   *
   */
  
! #include		"mac.h"
  
  #define	DOT		'.'
  #define	NULL	0

--- 11,19 -----
   *	second method was implemented by Douglas Gwyn, both of BRL.
   */
  
! #include		"defs.h"	/* DAG -- was just "mac.h" */
! #include	<sys/types.h>		/* DAG -- moved for SYMLINK */
! #include	<sys/stat.h>		/* DAG -- moved for SYMLINK */
  
  #if defined(SYMLINK) && !defined(S_IFLNK)
  #define	S_IFLNK	0120000
***************
*** 8,13
  
  #include		"mac.h"
  
  #define	DOT		'.'
  #define	NULL	0
  #define	SLASH	'/'

--- 15,24 -----
  #include	<sys/types.h>		/* DAG -- moved for SYMLINK */
  #include	<sys/stat.h>		/* DAG -- moved for SYMLINK */
  
+ #if defined(SYMLINK) && !defined(S_IFLNK)
+ #define	S_IFLNK	0120000
+ #endif
+ 
  #define	DOT		'.'
  #define	NULL	0
  #define	SLASH	'/'
***************
*** 11,16
  #define	DOT		'.'
  #define	NULL	0
  #define	SLASH	'/'
  #define MAXPWD	256
  
  extern char	longpwd[];

--- 22,30 -----
  #define	DOT		'.'
  #define	NULL	0
  #define	SLASH	'/'
+ #if defined(JOBS)
+ #define MAXPWD	(24*256)	/* who knows */
+ #else
  #define MAXPWD	256
  #endif
  
***************
*** 12,17
  #define	NULL	0
  #define	SLASH	'/'
  #define MAXPWD	256
  
  extern char	longpwd[];
  

--- 26,32 -----
  #define MAXPWD	(24*256)	/* who knows */
  #else
  #define MAXPWD	256
+ #endif
  
  extern char	longpwd[];
  
***************
*** 17,22
  
  static char cwdname[MAXPWD];
  static int 	didpwd = FALSE;
  
  cwd(dir)
  	register char *dir;

--- 32,41 -----
  
  static char cwdname[MAXPWD];
  static int 	didpwd = FALSE;
+ #if SYMLINK
+ /* Stuff to handle chdirs around symbolic links */
+ static char	*symlink = 0;	/* Pointer to after last symlink in cwdname */
+ #endif
  
  cwd(dir)
  	register char *dir;
***************
*** 21,26
  cwd(dir)
  	register char *dir;
  {
  	register char *pcwd;
  	register char *pdir;
  

--- 40,48 -----
  cwd(dir)
  	register char *dir;
  {
+ #if SYMLINK
+ 	struct stat statb;
+ #endif
  	register char *pcwd;
  	register char *pdir;
  
***************
*** 44,51
  		if (*pdir) 
  			pdir++;
  	}
! 	if(*(--pdir)==DOT && pdir>dir && *(--pdir)==SLASH)
! 		*pdir = NULL;
  	
  
  	/* Remove extra /'s */

--- 66,73 -----
  		if (*pdir) 
  			pdir++;
  	}
! 	if(pdir>dir && *(--pdir)==DOT && pdir>dir && *(--pdir)==SLASH)	/* DAG -- bug fix (added first test) */
! 		*pdir = '\0';	/* DAG -- not NULL */
  	
  
  	/* Remove extra /'s */
***************
*** 65,70
  
  		pcwd = cwdname;
  		didpwd = TRUE;
  	}
  	else
  	{

--- 87,95 -----
  
  		pcwd = cwdname;
  		didpwd = TRUE;
+ #if SYMLINK
+ 		symlink = 0;		/* Starting over, no links yet */
+ #endif
  	}
  	else
  	{
***************
*** 71,76
  		/* Relative path */
  
  		if (didpwd == FALSE) 
  			return;
  			
  		pcwd = cwdname + length(cwdname) - 1;

--- 96,104 -----
  		/* Relative path */
  
  		if (didpwd == FALSE) 
+ #if !defined(SYMLINK) && defined(JOBS)
+ 			pwd();		/* Get absolute pathname into cwdname[] */
+ #else
  			return;
  #endif
  			
***************
*** 72,77
  
  		if (didpwd == FALSE) 
  			return;
  			
  		pcwd = cwdname + length(cwdname) - 1;
  		if(pcwd != cwdname+1)

--- 100,106 -----
  			pwd();		/* Get absolute pathname into cwdname[] */
  #else
  			return;
+ #endif
  			
  		pcwd = cwdname + length(cwdname) - 1;
  		if(pcwd != cwdname+1)
***************
*** 93,98
  				;
  			pcwd++;
  			dir += 2;
  			if(*dir==SLASH)
  			{
  				dir++;

--- 122,135 -----
  				;
  			pcwd++;
  			dir += 2;
+ #if SYMLINK
+ 			/* Just undid symlink, so pwd the hard way */
+ 			if(pcwd < symlink)
+ 			{
+ 				pwd();
+ 				return;
+ 			}
+ #endif
  			if(*dir==SLASH)
  			{
  				dir++;
***************
*** 102,107
  		*pcwd++ = *dir++;
  		while((*dir) && (*dir != SLASH))
  			*pcwd++ = *dir++;
  		if (*dir) 
  			*pcwd++ = *dir++;
  	}

--- 139,161 -----
  		*pcwd++ = *dir++;
  		while((*dir) && (*dir != SLASH))
  			*pcwd++ = *dir++;
+ #if SYMLINK
+ 		/* Check to see if this path component is a symbolic link */
+ 		*pcwd = 0;
+ 		if(lstat(cwdname, &statb) != 0)
+ 		{
+ 			prs(cwdname);	/* DAG */
+ 			error(nolstat);	/* DAG -- made string sharable */
+ 			pwd();
+ 			return;
+ 		}
+ 		if((statb.st_mode & S_IFMT) == S_IFLNK)
+ 			/* Set fence so that when we attempt to
+ 			 * "cd .." past it, we know that it is invalid
+ 			 * and have to do it the hard way
+ 			 */
+ 			symlink = dir;
+ #endif
  		if (*dir) 
  			*pcwd++ = *dir++;
  	}
***************
*** 105,111
  		if (*dir) 
  			*pcwd++ = *dir++;
  	}
! 	*pcwd = NULL;
  
  	--pcwd;
  	if(pcwd>cwdname && *pcwd==SLASH)

--- 159,165 -----
  		if (*dir) 
  			*pcwd++ = *dir++;
  	}
! 	*pcwd = '\0';	/* DAG -- not NULL */
  
  	--pcwd;
  	if(pcwd>cwdname && *pcwd==SLASH)
***************
*** 112,118
  	{
  		/* Remove trailing / */
  
! 		*pcwd = NULL;
  	}
  	return;
  }

--- 166,172 -----
  	{
  		/* Remove trailing / */
  
! 		*pcwd = '\0';	/* DAG -- not NULL */
  	}
  	return;
  }
***************
*** 168,174
   *	Find the current directory the hard way.
   */
  
! #include	<sys/types.h>
  #include	<sys/dir.h>
  #include	<sys/stat.h>
  

--- 222,230 -----
   *	Find the current directory the hard way.
   */
  
! #if JOBS
! #include	<dir.h>
! #else
  #include	<sys/dir.h>
  #endif
  
***************
*** 170,176
  
  #include	<sys/types.h>
  #include	<sys/dir.h>
! #include	<sys/stat.h>
  
  
  static char dotdots[] =

--- 226,232 -----
  #include	<dir.h>
  #else
  #include	<sys/dir.h>
! #endif
  
  
  static char dotdots[] =
***************
*** 176,181
  static char dotdots[] =
  "../../../../../../../../../../../../../../../../../../../../../../../..";
  
  extern struct direct	*getdir();
  extern char		*movstrn();
  

--- 232,240 -----
  static char dotdots[] =
  "../../../../../../../../../../../../../../../../../../../../../../../..";
  
+ #if JOBS
+ #define	getdir(dirf)	readdir(dirf)
+ #else
  extern struct direct	*getdir();
  extern char		*movstrn();
  #endif
***************
*** 178,183
  
  extern struct direct	*getdir();
  extern char		*movstrn();
  
  static
  pwd()

--- 237,243 -----
  #else
  extern struct direct	*getdir();
  extern char		*movstrn();
+ #endif
  
  static
  pwd()
***************
*** 185,190
  	struct stat		cdir;	/* current directory status */
  	struct stat		tdir;
  	struct stat		pdir;	/* parent directory status */
  	int				pdfd;	/* parent directory file descriptor */
  
  	struct direct	*dir;

--- 245,253 -----
  	struct stat		cdir;	/* current directory status */
  	struct stat		tdir;
  	struct stat		pdir;	/* parent directory status */
+ #if JOBS
+ 	DIR				*pdfd;	/* parent directory stream */
+ #else
  	int				pdfd;	/* parent directory file descriptor */
  #endif
  
***************
*** 186,191
  	struct stat		tdir;
  	struct stat		pdir;	/* parent directory status */
  	int				pdfd;	/* parent directory file descriptor */
  
  	struct direct	*dir;
  	char 			*dot = dotdots + sizeof(dotdots) - 3;

--- 249,255 -----
  	DIR				*pdfd;	/* parent directory stream */
  #else
  	int				pdfd;	/* parent directory file descriptor */
+ #endif
  
  	struct direct	*dir;
  	char 			*dot = dotdots + sizeof(dotdots) - 3;
***************
*** 193,198
  	int				cwdindex = MAXPWD - 1;
  	int 			i;
  	
  	cwdname[cwdindex] = 0;
  	dotdots[index] = 0;
  

--- 257,265 -----
  	int				cwdindex = MAXPWD - 1;
  	int 			i;
  	
+ #if SYMLINK
+ 	symlink = 0;			/* Starting over, no links yet */
+ #endif
  	cwdname[cwdindex] = 0;
  	dotdots[index] = 0;
  
***************
*** 206,212
  	for(;;)
  	{
  		cdir = pdir;
! 
  		if ((pdfd = open(dot, 0)) < 0)
  		{
  			error("pwd: cannot open ..");

--- 273,281 -----
  	for(;;)
  	{
  		cdir = pdir;
! #if JOBS
! 		if ((pdfd = opendir(dot)) == (DIR *)0)
! #else
  		if ((pdfd = open(dot, 0)) < 0)
  #endif
  		{
***************
*** 208,213
  		cdir = pdir;
  
  		if ((pdfd = open(dot, 0)) < 0)
  		{
  			error("pwd: cannot open ..");
  		}

--- 277,283 -----
  		if ((pdfd = opendir(dot)) == (DIR *)0)
  #else
  		if ((pdfd = open(dot, 0)) < 0)
+ #endif
  		{
  			error("pwd: cannot open ..");
  		}
***************
*** 211,217
  		{
  			error("pwd: cannot open ..");
  		}
! 
  		if(fstat(pdfd, &pdir) < 0)
  		{
  			close(pdfd);

--- 281,289 -----
  		{
  			error("pwd: cannot open ..");
  		}
! #if JOBS
! 		if(fstat(pdfd->dd_fd, &pdir) < 0)
! #else
  		if(fstat(pdfd, &pdir) < 0)
  #endif
  		{
***************
*** 213,218
  		}
  
  		if(fstat(pdfd, &pdir) < 0)
  		{
  			close(pdfd);
  			error("pwd: cannot stat ..");

--- 285,291 -----
  		if(fstat(pdfd->dd_fd, &pdir) < 0)
  #else
  		if(fstat(pdfd, &pdir) < 0)
+ #endif
  		{
  #if JOBS
  			closedir(pdfd);
***************
*** 214,219
  
  		if(fstat(pdfd, &pdir) < 0)
  		{
  			close(pdfd);
  			error("pwd: cannot stat ..");
  		}

--- 287,295 -----
  		if(fstat(pdfd, &pdir) < 0)
  #endif
  		{
+ #if JOBS
+ 			closedir(pdfd);
+ #else
  			close(pdfd);
  #endif
  			error("pwd: cannot stat ..");
***************
*** 215,220
  		if(fstat(pdfd, &pdir) < 0)
  		{
  			close(pdfd);
  			error("pwd: cannot stat ..");
  		}
  

--- 291,297 -----
  			closedir(pdfd);
  #else
  			close(pdfd);
+ #endif
  			error("pwd: cannot stat ..");
  		}
  
***************
*** 223,228
  			if(cdir.st_ino == pdir.st_ino)
  			{
  				didpwd = TRUE;
  				close(pdfd);
  				if (cwdindex == (MAXPWD - 1))
  					cwdname[--cwdindex] = SLASH;

--- 300,308 -----
  			if(cdir.st_ino == pdir.st_ino)
  			{
  				didpwd = TRUE;
+ #if JOBS
+ 				closedir(pdfd);
+ #else
  				close(pdfd);
  #endif
  				if (cwdindex == (MAXPWD - 1))
***************
*** 224,229
  			{
  				didpwd = TRUE;
  				close(pdfd);
  				if (cwdindex == (MAXPWD - 1))
  					cwdname[--cwdindex] = SLASH;
  

--- 304,310 -----
  				closedir(pdfd);
  #else
  				close(pdfd);
+ #endif
  				if (cwdindex == (MAXPWD - 1))
  					cwdname[--cwdindex] = SLASH;
  
***************
*** 235,240
  			{
  				if ((dir = getdir(pdfd)) == 0)
  				{
  					close(pdfd);
  					reset_dir();
  					error("pwd: read error in ..");

--- 316,324 -----
  			{
  				if ((dir = getdir(pdfd)) == 0)
  				{
+ #if JOBS
+ 					closedir(pdfd);
+ #else
  					close(pdfd);
  					reset_dir();
  #endif
***************
*** 237,242
  				{
  					close(pdfd);
  					reset_dir();
  					error("pwd: read error in ..");
  				}
  			}

--- 321,327 -----
  #else
  					close(pdfd);
  					reset_dir();
+ #endif
  					error("pwd: read error in ..");
  				}
  			}
***************
*** 244,250
  		}
  		else
  		{
! 			char name[512];
  			
  			movstr(dot, name);
  			i = length(name) - 1;

--- 329,335 -----
  		}
  		else
  		{
! 			char name[256+MAXPWD];	/* DAG -- (was 512) */
  			
  			movstr(dot, name);
  			i = length(name) - 1;
***************
*** 251,256
  
  			name[i++] = '/';
  
  			do
  			{
  				if ((dir = getdir(pdfd)) == 0)

--- 336,342 -----
  
  			name[i++] = '/';
  
+ 			tdir.st_dev = pdir.st_dev;	/* DAG -- (safety) */
  			do
  			{
  				if ((dir = getdir(pdfd)) == 0)
***************
*** 255,260
  			{
  				if ((dir = getdir(pdfd)) == 0)
  				{
  					close(pdfd);
  					reset_dir();
  					error("pwd: read error in ..");

--- 341,349 -----
  			{
  				if ((dir = getdir(pdfd)) == 0)
  				{
+ #if JOBS
+ 					closedir(pdfd);
+ #else
  					close(pdfd);
  					reset_dir();
  #endif
***************
*** 257,262
  				{
  					close(pdfd);
  					reset_dir();
  					error("pwd: read error in ..");
  				}
  				*(movstrn(dir->d_name, &name[i], DIRSIZ)) = 0;

--- 346,352 -----
  #else
  					close(pdfd);
  					reset_dir();
+ #endif
  					error("pwd: read error in ..");
  				}
  #if JOBS
***************
*** 259,264
  					reset_dir();
  					error("pwd: read error in ..");
  				}
  				*(movstrn(dir->d_name, &name[i], DIRSIZ)) = 0;
  				stat(name, &tdir);
  			}		

--- 349,357 -----
  #endif
  					error("pwd: read error in ..");
  				}
+ #if JOBS
+ 				movstr(dir->d_name, &name[i]);
+ #else
  				*(movstrn(dir->d_name, &name[i], DIRSIZ)) = 0;
  #endif
  				stat(name, &tdir);
***************
*** 260,265
  					error("pwd: read error in ..");
  				}
  				*(movstrn(dir->d_name, &name[i], DIRSIZ)) = 0;
  				stat(name, &tdir);
  			}		
  			while(tdir.st_ino != cdir.st_ino || tdir.st_dev != cdir.st_dev);

--- 353,359 -----
  				movstr(dir->d_name, &name[i]);
  #else
  				*(movstrn(dir->d_name, &name[i], DIRSIZ)) = 0;
+ #endif
  				stat(name, &tdir);
  			}		
  			while(tdir.st_ino != cdir.st_ino || tdir.st_dev != cdir.st_dev);
***************
*** 264,269
  			}		
  			while(tdir.st_ino != cdir.st_ino || tdir.st_dev != cdir.st_dev);
  		}
  		close(pdfd);
  		reset_dir();
  

--- 358,366 -----
  			}		
  			while(tdir.st_ino != cdir.st_ino || tdir.st_dev != cdir.st_dev);
  		}
+ #if JOBS
+ 		closedir(pdfd);
+ #else
  		close(pdfd);
  		reset_dir();
  #endif
***************
*** 266,271
  		}
  		close(pdfd);
  		reset_dir();
  
  		for (i = 0; i < DIRSIZ; i++)
  			if (dir->d_name[i] == 0)

--- 363,369 -----
  #else
  		close(pdfd);
  		reset_dir();
+ #endif
  
  #if JOBS
  		i = dir->d_namlen;
***************
*** 267,272
  		close(pdfd);
  		reset_dir();
  
  		for (i = 0; i < DIRSIZ; i++)
  			if (dir->d_name[i] == 0)
  				break;

--- 365,373 -----
  		reset_dir();
  #endif
  
+ #if JOBS
+ 		i = dir->d_namlen;
+ #else
  		for (i = 0; i < DIRSIZ; i++)
  			if (dir->d_name[i] == 0)
  				break;
***************
*** 270,275
  		for (i = 0; i < DIRSIZ; i++)
  			if (dir->d_name[i] == 0)
  				break;
  
  		if (i > cwdindex - 1)
  				error(longpwd);

--- 371,377 -----
  		for (i = 0; i < DIRSIZ; i++)
  			if (dir->d_name[i] == 0)
  				break;
+ #endif
  
  		if (i > cwdindex - 1)
  				error(longpwd);
***************
*** 284,287
  		if (dot<dotdots) 
  			error(longpwd);
  	}
  }

--- 386,419 -----
  		if (dot<dotdots) 
  			error(longpwd);
  	}
+ }
+ #if !defined(SYMLINK) && defined(JOBS)
+ 
+ /* The following chdir() interface is used to outwit symbolic links. */
+ 
+ int
+ cwdir( dir )				/* attempt a full-pathname chdir */
+ 	char		*dir;		/* name to feed to chdir() */
+ 	{
+ 	char		savname[MAXPWD];	/* saved cwdname[] */
+ 	register int	retval;		/* chdir() return value */
+ 
+ 	(void)movstr( cwdname, savname );	/* save current name */
+ 
+ 	cwd( dir );			/* adjust cwdname[] */
+ 
+ 	if ( (retval = chdir( cwdname )) < 0 )
+ 		(void)movstr( savname, cwdname );	/* restore name */
+ 
+ 	return retval;
+ 	}
+ #endif
+ 
+ char *
+ retcwd()
+ {
+ 	if (didpwd == FALSE)
+ 		pwd ();
+ 	
+ 	return (cwdname);
  }
:::::::: service.c :::::::
*** ../orig.u/service.c	Wed May 15 17:08:28 1985
--- service.c	Wed May 29 15:54:16 1985
***************
*** 8,13
  
  #include	"defs.h"
  #include	<errno.h>
  
  #define ARGMK	01
  

--- 8,17 -----
  
  #include	"defs.h"
  #include	<errno.h>
+ #if JOBS
+ extern int	errno;
+ #include	"/usr/include/sys/wait.h"
+ #endif
  
  #define ARGMK	01
  
***************
*** 24,29
  	struct ionod	*iop;
  	int		save;
  {
  	register char	*ion;
  	register int	iof, fd;
  	int		ioufd;

--- 28,34 -----
  	struct ionod	*iop;
  	int		save;
  {
+ 	extern long	lseek();	/* DAG -- bug fix (was missing) */
  	register char	*ion;
  	register int	iof, fd;
  	int		ioufd;
***************
*** 70,75
  				else
  					fd = dup(fd);
  			}
  			else if ((iof & IOPUT) == 0)
  				fd = chkopen(ion);
  			else if (flags & rshflg)

--- 75,85 -----
  				else
  					fd = dup(fd);
  			}
+ 			else if (iof & IORDW)
+ 			{
+ 				if ((fd = open(ion, 2)) < 0)
+ 					failed(ion, badopen);
+ 			}
  			else if ((iof & IOPUT) == 0)
  				fd = chkopen(ion);
  			else if (flags & rshflg)
***************
*** 145,150
  	 */
  	register char	*scanp = path;
  	register char	*argp = locstak();
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;

--- 155,162 -----
  	 */
  	register char	*scanp = path;
  	register char	*argp = locstak();
+ 	char	*save = argp;
+ 	char	*cp;
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;
***************
*** 148,153
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;
  	if (scanp != path)
  		*argp++ = '/';
  	if (*scanp == COLON)

--- 160,172 -----
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;
+ 	*argp = '\0';
+ 	/* try a tilde expansion */
+ 	if (*save == SQUIGGLE && (cp = homedir (save + 1)) != nullstr)
+ 	{
+ 		movstr (cp, save);
+ 		argp = save + length (save) - 1;
+ 	}
  	if (scanp != path)
  		*argp++ = '/';
  	if (*scanp == COLON)
***************
*** 232,237
  		if (input)
  			close(input);
  		input = chkopen(p);
  	
  #ifdef ACCT
  		preacct(p);	/* reset accounting */

--- 251,271 -----
  		if (input)
  			close(input);
  		input = chkopen(p);
+ #if JOBS
+ 		/* don't try to interpret directories etc. */
+ 		{
+ #include	<sys/types.h>
+ #include	<sys/stat.h>
+ 			struct stat	sbuf;
+ 
+ 			if (fstat(input, &sbuf) == 0
+ 				&& (sbuf.st_mode&S_IFMT) != S_IFREG)
+ 			{
+ 				close (input);
+ 				goto def;	/* badexec unless other found */
+ 			}
+ 		}
+ #endif
  	
  #ifdef ACCT
  		preacct(p);	/* reset accounting */
***************
*** 254,259
  		failed(p, txtbsy);
  
  	default:
  		xecmsg = badexec;
  	case ENOENT:
  		return(prefix);

--- 288,296 -----
  		failed(p, txtbsy);
  
  	default:
+ #if JOBS
+ 	def:
+ #endif
  		xecmsg = badexec;
  	case ENOENT:
  		return(prefix);
***************
*** 268,273
  static int	pwlist[MAXP];
  static int	pwc;
  
  postclr()
  {
  	register int	*pw = pwlist;

--- 305,355 -----
  static int	pwlist[MAXP];
  static int	pwc;
  
+ #if JOBS
+ static int	*wf_pwlist;
+ static int	wf_pwc;
+ 
+ void
+ set_wfence()
+ {
+ 	wf_pwlist = &pwlist[pwc];
+ 	wf_pwc = 0;
+ }
+ 
+ BOOL
+ unpost(pcsid)
+ 	int	pcsid;
+ {
+ 	register int	*pw = pwlist;
+ 
+ 	if (pcsid)
+ 	{
+ 		while (pw <= &pwlist[pwc])
+ 		{
+ 			if (pcsid == *pw)
+ 			{
+ 				if (pw >= wf_pwlist)
+ 					wf_pwc--;
+ 				else
+ 					wf_pwlist--;
+ 				while (pw <= &pwlist[pwc])
+ 				{
+ 					*pw = pw[1];
+ 					pw++;
+ 				}
+ 				pw[pwc] = 0;
+ 				pwc--;
+ 				return TRUE;
+ 			}
+ 			pw++;
+ 		}
+ 		return FALSE;
+ 	}
+ 	else
+ 		return TRUE;
+ }
+ #endif
+ 
  postclr()
  {
  	register int	*pw = pwlist;
***************
*** 273,278
  	register int	*pw = pwlist;
  
  	while (pw <= &pwlist[pwc])
  		*pw++ = 0;
  	pwc = 0;
  }

--- 355,364 -----
  	register int	*pw = pwlist;
  
  	while (pw <= &pwlist[pwc])
+ 	{
+ #if JOBS
+ 		j_child_clear(*pw);
+ #endif
  		*pw++ = 0;
  	}
  	pwc = 0;
***************
*** 274,279
  
  	while (pw <= &pwlist[pwc])
  		*pw++ = 0;
  	pwc = 0;
  }
  

--- 360,366 -----
  		j_child_clear(*pw);
  #endif
  		*pw++ = 0;
+ 	}
  	pwc = 0;
  }
  
***************
*** 285,291
  	if (pcsid)
  	{
  		while (*pw)
! 			pw++;
  		if (pwc >= MAXP - 1)
  			pw--;
  		else

--- 372,383 -----
  	if (pcsid)
  	{
  		while (*pw)
! #if JOBS
! 			if (pcsid == *pw)
! 				return;
! 			else
! #endif
! 				pw++;
  		if (pwc >= MAXP - 1)
  			pw--;
  		else
***************
*** 289,294
  		if (pwc >= MAXP - 1)
  			pw--;
  		else
  			pwc++;
  		*pw = pcsid;
  	}

--- 381,387 -----
  		if (pwc >= MAXP - 1)
  			pw--;
  		else
+ 		{
  			pwc++;
  #if JOBS
  			wf_pwc++;
***************
*** 290,295
  			pw--;
  		else
  			pwc++;
  		*pw = pcsid;
  	}
  }

--- 383,392 -----
  		else
  		{
  			pwc++;
+ #if JOBS
+ 			wf_pwc++;
+ #endif
+ 		}
  		*pw = pcsid;
  	}
  }
***************
*** 297,302
  await(i, bckg)
  int	i, bckg;
  {
  	int	rc = 0, wx = 0;
  	int	w;
  	int	ipwc = pwc;

--- 394,404 -----
  await(i, bckg)
  int	i, bckg;
  {
+ #if JOBS
+ #include	"/usr/include/sys/time.h"
+ #include	"/usr/include/sys/resource.h"
+ 	struct rusage	ru;
+ #endif
  	int	rc = 0, wx = 0;
  	int	w;
  	int	ipwc = pwc;
***************
*** 300,305
  	int	rc = 0, wx = 0;
  	int	w;
  	int	ipwc = pwc;
  
  	post(i);
  	while (pwc)

--- 402,409 -----
  	int	rc = 0, wx = 0;
  	int	w;
  	int	ipwc = pwc;
+ #if JOBS
+ 	BOOL	update_only = i == -2;
  
  	if (update_only)
  		i = -1;
***************
*** 301,307
  	int	w;
  	int	ipwc = pwc;
  
! 	post(i);
  	while (pwc)
  	{
  		register int	p;

--- 405,418 -----
  #if JOBS
  	BOOL	update_only = i == -2;
  
! 	if (update_only)
! 		i = -1;
! 	if ((flags&jobflg) == 0 || i != -1)
! #endif
! 		post(i);
! #if JOBS
! 	while (pwc || (flags&jobflg))
! #else
  	while (pwc)
  #endif
  	{
***************
*** 303,308
  
  	post(i);
  	while (pwc)
  	{
  		register int	p;
  		register int	sig;

--- 414,420 -----
  	while (pwc || (flags&jobflg))
  #else
  	while (pwc)
+ #endif
  	{
  		register int	p;
  		register int	sig;
***************
*** 310,315
  		int	found = 0;
  
  		{
  			register int	*pw = pwlist;
  
  			p = wait(&w);

--- 422,428 -----
  		int	found = 0;
  
  		{
+ #ifndef JOBS
  			register int	*pw = pwlist;
  #endif
  
***************
*** 311,316
  
  		{
  			register int	*pw = pwlist;
  
  			p = wait(&w);
  			if (wasintr)

--- 424,430 -----
  		{
  #ifndef JOBS
  			register int	*pw = pwlist;
+ #endif
  
  #if JOBS
  			if (i == 0 && (flags&jobflg) && wf_pwc == 0)
***************
*** 312,317
  		{
  			register int	*pw = pwlist;
  
  			p = wait(&w);
  			if (wasintr)
  			{

--- 426,447 -----
  			register int	*pw = pwlist;
  #endif
  
+ #if JOBS
+ 			if (i == 0 && (flags&jobflg) && wf_pwc == 0)
+ 				break;
+ 			if ((pwc == 0 && (flags&jobflg)) || update_only)
+ 			{
+ 				if ((p = wait3(&w, WUNTRACED|WNOHANG, &ru)) == 0)
+ 				{
+ 					unpost (i);
+ 					break;
+ 				}
+ 				if (pwc == 0 && p == -1)
+ 					break;
+ 			}
+ 			else
+ 				p = wait3(&w, WUNTRACED, &ru);
+ #else
  			p = wait(&w);
  #endif
  			if (wasintr)
***************
*** 313,318
  			register int	*pw = pwlist;
  
  			p = wait(&w);
  			if (wasintr)
  			{
  				wasintr = 0;

--- 443,449 -----
  				p = wait3(&w, WUNTRACED, &ru);
  #else
  			p = wait(&w);
+ #endif
  			if (wasintr)
  			{
  				wasintr = 0;
***************
*** 321,326
  					break;
  				}
  			}
  			while (pw <= &pwlist[ipwc])
  			{
  				if (*pw == p)

--- 452,462 -----
  					break;
  				}
  			}
+ 
+ #if JOBS
+ 			if (unpost(p))
+ 				found++;
+ #else
  			while (pw <= &pwlist[ipwc])
  			{
  				if (*pw == p)
***************
*** 332,337
  				else
  					pw++;
  			}
  		}
  		if (p == -1)
  		{

--- 468,474 -----
  				else
  					pw++;
  			}
+ #endif
  		}
  		if (p == -1)
  		{
***************
*** 337,342
  		{
  			if (bckg)
  			{
  				register int *pw = pwlist;
  
  				while (pw <= &pwlist[ipwc] && i != *pw)

--- 474,483 -----
  		{
  			if (bckg)
  			{
+ #if JOBS
+ 				j_child_clear(i);
+ 				unpost(i);
+ #else
  				register int *pw = pwlist;
  
  				while (pw <= &pwlist[ipwc] && i != *pw)
***************
*** 346,351
  					*pw = 0;
  					pwc--;
  				}
  			}
  			continue;
  		}

--- 487,493 -----
  					*pw = 0;
  					pwc--;
  				}
+ #endif
  			}
  			continue;
  		}
***************
*** 354,360
  		{
  			if (sig == 0177)	/* ptrace! return */
  			{
- 				prs("ptrace: ");
  				sig = w_hi;
  			}
  			if (sysmsg[sig])

--- 496,501 -----
  		{
  			if (sig == 0177)	/* ptrace! return */
  			{
  				sig = w_hi;
  #if JOBS
  				if ((flags&jobflg) &&
***************
*** 356,361
  			{
  				prs("ptrace: ");
  				sig = w_hi;
  			}
  			if (sysmsg[sig])
  			{

--- 497,512 -----
  			if (sig == 0177)	/* ptrace! return */
  			{
  				sig = w_hi;
+ #if JOBS
+ 				if ((flags&jobflg) &&
+ 					(sig == SIGSTOP || sig == SIGTSTP ||
+ 					 sig == SIGTTOU || sig == SIGTTIN))
+ 				{
+ 					j_child_stop(p, sig);
+ 					goto j_bypass;
+ 				}
+ #endif
+ 				prs("ptrace: ");
  			}
  			if (sysmsg[sig])
  			{
***************
*** 371,376
  			}
  			newline();
  		}
  		if (rc == 0 && found != 0)
  			rc = (sig ? sig | SIGFLG : w_hi);
  		wx |= w;

--- 522,558 -----
  			}
  			newline();
  		}
+ #if JOBS
+ 		if (flags&infoflg)
+ 		{
+ 			register int	k;
+ 			long		l;
+ 
+ 			prc('[');
+ 			l = ru.ru_utime.tv_sec * 1000000L + ru.ru_utime.tv_usec
+ 			  + ru.ru_stime.tv_sec * 1000000L + ru.ru_stime.tv_usec;
+ 			prn((int)(l / 1000000));	/* integral seconds */
+ 			k = (int)(l % 1000000L) / 1000;	/* thousandths */
+ 			prc('.');
+ 			if (k < 100)
+ 				prc('0');
+ 			if (k < 10)
+ 				prc('0');
+ 			prn(k);
+ 			blank();
+ 			prn((int)ru.ru_inblock);
+ 			blank();
+ 			prn((int)ru.ru_oublock);
+ 			blank();
+ 			prn((int)ru.ru_minflt);
+ 			blank();
+ 			prn((int)ru.ru_majflt);
+ 			prc(']');
+ 			newline();
+ 		}
+ 		j_child_die(p);
+ 	j_bypass:
+ #endif
  		if (rc == 0 && found != 0)
  			rc = (sig ? sig | SIGFLG : w_hi);
  		wx |= w;
:::::::: setbrk.c :::::::
No differences encountered
:::::::: sh.mk :::::::
*** ../orig.u/sh.mk	Wed May 15 17:08:30 1985
--- sh.mk	Wed May 29 16:28:26 1985
***************
*** 5,11
  ROOT=
  INS = /etc/install -n $(ROOT)/bin
  INSDIR =
! CFLAGS = -O -DNICE -DACCT -DNICEVAL=4
  LDFLAGS = -n -s
  
  OFILES = setbrk.o blok.o stak.o cmd.o fault.o main.o word.o string.o\

--- 5,11 -----
  ROOT=
  INS = /etc/install -n $(ROOT)/bin
  INSDIR =
! CFLAGS = -O -DNICE -DNICEVAL=4 -DJOBS
  LDFLAGS = -n -s
  
  OFILES = setbrk.o blok.o stak.o cmd.o fault.o main.o word.o string.o\
***************
*** 10,15
  
  OFILES = setbrk.o blok.o stak.o cmd.o fault.o main.o word.o string.o\
  name.o args.o xec.o service.o error.o io.o print.o macro.o expand.o\
  ctype.o msg.o test.o defs.o echo.o hash.o hashserv.o pwd.o func.o
  
  all: sh

--- 10,17 -----
  
  OFILES = setbrk.o blok.o stak.o cmd.o fault.o main.o word.o string.o\
  name.o args.o xec.o service.o error.o io.o print.o macro.o expand.o\
+ history.o homedir.o \
+ jobs.o signal.o ulimit.o \
  ctype.o msg.o test.o defs.o echo.o hash.o hashserv.o pwd.o func.o
  
  all: sh
***************
*** 20,34
  $(OFILES):	defs.h $(FRC)
  
  ctype.o:	ctype.h
! 		if [ "${_ID_}" ];\
! 		then \
! 			$(CC) $(CFLAGS) -c ctype.c; \
! 		elif [ "${_SH_}" ]; \
! 		then \
! 			CC=$(CC) AS=$(AS) $(_SH_) ./:fix ctype; \
! 		else \
! 			CC=$(CC) AS=$(AS) sh ./:fix ctype; \
! 		fi
  
  xec.o:		xec.c
  	set +e; if u370;\

--- 22,32 -----
  $(OFILES):	defs.h $(FRC)
  
  ctype.o:	ctype.h
! 		$(CC) $(CFLAGS) -S ctype.c
! 		sed '/^[ 	]*\.data/s/data/text/' < ctype.s > x.s
! 		mv x.s ctype.s
! 		$(AS) ctype.s -o ctype.o
! 		rm ctype.s
  
  xec.o:		xec.c
  	set +e; if u370;\
***************
*** 55,69
  
  
  msg.o:		msg.c $(FRC)
! 		if [ "${_ID_}" ];\
! 		then \
! 			$(CC) $(CFLAGS) -c msg.c; \
! 		elif [ "${_SH_}" ]; \
! 		then \
! 			CC=$(CC) AS=$(AS) $(_SH_) ./:fix msg; \
! 		else \
! 			CC=$(CC) AS=$(AS) sh ./:fix msg; \
! 		fi
  
  test:
  	  rtest $(TESTDIR)/sh

--- 53,63 -----
  
  
  msg.o:		msg.c $(FRC)
! 		$(CC) $(CFLAGS) -S msg.c
! 		sed '/^[ 	]*\.data/s/data/text/' < msg.s > x.s
! 		mv x.s msg.s
! 		$(AS) msg.s -o msg.o
! 		rm msg.s
  
  test:
  	  rtest $(TESTDIR)/sh
:::::::: stak.c :::::::
No differences encountered
:::::::: stak.h :::::::
No differences encountered
:::::::: string.c :::::::
No differences encountered
:::::::: sym.h :::::::
*** ../orig.u/sym.h	Wed May 15 17:08:32 1985
--- sym.h	Sun May 19 16:37:20 1985
***************
*** 45,47
  #define ESCAPE	'\\'
  #define BRACE	'{'
  #define COMCHAR '#'

--- 45,48 -----
  #define ESCAPE	'\\'
  #define BRACE	'{'
  #define COMCHAR '#'
+ #define PERCENT '%'	/* DAG -- useful addition */
:::::::: test.c :::::::
*** ../orig.u/test.c	Wed May 15 17:08:33 1985
--- test.c	Mon May 20 15:57:01 1985
***************
*** 126,131
  		if (eq(a, "-k"))
  			return(ftype(nxtarg(0), S_ISVTX));
  		if (eq(a, "-p"))
  			return(filtyp(nxtarg(0),S_IFIFO));
     		if (eq(a, "-s"))
  			return(fsizep(nxtarg(0)));

--- 126,134 -----
  		if (eq(a, "-k"))
  			return(ftype(nxtarg(0), S_ISVTX));
  		if (eq(a, "-p"))
+ #if JOBS && !defined(pyr)
+ #define	S_IFIFO		S_IFSOCK	/* fifo - map to socket on 4.2BSD */
+ #endif
  			return(filtyp(nxtarg(0),S_IFIFO));
     		if (eq(a, "-s"))
  			return(fsizep(nxtarg(0)));
:::::::: timeout.h :::::::
No differences encountered
:::::::: word.c :::::::
*** ../orig.u/word.c	Wed May 15 17:08:34 1985
--- word.c	Thu Jun  6 14:37:41 1985
***************
*** 19,24
  	struct argnod	*arg = (struct argnod *)locstak();
  	register char	*argp = arg->argval;
  	int		alpha = 1;
  
  	wdnum = 0;
  	wdset = 0;

--- 19,25 -----
  	struct argnod	*arg = (struct argnod *)locstak();
  	register char	*argp = arg->argval;
  	int		alpha = 1;
+ 	char		*save;
  
  	wdnum = 0;
  	wdset = 0;
***************
*** 23,28
  	wdnum = 0;
  	wdset = 0;
  
  	while (1)
  	{
  		while (c = nextc(0), space(c))		/* skipc() */

--- 24,30 -----
  	wdnum = 0;
  	wdset = 0;
  
+ 	catcheof = TRUE;
  	while (1)
  	{
  		while (c = nextc(0), space(c))		/* skipc() */
***************
*** 38,43
  			break;	/* out of comment - white space loop */
  		}
  	}
  	if (!eofmeta(c))
  	{
  		do

--- 40,46 -----
  			break;	/* out of comment - white space loop */
  		}
  	}
+ 	save = argp;	/* save start of word */
  	if (!eofmeta(c))
  	{
  		do
***************
*** 69,74
  							chkpr();
  					}
  				}
  			}
  		} while ((c = nextc(0), !eofmeta(c)));
  		argp = endstak(argp);

--- 72,93 -----
  							chkpr();
  					}
  				}
+ 				else if (c == SQUIGGLE &&
+ 						validtilde (save, argp))
+ 				{
+ 					char *name, *home;
+ 
+ 					name = argp;
+ 					while ((c = nextc(0)) != '/' &&
+ 							!eofmeta(c))
+ 						*name++ = c;
+ 					peekc = c;
+ 					*name = '\0';
+ 					home = homedir (argp);
+ 					if(*home)
+ 						movstr (home, --argp);
+ 					argp += length (argp) - 1;
+ 				}
  			}
  		} while ((c = nextc(0), !eofmeta(c)));
  		argp = endstak(argp);
***************
*** 117,122
  			wdval = EOFSYM;
  		if (iopend && eolchar(c))
  		{
  			copy(iopend);
  			iopend = 0;
  		}

--- 136,144 -----
  			wdval = EOFSYM;
  		if (iopend && eolchar(c))
  		{
+ 			int histon = (flags&nohistflg) == 0;
+ 
+ 			flags |= nohistflg;	/* no history for here docs */
  			copy(iopend);
  			if (histon)		/* turn history back on */
  				flags &= ~nohistflg;
***************
*** 118,123
  		if (iopend && eolchar(c))
  		{
  			copy(iopend);
  			iopend = 0;
  		}
  	}

--- 140,147 -----
  
  			flags |= nohistflg;	/* no history for here docs */
  			copy(iopend);
+ 			if (histon)		/* turn history back on */
+ 				flags &= ~nohistflg;
  			iopend = 0;
  		}
  	}
***************
*** 121,126
  			iopend = 0;
  		}
  	}
  	reserv = FALSE;
  	return(wdval);
  }

--- 145,151 -----
  			iopend = 0;
  		}
  	}
+ 	catcheof = FALSE;
  	reserv = FALSE;
  	return(wdval);
  }
***************
*** 157,162
  
  readc()
  {
  	register char	c;
  	register int	len;
  	register struct fileblk *f;

--- 182,188 -----
  
  readc()
  {
+ 	static int	eofcount = 0;	/* to break endless catcheof loop */
  	register char	c;
  	register int	len;
  	register struct fileblk *f;
***************
*** 200,209
  	}
  	else if ((len = readb()) <= 0)
  	{
! 		close(f->fdes);
! 		f->fdes = -1;
! 		c = EOF;
! 		f->feof++;
  	}
  	else
  	{

--- 226,260 -----
  	}
  	else if ((len = readb()) <= 0)
  	{
! 		if (catcheof
! #if JOBS
! 		 && (flags&(ttyflg|prompt|dotflg)) == (ttyflg|prompt)
! 		 && ((flags&noeotflg) || j_finish(FALSE))
! #else
! 		 && (flags&(ttyflg|prompt|noeotflg|dotflg)) == (ttyflg|prompt|noeotflg)
! #endif
! 		 && ++eofcount < 10)	/* in case terminal is disconnected */
! 		{
! #if JOBS
! 			if ((flags&(ttyflg|prompt|noeotflg))
! 			 == (ttyflg|prompt|noeotflg))
! #endif
! 				prs ("use \"exit\"\n");
! #if JOBS
! 			/* else "there are stopped jobs" was printed */
! #endif
! 			c = NL;
! 		}
! 		else
! 		{
! 			close(f->fdes);
! 			f->fdes = -1;
! 			c = EOF;
! 			f->feof++;
! #if JOBS
! 			j_finish(TRUE);
! #endif
! 		}
  	}
  	else
  	{
***************
*** 207,213
  	}
  	else
  	{
! 		f->fend = (f->fnxt = f->fbuf) + len;
  		goto retry;
  	}
  	return(c);

--- 258,265 -----
  	}
  	else
  	{
! 		f->fend = f->fnxt + len;
! 		eofcount = 0;
  		goto retry;
  	}
  	return(c);
***************
*** 214,220
  }
  
  static
! readb()
  {
  	register struct fileblk *f = standin;
  	register int	len;

--- 266,272 -----
  }
  
  static
! readblock ()	/* ADR -- changed the name */
  {
  	register struct fileblk *f = standin;
  	register int	len;
***************
*** 234,237
  		}
  	} while ((len = read(f->fdes, f->fbuf, f->fsiz)) < 0 && trapnote);
  	return(len);
  }

--- 286,486 -----
  		}
  	} while ((len = read(f->fdes, f->fbuf, f->fsiz)) < 0 && trapnote);
  	return(len);
+ }
+ 
+ /* readb --- read a block from the outside world, and history process it */
+ 
+ /*
+  * In BSD systems, using the literal next capability of the tty driver, it
+  * is actually possible to put a newline in the middle of the input line,
+  * and then hit return, so that the shell sees two lines of input.
+  *
+  * As a design decision, if there is a \n in the middle of what we've read
+  * from a terminal, treat the commands as two separately typed commands. I.e.
+  *
+  *	echo hi ^J echo there
+  *
+  * is the same as
+  *
+  *	echo hi
+  *	echo there
+  *
+  * The major reason for doing it this way is that the history mechanism knows
+  * that a \n is the end of a line.
+  *
+  * Finally, on USG systems, we just leave this code alone, since it won't
+  * get executed anyway.
+  */
+ 
+ /*
+  * In word.c, the readc() function keeps a pointer to what standin pointed to
+  * when readc first gets called.  Therefore, where standin points to can not 
+  * not change across calls to readb().  To get around this, we change the
+  * contents of the structure pointed to by standin, saving and restoring
+  * it as necessary.
+  */
+ 
+ #define LARGEBUF	(HISTSIZE / 2)	/* size of expanded history */
+ 
+ static
+ readb()
+ {
+ 	int ilen, i, j;
+ 	char ibuf[BUFSIZ];	/* input into scratch area, pass to history */
+ 	static char expansion[LARGEBUF];
+ 	static int moreinbuf = FALSE;
+ 	static int saved_ilen = 0;
+ 	static int start_here = 0;
+ 	static struct fileblk *f = 0;
+ 	auto int gotoutofbuf = 0;
+ 
+ 	if (expanded)	/* just did a history substitution */
+ 		expanded = 0;
+ 
+ 	if ((flags & nohistflg) || (flags & prompt) == 0 || ! isatty (input)
+ 			|| standin->fstak != 0)
+ 	{
+ 		ilen = readblock ();
+ 		if (ilen > 0)
+ 			standin->fnxt = standin->fbuf;
+ 		return (ilen);
+ 		/* not doing history expansion at all */
+ 	}
+ 
+ 	if (f == 0)
+ 		f = standin;
+ 
+ 	ilen = 0;
+ 
+ 	/*
+ 	 * First, if there was more stuff in the last buffer, go and get it.
+ 	 * If not get some more from the outside world.
+ 	 *
+ 	 * Then, make sure we've read up to a newline.
+ 	 * This is basically in case someone has done something bizarre
+ 	 * like 'stty raw', and input is coming in one character at a time.
+ 	 *
+ 	 * We use a heuristic.  If amount read is just 1, keep reading till
+ 	 * we get a newline.  Else, read in a complete line from the terminal.
+ 	 * Once we're in raw mode, can't reset it until a newline is typed.
+ 	 *
+ 	 * If not reading one character at a time, then do the stuff for
+ 	 * embedded newlines.
+ 	 */
+ 
+ 	if (moreinbuf)
+ 	{
+ 		for (i = 0, j = start_here; f->fbuf[j] != NL && j < saved_ilen; i++, j++)
+ 			ibuf[i] = f->fbuf[j];
+ 
+ #ifdef notdef
+ 		if (f->fbuf[j] != NL)
+ 		{
+ 			prs ("internal i/o error C in readb\n");
+ 			return (0);
+ 		}
+ #endif
+ 
+ 		if (f->fbuf[j] == NL)
+ 			ibuf[i++] = NL;
+ 		ibuf[i] = '\0';
+ 		ilen = i;
+ 		/* embedded newline */
+ 		moreinbuf = (++j < saved_ilen - 1);
+ 		if (moreinbuf)
+ 			start_here = j;	/* where to start next time */
+ 		gotoutofbuf = 1;
+ 	}
+ 	else	/* wasn't an embedded \n last time */
+ 	{
+ 		ilen = readblock ();
+ 	
+ 		if (ilen <= 0)	/* EOF or error */
+ 			return (ilen);
+ 
+ 		if (ilen == 1)	/* either in raw mode, or an empty line */
+ 		{
+ 			i = 0;
+ 			ibuf[i++] = f->fbuf[0];
+ 			if (f->fbuf[0] == NL)
+ 			{
+ 				ibuf[i] = '\0';
+ 				goto dohist;
+ 			}
+ 
+ 			while ((ilen = readblock()) > 0)
+ 			{
+ 				if (ilen != 1)
+ 				{
+ 					prs ("internal i/o error A in readb\n");
+ 					return (0);
+ 				}
+ 				ibuf[i++] = f->fbuf[0];
+ 				if (f->fbuf[0] == NL)
+ 				{
+ 					ibuf[i] = '\0';
+ 					break;	/* while */
+ 				}
+ 			}
+ 			ilen = i;
+ 			gotoutofbuf = TRUE;
+ 			/* force code below to use collected string */
+ 		}
+ 		else
+ 		{
+ 			/* reading bunches of characters at once */
+ 			for (i = 0; f->fbuf[i] != NL && i < ilen; i++)
+ 				ibuf[i] = f->fbuf[i];
+ 
+ #ifdef notdef
+ 			if (f->fbuf[i] != NL)
+ 			{
+ 				prs ("internal i/o error B in readb\n");
+ 				return (0);
+ 			}
+ #endif
+ 
+ 			ibuf[i++] = NL;
+ 			ibuf[i] = '\0';
+ 			/* ilen was set by readblock() */
+ 			/* embedded newline */
+ 			moreinbuf = (i < ilen - 1);
+ 			if (moreinbuf)
+ 			{
+ 				saved_ilen = ilen;
+ 				start_here = i;
+ 				/* where to start next time */
+ 				gotoutofbuf = 1;
+ 			}
+ 		}
+ 	}
+ 
+ dohist:
+ 	/* quick heuristic */
+ 	if (! gotoutofbuf && ilen == 1 && f->fbuf[0] == NL)
+ 	{
+ 		f->fnxt = f->fbuf;
+ 		return (ilen);
+ 	}
+ 
+ 	if (histsub (ibuf, expansion, sizeof expansion))
+ 	{
+ 		int olen = length (expansion) - 1;
+ 		if (! expanded && ! gotoutofbuf)
+ 		{
+ 			standin->fnxt = standin->fbuf;
+ 			return (ilen);
+ 		}
+ 		/* else
+ 			expanded == TRUE or from buffer */
+ 		standin->fnxt = expansion;
+ 		return (olen);
+ 	}
+ 	else
+ 	{
+ 		/* hist expansion failed, return an empty line */
+ 		standin->fnxt = standin->fbuf;
+ 		standin->fbuf[0] = NL;
+ 		return (1);
+ 	}
  }
:::::::: xec.c :::::::
*** ../orig.u/xec.c	Wed May 15 17:08:37 1985
--- xec.c	Wed Jun  5 11:11:18 1985
***************
*** 27,32
  	 */
  	register struct trenod	*t;
  	char		*sav = savstak();
  
  	sigchk();
  	if (!errorflg)

--- 27,42 -----
  	 */
  	register struct trenod	*t;
  	char		*sav = savstak();
+ #if pyr
+ 	auto int change_univ = FALSE;
+ 	auto int new_univ = 0;
+ 	/*
+ 	 * univesrses run from 1 to NUMUNIV: We start out at 0
+ 	 * and increment new_univ in the switch for internal
+ 	 * commands, below.  new_univ must *not* be assigned to, directly
+ 	 * or via side effects, any place else.
+ 	 */
+ #endif
  
  	sigchk();
  	if (!errorflg)
***************
*** 109,114
  					if (flags & execpr)
  						execprint(com);
  
  					if (comtype == NOTFOUND)
  					{
  						pos = hashdata(cmdhash);

--- 119,130 -----
  					if (flags & execpr)
  						execprint(com);
  
+ 					/*
+ 					 * fix a bug which caused the shell
+ 					 * to do not do a second command if
+ 					 * the first was not found. (bug fix
+ 					 * from USENET)
+ 					 */
  					if (comtype == NOTFOUND)
  					{
  						char *errstr;
***************
*** 111,116
  
  					if (comtype == NOTFOUND)
  					{
  						pos = hashdata(cmdhash);
  						if (pos == 1)
  							failed(*com, notfound);

--- 127,134 -----
  					 */
  					if (comtype == NOTFOUND)
  					{
+ 						char *errstr;
+ 
  						pos = hashdata(cmdhash);
  						if (pos == 1)
  							errstr = notfound;
***************
*** 113,119
  					{
  						pos = hashdata(cmdhash);
  						if (pos == 1)
! 							failed(*com, notfound);
  						else if (pos == 2)
  							failed(*com, badexec);
  						else

--- 131,137 -----
  
  						pos = hashdata(cmdhash);
  						if (pos == 1)
! 							errstr = notfound;
  						else if (pos == 2)
  							errstr = badexec;
  						else
***************
*** 115,121
  						if (pos == 1)
  							failed(*com, notfound);
  						else if (pos == 2)
! 							failed(*com, badexec);
  						else
  							failed(*com, badperm);
  						break;

--- 133,139 -----
  						if (pos == 1)
  							errstr = notfound;
  						else if (pos == 2)
! 							errstr = badexec;
  						else
  							errstr = badperm;
  						prp();
***************
*** 117,123
  						else if (pos == 2)
  							failed(*com, badexec);
  						else
! 							failed(*com, badperm);
  						break;
  					}
  

--- 135,147 -----
  						else if (pos == 2)
  							errstr = badexec;
  						else
! 							errstr = badperm;
! 						prp();
! 						prs_cntl(*com);
! 						prs (colon);
! 						prs (errstr);
! 						newline();
! 						exitval = 1;
  						break;
  					}
  
***************
*** 148,153
  								if ((f = pathopen(getpath(a1), a1)) < 0)	
  									failed(a1, notfound);	
  								else	
  									execexp(0, f);	
  							}	
  							break;	

--- 172,181 -----
  								if ((f = pathopen(getpath(a1), a1)) < 0)	
  									failed(a1, notfound);	
  								else	
+ 								{
+ 									int	savedot = flags&dotflg;
+ 
+ 									flags |= dotflg;
  									execexp(0, f);	
  									flags &= ~dotflg;
  									flags |= savedot;
***************
*** 149,154
  									failed(a1, notfound);	
  								else	
  									execexp(0, f);	
  							}	
  							break;	
  				

--- 177,185 -----
  
  									flags |= dotflg;
  									execexp(0, f);	
+ 									flags &= ~dotflg;
+ 									flags |= savedot;
+ 								}
  							}	
  							break;	
  				
***************
*** 163,169
  								prc_buff(NL);	
  							}	
  							break;	
! 				
  						case SYSEXIT:	
  							flags |= forked;	/* force exit */	
  							exitsh(a1 ? stoi(a1) : retval);

--- 194,200 -----
  								prc_buff(NL);	
  							}	
  							break;	
! 
  						case SYSEXIT:	
  #if JOBS
  							if (j_finish(FALSE))
***************
*** 165,170
  							break;	
  				
  						case SYSEXIT:	
  							flags |= forked;	/* force exit */	
  							exitsh(a1 ? stoi(a1) : retval);
  				

--- 196,207 -----
  							break;	
  
  						case SYSEXIT:	
+ #if JOBS
+ 							if (j_finish(FALSE))
+ 								break;
+ #endif
+ 							histsave (histfnod.namval);
+ 							/* save before setting flag */
  							flags |= forked;	/* force exit */	
  
  							exitsh(a1 ? stoi(a1) : retval);
***************
*** 166,171
  				
  						case SYSEXIT:	
  							flags |= forked;	/* force exit */	
  							exitsh(a1 ? stoi(a1) : retval);
  				
  						case SYSNULL:	

--- 203,209 -----
  							histsave (histfnod.namval);
  							/* save before setting flag */
  							flags |= forked;	/* force exit */	
+ 
  							exitsh(a1 ? stoi(a1) : retval);
  				
  						case SYSNULL:	
***************
*** 248,256
  							}	
  		
  #ifdef RES	/* Research includes login as part of the shell */	
! 		
! 						case SYSLOGIN:	
! 							oldsigs();	
  							execa(com, -1);
  							done();	
  #else	

--- 286,296 -----
  							}	
  		
  #ifdef RES	/* Research includes login as part of the shell */	
! 
! 						case SYSLOGIN:
! 							histsave (histfnod.namval);
! 							flags |= forked;	/* DAG -- bug fix (force bad exec to terminate shell) */
! 							oldsigs();
  							execa(com, -1);
  							done();
  #else
***************
*** 252,260
  						case SYSLOGIN:	
  							oldsigs();	
  							execa(com, -1);
! 							done();	
! #else	
! 			
  						case SYSNEWGRP:	
  							if (flags & rshflg)	
  								failed(com[0], restricted);	

--- 292,299 -----
  							flags |= forked;	/* DAG -- bug fix (force bad exec to terminate shell) */
  							oldsigs();
  							execa(com, -1);
! 							done();
! #else
  						case SYSNEWGRP:	
  							if (flags & rshflg)	
  								failed(com[0], restricted);	
***************
*** 260,265
  								failed(com[0], restricted);	
  							else	
  							{	
  								flags |= forked;	/* force bad exec to terminate shell */	
  								oldsigs();	
  								execa(com, -1);

--- 299,305 -----
  								failed(com[0], restricted);	
  							else	
  							{	
+ 								histsave (histfnod.namval);
  								flags |= forked;	/* force bad exec to terminate shell */	
  								oldsigs();	
  								execa(com, -1);
***************
*** 266,272
  								done();	
  							}	
  		
! #endif	
  		
  						case SYSCD:	
  							if (flags & rshflg)	

--- 306,312 -----
  								done();	
  							}	
  		
! #endif
  		
  						case SYSCD:	
  							if (flags & rshflg)	
***************
*** 273,278
  								failed(com[0], restricted);	
  							else if ((a1 && *a1) || (a1 == 0 && (a1 = homenod.namval)))	
  							{	
  								char *cdpath;	
  								char *dir;	
  								int f;	

--- 313,319 -----
  								failed(com[0], restricted);	
  							else if ((a1 && *a1) || (a1 == 0 && (a1 = homenod.namval)))	
  							{	
+ 								register char *safe;	/* DAG -- added (see note, below) */
  								char *cdpath;	
  								char *dir;	
  								int f;	
***************
*** 279,286
  		
  								if ((cdpath = cdpnod.namval) == 0 ||	
  								     *a1 == '/' ||	
! 								     cf(a1, ".") == 0 ||	
! 								     cf(a1, "..") == 0 ||	
  								     (*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/')))	
  									cdpath = nullstr;	
  		

--- 320,327 -----
  		
  								if ((cdpath = cdpnod.namval) == 0 ||	
  								     *a1 == '/' ||	
! 								     cf(a1, ".") == 0 ||
! 								     cf(a1, "..") == 0 ||
  								     (*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/')))	
  									cdpath = nullstr;	
  		
***************
*** 284,289
  								     (*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/')))	
  									cdpath = nullstr;	
  		
  								do	
  								{	
  									dir = cdpath;	

--- 325,337 -----
  								     (*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/')))	
  									cdpath = nullstr;	
  		
+ /* DAG -- catpath() leaves the trial directory above the top of the "stack".
+ 	This is too dangerous; systems using directory access routines may
+ 	alloc() storage and clobber the string.  Therefore I have changed the
+ 	code to alloc() a safe place to put the trial strings.  Most of the
+ 	changes involved replacing "curstak()" with "safe".
+ */								safe = alloc((unsigned)(length(cdpath) + length(a1)));	/* DAG -- added */
+ 
  								do	
  								{	
  									dir = cdpath;	
***************
*** 288,293
  								{	
  									dir = cdpath;	
  									cdpath = catpath(cdpath,a1);	
  								}	
  								while ((f = (chdir(curstak()) < 0)) && cdpath);
  		

--- 336,342 -----
  								{	
  									dir = cdpath;	
  									cdpath = catpath(cdpath,a1);	
+ 									(void)movstr(curstak(),safe);	/* DAG -- added (see note, above) */
  								}	
  #if !defined(SYMLINK) && defined(JOBS)
  								while ((f = (cwdir(safe) < 0)) && cdpath);	/* DAG */
***************
*** 289,295
  									dir = cdpath;	
  									cdpath = catpath(cdpath,a1);	
  								}	
! 								while ((f = (chdir(curstak()) < 0)) && cdpath);
  		
  								if (f)	
  									failed(a1, baddir);	

--- 338,348 -----
  									cdpath = catpath(cdpath,a1);	
  									(void)movstr(curstak(),safe);	/* DAG -- added (see note, above) */
  								}	
! #if !defined(SYMLINK) && defined(JOBS)
! 								while ((f = (cwdir(safe) < 0)) && cdpath);	/* DAG */
! #else
! 								while ((f = (chdir(safe) < 0)) && cdpath);	/* DAG */
! #endif
  		
  								if (f)	
  								{
***************
*** 292,297
  								while ((f = (chdir(curstak()) < 0)) && cdpath);
  		
  								if (f)	
  									failed(a1, baddir);	
  								else 
  								{

--- 345,352 -----
  #endif
  		
  								if (f)	
+ 								{
+ 									free(safe);	/* DAG -- added (see note, above) */
  									failed(a1, baddir);	
  								}
  								else 
***************
*** 293,298
  		
  								if (f)	
  									failed(a1, baddir);	
  								else 
  								{
  									cwd(curstak());

--- 348,354 -----
  								{
  									free(safe);	/* DAG -- added (see note, above) */
  									failed(a1, baddir);	
+ 								}
  								else 
  								{
  #if defined(SYMLINK) || !defined(JOBS)
***************
*** 295,301
  									failed(a1, baddir);	
  								else 
  								{
! 									cwd(curstak());
  									if (cf(nullstr, dir) &&	
  									    *dir != ':' &&	
  									 	any('/', curstak()) &&	

--- 351,359 -----
  								}
  								else 
  								{
! #if defined(SYMLINK) || !defined(JOBS)
! 									cwd(safe);	/* DAG */
! #endif
  									if (cf(nullstr, dir) &&	
  									    *dir != ':' &&	
  									 	any('/', safe) &&	/* DAG */
***************
*** 298,304
  									cwd(curstak());
  									if (cf(nullstr, dir) &&	
  									    *dir != ':' &&	
! 									 	any('/', curstak()) &&	
  									 	flags & prompt)	
  									{	
  										prs_buff(curstak());	

--- 356,362 -----
  #endif
  									if (cf(nullstr, dir) &&	
  									    *dir != ':' &&	
! 									 	any('/', safe) &&	/* DAG */
  									 	flags & prompt)	
  										cwdprint();	/* DAG -- improvement */
  									free(safe);	/* DAG -- added (see note, above) */
***************
*** 300,309
  									    *dir != ':' &&	
  									 	any('/', curstak()) &&	
  									 	flags & prompt)	
! 									{	
! 										prs_buff(curstak());	
! 										prc_buff(NL);	
! 									}
  								}
  								zapcd();
  							}	

--- 358,365 -----
  									    *dir != ':' &&	
  									 	any('/', safe) &&	/* DAG */
  									 	flags & prompt)	
! 										cwdprint();	/* DAG -- improvement */
! 									free(safe);	/* DAG -- added (see note, above) */
  								}
  								zapcd();
  							}	
***************
*** 452,458
  								if (command == 1 || command == 4)	
  								{	
  									prl(i);	
! 									prc_buff('\n');	
  								}	
  								break;	
  							}				

--- 508,514 -----
  								if (command == 1 || command == 4)	
  								{	
  									prl(i);	
! 									prc_buff(NL);	
  								}	
  								break;	
  							}				
***************
*** 478,486
  								prc_buff(NL);	
  							}	
  							break;	
! 		
! #endif	
! 		
  						case SYSTST:
  							exitval = test(argn, com);
  							break;

--- 534,540 -----
  								prc_buff(NL);	
  							}	
  							break;	
! 
  						case SYSTST:
  							exitval = test(argn, com);
  							break;
***************
*** 484,489
  						case SYSTST:
  							exitval = test(argn, com);
  							break;
  
  						case SYSECHO:
  							exitval = echo(argn, com);

--- 538,544 -----
  						case SYSTST:
  							exitval = test(argn, com);
  							break;
+ #endif	/* RES (DAG -- bug fix: SYSTST not in RES) */
  
  						case SYSECHO:
  							exitval = echo(argn, com);
***************
*** 548,553
  							}
  							break;
  
  						default:	
  							prs_buff("unknown builtin\n");
  						}	

--- 603,675 -----
  							}
  							break;
  
+ #if JOBS
+ 						case SYSJOBS:
+ 
+ 							j_print();
+ 							break;
+ 
+ 						case SYSFG:
+ 
+ 							j_resume(a1, FALSE);
+ 							break;
+ 
+ 						case SYSBG:
+ 
+ 							j_resume(a1, TRUE);
+ 							break;
+ 
+ 						case SYSSUSPEND:
+ 							exitval = 1;
+ 							if (getppid() == 1)
+ 								prs ("cannot suspend a login shell\n");	/* yet ... */
+ 							else
+ 							{
+ 								exitval = 0;
+ 								kill (getpid(), SIGSTOP);
+ 							}
+ 							break;
+ #endif
+ 
+ #if pyr
+ 						/*
+ 						 * UCB is Universe 2
+ 						 * ATT is Universe 1
+ 						 * new_univ == 0
+ 						 */
+ 						case SYSUCB:
+ 							new_univ++;
+ 							/* fall thru */
+ 						case SYSATT:
+ 							new_univ++;
+ 							if (argn > 1)
+ 							{
+ 								change_univ = TRUE;
+ 								com++;
+ 								goto doit;
+ 							}
+ 							else
+ 							{
+ 								setuniverse (cur_univ = new_univ);
+ 								univnod.namflg &= ~N_RDONLY;
+ 								assign (& univnod, univ_name[cur_univ - 1]);
+ 								attrib ((& univnod), N_RDONLY);
+ 								break;
+ 							}
+ 						
+ 						case SYSUNIVERSE:
+ 							if (eq(com[1], "-l"))
+ 								prs_buff (univ_longname[cur_univ - 1]);
+ 							else
+ 								prs_buff (univ_name[cur_univ - 1]);
+ 							prc_buff (NL);
+ 							break;
+ #endif
+ 
+ 						case SYSHISTORY:
+ 							exitval = history (argn, com);
+ 							break;
+ 
  						default:	
  							prs_buff("unknown builtin\n");
  						}	
***************
*** 586,591
  			}
  
  		case TFORK:
  			exitval = 0;
  			if (execflg && (treeflgs & (FAMP | FPOU)) == 0)
  				parent = 0;

--- 708,716 -----
  			}
  
  		case TFORK:
+ #if pyr
+ 		doit:
+ #endif
  			exitval = 0;
  			if (execflg && (treeflgs & (FAMP | FPOU)) == 0)
  				parent = 0;
***************
*** 625,630
  					alarm(forkcnt);
  					pause(); 
  				}
  			}
  			if (parent)
  			{

--- 750,759 -----
  					alarm(forkcnt);
  					pause(); 
  				}
+ #if JOBS
+ 				if (parent == 0)
+ 					j_top_level = FALSE;
+ #endif
  			}
  			if (parent)
  			{
***************
*** 633,638
  				 * it may or may not wait for the child
  				 */
  				if (treeflgs & FPRS && flags & ttyflg)
  				{
  					prn(parent);
  					newline();

--- 762,770 -----
  				 * it may or may not wait for the child
  				 */
  				if (treeflgs & FPRS && flags & ttyflg)
+ #if JOBS
+ 				if ((flags&jobflg) == 0)
+ #endif
  				{
  					prn(parent);
  					newline();
***************
*** 639,644
  				}
  				if (treeflgs & FPCL)
  					closepipe(pf1);
  				if ((treeflgs & (FAMP | FPOU)) == 0)
  					await(parent, 0);
  				else if ((treeflgs & FAMP) == 0)

--- 771,779 -----
  				}
  				if (treeflgs & FPCL)
  					closepipe(pf1);
+ #if JOBS
+ 				j_child_post(parent, treeflgs&FAMP, treeflgs&FPIN, t);
+ #endif
  				if ((treeflgs & (FAMP | FPOU)) == 0)
  				{
  					await(parent, 0);
***************
*** 640,645
  				if (treeflgs & FPCL)
  					closepipe(pf1);
  				if ((treeflgs & (FAMP | FPOU)) == 0)
  					await(parent, 0);
  				else if ((treeflgs & FAMP) == 0)
  					post(parent);

--- 775,781 -----
  				j_child_post(parent, treeflgs&FAMP, treeflgs&FPIN, t);
  #endif
  				if ((treeflgs & (FAMP | FPOU)) == 0)
+ 				{
  					await(parent, 0);
  #if JOBS
  					j_reset_pg();
***************
*** 641,646
  					closepipe(pf1);
  				if ((treeflgs & (FAMP | FPOU)) == 0)
  					await(parent, 0);
  				else if ((treeflgs & FAMP) == 0)
  					post(parent);
  				else

--- 777,786 -----
  				if ((treeflgs & (FAMP | FPOU)) == 0)
  				{
  					await(parent, 0);
+ #if JOBS
+ 					j_reset_pg();
+ #endif
+ 				}
  				else if ((treeflgs & FAMP) == 0)
  					post(parent);
  				else
***************
*** 650,655
  			}
  			else	/* this is the forked branch (child) of execute */
  			{
  				flags |= forked;
  				fiotemp  = 0;
  

--- 790,805 -----
  			}
  			else	/* this is the forked branch (child) of execute */
  			{
+ #if pyr
+ 				if (change_univ)
+ 				{
+ 					setuniverse (new_univ);
+ 					univnod.namflg &= ~N_RDONLY;
+ 					assign (& univnod, univ_name[cur_univ - 1]);
+ 					attrib ((& univnod), N_RDONLY);
+ 				}
+ #endif
+ 
  				flags |= forked;
  				fiotemp  = 0;
  
***************
*** 674,679
  				 */
  				oldsigs();
  				if (treeflgs & FINT)
  				{
  					signal(SIGINT, 1);
  					signal(SIGQUIT, 1);

--- 824,832 -----
  				 */
  				oldsigs();
  				if (treeflgs & FINT)
+ #if JOBS
+ 				if ((flags&jobflg) == 0)
+ #endif
  				{
  					signal(SIGINT, SIG_IGN);	/* DAG */
  					signal(SIGQUIT, SIG_IGN);	/* DAG */
***************
*** 675,682
  				oldsigs();
  				if (treeflgs & FINT)
  				{
! 					signal(SIGINT, 1);
! 					signal(SIGQUIT, 1);
  
  #ifdef NICE
  					nice(NICEVAL);

--- 828,835 -----
  				if ((flags&jobflg) == 0)
  #endif
  				{
! 					signal(SIGINT, SIG_IGN);	/* DAG */
! 					signal(SIGQUIT, SIG_IGN);	/* DAG */
  
  #ifdef NICE
  					nice(NICEVAL);
***************
*** 700,705
  				 * default std input for &
  				 */
  				if (treeflgs & FINT && ioset == 0)
  					rename(chkopen(devnull), 0);
  				/*
  				 * io redirection

--- 853,861 -----
  				 * default std input for &
  				 */
  				if (treeflgs & FINT && ioset == 0)
+ #if JOBS
+ 				if ((flags&jobflg) == 0)
+ #endif
  					rename(chkopen(devnull), 0);
  				/*
  				 * io redirection

sources-request@genrad.UUCP (06/12/85)

From: Arnold Robbins <gatech!arnold>

This is part 7 of 9.  It contains the diffs for the System V Release 2
Bourne shell man page, sh.1.

BSD users who happen to also have source for System V Release 2 will probably
want to use this version of the shell, since it has many bug fixes and
improvements over the (much) earlier version that comes with Berkeley Unix.

Note that on a non-BSD system, you will have to edit the patched man page
to remove all references to the I and J flags, and to the job control
features.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
----------- pretend your screen is really a paper towel ------------
*** ../orig.u/sh.1	Wed May 15 17:23:11 1985
--- sh.1	Thu Jun  6 09:11:54 1985
***************
*** 34,40
  .SH SYNOPSIS
  .B sh
  [
! .B \-acefhiknrstuvx
  ] [ args ]
  .br
  .B rsh

--- 34,40 -----
  .SH SYNOPSIS
  .B sh
  [
! .B \-acefhiknqrstuvxEHIJ
  ] [ args ]
  .br
  .B rsh
***************
*** 39,45
  .br
  .B rsh
  [
! .B \-acefhiknrstuvx
  ] [ args ]
  .SH DESCRIPTION
  .I Sh\^

--- 39,45 -----
  .br
  .B rsh
  [
! .B \-acefhiknqrstuvxEHIJ
  ] [ args ]
  .SH DESCRIPTION
  .I Sh\^
***************
*** 72,77
  .BR ? ,
  .BR \- ,
  .BR $ ,
  and
  .BR !\\^ .
  .SS Commands

--- 72,78 -----
  .BR ? ,
  .BR \- ,
  .BR $ ,
+ .BR + ,
  and
  .BR !\\^ .
  .SS Commands
***************
*** 446,451
  .B $
  The process number of this shell.
  .TP
  .B !
  The process number of the last background command invoked.
  .PD

--- 447,464 -----
  .B $
  The process number of this shell.
  .TP
+ .B +
+ The process number of the parent of this shell.  In particular,
+ the value of
+ .B $+
+ will track the value of the
+ .IR getppid (2)
+ system calll.  I.e. if
+ .I init
+ should inherit this shell,
+ .B $+
+ will become 1.
+ .TP
  .B !
  The process number of the last background command invoked.
  .PD
***************
*** 552,557
  below) for this name.
  If it is found and there is an 'r' in the file name part of its value, the
  shell becomes a restricted shell.
  .PD
  .RE
  .PP

--- 565,576 -----
  below) for this name.
  If it is found and there is an 'r' in the file name part of its value, the
  shell becomes a restricted shell.
+ .TP
+ .B
+ .SM HISTFILE
+ The file where command history is saved across login sessions.
+ The default value is
+ .BR \s-1$HOME\s+1/.history .
  .PD
  .RE
  .PP
***************
*** 556,562
  .RE
  .PP
  The shell gives default values to
! \f3\s-1PATH\s+1\fP, \f3\s-1PS1\s+1\fP, \f3\s-1PS2\s+1\fP, \f3\s-1MAILCHECK\s+1\fP and \f3\s-1IFS\s+1\fP.
  .SM
  .B HOME
  and

--- 575,582 -----
  .RE
  .PP
  The shell gives default values to
! \f3\s-1HISTFILE\s+1\fP, \f3\s-1PATH\s+1\fP, \f3\s-1PS1\s+1\fP,
! \f3\s-1PS2\s+1\fP, \f3\s-1MAILCHECK\s+1\fP and \f3\s-1IFS\s+1\fP.
  .SM
  .B HOME
  and
***************
*** 564,569
  .B MAIL
  are set by
  .IR login (1).
  .SS Blank Interpretation
  After parameter and command substitution,
  the results of substitution are scanned for internal field separator

--- 584,810 -----
  .B MAIL
  are set by
  .IR login (1).
+ .SS Tilde Substitution
+ An unquoted tilde character
+ .RB ( ~ )
+ will cause the shell to attempt a tilde substituion.  Tilde substitutions
+ are used to automatically determine home directories.  Both the current
+ user's home directory, and the home directory of any other user on
+ the system may be found.
+ .PP
+ A
+ .B ~
+ by itself is equivalent to using
+ .BR \s-1$HOME\s+1 .
+ E.g.
+ .B ~/bin
+ is the same as saying
+ .BR \s-1$HOME\s+1/bin .
+ The notation
+ .B ~person
+ will cause the shell to look up
+ .BR person 's
+ home directory in the
+ .B /etc/passwd
+ file, and substitute it in.  For example, if user
+ .BR arnold 's
+ home directory is
+ .BR /user/arnold ,
+ the shell would replace
+ .BR ~arnold/bin
+ with
+ .BR /user/arnold/bin .
+ .PP
+ Tilde substitutions are recognized at the beginning of words, after
+ equal signs (for shell variable assignment), in the middle of single letter
+ flag arguments to commands (e.g. \fBecho \-t~arnold\fP), and after
+ colons inside the
+ .B
+ .SM PATH
+ and
+ .B
+ .SM CDPATH
+ shell parameters.
+ .PP
+ If
+ .B /etc/passwd
+ cannot be read, or if
+ no user can be found to match the attempted tilde substitution,
+ the text is left unmodified.
+ .SS History Substitution
+ When reading input from an interactive terminal, a
+ .RB `` ! ''
+ character, anywhere on the line,
+ signals the shell that it should attempt
+ to perform a history substitution.
+ A history substitution is a shorthand method which allows the user
+ to recall all or part of a previous command, possibly editing the
+ recalled portion.
+ The recalled (and possibly changed) command line is then placed into
+ the current command line,
+ to be passed on to the rest of the shell for normal processing.
+ A history substitution takes the form:
+ .PP
+ .if t .RS
+ \fB!\fP\^[ \fIstr\fP | \fB?\fIstr\fB?\fR | \fInum\fP ]\c
+ [ \fB\(ga\fInum\fR [ \- [ \fInum\fP ] ]\c
+ { \fB^\fIstr\fB^\fIstr\fB^\fR [\fBg\fP] }
+ .if t .RE
+ .PP
+ A history substitution contains three parts;
+ command selection, argument selection, and editing.
+ .I Command selection
+ chooses what command will be retrieved from the stored
+ history.
+ .I Argument selection
+ chooses which arguments from that command will be extracted.
+ .I Editing
+ allows the user to change spelling or make a substitution.
+ .PP
+ The history substitution is triggered by the
+ .RB `` ! '',
+ and continues until another
+ .RB `` ! ''
+ is encountered, or until
+ something that could not be part of a history substitution is seen.
+ This is so that the
+ history substitution will be properly concatenated with the following text.
+ Whenever a history substitution is encountered and properly performed,
+ the shell echoes the resulting line to the terminal and then executes the
+ command.
+ .PP
+ History substitution occurs inside double quotes and grave accents, but will
+ not occur inside single quotes.  To get a literal
+ .RB `` ! ''
+ character, outside of single quotes, precede it with a
+ .BR \e .
+ The
+ .BR ? ,
+ .BR \(ga ,
+ and
+ .B ^
+ characters are treated specially by the history mechanism only when preceded
+ by a
+ .RB `` ! '',
+ otherwise they have their normal meaning
+ of ``match a single character'',
+ ``enclose a command substitution'',
+ and as a synonym for the \fB\(bv\fP
+ character.
+ .PP
+ The full meaning of the history syntax is as follows:
+ .RS
+ .TP
+ \fB!\fP\^[ \fIstr\fP | \fB?\fIstr\fB?\fR | \fInum\fP ]
+ The first thing in a history substitution is
+ .IR "command selection" .
+ This is used to retrieve a given command line for use, or for further
+ processing.  In a history command selection, \fB!\fIstr\fR
+ will find the most recent command line that started with the
+ characters in
+ .IR str .
+ \fB!?\fIstr\fB?\fR will find the most recent command line that contained
+ .I str
+ anywhere on the line.  It also allows
+ .I str
+ to contain blanks and tabs, whereas the first form does not.
+ \fB!\fInum\fR allows the user to specify the number of a command, according
+ to the output of the
+ .B history
+ command (see the section on special commands, below).
+ .TP
+ \fB\(ga\fInum\fR [ \- [ \fInum\fP ]
+ The next portion of a history substitution is an optional
+ .IR "argument selection" .
+ This chooses which portions of the command are to be kept.
+ History arguments are not exactly the same as the arguments the rest of
+ the shell uses, since history expansion occurs before argument collection.
+ Arguments in this context are blank or tab separated words on the command line.
+ Single or double quoted strings, strings inside grave accents, shell regular
+ expressions, commands in parentheses (which get executed in a subshell),
+ and commands enclosed in braces,
+ are all treated as single arguments for the history mechanism, even though
+ they may have white space in them.
+ .sp
+ Arguments are numbered from zero, starting at the leftmost portion of the
+ line.  In an argument selection, \fB\(ga\fInum\fR specifies that only argument
+ .I num
+ is to be extracted and kept for further processing or use, and the rest
+ of the command line is to be dropped.
+ \fB\(ga\fInum\fB\-\fInum\fR
+ specifies that the arguments from the first
+ .I num
+ to the last
+ .I num
+ are to be kept. In place of any
+ .IR num ,
+ .B $
+ may be specified to obtain the last argument on the line.
+ The form \fB\(ga\-\fInum\fR is a shorthand for \fB\(ga\fP1\fB\-\fInum\fR
+ and
+ \fB\(ga\fInum\fB\-\fR
+ is a short form for
+ \fB\(ga\fInum\fB\-$\fR.
+ Finally, the notation
+ \fB\(ga\-\fP
+ indicates all the arguments.  That is, \fB\(ga\-\fP implies
+ \fB\(ga1\-$\fP.
+ .TP
+ \fB^\fIstr\fB^\fIstr\fB^\fR [\fBg\fP]
+ The last portion of a history substitution is also optional, and is the
+ .I editing
+ phase.  This allows the remaining portions of the retrieved
+ command line to modified, like the substitute command in
+ .IR ed (1),
+ although in a much more limited fashion.
+ In the history mechanism,
+ .I str
+ is not a regular expression, as in
+ .IR ed,
+ but just a simple string.
+ The history mechanism does not recognize
+ either the shell's pattern matching characters or the editor's
+ regular expression characters.
+ Each substitution happens only once on a line, unless a trailing ``g''
+ is appended to the substitution.  In this case, the substitution occurs
+ globally (everywhere) on the line.
+ Substitutions may be strung together,
+ so that more than one can be done at once.
+ The trailing ``g'' may be in either upper or lower case.
+ .RE
+ .PP
+ Some examples of history substitution are given below.
+ Should a history substitution fail, the errant command will
+ .I not
+ be added to the history buffers.
+ .PP
+ The history mechanism recognizes lines that end with unbalanced quotes.
+ When the quotes are balanced on the next line(s), 
+ It will join this line with the one that opened the quotes, keeping the
+ embedded newline(s). So, e.g.,
+ .RS
+ .sp
+ .nf
+ .RB "$ " "echo 'open"
+ .RB "> " "close'"
+ .fi
+ .RE
+ .sp
+ will be saved as one history ``event.''
+ This does
+ .I not
+ extend to other shell constructs, like balancing parentheses across
+ newlines.
+ .PP
+ The history mechanism keeps a maximum of
+ 256
+ stored commands at any one time, and the total text of the
+ stored history may occupy no more than
+ 4096
+ characters.
+ Experience indicates that it is not necessary to store more than this,
+ and the extra history buffers should not make the shell too large for
+ machines with small address spaces (e.g. PDP-11's).
  .SS Blank Interpretation
  After history, tilde, parameter and command substitution,
  the results of substitution are scanned for internal field separator
***************
*** 565,571
  are set by
  .IR login (1).
  .SS Blank Interpretation
! After parameter and command substitution,
  the results of substitution are scanned for internal field separator
  characters (those found in
  .BR \s-1IFS\s+1 )

--- 806,812 -----
  and the extra history buffers should not make the shell too large for
  machines with small address spaces (e.g. PDP-11's).
  .SS Blank Interpretation
! After history, tilde, parameter and command substitution,
  the results of substitution are scanned for internal field separator
  characters (those found in
  .BR \s-1IFS\s+1 )
***************
*** 616,622
  matches any
  character lexically between the pair, inclusive.
  If the first character following the opening 
! \`\`\*(OK\'\'
  is a
  .B "``!''"
  any character not enclosed is matched.

--- 857,863 -----
  matches any
  character lexically between the pair, inclusive.
  If the first character following the opening 
! .RB `` \*(OK ''
  is a
  .RB `` ! ''
  any character not enclosed is matched.
***************
*** 618,624
  If the first character following the opening 
  \`\`\*(OK\'\'
  is a
! .B "``!''"
  any character not enclosed is matched.
  .PD
  .RE

--- 859,865 -----
  If the first character following the opening 
  .RB `` \*(OK ''
  is a
! .RB `` ! ''
  any character not enclosed is matched.
  Note that when typing input from the terminal, the
  .RB `` ! ''
***************
*** 620,625
  is a
  .B "``!''"
  any character not enclosed is matched.
  .PD
  .RE
  .SS Quoting

--- 861,871 -----
  is a
  .RB `` ! ''
  any character not enclosed is matched.
+ Note that when typing input from the terminal, the
+ .RB `` ! ''
+ should be preceded by a
+ .BR \e ,
+ so that the shell does not attempt to perform a history substitution.
  .PD
  .RE
  .SS Quoting
***************
*** 644,650
  are quoted.
  Inside double quote marks
  (\f3"\^"\fP),
! parameter and command substitution occurs and
  .B \e
  quotes the characters
  .BR \e ,

--- 890,896 -----
  are quoted.
  Inside double quote marks
  (\f3"\^"\fP),
! history, parameter and command substitution occurs and
  .B \e
  quotes the characters
  .BR \e ,
***************
*** 650,655
  .BR \e ,
  .BR \*` ,
  \f3"\fP,
  and
  .BR $ .
  .B

--- 896,902 -----
  .BR \e ,
  .BR \*` ,
  \f3"\fP,
+ .BR ! ,
  and
  .BR $ .
  .B
***************
*** 671,676
  .SM
  .B PS1
  before reading a command.
  If at any time a new-line is typed and further input is needed
  to complete a command, the secondary prompt
  (i.e., the value of

--- 918,934 -----
  .SM
  .B PS1
  before reading a command.
+ If the user is super-user and
+ .SM
+ .B PS1
+ is not set to
+ .RB `` "# \|" ''
+ already, the
+ .SM
+ .B PS1
+ prompt is followed by
+ .RB `` "# \|" ''
+ as a BRL-supplied safety reminder.
  If at any time a new-line is typed and further input is needed
  to complete a command, the secondary prompt
  (i.e., the value of
***************
*** 676,681
  (i.e., the value of
  .BR \s-1PS2\s+1 )
  is issued.
  .SS Input/Output
  Before a command is executed, its input and output
  may be redirected using a special notation interpreted by the shell.

--- 934,996 -----
  (i.e., the value of
  .BR \s-1PS2\s+1 )
  is issued.
+ .PP
+ Many people like to have the shell provide them with useful information
+ in their prompt.  To accomadate this, the shell will recognize special
+ sequences of characters in the value of
+ .BR PS1 ,
+ and substitute the appropriate information for them.
+ The special sequences and what they signify are:
+ .RS
+ .TP
+ .B %d
+ Place the current working directory into the prompt.
+ .TP
+ .B %e
+ Place the current event number (as defined by the
+ .B history
+ command) into the prompt.
+ If history evaluation has been turned off (via
+ .BR "set -H" ),
+ no number will be substituted in (i.e. the
+ .B %e
+ will be removed).
+ .TP
+ .B %h
+ Place the machine's host name into the prompt.  The host name is usually
+ the name by which the machine is known to the outside world for electronic
+ mail addressing.
+ .TP
+ .B %l
+ Place the user's login name into the prompt.
+ The login name selected is the first entry in the
+ .B /etc/passwd
+ file whose
+ .I uid
+ matches the value of the
+ .IR getuid (2)
+ system call.
+ This will be a problem on systems where multiple users share the same
+ user-id number.
+ .TP
+ .B %t
+ Place the current time of day, in the form \s-1HH:MM\s+1 into the prompt.
+ The time is on a 24 hour clock, i.e. 1:30 in the afternoon will be 13:30.
+ .TP
+ .BI % x
+ Place the character
+ .I x
+ into the prompt.
+ If the user wishes to put a literal
+ .B %
+ into the prompt, then
+ .B PS1
+ should have
+ .B %%
+ in it.
+ .RE
+ .PP
+ Some of these facilities are of more use than others.
  .SS Input/Output
  Before a command is executed, its input and output
  may be redirected using a special notation interpreted by the shell.
***************
*** 741,746
  all leading tabs are stripped from
  .I word\^
  and from the document.
  .TP
  .B <\h@-.1m@&digit
  Use the file associated with file descriptor

--- 1056,1063 -----
  all leading tabs are stripped from
  .I word\^
  and from the document.
+ History substitution is turned off
+ while processing the document.
  .TP
  .B <\h@-.1m@&digit
  Use the file associated with file descriptor
***************
*** 753,758
  The standard input is closed.
  Similarly for the standard output using
  .BR >\h@-.1m@&\h@-.1m@\- .
  .PD
  .PP
  If any of the above is preceded by a digit,

--- 1070,1083 -----
  The standard input is closed.
  Similarly for the standard output using
  .BR >\h@-.1m@&\h@-.1m@\- .
+ .TP
+ .B <\&>\&word
+ Use file
+ .I word
+ for standard input (file descriptor 0),
+ but open it for reading
+ .I and
+ writing.
  .PD
  .PP
  If any of the above is preceded by a digit,
***************
*** 824,830
  .BR "set -a" ).
  A parameter may be removed from the environment
  with the 
! .BR unset command.
  The environment seen by any executed command is thus composed
  of any unmodified name-value pairs originally inherited by the shell,
  minus any pairs removed by

--- 1149,1156 -----
  .BR "set -a" ).
  A parameter may be removed from the environment
  with the 
! .BR unset
! command.
  The environment seen by any executed command is thus composed
  of any unmodified name-value pairs originally inherited by the shell,
  minus any pairs removed by
***************
*** 859,865
  The following
  first prints
  .B "a=b c"
! and
  .BR c :
  .PP
  .RS

--- 1185,1191 -----
  The following
  first prints
  .B "a=b c"
! and then
  .BR c :
  .PP
  .RS
***************
*** 880,885
  the
  .B trap
  command below).
  .SS Execution
  Each time a command is executed, the above substitutions are
  carried out.

--- 1206,1214 -----
  the
  .B trap
  command below).
+ When job control is enabled,
+ \s-1SIGTSTP\s0
+ causes a foreground command to be stopped.
  .SS Execution
  Each time a command is executed, the above substitutions are
  carried out.
***************
*** 945,951
  .B 
  .SM PATH
  variable is changed or the
! .B hash -r
  command is executed (see below).
  .SS Special Commands
  Input/output redirection is now permitted for these commands.

--- 1274,1280 -----
  .B 
  .SM PATH
  variable is changed or the
! .B hash \-r
  command is executed (see below).
  .SS Special Commands
  Input/output redirection is now permitted for these commands.
***************
*** 1028,1034
  .br
  .ne 2.1v
  .TP
! \f3echo\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  Echo arguments. See
  .IR echo (1) 
  for usage and description.

--- 1357,1363 -----
  .br
  .ne 2.1v
  .TP
! \f3echo\fP \*(OK \f3\-n\fP \*(CK \*(OK \f2arg\^\fP .\|.\|. \*(CK
  Echo arguments. See
  .IR echo (1) 
  for usage and description.
***************
*** 1032,1037
  Echo arguments. See
  .IR echo (1) 
  for usage and description.
  .TP
  \f3eval\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  The arguments are read as input

--- 1361,1375 -----
  Echo arguments. See
  .IR echo (1) 
  for usage and description.
+ The semantics of
+ .BR echo ,
+ except for the BRL addition of the old-fashioned
+ .B \-n
+ ``no newline'' option,
+ are those of the UNIX System V command;
+ in particular,
+ .B \e
+ escape sequences are processed.
  .TP
  \f3eval\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  The arguments are read as input
***************
*** 1088,1093
  adjacent to the \f2hits\fR information.
  \f2Cost\fR will be incremented when the recalculation is done.
  .TP
  \f3newgrp\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  Equivalent to
  .BI "exec newgrp" " arg\^"

--- 1426,1474 -----
  adjacent to the \f2hits\fR information.
  \f2Cost\fR will be incremented when the recalculation is done.
  .TP
+ \fBhistory\fP \*(OK \fB\-irs\fP \*(OK \fIfilename\fP \*(CK \*(CK
+ The \fBhistory\fP command, with no arguments, will print all the commands that
+ are currently saved in the shell's history buffers.  As new commands are
+ executed, and space in the buffers runs out, old commands will be deleted.  The
+ .B history
+ commands prints out the stored commands with sequence numbers.  Negative
+ numbered commands, through command number zero, are commands that were
+ retrieved from the saved history file.  Commands starting at one were
+ entered during the current login session.
+ If a saved command contains embedded newlines, these will be printed out
+ as the sequence
+ .BR \en ,
+ so that individual command stay on one line.
+ .sp
+ The \fBhistory\fP command takes two optional arguments.  If the first
+ argument is \fB\-s\fP, the shell will save its current history buffers
+ in the file named as the third argument. If no file is given, it will
+ use the value of
+ .BR \s-1HISTFILE\s+1 .
+ .sp
+ Similarly, if the first argument is \fB\-r\fP, the shell will reset its
+ history buffers from the saved history in the file given as the third argument.
+ Again, if no file name is given,
+ .B \s-1$HISTFILE\s+1
+ will be used.
+ .sp
+ The command
+ .B history -i
+ will cause the shell to reinitialize its history buffers.  In other words,
+ all the shell's saved history will be thrown away, and the shell will
+ start from scratch.
+ .sp
+ The \fBhistory\fP command will have absolutely no effect at all if input
+ is not coming from a terminal.  I.e., inside shell files, the
+ .B history
+ command is effectively a null operation.
+ .sp
+ The
+ .B history
+ command will always have an exit status of 1 inside a shell file.
+ If input is coming from a terminal, then the exit status wil be 0
+ if the command succeeds, 1 otherwise.
+ .TP
  \f3newgrp\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  Equivalent to
  .BI "exec newgrp" " arg\^"
***************
*** 1135,1141
  If
  .I n 
  is omitted, the return status is that of the last command executed.
! .bp
  .TP
  \f3set\fP \*(OK \f3\-\-aefhkntuvx\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK \*(CK
  .RS

--- 1516,1522 -----
  If
  .I n 
  is omitted, the return status is that of the last command executed.
! .\" .bp
  .TP
  \f3set\fP \*(OK \f3\-\-aefhkntuvxEHIJ\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK \*(CK
  .RS
***************
*** 1137,1143
  is omitted, the return status is that of the last command executed.
  .bp
  .TP
! \f3set\fP \*(OK \f3\-\-aefhkntuvx\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK \*(CK
  .RS
  .TP
  .B \-a

--- 1518,1524 -----
  is omitted, the return status is that of the last command executed.
  .\" .bp
  .TP
! \f3set\fP \*(OK \f3\-\-aefhkntuvxEHIJ\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK \*(CK
  .RS
  .TP
  .B \-a
***************
*** 1173,1178
  .B \-x
  Print commands and their arguments as they are executed.
  .TP
  .B \-\-
  Do not change any of the flags; useful in setting
  .B $1

--- 1554,1595 -----
  .B \-x
  Print commands and their arguments as they are executed.
  .TP
+ .B \-E
+ Prevents an EOT
+ .RI ( control-D\^ )
+ from terminating an interactive shell.
+ Added by BRL mostly for use in
+ .IR .profile\^ s
+ to avoid accidental logout.
+ .TP
+ .B \-H
+ Disable history processing.  If the shell is invoked with this option,
+ it will not bother trying to restore its saved history from the
+ contents of
+ .BR \s-1$HISTFILE\s+1 .
+ While this flag is in effect, the shell will not save any commands in
+ its history buffers.
+ The sequence
+ .B %e
+ in the value of
+ .B \s-1PS1\s+1
+ will also have no effect on the generated prompt string.
+ If
+ .B set +H
+ is used to turn history processing back on, the shell will start saving
+ subsequent commands from that point on.
+ .TP
+ .B \-I
+ (BRL addition)
+ Prints a resource usage summary
+ on 4.2BSD
+ (system plus user time, blocks input and output, page reclaims and faults)
+ for each command after it terminates.
+ .TP
+ .B \-J
+ (BRL addition)
+ Enables ``job control'' features (see below).
+ .TP
  .B \-\-
  Do not change any of the flags; useful in setting
  .B $1
***************
*** 1292,1298
  If
  .I nnn\^
  is omitted, the current value of the mask is printed.
! .bp
  .TP
  \f3unset\fP \*(OK \f2name\^\fP .\|.\|. \*(CK
  For each 

--- 1709,1715 -----
  If
  .I nnn\^
  is omitted, the current value of the mask is printed.
! .\" .bp
  .TP
  \f3unset\fP \*(OK \f2name\^\fP .\|.\|. \*(CK
  For each 
***************
*** 1321,1326
  and from
  .BR \s-1$HOME\s+1/.profile ,
  if such files exist.
  Thereafter, commands are read as described below, which
  is also the case when the shell is invoked as
  .BR /bin/sh .

--- 1738,1755 -----
  and from
  .BR \s-1$HOME\s+1/.profile ,
  if such files exist.
+ Next, whether or not the first character of argument zero was a
+ .BR \- ,
+ and no matter how the shell was invoked,
+ the shell will read commands from the file
+ .BR \s-1$HOME\s+1/.shrc ,
+ if it exists.
+ The, if the shell is interactive, is not a forked subshell,
+ and the
+ .B \-H
+ flag is not in effect,
+ it will attempt restore its saved history from
+ .BR \s-1$HISTFILE\s+1 .
  Thereafter, commands are read as described below, which
  is also the case when the shell is invoked as
  .BR /bin/sh .
***************
*** 1324,1329
  Thereafter, commands are read as described below, which
  is also the case when the shell is invoked as
  .BR /bin/sh .
  The flags below are interpreted by the shell on invocation only; Note
  that unless the 
  .B \-c

--- 1753,1763 -----
  Thereafter, commands are read as described below, which
  is also the case when the shell is invoked as
  .BR /bin/sh .
+ If any character of argument zero past the last slash (if any) is
+ .BR j ,
+ the
+ .B \-J
+ (job control) flag is automatically set.
  The flags below are interpreted by the shell on invocation only; Note
  that unless the 
  .B \-c
***************
*** 1372,1377
  If the
  .B \-r
  flag is present the shell is a restricted shell.
  .PD
  .PP
  The remaining flags and arguments are described under the

--- 1806,1822 -----
  If the
  .B \-r
  flag is present the shell is a restricted shell.
+ .TP
+ .B \-q
+ If the
+ .B \-q
+ flag is present, the shell will do a ``quick'' startup.
+ This means that the shell will
+ .I not
+ read the contents of the
+ .B \s-1$HOME\s+1/.shrc
+ file.
+ The shell will also not try to read this file if it is a restricted shell.
  .PD
  .PP
  The remaining flags and arguments are described under the
***************
*** 1439,1445
  .IR rsh .
  Some systems also provide a restricted editor
  .IR red .
! .bp
  .SH EXIT STATUS
  Errors detected by the shell, such as syntax errors,
  cause the shell

--- 1884,1973 -----
  .IR rsh .
  Some systems also provide a restricted editor
  .IR red .
! .\" .bp
! .SS Job Control
! Job control features are enabled by the
! .B \-J
! flag.
! When job control is enabled,
! background commands and foreground commands that have been stopped
! (usually by a \s-1SIGTSTP\s0 signal generated by typing
! .IR ^Z\^ )
! are placed into separate individual
! .IR "process groups"\^ .
! The following commands are used to manipulate these process groups:
! .PP
! .PD 0
! .TP
! \f3jobs\fP
! Display information about the controlled jobs.
! The job number is given in brackets,
! followed by a plus sign if it is the ``current job'',
! then the process group number for the job,
! then the command.
! .TP
! \f3fg\fP \*(OK \f2n\^\fP \*(CK
! Resume the stopped foreground job in the foreground.
! If the process group
! .I n\^
! is not specified then the ``current job'' is resumed.
! .TP
! \f3bg\fP \*(OK \f2n\^\fP \*(CK
! Resume the stopped foreground job in the background.
! If the process group
! .I n\^
! is not specified then the ``current job'' is resumed.
! .TP
! .B suspend
! Suspend the shell process itself in the background.
! The shell will complain
! if it is a login shell, and will not suspend itself.
! Otherwise, it does not matter whether or not job control is enabled.
! .PD
! .PP
! With job control enabled,
! there are the following additional substitutable parameters:
! .PP
! .PD 0
! .TP
! .BR %%
! If there is a ``current job'',
! then this expression is replaced by
! its process group number.
! .TP
! .BI % n\^
! If the specified job number is one of the known jobs,
! then this expression is replaced by
! the corresponding process group number.
! .SS Saving and Restoring History
! When an interactive shell starts up, if the
! .B \-H
! flag is not in effect, it will attempt to read the contents of
! .B \s-1$HISTFILE\s+1
! into its history buffers.  This allows the user to recall commands
! executed during a previous login session.
! When the shell exits or executes an
! .B exec
! (again, if
! .B \-H
! is not in effect), it will attempt to write its current history
! buffers into
! .BR \s-1$HISTFILE\s+1 ,
! for use in a future login session.
! .PP
! The
! .B history
! command allows the user to save the current history buffers into
! a file of his or her own choosing, or to restore them from a given file.
! If
! .B \-H
! has been set, the
! .B history
! command will give a warning that history processing is not
! available, and will
! .I not
! save or restore the shell's history buffers.
! .PD
  .SH EXIT STATUS
  Errors detected by the shell, such as syntax errors,
  cause the shell
***************
*** 1455,1460
  .br
  \s-1$HOME\s+1/\f3.\fPprofile
  .br
  /tmp/sh\(**
  .br
  /dev/null

--- 1983,1990 -----
  .br
  \s-1$HOME\s+1/\f3.\fPprofile
  .br
+ \s-1$HOME\s+1/\f3.\fPshrc
+ .br
  /tmp/sh\(**
  .br
  /dev/null
***************
*** 1462,1467
  acctcom(1),
  cd(1),
  echo(1),
  env(1),
  login(1),
  newgrp(1),

--- 1992,1998 -----
  acctcom(1),
  cd(1),
  echo(1),
+ ed(1),
  env(1),
  login(1),
  newgrp(1),
***************
*** 1475,1480
  dup(2),
  exec(2),
  fork(2),
  pipe(2),
  signal(2),
  ulimit(2),

--- 2006,2013 -----
  dup(2),
  exec(2),
  fork(2),
+ getppid(2),
+ getuid(2),
  pipe(2),
  signal(2),
  ulimit(2),
***************
*** 1502,1504
  .B cd\^
  command with a full path name
  to correct this situation.

--- 2035,2151 -----
  .B cd\^
  command with a full path name
  to correct this situation.
+ .SH PYRAMID SPECIFIC
+ .PP
+ On computers manufactured by the Pyramid Corporation, which support
+ both the University of California at Berkeley 4.2BSD version of \s-1UNIX\s+1,
+ and the AT&T System V version of \s-1UNIX\s+1,
+ the shell has several additional capabilities.
+ .SS Special Commands
+ .PP
+ There are three additional commands built in to the shell. They are:
+ .RS
+ .TP
+ \fBatt\fP \*(OK command \*(CK
+ Switch the current ``universe'' to be ATT System V.
+ If a command is specified, that command will be run in the ``att''
+ universe, without affecting the shell's current universe.
+ The
+ .B \-t
+ option of
+ .B /bin/att
+ is not (yet) supported.
+ .TP
+ \fBucb\fP \*(OK command \*(CK
+ Switch the current ``universe'' to be University of California at
+ Berkeley 4.2BSD.
+ If a command is specified, that command will be run in the ``ucb''
+ universe, without affecting the shell's current universe.
+ The
+ .B \-t
+ option of
+ .B /bin/ucb
+ is not (yet) supported.
+ .TP
+ \fBuniverse\fP \*(OK \fB\-l\fP \*(CK
+ Print the current universe, either ``att'' or ``ucb''. The
+ .B \-l
+ option will print a longer, more explanative name for the current universe.
+ .RE
+ .PP
+ If the shell cannot determine the current universe when it starts up,
+ it will default to
+ .BR ucb .
+ .SS Shell Variables
+ .PP
+ There is an additional pre-defined shell parameter,
+ .BR \s-1UNIVERSE\s+1 .
+ The value of
+ .B \s-1UNIVERSE\s+1
+ .I always
+ tracks that of the current universe.  Using it is equivalent to a
+ \*`universe\` command substitution,
+ except that a new process will not be created.
+ This variable cannot be set by the user (it is \fBreadonly\fP),
+ and any inherited value from the environment will be ignored.
+ .SS Special Sequences for \s-1PS1\s+1
+ .PP
+ Finally, the sequence
+ .B %u
+ in the value of
+ .B \s-1PS1\s-1
+ will cause the shell to subsitute in the name of the current universe,
+ either ``att'' or ``ucb''.
+ .SH HISTORY EXAMPLES
+ Command history provides a powerful method for easily redoing previous
+ commands, or for quicly fixing typing mistakes.
+ Here are some annotated examples.  User input is in
+ .BR boldface .
+ .sp
+ .nf
+ # first, list some files
+ .RB "$ " lf
+ hello.c		echo.c
+ # now, make a typing mistake
+ .RB "$ " "cat hello"
+ hello: No such file or directory
+ # fix it.  The trailing ! ends the history substitution,
+ # in order to correctly concatenate it with the following .c
+ .RB "$ " "!!.c"
+ cat hello.c
+ main () { printf ("hello world\en"); }
+ # now look at echo.c instead
+ .RB "$ " "!^hello^echo"
+ cat echo.c
+ main () { printf ("echo: no arguments\en"); }
+ # do it again, just for fun
+ .RB "$ " "!"
+ cat echo.c
+ main () { printf ("echo: no arguments\en"); }
+ # now we'll rearrange some arguments
+ .RB "$ " "echo 1 2 3 4 5"
+ 1 2 3 4 5
+ # print last argument, first and second arguments, then change 4 to four
+ .RB "$ " "echo !\(ga$ !\(ga1-2 !\(ga4^4^four"
+ echo 5 1 2 four
+ 5 1 2 four
+ # do something with all the previous arguments at once
+ .RB "$ " "echo the previous arguments were !\(ga\-"
+ echo the previous arguments were 5 1 2 four
+ the previous arguments were 5 1 2 four
+ # now do some substitutions.  first get something to work with.
+ .RB "$ " "echo aa bb cc"
+ aa bb cc
+ # change the first 'a' to a 'b', and change all c's to d's
+ .RB "$ " "!^a^b^^c^d^g"
+ echo ba bb dd
+ ba bb dd
+ .fi
+ .PP
+ These few brief examples should provide a general feel for the
+ history mechanism.  The quickest way to learn it is to experiment
+ with it for a while, using the
+ .B echo
+ command, which can do very little damage.
+ While it looks cryptic when being typed, it is very general and
+ orthogonal, and quickly becomes natural.

sources-request@genrad.UUCP (06/12/85)

From: Arnold Robbins <gatech!arnold>

This is part 8 of 9.  It contains the code diffs for the System V Release 2
Bourne shell that comes with BRL Unix (/usr/5bin/sh).

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
--------------- You know what to do here -----------------------
:::::::: :fix :::::::
No differences encountered
:::::::: Makefile :::::::
*** ../orig.u/Makefile	Wed May 15 17:11:54 1985
--- Makefile	Fri Jun  7 11:46:36 1985
***************
*** 3,9
  TESTDIR	= .
  INS	= cp
  INSDIR	= /usr/5bin
! DEFS	= -DNICE -DNICEVAL=4 -DBRL -DJOBS	# for BSD, add -DBSD	# -DACCT
  CFLAGS	= $(DEFS) -O
  ACCTINC	=					# -I/usr/src/cmd/acct
  LDFLAGS	= -s -n

--- 3,9 -----
  TESTDIR	= .
  INS	= cp
  INSDIR	= /usr/5bin
! DEFS	= -DNICE -DNICEVAL=4 -DBRL -DJOBS -DBSD # for BSD, add -DBSD	# -DACCT
  CFLAGS	= $(DEFS) -O
  ACCTINC	=					# -I/usr/src/cmd/acct
  LDFLAGS	= -s -n
***************
*** 12,18
  OFILES	= setbrk.o blok.o stak.o cmd.o fault.o main.o word.o string.o\
  	  name.o args.o xec.o service.o error.o io.o print.o macro.o expand.o\
  	  ctype.o msg.o test.o defs.o hash.o hashserv.o pwd.o func.o\
! 	  echo.o jobs.o	# for BSD, remove echo.o and add signal.o and ulimit.o
  
  CFILES	= setbrk.c blok.c stak.c cmd.c fault.c main.c word.c string.c\
  	  name.c args.c xec.c service.c error.c io.c print.c macro.c expand.c\

--- 12,19 -----
  OFILES	= setbrk.o blok.o stak.o cmd.o fault.o main.o word.o string.o\
  	  name.o args.o xec.o service.o error.o io.o print.o macro.o expand.o\
  	  ctype.o msg.o test.o defs.o hash.o hashserv.o pwd.o func.o\
! 	  history.o homedir.o \
! 	  echo.o jobs.o	signal.o ulimit.o # for BSD, add signal.o and ulimit.o
  
  CFILES	= setbrk.c blok.c stak.c cmd.c fault.c main.c word.c string.c\
  	  name.c args.c xec.c service.c error.c io.c print.c macro.c expand.c\
***************
*** 17,23
  CFILES	= setbrk.c blok.c stak.c cmd.c fault.c main.c word.c string.c\
  	  name.c args.c xec.c service.c error.c io.c print.c macro.c expand.c\
  	  ctype.c msg.c test.c defs.c hash.c hashserv.c pwd.c func.c\
! 	  echo.c jobs.c	# for BSD, remove echo.c and add signal.c and ulimit.c
  
  all:		sh
  

--- 18,25 -----
  CFILES	= setbrk.c blok.c stak.c cmd.c fault.c main.c word.c string.c\
  	  name.c args.c xec.c service.c error.c io.c print.c macro.c expand.c\
  	  ctype.c msg.c test.c defs.c hash.c hashserv.c pwd.c func.c\
! 	  history.c homedir.c \
! 	  echo.c jobs.c signal.c ulimit.c # for BSD, add signal.c and ulimit.c
  
  all:		sh
  
***************
*** 37,46
  main.o:		timeout.h
  
  ctype.o:
! 	if gould; \
! 	then	$(CC) $(CFLAGS) -R -c ctype.c; \
! 	else	sh ./:fix ctype; \
! 	fi
  
  msg.o:
  	if gould; \

--- 39,49 -----
  main.o:		timeout.h
  
  ctype.o:
! 	$(CC) $(CFLAGS) -S ctype.c
! 	sed '/^[ 	]*\.data/s/text/data/' < ctype.s > x.s
! 	$(CC) -c x.s
! 	mv x.o ctype.o
! 	rm x.s ctype.s
  
  msg.o:
  	$(CC) $(CFLAGS) -S msg.c
***************
*** 43,52
  	fi
  
  msg.o:
! 	if gould; \
! 	then	$(CC) $(CFLAGS) -R -c msg.c; \
! 	else	sh ./:fix msg; \
! 	fi
  
  service.o:
  	$(CC) $(CFLAGS) $(ACCTINC) -c service.c

--- 46,56 -----
  	rm x.s ctype.s
  
  msg.o:
! 	$(CC) $(CFLAGS) -S msg.c
! 	sed '/^[ 	]*\.data/s/text/data/' < msg.s > x.s
! 	$(CC) -c x.s
! 	mv x.o msg.o
! 	rm x.s msg.s
  
  service.o:
  	$(CC) $(CFLAGS) $(ACCTINC) -c service.c
:::::::: Makefile.gould :::::::
No differences encountered
:::::::: SH_NOTES :::::::
No differences encountered
:::::::: args.c :::::::
*** ../orig.u/args.c	Wed May 15 17:11:55 1985
--- args.c	Wed Jun  5 14:48:23 1985
***************
*** 15,21
  
  #if BRL
  #if JOBS
! char	flagadr[17];
  #else
  char	flagadr[16];
  #endif

--- 15,21 -----
  
  #if BRL
  #if JOBS
! char	flagadr[19];
  #else
  char	flagadr[18];
  #endif
***************
*** 17,23
  #if JOBS
  char	flagadr[17];
  #else
! char	flagadr[16];
  #endif
  #else	/* !BRL */
  #if JOBS

--- 17,23 -----
  #if JOBS
  char	flagadr[19];
  #else
! char	flagadr[18];
  #endif
  #else	/* !BRL */
  #if JOBS
***************
*** 21,27
  #endif
  #else	/* !BRL */
  #if JOBS
! char	flagadr[15];
  #else
  char	flagadr[14];
  #endif

--- 21,27 -----
  #endif
  #else	/* !BRL */
  #if JOBS
! char	flagadr[17];
  #else
  char	flagadr[16];
  #endif
***************
*** 23,29
  #if JOBS
  char	flagadr[15];
  #else
! char	flagadr[14];
  #endif
  #endif
  

--- 23,29 -----
  #if JOBS
  char	flagadr[17];
  #else
! char	flagadr[16];
  #endif
  #endif
  
***************
*** 49,54
  #if JOBS
  	'J',
  #endif
  	 0
  };
  

--- 49,56 -----
  #if JOBS
  	'J',
  #endif
+ 	'q',		/* ADR -- -q to not read ~/.shrc */
+ 	'H',		/* ADR -- -H turn off history mechanism */
  	 0
  };
  
***************
*** 74,79
  #if JOBS
  	jobflg,
  #endif
  	  0
  };
  

--- 76,83 -----
  #if JOBS
  	jobflg,
  #endif
+ 	quickflg,
+ 	nohistflg,
  	  0
  };
  
***************
*** 109,115
  
  		/*
  		 * Step along 'flagchar[]' looking for matches.
! 		 * 'sicr' are not legal with 'set' command.
  		 */
  
  		while (*++cp)

--- 113,119 -----
  
  		/*
  		 * Step along 'flagchar[]' looking for matches.
! 		 * 'sicrq' are not legal with 'set' command.
  		 */
  
  		while (*++cp)
***************
*** 119,125
  				flagc++;
  			if (*cp == *flagc)
  			{
! 				if (eq(argv[0], setstr) && any(*cp, sicrstr))	/* DAG -- made strings sharable */
  					failed(argv[1], badopt);
  				else
  				{

--- 123,129 -----
  				flagc++;
  			if (*cp == *flagc)
  			{
! 				if (eq(argv[0], setstr) && any(*cp, sicrqstr))	/* DAG -- made strings sharable */
  					failed(argv[1], badopt);
  				else
  				{
***************
*** 147,152
  	}
  	else if (argc > 1 && *argp[1] == '+')	/* unset flags x, k, t, n, v, e, u */
  						/* or any added BRL/JOBS flags */
  	{
  		cp = argp[1];
  		while (*++cp)

--- 151,157 -----
  	}
  	else if (argc > 1 && *argp[1] == '+')	/* unset flags x, k, t, n, v, e, u */
  						/* or any added BRL/JOBS flags */
+ 						/* or history flag */
  	{
  		cp = argp[1];
  		while (*++cp)
***************
*** 157,163
  			/*
  			 * step through flags
  			 */
! 			if (!any(*cp, sicrstr) && *cp == *flagc)	/* DAG -- made string sharable */
  			{
  				/*
  				 * only turn off if already on

--- 162,168 -----
  			/*
  			 * step through flags
  			 */
! 			if (!any(*cp, sicrqstr) && *cp == *flagc)	/* DAG -- made string sharable */
  			{
  				/*
  				 * only turn off if already on
:::::::: blok.c :::::::
No differences encountered
:::::::: brkincr.h :::::::
No differences encountered
:::::::: cmd.c :::::::
No differences encountered
:::::::: ctype.c :::::::
No differences encountered
:::::::: ctype.h :::::::
*** ../orig.u/ctype.h	Wed May 15 17:11:55 1985
--- ctype.h	Thu Apr 25 11:44:38 1985
***************
*** 80,86
  extern char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DIG))
! #define dolchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN))
  #define defchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DEF))
  #define setchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_SET))
  #define digchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_DIG))

--- 80,86 -----
  extern char	_ctype2[];
  
  #define	digit(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DIG))
! #define dolchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS))
  #define defchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_DEF))
  #define setchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_SET))
  #define digchar(c)	(((c)&QUOTE)==0 && _ctype2[c]&(T_AST|T_DIG))
:::::::: defs.c :::::::
*** ../orig.u/defs.c	Wed May 15 17:11:56 1985
--- defs.c	Thu May  9 10:57:13 1985
***************
*** 17,22
  struct ionod	*iopend;	/* documents waiting to be read at NL */
  struct fdsave	fdmap[NOFILE];
  
  /* substitution */
  int				dolc;
  char			**dolv;

--- 17,34 -----
  struct ionod	*iopend;	/* documents waiting to be read at NL */
  struct fdsave	fdmap[NOFILE];
  
+ /* history stuff */
+ int	event_count = 1;
+ int	expanded = 0;	/* did a history expansion occur? */
+ 
+ /* keep track of the parent pid */
+ int	ppid;
+ 
+ #if pyr
+ /* keep track of the current universe */
+ int	cur_univ;
+ #endif
+ 
  /* substitution */
  int				dolc;
  char			**dolv;
***************
*** 36,41
  /* special names */
  char			*pcsadr;
  char			*pidadr;
  char			*cmdadr;
  
  /* transput */ 

--- 48,54 -----
  /* special names */
  char			*pcsadr;
  char			*pidadr;
+ char			*ppidadr;
  char			*cmdadr;
  
  /* transput */ 
:::::::: defs.h :::::::
*** ../orig.u/defs.h	Wed May 15 17:11:56 1985
--- defs.h	Wed Jun  5 15:19:40 1985
***************
*** 3,9
   *	UNIX shell
   */
  
! #if BSD || gould
  #define	void	int	/* avoid compiler bug */
  #endif
  

--- 3,9 -----
   *	UNIX shell
   */
  
! #if BSD || gould || pyr
  #define	void	int	/* avoid compiler bug */
  #endif
  
***************
*** 87,92
  #define		SYSJOBS		29
  #define		SYSFG		30
  #define		SYSBG		31
  #endif
  
  /* used for input and output of shell */

--- 87,93 -----
  #define		SYSJOBS		29
  #define		SYSFG		30
  #define		SYSBG		31
+ #define		SYSSUSPEND	32
  #endif
  
  #if pyr
***************
*** 89,94
  #define		SYSBG		31
  #endif
  
  /* used for input and output of shell */
  #define 	INIO 		19
  

--- 90,105 -----
  #define		SYSSUSPEND	32
  #endif
  
+ #if pyr
+ #define		SYSATT		33
+ #define		SYSUCB		34
+ #define		SYSUNIVERSE	35
+ #define		U_ATT		1	/* ATT is Universe number 1 */
+ #define		U_UCB		2	/* UCB is Universe number 2 */
+ #endif
+ 
+ #define		SYSHISTORY	36
+ 
  /* used for input and output of shell */
  #define 	INIO 		19
  
***************
*** 111,117
  #include	"mode.h"
  #include	"name.h"
  #include	<signal.h>
! #if BSD
  #define	SIGUSR1	16
  #define	SIGUSR2	17
  #endif

--- 122,128 -----
  #include	"mode.h"
  #include	"name.h"
  #include	<signal.h>
! #if BSD && ! defined(pyr)	/* avoid dual universe problems */
  #define	SIGUSR1	16
  #define	SIGUSR2	17
  #endif
***************
*** 115,121
  #define	SIGUSR1	16
  #define	SIGUSR2	17
  #endif
! #if defined(JOBS) && !defined(BSD)
  #define	SIGSTOP	17
  #define	SIGTSTP	18
  #define	SIGCONT	19

--- 126,132 -----
  #define	SIGUSR1	16
  #define	SIGUSR2	17
  #endif
! #if defined(JOBS) && !defined(BSD) && !defined(pyr)
  #define	SIGSTOP	17
  #define	SIGTSTP	18
  #define	SIGCONT	19
***************
*** 123,128
  #define	SIGTTOU	22
  #endif
  
  
  /*	error catching */
  extern int 		errno;

--- 134,140 -----
  #define	SIGTTOU	22
  #endif
  
+ #define HISTSIZE	4096
  
  /*	error catching */
  extern int 		errno;
***************
*** 148,153
  extern char				*mactrim();
  extern char				*macro();
  extern char				*execs();
  /* extern char				*copyto();	/* DAG -- (bug fix) static */
  extern int				exname();
  extern char				*staknam();

--- 160,168 -----
  extern char				*mactrim();
  extern char				*macro();
  extern char				*execs();
+ extern char				*homedir();
+ extern char				*username();
+ extern char				*retcwd();
  /* extern char				*copyto();	/* DAG -- (bug fix) static */
  extern int				exname();
  extern char				*staknam();
***************
*** 168,173
  extern BOOL				j_finish();
  extern char				*j_macro();
  #endif
  
  #define 	attrib(n,f)		(n->namflg |= f)
  #define 	round(a,b)		(((int)(((char *)(a)+b)-1))&~((b)-1))

--- 183,189 -----
  extern BOOL				j_finish();
  extern char				*j_macro();
  #endif
+ extern int				history();
  
  #define 	attrib(n,f)		(n->namflg |= f)
  #define 	round(a,b)		(((int)(((char *)(a)+b)-1))&~((b)-1))
***************
*** 184,189
  extern struct ionod		*iopend;	/* documents waiting to be read at NL */
  extern struct fdsave	fdmap[];
  
  
  /* substitution */
  extern int				dolc;

--- 200,208 -----
  extern struct ionod		*iopend;	/* documents waiting to be read at NL */
  extern struct fdsave	fdmap[];
  
+ /* history stuff */
+ extern int	event_count;
+ extern int	expanded;	/* did a history expansion occur? */
  
  /* keep track of the parent pid */
  extern int	ppid;
***************
*** 185,190
  extern struct fdsave	fdmap[];
  
  
  /* substitution */
  extern int				dolc;
  extern char				**dolv;

--- 204,219 -----
  extern int	event_count;
  extern int	expanded;	/* did a history expansion occur? */
  
+ /* keep track of the parent pid */
+ extern int	ppid;
+ 
+ #if pyr
+ /* keep track of the current universe */
+ extern int	cur_univ;
+ extern char	*univ_name[];		/* from <universe.h> */
+ extern char	*univ_longname[];
+ #endif
+ 
  /* substitution */
  extern int				dolc;
  extern char				**dolv;
***************
*** 205,211
  extern char				endoffile[];
  extern char				synmsg[];
  extern char				setstr[]; 	/* DAG -- made sharable */
! extern char				sicrstr[];	/* DAG */
  extern char				bang[];		/* DAG */
  extern char				pdstr[];	/* DAG */
  extern char				dotdot[];	/* DAG */

--- 234,240 -----
  extern char				endoffile[];
  extern char				synmsg[];
  extern char				setstr[]; 	/* DAG -- made sharable */
! extern char				sicrqstr[];	/* ADR */
  extern char				bang[];		/* DAG */
  extern char				pdstr[];	/* DAG */
  extern char				dotdot[];	/* DAG */
***************
*** 228,233
  extern char				dashd[];	/* DAG */
  extern char				dashf[];	/* DAG */
  extern char				dashg[];	/* DAG */
  extern char				dashk[];	/* DAG */
  extern char				dashn[];	/* DAG */
  extern char				dasho[];	/* DAG */

--- 257,263 -----
  extern char				dashd[];	/* DAG */
  extern char				dashf[];	/* DAG */
  extern char				dashg[];	/* DAG */
+ extern char				dashi[];	/* ADR */
  extern char				dashk[];	/* DAG */
  #if pyr
  extern char				dashl[];	/* ADR */
***************
*** 229,234
  extern char				dashf[];	/* DAG */
  extern char				dashg[];	/* DAG */
  extern char				dashk[];	/* DAG */
  extern char				dashn[];	/* DAG */
  extern char				dasho[];	/* DAG */
  extern char				dashp[];	/* DAG */

--- 259,267 -----
  extern char				dashg[];	/* DAG */
  extern char				dashi[];	/* ADR */
  extern char				dashk[];	/* DAG */
+ #if pyr
+ extern char				dashl[];	/* ADR */
+ #endif
  extern char				dashn[];	/* DAG */
  extern char				dasho[];	/* DAG */
  extern char				dashp[];	/* DAG */
***************
*** 274,279
  extern char				ishashed[];	/* DAG */
  extern char				rpnlstr[];	/* DAG */
  extern char				isstr[];	/* DAG */
  #if JOBS
  extern char				rsqbrk[];
  extern char				spspstr[];

--- 307,313 -----
  extern char				ishashed[];	/* DAG */
  extern char				rpnlstr[];	/* DAG */
  extern char				isstr[];	/* DAG */
+ extern char				rdwstr[];	/* ADR */
  #if JOBS
  extern char				rsqbrk[];
  extern char				spspstr[];
***************
*** 300,305
  extern char				selsstr[];
  extern char				sfistr[];
  extern char				iesacstr[];
  #endif
  #if SYMLINK
  extern char				nolstat[];

--- 334,340 -----
  extern char				selsstr[];
  extern char				sfistr[];
  extern char				iesacstr[];
+ extern char				nosusp[];
  #endif
  #if SYMLINK
  extern char				nolstat[];
***************
*** 339,344
  extern char				supprompt[];
  extern char				profile[];
  extern char				sysprofile[];
  
  /* built in names */
  extern struct namnod	fngnod;

--- 374,381 -----
  extern char				supprompt[];
  extern char				profile[];
  extern char				sysprofile[];
+ extern char				shrc[];
+ extern char				savehist[];
  
  /* built in names */
  extern struct namnod	fngnod;
***************
*** 355,360
  #if BRL
  extern struct namnod	timenod;
  #endif
  
  /* special names */
  extern char				flagadr[];

--- 392,401 -----
  #if BRL
  extern struct namnod	timenod;
  #endif
+ #if pyr
+ extern struct namnod	univnod;
+ #endif
+ extern struct namnod	histfnod;
  
  /* special names */
  extern char				flagadr[];
***************
*** 360,365
  extern char				flagadr[];
  extern char				*pcsadr;
  extern char				*pidadr;
  extern char				*cmdadr;
  
  extern char				defpath[];

--- 401,407 -----
  extern char				flagadr[];
  extern char				*pcsadr;
  extern char				*pidadr;
+ extern char				*ppidadr;
  extern char				*cmdadr;
  
  extern char				defpath[];
***************
*** 378,383
  #if BRL
  extern char				timename[];	/* TIMEOUT */
  #endif
  
  /* transput */
  extern char				tmpout[];

--- 420,429 -----
  #if BRL
  extern char				timename[];	/* TIMEOUT */
  #endif
+ #if pyr
+ extern char				univname[];	/* UNIVERSE */
+ #endif
+ extern char				histfilename[];	/* HISTFILE */
  
  /* transput */
  extern char				tmpout[];
***************
*** 436,441
  #define		noeotflg	02000000
  #define		dotflg		04000000
  #endif
  
  extern long				flags;
  extern int				rwait;	/* flags read waiting */

--- 482,489 -----
  #define		noeotflg	02000000
  #define		dotflg		04000000
  #endif
+ #define		quickflg	010000000
+ #define		nohistflg	020000000
  
  extern long				flags;
  extern int				rwait;	/* flags read waiting */
***************
*** 444,450
  #include	<setjmp.h>
  extern jmp_buf			subshell;
  extern jmp_buf			errshell;
! #if defined(BSD) && !defined(BSD41C)
  #define	setjmp( env )		_setjmp( env )
  #define	longjmp( env, val )	_longjmp( env, val )
  #endif

--- 492,498 -----
  #include	<setjmp.h>
  extern jmp_buf			subshell;
  extern jmp_buf			errshell;
! #if defined(BSD) && !defined(BSD41C) && !defined(pyr)
  #define	setjmp( env )		_setjmp( env )
  #define	longjmp( env, val )	_longjmp( env, val )
  #endif
:::::::: echo.c :::::::
No differences encountered
:::::::: error.c :::::::
*** ../orig.u/error.c	Wed May 15 17:11:56 1985
--- error.c	Wed May 15 16:02:49 1985
***************
*** 96,101
  		exit(99);
  	}
  #endif
  	exit(exitval);
  }
  

--- 96,103 -----
  		exit(99);
  	}
  #endif
+ 
+ 	histsave (histfnod.namval);
  	exit(exitval);
  }
  
:::::::: expand.c :::::::
No differences encountered
:::::::: fault.c :::::::
No differences encountered
:::::::: func.c :::::::
*** ../orig.u/func.c	Wed May 15 17:11:56 1985
--- func.c	Wed Jun  5 16:01:27 1985
***************
*** 371,376
  					prs_buff(fromastr);	/* DAG */
  
  			}
  			else if ((iof & IOPUT) == 0)
  				prc_buff('<');
  			else if (iof & IOAPP)

--- 371,378 -----
  					prs_buff(fromastr);	/* DAG */
  
  			}
+ 			else if (iof & IORDW)
+ 				prs_buff(rdwstr);	/* ADR */
  			else if ((iof & IOPUT) == 0)
  				prc_buff('<');
  			else if (iof & IOAPP)
:::::::: hash.c :::::::
No differences encountered
:::::::: hash.h :::::::
No differences encountered
:::::::: hashserv.c :::::::
No differences encountered
:::::::: io.c :::::::
No differences encountered
:::::::: jobs.c :::::::
*** ../orig.u/jobs.c	Wed May 15 17:11:57 1985
--- jobs.c	Wed Jun  5 11:55:37 1985
***************
*** 3,8
   *
   *  created by Ron Natalie, BRL
   *  slight changes by Doug Gwyn
   */
  
  #include "defs.h"

--- 3,9 -----
   *
   *  created by Ron Natalie, BRL
   *  slight changes by Doug Gwyn
+  *  some more slight changes by Arnold Robbins (mainly for the BSD /bin/sh)
   */
  
  #include "defs.h"
***************
*** 8,14
  #include "defs.h"
  #include "sym.h"
  
! #if BSD	/* native /bin/sh */
  #include <sys/ioctl.h>
  #else	/* /usr/5bin/sh */
  #include	<sys/_ioctl.h>

--- 9,27 -----
  #include "defs.h"
  #include "sym.h"
  
! #ifndef TAB	/* very original, early /bin/sh */
! #include <signal.h>
! #define comptr(x)	((COMPTR) x)
! #define lstptr(x)	((LSTPTR) x)
! #define forkptr(x)	((FORKPTR) x)
! #define parptr(x)	((PARPTR) x)
! #define forptr(x)	((FORPTR) x)
! #define whptr(x)	((WHPTR) x)
! #define ifptr(x)	((IFPTR) x)
! #define swptr(x)	((SWPTR) x)
! #endif
! 
! #if BSD || (JOBS && ! BRL)	/* native /bin/sh */
  #include <sys/ioctl.h>
  #else	/* /usr/5bin/sh */
  #include	<sys/_ioctl.h>
***************
*** 457,463
  				if(j_stuff(numbuf))
  					return 1;
  			}
! 			switch(iof & (IODOC|IOPUT|IOMOV|IOAPP))  {
  			case IOGET:
  				if(j_stuff(rdinstr))	/* DAG */
  					return 1;

--- 470,476 -----
  				if(j_stuff(numbuf))
  					return 1;
  			}
! 			switch(iof & (IODOC|IOPUT|IOMOV|IOAPP|IORDW))  {
  			case IOGET:
  				if(j_stuff(rdinstr))	/* DAG */
  					return 1;
***************
*** 482,487
  				if(j_stuff(fromastr))	/* DAG */
  					return 1;
  				break;
  			}
  			if(j_stuff(t->ioname))
  				return 1;

--- 495,504 -----
  				if(j_stuff(fromastr))	/* DAG */
  					return 1;
  				break;
+ 			case IORDW:
+ 				if(j_stuff(rdwstr))	/* ADR */
+ 					return 1;
+ 				break;
  			}
  			if(j_stuff(t->ioname))
  				return 1;
***************
*** 503,508
  
  	type = t->tretyp & COMMSK;
  	switch(type)  {
  	case	TFND:	/* added by DAG for System V Release 2 shell */
  		return j_stuff(fndptr(t)->fndnam)
  		    || j_stuff(sfnstr)	/* DAG */

--- 520,526 -----
  
  	type = t->tretyp & COMMSK;
  	switch(type)  {
+ #ifdef TFND	/* ADR --- don't put this stuff in the plain BSD /bin/sh */
  	case	TFND:	/* added by DAG for System V Release 2 shell */
  		return j_stuff(fndptr(t)->fndnam)
  		    || j_stuff(sfnstr)	/* DAG */
***************
*** 508,513
  		    || j_stuff(sfnstr)	/* DAG */
  		    || j_do(fndptr(t)->fndval)
  		    || j_stuff(efnstr);	/* DAG */
  
  	case	TCOM:
  		if(comptr(t)->comset)  {

--- 526,532 -----
  		    || j_stuff(sfnstr)	/* DAG */
  		    || j_do(fndptr(t)->fndval)
  		    || j_stuff(efnstr);	/* DAG */
+ #endif
  
  	case	TCOM:
  		if(comptr(t)->comset)  {
:::::::: mac.h :::::::
*** ../orig.u/mac.h	Wed May 15 17:11:57 1985
--- mac.h	Thu Apr 25 11:44:51 1985
***************
*** 19,24
  #define RQ	'\''
  #define MINUS	'-'
  #define COLON	':'
  #define TAB	'\t'
  
  

--- 19,25 -----
  #define RQ	'\''
  #define MINUS	'-'
  #define COLON	':'
+ #define SQUIGGLE	'~'	/* TILDE defined in BSD tty handler */
  #define TAB	'\t'
  
  
:::::::: macro.c :::::::
*** ../orig.u/macro.c	Wed May 15 17:11:57 1985
--- macro.c	Thu Apr 25 11:44:51 1985
***************
*** 133,138
  			}
  			else if (c == '$')
  				v = pidadr;
  			else if (c == '!')
  				v = pcsadr;
  			else if (c == '#')

--- 133,147 -----
  			}
  			else if (c == '$')
  				v = pidadr;
+ 			else if (c == '+')
+ 			{
+ 				if (ppid != getppid())	/* parent died */
+ 				{
+ 					ppid = getppid();
+ 					assnum (&ppidadr, ppid);
+ 				}
+ 				v = ppidadr;
+ 			}
  			else if (c == '!')
  				v = pcsadr;
  			else if (c == '#')
:::::::: main.c :::::::
*** ../orig.u/main.c	Wed May 15 17:11:57 1985
--- main.c	Tue May 21 17:17:32 1985
***************
*** 69,77
  		if (argv0[0] != '-' || argv0[1] != 'S')
  			loginsh = 0;
  	}
! #endif
! #endif
! #if !defined(BRL) || !defined(pdp11)
  	loginsh = argv0[0] == '-';
  #endif
  

--- 69,75 -----
  		if (argv0[0] != '-' || argv0[1] != 'S')
  			loginsh = 0;
  	}
! #else
  	loginsh = argv0[0] == '-';
  #endif
  #endif
***************
*** 74,79
  #if !defined(BRL) || !defined(pdp11)
  	loginsh = argv0[0] == '-';
  #endif
  
  	stdsigs();
  

--- 72,78 -----
  #else
  	loginsh = argv0[0] == '-';
  #endif
+ #endif
  
  	stdsigs();
  
***************
*** 179,184
  	replace(&cmdadr, dolv[0]);	/* cmdadr is $0 */
  
  	/*
  	 * set pidname '$$'
  	 */
  	assnum(&pidadr, getpid());

--- 178,189 -----
  	replace(&cmdadr, dolv[0]);	/* cmdadr is $0 */
  
  	/*
+ 	 * set ppidname '$+'
+ 	 */
+ 	ppid = getppid();
+ 	assnum (& ppidadr, ppid);
+ 
+ 	/*
  	 * set pidname '$$'
  	 */
  	assnum(&pidadr, getpid());
***************
*** 202,207
  	dfault(&mchknod, MAILCHECK);
  	mailchk = stoi(mchknod.namval);
  
  	if ((beenhere) == FALSE)	/* ? profile */	/* DAG -- only increment once */
  	{
  		++beenhere;		/* DAG */

--- 207,239 -----
  	dfault(&mchknod, MAILCHECK);
  	mailchk = stoi(mchknod.namval);
  
+ #if pyr
+ 	/*
+ 	 * find out current universe, initialize $UNIVERSE
+ 	 */
+ 	cur_univ = setuniverse (U_UCB); /* retrieve old and set to UCB */
+ 	if (cur_univ == -1)
+ 	{
+ 		/* unknown current, default to UCB */
+ 		cur_univ = U_UCB;
+ 		setuniverse (cur_univ);
+ 	}
+ 	else if (cur_univ != U_UCB)
+ 		setuniverse (cur_univ); /* restore to what it was */
+ 	
+ 	/*
+ 	 * force value, ignore whatever was in environment
+ 	 */
+ 	assign (& univnod, univ_name[cur_univ - 1]);
+ 	attrib ((& univnod), N_RDONLY);   /* user can not set $UNIVERSE */
+ #endif
+ 
+ 	/*
+ 	 * assign default value of $HOME/.history to $HISTFILE
+ 	 */
+ 	(void) catpath ("~", savehist);
+ 	dfault (& histfnod, curstak());
+ 
  	if ((beenhere) == FALSE)	/* ? profile */	/* DAG -- only increment once */
  	{
  		++beenhere;		/* DAG */
***************
*** 211,216
  			struct stat	statb;	/* needed for test */
  #endif
  
  #ifndef RES
  
  			if ((input = pathopen(nullstr, sysprofile)) >= 0)

--- 243,253 -----
  			struct stat	statb;	/* needed for test */
  #endif
  
+ 			if (geteuid() != getuid())
+ 				setuid (getuid());
+ 			if (getegid() != getgid())
+ 				setgid (getgid());
+ 
  #ifndef RES
  
  			if ((input = pathopen(nullstr, sysprofile)) >= 0)
***************
*** 232,237
  		}
  		if (rsflag == 0 || rflag == 0)
  			flags |= rshflg;
  		/*
  		 * open input file if specified
  		 */

--- 269,288 -----
  		}
  		if (rsflag == 0 || rflag == 0)
  			flags |= rshflg;
+ 
+ 		/* if all OK, process $HOME/.shrc */
+ 		if (geteuid() == getuid() && getegid() == getgid()
+ 			&& (flags & (rshflg|quickflg)) == 0
+ 			&& (input = pathopen ("~", shrc)) >= 0)
+ 		{
+ 			int promptflags = (flags & (ttyflg|intflg|prompt));
+ 
+ 			/* turn off anything that will cause prompting */
+ 			flags &= ~promptflags;
+ 			exfile (rflag);
+ 			flags |= promptflags;
+ 		}
+ 
  		/*
  		 * open input file if specified
  		 */
***************
*** 300,305
  			setmail(mailpnod.namval);
  		else
  			setmail(mailnod.namval);
  	}
  	else
  	{

--- 351,359 -----
  			setmail(mailpnod.namval);
  		else
  			setmail(mailnod.namval);
+ 
+ 		/* restore previous history */
+ 		histrest (histfnod.namval);
  	}
  	else
  	{
***************
*** 349,355
  				}
  			}
  
! 			prs(ps1nod.namval);
  
  #if BRL
  			if (userid == 0 && !eq(ps1nod.namval, supprompt))

--- 403,410 -----
  				}
  			}
  
! 			/* do special handling for $PS1 */
! 			pr_prompt(ps1nod.namval);
  
  #if BRL
  			if (userid == 0 && !eq(ps1nod.namval, supprompt))
:::::::: mode.h :::::::
No differences encountered
:::::::: msg.c :::::::
*** ../orig.u/msg.c	Wed May 15 17:11:58 1985
--- msg.c	Wed Jun  5 15:19:55 1985
***************
*** 42,49
  char	wtfailed[]	= "is read only";
  char	notid[]		= "is not an identifier";
  char 	badulimit[]	= "bad ulimit";	/* DAG -- lower case */
! char	badreturn[] = "cannot return when not in function";
! char	badexport[] = "cannot export functions";
  char	badunset[] 	= "cannot unset";
  char	nohome[]	= "no home directory";
  char 	badperm[]	= "execute permission denied";

--- 42,49 -----
  char	wtfailed[]	= "is read only";
  char	notid[]		= "is not an identifier";
  char 	badulimit[]	= "bad ulimit";	/* DAG -- lower case */
! char	badreturn[]	= "cannot return when not in function";
! char	badexport[]	= "cannot export functions";
  char	badunset[] 	= "cannot unset";
  char	nohome[]	= "no home directory";
  char 	badperm[]	= "execute permission denied";
***************
*** 98,103
  #if BRL
  char	timename[]	= "TIMEOUT";
  #endif
  
  /*
   * string constants

--- 98,107 -----
  #if BRL
  char	timename[]	= "TIMEOUT";
  #endif
+ #if pyr
+ char	univname[]	= "UNIVERSE";
+ #endif
+ char	histfilename[]	= "HISTFILE";
  
  /*
   * string constants
***************
*** 116,122
  char	stdprompt[]	= "$ ";
  char	supprompt[]	= "# ";
  char	profile[]	= ".profile";
! #if !defined(BRL) || defined(pdp11)
  char	sysprofile[]	= "/etc/profile";
  #else
  char	sysprofile[]	= "/usr/5lib/profile";

--- 120,128 -----
  char	stdprompt[]	= "$ ";
  char	supprompt[]	= "# ";
  char	profile[]	= ".profile";
! char	shrc[]		= ".shrc";
! char	savehist[]	= ".history";
! #if defined(GATECH) || !defined(BRL) || defined(pdp11)
  char	sysprofile[]	= "/etc/profile";
  #else
  char	sysprofile[]	= "/usr/5lib/profile";
***************
*** 122,128
  char	sysprofile[]	= "/usr/5lib/profile";
  #endif
  char	setstr[]	= "set";			/* DAG -- made sharable */
! char	sicrstr[]	= "sicr";			/* DAG */
  char	bang[]		= "!";				/* DAG */
  char	pdstr[]		= ".";				/* DAG */
  char	dotdot[]	= "..";				/* DAG */

--- 128,134 -----
  char	sysprofile[]	= "/usr/5lib/profile";
  #endif
  char	setstr[]	= "set";			/* DAG -- made sharable */
! char	sicrqstr[]	= "sicrq";			/* ADR */
  char	bang[]		= "!";				/* DAG */
  char	pdstr[]		= ".";				/* DAG */
  char	dotdot[]	= "..";				/* DAG */
***************
*** 145,150
  char	dashd[]		= "-d";				/* DAG */
  char	dashf[]		= "-f";				/* DAG */
  char	dashg[]		= "-g";				/* DAG */
  char	dashk[]		= "-k";				/* DAG */
  char	dashn[]		= "-n";				/* DAG */
  char	dasho[]		= "-o";				/* DAG */

--- 151,157 -----
  char	dashd[]		= "-d";				/* DAG */
  char	dashf[]		= "-f";				/* DAG */
  char	dashg[]		= "-g";				/* DAG */
+ char	dashi[]		= "-i";				/* ADR */
  char	dashk[]		= "-k";				/* DAG */
  #if pyr
  char	dashl[]		= "-l";				/* ADR */
***************
*** 146,151
  char	dashf[]		= "-f";				/* DAG */
  char	dashg[]		= "-g";				/* DAG */
  char	dashk[]		= "-k";				/* DAG */
  char	dashn[]		= "-n";				/* DAG */
  char	dasho[]		= "-o";				/* DAG */
  char	dashp[]		= "-p";				/* DAG */

--- 153,161 -----
  char	dashg[]		= "-g";				/* DAG */
  char	dashi[]		= "-i";				/* ADR */
  char	dashk[]		= "-k";				/* DAG */
+ #if pyr
+ char	dashl[]		= "-l";				/* ADR */
+ #endif
  char	dashn[]		= "-n";				/* DAG */
  char	dasho[]		= "-o";				/* DAG */
  char	dashp[]		= "-p";				/* DAG */
***************
*** 191,196
  char	ishashed[]	= " is hashed (";		/* DAG */
  char	rpnlstr[]	= ")\n";			/* DAG */
  char	isstr[]		= " is ";			/* DAG */
  #if JOBS
  char	rsqbrk[]	= "] ";
  char	spspstr[]	= " \ ";

--- 201,207 -----
  char	ishashed[]	= " is hashed (";		/* DAG */
  char	rpnlstr[]	= ")\n";			/* DAG */
  char	isstr[]		= " is ";			/* DAG */
+ char	rdwstr[]	= "<> ";
  #if JOBS
  char	rsqbrk[]	= "] ";
  char	spspstr[]	= " \ ";
***************
*** 217,222
  char	selsstr[]	= "; else ";
  char	sfistr[]	= "; fi";
  char	iesacstr[]	= " in ... esac";
  #endif
  #if BRL
  char	drshell[]	= "-rsh";

--- 228,234 -----
  char	selsstr[]	= "; else ";
  char	sfistr[]	= "; fi";
  char	iesacstr[]	= " in ... esac";
+ char	nosusp[]	= "cannot suspend a login shell\n";	/* yet... */
  #endif
  #if BRL
  char	drshell[]	= "-rsh";
***************
*** 329,334
  	{ lbstr,	SYSTST },	/* DAG -- use shared string */
  #endif
  
  #if JOBS
  	{ "bg",		SYSBG },
  #endif

--- 341,350 -----
  	{ lbstr,	SYSTST },	/* DAG -- use shared string */
  #endif
  
+ #if pyr
+ 	{ "att",	SYSATT },
+ #endif
+ 
  #if JOBS
  	{ "bg",		SYSBG },
  #endif
***************
*** 347,352
  #endif
  
  	{ "hash",	SYSHASH	},
  
  #if JOBS
  	{ "jobs",	SYSJOBS },

--- 363,369 -----
  #endif
  
  	{ "hash",	SYSHASH	},
+ 	{ "history",	SYSHISTORY },
  
  #if JOBS
  	{ "jobs",	SYSJOBS },
***************
*** 376,381
  	{ "return",	SYSRETURN },
  	{ setstr,	SYSSET	},	/* DAG -- use shared string */
  	{ "shift",	SYSSHFT	},
  	{ "test",	SYSTST },
  	{ "times",	SYSTIMES },
  	{ "trap",	SYSTRAP	},

--- 393,401 -----
  	{ "return",	SYSRETURN },
  	{ setstr,	SYSSET	},	/* DAG -- use shared string */
  	{ "shift",	SYSSHFT	},
+ #if JOBS
+ 	{ "suspend",	SYSSUSPEND },	/* ADR */
+ #endif
  	{ "test",	SYSTST },
  	{ "times",	SYSTIMES },
  	{ "trap",	SYSTRAP	},
***************
*** 381,386
  	{ "trap",	SYSTRAP	},
  	{ "type",	SYSTYPE },
  
  
  #ifndef RES		
  	{ "ulimit",	SYSULIMIT },

--- 401,409 -----
  	{ "trap",	SYSTRAP	},
  	{ "type",	SYSTYPE },
  
+ #if pyr
+ 	{ "ucb",	SYSUCB },
+ #endif
  
  #ifndef RES		
  	{ "ulimit",	SYSULIMIT },
***************
*** 387,392
  	{ "umask",	SYSUMASK },
  #endif
  
  	{ "unset", 	SYSUNS },
  	{ "wait",	SYSWAIT	}
  };

--- 410,419 -----
  	{ "umask",	SYSUMASK },
  #endif
  
+ #if pyr
+ 	{ "universe",	SYSUNIVERSE },
+ #endif
+ 
  	{ "unset", 	SYSUNS },
  	{ "wait",	SYSWAIT	}
  };
***************
*** 392,394
  };
  
  int	no_commands = sizeof commands / sizeof(struct sysnod);	/* DAG -- improved */

--- 419,427 -----
  };
  
  int	no_commands = sizeof commands / sizeof(struct sysnod);	/* DAG -- improved */
+ 
+ #if pyr
+ #include <sys/types.h>	/* to get sys/inode.h to work (sigh) */
+ #include <sys/inode.h>	/* NUMUNIV is defined to be NCLNK */
+ #include <universe.h>	/* gets char *univ_name[] && char *univ_longname[] */
+ #endif
:::::::: name.c :::::::
*** ../orig.u/name.c	Wed May 15 17:11:58 1985
--- name.c	Wed May  8 10:02:45 1985
***************
*** 15,20
  #if BRL
  struct namnod timenod =	/* for TIMEOUT */
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	timename

--- 15,24 -----
  #if BRL
  struct namnod timenod =	/* for TIMEOUT */
  {
+ 	&acctnod,
+ #if pyr
+ 	&univnod,
+ #else
  	(struct namnod *)NIL,
  #endif
  	timename
***************
*** 16,22
  struct namnod timenod =	/* for TIMEOUT */
  {
  	(struct namnod *)NIL,
! 	(struct namnod *)NIL,
  	timename
  };
  #endif

--- 20,26 -----
  	&univnod,
  #else
  	(struct namnod *)NIL,
! #endif
  	timename
  };
  #endif
***************
*** 20,26
  	timename
  };
  #endif
! struct namnod ps2nod =
  {
  	(struct namnod *)NIL,
  	&acctnod,

--- 24,31 -----
  	timename
  };
  #endif
! #if pyr
! struct namnod univnod = /* current universe */
  {
  #if BRL
  	(struct namnod *)NIL,
***************
*** 22,27
  #endif
  struct namnod ps2nod =
  {
  	(struct namnod *)NIL,
  	&acctnod,
  	ps2name

--- 27,33 -----
  #if pyr
  struct namnod univnod = /* current universe */
  {
+ #if BRL
  	(struct namnod *)NIL,
  #else
  	&acctnod,
***************
*** 23,28
  struct namnod ps2nod =
  {
  	(struct namnod *)NIL,
  	&acctnod,
  	ps2name
  };

--- 29,35 -----
  {
  #if BRL
  	(struct namnod *)NIL,
+ #else
  	&acctnod,
  #endif
  	(struct namnod *)NIL,
***************
*** 24,29
  {
  	(struct namnod *)NIL,
  	&acctnod,
  	ps2name
  };
  struct namnod cdpnod = 

--- 31,59 -----
  	(struct namnod *)NIL,
  #else
  	&acctnod,
+ #endif
+ 	(struct namnod *)NIL,
+ 	univname,
+ };
+ #endif
+ struct namnod histfnod =	/* history file */
+ {
+ 	&cdpnod,
+ 	&homenod,
+ 	histfilename
+ };
+ struct namnod ps2nod =
+ {
+ 	&ps1nod,
+ #if BRL
+ 	&timenod,
+ #else
+ #if pyr
+ 	&univnod,
+ #else
+ 	&acctnod,
+ #endif
+ #endif
  	ps2name
  };
  struct namnod cdpnod = 
***************
*** 34,40
  };
  struct namnod pathnod =
  {
- 	&mailpnod,
  	(struct namnod *)NIL,
  	pathname
  };

--- 64,69 -----
  };
  struct namnod pathnod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	pathname
***************
*** 36,41
  {
  	&mailpnod,
  	(struct namnod *)NIL,
  	pathname
  };
  struct namnod ifsnod =

--- 65,71 -----
  struct namnod pathnod =
  {
  	(struct namnod *)NIL,
+ 	(struct namnod *)NIL,
  	pathname
  };
  struct namnod ifsnod =
***************
*** 40,46
  };
  struct namnod ifsnod =
  {
! 	&homenod,
  	&mailnod,
  	ifsname
  };

--- 70,76 -----
  };
  struct namnod ifsnod =
  {
! 	&histfnod,
  	&mailnod,
  	ifsname
  };
***************
*** 47,53
  struct namnod ps1nod =
  {
  	&pathnod,
! 	&ps2nod,
  	ps1name
  };
  struct namnod homenod =

--- 77,83 -----
  struct namnod ps1nod =
  {
  	&pathnod,
! 	(struct namnod *)NIL,
  	ps1name
  };
  struct namnod homenod =
***************
*** 52,58
  };
  struct namnod homenod =
  {
- 	&cdpnod,
  	(struct namnod *)NIL,
  	homename
  };

--- 82,87 -----
  };
  struct namnod homenod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	homename
***************
*** 54,59
  {
  	&cdpnod,
  	(struct namnod *)NIL,
  	homename
  };
  struct namnod mailnod =

--- 83,89 -----
  struct namnod homenod =
  {
  	(struct namnod *)NIL,
+ 	(struct namnod *)NIL,
  	homename
  };
  struct namnod mailnod =
***************
*** 59,65
  struct namnod mailnod =
  {
  	(struct namnod *)NIL,
! 	(struct namnod *)NIL,
  	mailname
  };
  struct namnod mchknod =

--- 89,95 -----
  struct namnod mailnod =
  {
  	(struct namnod *)NIL,
! 	&mchknod,
  	mailname
  };
  struct namnod mchknod =
***************
*** 64,71
  };
  struct namnod mchknod =
  {
! 	&ifsnod,
! 	&ps1nod,
  	mchkname
  };
  struct namnod acctnod =

--- 94,101 -----
  };
  struct namnod mchknod =
  {
! 	(struct namnod *)NIL,
! 	(struct namnod *)NIL,
  	mchkname
  };
  struct namnod acctnod =
***************
*** 71,79
  struct namnod acctnod =
  {
  	(struct namnod *)NIL,
- #if BRL
- 	&timenod,	/* lopsided tree, but who cares */
- #else
  	(struct namnod *)NIL,
  #endif
  	acctname

--- 101,106 -----
  struct namnod acctnod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	acctname
  };
***************
*** 75,81
  	&timenod,	/* lopsided tree, but who cares */
  #else
  	(struct namnod *)NIL,
- #endif
  	acctname
  };
  struct namnod mailpnod =

--- 102,107 -----
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	acctname
  };
  struct namnod mailpnod =
***************
*** 80,87
  };
  struct namnod mailpnod =
  {
! 	(struct namnod *)NIL,
! 	(struct namnod *)NIL,
  	mailpname
  };
  

--- 106,113 -----
  };
  struct namnod mailpnod =
  {
! 	&ifsnod,
! 	&ps2nod,
  	mailpname
  };
  
***************
*** 86,92
  };
  
  
! struct namnod *namep = &mchknod;
  
  /* ========	variable and string handling	======== */
  

--- 112,118 -----
  };
  
  
! struct namnod *namep = &mailpnod;
  
  /* ========	variable and string handling	======== */
  
:::::::: name.h :::::::
No differences encountered
:::::::: print.c :::::::
*** ../orig.u/print.c	Wed May 15 17:11:58 1985
--- print.c	Wed May 29 16:24:45 1985
***************
*** 265,267
  
  	prs_buff(numbuf);
  }

--- 265,384 -----
  
  	prs_buff(numbuf);
  }
+ 
+ void
+ pr_prompt (str)
+ register char *str;
+ {
+ 	for (; *str; str++)
+ 	{
+ 		if (*str != '%')
+ 			prc_buff (*str);
+ 		else if (*(str+1) == 'd')
+ 		{
+ 			/* current directory */
+ 			str++;
+ 			prs_buff (retcwd());
+ 		}
+ 		else if (*(str+1) == 'e')
+ 		{
+ 			/* event count */
+ 			str++;
+ 			if ((flags & nohistflg) == 0)
+ 				prn_buff (event_count);
+ 		}
+ 		else if (*(str+1) == 'h')
+ 		{
+ 			/* hostname */
+ 			static char *cp = 0;
+ 			static int didhost = FALSE;
+ 			static int didgt = FALSE;
+ #ifdef BSD
+ 			static char buf[257];
+ 
+ 			if (! didhost)
+ 			{
+ 				gethostname (buf, sizeof buf);
+ 				didhost = TRUE;
+ 				cp = buf;
+ 			}
+ #else
+ #include <sys/utsname.h>	/* has an extern declaration in it */
+ 			static struct utsname name;
+ 
+ 			if (! didhost)
+ 			{
+ 				uname (& name);
+ 				/* avoid emulation bug */
+ 				name.sysname[sizeof(name.sysname)-1] = '\0';
+ 				didhost = TRUE;
+ 				cp = name.sysname;
+ 			}
+ #endif
+ 
+ #ifdef GATECH
+ 			/*
+ 			 * this is to get rid of the dumb gt- convention.
+ 			 * a gt w/out the - is also removed.
+ 			 */
+ 			if (! didgt)
+ 			{
+ 				didgt = TRUE;
+ 				if (cp[0] == 'g' && cp[1] == 't' && cp[2])
+ 				{
+ 					cp += 2;
+ 					if (cp[0] == '-' && cp[1])
+ 						cp++;
+ 				}
+ 			}
+ #endif
+ 			prs_buff (cp);
+ 			str++;
+ 		}
+ 		else if (*(str+1) == 'l')
+ 		{
+ 			/* login name */
+ 			static char *cp = 0;
+ 			static int didname = FALSE;
+ 
+ 			str++;
+ 			if (! didname)
+ 			{
+ 				cp = username ();
+ 				didname = TRUE;
+ 			}
+ 
+ 			if (cp)
+ 				prs_buff (cp);
+ 		}
+ 		else if (*(str+1) == 't')
+ 		{
+ 			/* current time, HH:MM */
+ 			long l;
+ 			char *cp, *ctime ();
+ 
+ 			str++;
+ 			time (& l);
+ 			cp = ctime (& l);
+ 			cp[16] = '\0';
+ 			cp += 11;
+ 			prs_buff (cp);
+ 		}
+ #if pyr
+ 		else if (*(str+1) == 'u')
+ 		{
+ 			/* current univeserse */
+ 			str++;
+ 			prs_buff (univ_name[cur_univ-1]);
+ 		}
+ #endif
+ 		else if (*(str+1) == '\0')	/* % was last char in string */
+ 		{
+ 			prc_buff (*str);
+ 			continue;
+ 		}
+ 		else
+ 			prc_buff (*(++str));
+ 	}
+ 	flushb();
+ }
:::::::: pwd.c :::::::
*** ../orig.u/pwd.c	Wed May 15 17:11:58 1985
--- pwd.c	Thu Apr 25 11:44:56 1985
***************
*** 455,457
  	return retval;
  	}
  #endif

--- 455,466 -----
  	return retval;
  	}
  #endif
+ 
+ char *
+ retcwd()
+ {
+ 	if (didpwd == FALSE)
+ 		pwd ();
+ 	
+ 	return (cwdname);
+ }
:::::::: service.c :::::::
*** ../orig.u/service.c	Wed May 15 17:11:58 1985
--- service.c	Wed May 29 15:55:29 1985
***************
*** 79,84
  				else
  					fd = dup(fd);
  			}
  			else if ((iof & IOPUT) == 0)
  				fd = chkopen(ion);
  			else if (flags & rshflg)

--- 79,89 -----
  				else
  					fd = dup(fd);
  			}
+ 			else if (iof & IORDW)
+ 			{
+ 				if ((fd = open(ion, 2)) < 0)
+ 					failed(ion, badopen);
+ 			}
  			else if ((iof & IOPUT) == 0)
  				fd = chkopen(ion);
  			else if (flags & rshflg)
***************
*** 157,162
  	 */
  	register char	*scanp = path;
  	register char	*argp = locstak();
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;

--- 162,169 -----
  	 */
  	register char	*scanp = path;
  	register char	*argp = locstak();
+ 	char	*save = argp;
+ 	char	*cp;
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;
***************
*** 160,165
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;
  	if (scanp != path)
  		*argp++ = '/';
  	if (*scanp == COLON)

--- 167,179 -----
  
  	while (*scanp && *scanp != COLON)
  		*argp++ = *scanp++;
+ 	*argp = '\0';
+ 	/* try a tilde expansion */
+ 	if (*save == SQUIGGLE && (cp = homedir (save + 1)) != nullstr)
+ 	{
+ 		movstr (cp, save);
+ 		argp = save + length (save) - 1;
+ 	}
  	if (scanp != path)
  		*argp++ = '/';
  	if (*scanp == COLON)
:::::::: setbrk.c :::::::
No differences encountered
:::::::: signal.vax :::::::
No differences encountered
:::::::: stak.c :::::::
No differences encountered
:::::::: stak.h :::::::
No differences encountered
:::::::: string.c :::::::
No differences encountered
:::::::: sym.h :::::::
No differences encountered
:::::::: test.c :::::::
*** ../orig.u/test.c	Wed May 15 17:11:59 1985
--- test.c	Thu Apr 25 11:45:03 1985
***************
*** 126,132
  		if (eq(a, dashk))				/* DAG */
  			return(ftype(nxtarg(0), S_ISVTX));
  		if (eq(a, dashp))				/* DAG */
! #if BSD
  #define S_IFIFO	S_IFSOCK	/* fifo - map to socket on 4.2BSD */
  #endif
  			return(filtyp(nxtarg(0),S_IFIFO));

--- 126,132 -----
  		if (eq(a, dashk))				/* DAG */
  			return(ftype(nxtarg(0), S_ISVTX));
  		if (eq(a, dashp))				/* DAG */
! #if BSD && !defined(pyr)
  #define S_IFIFO	S_IFSOCK	/* fifo - map to socket on 4.2BSD */
  #endif
  			return(filtyp(nxtarg(0),S_IFIFO));
:::::::: timeout.h :::::::
No differences encountered
:::::::: ulimit.c :::::::
No differences encountered
:::::::: word.c :::::::
*** ../orig.u/word.c	Wed May 15 17:11:59 1985
--- word.c	Thu Jun  6 14:32:13 1985
***************
*** 19,24
  	struct argnod	*arg = (struct argnod *)locstak();
  	register char	*argp = arg->argval;
  	int		alpha = 1;
  
  	wdnum = 0;
  	wdset = 0;

--- 19,25 -----
  	struct argnod	*arg = (struct argnod *)locstak();
  	register char	*argp = arg->argval;
  	int		alpha = 1;
+ 	char		*save;
  
  	wdnum = 0;
  	wdset = 0;
***************
*** 41,46
  			break;	/* out of comment - white space loop */
  		}
  	}
  	if (!eofmeta(c))
  	{
  		do

--- 42,48 -----
  			break;	/* out of comment - white space loop */
  		}
  	}
+ 	save = argp;	/* save start of word */
  	if (!eofmeta(c))
  	{
  		do
***************
*** 72,77
  							chkpr();
  					}
  				}
  			}
  		} while ((c = nextc(0), !eofmeta(c)));
  		argp = endstak(argp);

--- 74,98 -----
  							chkpr();
  					}
  				}
+ 				/*
+ 				 * check for ~login name
+ 				 */
+ 				else if (c == SQUIGGLE &&
+ 						validtilde (save, argp))
+ 				{
+ 					char *name, *home;
+ 
+ 					name = argp;
+ 					while ((c = nextc(0)) != '/' &&
+ 							!eofmeta(c))
+ 						*name++ = c;
+ 					peekc = c;
+ 					*name = '\0';
+ 					home = homedir(argp);
+ 					if (*home)
+ 						movstr (home, --argp);
+ 					argp += length (argp) - 1;
+ 				}
  			}
  		} while ((c = nextc(0), !eofmeta(c)));
  		argp = endstak(argp);
***************
*** 120,125
  			wdval = EOFSYM;
  		if (iopend && eolchar(c))
  		{
  			copy(iopend);
  			iopend = 0;
  		}

--- 141,149 -----
  			wdval = EOFSYM;
  		if (iopend && eolchar(c))
  		{
+ 			int histon = (flags&nohistflg) == 0;
+ 
+ 			flags |= nohistflg;	/* no history in here docs */
  			copy(iopend);
  			if (histon)		/* turn history back on */
  				flags &= ~nohistflg;
***************
*** 121,126
  		if (iopend && eolchar(c))
  		{
  			copy(iopend);
  			iopend = 0;
  		}
  	}

--- 145,152 -----
  
  			flags |= nohistflg;	/* no history in here docs */
  			copy(iopend);
+ 			if (histon)		/* turn history back on */
+ 				flags &= ~nohistflg;
  			iopend = 0;
  		}
  	}
***************
*** 245,251
  	}
  	else
  	{
! 		f->fend = (f->fnxt = f->fbuf) + len;
  #if BRL || JOBS
  		eofcount = 0;
  #endif

--- 271,278 -----
  	}
  	else
  	{
! 		/* f->fend = (f->fnxt = f->fbuf) + len; */
! 		f->fend = f->fnxt + len;
  #if BRL || JOBS
  		eofcount = 0;
  #endif
***************
*** 255,261
  }
  
  static
! readb()
  {
  	register struct fileblk *f = standin;
  	register int	len;

--- 282,288 -----
  }
  
  static
! readblock()	/* ADR -- changed the name */
  {
  	register struct fileblk *f = standin;
  	register int	len;
***************
*** 275,278
  		}
  	} while ((len = read(f->fdes, f->fbuf, f->fsiz)) < 0 && trapnote);
  	return(len);
  }

--- 302,502 -----
  		}
  	} while ((len = read(f->fdes, f->fbuf, f->fsiz)) < 0 && trapnote);
  	return(len);
+ }
+ 
+ /* readb --- read a block from the outside world, and history process it */
+ 
+ /*
+  * In BSD systems, using the literal next capability of the tty driver, it
+  * is actually possible to put a newline in the middle of the input line,
+  * and then hit return, so that the shell sees two lines of input.
+  *
+  * As a design decision, if there is a \n in the middle of what we've read
+  * from a terminal, treat the commands as two separately typed commands. I.e.
+  *
+  *	echo hi ^J echo there
+  *
+  * is the same as
+  *
+  *	echo hi
+  *	echo there
+  *
+  * The major reason for doing it this way is that the history mechanism knows
+  * that a \n is the end of a line.
+  *
+  * Finally, on USG systems, we just leave this code alone, since it won't
+  * get executed anyway.
+  */
+ 
+ /*
+  * In word.c, the readc() function keeps a pointer to what standin pointed to
+  * when readc first gets called.  Therefore, where standin points to can not 
+  * not change across calls to readb().  To get around this, we change the
+  * contents of the structure pointed to by standin, saving and restoring
+  * it as necessary.
+  */
+ 
+ #define LARGEBUF	(HISTSIZE / 2)	/* size of expanded history */
+ 
+ static
+ readb()
+ {
+ 	int ilen, i, j;
+ 	char ibuf[BUFSIZ];	/* input into scratch area, pass to history */
+ 	static char expansion[LARGEBUF];
+ 	static int moreinbuf = FALSE;
+ 	static int saved_ilen = 0;
+ 	static int start_here = 0;
+ 	static struct fileblk *f = 0;
+ 	auto int gotoutofbuf = 0;
+ 
+ 	if (expanded)	/* just did a history substitution */
+ 		expanded = 0;
+ 
+ 	if ((flags & nohistflg) || (flags & prompt) == 0 || ! isatty (input)
+ 			|| standin->fstak != 0)
+ 	{
+ 		ilen = readblock ();
+ 		if (ilen > 0)
+ 			standin->fnxt = standin->fbuf;
+ 		return (ilen);
+ 		/* not doing history expansion at all */
+ 	}
+ 
+ 	if (f == 0)
+ 		f = standin;
+ 
+ 	ilen = 0;
+ 
+ 	/*
+ 	 * First, if there was more stuff in the last buffer, go and get it.
+ 	 * If not get some more from the outside world.
+ 	 *
+ 	 * Then, make sure we've read up to a newline.
+ 	 * This is basically in case someone has done something bizarre
+ 	 * like 'stty raw', and input is coming in one character at a time.
+ 	 *
+ 	 * We use a heuristic.  If amount read is just 1, keep reading till
+ 	 * we get a newline.  Else, read in a complete line from the terminal.
+ 	 * Once we're in raw mode, can't reset it until a newline is typed.
+ 	 *
+ 	 * If not reading one character at a time, then do the stuff for
+ 	 * embedded newlines.
+ 	 */
+ 
+ 	if (moreinbuf)
+ 	{
+ 		for (i = 0, j = start_here; f->fbuf[j] != NL && j < saved_ilen; i++, j++)
+ 			ibuf[i] = f->fbuf[j];
+ 
+ #ifdef notdef
+ 		if (f->fbuf[j] != NL)
+ 		{
+ 			prs ("internal i/o error C in readb\n");
+ 			return (0);
+ 		}
+ #endif
+ 
+ 		if (f->fbuf[j] == NL)
+ 			ibuf[i++] = NL;
+ 		ibuf[i] = '\0';
+ 		ilen = i;
+ 		/* embedded newline */
+ 		moreinbuf = (++j < saved_ilen - 1);
+ 		if (moreinbuf)
+ 			start_here = j;	/* where to start next time */
+ 		gotoutofbuf = 1;
+ 	}
+ 	else	/* wasn't an embedded \n last time */
+ 	{
+ 		ilen = readblock ();
+ 	
+ 		if (ilen <= 0)	/* EOF or error */
+ 			return (ilen);
+ 
+ 		if (ilen == 1)	/* either in raw mode, or an empty line */
+ 		{
+ 			i = 0;
+ 			ibuf[i++] = f->fbuf[0];
+ 			if (f->fbuf[0] == NL)
+ 			{
+ 				ibuf[i] = '\0';
+ 				goto dohist;
+ 			}
+ 
+ 			while ((ilen = readblock()) > 0)
+ 			{
+ 				if (ilen != 1)
+ 				{
+ 					prs ("internal i/o error A in readb\n");
+ 					return (0);
+ 				}
+ 				ibuf[i++] = f->fbuf[0];
+ 				if (f->fbuf[0] == NL)
+ 				{
+ 					ibuf[i] = '\0';
+ 					break;	/* while */
+ 				}
+ 			}
+ 			ilen = i;
+ 			gotoutofbuf = TRUE;
+ 			/* force code below to use collected string */
+ 		}
+ 		else
+ 		{
+ 			/* reading bunches of characters at once */
+ 			for (i = 0; f->fbuf[i] != NL && i < ilen; i++)
+ 				ibuf[i] = f->fbuf[i];
+ 
+ #ifdef notdef
+ 			if (f->fbuf[i] != NL)
+ 			{
+ 				prs ("internal i/o error B in readb\n");
+ 				return (0);
+ 			}
+ #endif
+ 
+ 			ibuf[i++] = NL;
+ 			ibuf[i] = '\0';
+ 			/* ilen was set by readblock() */
+ 			/* embedded newline */
+ 			moreinbuf = (i < ilen - 1);
+ 			if (moreinbuf)
+ 			{
+ 				saved_ilen = ilen;
+ 				start_here = i;
+ 				/* where to start next time */
+ 				gotoutofbuf = 1;
+ 			}
+ 		}
+ 	}
+ 
+ dohist:
+ 	/* quick heuristic */
+ 	if (! gotoutofbuf && ilen == 1 && f->fbuf[0] == NL)
+ 	{
+ 		f->fnxt = f->fbuf;
+ 		return (ilen);
+ 	}
+ 
+ 	if (histsub (ibuf, expansion, sizeof expansion))
+ 	{
+ 		int olen = length (expansion) - 1;
+ 		if (! expanded && ! gotoutofbuf)
+ 		{
+ 			standin->fnxt = standin->fbuf;
+ 			return (ilen);
+ 		}
+ 		/* else
+ 			expanded == TRUE or from buffer */
+ 		standin->fnxt = expansion;
+ 		return (olen);
+ 	}
+ 	else
+ 	{
+ 		/* hist expansion failed, return an empty line */
+ 		standin->fnxt = standin->fbuf;
+ 		standin->fbuf[0] = NL;
+ 		return (1);
+ 	}
  }
:::::::: xec.c :::::::
*** ../orig.u/xec.c	Wed May 15 17:12:00 1985
--- xec.c	Tue Jun  4 17:57:01 1985
***************
*** 27,32
  	 */
  	register struct trenod	*t;
  	char		*sav = savstak();
  
  	sigchk();
  	if (!errorflg)

--- 27,42 -----
  	 */
  	register struct trenod	*t;
  	char		*sav = savstak();
+ #if pyr
+ 	auto int change_univ = FALSE;
+ 	auto int new_univ = 0;
+ 	/*
+ 	 * univesrses run from 1 to NUMUNIV: We start out at 0
+ 	 * and increment new_univ in the switch for internal
+ 	 * commands, below.  new_univ must *not* be assigned to, directly
+ 	 * or via side effects, any place else.
+ 	 */
+ #endif
  
  	sigchk();
  	if (!errorflg)
***************
*** 109,114
  					if (flags & execpr)
  						execprint(com);
  
  					if (comtype == NOTFOUND)
  					{
  						pos = hashdata(cmdhash);

--- 119,130 -----
  					if (flags & execpr)
  						execprint(com);
  
+ 					/*
+ 					 * fix a bug which caused the shell
+ 					 * to do not do a second command if
+ 					 * the first was not found. (bug fix
+ 					 * from USENET)
+ 					 */
  					if (comtype == NOTFOUND)
  					{
  						char *errstr;
***************
*** 111,116
  
  					if (comtype == NOTFOUND)
  					{
  						pos = hashdata(cmdhash);
  						if (pos == 1)
  							failed(*com, notfound);

--- 127,134 -----
  					 */
  					if (comtype == NOTFOUND)
  					{
+ 						char *errstr;
+ 
  						pos = hashdata(cmdhash);
  						if (pos == 1)
  							errstr = notfound;
***************
*** 113,119
  					{
  						pos = hashdata(cmdhash);
  						if (pos == 1)
! 							failed(*com, notfound);
  						else if (pos == 2)
  							failed(*com, badexec);
  						else

--- 131,137 -----
  
  						pos = hashdata(cmdhash);
  						if (pos == 1)
! 							errstr = notfound;
  						else if (pos == 2)
  							errstr = badexec;
  						else
***************
*** 115,121
  						if (pos == 1)
  							failed(*com, notfound);
  						else if (pos == 2)
! 							failed(*com, badexec);
  						else
  							failed(*com, badperm);
  						break;

--- 133,139 -----
  						if (pos == 1)
  							errstr = notfound;
  						else if (pos == 2)
! 							errstr = badexec;
  						else
  							errstr = badperm;
  						prp();
***************
*** 117,123
  						else if (pos == 2)
  							failed(*com, badexec);
  						else
! 							failed(*com, badperm);
  						break;
  					}
  

--- 135,147 -----
  						else if (pos == 2)
  							errstr = badexec;
  						else
! 							errstr = badperm;
! 						prp();
! 						prs_cntl(*com);
! 						prs (colon);
! 						prs (errstr);
! 						newline();
! 						exitval = 1;
  						break;
  					}
  
***************
*** 193,198
  							if (j_finish(FALSE))
  								break;
  #endif
  							flags |= forked;	/* force exit */	
  #if BRL && pdp11
  							if (loginsh)

--- 217,224 -----
  							if (j_finish(FALSE))
  								break;
  #endif
+ 							histsave (histfnod.namval);
+ 							/* save before setting flag */
  							flags |= forked;	/* force exit */	
  #if BRL && pdp11
  							if (loginsh)
***************
*** 289,294
  #ifdef RES	/* Research includes login as part of the shell */	
  
  						case SYSLOGIN:
  							flags |= forked;	/* DAG -- bug fix (force bad exec to terminate shell) */
  							oldsigs();
  							execa(com, -1);

--- 315,321 -----
  #ifdef RES	/* Research includes login as part of the shell */	
  
  						case SYSLOGIN:
+ 							histsave (histfnod.namval);
  							flags |= forked;	/* DAG -- bug fix (force bad exec to terminate shell) */
  							oldsigs();
  							execa(com, -1);
***************
*** 298,303
  #ifndef	BRL
  						case SYSLOGIN:	
  #endif
  							flags |= forked;	/* DAG -- bug fix (force bad exec to terminate shell) */
  							oldsigs();	
  							execa(com, -1);

--- 325,331 -----
  #ifndef	BRL
  						case SYSLOGIN:	
  #endif
+ 							histsave (histfnod.namval);
  							flags |= forked;	/* DAG -- bug fix (force bad exec to terminate shell) */
  							oldsigs();	
  							execa(com, -1);
***************
*** 309,314
  								failed(com[0], restricted);	
  							else	
  							{	
  								flags |= forked;	/* force bad exec to terminate shell */	
  								oldsigs();	
  								execa(com, -1);

--- 337,343 -----
  								failed(com[0], restricted);	
  							else	
  							{	
+ 								histsave (histfnod.namval);
  								flags |= forked;	/* force bad exec to terminate shell */	
  								oldsigs();	
  								execa(com, -1);
***************
*** 518,524
  								if (command == 1 || command == 4)	
  								{	
  									prl(i);	
! 									prc_buff('\n');	
  								}	
  								break;	
  							}				

--- 547,553 -----
  								if (command == 1 || command == 4)	
  								{	
  									prl(i);	
! 									prc_buff(NL);	
  								}	
  								break;	
  							}				
***************
*** 669,674
  
  							j_resume(a1, TRUE);
  							break;
  #endif
  
  						default:	

--- 698,714 -----
  
  							j_resume(a1, TRUE);
  							break;
+ 
+ 						case SYSSUSPEND:
+ 							exitval = 1;
+ 							if (getppid() == 1)
+ 								prs (nosusp);
+ 							else
+ 							{
+ 								exitval = 0;
+ 								kill (getpid(), SIGSTOP);
+ 							}
+ 							break;
  #endif
  
  #if pyr
***************
*** 671,676
  							break;
  #endif
  
  						default:	
  							prs_buff("unknown builtin\n");
  						}	

--- 711,754 -----
  							break;
  #endif
  
+ #if pyr
+ 						/*
+ 						 * UCB is Universe 2
+ 						 * ATT is Universe 1
+ 						 * new_univ == 0
+ 						 */
+ 						case SYSUCB:
+ 							new_univ++;
+ 							/* fall thru */
+ 						case SYSATT:
+ 							new_univ++;
+ 							if (argn > 1)
+ 							{
+ 								change_univ = TRUE;
+ 								com++;
+ 								goto doit;
+ 							}
+ 							else
+ 							{
+ 								setuniverse (cur_univ = new_univ);
+ 								univnod.namflg &= ~N_RDONLY;
+ 								assign (& univnod, univ_name[cur_univ - 1]);
+ 								attrib ((& univnod), N_RDONLY);
+ 								break;
+ 							}
+ 						
+ 						case SYSUNIVERSE:
+ 							if (eq(com[1], dashl))
+ 								prs_buff (univ_longname[cur_univ - 1]);
+ 							else
+ 								prs_buff (univ_name[cur_univ - 1]);
+ 							prc_buff (NL);
+ 							break;
+ #endif
+ 
+ 						case SYSHISTORY:
+ 							exitval = history (argn, com);
+ 							break;
  						default:	
  							prs_buff("unknown builtin\n");
  						}	
***************
*** 709,714
  			}
  
  		case TFORK:
  			exitval = 0;
  			if (execflg && (treeflgs & (FAMP | FPOU)) == 0)
  				parent = 0;

--- 787,795 -----
  			}
  
  		case TFORK:
+ #if pyr
+ 		doit:
+ #endif
  			exitval = 0;
  			if (execflg && (treeflgs & (FAMP | FPOU)) == 0)
  				parent = 0;
***************
*** 788,793
  			}
  			else	/* this is the forked branch (child) of execute */
  			{
  #if BRL
  				loginsh = 0;
  #endif

--- 869,884 -----
  			}
  			else	/* this is the forked branch (child) of execute */
  			{
+ #if pyr
+ 				if (change_univ)
+ 				{
+ 					setuniverse (new_univ);
+ 					univnod.namflg &= ~N_RDONLY;
+ 					assign (& univnod, univ_name[cur_univ - 1]);
+ 					attrib ((& univnod), N_RDONLY);
+ 				}
+ #endif
+ 
  #if BRL
  				loginsh = 0;
  #endif

sources-request@genrad.UUCP (06/12/85)

From: Arnold Robbins <gatech!arnold>

This is part 9 of 9.  It contains the diffs for the manual page for the
System V Release 2 Bourne shell that comes with BRL Unix.  The original
man page is in /usr/5lib/man/u_man/man1/sh.1.

Arnold Robbins
arnold@gatech.{UUCP, CSNET}
--------------- You know what to do here -----------------------
*** ../orig.u/sh.1	Wed May 15 17:22:38 1985
--- sh.1	Wed Jun  5 11:08:21 1985
***************
*** 34,40
  .SH SYNOPSIS
  .B sh
  [
! .B \-acefhiknrstuvxEIJ
  ] [ args ]
  .SH DESCRIPTION
  .I Sh\^

--- 34,40 -----
  .SH SYNOPSIS
  .B sh
  [
! .B \-acefhiknqrstuvxEHIJ
  ] [ args ]
  .SH DESCRIPTION
  .I Sh\^
***************
*** 62,67
  .BR ? ,
  .BR \- ,
  .BR $ ,
  and
  .BR !\\^ .
  .SS Commands

--- 62,68 -----
  .BR ? ,
  .BR \- ,
  .BR $ ,
+ .BR + ,
  and
  .BR !\\^ .
  .SS Commands
***************
*** 436,441
  .B $
  The process number of this shell.
  .TP
  .B !
  The process number of the last background command invoked.
  .PD

--- 437,454 -----
  .B $
  The process number of this shell.
  .TP
+ .B +
+ The process number of the parent of this shell.  In particular,
+ the value of
+ .B $+
+ will track the value of the
+ .IR getppid (2)
+ system call.  I.e. if
+ .I init
+ should inherit this shell,
+ .B $+
+ will become 1.
+ .TP
  .B !
  The process number of the last background command invoked.
  .PD
***************
*** 525,530
  \f3\s-1PS1\s+1\fP
  prompt causes the shell to auto-terminate.
  Set to 0 to disable this BRL feature.
  .PD
  .RE
  .PP

--- 538,549 -----
  \f3\s-1PS1\s+1\fP
  prompt causes the shell to auto-terminate.
  Set to 0 to disable this BRL feature.
+ .TP
+ .B
+ .SM HISTFILE
+ The file where command history is saved across login sessions.
+ The default value is
+ .BR \s-1$HOME\s+1/.history .
  .PD
  .RE
  .PP
***************
*** 529,535
  .RE
  .PP
  The shell gives default values to
! \f3\s-1PATH\s+1\fP, \f3\s-1PS1\s+1\fP, \f3\s-1PS2\s+1\fP, \f3\s-1MAILCHECK\s+1\fP and \f3\s-1IFS\s+1\fP.
  .SM
  .B HOME
  and

--- 548,554 -----
  .RE
  .PP
  The shell gives default values to
! \f3\s-1HISTFILE\s+1\fP, \f3\s-1PATH\s+1\fP, \f3\s-1PS1\s+1\fP, \f3\s-1PS2\s+1\fP, \f3\s-1MAILCHECK\s+1\fP and \f3\s-1IFS\s+1\fP.
  .SM
  .B HOME
  and
***************
*** 537,542
  .B MAIL
  are set by
  .IR login (1).
  .SS Blank Interpretation
  After parameter and command substitution,
  the results of substitution are scanned for internal field separator

--- 556,782 -----
  .B MAIL
  are set by
  .IR login (1).
+ .SS Tilde Substitution
+ An unquoted tilde character
+ .RB ( ~ )
+ will cause the shell to attempt a tilde substituion.  Tilde substitutions
+ are used to automatically determine home directories.  Both the current
+ user's home directory, and the home directory of any other user on
+ the system may be found.
+ .PP
+ A
+ .B ~
+ by itself is equivalent to using
+ .BR \s-1$HOME\s+1 .
+ E.g.
+ .B ~/bin
+ is the same as saying
+ .BR \s-1$HOME\s+1/bin .
+ The notation
+ .B ~person
+ will cause the shell to look up
+ .BR person 's
+ home directory in the
+ .B /etc/passwd
+ file, and substitute it in.  For example, if user
+ .BR arnold 's
+ home directory is
+ .BR /user/arnold ,
+ the shell would replace
+ .BR ~arnold/bin
+ with
+ .BR /user/arnold/bin .
+ .PP
+ Tilde substitutions are recognized at the beginning of words, after
+ equal signs (for shell variable assignment), in the middle of single letter
+ flag arguments to commands (e.g. \fBecho \-t~arnold\fP), and after
+ colons inside the
+ .B
+ .SM PATH
+ and
+ .B
+ .SM CDPATH
+ shell parameters.
+ .PP
+ If
+ .B /etc/passwd
+ cannot be read, or if
+ no user can be found to match the attempted tilde substitution,
+ the text is left unmodified.
+ .SS History Substitution
+ When reading input from an interactive terminal, a
+ .RB `` ! ''
+ character, anywhere on the line,
+ signals the shell that it should attempt
+ to perform a history substitution.
+ A history substitution is a shorthand method which allows the user
+ to recall all or part of a previous command, possibly editing the
+ recalled portion.
+ The recalled (and possibly changed) command line is then placed into
+ the current command line,
+ to be passed on to the rest of the shell for normal processing.
+ A history substitution takes the form:
+ .PP
+ .if t .RS
+ \fB!\fP\^[ \fIstr\fP | \fB?\fIstr\fB?\fR | \fInum\fP ]\c
+ [ \fB\(ga\fInum\fR [ \- [ \fInum\fP ] ]\c
+ { \fB^\fIstr\fB^\fIstr\fB^\fR [\fBg\fP] }
+ .if t .RE
+ .PP
+ A history substitution contains three parts;
+ command selection, argument selection, and editing.
+ .I Command selection
+ chooses what command will be retrieved from the stored
+ history.
+ .I Argument selection
+ chooses which arguments from that command will be extracted.
+ .I Editing
+ allows the user to change spelling or make a substitution.
+ .PP
+ The history substitution is triggered by the
+ .RB `` ! '',
+ and continues until another
+ .RB `` ! ''
+ is encountered, or until
+ something that could not be part of a history substitution is seen.
+ This is so that the
+ history substitution will be properly concatenated with the following text.
+ Whenever a history substitution is encountered and properly performed,
+ the shell echoes the resulting line to the terminal and then executes the
+ command.
+ .PP
+ History substitution occurs inside double quotes and grave accents, but will
+ not occur inside single quotes.  To get a literal
+ .RB `` ! ''
+ character, outside of single quotes, precede it with a
+ .BR \e .
+ The
+ .BR ? ,
+ .BR \(ga ,
+ and
+ .B ^
+ characters are treated specially by the history mechanism only when preceded
+ by a
+ .RB `` ! '',
+ otherwise they have their normal meaning
+ of ``match a single character'',
+ ``enclose a command substitution'',
+ and as a synonym for the \fB\(bv\fP
+ character.
+ .PP
+ The full meaning of the history syntax is as follows:
+ .RS
+ .TP
+ \fB!\fP\^[ \fIstr\fP | \fB?\fIstr\fB?\fR | \fInum\fP ]
+ The first thing in a history substitution is
+ .IR "command selection" .
+ This is used to retrieve a given command line for use, or for further
+ processing.  In a history command selection, \fB!\fIstr\fR
+ will find the most recent command line that started with the
+ characters in
+ .IR str .
+ \fB!?\fIstr\fB?\fR will find the most recent command line that contained
+ .I str
+ anywhere on the line.  It also allows
+ .I str
+ to contain blanks and tabs, whereas the first form does not.
+ \fB!\fInum\fR allows the user to specify the number of a command, according
+ to the output of the
+ .B history
+ command (see the section on special commands, below).
+ .TP
+ \fB\(ga\fInum\fR [ \- [ \fInum\fP ]
+ The next portion of a history substitution is an optional
+ .IR "argument selection" .
+ This chooses which portions of the command are to be kept.
+ History arguments are not exactly the same as the arguments the rest of
+ the shell uses, since history expansion occurs before argument collection.
+ Arguments in this context are blank or tab separated words on the command line.
+ Single or double quoted strings, strings inside grave accents, shell regular
+ expressions, commands in parentheses (which get executed in a subshell),
+ and commands enclosed in braces,
+ are all treated as single arguments for the history mechanism, even though
+ they may have white space in them.
+ .sp
+ Arguments are numbered from zero, starting at the leftmost portion of the
+ line.  In an argument selection, \fB\(ga\fInum\fR specifies that only argument
+ .I num
+ is to be extracted and kept for further processing or use, and the rest
+ of the command line is to be dropped.
+ \fB\(ga\fInum\fB\-\fInum\fR
+ specifies that the arguments from the first
+ .I num
+ to the last
+ .I num
+ are to be kept. In place of any
+ .IR num ,
+ .B $
+ may be specified to obtain the last argument on the line.
+ The form \fB\(ga\-\fInum\fR is a shorthand for \fB\(ga\fP1\fB\-\fInum\fR
+ and
+ \fB\(ga\fInum\fB\-\fR
+ is a short form for
+ \fB\(ga\fInum\fB\-$\fR.
+ Finally, the notation
+ \fB\(ga\-\fP
+ indicates all the arguments.  That is, \fB\(ga\-\fP implies
+ \fB\(ga1\-$\fP.
+ .TP
+ \fB^\fIstr\fB^\fIstr\fB^\fR [\fBg\fP]
+ The last portion of a history substitution is also optional, and is the
+ .I editing
+ phase.  This allows the remaining portions of the retrieved
+ command line to modified, like the substitute command in
+ .IR ed (1),
+ although in a much more limited fashion.
+ In the history mechanism,
+ .I str
+ is not a regular expression, as in
+ .IR ed,
+ but just a simple string.
+ The history mechanism does not recognize
+ either the shell's pattern matching characters or the editor's
+ regular expression characters.
+ Each substitution happens only once on a line, unless a trailing ``g''
+ is appended to the substitution.  In this case, the substitution occurs
+ globally (everywhere) on the line.
+ Substitutions may be strung together,
+ so that more than one can be done at once.
+ The trailing ``g'' may be in either upper or lower case.
+ .RE
+ .PP
+ Some examples of history substitution are given below.
+ Should a history substitution fail, the errant command will
+ .I not
+ be added to the history buffers.
+ .PP
+ The history mechanism recognizes lines that end with unbalanced quotes.
+ When the quotes are balanced on the next line(s), 
+ It will join this line with the one that opened the quotes, keeping the
+ embedded newline(s). So, e.g.,
+ .RS
+ .sp
+ .nf
+ .RB "$ " "echo 'open"
+ .RB "> " "close'"
+ .fi
+ .RE
+ .sp
+ will be saved as one history ``event.''
+ This does
+ .I not
+ extend to other shell constructs, like balancing parentheses across
+ newlines.
+ .PP
+ The history mechanism keeps a maximum of
+ 256
+ stored commands at any one time, and the total text of the
+ stored history may occupy no more than
+ 4096
+ characters.
+ Experience indicates that it is not necessary to store more than this,
+ and the extra history buffers should not make the shell too large for
+ machines with small address spaces (e.g. PDP-11's).
  .SS Blank Interpretation
  After history, tilde, parameter and command substitution,
  the results of substitution are scanned for internal field separator
***************
*** 538,544
  are set by
  .IR login (1).
  .SS Blank Interpretation
! After parameter and command substitution,
  the results of substitution are scanned for internal field separator
  characters (those found in
  .BR \s-1IFS\s+1 )

--- 778,784 -----
  and the extra history buffers should not make the shell too large for
  machines with small address spaces (e.g. PDP-11's).
  .SS Blank Interpretation
! After history, tilde, parameter and command substitution,
  the results of substitution are scanned for internal field separator
  characters (those found in
  .BR \s-1IFS\s+1 )
***************
*** 593,598
  is a
  .RB `` ! ''
  any character not enclosed is matched.
  .PD
  .RE
  .SS Quoting

--- 833,843 -----
  is a
  .RB `` ! ''
  any character not enclosed is matched.
+ Note that when typing input from the terminal, the
+ .RB `` ! ''
+ should be preceded by a
+ .BR \e ,
+ so that the shell does not attempt to perform a history substitution.
  .PD
  .RE
  .SS Quoting
***************
*** 617,623
  are quoted.
  Inside double quote marks
  (\f3"\^"\fP),
! parameter and command substitution occurs and
  .B \e
  quotes the characters
  .BR \e ,

--- 862,868 -----
  are quoted.
  Inside double quote marks
  (\f3"\^"\fP),
! history, parameter, and command substitution occurs and
  .B \e
  quotes the characters
  .BR \e ,
***************
*** 623,628
  .BR \e ,
  .BR \*` ,
  \f3"\fP,
  and
  .BR $ .
  .B

--- 868,874 -----
  .BR \e ,
  .BR \*` ,
  \f3"\fP,
+ .BR ! ,
  and
  .BR $ .
  .B
***************
*** 660,665
  (i.e., the value of
  .BR \s-1PS2\s+1 )
  is issued.
  .SS Input/Output
  Before a command is executed, its input and output
  may be redirected using a special notation interpreted by the shell.

--- 906,971 -----
  (i.e., the value of
  .BR \s-1PS2\s+1 )
  is issued.
+ .PP
+ Many people like to have the shell provide them with useful information
+ in their prompt.  To accomadate this, the shell will recognize special
+ sequences of characters in the value of
+ .BR PS1 ,
+ and substitute the appropriate information for them.
+ The special sequences and what they signify are:
+ .RS
+ .TP
+ .B %d
+ Place the current working directory into the prompt.
+ .TP
+ .B %e
+ Place the current event number (as defined by the
+ .B history
+ command) into the prompt.
+ If history evaluation has been turned off (via
+ .BR "set -H" ),
+ no number will be substituted in (i.e. the
+ .B %e
+ will be removed).
+ .TP
+ .B %h
+ Place the machine's host name into the prompt.  The host name is usually
+ the name by which the machine is known to the outside world for electronic
+ mail addressing.
+ .ig
+ At Georgia Tech, a leading ``gt'' or ``gt-'' in the host name will be removed.
+ ..
+ .TP
+ .B %l
+ Place the user's login name into the prompt.
+ The login name selected is the first entry in the
+ .B /etc/passwd
+ file whose
+ .I uid
+ matches the value of the
+ .IR getuid (2)
+ system call.
+ This will be a problem on systems where multiple users share the same
+ user-id number.
+ .TP
+ .B %t
+ Place the current time of day, in the form \s-1HH:MM\s+1 into the prompt.
+ The time is on a 24 hour clock, i.e. 1:30 in the afternoon will be 13:30.
+ .TP
+ .BI % x
+ Place the character
+ .I x
+ into the prompt.
+ If the user wishes to put a literal
+ .B %
+ into the prompt, then
+ .B PS1
+ should have
+ .B %%
+ in it.
+ .RE
+ .PP
+ Some of these facilities are of more use than others.
  .SS Input/Output
  Before a command is executed, its input and output
  may be redirected using a special notation interpreted by the shell.
***************
*** 725,730
  all leading tabs are stripped from
  .I word\^
  and from the document.
  .TP
  .B <\h@-.1m@&digit
  Use the file associated with file descriptor

--- 1031,1038 -----
  all leading tabs are stripped from
  .I word\^
  and from the document.
+ History substitution is turned off
+ while processing the document.
  .TP
  .B <\h@-.1m@&digit
  Use the file associated with file descriptor
***************
*** 737,742
  The standard input is closed.
  Similarly for the standard output using
  .BR >\h@-.1m@&\h@-.1m@\- .
  .PD
  .PP
  If any of the above is preceded by a digit,

--- 1045,1058 -----
  The standard input is closed.
  Similarly for the standard output using
  .BR >\h@-.1m@&\h@-.1m@\- .
+ .TP
+ .B <\&>\&word
+ Use file
+ .I word
+ for standard input (file descriptor 0),
+ but open it for reading
+ .I and
+ writing.
  .PD
  .PP
  If any of the above is preceded by a digit,
***************
*** 806,812
  .BR "set -a" ).
  A parameter may be removed from the environment
  with the 
! .BR unset command.
  The environment seen by any executed command is thus composed
  of any unmodified name-value pairs originally inherited by the shell,
  minus any pairs removed by

--- 1122,1129 -----
  .BR "set -a" ).
  A parameter may be removed from the environment
  with the 
! .B unset
! command.
  The environment seen by any executed command is thus composed
  of any unmodified name-value pairs originally inherited by the shell,
  minus any pairs removed by
***************
*** 823,829
  Thus:
  .RS
  .PP
! \s-1TERM\s+1=450 \|cmd 				and
  .br
  (export \|\s-1TERM\s+1; \|\s-1TERM\s+1=450; \|cmd)
  .RE

--- 1140,1146 -----
  Thus:
  .RS
  .PP
! \s-1TERM\s+1=450 \|cmd                          and
  .br
  (export \|\s-1TERM\s+1; \|\s-1TERM\s+1=450; \|cmd)
  .RE
***************
*** 1083,1088
  adjacent to the \f2hits\fR information.
  \f2Cost\fR will be incremented when the recalculation is done.
  .TP
  \f3login\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  Equivalent to
  .BI "exec login" " arg\^"

--- 1400,1448 -----
  adjacent to the \f2hits\fR information.
  \f2Cost\fR will be incremented when the recalculation is done.
  .TP
+ \fBhistory\fP \*(OK \fB\-irs\fP \*(OK \fIfilename\fP \*(CK \*(CK
+ The \fBhistory\fP command, with no arguments, will print all the commands that
+ are currently saved in the shell's history buffers.  As new commands are
+ executed, and space in the buffers runs out, old commands will be deleted.  The
+ .B history
+ commands prints out the stored commands with sequence numbers.  Negative
+ numbered commands, through command number zero, are commands that were
+ retrieved from the saved history file.  Commands starting at one were
+ entered during the current login session.
+ If a saved command contains embedded newlines, these will be printed out
+ as the sequence
+ .BR \en ,
+ so that individual command stay on one line.
+ .sp
+ The \fBhistory\fP command takes two optional arguments.  If the first
+ argument is \fB\-s\fP, the shell will save its current history buffers
+ in the file named as the third argument. If no file is given, it will
+ use the value of
+ .BR \s-1HISTFILE\s+1 .
+ .sp
+ Similarly, if the first argument is \fB\-r\fP, the shell will reset its
+ history buffers from the saved history in the file given as the third argument.
+ Again, if no file name is given,
+ .B \s-1$HISTFILE\s+1
+ will be used.
+ .sp
+ The command
+ .B history -i
+ will cause the shell to reinitialize its history buffers.  In other words,
+ all the shell's saved history will be thrown away, and the shell will
+ start from scratch.
+ .sp
+ The \fBhistory\fP command will have absolutely no effect at all if input
+ is not coming from a terminal.  I.e., inside shell files, the
+ .B history
+ command is effectively a null operation.
+ .sp
+ The
+ .B history
+ command will always have an exit status of 1 inside a shell file.
+ If input is coming from a terminal, then the exit status wil be 0
+ if the command succeeds, 1 otherwise.
+ .TP
  \f3login\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK
  Equivalent to
  .BI "exec login" " arg\^"
***************
*** 1136,1142
  .I n 
  is omitted, the return status is that of the last command executed.
  .TP
! \f3set\fP \*(OK \f3\-\-aefhkntuvxEIJ\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK \*(CK
  .RS
  .TP
  .B \-a

--- 1496,1502 -----
  .I n 
  is omitted, the return status is that of the last command executed.
  .TP
! \f3set\fP \*(OK \f3\-\-aefhkntuvxEHIJ\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK \*(CK
  .RS
  .TP
  .B \-a
***************
*** 1180,1185
  .IR .profile\^ s
  to avoid accidental logout.
  .TP
  .B \-I
  (BRL addition)
  Prints a resource usage summary

--- 1540,1562 -----
  .IR .profile\^ s
  to avoid accidental logout.
  .TP
+ .B \-H
+ Disable history processing.  If the shell is invoked with this option,
+ it will not bother trying to restore its saved history from the
+ contents of
+ .BR \s-1$HISTFILE\s+1 .
+ While this flag is in effect, the shell will not save any commands in
+ its history buffers.
+ The sequence
+ .B %e
+ in the value of
+ .B \s-1PS1\s+1
+ will also have no effect on the generated prompt string.
+ If
+ .B set +H
+ is used to turn history processing back on, the shell will start saving
+ subsequent commands from that point on.
+ .TP
  .B \-I
  (BRL addition)
  Prints a resource usage summary
***************
*** 1332,1337
  and from
  .BR \s-1$HOME\s+1/.profile ,
  if such files exist.
  Thereafter, commands are read as described below, which
  is also the case when the shell is invoked as
  .BR /bin/sh .

--- 1709,1726 -----
  and from
  .BR \s-1$HOME\s+1/.profile ,
  if such files exist.
+ Next, whether or not the first character of argument zero was a
+ .BR \- ,
+ and no matter how the shell was invoked,
+ the shell will read commands from the file
+ .BR \s-1$HOME\s+1/.shrc ,
+ if it exists.
+ Then, if the shell is interactive, is not a forked subshell,
+ and the
+ .B \-H
+ flag is not in effect,
+ it will attempt to restore its saved history from
+ .BR \s-1$HISTFILE\s+1 .
  Thereafter, commands are read as described below, which
  is also the case when the shell is invoked as
  .BR /bin/sh .
***************
*** 1340,1345
  the
  .B \-J
  (job control) flag is automatically set.
  The flags below are interpreted by the shell on invocation only; note
  that unless the 
  .B \-c

--- 1729,1740 -----
  the
  .B \-J
  (job control) flag is automatically set.
+ .ig
+ At Georgia Tech, job control is always turned on, even if the
+ .B \-J
+ flag was not given, and even if argument zero did not contain a
+ .BR j .
+ ..
  The flags below are interpreted by the shell on invocation only; note
  that unless the 
  .B \-c
***************
*** 1388,1393
  If the
  .B \-r
  flag is present the shell is a restricted shell.
  .PD
  .PP
  The remaining flags and arguments are described under the

--- 1783,1799 -----
  If the
  .B \-r
  flag is present the shell is a restricted shell.
+ .TP
+ .B \-q
+ If the
+ .B \-q
+ flag is present, the shell will do a ``quick'' startup.
+ This means that the shell will
+ .I not
+ read the contents of the
+ .B \s-1$HOME\s+1/.shrc
+ file.
+ The shell will also not try to read this file if it is a restricted shell.
  .PD
  .PP
  The remaining flags and arguments are described under the
***************
*** 1425,1430
  If the process group
  .I n\^
  is not specified then the ``current job'' is resumed.
  .PD
  .PP
  With job control enabled,

--- 1831,1842 -----
  If the process group
  .I n\^
  is not specified then the ``current job'' is resumed.
+ .TP
+ .B suspend
+ Suspend the shell process itself in the background.
+ The shell will complain
+ if it is a login shell, and will not suspend itself.
+ Otherwise, it does not matter whether or not job control is enabled.
  .PD
  .PP
  With job control enabled,
***************
*** 1441,1446
  If the specified job number is one of the known jobs,
  then this expression is replaced by
  the corresponding process group number.
  .PD
  .SH EXIT STATUS
  Errors detected by the shell, such as syntax errors,

--- 1853,1886 -----
  If the specified job number is one of the known jobs,
  then this expression is replaced by
  the corresponding process group number.
+ .SS Saving and Restoring History
+ When an interactive shell starts up, if the
+ .B \-H
+ flag is not in effect, it will attempt to read the contents of
+ .B \s-1$HISTFILE\s+1
+ into its history buffers.  This allows the user to recall commands
+ executed during a previous login session.
+ When the shell exits or executes an
+ .B exec
+ (again, if
+ .B \-H
+ is not in effect), it will attempt to write its current history
+ buffers into
+ .BR \s-1$HISTFILE\s+1 ,
+ for use in a future login session.
+ .PP
+ The
+ .B history
+ command allows the user to save the current history buffers into
+ a file of his or her own choosing, or to restore them from a given file.
+ If
+ .B \-H
+ has been set, the
+ .B history
+ command will give a warning that history processing is not
+ available, and will
+ .I not
+ save or restore the shell's history buffers.
  .PD
  .SH EXIT STATUS
  Errors detected by the shell, such as syntax errors,
***************
*** 1457,1462
  .br
  \s-1$HOME\s+1/\f3.\fPprofile
  .br
  /tmp/sh\(**
  .br
  /dev/null

--- 1897,1904 -----
  .br
  \s-1$HOME\s+1/\f3.\fPprofile
  .br
+ \s-1$HOME\s+1/\f3.\fPshrc
+ .br
  /tmp/sh\(**
  .br
  /dev/null
***************
*** 1464,1469
  acctcom(1),
  cd(1),
  echo(1),
  env(1),
  login(1),
  newgrp(1),

--- 1906,1912 -----
  acctcom(1),
  cd(1),
  echo(1),
+ ed(1),
  env(1),
  login(1),
  newgrp(1),
***************
*** 1477,1482
  dup(2),
  exec(2),
  fork(2),
  pipe(2),
  signal(2),
  ulimit(2),

--- 1920,1927 -----
  dup(2),
  exec(2),
  fork(2),
+ getppid(2),
+ getuid(2),
  pipe(2),
  signal(2),
  ulimit(2),
***************
*** 1510,1512
  .B login
  command is replaced by
  .BR newgrp .

--- 1955,2071 -----
  .B login
  command is replaced by
  .BR newgrp .
+ .SH PYRAMID SPECIFIC
+ .PP
+ On computers manufactured by the Pyramid Corporation, which support
+ both the University of California at Berkeley 4.2BSD version of \s-1UNIX\s+1,
+ and the AT&T System V version of \s-1UNIX\s+1,
+ the shell has several additional capabilities.
+ .SS Special Commands
+ .PP
+ There are three additional commands built in to the shell. They are:
+ .RS
+ .TP
+ \fBatt\fP \*(OK command \*(CK
+ Switch the current ``universe'' to be ATT System V.
+ If a command is specified, that command will be run in the ``att''
+ universe, without affecting the shell's current universe.
+ The
+ .B \-t
+ option of
+ .B /bin/att
+ is not (yet) supported.
+ .TP
+ \fBucb\fP \*(OK command \*(CK
+ Switch the current ``universe'' to be University of California at
+ Berkeley 4.2BSD.
+ If a command is specified, that command will be run in the ``ucb''
+ universe, without affecting the shell's current universe.
+ The
+ .B \-t
+ option of
+ .B /bin/ucb
+ is not (yet) supported.
+ .TP
+ \fBuniverse\fP \*(OK \fB\-l\fP \*(CK
+ Print the current universe, either ``att'' or ``ucb''. The
+ .B \-l
+ option will print a longer, more explanative name for the current universe.
+ .RE
+ .PP
+ If the shell cannot determine the current universe when it starts up,
+ it will default to
+ .BR ucb .
+ .SS Shell Variables
+ .PP
+ There is an additional pre-defined shell parameter,
+ .BR \s-1UNIVERSE\s+1 .
+ The value of
+ .B \s-1UNIVERSE\s+1
+ .I always
+ tracks that of the current universe.  Using it is equivalent to a
+ \*`universe\` command substitution,
+ except that a new process will not be created.
+ This variable cannot be set by the user (it is \fBreadonly\fP),
+ and any inherited value from the environment will be ignored.
+ .SS Special Sequences for \s-1PS1\s+1
+ .PP
+ Finally, the sequence
+ .B %u
+ in the value of
+ .B \s-1PS1\s-1
+ will cause the shell to subsitute in the name of the current universe,
+ either ``att'' or ``ucb''.
+ .SH HISTORY EXAMPLES
+ Command history provides a powerful method for easily redoing previous
+ commands, or for quicly fixing typing mistakes.
+ Here are some annotated examples.  User input is in
+ .BR boldface .
+ .sp
+ .nf
+ # first, list some files
+ .RB "$ " lf
+ hello.c		echo.c
+ # now, make a typing mistake
+ .RB "$ " "cat hello"
+ hello: No such file or directory
+ # fix it.  The trailing ! ends the history substitution,
+ # in order to correctly concatenate it with the following .c
+ .RB "$ " "!!.c"
+ cat hello.c
+ main () { printf ("hello world\en"); }
+ # now look at echo.c instead
+ .RB "$ " "!^hello^echo"
+ cat echo.c
+ main () { printf ("echo: no arguments\en"); }
+ # do it again, just for fun
+ .RB "$ " "!"
+ cat echo.c
+ main () { printf ("echo: no arguments\en"); }
+ # now we'll rearrange some arguments
+ .RB "$ " "echo 1 2 3 4 5"
+ 1 2 3 4 5
+ # print last argument, first and second arguments, then change 4 to four
+ .RB "$ " "echo !\(ga$ !\(ga1-2 !\(ga4^4^four"
+ echo 5 1 2 four
+ 5 1 2 four
+ # do something with all the previous arguments at once
+ .RB "$ " "echo the previous arguments were !\(ga\-"
+ echo the previous arguments were 5 1 2 four
+ the previous arguments were 5 1 2 four
+ # now do some substitutions.  first get something to work with.
+ .RB "$ " "echo aa bb cc"
+ aa bb cc
+ # change the first 'a' to a 'b', and change all c's to d's
+ .RB "$ " "!^a^b^^c^d^g"
+ echo ba bb dd
+ ba bb dd
+ .fi
+ .PP
+ These few brief examples should provide a general feel for the
+ history mechanism.  The quickest way to learn it is to experiment
+ with it for a while, using the
+ .B echo
+ command, which can do very little damage.
+ While it looks cryptic when being typed, it is very general and
+ orthogonal, and quickly becomes natural.