diff --git a/README.md b/README.md index e64b7e42..99c27af0 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ There's a [DDT cheat sheet](doc/DDT.md) for Unix users. - HSNAME, displays user's HSNAME. - HSNDEV, HSNAME device. - IDLE, list idle users. + - INLINE, reads line from TTY and adds to JCL (for DDT init files) - INQUIR, user account database. - INQUPD, processes INQUIR change requests. - JOBS, list jobs by category. diff --git a/build/build.tcl b/build/build.tcl index 150bfffb..fc92691b 100644 --- a/build/build.tcl +++ b/build/build.tcl @@ -711,6 +711,10 @@ respond "*" ":link .info.;its usets,sysdoc;usets >\r" respond "*" ":link .info.;its %pi,sysdoc;%pi >\r" respond "*" ":link .info.;its ttyvar,sysdoc;ttyvar >\r" +# inline +respond "*" ":midas sys2;ts inline_sysen1;inline\r" +expect ":KILL" + # ndskdmp tape respond "*" ":link kshack;good ram,.;ram ram\r" respond "*" ":link kshack;ddt bin,.;@ ddt\r" diff --git a/doc/_info_/inline.info b/doc/_info_/inline.info new file mode 100644 index 00000000..67a00e0f --- /dev/null +++ b/doc/_info_/inline.info @@ -0,0 +1,45 @@ +INLINE -- 1:47am Monday, 2 January 1978 -- RWK + +Often in writing a DDT init, you want to read a single line of input, +and do something based on that. + +:INLINE +Will read from the TTY one line (or up to a ^C, for JCL lines that want to +end with ^C, like :SEND's). This line is added to the end of the JCL and fed +to DDT. + +A couple of examples will make this clear. +in a init file: + +:Where Are You? :INLINE :TTYLOC +will type out +"Where Are You? " +and the user may then type "836A Hacker's Haven" +and it will do a +:TTYLOC 836A Hacker's Haven + +Note that the space is inserted between the ":TTYLOC" and the +"836A Hacker's Haven". This can be overcome by ending in a rubout. + +using the :X program: +:X :INLINE :DELETE FOO;BAR +will save away the :INLINE :Delete FOO;BAR +in a file _X (see the documentation on the X program) +and run it. +:INLINE will let you add second file-names onto the end of the :Delete FOO;BAR +Thus, after typing the line above beginning with ":X", you can type +BUZZ +and it will do +:DELETE FOO;BAR BUZZ +After the first time, you can type X^K +BAZ +and it will do +:DELETE FOO;BAR BAZ + +There are a few characters that are special in typein: +^D flushes the input line, allowing you to re-type it. +^L re-displays +^Z quits out of it, doesn't end the init file, but doesn't run anything either. +rubout rubs out the last character. It does EMACS style rubout on printing +terminals. On displays it erases. On printing terminals without backspace +(ugh) it will echo as it rubs out. diff --git a/src/rwk/syscal.54 b/src/rwk/syscal.54 new file mode 100755 index 00000000..f7e44016 --- /dev/null +++ b/src/rwk/syscal.54 @@ -0,0 +1,198 @@ +;; SYSCAL macro. + + +; from EAK;MACROS > +; macro to reserve space in variables section +; VAR FOO reserves 1 word of space for FOO +; VAR BAR(N) reserves n words of space for BAR +define var x +irps a,b,[x] + ifse b,(, .vector x + .else .scalar x + .istop + termin +termin + + +ifndef loss,loss=.lose 1400 ;default thing to do when you lose + +cnt==4000,,0 ;control +cnti==5000,,0 ;control immediate +errret==3000,,0 ;error return +argi==1000,,0 ;immediate argument +val==2000,,0 ;value return + +;; From RWK;EMPTY > + +DEFINE SYSCAL A,B,C= + .CALL [SETZ ? SIXBIT/A/ ? B ? setz+errret+c] TERMIN + +var debug"calerr + + + +define .pure +ifn syscal".pure.,.err Two .PURE's without a corresponding .UPURE +syscal".pure.==-1 +syscal"..unpr==. +loc syscal"..pure +termin + +define .upure +ife syscal".pure.,.err Two .UPURE's without a correspponding .PURE +syscal".pure.==0 +syscal"..pure==. +loc syscal"..unpr +termin + + +ifndef .M".purpg,.M".purpg==1 ;# of first pure page +syscal"..unpr==100 +syscal"..pure==2000*.m".purpg +syscal".pure.==0 ;initially allocating impure + +;; Macro to check for overlap of pure and impure +define .perch +define .pch. xx,yy,zz +printc \ +Impure storage from 0 to yy +Pure storage from xx to zz +\ +termin +.pch. \.m".purpg*2000,\syscal"..unpr,\syscal"..pure +ifl .M".purpg*2000-syscal"..unpr,.err UNPURE overlaps with PURE +termin + +define norm7 c ;normallize a 7-bit byte pointer + skipge c + sub c,[430000,,1] +termin + +define decbp c ;decrement byte pointer + add c,[70000,,] ;back up the byte pointer + skipge c ;did we cross a word boundary? + sub c,[430000,,1] ;then fix it +termin + +define decbp6 c ;decrement byte pointer + add c,[60000,,] ;back up the byte pointer + skipge c ;did we cross a word boundary? + sub c,[440000,,1] ;then fix it +termin + +;;; This macro takes two arguments, the first is a starting location in +;;; memory, and the second is a # of characters after that. +;;; It returns the BP that you'd get after that # of IDPB's into that buffer +define bpend buf,ln +<<000700+<<<<5-*5>>*7>+1>_14>>,,>> termin + +define upper chr ;uppercase a character + cail chr,141 ;lower "a" + caile chr,172 ;lower "z" + caia ;if got here, it's not lower a-z, skip + subi chr,40 ;convert case +termin + +define curpos vert,horz ;move cursor to absolute position + .iot tyoc,[^P] + .iot tyoc,["V] + movei 0,-1(vert) + .iot tyoc,0 + .iot tyoc,[^P] + .iot tyoc,["H] + movei 0,-1(horz) + .iot tyoc,0 +termin + +ifndef $type,$type=0 ;default +ifn $TYPE,[ +define type chan=tyoc,&STRING + push sp,[outspc chan,string] + call syscal"typer + pop sp, +termin + +define error &mesage + push sp,[outspc dspc,mesage] + call syscal"typer + pop sp,errmsg +termin + +define outspc chan,&string + <+<.length string>>,,[asciz string] +termin + +.begin syscal +.pure +typer: push sp,a + push sp,b + push sp,c + hrlzi a,440700 + hrr a,-4(sp) + ldb b,[221600,,-4(sp)] + movem b,siotct +var .M"SIOTCT + ldb c,[400400,,-4(sp)] + syscal siot,[c ? a ? siotct] + .lose 1400 + pop sp,c + pop sp,b + pop sp,a + ret +.upure +.end syscal +] + + +define do stuff,else,\label +define ddoo exit + jrst [stuff +jrst label] +!else! + +label:: +termin + +ddoo + +termin + + +define tabdef name + define name cruft + cruft + termin + +define a!name more + name [define name cruft + cruft + more] + termin + termin +termin + +;;; basic definitions +pjrst==jrst ;for pushj sp, ? popj sp, sequences. +call=pushj sp, +ret=popj sp, + +;;; macros to evaluate system symbols and locations + +define seval a,b ;get value of symbol B in A + move a,[squoze 0,/b/] + .eval a, + loss +termin + +define eval a,b + seval a,b + hrl a,a ;move to left + hrri a,a ;destination is a + .getloc a, ;get it into a +termin ;done! + +define pcall routin,args + push sp,args + call routin + pop sp,x +termin diff --git a/src/sysen1/inline.51 b/src/sysen1/inline.51 new file mode 100644 index 00000000..7a59e283 --- /dev/null +++ b/src/sysen1/inline.51 @@ -0,0 +1,220 @@ +; -*- MIDAS -*- + +title DDT init file hack to read a line from the TTY. + +; this program with some extra comments for instructional purposes. + +tyic==2 +tyoc==3 + +a=1 +b=2 +c=3 +d=4 +count=5 +sp=17 + +call=pushj sp, +ret=popj sp, + +pdlen=10 ;short pdl + +.insrt rwk;syscal > + +inline: move sp,[-pdlen,,pdl] + .break 12,[5,,jclbuf] + syscal open,[cnti .uai + argi tyic + [sixbit /TTY/]] + .lose 1400 + + syscal open,[cnti .uao+%TJDIS ;open in display mode + argi tyoc + [sixbit /TTY/]] + .lose 1400 + + syscal ttyset,[argi tyic ;set the TTY paramaters + [020202,,020202] ;no echoing, we do our own + [020202,,020202] + [%TSSII+%TSCLE,,0]] ;get ^Z, ^_, and don't clear on ^L + .lose 1400 + + syscal cnsget,[argi tyic ;get info on this TTY to rubout correctly + val vsize + val hsize + val 0 + val 0 + val ttyopt] ;this has %TOERS which says if we can erase + .lose 1400 + + move c,[350700,,buffer+1] ;byte pointer into buffer after our initial + ;:KILL + move a,[440700,,jclbuf] ;and to our JCL +jclscn: ildb b,a ;get a char + caie b,^M ;(caie = skip if equal to effective address) + cain b,^C ;if end (cain is same but skip if not equal) + jrst gtchrs + idpb b,c + jrst jclscn ;loop till end (jrst = go to) + +gtchrs: setzm count ;we start here + movem c,bpsav ;for later typeout from this point + cain b,177 ;did it end with a rubout? + jrst backup ;yep, flush it, and don't add a space + movei b,40 ;nope, add in a space after the command + idpb b,c ;put it there + movem c,bpsav ;and remember THIS as the start instead. + +inloop: .iot tyic,b ;read the character + cain b,177 ;is it a rubout? + jrst rubout ;go rub it out. + cain b,^L ;is it a ^L? + jrst displa ; yes, re-display + cain b,^Z ;is it a ^Z? + jrst byebye ;yes, quit + cain b,^D ;is it a ^D + jrst flush ;go flush it. + cain b,^W ;kill word? + jrst kword ; yes, go kill it. + aos count ;it's not a command, + cain b,^Q ;is it ^Q ? + jrst [.iot tyoc,b ; yes, echo the ^Q + .iot tyoc,[":] ; prompt + .iot tyic,b ; get another character + movei d,3 ; 3 positions to wipe out + call wipe ; wipe out that may characters + jrst dput] +dput: idpb b,c ;it's data, write it into the buffer + skipe lfflag ;do we need to LF because of rubouts? + jrst [.iot tyoc,[^J] ;LF + setzm lfflag ;note that we've done it + jrst echo] ;and continue +echo: .iot tyoc,b ;echo it + caie b,^C ;skip to do the .VALUE if it's ^C + cain b,^M ;if not, skip if it's not a CR, to not do it + .value buffer ; do it + jrst inloop ;get another character + +rubout: cain count, ;don't delete past beginning + jrst [.iot tyoc,[7] ;beep at him + jrst inloop] ;and don't do it! + sos count + ldb b,c ;get the character being rubbed out + movei d,1 ;most chars are 1 char wide + cail b,40 ;if control + cain b,177 ;or rubout + movei d,2 ;it's two instead + call wipe ;wipe out that many characters + +backup: decbp c ;decrement the byte pointer (macro) + jrst inloop ;go get another char + +displa: setzm lfflag ;don't need to LF after rubout if displayed + move b,ttyopt + tlnn b,%toers ;is it erasible? + jrst [.iot tyoc,[^M] ;terpri rather than ^PA, want it to do + .iot tyoc,[^J] ;something visible on empty line. + jrst displ1] ;and continue + + .iot tyoc,[^P] ;clear the screen + .iot tyoc,["C] ;since that's what people expect when they + ;type ^L + +displ1: move b,count ;need a copy of the count + move d,bpsav ;start it at where he started inputing + syscal siot,[argi tyoc ;type it out + d ? b] + .lose 1400 + jrst inloop ;and continue reading. + +flush: setzm lfflag ;don't need to LF after rubout if flushed + movei b,.length /^D XXX? +/ + move d,[440700,,[ascii /^D XXX? +/]] + syscal siot,[argi tyoc ? d ? b] ;type the ^D XXX? + .lose 1400 + setz count, ;back to the start + move c,bpsav + + jrst inloop + +kword: skipn count ;if count is zero + jrst [.iot tyoc,[7] ; beep + jrst inloop] ; and don't do anything + setz d, ;zero d, which is count of positions to wipe +kword1: ldb b,c ;get the character + caie b,177 ;rubout + cail b,40 ;or control + aos d ; it takes two chars to rub out + decbp c ;decrement the bp + sosg count ;back up the count + jrst kword3 ; oops, back to the begining + upper b ;uppercase b. + cail b,"A ;if not alphabetic + caile b,"Z + jrst kword1 ;then get another character +kword2: ldb b,c ;get another + upper b + cail b,"A ;if not before a word + caile b,"Z + jrst kword3 ;keep going back + caie b,177 ;rubout + cail b,40 ;or control + aos d ; it takes two chars to rub out + decbp c ;get the previous byte + sose count ;back up the count + jrst kword2 ; it's ok, we've got more chars + +kword3: call wipe ;clear the screen + jrst inloop ;backed over a word, ok. + +wipe: movni d,(d) ; d <- - + hrlzi d,(d) ; D <- ,,0 + push sp,b ;we use B locally +wipe1: move b,ttyopt + tlne b,%TOERS ;skip if can't erase + jrst [.iot tyoc,[^P] ;type the erase character ^P code (^PX) + .iot tyoc,["X] + jrst gobk] ;and return + + tlnn b,%tomvb ;if this TTY can't backspace directly + jrst [ldb b,c ;we can't erase, so, we + .iot tyoc,b ; echo deleted char (crude, but effective) + jrst gobk] ;and return + + .iot tyoc,[^H] ;backspace + .iot tyoc,["/] ;wipe it out + .iot tyoc,[^H] ;and back over it + setom lfflag ;and note to LF when we get real char. +gobk: aobjn d,wipe1 ;loop for each character. + pop sp,b ;restore b + ret ;return to caller + +byebye: movei a,.length /Flushed +/ + move b,[440700,,[ascii /Flushed +/]] + skipe lfflag ;do we need to LF because of rubouts? + .iot tyoc,[^J] ; yes. Don't bother zeroing flag, we die + skipn lfflag ;otherwise we need to space + .iot tyoc,[40] + syscal siot,[argi tyoc ? b ? a] ;type it out + jfcl + .logout 1, ;bye-bye + +bpsav: 0 ;saved byte pointer to start of user text +vsize: 0 +hsize: 0 +ttyopt: 0 +lfflag: 0 ;set non-zero if we have just rubbed out + ;means to LF when get a real char. +ocount: 0 ;count before killing word + +buffer: ascii /:KILL / ;buffer to write our DDT command in + block 150 + +jclbuf: block 100 +pdl: block pdlen + + end inline