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)"E)==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)"E)==0 ANDF _ctype1[c]&(T_SPC)) *************** *** 79,85 #define subchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_SUB|T_QOT)) #define escchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_ESC)) ! char _ctype2[]; #define digit(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DIG)) #define fngchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_FNG)) --- 82,88 ----- #define subchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_SUB|T_QOT)) #define escchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_ESC)) ! extern char _ctype2[]; #define digit(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DIG)) #define dolchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS)) *************** *** 82,89 char _ctype2[]; #define digit(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DIG)) ! #define fngchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_FNG)) ! #define dolchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN)) #define defchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DEF)) #define setchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_SET)) #define digchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST|T_DIG)) --- 85,91 ----- extern char _ctype2[]; #define digit(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DIG)) ! #define dolchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS)) #define defchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DEF)) #define setchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_SET)) #define digchar(c) (((c)"E)==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)"E)==0 && _ctype2[c]&(T_DIG)) ! #define dolchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN)) #define defchar(c) (((c)"E)==0 && _ctype2[c]&(T_DEF)) #define setchar(c) (((c)"E)==0 && _ctype2[c]&(T_SET)) #define digchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_DIG)) --- 80,86 ----- extern char _ctype2[]; #define digit(c) (((c)"E)==0 && _ctype2[c]&(T_DIG)) ! #define dolchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS)) #define defchar(c) (((c)"E)==0 && _ctype2[c]&(T_DEF)) #define setchar(c) (((c)"E)==0 && _ctype2[c]&(T_SET)) #define digchar(c) (((c)"E)==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)"E)==0 && _ctype2[c]&(T_DIG)) ! #define dolchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN)) #define defchar(c) (((c)"E)==0 && _ctype2[c]&(T_DEF)) #define setchar(c) (((c)"E)==0 && _ctype2[c]&(T_SET)) #define digchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_DIG)) --- 80,86 ----- extern char _ctype2[]; #define digit(c) (((c)"E)==0 && _ctype2[c]&(T_DIG)) ! #define dolchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN|_PLS)) #define defchar(c) (((c)"E)==0 && _ctype2[c]&(T_DEF)) #define setchar(c) (((c)"E)==0 && _ctype2[c]&(T_SET)) #define digchar(c) (((c)"E)==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.