%%s 9/38/988 %%d D 1.5 03-Aug-83 08:35:07 tools 5 4 %%c Removed catsub routine and modified subst to be able to invoke library %%c version of catsub. %%s 181/107/845 %%d D 1.4 26-Jul-83 22:18:27 sventek 4 3 %%c Added the 'q' command, the '!' command negation and fixed a bug dealing %%c with a numeric line number as the second address. These fixes are due %%c to Layne Cannon at Pacific Northwest Laboratories. %%s 10/10/942 %%d D 1.3 22-Jul-83 11:58:07 sventek 3 2 %%c Eliminated periods at end of quoted strings, as they are no longer needed. %%s 209/141/743 %%d D 1.2 01-Mar-83 05:22:28 cannon 2 1 %%c Modified by Layne Cannon (Battelle Northwest Labs) to match changes made %%c in pattern matching library routines and to correct multiple other problems. %%c Sedit now has the same search/replacement capabilities as ed. %%s 0/0/0 %%d D 1.1 25-Mar-82 12:13:07 v1.1 1 0 %%c Version 1.1 is the Spring 1982 Distribution of the LBL/Hughes release %%c of the Software Tools Virtual Operating System software and documentation. %%T %%I 1 #-h- patdef 787 asc 25-mar-82 08:38:03 v1.1 (sw-tools v1.1) ## definitions for the pattern matching routines # put on a file named 'defns' # Used by pattern.r and ed & sedit tools define(ANY,'?') define(BOL,'%') define(BOT,'{') define(CCL,'[') define(CCLEND,']') define(CHAR,'a') define(CLOSIZE,4) define(CLOSURE,'*') define(CLOSURE1,'+') # closure of one or more occurrences # i.e. (pat)+ == (pat)(pat)* define(COUNT,1) define(EOL,'$') define(EOT,'}') define(MAXTAG,10) define(NCCL,'n') define(PREVCL,2) define(START,3) define(DITTO,(-3)) define(SECTION,(-4)) # /ctag/ - common block to hold section limits for ch # put in a file called 'ctag' # Used by find, ch, and ed #common /ctag/ taglim(MAXTAG2) #integer taglim define(I_CTAG,common/ctag/taglim(arith(2,*,MAXTAG)) integer taglim) %%D 2 #-h- csedit 673 asc 25-mar-82 08:38:05 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 4 #-h- csedit 671 asc 28-feb-83 09:59:30 cannon (layne cannon) %%E 4 %%E 2 %%I 4 #-h- csedit 733 asc 26-jul-83 22:12:21 sventek (joseph sventek) %%E 4 ## common block for csedit tool # put on a file called 'csedit' # (used only by csedit) common /csedit/ aq, iq, buf(MAXBUF), lastbf, nlines, line1, line2, %%D 4 pat(MAXPAT), prevc, nflag %%E 4 %%I 4 pat(MAXPAT), prevc, nflag, qflag %%E 4 integer aq # end of append queue integer iq # end of insert queue %%D 2 character buf # buf for commands %%E 2 %%I 2 integer buf # buf for commands %%E 2 integer lastbf # next available character in buf integer nlines # number of line number expressions integer line1 # line number 1 or index to pattern integer line2 # line number 2 or index to pattern %%D 2 character pat # current pattern during compilation %%E 2 %%I 2 integer pat # current pattern during compilation %%E 2 integer prevc # index of previous command integer nflag # YES to print result of "p" commands only %%D 2 #-h- sedit.r 19532 asc 25-mar-82 08:38:16 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 3 #-h- sedit.r 20524 asc 28-feb-83 17:03:03 cannon (layne cannon) %%E 3 %%E 2 %%I 3 %%D 4 #-h- sedit.r 20531 asc 22-jul-83 11:56:19 sventek (joseph sventek) %%E 4 %%E 3 %%D 4 #-h- defns 1620 asc 25-mar-82 08:36:40 v1.1 (sw-tools v1.1) %%E 4 %%I 4 integer qflag # YES indicates quit command executed %%D 5 #-h- sedit.r 21094 asc 26-jul-83 22:12:26 sventek (joseph sventek) %%E 5 %%I 5 #-h- sedit.r 20281 asc 03-aug-83 08:33:59 tools (lblh csam sventek) %%E 5 #-h- defns 1928 asc 31-mar-83 12:11:31 cannon (layne cannon) %%E 4 # include ratdef define(NLINES,0) # number of line numbers define(NEXT,1) # index of next command define(LINE1,2) # line number 1 or index of pattern define(LINE2,3) # line number 2 or index of pattern %%D 4 define(COMMAND,4) # command define(LIST,5) # next command on insert/append list define(TEXT,6) # text for insert/append or file name for read %%E 4 %%I 4 define(STATE,4) # command state define(OKSTATE,0) # normal command state define(NOTSTATE,1) # DONT - execute only lines NOT referenced define(DELSTATE,2) # deleted command - dont execute define(COMMAND,5) # command define(LIST,6) # next command on insert/append list define(TEXT,7) # text for insert/append or file name for read %%E 4 define(APPENDCOM,'a') # append command define(CHANGECOM,'c') # change command define(DELETECOM,'d') # delete command define(INSERTCOM,'i') # insert command define(PRINTCOM,'p') # print command %%I 4 define(QUITCOM,'q') # quit command %%E 4 define(READCOM,'r') # read command define(SUBSTCOM,'s') # substitute command define(SUBSTGFLAG,COMMAND+1) # YES for global replacement define(SUBSTPFLAG,COMMAND+2) # YES for print define(SUBSTPAT,COMMAND+3) # index of pattern define(SUBSTNEW,COMMAND+4) # index of replacement define(WRITECOM,'w') # write command define(WRITEFD,COMMAND+1) # file descriptor for opened file or 0 %%D 4 define(EQUALCOM,'=') # print line number command %%E 4 %%I 4 define(EQUALCOM,'=') # print line number command define(DONTCOM,'!') # DONT flag for commands - negate line requests %%E 4 define(INSERTLIST,1) # location of list of inserts define(APPENDLIST,LIST+1) # location of list of appends define(COMMANDLIST,1) # location of command list define(FIRSTFREE,APPENDLIST+TEXT) # first free location in buf ifdef(LARGE_ADDRESS_SPACE) define(MAXBUF,20000) elsedef define(MAXBUF,5000) # size of command buffer enddef define(LASTLINE,'$') define(OK,YES) # to be compatible with addset/insstr define(GLOBAL,'g') # for getrhs define(PRINT,'p') # for ckp define(DITTO,(-3)) define(MAXNAME,FILENAMESIZE) include patdef %%D 2 #-h- main 2653 asc 25-mar-82 08:36:45 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 3 #-h- main 2968 asc 28-feb-83 11:38:07 cannon (layne cannon) %%E 3 %%E 2 %%I 3 %%D 4 #-h- main 2968 asc 22-jul-83 11:55:17 sventek (joseph sventek) %%E 4 %%E 3 %%I 4 #-h- main 3012 asc 01-apr-83 11:35:44 cannon (layne cannon) %%E 4 # sedit - stream editor DRIVER(sedit) %%D 2 character arg(MAXLINE), linbuf(MAXLINE) %%E 2 %%I 2 character arg(MAXLINE), linbuf(MAXLINE), clower %%E 2 integer i, j, nfiles, fd integer length, getarg, open, getlin include csedit %%D 2 string use "usage: sedit [-n] {[-e script | -f sfiles] ... | script} [file]..." %%E 2 %%I 2 string use "usage: sedit [-n] {[-e script | -f sfiles]... | script} [file]..." %%E 2 call query(use) %%D 2 prevc = COMMANDLIST # initialize lists %%E 2 %%I 2 prevc = COMMANDLIST # initialize lists %%E 2 buf(COMMANDLIST+NEXT) = 0 %%I 2 buf(INSERTLIST+LIST) = 0 buf(APPENDLIST+LIST) = 0 %%E 2 lastbf = FIRSTFREE nflag = NO %%I 4 qflag = NO %%E 4 nfiles = 0 i = 1 if (getarg (i, arg, MAXLINE) == EOF) call error(use) %%D 2 if (arg(1) == '-' & arg(2) == 'n') { %%E 2 %%I 2 if (arg(1) == '-' & clower(arg(2)) == 'n') { %%E 2 nflag = YES i = i + 1 } %%D 2 for (; getarg(i, arg, MAXLINE) != EOF; i = i + 2) if (arg(1) == '-' & arg(2) == 'f') { # -f filename if (getarg(i + 1, arg, MAXLINE) == EOF) call error(use) fd = open(arg, READ) if (fd == ERR) call cant(arg) %%E 2 %%I 2 for (; getarg(i, arg, MAXLINE) != EOF; i=i+1) if (arg(1) == '-' & clower(arg(2)) == 'f') # -f filename { if (arg(3) != EOS) call scopy( arg, 3, arg, 1) else { i = i+1 if (getarg(i, arg, MAXLINE) == EOF) call error(use) } if (arg(1) == '-' & arg(2) == EOS) fd = STDIN else fd = open(arg, READ) if (fd == ERR) call cant(arg) %%E 2 while (getlin(arg, fd) != EOF) call compil(arg, fd) %%D 2 call close(fd) %%E 2 %%I 2 if (fd != STDIN) call close(fd) %%E 2 } %%D 2 else if (arg(1) == '-' & arg(2) == 'e') { # -e script if (getarg(i + 1, arg, MAXLINE) == EOF) call error(use) %%E 2 %%I 2 else if (arg(1) == '-' & clower(arg(2)) == 'e') # -e script { if (arg(3) != EOS) call scopy( arg, 3, arg, 1) else { i = i+1 if (getarg(i, arg, MAXLINE) == EOF) call error(use) } %%E 2 j = length(arg) arg(j+1) = '@n' arg(j+2) = EOS call compil(arg, NO) } %%D 2 else # no flags %%E 2 %%I 2 else # no more flags %%E 2 break %%D 2 if (lastbf == FIRSTFREE) { # use argument as script %%E 2 %%I 2 if (lastbf == FIRSTFREE) # use arg as script { %%E 2 if (getarg(i, arg, MAXLINE) == EOF) call error(use) j = length(arg) arg(j+1) = '@n' arg(j+2) = EOS call compil(arg, NO) i = i + 1 } linbuf(1) = EOS lineno = 0 %%D 2 call docmds(linbuf, 0) # do line 0 commands for (; getarg(i, arg, MAXLINE) != EOF; i = i + 1) { %%E 2 %%I 2 %%D 4 call docmds(linbuf, 0) # do line 0 commands for (; getarg(i, arg, MAXLINE) != EOF; i = i + 1) %%E 4 %%I 4 call docmds(linbuf,0) # line 0 commands for (; qflag!=YES & getarg(i,arg,MAXLINE)!=EOF; i = i + 1) %%E 4 { %%E 2 if (arg(1) == '-' & arg(2) == EOS) fd = STDIN else fd = open(arg, READ) if (fd == ERR) call cant(arg) call sed(linbuf, lineno, fd) if (fd != STDIN) call close(fd) nfiles = nfiles + 1 } %%D 4 if (nfiles == 0) %%E 4 %%I 4 if (qflag!=YES & nfiles == 0) %%E 4 call sed(linbuf, lineno, STDIN) %%D 2 if (linbuf(1) != EOS) { # set last line number and do last line %%E 2 %%I 2 %%D 4 if (linbuf(1) != EOS) # set last line number and do last line %%E 4 %%I 4 if (qflag!=YES & linbuf(1) != EOS) # set last line number and do last line %%E 4 { %%E 2 lineno = lineno + 1 %%D 2 for (i = buf(COMMANDLIST+NEXT); i > 0; i = buf(i+NEXT)) { %%E 2 %%I 2 for (i = buf(COMMANDLIST+NEXT); i > 0; i = buf(i+NEXT)) { %%E 2 if (buf(i+LINE1) == -HUGE) buf(i+LINE1) = -lineno if (buf(i+LINE2) == -HUGE) buf(i+LINE2) = -lineno %%D 2 if (buf(i+COMMAND) == CHANGECOM) #clean unsatisfied c commands %%E 2 %%I 2 if (buf(i+COMMAND) == CHANGECOM) # clean unsatisfied c commands %%E 2 { if (buf(i+NLINES) == 2) %%D 2 buf(i+NLINES) = 1 # insures changed text is output %%E 2 %%I 2 buf(i+NLINES) = 1 # insure changed text is output %%E 2 if (buf(i+NLINES) == 3 & (buf(i+LINE2) > 0 | -buf(i+LINE2) >= lineno)) buf(i+LINE2) = -lineno } } call docmds(linbuf, lineno) } DRETURN end %%D 2 #-h- insstr 339 asc 25-mar-82 08:36:48 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- insstr 311 asc 28-feb-83 10:01:41 cannon (layne cannon) %%E 2 # insstr - add s to str(j) if it fits, increment j integer function insstr(s, str, j, maxsiz) %%D 2 character s(ARB), str(ARB) integer j, maxsiz integer i, addset %%E 2 %%I 2 character s(ARB) integer j, maxsiz, str(ARB) integer i, addint, int %%E 2 for (i = 1; s(i) != EOS; i = i + 1) %%D 2 if (addset(s(i), str, j, maxsiz) == NO) { insstr = NO return } insstr = YES return %%E 2 %%I 2 { int = s(i) if (addint(int, str, j, maxsiz) == NO) return(NO) } return(YES) %%E 2 end %%D 2 #-h- subcat 484 asc 25-mar-82 08:36:50 v1.1 (sw-tools v1.1) ## subcat - add replacement text to end of new. subroutine subcat(lin, from, to, sub, new, k, maxnew) integer addset integer from, i, j, junk, k, maxnew, to character lin(MAXLINE), new(maxnew), sub(MAXPAT) for (i = 1; sub(i) != EOS; i = i + 1) if (sub(i) == DITTO) for (j = from; j < to; j = j + 1) junk = addset(lin(j), new, k, maxnew) else junk = addset(sub(i), new, k, maxnew) return end %%E 2 %%I 2 %%D 3 #-h- subcat 839 asc 28-feb-83 16:07:09 cannon (layne cannon) %%E 3 %%I 3 %%D 4 #-h- subcat 838 asc 22-jul-83 11:55:20 sventek (joseph sventek) %%E 4 %%E 3 %%I 4 %%D 5 #-h- subcat 839 asc 28-feb-83 16:07:09 cannon (layne cannon) %%E 5 %%E 4 %%D 5 ## CatSub -- Add replacement text to end of new. ## This is the same as "rlib.w`pattern.r`catsub" except 'sub' is integer. subroutine subcat( lin, from, to, sub, new, k, maxnew) integer addset # function(s) integer from, i, j, junk, k, maxnew, to, sub(MAXPAT) character lin(MAXLINE), new(maxnew) I_CTAG # include ctag common block for( i = 1 ; sub(i) != EOS ; i = i + 1 ) { if( sub(i) == DITTO ) for( j = from ; j < to ; j = j + 1 ) junk = addset( lin(j), new, k, maxnew) else if( sub(i) == SECTION ) { i = i + 1 n = sub(i) if( n <= 0 | n > MAXTAG ) { %%E 5 %%D 3 call remark( "? In CatSub: illegal section." ) %%E 3 %%I 3 %%D 4 call remark( "? In CatSub: illegal section" ) %%E 4 %%E 3 %%I 4 %%D 5 call remark( "? In CatSub: illegal section." ) %%E 5 %%E 4 %%D 5 next } for( j = taglim( 2 * n - 1 ) ; j < taglim( 2 * n ) ; j = j + 1 ) junk = addset( lin(j), new, k, maxnew) } else junk = addset( sub(i), new, k, maxnew) } return end %%E 5 %%E 2 #-h- ckp 373 asc 25-mar-82 08:36:52 v1.1 (sw-tools v1.1) # ckp - check for "p" after command integer function ckp(lin, i, pflag, status) character lin(MAXLINE) integer i, j, pflag, status character clower j = i if (clower(lin(j)) == PRINT) { j = j + 1 pflag = YES } else pflag = NO if (lin(j) == '@n') status = OK else status = ERR ckp = status return end %%D 2 #-h- compil 3006 asc 25-mar-82 08:36:54 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 3 #-h- compil 2902 asc 28-feb-83 10:01:44 cannon (layne cannon) %%E 3 %%E 2 %%I 3 %%D 4 #-h- compil 2899 asc 22-jul-83 11:55:21 sventek (joseph sventek) %%E 4 %%E 3 %%I 4 #-h- compil 3071 asc 26-jul-83 22:11:35 sventek (joseph sventek) %%E 4 # compil - "compile" command in lin(i) from file fd, increment i subroutine compil(lin, fd) %%D 2 character lin(MAXLINE) %%E 2 %%I 2 character lin(MAXLINE), com %%E 2 integer fd character file(MAXNAME), sub(MAXPAT) %%D 2 integer i, gflag, pflag, status, fdw integer addset, insstr, create, getrhs, getfn, ckp, optpat, dotext, getlst, length %%E 2 %%I 2 integer i, j, gflag, pflag, status, fdw integer addint, addsi, insstr, addpat, patsiz integer create, getrhs, getfn, ckp, optpat, dotext, getlst, length %%E 2 character clower include csedit status = ERR i = 1 if (getlst(lin, i, status) == ERR) { call putlin(lin, ERROUT) %%D 3 call error("bad line numbers.") %%E 3 %%I 3 call error("bad line numbers") %%E 3 } call skipbl(lin, i) %%D 2 buf(prevc+NEXT) = lastbf # link in new command %%E 2 %%I 2 buf(prevc+NEXT) = lastbf # link in new command %%E 2 prevc = lastbf %%D 2 status = addset(nlines, buf, lastbf, MAXBUF) status = addset(0, buf, lastbf, MAXBUF) status = addset(line1, buf, lastbf, MAXBUF) status = addset(line2, buf, lastbf, MAXBUF) #fold commands to lower case status = addset(clower(lin(i)), buf, lastbf, MAXBUF) if (clower(lin(i)) == APPENDCOM & lin(i+1) == '@n' & fd != NO) { status = addset(0, buf, lastbf, MAXBUF) %%E 2 %%I 2 status = addint(nlines, buf, lastbf, MAXBUF) status = addint(0, buf, lastbf, MAXBUF) status = addint(line1, buf, lastbf, MAXBUF) status = addint(line2, buf, lastbf, MAXBUF) com = clower(lin(i)) #fold commands to lower case %%I 4 if (com == DONTCOM) { #check for command state status = addint(NOTSTATE, buf, lastbf, MAXBUF) i = i+1 call skipbl(lin, i) com = clower(lin(i)) } else status = addint(OKSTATE, buf, lastbf, MAXBUF) %%E 4 status = addint(com, buf, lastbf, MAXBUF) %%D 4 if (com == APPENDCOM & lin(i+1) == '@n' & fd != NO) { %%E 4 %%I 4 if (com == APPENDCOM & fd != NO) { %%E 4 status = addint(0, buf, lastbf, MAXBUF) %%E 2 status = dotext(fd) } %%D 2 else if (clower(lin(i)) == CHANGECOM & lin(i+1) == '@n' & fd != NO) { status = addset(0, buf, lastbf, MAXBUF) %%E 2 %%I 2 %%D 4 else if (com == CHANGECOM & lin(i+1) == '@n' & fd != NO) { %%E 4 %%I 4 else if (com == CHANGECOM & fd != NO) { %%E 4 status = addint(0, buf, lastbf, MAXBUF) %%E 2 status = dotext(fd) } %%D 2 else if (clower(lin(i)) == DELETECOM & lin(i+1) == '@n') %%E 2 %%I 2 %%D 4 else if (com == DELETECOM & lin(i+1) == '@n') %%E 4 %%E 2 %%I 4 else if (com == DELETECOM) %%E 4 status = OK %%D 2 else if (clower(lin(i)) == INSERTCOM & lin(i+1) == '@n' & fd != NO) { status = addset(0, buf, lastbf, MAXBUF) %%E 2 %%I 2 %%D 4 else if (com == INSERTCOM & lin(i+1) == '@n' & fd != NO) { %%E 4 %%I 4 else if (com == INSERTCOM & fd != NO) { %%E 4 status = addint(0, buf, lastbf, MAXBUF) %%E 2 status = dotext(fd) } %%D 2 else if (clower(lin(i)) == PRINTCOM & lin(i+1) == '@n') %%E 2 %%I 2 %%D 4 else if (com == PRINTCOM & lin(i+1) == '@n') %%E 4 %%E 2 %%I 4 else if (com == PRINTCOM) %%E 4 status = OK %%D 2 else if (clower(lin(i)) == READCOM) { status = addset(0, buf, lastbf, MAXBUF) %%E 2 %%I 2 %%I 4 else if (com == QUITCOM) status = OK %%E 4 else if (com == READCOM) { status = addint(0, buf, lastbf, MAXBUF) %%E 2 status = getfn(lin, i, file) if (status == OK) { status = insstr(file, buf, lastbf, MAXBUF) %%D 2 status = addset(EOS, buf, lastbf, MAXBUF) %%E 2 %%I 2 status = addint(EOS, buf, lastbf, MAXBUF) %%E 2 } } %%D 2 else if (clower(lin(i)) == SUBSTCOM) { %%E 2 %%I 2 else if (com == SUBSTCOM) { %%E 2 i = i + 1 if (optpat(lin, i) == OK) andif (getrhs(lin, i, sub, gflag) == OK) status = ckp(lin, i + 1, pflag, status) if (status == OK) { %%D 2 status = addset(gflag, buf, lastbf, MAXBUF) status = addset(pflag, buf, lastbf, MAXBUF) status = addset(lastbf + 2, buf, lastbf, MAXBUF) status = addset(lastbf + length(pat) + 2, buf, lastbf, MAXBUF) status = insstr(pat, buf, lastbf, MAXBUF) status = addset(EOS, buf, lastbf, MAXBUF) %%E 2 %%I 2 status = addint(gflag, buf, lastbf, MAXBUF) status = addint(pflag, buf, lastbf, MAXBUF) status = addint(lastbf+2, buf, lastbf, MAXBUF) for (j=1; pat(j)!=EOS; j=j+patsiz(pat,j)); status = addint(lastbf+j+1, buf, lastbf, MAXBUF) status = addpat(pat, buf, lastbf, MAXBUF) %%E 2 status = insstr(sub, buf, lastbf, MAXBUF) %%D 2 status = addset(EOS, buf, lastbf, MAXBUF) %%E 2 %%I 2 status = addint(EOS, buf, lastbf, MAXBUF) %%E 2 } } %%D 2 else if (clower(lin(i)) == WRITECOM) { %%E 2 %%I 2 else if (com == WRITECOM) { %%E 2 status = getfn(lin, i, file) if (status == OK) { fdw = create(file, WRITE) if (fdw == ERR) call cant(file) } %%D 2 status = addset(fdw, buf, lastbf, MAXBUF) %%E 2 %%I 2 status = addint(fdw, buf, lastbf, MAXBUF) %%E 2 } %%D 2 else if (clower(lin(i)) == EQUALCOM & lin(i+1) == '@n') %%E 2 %%I 2 %%D 4 else if (com == EQUALCOM & lin(i+1) == '@n') %%E 4 %%E 2 %%I 4 else if (com == EQUALCOM) %%E 4 status = OK else status = ERR if (status != OK) { call putlin(lin, ERROUT) if (lastbf > MAXBUF) %%D 3 call error("too many commands.") %%E 3 %%I 3 call error("too many commands") %%E 3 else %%D 3 call error("invalid command.") %%E 3 %%I 3 call error("invalid command") %%E 3 } return end %%D 2 #-h- docmds 2291 asc 25-mar-82 08:36:59 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 3 #-h- docmds 2289 asc 28-feb-83 14:23:44 cannon (layne cannon) %%E 3 %%E 2 %%I 3 %%D 4 #-h- docmds 2288 asc 22-jul-83 11:55:24 sventek (joseph sventek) %%E 4 %%E 3 %%I 4 #-h- docmds 2263 asc 26-jul-83 22:11:37 sventek (joseph sventek) %%E 4 # docmds-execute commands in buf on linbuf, which contains line lineno subroutine docmds(linbuf, lineno) character linbuf(MAXLINE) integer lineno %%D 4 integer i, n %%E 4 %%I 4 integer i, n, state %%E 4 integer match include csedit aq = APPENDLIST # initialize append and insert queues buf(aq+LIST) = 0 iq = INSERTLIST buf(iq+LIST) = 0 %%D 4 for (i = buf(COMMANDLIST+NEXT); i != 0; i = buf(i+NEXT)) { %%E 4 %%I 4 for (i = buf(COMMANDLIST+NEXT); i != 0; i = buf(i+NEXT)) { %%E 4 nlines = buf(i+NLINES) line1 = buf(i+LINE1) line2 = buf(i+LINE2) %%D 4 if (nlines == 0) call docom(i, linbuf, lineno) else if (nlines == 1) { if (-line1 == lineno) call docom(i, linbuf, lineno) else if (line1 > 0) andif (match(linbuf, buf(line1)) > 0) call docom(i, linbuf, lineno) %%E 4 %%I 4 state = buf(i+STATE) if (nlines<=0) # no line addr { if (lineno > 0) if (state==OKSTATE) call docom(i, linbuf, lineno) } else if (nlines<=2) # 1 or 2 addr inactive { if (line1<=0) # numeric { if (-line1==lineno) { if (nlines == 2) buf(i+NLINES) = 3 if (state==OKSTATE) call docom(i, linbuf, lineno) } else if (lineno>0 & state==NOTSTATE) # ! number call docom(i, linbuf, lineno) } else if (lineno > 0) { if (match(linbuf,buf(line1)) > 0) # pattern { if (nlines == 2) buf(i+NLINES) = 3 if (state==OKSTATE) call docom(i, linbuf, lineno) } else # ! pattern if (state==NOTSTATE) call docom(i, linbuf, lineno) } %%E 4 } %%D 4 else if (nlines == 2) { # 2 line numbers, searching for line1 if (-line1 == lineno) { buf(i+NLINES) = 3 # found it, change state call docom(i, linbuf, lineno) } else if (line1 > 0) andif (match(linbuf, buf(line1)) > 0) { buf(i+NLINES) = 3 call docom(i, linbuf, lineno) } } else if (nlines == 3) { # 2 line numbers, searching for line2 if (line2 <= 0) { if (lineno >= -line2) buf(i+NLINES) = 2 # found it, change state if (lineno <= -line2) call docom(i, linbuf, lineno) } else if (line2 > 0) { if (match(linbuf, buf(line2)) > 0) %%E 4 %%I 4 else if (nlines == 3) # 2 line addr active { if (line2 <= 0 & lineno >= -line2) # searching for line2 buf(i+NLINES) = 2 # found it, new state else if (line2 > 0) if (match(linbuf, buf(line2)) > 0) %%E 4 buf(i+NLINES) = 2 %%D 4 call docom(i, linbuf, lineno) } %%E 4 %%I 4 if (state == OKSTATE) # always within range call docom(i, linbuf, lineno) %%E 4 } else %%D 3 call error("in docmds: can't happen.") %%E 3 %%I 3 call error("in docmds: can't happen") %%E 3 %%D 4 if (linbuf(1) == EOS & lineno > 0) %%E 4 %%I 4 if (qflag==YES | (linbuf(1)==EOS & lineno>0)) %%E 4 break } %%D 4 # output inserts %%E 4 %%I 4 # output inserts %%E 4 for (i = buf(INSERTLIST+LIST); i > 0; i = buf(i+LIST)) %%D 2 call putlin(buf(i+TEXT), STDOUT) %%E 2 %%I 2 call putsi(buf(i+TEXT), STDOUT) %%E 2 if (nflag == NO) call putlin(linbuf, STDOUT) %%D 4 # output appends %%E 4 %%I 4 # output appends %%E 4 for (i = buf(APPENDLIST+LIST); i > 0; i = buf(i+LIST)) if (buf(i+COMMAND) == READCOM) %%D 4 call copyf(buf(i+TEXT), STDOUT) # do r command %%E 4 %%I 4 call copyf(buf(i+TEXT), STDOUT) # do r command %%E 4 else %%D 2 call putlin(buf(i+TEXT), STDOUT) %%E 2 %%I 2 call putsi(buf(i+TEXT), STDOUT) %%E 2 return end %%D 2 #-h- docom 1250 asc 25-mar-82 08:37:02 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 4 #-h- docom 1244 asc 28-feb-83 09:57:38 cannon (layne cannon) %%E 4 %%E 2 %%I 4 #-h- docom 1290 asc 31-mar-83 10:52:52 cannon (layne cannon) %%E 4 # docom - execute a single command at buf(i) on linbuf and lineno subroutine docom(i, linbuf, lineno) character linbuf(MAXLINE) integer i, lineno character cmd %%D 2 integer k1, k2, junk %%E 2 %%I 2 integer k1, k2 %%E 2 include csedit cmd = buf(i+COMMAND) if (cmd == APPENDCOM) { buf(aq+LIST) = i aq = i buf(i+LIST) = 0 } else if (cmd == CHANGECOM) { linbuf(1) = EOS if (buf(i+NLINES) <= 2) { buf(aq+LIST) = i aq = i buf(i+LIST) = 0 } } else if (cmd == DELETECOM) linbuf(1) = EOS else if (cmd == INSERTCOM) { buf(iq+LIST) = i iq = i buf(i+LIST) = 0 } else if (cmd == PRINTCOM) call putlin(linbuf, STDOUT) %%I 4 else if (cmd == QUITCOM) qflag = YES %%E 4 else if (cmd == READCOM) { buf(aq+LIST) = i aq = i buf(i+LIST) = 0 } else if (cmd == SUBSTCOM) { k1 = buf(i+SUBSTPAT) k2 = buf(i+SUBSTNEW) call subst(linbuf, buf(k1), buf(k2), buf(i+SUBSTGFLAG), buf(i+SUBSTPFLAG)) } else if (cmd == WRITECOM) { if (buf(i+WRITEFD) != 0) call putlin(linbuf, buf(i+WRITEFD)) } else if (cmd == EQUALCOM) { call putdec(lineno, 1) call putc('@n') } # else ignore command return end %%D 2 #-h- dotext 376 asc 25-mar-82 08:37:04 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- dotext 376 asc 28-feb-83 09:57:39 cannon (layne cannon) %%E 2 # dotext - append text in file fd onto buf integer function dotext(fd) integer fd %%D 2 integer getlin, addset, insstr %%E 2 %%I 2 integer getlin, addint, insstr %%E 2 character lin(MAXLINE) include csedit while (getlin(lin, fd) != EOF) { if (lin(1) == '.' & lin(2) == '@n') break junk = insstr(lin, buf, lastbf, MAXBUF) } %%D 2 dotext = addset(EOS, buf, lastbf, MAXBUF) %%E 2 %%I 2 dotext = addint(EOS, buf, lastbf, MAXBUF) %%E 2 return end %%D 2 #-h- copyf 339 asc 25-mar-82 08:37:06 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- copyf 458 asc 28-feb-83 09:57:40 cannon (layne cannon) %%E 2 # copyf - copy file name to opened file fdo subroutine copyf(name, fdo) %%D 2 character name(ARB) %%E 2 %%I 2 integer name(ARB) %%E 2 integer fdo %%D 2 integer fdi %%E 2 %%I 2 integer fdi, i %%E 2 integer open %%D 2 character c %%E 2 %%I 2 character c, namstr(MAXLINE) %%E 2 character getch %%D 2 fdi = open(name, READ) %%E 2 %%I 2 for (i=1; name(i)!=EOS; i=i+1) #get name into string namstr(i) = name(i) namstr(i) = EOS fdi = open(namstr, READ) %%E 2 if (fdi == ERR) %%D 2 call cant(name) %%E 2 %%I 2 call cant(namstr) %%E 2 while (getch(c, fdi) != EOF) call putch(c, fdo) call close(fdi) return end #-h- getfn 457 asc 25-mar-82 08:37:08 v1.1 (sw-tools v1.1) # getfn - get file name from lin(i)... integer function getfn(lin, i, file) character lin(MAXLINE), file(MAXLINE) integer i, j, k getfn = ERR if (lin(i + 1) == ' ' | lin(i + 1) == '@t') { j = i + 2 # get new file name call skipbl(lin, j) for (k = 1; lin(j) != '@n'; k = k + 1) { file(k) = lin(j) j = j + 1 } file(k) = EOS if (k > 1) getfn = OK } return end #-h- getlst 503 asc 25-mar-82 08:37:10 v1.1 (sw-tools v1.1) # getlst - get a list of line numbers starting at lin(i), increment i integer function getlst(lin, i, status) character lin(MAXLINE) integer i integer status # ignored integer num integer getone include csedit nlines = 0 if (getone(lin, i, num) == EOF) return(OK) line1 = num nlines = nlines + 1 if (lin(i) != ',') return(OK) i = i + 1 if (getone(lin, i, num) != OK) return(ERR) line2 = num nlines = nlines + 1 return(OK) end %%D 2 #-h- getone 1020 asc 25-mar-82 08:37:13 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- getone 963 asc 28-feb-83 11:58:20 cannon (layne cannon) %%E 2 # getone - evaluate one line number expression, increment i integer function getone(lin, i, num) character lin(MAXLINE) integer i, istart, num %%D 2 integer insstr, addset, ctoi, optpat %%E 2 %%I 2 integer addpat, ctoi, optpat %%E 2 include csedit getone = OK call skipbl(lin, i) istart = i if (lin(i) >= '0' & lin(i) <= '9') { num = ctoi(lin, i) i = i - 1 # move back; to be advanced at the end if (num < 0) getone = ERR num = -num } else if (lin(i) == LASTLINE) num = -HUGE else if (lin(i) == '/') { if (optpat(lin, i) == ERR) # build the pattern getone = ERR else if (lin(i) == '/') { num = lastbf %%D 2 junk = insstr(pat, buf, lastbf, MAXBUF) if (addset(EOS, buf, lastbf, MAXBUF) == NO) %%E 2 %%I 2 if (addpat(pat, buf, lastbf, MAXBUF) == NO) %%E 2 getone = ERR } } else getone = EOF if (getone == OK) i = i + 1 # point at next character to be examined call skipbl(lin, i) if (i <= istart) getone = EOF else getone = OK return end #-h- getrhs 494 asc 25-mar-82 08:37:14 v1.1 (sw-tools v1.1) # getrhs - get substitution string for "s" command integer function getrhs(lin, i, sub, gflag) character lin(MAXLINE), sub(MAXPAT) integer maksub character clower integer gflag, i getrhs = ERR if (lin(i) == EOS) return if (lin(i + 1) == EOS) return i = maksub(lin, i + 1, lin(i), sub) if (i == ERR) return if (clower(lin(i + 1)) == GLOBAL) { i = i + 1 gflag = YES } else gflag = NO getrhs = OK return end %%D 2 #-h- maksub 648 asc 25-mar-82 08:37:15 v1.1 (sw-tools v1.1) ## maksub - make substitution string in sub (/*/sor/chr) integer function maksub(arg, from, delim, sub) character esc character arg(MAXARG), delim, sub(MAXPAT) integer addset integer from, i, j, junk j = 1 for (i = from; arg(i) != delim & arg(i) != EOS; i = i + 1) if (arg(i) == AND) junk = addset(DITTO, sub, j, MAXPAT) else junk = addset(esc(arg, i), sub, j, MAXPAT) if (arg(i) != delim) # missing delimiter maksub = ERR else if (addset(EOS, sub, j, MAXPAT) == NO) # no room maksub = ERR else maksub = i return end %%E 2 #-h- optpat 546 asc 25-mar-82 08:37:15 v1.1 (sw-tools v1.1) # optpat - make pattern if specified at lin(i) integer function optpat(lin, i) character lin(MAXLINE) integer makpat integer i include csedit if (lin(i) == EOS) i = ERR else if (lin(i + 1) == EOS) i = ERR else if (lin(i + 1) == lin(i)) # repeated delimiter i = i + 1 # leave existing pattern alone else i = makpat(lin, i + 1, lin(i), pat) if (pat(1) == EOS) i = ERR if (i == ERR) { pat(1) = EOS optpat = ERR } else optpat = OK return end %%D 4 #-h- sed 818 asc 25-mar-82 08:37:17 v1.1 (sw-tools v1.1) %%E 4 %%I 4 #-h- sed 839 asc 01-apr-83 12:41:49 cannon (layne cannon) %%E 4 # sed-execute all commands for file fd, use linbuf and increment lineno subroutine sed(linbuf, lineno, fd) character linbuf(MAXLINE) integer lineno, fd character buf1(MAXLINE), buf2(MAXLINE) integer getlin include csedit if (getlin(buf1, fd) == EOF) return if (lineno > 0) { # do previous last line lineno = lineno + 1 call docmds(linbuf, lineno) } %%D 4 repeat { if (getlin(buf2, fd) == EOF) { # buf1 contains last line %%E 4 %%I 4 while (qflag != YES) { if (getlin(buf2, fd) == EOF) { # buf1 contains last line %%E 4 call scopy(buf1, 1, linbuf, 1) break } lineno = lineno + 1 call docmds(buf1, lineno) %%D 4 if (getlin(buf1, fd) == EOF) { # buf2 contains last line call scopy(buf2, 1, linbuf, 1) break } lineno = lineno + 1 call docmds(buf2, lineno) %%E 4 %%I 4 if (qflag != YES) { if (getlin(buf1, fd) == EOF) { # buf2 contains last line call scopy(buf2, 1, linbuf, 1) break } lineno = lineno + 1 call docmds(buf2, lineno) } %%E 4 } return end %%D 2 #-h- subst 1001 asc 25-mar-82 08:37:20 v1.1 (sw-tools v1.1) %%E 2 %%I 2 %%D 5 #-h- subst 989 asc 28-feb-83 09:56:27 cannon (layne cannon) %%E 5 %%E 2 %%I 5 #-h- subst 1085 asc 03-aug-83 08:30:55 tools (lblh csam sventek) %%E 5 # subst - substitute sub for occurrences of pat in txt %%D 5 subroutine subst(txt, pat, sub, gflag, pflag) %%E 5 %%D 2 character txt(MAXLINE), pat(ARB), sub(ARB) integer gflag, pflag character new(MAXLINE) %%E 2 %%I 2 %%D 5 integer pat(ARB), sub(ARB), gflag, pflag character txt(MAXLINE), new(MAXLINE) %%E 5 %%E 2 %%I 5 subroutine subst(txt, pat, isub, gflag, pflag) integer pat(ARB), isub(ARB), gflag, pflag character txt(MAXLINE), new(MAXLINE), sub(MAXPAT) %%E 5 integer addset, amatch integer j, junk, k, lastm, m, subbed j = 1 subbed = NO lastm = 0 %%I 5 for (k = 1; isub(k) != EOS; k = k + 1) sub(k) = isub(k) sub(k) = EOS %%E 5 for (k = 1; txt(k) != EOS; ) { if (gflag == YES | subbed == NO) m = amatch(txt, k, pat) else m = 0 if (m > 0 & lastm != m) { # replace matched text subbed = YES %%D 5 call subcat(txt, k, m, sub, new, j, MAXLINE) %%E 5 %%I 5 call catsub(txt, k, m, sub, new, j, MAXLINE) %%E 5 lastm = m } if (m == 0 | m == k) { # no match or null match junk = addset(txt(k), new, j, MAXLINE) k = k + 1 } else # skip matched text k = m } if (subbed == YES) { if (addset(EOS, new, j, MAXLINE) == NO) return call scopy(new, 1, txt, 1) if (pflag == YES) call putlin(txt, STDOUT) } return end %%D 2 #-h- sedit.fmt 4790 asc 25-mar-82 08:38:33 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- addpat 385 asc 28-feb-83 10:01:51 cannon (layne cannon) # addpat - add pattern to buffer for storage integer function addpat(p,str,j,maxsiz) integer p(ARB), str(ARB) integer j, maxsiz integer i, lim, addint, patsiz for (lim=1; p(lim)!=EOS; lim=lim+patsiz(p,lim)) ; for (i=1; i<=lim; i=i+1) { if (addint(p(i), str, j, maxsiz) == NO) { addpat = NO return } } addpat = YES return end #-h- addsi 318 asc 25-feb-83 13:46:33 cannon (layne cannon) # addsi - add s to str(j) if it fits, increment j ## add a string of integers integer function addsi(s, str, j, maxsiz) integer s(ARB) integer j, maxsiz, str(ARB) integer i, addint, int for (i = 1; s(i) != EOS; i = i + 1) if (addint( s(i), str, j, maxsiz) == NO) return(NO) return(YES) end #-h- putsi 198 asc 28-feb-83 14:21:24 cannon (layne cannon) ## putsi - write character string (in integer format) to file subroutine putsi(str, fd) integer str(ARB), fd, i for (i=1; str(i)!=EOS; i=i+1) call putch(str(i),fd) return end %%D 4 #-h- sedit.fmt 4957 asc 01-mar-83 05:15:38 cannon (layne cannon) %%E 4 %%E 2 %%I 4 #-h- sedit.fmt 5501 asc 26-jul-83 22:12:37 sventek (joseph sventek) %%E 4 .so ~bin/manhdr %%D 2 .hd Sedit (1) 30-Nov-79 %%E 2 %%I 2 %%D 4 .hd Sedit (1) 1-Mar-83 %%E 4 %%E 2 %%I 4 .hd Sedit (1) 26-Jul-83 %%E 4 stream editor .sy %%D 4 sedit [-n] {[-e script | -f sfile]... | script} [file]... %%E 4 %%I 4 sedit [-n] [[-e] command] ... [-f commandfile] ... [file] ... %%E 4 .ds %%D 4 sedit copies the named input files to the standard output, performing editing as directed by sedit commands in "script" or in "sfile". %%E 4 %%I 4 sedit copies the input files (default is standard input) to the standard output, performing one or more editing commands (see 'ed') on each line. .sp The -n flag indicates that only lines that are explicitly printed by 'p' commands are to be copied to the standard output. Double copies of some lines will be output if the 'p' command is used without specifying the -n flag. .sp %%E 4 The -e flag indicates that the next argument is %%D 4 to be interpreted as an sedit command (see below). %%E 4 %%I 4 a sedit command. .sp %%E 4 The -f flag indicates that the next argument is the name of a file in which sedit commands appear one per line. %%I 4 .sp %%E 4 The -e and -f arguments may be intermixed in any order. The order of command execution is the order in which commands are read. %%I 4 .sp %%E 4 If no -e or -f flags are given, the first argument is used as an sedit command. %%D 4 Normally, sedit writes each line of input to the output after editing; the -n option suppresses this action. As a result, the only output is that resulting from sedit commands. %%E 4 When the first argument not in the scope of a flag is encountered, it and all succeeding arguments are taken as input files. If no files are given, or if the name "-" is specified, the standard input is read. .sp Sedit commands have the general form .sp .in +3 .nf %%D 4 line1 [, line2] command arguments %%E 4 %%I 4 line1 [, line2] [!] command arguments %%E 4 .in -3 .sp .fi A line number (line1 or line2) is either a decimal number that refers to a specific input line (input lines are counted cumulatively across files), a "$" that refers to the last line of input, %%D 2 or a /pattern/ where pattern is a regular expression (as in edit). %%E 2 %%I 2 or a /pattern/ where pattern is a regular expression (as in 'ed'). %%E 2 Line number 0 may be used to specify commands that should be executed before any input is read. .sp A command with no line numbers is applied to every line of input. A command with one line number is applied to every line of input that matches the line number. A command with two line numbers is applied to every line of input beginning with the first line that matches line1 through the next line that %%D 4 matches line2. Thereafter, the process is repeated, looking again %%E 4 %%I 4 matches line2. Thereafter, the process is repeated, looking again %%E 4 for a line that matches line1. .sp %%D 4 Sedit accepts the following commands. Each command may be %%E 4 %%I 4 A command is negated by placing the '!' character after the line numbers and before the command character. This has the effect of executing the command on all of the lines except the ones specified. .sp There is no notion of '.' and no relative addressing. No expressions in addresses are allowed. There are no backward pattern searches with '\'. A 'p' at the end of a command only works with the 's' command. .sp If an 'a', 'i', 'c', or 'r' command is successfully executed, the text is inserted into the standard output whether or not the line on which the match was made is later deleted or not. Text inserted in the output stream by these commands is not scanned for any pattern matches, nor are any sedit commands applied to it, nor will it effect the input line numbering. .sp Sedit accepts the following commands. Each command may be %%E 4 used with 0, 1, or 2 line numbers. %%D 4 The a, c, and i commands may not appear in command line scripts. %%E 4 %%I 4 Any of the commands may appear on the 'sedit' command line except the a, c, and i commands. They can only be used in command files. %%E 4 .sp .nf %%I 2 .ne 5 %%E 2 .cc + a . +cc . .fi .in +3 %%D 4 Append. The is placed on the output after each selected line. The does not change the line number nor is it subject to subsequent sedit commands. %%E 4 %%I 4 Append. The is placed on the output after each selected line. %%E 4 .in -3 .sp .ne 5 .nf .cc + c . +cc . .fi .in +3 %%D 4 Change. The selected lines are deleted and %%E 4 %%I 4 Change. The selected lines are deleted and %%E 4 is placed on the output in their place. %%D 4 The does not change the line number nor is it subject to subsequent sedit commands. %%E 4 .in -3 .sp d .in +3 %%D 4 Delete. The selected lines are deleted. %%E 4 %%I 4 Delete. The selected lines are deleted. %%E 4 .in -3 .sp .nf .cc + i . +cc . .fi .in +3 %%D 4 Insert. The is placed on the output before each selected line. The does not change the line number nor is it subject to subsequent sedit commands. %%E 4 %%I 4 Insert. The is placed on the output before each selected line. %%E 4 .in -3 .sp p .in +3 %%D 4 Print. The selected lines are printed on the standard output. %%E 4 %%I 4 Print. The selected lines are printed on the standard output. %%E 4 .in -3 .sp %%I 4 q .in +3 Quit. The current line is output (unless the -n option is specified) and no further processing is done. .in -3 .sp %%E 4 r file .in +3 %%D 4 Read file. The contents of "file" are placed on the output after %%E 4 %%I 4 Read file. The contents of "file" are placed on the output after %%E 4 each selected line exactly as if the contents were given as in an %%D 4 a command. The new lines do not change the line number nor are they subject to subsequent sedit commands. %%E 4 %%I 4 a command. %%E 4 .in -3 .sp s/pat/new/gp .in +3 %%D 4 Substitute. The leftmost %%E 4 %%D 2 occurrences of pat in the selected lines is changed to new. %%E 2 %%I 2 %%I 4 Substitute. The leftmost %%E 4 occurrences of pat in the selected lines are changed to new. %%E 2 %%D 4 If g is specified, all occurrences are changed. If p is %%E 4 %%I 4 If g is specified, all occurrences are changed. If p is %%E 4 specified, the resulting line is printed. %%I 2 The search string 'pat' is a regular expression as defined for 'ed'. The replacement string 'new' also uses the same conventions as 'ed' for search string replacement (&, and $1...$9). %%E 2 %%I 4 Subsequent sedit commands will only match the resulting lines. %%E 4 .in -3 .sp w file .in +3 %%D 4 Write file. The selected lines are appended to "file". Files %%E 4 %%I 4 Write file. The selected lines are appended to "file". Files %%E 4 mentioned in w commands are created before processing begins. The limit on the number of w commands depends on the number of files that can be opened at the same time. .in -3 .sp = .in +3 %%D 4 Print line number. The current line number is printed %%E 4 %%I 4 Print line number. The current line number is printed %%E 4 on the output as a line. .in -3 .sp %%D 4 Text appended by a, c, or r commands is placed on the output in the same order as the execution of the commands. Similar comments apply to text inserted by i commands. .sp %%E 4 Sedit %%D 2 can accomodate commands totaling approximately 5000 characters (including arguments), and lines up to 120 characters in length. %%E 2 %%I 2 can accomodate commands (including arguments), totaling approximately 5000 characters (20,000 if LARGE_ADDRESS_SPACE is defined). %%E 2 .fi .sa %%D 2 edit, change, find, tr %%E 2 %%I 2 ed, change, tr %%E 2 .di In addition to the usual error messages resulting from file access %%D 2 failure, sedit issues the following messages preceeding by the %%E 2 %%I 2 failure, sedit issues the following messages preceded by the %%E 2 offending command line. .sp bad line numbers .in +3 indicates that the line number expressions are invalid. .in -3 .sp invalid command .in +3 indicates that the command preceeding the message is illegal. This message is issued for a, i, or c commands if they appear in command string scripts. .in -3 .sp too many commands .in +3 indicates exhaustion of space to hold commands. The size of the command buffer is determined by the MAXBUF definition in the source code. .in -3 .au %%D 4 Chris Fraser (U. of Arizona) %%E 4 %%D 2 .bu %%E 2 %%D 4 .br %%E 4 %%D 2 The '$' indicator for end-of-file doesn't always work. %%E 2 %%I 2 Layne Cannon (Battelle Northwest Labs) %%I 4 .br Chris Fraser (U. of Arizona) %%E 4 .bu %%E 2 %%E 1