%%s 4/4/2783 %%d D 1.2 09-Apr-82 10:46:02 j 2 1 %%c Reordered the statements in sh.w`sh.r`rlogin to conform with normal %%c statement ordering. Moved the string declaration after all other %%c declarations and before the first executable statement. %%s 0/0/0 %%d D 1.1 25-Mar-82 12:13:36 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- eshdef 123 asc 25-mar-82 08:45:05 v1.1 (sw-tools v1.1) define(prompt,ledpmt) #define(IMBED_ED,) define(DO_STARTUP,) define(USE_STRING,"usage: esh [-cdnvx] [file [arguments]].") #-h- hshdef 104 asc 25-mar-82 08:45:06 v1.1 (sw-tools v1.1) define(prompt,logpmt) define(DO_STARTUP,) define(USE_STRING,"usage: hsh [-cdnvx] [file [arguments]].") #-h- cpars 537 asc 25-mar-82 08:45:07 v1.1 (sw-tools v1.1) # /cpars/ - holds token and tree info for shell # put on a file called 'cpars' # Used only by the shell common /cpars/ tkbuf(TSIZE, MAXTOK), tree(TREESIZE), stack(MAXSTACK), treend, pp, ibuf(MAXLINE) integer tkbuf #token table for parsing integer tree #parse tree integer stack #push down stack for tokens integer treend #next available tree node; init by parse integer pp #push down counter; init by parse character ibuf #input buffer #-h- csclin 160 asc 25-mar-82 08:45:11 v1.1 (sw-tools v1.1) ## csclin - scratch line for shell # put on a file called 'csclin' common / csclin / lin(MAXLINE) character lin # scratch line for use throughout the shell. #-h- shflag 900 asc 25-mar-82 08:45:12 v1.1 (sw-tools v1.1) # shflag - common block to hold shell flags # put on a file called 'shflag' # Used only by the shell common /shflag/ exec, prlin, prcom, carg, drop, cargdn, shin, logfd, inunit, clin(MAXLINE) integer exec # flag to cause/suppress command execution # init = YES integer prlin # flag to cause printing of lines as read # init = NO integer prcom # flag to cause printing of command as executed # init = NO integer carg # flag to cause execution of shell command line as input # init = NO integer drop # flag to cause drop-through to native CLI upon search # error - init = YES integer cargdn # YES if -c & arguments have been fetched. integer shin # file identifier for shell input (generally STDIN) integer logfd # open unit for reading login.sh integer inunit # input unit for shell character clin # buffer to hold shell arg to be used as input #-h- stdsub 1131 asc 25-mar-82 08:45:12 v1.1 (sw-tools v1.1) # /stdsub/ - common block holding file info for shell # put on a file named 'stdsub' # Used only by the shell common /stdsub/ in, cin(MAXSTACK), out, cout(MAXSTACK), er, cerr(MAXSTACK), aout(MAXSTACK), script, pctr, pfile(MAXSTACK), hfile(FILENAMESIZE), input(FILENAMESIZE), sh(FILENAMESIZE), spath(MAXPATHSIZE), olddir(FILENAMESIZE), homedr(FILENAMESIZE) integer in # input stack count integer cin # input substitution stack integer out # output stack count integer cout # output stack integer er # errout stack count integer cerr # errout stack integer aout # append flag integer script # flag showing if script file being processed integer pctr # running pipe count character pfile # names of pipe files character hfile # names of heredocument files character input # holds name of standard input file for script # init input(1) = EOS character sh # holds name of shell for script and background character spath # search path for loccom calls - initialized by initsh character olddir # name of `previous' directory. character homedr # name of home directory. #-h- shcmd 636 asc 25-mar-82 08:45:16 v1.1 (sw-tools v1.1) ## ShCmd -- Common block holding shell commands # Put on a file called 'shcmd' # Used only by the shell common /shcmd/ cd(3), e(2), ho(3), home(5), logout(7), von(4), voff(5), xon(4), xoff(5), shopth(5) character cd # change working directory character e # Enter embedded editor character ho # change to home directory character home # synonym for ``ho'' character logout # logout from shell character von # equivalent to `-v' in command line character voff # turns off `von' character xon # equivalent to `xon' in command line character xoff # turns off `xon' character shopth # command to show search path %%D 2 #-h- sh.r 38879 asc 25-mar-82 08:45:31 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- sh.r 38872 asc 09-apr-82 10:29:32 j (sventek j) %%E 2 #-h- defns 1902 asc 25-mar-82 08:42:12 v1.1 (sw-tools v1.1) # definitions for shell # put on a file named 'defns' # Used only by the shell define(TSIZE,4) define(MAXSHLINE,MAXLINE) # maximum command line length define(SHELL,17) # flag for shell command define(IBPTR,1) # array index for token pointers define(TMARK,2) # array index for token marks define(NODEPTR,3) # array index for node pointers define(ESCAN,4) # array index for end of scan define(MAXTOK,132) # max token size define(TREESIZE,200) # max size of tree define(ROOT,-1) # flag for beginning of tree define(PARENT,1) define(NTYPE,2) define(LCHILD,3) define(RCHILD,4) define(REDIN,5) define(REDOUT,6) define(REDERR,7) define(NENT,8) define(CMD,9) define(ARGUMENT,10) define(COM,'c') define(PAR,'p') define(SSYNTAX,0) define(SSYN1,1) define(SSYN2,2) define(SSYN3,3) define(MAXSTACK,15) define(PIPE,'|') define(SEPCHAR,';') define(SCRIPT,2) define(OWNER,-1) # flag for receiving message from parent define(BUFSIZE,MAXLINE) define(COMMENTCHAR,'#') define(MAXPATHSIZE,arith(FILENAMESIZE,*,3)) # max size of search path define(PB_SIZE,512) # size of push back buffer #define(DEBUG,) # if defined, issue debug statements ifdef(DEBUG) # macro definitions when debugging define(debug_int,call putlin($1,ERROUT);call putint($2,5,ERROUT) call putch('@n',ERROUT)) define(debug_str,call putlin($1,ERROUT);call putstr($2,5,ERROUT) call putch('@n',ERROUT)) define(debug_token,call putch('@n',ERROUT);debug_int("token #",$1) debug_int(" TMARK:",tkbuf(TMARK,$1)) debug_int(" NODE:",tkbuf(NODEPTR,$1)) debug_int(" ESCAN:",tkbuf(ESCAN,$1))) define(debug_node,call putch('@n',ERROUT);debug_int("node #",$1) debug_int(" parent:",tree($1+PARENT)) debug_str(" type:",tree($1+NTYPE)) debug_int(" Lchild:",tree($1+LCHILD)) debug_int(" Rchild:",tree($1+RCHILD))) enddef ifnotdef(USE_STRING) define(USE_STRING,"usage: sh [-cdnvx] [file [arguments]].") enddef #-h- main 569 asc 25-mar-82 08:42:14 v1.1 (sw-tools v1.1) ## sh - driver subroutine for DEH shell DRIVER(sh) character line(MAXSHLINE) integer parser, shline call query(USE_STRING) call initsh repeat { if (shline(line) == EOF) break if (line(1) == '@n' | line(1) == COMMENTCHAR) next if (line(1) == '?' & line(2) == '@n') { call remark("Type intro for an introduction to the tools.") next } if (parser(line) == ERR) call remark ("syntax error.") else call execut } call endsh(EOF) DRETURN end #-h- arglin 419 asc 25-mar-82 08:42:15 v1.1 (sw-tools v1.1) ## arglin - pick up all arguments starting with i subroutine arglin (buf, i) character buf(ARB) integer i, k, m integer getarg include csclin k = 1 for (j=i; getarg(j, lin, MAXLINE) != EOF; j=j+1) { if (lin(1) == ESCAPE & lin(2) == '<' ) m = 2 else m = 1 call stcopy(lin, m, buf, k) call chcopy( ' ', buf, k) } if (k > 1) k = k - 1 #delete last blank buf(k) = '@n' buf(k+1) = EOS return end #-h- atbeg 350 asc 25-mar-82 08:42:16 v1.1 (sw-tools v1.1) ## atbeg - return YES if at beginning of new shell token integer function atbeg(c) character c integer spec if (spec(c) == YES | #special shell character c == '<' | c == '>' | c == '?' | #redirected IO c == ' ' | c == '@t' | #arg separator c == ''' | c == '"') #new quoted string atbeg = YES else atbeg = NO return end #-h- cmdtyp 514 asc 25-mar-82 08:42:18 v1.1 (sw-tools v1.1) ## cmdtyp - check command and prepare for appropriate fetching integer function cmdtyp (comand, path) character comand(ARB), path(ARB) integer equal, shcom integer loccom include stdsub string local "local" string execut "x" string suffix BOTH_SUFFIX call strcpy(comand, path) if (shcom(comand) == YES) cmdtyp = SHELL else if (equal(comand, execut) == YES) { call strcpy(local, path) cmdtyp = BINARY } else cmdtyp = loccom(comand, spath, suffix, path) return end #-h- doampr 955 asc 25-mar-82 08:42:19 v1.1 (sw-tools v1.1) ## doampr - process ampersand node of parse tree subroutine doampr (node, dir) integer node, dir, i integer spawn, getcl, loccom character desc(PIDSIZE) include stdsub include cpars include shflag string shstr "sh" string suffix IMAGE_SUFFIX string second " -c " if (dir == RCHILD | dir == PARENT) return if ( loccom( shstr, spath, suffix, sh) != BINARY ) { call remark( "? Can't locate shell image file.") return } i = 1 call stcopy( shstr, 1, clin, i) call stcopy( second, 1, clin, i) if (getcl(node, dir, clin, i) == ERR) return call stripb(clin) # strip trailing blanks if (prcom == YES) #user wishes to see command call dspcom(sh, clin) if (exec == YES) #execute command { if (spawn(sh, clin, desc, BACKGR) == ERR) call remark ("Cannot spawn background process.") else call remark (desc) } return end #-h- docom 1714 asc 25-mar-82 08:42:21 v1.1 (sw-tools v1.1) ## docom - process command node of parse tree integer function docom (node, dir) integer dir, i, j, node, type, status integer spawn, shellc integer cmdtyp, equal integer pickup, inf, outf, errf, length character comand(FILENAMESIZE), desc(PIDSIZE) include shflag include shcmd string local "local" string errmsg "? Can't find program or script named `" #pick up command j = 1 junk = pickup(clin, j, node, CMD, junk) call fold(clin) type = cmdtyp( clin, comand) #check task and prepare command call if( type == ERR & drop == NO ) { call putlin(errmsg, ERROUT) call putlin(comand, ERROUT) call remark("'.") return(ERR) } if( equal( comand, local) == YES | type == SHELL ) j = 1 else call chcopy( ' ', clin, j) if( type == ASCII ) call scrf(node, comand, clin) else #pick up arguments { if( type == ERR ) call strcpy( local, comand) for( i = 1 ; pickup( clin, j, node, ARGUMENT, i) != ERR ; i = i + 1 ) call chcopy( ' ', clin, j) #pick up file substitutions if( inf(node, clin, j) != ERR ) call chcopy( ' ', clin, j) if( outf(node, clin, j) != ERR ) call chcopy( ' ', clin, j) if( errf(node, clin, j) != ERR ) call chcopy( ' ', clin, j) } call stripb( clin) # strip trailing blanks if( prcom == YES & equal(comand, xoff) == NO ) #user wishes to see command call dspcom(comand, clin) if( exec == YES ) #execute command { if( type == SHELL ) #execute shell commands status = shellc( comand, clin) else { status = spawn( comand, clin, desc, WAIT) if( status == ERR ) call remark( "? Can't spawn process.") else if( status != OK ) andif( status != CHILD_ABORTED ) status = ERR } } else status = OK return(status) end #-h- dopar 1132 asc 25-mar-82 08:42:22 v1.1 (sw-tools v1.1) ## dopar - handle parenthesized statement integer function dopar (p1,p2) character tok integer p, p1, p2, l, pnode, node, pt, ndx integer setree, mktree include cpars l = 0 for (p=p1; p') { if (setree(node, REDOUT, tkbuf( IBPTR, p)) == ERR) { dopar = ERR return } } else if (tok == '?') { if (setree(node, REDERR, tkbuf( IBPTR, p)) == ERR) { dopar = ERR return } } else { call stxerr("invalid token following parenthesis (dopar).") dopar = ERR return } } dopar = OK return end #-h- doparn 1129 asc 25-mar-82 08:42:24 v1.1 (sw-tools v1.1) ## doparn - process parentheses node of parse tree integer function doparn (node, dir) integer node, dir include cpars include stdsub if (dir == LCHILD) { if (tree(node+REDIN) != 0) #input substitution { if (in == 0 | (in != 0 & cin(in) > 0) ) { in = in + 1 cin(in) = tree(node+REDIN) #flag substitution by setting to negative tree(node+REDIN) = -tree(node+REDIN) } } if (tree(node+REDOUT) != 0) { if (out == 0 | #output substitution (out != 0 & cout(out) > 0)) { out = out + 1 cout(out) = tree(node+REDOUT) #flag substitution tree(node+REDOUT) = -tree(node+REDOUT) } } if (tree(node+REDERR) != 0) { er = er + 1 cerr(er ) = tree(node+REDERR) #flag substitution tree(node+REDERR) = -tree(node+REDERR) } } else { if (tree(node+REDIN) < 0) { in = in - 1 tree(node+REDIN) = abs(tree(node+REDIN)) } if (tree(node+REDOUT) < 0) { out = out - 1 tree(node+REDOUT) = abs(tree(node+REDOUT)) } if (tree(node+REDERR) < 0) { er = er - 1 tree(node+REDERR) = abs(tree(node+REDERR)) } } return(OK) end #-h- dopipe 371 asc 25-mar-82 08:42:26 v1.1 (sw-tools v1.1) ## dopipe - process pipe node of parse tree integer function dopipe (node, dir) integer node, dir include stdsub if (dir == LCHILD) { pctr = pctr + 1 pfile(pctr) = NO out = out + 1 cout(out) = -pctr aout(out) = 0 } else if (dir == RCHILD) { in = in + 1 cin(in) = cout(out) out = out - 1 } else { pctr = pctr - 1 in = in - 1 } return(OK) end #-h- dosemi 285 asc 25-mar-82 08:42:26 v1.1 (sw-tools v1.1) ## dosemi - process semicolon node of parse tree integer function dosemi (node, dir) integer node, dir include stdsub if (dir == RCHILD) { if (out > 0) aout(out) = aout(out) + 1 } else if (dir == PARENT) { if (out > 0) aout(out) = aout(out) - 1 } return(OK) end #-h- doverb 1081 asc 25-mar-82 08:42:28 v1.1 (sw-tools v1.1) ## doverb - handle final command syntax integer function doverb (p1,p2) character tok integer p, p1, p2, p3, i, node, ndx integer mktree, setree include cpars ndx = tkbuf( IBPTR, p1) tok = ibuf(ndx) #check token if (tok == '<' | tok == '>' | tok == '?') { call stxerr("command must preceed i/o redirection (doverb).") return(ERR) } nargs = p2 - p1 -1 if (mktree(tkbuf( NODEPTR, p1), COM, 9+nargs, node) == ERR) #make tree entry return(ERR) i = 0 #enter pointers for (p=p1; p') { if (setree(node, REDOUT, tkbuf( IBPTR, p)) == ERR) return(ERR) nargs = nargs - 1 } else if (tok == '?') { if (setree(node, REDERR, tkbuf( IBPTR, p)) == ERR) return(ERR) nargs = nargs - 1 } else { if (setree(node, CMD+i, tkbuf( IBPTR, p)) == ERR) return(ERR) i = i + 1 } } if (setree(node, NENT, nargs) == ERR) #set nbr args return(ERR) return(OK) end #-h- dspcom 370 asc 25-mar-82 08:42:29 v1.1 (sw-tools v1.1) subroutine dspcom(com, arg) integer i integer equal, shcom # function(s) character com(ARB), arg(ARB) string local "local" call putlin(com, ERROUT) i = 1 if( equal( com, local) == NO & shcom(com) == NO) while (arg(i) != ' ' & arg(i) != EOS) i = i + 1 else call putch(' ', ERROUT) call putlin(arg(i), ERROUT) call putch('@n', ERROUT) return end #-h- dsppth 328 asc 25-mar-82 08:42:30 v1.1 (sw-tools v1.1) ## Dsppth - Display search path. subroutine dsppth include stdsub integer i string sepstr " -> " call pwdir(STDOUT, EOS) for( i = 1 ; spath(i) != '@n' ; i = i + 1 ) if( spath(i) == EOS & spath(i+1) != '@n' ) call putlin(sepstr, STDOUT) else call putch(spath(i), STDOUT) call putch('@n', STDOUT) return end #-h- endsh 236 asc 25-mar-82 08:42:30 v1.1 (sw-tools v1.1) ## endsh - terminate execution of the shell subroutine endsh(comand) character comand ifdef(prompt) integer junk string null "" enddef ifdef(prompt) if (comand != EOF) call logend(null, junk) enddef call endst(OK) end #-h- errf 494 asc 25-mar-82 08:42:31 v1.1 (sw-tools v1.1) ## errf - pick up errout file substitution for command integer function errf (node, buf, i) integer node, i integer pickup integer junk character buf(ARB) include cpars include stdsub errf = ERR if( er == 0 & pickup( buf, i, node, REDERR, junk) != ERR ) errf = OK else if (er > 0 & cerr(er) > 0) #check for parens { ### Er may not be properly set if (aout(out) != 0) #append call chcopy( '?', buf, i) call stcopy (ibuf, cerr(er), buf, i) errf = OK } return end #-h- execut 997 asc 25-mar-82 08:42:33 v1.1 (sw-tools v1.1) ## execut - process shell parse tree subroutine execut integer node, type, dir, status, i, j, junk integer mvnext, dosemi, doampr, dopipe, doparn, docom, remove include stdsub in = 0 #initialize file substitution stacks out = 0 er = 0 pctr = 0 hfile(1) = EOS for (i=1; i<=MAXSTACK; i=i+1) pfile(i) = NO node = ROOT while (mvnext(node, type, dir) != ROOT) #move thru tree { if (type == SEPCHAR) status = dosemi (node, dir) else if (type == '&') status = doampr (node, dir) else if (type == PIPE) status = dopipe (node, dir) else if (type == PAR) status = doparn (node, dir) else if (type == COM) status = docom (node, dir) else { call remark("? Invalid parse tree (execut).") status = ERR } if( status == ERR | status == CHILD_ABORTED ) break } if( hfile(1) != EOS ) junk = remove(hfile) for (i=1; i<=MAXSTACK; i=i+1) #remove scratch files if (pfile(i) == YES) { j = 1 call gpname( i, hfile, j) junk = remove( hfile) } return end #-h- getcl 715 asc 25-mar-82 08:42:34 v1.1 (sw-tools v1.1) ## getcl - get command line for background process integer function getcl(node, dir, buf, k) integer node, junk, snode, type, dir, lastd, k character buf(ARB) integer mvnext, gtask include shflag snode = node repeat { junk = mvnext(node, type, dir) if (node == snode) #back to where we started break if (type == SEPCHAR & dir == RCHILD) call chcopy( SEPCHAR, buf, k) else if (type == '&') { if (dir == RCHILD | (dir == PARENT & lastd == LCHILD)) call chcopy( '&', buf, k) lastd = dir } else if (type == PIPE & dir == RCHILD) call chcopy( '|', buf, k) else if (type == PAR) call gpar(node, dir, buf, k) else if (type == COM) getcl = gtask(node, buf, k) } return end #-h- gpar 563 asc 25-mar-82 08:42:35 v1.1 (sw-tools v1.1) ## gpar - get parentheses info for script file subroutine gpar(node, dir, buf, i) integer node, dir, i, n character buf(ARB) integer pickup, length string rpst ") @@" if (dir == LCHILD) call chcopy( '(', buf, i) else if (dir == PARENT) { n = i call stcopy( rpst, 1, buf, i) if( pickup( buf, i, node, REDIN, junk) != ERR) call chcopy( ' ', buf, i) else i = n + 2 if ( pickup( buf, i, node, REDOUT, junk) != ERR) call chcopy( ' ', buf, i) if ( pickup( buf, i, node, REDERR, junk) != ERR) call chcopy( ' ', buf, i) } return end #-h- gpname 376 asc 25-mar-82 08:42:37 v1.1 (sw-tools v1.1) ## gpname - make unique pipe name for file id n subroutine gpname(n, name, i) character name(ARB) integer itoc, length integer i, junk, n include stdsub string pipef(5) "p" pfile(n) = YES # has been generated junk = itoc( n, pipef(2), 3) # generate scratf seed call scratf( pipef, name(i)) # generate name i = i + length( name(i)) # bump pointer return end #-h- gtask 850 asc 25-mar-82 08:42:38 v1.1 (sw-tools v1.1) ## gtask - pick up command and arguments for background process integer function gtask(node, buf, j) integer node, junk, type, j, k, n integer pickup, cmdtyp character buf(ARB) include shflag n = j junk = pickup( buf, j, node, CMD, junk) k = j + 1 type = cmdtyp( buf(n), buf(k)) if( type == ERR & drop == NO ) { call remark ("invalid task") j = n buf(j) = EOS return(ERR) } gtask = OK #pick up arguments call chcopy( ' ', buf, j) for (i=1; pickup( buf, j, node, ARGUMENT, i) != ERR; i=i+1) call chcopy( ' ', buf, j) call chcopy( ESCAPE, buf, j) if( pickup( buf, j, node, REDIN, junk) != ERR) call chcopy( ' ', buf, j) else j = j - 1 if ( pickup( buf, j, node, REDOUT, junk) != ERR) call chcopy( ' ', buf, j) if ( pickup( buf, j, node, REDERR, junk) != ERR) call chcopy( ' ', buf, j) buf(j) = EOS return end #-h- herdoc 585 asc 25-mar-82 08:42:39 v1.1 (sw-tools v1.1) ## herdoc - generate 'here document' for shell subroutine herdoc(char, buf, i) character char, buf(ARB) integer create, getlin integer int, i, n include stdsub include shflag include csclin string doc "doc" n = i call chcopy( '<', buf, i) call scratf(doc, hfile) int = create(hfile, WRITE) if (int == ERR) { call remark("? Can't open file for inline text.") hfile(1) = EOS i = n buf(i) = EOS return } call stcopy( hfile, 1, buf, i) while( getlin( lin, shin) != EOF) { if (lin(1) == char) break call putlin(lin, int) } call close(int) return end #-h- inf 706 asc 25-mar-82 08:42:40 v1.1 (sw-tools v1.1) ## inf - pick up input substitution for command integer function inf(node, buf, i) integer node, i, n integer pickup character buf(ARB), char include stdsub include cpars n = i if (in > 0 & cin(in) < 0) #receive input from pipe { call chcopy( '<', buf, i) call gpname( abs(cin(in)), buf, i) } else if( pickup( buf, i, node, REDIN, junk) == ERR & in > 0 ) call stcopy( ibuf, cin(in), buf, i) else if (script == YES & input(1) != EOS) { call chcopy( '<', buf, i) call stcopy( input, 1, buf, i) } if (buf(n) == '<' & buf(n+1) == '<') #check for 'here document' { char = buf(n+2) i = n call herdoc( char, buf, i) } if (buf(n) != EOS) return(OK) else return(ERR) end #-h- initsh 1937 asc 25-mar-82 08:42:42 v1.1 (sw-tools v1.1) ## initsh - initialize shell subroutine initsh integer getarg, open, loccom, length, index integer i include shflag include shcmd include stdsub PB_DECL(PB_SIZE) # declaration for push back buffer string suffix NO_SUFFIX data cd /'c', 'd', EOS/ ifdef(IMBED_ED) data e /'e', EOS/ enddef data ho /'h', 'o', EOS/ data home /'h', 'o', 'm', 'e', EOS/ data logout /'l', 'o', 'g', 'o', 'u', 't', EOS/ data shopth /'p', 'a', 't', 'h', EOS/ data von /'v', 'o', 'n', EOS/ data voff /'v', 'o', 'f', 'f', EOS/ data xon /'x', 'o', 'n', EOS/ data xoff /'x', 'o', 'f', 'f', EOS/ data input(1) /EOS/ # initialize standard input file data shin /STDIN/ call pbinit(PB_SIZE) # initialize push-back buffer prlin = NO exec = YES prcom = NO carg = NO drop = YES script = NO # initialize search path # search path is :~home/tools~usr:~bin call impath(spath) # fetch search path. call homdir( homedr, LOCAL) # get user's home directory. call gwdir( olddir, LOCAL) # previous directory is current work dir. call enbint # enable software interrupts for( i = 1 ; getarg(i, clin, MAXLINE) != EOF ; i = i + 1 ) { if( i == 1 & clin(1) == '-' ) #shell flag { call fold(clin) if( index( clin, 'v') > 0 ) prlin = YES if( index( clin, 'n') > 0 ) exec = NO if( index( clin, 'x') > 0 ) prcom = YES if( index( clin, 'c') > 0 ) carg = YES if( index( clin, 'd') > 0 ) drop = NO call delarg(i) i = i - 1 } else if( carg == YES ) { call arglin(clin, i) cargdn = NO break } else if( i == 1 ) { if( loccom( clin, spath, suffix, clin) != ASCII ) call cant(clin) shin = open(clin, READ) if( shin == ERR ) call cant(clin) script = YES } else if( clin(1) == ESCAPE ) { if( clin(2) == '<' ) call scopy(clin, 3, input, 1) else next call delarg (i) i = i - 1 } } call rlogin # set up unit for login.sh return end #-h- mktoks 775 asc 25-mar-82 08:42:45 v1.1 (sw-tools v1.1) ## mktoks - create parse tables for shell parser integer function mktoks (line, k) integer length integer i, paren character line(ARB) integer shtok integer k, l include cpars paren = 0 i = 1 call putbak (EOS) #initialize buffer call pbstr (line) for (k=1; shtok(ibuf(i)) != EOS; k=k+1) { if (ibuf(i) != EOS) { tkbuf(IBPTR,k) = i tkbuf(TMARK,k) = 0 tkbuf(NODEPTR,k) = 0 tkbuf(ESCAN,k) = 0 if (ibuf(i) == '(') paren = paren + 1 else if (ibuf(i) == ')') paren = paren - 1 l = i + length(ibuf(i)) - 1 if ((ibuf(i) == ''' | ibuf(i) == '"') & ibuf(l) != ibuf(i)) { call remark("? Unbalanced quotes.") return(ERR) } i = l + 2 } } k = k - 1 ibuf(i) = EOS if (paren != 0) return(ERR) else return(OK) end #-h- mktree 866 asc 25-mar-82 08:42:46 v1.1 (sw-tools v1.1) ## mktree - create child node for given parent integer function mktree (pnode, type, size, cnode) integer pnode, type, size, cnode, i include cpars cnode = treend treend = treend + size #next available space if (treend >TREESIZE) { call stxerr("tree buffer size exceeded (mktree)") cnode = ERR return(ERR) } for (i=1; i<=size; i=i+1) #clear entries tree(cnode+i) = 0 tree(cnode+PARENT) = pnode tree(cnode+NTYPE) = type #ifdef(DEBUG) # call putch('@n',ERROUT) # debug_int("child node =",cnode) # debug_int("parent node =",pnode) #enddef if (pnode >= 0) #install back pointer { # ifdef(DEBUG) # debug_node(pnode) # enddef if (tree(pnode+LCHILD) == 0) tree(pnode+LCHILD) = cnode else if (tree(pnode+RCHILD) == 0) tree(pnode+RCHILD) = cnode else { call stxerr("too many children (mktree)") return(ERR) } } return(cnode) end #-h- mvnext 355 asc 25-mar-82 08:42:48 v1.1 (sw-tools v1.1) ## mvnext - move to next node in parse tree integer function mvnext (node, type, dir) integer node, dir, type integer nxtbr include cpars if (node == ROOT) #just starting { mvnext = 0 dir = LCHILD } else mvnext = tree(node+dir) if (mvnext != ROOT) { type = tree(mvnext+NTYPE) dir = nxtbr(mvnext, node) } node = mvnext return end #-h- nextp 187 asc 25-mar-82 08:42:49 v1.1 (sw-tools v1.1) ## nextp - get next pointer from pushdown stack integer function nextp (p) integer p include cpars if (pp == 0) p = EOS else { p = stack(pp) pp = pp - 1 } return(p) end #-h- nodir 236 asc 25-mar-82 08:42:49 v1.1 (sw-tools v1.1) ## NoDir - Print error message for invalid directory spec. subroutine nodir(dir) character dir(ARB) string start "? Can't find directory named `" call putlin( start, ERROUT) call putlin( dir, ERROUT) call remark( "'.") return end #-h- nxtbr 391 asc 25-mar-82 08:42:50 v1.1 (sw-tools v1.1) ## nxtbr - determine next direction for moving in parse tree integer function nxtbr (node, lnode) integer node, lnode include cpars if (lnode == tree(node+PARENT)) #going down { if (tree(node+LCHILD) != 0) return(LCHILD) else return(PARENT) } else if (lnode == tree(node+LCHILD) & #going up tree(node+RCHILD) != 0) return(RCHILD) else return(PARENT) end #-h- outf 588 asc 25-mar-82 08:42:51 v1.1 (sw-tools v1.1) ## outf - pick up output file substitution for command integer function outf (node, buf, i) integer node, i integer pickup integer junk character buf(ARB) include cpars include stdsub if( out == 0 & pickup( buf, i, node, REDOUT, junk) != ERR ) return(OK) else if (out > 0) #check for pipes and parens { if (aout(out) != 0) #append call chcopy( '>', buf, i) if (cout(out) > 0) #use paren substitution call stcopy( ibuf, cout(out), buf, i) else #pipe { call chcopy( '>', buf, i) call gpname( abs(cout(out)), buf, i) } return(OK) } return(ERR) end #-h- param 458 asc 25-mar-82 08:42:52 v1.1 (sw-tools v1.1) ## param - handle parameter substitution for the shell integer function param(c) character c, num(2), ngetch integer getarg, ctoi, i, junk include shflag include csclin if (c == '$') #handle param substitution { num(1) = ngetch( num(1), shin) num(2) = EOS i = 1 n = ctoi( num, i) if (n > 0) { if( getarg( n+1, lin, MAXLINE) != EOF) call pbstr(lin) c = ngetch( c, shin) } else c = num(1) return(YES) } else return(NO) end #-h- parser 1280 asc 25-mar-82 08:42:54 v1.1 (sw-tools v1.1) ## parser - parse shell command line # syntax : empty # | syn1 # syn1 : syn2 # | syn2 & syntax # | syn2 ; syntax # syn2 : syn3 # | syn3 | syn2 # syn3 : (syn1) [out] [?errout] # | tok tok* [out] [?errout] integer function parser (line) integer p, p1, p2, mark, i, j integer syntax, syn1, syn2, syn3 integer mktoks, nextp character line(ARB) include cpars include shflag treend = 0 #initialize tree pointer pp = 0 #initialize stack pointer for (i=1; i<=TSIZE; i=i+1) #initialize token table for (j=1; j<=MAXTOK; j=j+1) tkbuf(i,j) = 0 for (i=1; i<=TREESIZE; i=i+1) #initialize parse tree tree(i) = 0 for (i=1; i<=MAXLINE; i=i+1) #initialize input buffer ibuf(i) = EOS if (mktoks(line,p2) == ERR) return(ERR) tkbuf( TMARK, 1) = SSYNTAX tkbuf( NODEPTR, 1) = -1 tkbuf( ESCAN, 1) = p2 call putbac (1) while (nextp(p1) != EOS) #generate parse tree { mark = tkbuf( TMARK, p1) p2 = tkbuf( ESCAN, p1) if (mark == SSYNTAX) parser = syntax(p1, p2) else if (mark == SSYN1) parser = syn1(p1, p2) else if (mark == SSYN2) parser = syn2(p1,p2) else if (mark == SSYN3) parser = syn3(p1,p2) if (parser == ERR) return } parser = OK return end #-h- pastbl 196 asc 25-mar-82 08:42:55 v1.1 (sw-tools v1.1) ## pastbl - read past blanks and tabs on input subroutine pastbl (c) character c character ngetch include shflag repeat c = ngetch(c, shin) until (c != ' ' & c != '@t') return end #-h- pickup 667 asc 25-mar-82 08:42:56 v1.1 (sw-tools v1.1) ## pickup - pick up character string from parse tree integer function pickup( array, i, node, field, arg) integer node, field, arg, i character array(ARB) include cpars pickup = OK if ( (field == REDIN | field == REDOUT | field == REDERR) & (tree(node+NTYPE) == COM | tree(node+NTYPE) == PAR) & tree(node+field) != 0 ) call stcopy( ibuf, tree(node+field), array, i) else if (field == CMD & tree(node+NTYPE) == COM) call stcopy( ibuf, tree(node+CMD), array, i) else if (field == ARGUMENT & tree(node+NTYPE) == COM & arg <= tree(node+NENT) ) call stcopy( ibuf, tree(node+CMD+arg), array, i) else pickup = ERR return end #-h- putbac 209 asc 25-mar-82 08:42:56 v1.1 (sw-tools v1.1) ## putbac - put pointer on pushdown stack subroutine putbac (p) integer p include cpars pp = pp + 1 if (pp > MAXSTACK) call stxerr("stack size exceeded (putbac)") else stack(pp) = p return end #-h- pwdir 215 asc 25-mar-82 08:42:57 v1.1 (sw-tools v1.1) subroutine pwdir( fd, c) character file(FILENAMESIZE), c integer fd call gwdir( file, PATH) if( file(2) == '@@' ) file(2) = '\' call putlin(file, fd) if (c != EOS) call putch(c, fd) return end #-h- qs 364 asc 25-mar-82 08:42:58 v1.1 (sw-tools v1.1) ## qs - handle extract quoted string token in shell subroutine qs(char, tok) character c, tok(ARB), char integer j, junk integer param character ngetch include shflag tok(1) = char j = 2 for (c=ngetch(c,shin); c != EOS; c=ngetch(c, shin)) { if (c == EOS) break tok(j) = c j = j + 1 if (c == char) #done break } tok(j) = EOS return end %%D 2 #-h- rlogin 282 asc 25-mar-82 08:42:58 v1.1 (sw-tools v1.1) %%E 2 %%I 2 #-h- rlogin 282 asc 09-apr-82 10:28:40 j (sventek j) %%E 2 subroutine rlogin integer open %%D 2 string lgin "login.sh" %%E 2 include shflag include stdsub %%I 2 string lgin "login.sh" %%E 2 inunit = shin ifdef(DO_STARTUP) call tooldr(sh, LOCAL) call concat(sh, lgin, hfile) logfd = open(hfile, READ) if (logfd != ERR) shin = logfd elsedef logfd = ERR enddef return end #-h- scrf 1409 asc 25-mar-82 08:42:59 v1.1 (sw-tools v1.1) ## scrf - prepare script file for execution by shell subroutine scrf (node, comand, args) character comand(ARB), args(ARB) integer pickup, inf, outf, errf, length, loccom integer i, j, type include shflag include stdsub string suffix IMAGE_SUFFIX string prflag "-v " string cmflag "-x " string drflag "-d " string shstr "sh" # handle scripts by spawning the shell with the script as input j = 1 call stcopy( shstr, 1, args, j) call chcopy( ' ', args, j) if (prlin == YES) #pass along shell flags call stcopy( prflag, 1, args, j) if (prcom == YES) call stcopy( cmflag, 1, args, j) if (drop == NO) call stcopy( drflag, 1, args, j) # The shell becomes the main command and the script file name # becomes an argument to the shell call stcopy( comand, 1, args, j) if( loccom( shstr, spath, suffix, comand) != BINARY ) { call remark( "? Can't locate shell image file.") return } call chcopy( ' ', args, j) for (i=1; pickup(args, j, node, ARGUMENT, i) != ERR; i=i+1) #pick up args call chcopy( ' ', args, j) call chcopy( ESCAPE, args, j) if( inf(node, args, j) != ERR) #pick up STDIN substitution call chcopy( ' ', args, j) else j = j - 1 if( outf(node, args, j) != ERR) #pick up STDOUT substitution call chcopy( ' ', args, j) if( errf(node, args, j) != ERR) #pick up ERROUT substitution call chcopy( ' ', args, j) args(j) = EOS return end #-h- setree 290 asc 25-mar-82 08:43:01 v1.1 (sw-tools v1.1) ## setree - put 'value' in given node at given position integer function setree (node, posn, value) integer node, posn, value, i include cpars i = node + posn if (tree(i) != 0) { call stxerr("doubly defined argument (setree)") return(ERR) } tree(i) = value return(OK) end #-h- shcom 548 asc 25-mar-82 08:43:01 v1.1 (sw-tools v1.1) ## shcom - see if command is shell command integer function shcom(comand) character comand(ARB) integer equal # function(s) include shcmd if( equal( comand, cd) == YES | ifdef(IMBED_ED) equal( comand, e) == YES | enddef equal( comand, ho) == YES | equal( comand, home) == YES | equal( comand, logout) == YES | equal( comand, von) == YES | equal( comand, voff) == YES | equal( comand, xon) == YES | equal( comand, xoff) == YES | equal( comand, shopth) == YES ) return(YES) else return(NO) end #-h- shellc 1346 asc 25-mar-82 08:43:03 v1.1 (sw-tools v1.1) ## shellc - execute shell command integer function shellc (comand, args) character args(ARB), comand(ARB) integer cwdir, equal # function(s) integer i, status include shcmd include stdsub include shflag status = OK if( equal( comand, cd) == YES) { call gwdir( sh, LOCAL) # fetch current working directory if( args(1) == EOS ) # bare cd => back to previous dir call strcpy( olddir, args) if( cwdir(args) == ERR ) # oops, no such directory { call nodir( args) status = ERR } else { call strcpy( sh, olddir) # store previous directory call pwdir(ERROUT, '@n') # verify change to user } } else if( equal( comand, ho) == YES | equal( comand, home) == YES ) { call gwdir( sh, LOCAL) if( cwdir(homedr) == ERR ) { call nodir( homedr) status = ERR } else { call strcpy( sh, olddir) call pwdir( ERROUT, '@n') } } else if( equal(comand, von) == YES ) prlin = YES else if( equal(comand, voff) == YES ) prlin = NO else if( equal(comand, xon) == YES ) prcom = YES else if( equal(comand, xoff) == YES ) prcom = NO else if( equal(comand, shopth) == YES ) call dsppth else if( equal(comand, logout) == YES ) call endsh('q') ifdef(IMBED_ED) else if( equal( comand, e) == YES ) call editor(args) enddef else call remark ("? Invalid shell command.") return(status) end #-h- shline 957 asc 25-mar-82 08:43:05 v1.1 (sw-tools v1.1) ## shline - prompt and get input line for shell integer function shline (line) character line(ARB) integer equal, length, prompt character tmpara(5) integer i, k include shflag include shcmd string pchar "% " if( carg == YES ) # get input from command line { if( cargdn == YES ) { line(1) = EOS k = EOF } else { call strcpy( clin, line) cargdn = YES k = length(line) } } else repeat { k = prompt( pchar, line, shin) if (k != EOF) break if( shin == logfd ) # finished login.sh - now input { call close(shin) # close login.sh shin = inunit # restore input unit k = OK # read again on input file } } until (k == EOF) if( k != EOF ) { for( i=1 ; i <= 4 & i <= k ; i = i + 1 ) tmpara(i) = line(i) tmpara(i) = EOS call fold(tmpara) if( prlin == YES & equal(tmpara, voff) == NO ) # user wishes to see line call putlin(line, ERROUT) } return(k) end #-h- shtok 1201 asc 25-mar-82 08:43:06 v1.1 (sw-tools v1.1) ## shtok - extract next shell token integer function shtok (tok) character tok(ARB), c, ngetch integer spec, param, atbeg integer i, j, pstat include shflag pstat = NO #initialize variable repeat #loop until non-null token found { call pastbl(c) #skip leading blanks & tabs j = 1 if (spec(c) == YES) #single shell special character { tok(1) = c tok(2) = EOS shtok = c return } if (c == ''' | c == '"') #quoted string { call qs(c, tok) shtok = tok(1) return } if (c == '<' | c == '>' | c == '?') #redirected IO for (i=1; i<=2; i=i+1) { tok(j) = c j = j + 1 call pastbl(c) if (c != tok(j-1)) break } for ( ; c != EOS; c=ngetch(c, shin)) { pstat = param(c) if (c == EOS) break if (atbeg(c) == YES) { call putbak(c) break } if (c == ESCAPE) { c = ngetch(c, shin) if (spec(c) == NO & #ignore if not shell char. (c != ESCAPE & c != '$')) { call putbak(c) c = ESCAPE } } tok(j) = c j = j + 1 } tok(j) = EOS shtok = tok(1) if (pstat == NO | j < 1) return #continue if null token produced by empty parameter substitution pstat = NO } end #-h- spec 367 asc 25-mar-82 08:43:08 v1.1 (sw-tools v1.1) ## spec - handle special characters in shell commands integer function spec (c) character c character sp(8) data sp(1), sp(2), sp(3), sp(4), sp(5), sp(6), sp(7), sp(8) /'&', '(', ')', SEPCHAR, '|', '^', '@n', EOS/ if (index(sp, c) != 0) { spec = YES if (c == '^') #allow '^' for PIPE c = '|' } else spec = NO return end #-h- stripb 170 asc 25-mar-82 08:43:09 v1.1 (sw-tools v1.1) subroutine stripb(buf) integer i integer length character buf(ARB) for( i=length(buf) ; i > 0 ; i=i-1 ) if( buf(i) != ' ' ) break buf(i+1) = EOS return end #-h- stxerr 227 asc 25-mar-82 08:43:09 v1.1 (sw-tools v1.1) ## stxerr - report syntax error subroutine stxerr (reason) character reason(ARB) include cpars string first "? Syntax error: " call putlin(first, ERROUT) call putlin (reason, ERROUT) call putch ('@n', ERROUT) return end #-h- syn1 1194 asc 25-mar-82 08:43:10 v1.1 (sw-tools v1.1) ## syn1 - parse shell syntax level 1 # SYN1 -> SYN2 # -> SYN2 ; SYNTAX # -> SYN2 & SYNTAX integer function syn1 (p1,p2) character tok integer p, p1, p2, node, l, pt, ndx integer mktree include cpars l = 0 ifdef(DEBUG) debug_int("p1 =",p1) debug_int("p2 =",p2) enddef for (p=p1; p 0) call stxerr("unbalenced left parentheses (syn1)") else { tkbuf( TMARK, p1) = SSYN2 call putbac (p1) } return(OK) end #-h- syn2 840 asc 25-mar-82 08:43:12 v1.1 (sw-tools v1.1) ## syn2 - parse shell syntax level 2 # SYN2 -> SYN3 # -> SYN3 | SYN2 integer function syn2 (p1,p2) character tok integer p, p1, p2, l, node, pt, ndx integer mktree include cpars l = 0 for (p=p1; p (SYN1) [out] [?errout] # -> word word* [out] [?errout] integer function syn3 (p1,p2) integer p1, p2, ndx integer dopar, doverb include cpars if (p1 >= p2) { call stxerr("empty command (syn3)") return(ERR) } ndx = tkbuf( IBPTR, p1) if (ibuf(ndx) == '(') return( dopar(p1,p2)) else return( doverb(p1,p2)) end #-h- syntax 491 asc 25-mar-82 08:43:14 v1.1 (sw-tools v1.1) ## syntax - parse shell syntax level zero # SYNTAX -> EMPTY # -> SYN1 integer function syntax (p1,p2) integer p, p1, p2, ndx character tok include cpars for (p=p1; p', `?', `>>', `??', (and sometimes `-'). An argument of the form `name' causes file `name' to be used as the standard output. An argument of the form `?name' causes the file `name' to be used as the standard error output. Arguments of the form `>>name' or `??name' cause program output to be appended to `name' for standard output or error output respectively. If `name' does not exist, it will be created. Most tools have the capability to read their input from a series of files. In this case, the list of files overrides reading from standard input. However, many of the tools allow you to read from both a list of files and from input by specifying the filename `-' for standard input. For example: .ce format file1 - file2 would read its input from `file1', then from the standard input, then from `file2'. .ti -2 o FILTERS AND PIPES The output from one command may be directed to the input of another. A sequence of commands separated by vertical bars (`|') or carets (`^') causes the shell to arrange that the standard output of each command be delivered to the standard input of the next command in sequence. Thus in the command line: .ce sort list | uniq | crt `Sort' sorts the contents of file `list'; its output is passed to `uniq', which strips out duplicate lines. The output from `uniq' is then input to `crt', which prepares the lines for viewing on your crt terminal. The vertical bar is called a `pipe'. Programs such as `sort', `uniq', and `crt', which copy standard input to standard output (making some changes along the way) are called `filters'. .ti -2 o COMMAND SEPARATORS Commands need not be on different lines; instead they may be separated by semicolons: .ce ar t file; ed The above command will first list the contents of the archived file `file', then enter the editor. The shell also allows commands to be grouped together with parentheses, where the group can then be used as a filter. For example: .ce (date; cat chocolate) | comm vanilla writes first the date and then the file `chocolate' to standard output, which is then read as input by `comm'. This tool compares the results with existing file `vanilla' to see which lines the two files have in common. .ti -2 o MULTITASKING On many systems the shell also allows processes to be executed in the background. If a command is followed by `&', the shell will not wait for the command to finish before prompting again; instead, it is ready immediately to accept a new command. For instance: .ce ratfor ambrose >george & preprocesses the file `ambrose', putting the output on `george'. No matter how long the compilation takes, the shell returns immediately. The identification number of the process running that command is printed. This identification may be used to wait for the completion of the command or to terminate it. The `&' may be used several times in a line. Parentheses and pipes are also allowed (within the same background process). .ti -2 o SCRIPT FILES The shell itself is a command, and may be called recursively, either implicitly or explicitly. This is primarily useful for executing files containing lines of shell commands. For instance, suppose you had a file named `nbrcount.sh' which looked like this: .nf .in +15 echo "Counting strings of digits" tr $4 ar u loveletters $4 .in -15 .fi Then, executing the command: .ce private Dan John Harold fair would merge the files `Dan', `John', and `Harold', encrypt them, and store them away in an archive under the name `fair'. Script files may be used as filters in pipelines just like regular commands. Script files sometimes require in-line data to be available to them. A special input redirection notation `<<' is used to achieve this effect. For example, the editor normally takes its commands from the standard input. However, within a shell procedure commands could be embedded this way: .nf .in +15 ed file <', where is the character one needs to type in conjunction with the CTRL key to generate the control character. !b[rowse] [n][l] This command is a synonym for history. It is included to increase the similiarity of function with the editor. .ti -3 2. history recall ![line_number][;line_number]... This command permits the recall of a command from the history for re-execution. The command so recalled is displayed and then passed on to the shell for execution. This command is then entered at the bottom of the history. Valid line_numbers are the same as those for the editor. For example, a line_number may be the number listed next to the command in the history display, a pattern of the form "\pattern[\]", which indicates a backward search in the 25 line history window, or a pattern of the form "/pattern[/]", indicating a search forward, wrapping to the start of the 25 line window. The trailing '\' or '/' are optional when specifying a single pattern. The semi-colon syntax is the same as that in `ed', indicating that the search for the second pattern is to start at the line where the first pattern was found. If the pattern specified was illegal, or a line matching the pattern could not be found, or an invalid line_number was specified, a comment is displayed # invalid line number and you are prompted for more input. The history is not modified in this case. All sequences of patterns resolve into a single line number. It is not possible to request a range of lines from the history. It should be noted that the line_numbering is completely regular with `ed'. In particular, "!" followed by nothing maps into a fetch of the current line (last command typed). See the writeup on `ed' for more details on the specification of line_numbers. .ti -3 3. history recall and modification ![line_number]s/pat/repl[/[g]] Upon successfully recalling a command from the history, it may be modified before it is passed on to `esh' for execution. This is performed with the 's' command, which is exactly the same as that for `ed'. The delimiters for `pat' and `repl' may be any character, the remembered pattern feature is available, and the trailing delimiter after the replacement pattern is optional. The optional trailing `g' indicates substitution for all occurrences of 'pat' in the line. See the `ed' manual entry for more information on the substitute command. If the substitution fails for any reason, a comment is displayed # illegal substitution and you are prompted for more input. The history is not modified in this case. .ti -3 4. history archiving !w[rite] [>[>]]file This command permits you to archive (save) the entire transcript of activity to a file. It also passes an EOF to `esh', which causes `esh' to terminate execution. The commands !w file .br !w >file both cause `file' to be overwritten with the transcript, while >>file causes the transcript to be appended to `file'. It should be noted that the !w command causes ALL of the input given to `esh' in this session to be saved, not just the current 25 line window. It also passes an EOF to `esh', which will terminate execution. .ti -3 5. history deletion !q[uit] .br ^Z These commands cause an EOF to be sent to `esh' and the deletion of the log of activity. .in -5 Lines consisting solely of a carriage return are NOT logged in the history. If you need to perform several edits on a command before having it executed, you can exploit the fact that lines beginning with a sharp (#) are comments to the shell. For example: .in +5 .nf !\%ed\s/%/#/ !s/pat1/repl1/ .in +6 .cc * . . . . . . *cc . .in -6 !s/patn/repln/ !s/%#// .fi .in -5 All of the intermediate comment lines will be placed in the history, displacing other lines from the window which may possibly be needed. Of course, it may be simpler in such cases to just enter the command by hand. .sp 2 I N T R A L I N E E D I T I N G .sp The intraline editing functions are a subset of those available in the "VI" screen editor from Berkeley. You are referred to the VI documentation for a tutorial introduction. The intraline editing "mode" is entered via ^E. Exactly what happens when the ^E is typed depends on what precedes it on the command line. If the ^E is the first character on a line, the previous command is retrieved and the cursor is positioned at the beginning of the line. If the line is a history reference (i.e. begins with a "!"), the referenced line is retrieved and the cursor is positioned at the beginning of the line. If the line is anything else, the cursor is positioned at the end of the line. Once in the intraline editor the following commands are allowed: .sp Notes: `[n]' indicates an optional integer count input is terminated with ^Z or ESC .nf MOVE cursor: ------------ [n]SPACE -> positions [n]BS <- positions [n]h <- positions % <- to beginning of line (BOL) $ -> to end of line (EOL) [n]w -> (non-alphanumeric) words [n]W -> (non-blank) words [n]b <- (non-alphanumeric) words [n]B <- (non-blank) words [n]e -> to end of th (non-alphanumeric) word [n]E -> to end of th (non-blank) word [n]f -> thru th occurrence of char [n]t -> to th occurrence of char [n]F <- thru th occurrence of char [n]T <- to th occurrence of char [n]; Repeat last `f', `t', `F', or `T' [n], Repeat last `f', `t', `F', or `T' in reverse INSERT or APPEND : ------------------------ [n]i Insert text before cursor [n]I Insert text before beginning of line [n]a Append text after cursor [n]A Append text after end of line REPLACE or SUBSTITUTE for character(s): ---------------------------------------------- R Replace (overlay) text on screen with r Replace current character with [n]s Substitute characters with CHANGE to : ------------------- [n]cw next (non-alphanumeric) words to [n]cW next (non-blank) words to [n]ce thru end of th (non-alphanumeric) word to [n]cE thru end of th (non-blank) word to c% text from BOL thru cursor to c$ text from cursor thru EOL to C Synonym for `c$' DELETE (s): ------------------------ [n]x characters, starting at cursor [n]dSPACE characters, starting at cursor [n]X previous characters [n]dw next (non-alphanumeric) words [n]dW next (non-blank) words [n]db previous (non-alphanumeric) words [n]dB previous (non-blank) words [n]df thru next th occurrence of char [n]dt to next th occurrence of char [n]dF thru prev th occurrence of char [n]dT to prev th occurrence of char dd entire line d% from beginning of line to cursor, inclusive d$ from cursor to end of line, inclusive D Synonym for `d$' [n]. Repeat previous `delete' command UNDO action of previous command(s): ----------------------------------- u Undo the last change to the line U Undo ALL commands; restore line to original state EXIT intra-line editor: ----------------------- ^Z Move cursor to EOL and exit intra-line edit ^E Move cursor to EOL and force RETURN RETURN Delete after cursor to EOL and execute command line .sp .fi The three methods of exiting the intraline editing mode are worthy of special mention. In particular you will usually exit with ^E rather than RETURN or ^Z, since the RETURN will chop off everything to the right of the cursor and ^Z will merely return to the line-gathering routine which invoked the intraline editor. Note that a ^E^E sequence may be used to repeat the previous command line. .fl .sa sh - command line interpreter .di # invalid line number .br # invalid substitution .au Editing features: Dave Martin .br History mechanism: Joe Sventek .bu #-h- hsh.fmt 6206 asc 25-mar-82 08:47:00 v1.1 (sw-tools v1.1) .so ~bin/manhdr .hd Hsh (1) 2-May-81 shell with history and editing functions .sy hsh [-cdnvx] [file [arguments]] .ds `hsh' is identical to `sh' with the exception that a history is kept of commands typed; recall and editing functions on the history are permitted and described below. Consult the manual entry for `sh' for more information on the common functions. A history of the commands input to `hsh' are maintained for each session. The user may invoke special history manipulating functions by starting a command line with an exclamation mark (! - also known as a BANG) in column 1. If is is necessary to send a line starting with a BANG to the shell, lines starting with "@!" have the "@" stripped off, and the remainder of the line is given to the shell. Lines starting with BANG enable the user to communicate with a miniature version of the editor `ed'. At any time, the last 25 commands are available for recall and manipulation. The current line concept of `ed' is supported, although the current line is ALWAYS the last command in the history. Legal history commands are: .in +5 .ti -3 1. history display !h[istory] [n][l] This is the equivalent of a browse command in `ed'. !h will display the last screenful of commands, along with their line numbers. The screensize, which defaults to 22 lines, may be changed by specifying a BLANK and a number following the !h[istory] string (!h 10, for example). The new screensize is remembered and used in all !h commands as the default screensize. Specifying a screensize larger than 25 has the effect of setting the size to 25. The optional trailing `l' (list) will cause control characters in the commands to be displayed as `^', where is the character one needs to type in conjunction with the CTRL key to generate the control character. !b[rowse] [n][l] This command is a synonym for history. It is included to increase the similiarity of function with the editor. .ne 30 .ti -3 2. history recall ![line_number][;line_number]... This command permits the recall of a command from the history for re-execution. The command so recalled is displayed to the user and then passed on to the shell for execution. This command is then entered at the bottom of the history. Valid line_numbers are the same as those for the editor. For example, a line_number may be the number listed next to the command in the history display, a pattern of the form "\pattern[\]", which indicates a backward search in the 25 line history window, or a pattern of the form "/pattern[/]", indicating a search forward, wrapping to the start of the 25 line window. The trailing '\' or '/' are optional when specifying a single pattern. The semi-colon syntax is the same as that in `ed', indicating that the search for the second pattern is to start at the line where the first pattern was found. If the pattern specified was illegal, or a line matching the pattern could not be found, or an invalid line_number was specified, a comment is displayed to the user # invalid line number and the user is prompted for more input. The history is not modified in this case. All sequences of patterns resolve into a single line number. It is not possible to request a range of lines from the history. It should be noted that the line_numbering is completely regular with `ed'. In particular, "!" followed by nothing maps into a fetch of the current line (last command typed). See the writeup on `ed' for more details on the specification of line_numbers. .ti -3 3. history recall and modification ![line_number]s/pat/repl[/[g]] Upon successfully recalling a command from the history, it may be modified before it is passed on to `hsh' for execution. This is performed with the 's' command, which is exactly the same as that for `ed'. The delimiters for `pat' and `repl' may be any character, the remembered pattern feature is available, and the trailing delimiter after the replacement pattern is optional. The optional trailing 'g' indicates substitution for all occurrences of 'pat' in the line. See the `ed' manual entry for more information on the substitute command. If the substitution fails for any reason, a comment is displayed to the user # illegal substitution and the user is prompted for more input. The history is not modified in this case. .ti -3 4. history archiving !w[rite] [>[>]]file This command permits the user to archive (save) the entire transcript of activity to a file. It also passes an EOF to `hsh', which causes `hsh' to terminate execution. The commands !w file .br !w >file both cause `file' to be overwritten with the transcript, while >>file causes the transcript to be appended to `file'. It should be noted that the !w command causes ALL of the input given to `hsh' in this session to be saved, not just the current 25 line window. It also passes an EOF to `hsh', which will terminate execution. .ti -3 5. history deletion !q[uit] .br ^Z These commands cause an EOF to be sent to `hsh' and the deletion of the log of activity. .in -5 .ne 30 Lines consisting solely of a carriage return are NOT logged in the history. If the user needs to perform several edits on a command before having it executed, he can exploit the fact that lines beginning with a sharp (#) are comments to the shell. For example: .in +5 .nf !\%ed\s/%/#/ !s/pat1/repl1/ .in +6 .cc * . . . . . . *cc . .in -6 !s/patn/repln/ !s/%#// .fi .in -5 All of the intermediate comment lines will be placed in the history, displacing other lines from the window which may possibly be needed. Of course, it may be simpler in such cases to just enter the command by hand. .fl Creates a scratch file ~tmp/pid.log for the command transcript. .sa .nf sh - command line interpreter esh - shell with file recognition and RAW tty I/O ed - text editor .fi .di # invalid line number .br # invalid substitution .au Joe Sventek .bu %%E 1