!ECCExx: Implementation of ECCE for 2900/EMAS, VAX/VMS and APM ! Revised specification (1981/82) including video support. ! Hamish Dewar Edinburgh University Computer Science Department ! ! V0 (09/02/81): initial test release ! V1 (04/06/81): VT52/Bantam/hard-copy support ! V2 (16/11/81): Esprit supported / Overwrite + C- ! V3 (03/03/82): Overwrite modded + K- ! V4 (15/12/82): revised macros & block move ! V5.0 (29/01/83): standard VTI / revised overwrite ! ! This single source file covers the three versions. ! Simulated conditional compilation statements are used for parts ! which are special to specific versions. All these versions ! assume the availability of sufficient memory (virtual or real) ! to avoid the necessity for manipulating explicitly created ! temporary files. In the Emas version the source file (and any ! secondary files) are mapped directly into virtual memory and ! a separate area is used for the new file being created; in the ! VMS version (because of the idiosyncratic record format of files), ! and the APM version (because of lack of virtual memory at present), ! the source file is 'read in' to the new file area (and secondary ! file to its own area). ! All versions use the EUCSD standard Video Terminal Interface and ! VM management routines, together with the IMP run-time support ! library. ! ! The ASCII character set is assumed, with NL (pre-defined = LF) ! as the line-break character WITHIN THE TEXT FILE. ! The Editor expects to receive RETURN (= ASCII RT) and LF distinctively ! FROM THE KEYBOARD, and at present expects THESE CHARACTERS TO BE ! INTERCHANGED. ! ! One of the objectives in the design of the video facilities was ! to avoid having to pre-suppose single-character interaction on ! sequences of printing characters. There are a few cases where ! there would be a small ergonomic gain from exploiting this mode ! of operation on a system where it is unproblematic, but it ! would be a pity to lose compatibility on that score. ! The Editor does pre-suppose termination of input on any control ! character or control sequence without echoing; it might be possible ! to make a special case of some or all of the cursor controls ! where the performance implications of interaction even on every ! control key is problematic. ! ! ! ! ! ! ! ! ! ! ! !!!!!!!!!!!!!! Standard Video Terminal Interface !!!!!!!!!!!!! !$IF EMAS OR VAX ! Terminal mode constinteger SINGLE=1, NOECHO=4, PASSDEL=8, NOTYPEAHEAD=16, NOTERMECHO=32, CONTROLTERM=64, LEAVECONTROLS=256, SPECIALPAD=8192, NEWTCP=16384 constinteger SCREENMODE=controlterm+notermecho+leavecontrols+passdel ! Video FUNction/MODE flag values:- constinteger INTENSE=1, REVERSE=2, UNDERLINE=4, BLINK=8, SHADE=15 constinteger FULLSCROLL=16, ANYSCROLL=32; !FUN only constinteger NOSCROLL=16, FREEZE=32; !MODE only recordformat WININFO(byteinteger top,rows,left,cols, row,col,fun,mode) externalrecord(wininfo)spec VDU externalrecord(wininfo)spec WIN externalintegerspec VTTYPE ! externalroutinespec DEFINE VIDEO alias "VTDEFVIDEO"(integer emastype) externalroutinespec SET VIDEO MODE alias "VTSETVIDEO"(integer mode) externalroutinespec PUSH WINDOW alias "VTPUSH" externalroutinespec POP WINDOW alias "VTPOP" externalroutinespec SWOP WINDOW alias "VTSWOP" externalroutinespec SET FRAME alias "VTSETFRAME"(integer t,r,l,c) externalroutinespec SET MODE alias "VTSETMODE"(integer m) externalroutinespec SET SHADE alias "VTSETSHADE"(integer s) externalroutinespec CLEAR LINE alias "VTCROL" !%externalroutinespec CLEAR FRAME %alias "VTCFRAME" externalroutinespec SCROLL alias "VTSCROLL"(integer t,b,n) externalroutinespec VT AT alias "VTSETCURSOR"(integer row,col) !%externalroutinespec GOTOXY %alias "VTGOTOXY"(%integer x,y) ! !$IF EMAS {%recordformat EVENTINFO(%integer event,sub,extra, %string(255) message) {%externalrecord(eventinfo)%spec EVENT %alias "VTEVENT" {%externalroutinespec OPEN INPUT %alias "VTOPIN"(%integer s, { %string(255) file) {%externalroutinespec OPEN OUTPUT %alias "VTOPOUT"(%integer s, { %string(255) file) {%externalroutinespec CLOSE INPUT %alias "VTCLIN" {%externalroutinespec CLOSE OUTPUT %alias "VTCLOUT" {%externalintegerfnspec OUTSTREAM %alias "VTOUTS" !$IF EMAS OR VAX externalroutinespec SELECT INPUT alias "VTSELIN"(integer i) externalroutinespec SELECT OUTPUT alias "VTSELOUT"(integer i) externalroutinespec PRINT SYMBOL alias "VTPSYM"(integer sym) externalroutinespec SPACE alias "VTSP" externalroutinespec SPACES alias "VTSPS"(integer n) externalroutinespec NEWLINE alias "VTNL" externalroutinespec NEWLINES alias "VTNLS"(integer n) externalroutinespec PRINT STRING alias "VTPSTRING"(string(255) s) externalroutinespec WRITE alias "VTWRITE"(integer v,p) externalroutinespec VTPROMPT alias "VTPROMPT"(string(255) s) externalroutinespec READ SYMBOL alias "VTRSYM"(integername k) externalintegerfnspec NEXT SYMBOL alias "VTNSYM" externalroutinespec SKIP SYMBOL alias "VTSSYM" externalroutinespec READ alias "VTREAD"(integername v) constinteger bs=8, rt=13, esc=27, del=127 !$FINISH constinteger bantam=6 ! !!!!!!!!!!!!!!!!! Other external refs and globals !!!!!!!!!!!!!!!!!!!!!!!!! constinteger ret=10 constinteger casebit=32; !upper<->lower ! !$IF VAX OR APM BEGIN; !program, not routine constinteger CORDON=0 constinteger MAXNAME=127; !max file-name length conststring(3) NULLSTREAM = "NL:" recordformat FILE(string(maxname) NAME, c integer START,LIM,VMSTART,VMLIM,FLAG) !$IF VAX conststring(12) HELPFILE="????????????" conststring(9) DICTFILE="ECCE_DICT" externalroutinespec MOVE(integer length,from,to) !%externalintegerfnspec UINFI(%integer i) !%externalintegerfnspec CHECKQUOTA(%string(127) filename) externalstring(72)fnspec SYSMESS(integer i) externalstring(255)fnspec CLIPARAM ! ! Special routines from PMM to handle file referencing and i/o externalintegerfnspec READIN(string(maxname)name file, integer extra, integername base,start,fend,limit) externalintegerfnspec WRITEOUT(string(maxname)name file, integer base,start,fend,limit) externalroutinespec DELETEVM(integer base,limit) ! routine CONNECT INPUT(record(file)name f) ! Reference file specified by F_NAME ! allocate store to hold it + extra blocks specified by F_FLAG ! place the file in store ! Return store addresses in F_VMSTART/F_VMLIM ! file addresses in F_START/F_LIM ! ( VMSTART <= START <= LIM <= VMLIM ) ! ! Discard any previous input file deletevm(f_vmstart,f_vmlim) if f_vmstart # 0 ! Read the file in f_flag = readin(f_name,f_flag,f_vmstart,f_start,f_lim,f_vmlim) if f_flag # 0 start print string(" *".sysmess(f_flag).": ".f_name) ! no newline at present f_vmstart = 0; f_start = 0; f_lim = 0 finish ! Ensure that file does not end with partial line f_lim = f_lim-1 while f_lim # f_start and byteinteger(f_lim-1)#nl end; !CONNECT INPUT routine CONNECT DICT(integername base) integer f,s,l externalintegerfnspec connect(string(127) file, integername start,length) f = connect(dictfile,s,l) f = connect("DR0:[HMD.ECCE]DICT.MAP",s,l) if f&1 = 0; !*temp* if f&1 = 0 then print string("Dictionary not available") c else base = s end ! !$IF APM {%routine MOVE(%integer length,from,to) { %while length > 0 %cycle { byteinteger(to) = byteinteger(from) { to = to+1; from = from+1; length = length-1 { %repeat { %return {! length = length-1 {! %return %if length <= 0 {! *MOVE FROM,A0; *MOVE TO,A1; *MOVE LENGTH,D0 {! *MOVE.B (A0)+,(A1)+; *DBRA D0,-4 {%end {! {%routine CONNECT INPUT(%record(file)%name f) { %on %event 9 %start { printstring(event_message) { f_flag = 1 { %return { %finish {! %if f ## sec %then open input(2,f_name) %c {! %else open input(3,f_name) { open input(2,f_name) { select input(0) {%END {! !$IF EMAS {%constinteger CORDON=2; !to alleviate effects of echoed typeahead {%constinteger MAXNAME=31 {%conststring(5) NULLSTREAM = ".NULL" {%conststring(24) HELPFILE = "ECSLIB.GENERALY_ECCEVIEW" {%conststring(24) DICTFILE = "ECSLIB.GENERALY_ECCEDICT" {%externalroutinespec PROMPT(%STRING(15) S) {%externalroutinespec VIEW(%STRING(255) S) {%recordformat FILE(%string(maxname) NAME, %integer START,LIM,FLAG) {! {%routine MOVE(%integer length, from, to) { *LB_LENGTH { *JAT_14,<L99> { *LDTB_X'18000000' { *LDB_%B { *LDA_FROM { *CYD_0 { *LDA_TO { *MV_%L=%DR {L99: {%END {%INCLUDE "ECSC10.ECCE_FCP" {! !$FINISH ! !!!!!!!!!!!!!!!!!!! Editor parameters and options !!!!!!!!!!!!!!!!! !** NB ORDER -- see VALUE constinteger optnames=18, optmax=5 ! vcccwwwwtemmmwm ! mcltclrttaaiaia ! ooeooeooyrrnrdp ! dlfplfwpplkwgtc ! est sts ey iiha ! nn s constinteger numeric=2_111111111001110 ! owninteger mapcase=1; !1/0 ignore/heed case owninteger width=80; !line width owninteger margin=0; !left margin owninteger minwin=7; !minimum window size owninteger mark=0; !1/0 show FP by mark/hilight owninteger early=0; !1/0 update early/late !Settable at outset only:- !$IF EMAS {%owninteger ttype=-1 !$IF VAX OR APM owninteger ttype=11; !terminal type (ERCC coding) !$FINISH owninteger wtop=0, wrows=255; !window area top,rows owninteger wleft=0, wcols=255; !window area left,cols owninteger ctop=99; !command row (1st of 2) owninteger cleft=0, ccols=255; !command area left,cols !$IF VAX OR APM owninteger vmode=0 !$IF EMAS {%owninteger vmode=newtcp !$FINISH ownstring(maxname) pre=""; ![treated specially] !** end of OPTIONS ownrecord(file) in,sec,out conststring(7)array optname(1:optnames) = "NOMATCH", "MATCH", "WIDTH", "MARGIN", "MINWIN", "HILIGHT","MARK", "LATE", "EARLY", "TTYPE", "WTOP", "WROWS", "WLEFT", "WCOLS", "CTOP", "CLEFT", "CCOLS", "VMODE" ! integermap value(integer i) result == integer(addr(mapcase)+i<<2); !mapcase == 0 end !!!!!!!!!!!!!!!!! Command parameter processing !!!!!!!!!!!!!!!!! ! routine SET PARAMETERS(string(255) parm) integer l,sym on event 9 start; stop; finish ! routine GETNAME(string(maxname)name s) ! Extract next name from PARM, leaving terminator in SYM s = "" cycle sym = nl l = l+1 and sym = charno(parm,l) if l < length(parm) exit if sym<' ' or sym=',' or sym='/' or sym='-' or sym='=' if sym = ' ' start exit if s # "" finish else start sym = sym-casebit if sym >= 'a' sym=0 and return if length(s) >= maxname s = s.tostring(sym) finish repeat s = ".N" if s = nullstream end ! routine GET QUALIFIER integer i,j,k,ll string(maxname) s ll = l+1 get name(s) if s = "PRE" start sym=0 and return if sym # '=' get name(pre) finish else start i = 0; j = 0; k = 1 while optname(k) # s cycle k = k+1 l=ll and sym=0 and return if k > optnames j = j+1; j = 0 and i = i+1 if j = 2 or numeric>>i&1 # 0 repeat if numeric>>i&1 # 0 start sym=0 and return if sym # '=' j = 0 cycle sym = nl l = l+1 and sym = charno(parm,l) if l < length(parm) exit unless '0' <= sym <= '9' j = j*10+sym-'0' repeat finish value(i) = j finish end l = 0 cycle get name(in_name) exit if in_name # "" get qualifier while sym = '-' exit if sym = '/' if sym = nl start prompt("File: ") cycle read symbol(sym) exit if sym < ' ' parm = parm.tostring(sym) repeat finish repeat prompt("") in_name = "" if in_name = ".N" out_name = in_name get name(sec_name) if sym = ',' if sym = ' ' or sym = '/' start get name(out_name) out_name = "" if out_name = ".N" finish get qualifier while sym = '-' if sym # nl start print string(" Faulty parameters: ".parm) newline print symbol(' ') and l = l-1 until l <= -19 print symbol('^'); newline stop finish end; !SET PARAMETERS ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!! Key definition map and macros !!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! The Video Terminal Interface converts multi-character ! control sequences to character values in the range 128:255. ! For 2-char sequences, the value is 2nd char + 128. ! For 3-char sequences, the value is 3rd char!!96 + 128 ! The array DEF records the significance of each symbol, ! as either a basic symbol (<32768) or macro definition. ! Initial entries are a melange of values relevant to specific ! known terminals. constinteger posmask=16_3FFF, limshift=14 constinteger macro=1<<limshift, null=640<<limshift+640, nullref=127 !128:191 second 0-63 third (!!96) 64:127 !192:255 second 64-127 third (!!96) 0:63 ownintegerarray DEF(0:255) = ' ', 'G', 'K', ' ', ' ', ' ', ' ', ' ', 'g'{BS}, 'N'{TAB}, 'M'{LF}, '{'{VT}, '>'{FF}, '1'{RT}, 'E', 'I', ' ', ' ', ' ', ' ', ' ', ' ', '}', ' ', '>'{CAN}, 'E'+'0'<<8, ' ', ' '{ESC}, ' ', ' ', '}', ' ', ' ', '!', '"', '#', '$', '%', '&', '''', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', ' ', ' ', ' ', '[', '¬', ']', '^', '_', '|!|M', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 650<<limshift+648, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', ' ', ' ', ' ', '{', '||', '}', '~', null, ' ', ' ', ' ', ' '{?c}, ' ', ' ', ' ', ' '{?g}, ' ', ' '{?i}, ' ', ' '{?k}, 'F'+'"'<<8{?l}, 'm'+'0'<<8{?m}, ' ', ' '{?o}, 'F'+'!'<<8{p}, 'E'+'0'<<8{?q}, 'S'+'!'<<8{?r}, '^'{?s}, 'K'{?t}, 'E'{?u}, 648<<limshift+644{?v}, 'G'+'0'<<8{?w}, 'I'{?x}, 644<<limshift+640{?y}, ' '{?z}, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '{?C}, ' ', ' ', ' ', ' '{?G}, ' ', ' ', ' ', '}'{?K}, '{'{?L}, '¬'{?M}, ' ', ' '{?O}, ' ', 'o'+'0'<<8{1}, ' '{2}, ' '{?S}, ' ', ' ', ' ' ,' '{?W}, ' ', ' ', ' ', ' '{?[}, ' '{¬}, ' '{]}, ' '{^}, ' '{_}, '}'{@}, '{'{A}, '}'{B}, '>'{C}, '<'{D}, 'G'{E}, ' ', ' '{G}, 'L'+'0'<<8{H}, ' ', '$'{J}, 'e'+'0'<<8{K}, ' ', 'k'{M}, ' ', ' '{O}, ' ', 'I'{Q}, 'K'{R}, ' ', 'E'+'0'<<8{T}, ' ', ' ', 'E'{W}, ' ', ' ', ' ', ' '{[}, ' ', ' '{]}, ' '{^}, ' '('f'-'^'-1), 'S'+'"'<<8{f}, ' ', ' ', 'i'+'0'<<8{i}, ' '('z'-'i'-1), 'n'{z}, ' '(127-'z') !$IF EMAS OR VAX constinteger macbound=16383 !$IF APM {%constinteger macbound=8191 !$FINISH ownbyteintegerarray mac(0:macbound) = 0 (640), 'I','.',' ','.', 'D','.',' ','.', '%','H', 0 (*) !Indexing MAC: !FREEBASE,COMBASE,INSERTBASE re-assignable constinteger textlim=128 owninteger freebase=128, combase=256, insertbase=384, matchbase=512, macbase=640, macfree = 650 ! !!!!!!!!!!!!!!!!!!! Start of Editor proper !!!!!!!!!!!!!!!!!!! ! routine EDI(record(file)name old,secfile,new, string(255) message) ! Only the START and LIM components of the file info records ! OLD, SECFILE and NEW are relevant for editing (except when ! referencing secondary input). ! In the Vax version the original file is copied into the ! working space (NEW) prior to entry; in the EMAS version ! it is accessed (initially) in its original mapped site. ! constinteger stopper=-10000; !loop stop !$IF EMAS OR VAX constinteger mingap=4096; !room for manoeuvre !$IF APM {%constinteger mingap=1024 !$FINISH integer code; !command code integer ref; !text or bracket pointer integer scope; !search limit integer num; !repetition number owninteger term=ret; !last symbol read owninteger sym=ret; !last symbol got integer control,fpsym,pend; !characters integer hold,holdsym,pos; !work variables owninteger edmode=-1; !command/data owninteger error=0 owninteger commandstream=0; !0[1] for terminal[file] owninteger sin=0; !0[1] for main[secondary] input owninteger casemask=¬casebit; !¬casebit/¬0 to ignore/heed case owninteger dict=0 ! !File state info recordformat fstate(integer start {start of file}, lbeg {line start position}, fp {current position}, lim {end of file}, line {line number of current pos}, diff {diff between LINE and ROW}, top {top row of sub_window}, win {floating top}, bot {bottom row of sub_window}, min {minimum window size}) !** Note that LBEG is such that FP-LBEG = #chars to left of FP ownrecord(fstate) cur=0,main=0,sec=0 integer fp; !current file position integer fp1; !temporary FP integer lend; !line end position integer gapstart,gaplim; !gap start/limit integer oldgapstart,oldgaplim owninteger gapline !The following assumes that (relevant) addresses are positive constinteger floor=0; !** LESS THAN ANY VALID ADDRESS ** constinteger ceiling=16_7FFFFFFF integer newlim; !effective limit of new file !also = start of deletion store integer delmax; !current end of deletions !$IF EMAS {%integer gdiff !$IF VAX or APM constinteger gdiff=0 !$FINISH owninteger foundpos=0,foundsize=0; !matched text info owninteger markpos=0,markline; !marker position ! ! Video control owninteger video=0 owninteger fscroll=0, cscroll=0 owninteger chalf=0 owninteger vgap=0 constinteger unknown=-99999; !impossible value for _DIFF constinteger offscreen=99; !impossible value for _WIN owninteger joins=0; !count of lines added/removed owninteger endon=0; !**END** displayed indic owninteger altmin,altlim; !pos of earliest/latest alteration owninteger altline; !for ALTMIN owninteger altlimlbeg=0; !for ALTLIM integer fprow,fpcol integer vp; !file pointer for displaying owninteger printline=0,printed=0; !for hard-copy ! ownstring(2) newprom="??", curprom="" conststring(2)array prom(0:3) = ">>", "$$", "^>", "^$" ! integer dictpos integer mac0 owninteger reflim=128,reflim1=128 constinteger mstbound=7 ownintegerarray mstack(0:mstbound) = 0 (*) owninteger msp=0; !macro stack pointer owninteger comlim owninteger tlim,tlim1 owninteger inpos=0,inlim=0,inlim1=0 constinteger null=640<<limshift+640 owninteger idef=null,mdef=null owninteger traildels=0 ! !Cell format for storage of commands recordformat commandcell(byteinteger code,ref, c SHORTinteger scope, integer count) constinteger cbound=60 record(commandcell) array r(1:cbound) owninteger ci=0,cmax=0,cmax1=0; !indexing R ! switch c(4:15), pc('A':95), s(' ':127) integer type,chain ownrecord(commandcell) lastcell ! !Symbol types:- ! 0-3:non-commands 4-7:alteration group 7-9:location group ! 0:numeric 1:terminator 2:illegal 3:quote ! 4: 5:ABCEJKLR@$ 6:ISOG 7:DU ! 8:F 9:TV 10:MNP<>{} 11:( , ! 12: 13:: 14:) 15:? ¬ !High-order bits used to classify chars in file: constinteger lowercase=16_10,digit=16_20,uppercase=16_30, letter=16_10,upperordigit=16_20,alphanum=16_30, opener=16_40,closer=16_80 constbyteintegerarray symtype(0:255) = c 16_01 (32), 16_02{ }, 16_03{!}, 16_03{"}, 16_0A{#}, 16_0A{$}, 16_02{%}, 16_03{&}, 16_03{'}, 16_4B{(}, 16_8E{)}, 16_00{*}, 16_0A{+}, 16_0B{,}, 16_02{-}, 16_03{.}, 16_03{/}, 16_20{0}, 16_20{1}, 16_20{2}, 16_20{3}, 16_20{4}, 16_20{5}, 16_20{6}, 16_20{7}, 16_20{8}, 16_20{9}, 16_0D{:}, 16_01{;}, 16_4A{<}, 16_0F{=}, 16_8A{>}, 16_0F{?}, 16_05{@}, 16_15{A}, 16_15{B}, 16_15{C}, 16_17{D}, 16_15{E}, 16_18{F}, 16_16{G}, 16_12{H}, 16_16{I}, 16_15{J}, 16_15{K}, 16_1A{L}, 16_1A{M}, 16_1A{N}, 16_16{O}, 16_1A{P}, 16_1A{Q}, 16_1A{R}, 16_16{S}, 16_19{T}, 16_17{U}, 16_19{V}, 16_12{W}, 16_12{X}, 16_12{Y}, 16_12{Z}, 16_42{[}, 16_0F{¬}, 16_82{]}, 16_0A{^}, 16_02{_}, 16_02{|!|M}, 16_32{a}, 16_32{b}, 16_35{c}, 16_37{d}, 16_35{e}, 16_38{f}, 16_35{g}, 16_32{h}, 16_35{i}, 16_32{j}, 16_35{k}, 16_3A{l}, 16_3A{m}, 16_3A{n}, 16_35{o}, 16_32{p}, 16_32{q}, 16_3A{r}, 16_32{s}, 16_37{t}, 16_32{u}, 16_32{v}, 16_32{w}, 16_32{x}, 16_32{y}, 16_32{z}, 16_4A{{}, 16_02{||}, 16_8A{}, 16_02{~}, 16_02{127}, 16_02 (128) ! on event 9,14 start; !End-of-input, Too big -> ignore finish -> edistart !!!!!!!!! Simple (command) stream opening and closing !!!!!!!!!!! ! routine OPEN IN(string(maxname) file) on event 9 start printstring(event_message) return finish open input(1,file); select input(1) commandstream = 1 end routine OPEN OUT(string(maxname) file) on event 9 start printstring(event_message) signal 9 finish open output(1,file); select output(1) end routine CLOSE IN close input; select input(0) end routine CLOSE OUT close output; select output(0) end ! !!!!!!!!!!!!!! General-purpose output routines !!!!!!!!!!!!!!!!!!! ! routine PRINT CODE(integer k) ! Print command letter (mapping 'minus' values) print symbol(k-casebit) and k='-' if 'a' <= k <= 'w' print symbol(k) end ! routine AT(integer row,col); !file window swop window if win_top # wtop !$IF EMAS OR VAX vt at(row,col) !$IF APM { gotoxy(col,row) !$FINISH end routine CAT(integer row,col); !command window swop window if win_top # ctop !$IF EMAS OR VAX vt at(row,col) !$IF APM { gotoxy(col,row) !$FINISH end ! routine COMPLAIN(string(255) text) cat(1,chalf); print string(text); print symbol(nl) signal 14 end ! !!!!!!!!!!!!!!!!!!!! Macro management !!!!!!!!!!!!!!!!!!!!!!!!!! ! owninteger rr=0 routine MACPUSH(integer newdef) if newdef # null start complain("* Too many macro levels") if msp > mstbound mstack(msp) = inlim<<limshift+inpos msp = msp+1 inpos = newdef&posmask;l3: inlim = newdef>>limshift finish end ! routine RELEASE(integer k) integer i i = def(k) macfree = i&posmask if i>>limshift = macfree def(k) = ' ' end ! routine COMPRESS(integer needed) !Compress macro text integer oldfree,i,j,p,pos,lim,max integerarray order(0:127) routine SORT(integer a,b) integer l,u,v while a < b cycle l = a-1; u = b v = order(u) cycle l = l+1 until l = u or def(order(l)) > def(v) exit if l = u order(u) = order(l) u = u-1 until u = l or def(order(u)) < def(v) exit if u = l order(l) = order(u) repeat order(u) = v sort(a,l-1) a = u+1 repeat end max = -1 for i = 0,1,255 cycle max = max+1 and order(max) = i if def(i) >= macro repeat sort(0,max) oldfree = macfree; macfree = macbase for i = 0,1,max cycle j = order(i); p = def(j) pos = p&posmask; lim = p>>limshift if pos # macfree start while pos # lim cycle mac(macfree) = mac(pos) macfree = macfree+1; pos = pos+1 repeat p = (lim-macfree)<<limshift+(lim-macfree) def(j) = def(j)-p inpos = inpos-(lim-macfree) if inlim = lim j = msp while j > 0 cycle j = j-1 mstack(j) = mstack(j)-p if mstack(j)>>limshift = lim repeat finish else macfree = lim repeat complain("* Macros too long *") if oldfree-macfree < needed end ! E d i t o r - s p e c i f i c v i d e o r o u t i n e s ! routine SET WINDOWS ! Make window parameters consistent and set up sub-windows ! -- called at outset only integer vrows vrows = vdu_rows-cordon; !effective screen size [temp for Emas] wrows = vrows-2 if wrows > vrows-2; !must have 2 lines for commands ctop = vrows-2 if ctop > vrows-2 wtop = vrows-1 if wtop >= vrows wrows = vrows-wtop if wrows > vrows-wtop wtop = 0 if wtop = 1 and wtop+wrows > vrows-2 wcols = vdu_cols if wcols > vdu_cols if wtop-2 < ctop < wtop+wrows start ctop = wtop+wrows; !try after file window ctop = wtop-2 if ctop+2 > vrows; !before file window finish ccols = 40 if ccols < 40 ccols = vdu_cols if ccols > vdu_cols chalf = ccols>>1 video = vdu_fun if vdu_fun&anyscroll # 0 start; !video can scroll if wcols = vdu_cols start; !full-length rows fscroll = 1 video = video-256 and wrows = wrows+1 if ctop = wtop+wrows finish cscroll = 1 if ccols = vdu_cols finish set frame(wtop,wrows,wleft,wcols) wrows = wrows-1 if video < 0; !restore win_mode = noscroll push window; !save set frame(ctop,2,cleft,ccols) win_mode = noscroll mark = 1 if vdu_fun&intense = 0; !cannot highlight end ! routine COERCE PARAMETERS !Make (dynamically alterable) parameters consistent cur_min = wrows if cur_min > wrows mark = 0 if video = 0 width = 80 unless 5 <= width <= 256 margin = 0 unless margin < width casemask = ¬0; casemask = ¬casebit if mapcase # 0 end ! routine HEADER(integer r) if video # 0 start at(r,0); print string("<<"); print symbol(nl) finish end ! routine SAVE COMMAND !scroll down to preserve command swop window if win_top # ctop scroll(0,1,-1); curprom = "" end ! !!!!!!!!!!!!!! S c r e e n u p d a t i n g !!!!!!!!!!!!!!!!! ! !$IF APM {%routinespec read file !$FINISH routine DISPLAY LINE integer k,p p = fp; p = lend if fp > lend if vp # endon start; cycle vp = gaplim if vp = gapstart if vp = p start cur_diff = cur_line-win_row; !NB external ref while vgap > 0 cycle vgap = vgap-1; print symbol(' ') repeat finish if vp = altlim start altlim = floor return if joins = 0 and vp-altlimlbeg = win_col-mark finish !$IF APM { read file %if vp = cur_lim !$FINISH if vp = cur_lim start endon = vp print string(" **END**") exit finish k = byteinteger(vp); vp = vp+1 if k < ' ' or k >= 127 start exit if k = nl k = '_' finish print symbol(k) repeat; finish print symbol(nl) end ! routine UPDATE ! If a change has been made to the file, update screen, ! but only if change has affected screen line(s). ! ALTMIN and ALTLIM delimit the area which has been affected ! by alterations integer r,c,d,lim return if altlim = floor; !no change => return if video = 0 cur_diff = unknown if joins+cur_min <= 0; !many breaks r = altline-cur_diff if r < cur_win start cur_diff = cur_diff-joins cur_diff = unknown if cur_line-cur_diff >= cur_win finish else if r <= cur_bot start; !within current window vp = altmin; c = 0 cycle altmin = gapstart if altmin = gaplim exit if altmin = cur_start or byteinteger(altmin-1) = nl altmin = altmin-1; c = c+1 repeat swop window if win_top # wtop d = 0; endon = 0 lim = altlim; lim = gapstart if lim = gaplim cycle if c+vgap = 0 and fscroll # 0 and joins # 0 start if joins < 0 start; !net expansion if cur_win > cur_top start cur_win = cur_win-1; r = r-1 cur_diff = cur_diff+1 scroll(cur_top,r,1) finish else start scroll(r,cur_bot,-1) finish joins = joins+1 finish else if altlim = floor or vp = lim start d = cur_bot+1-r-joins if d > 0 start cycle scroll(r,cur_bot,1) joins = joins-1 repeat until joins = 0 cycle; !Scan forward cycle vp = gaplim if vp = gapstart endon = vp and exit if vp = cur_lim vp = vp+1 repeat until byteinteger(vp-1) = nl r = r+1; d = d-1 repeat until d = 0 while r <= cur_bot cycle at(r,mark); display line; r = r+1 repeat exit finish finish finish at(r,c+mark); display line; c = 0; r = r+1 repeat until r > cur_bot or (altlim=floor and joins=0) finish altmin = ceiling; altlim = floor joins = 0 end ! routine DISPLAY(integer indic) ! Update screen & ensure that current line is on screen integer r,pre,count ! routine SCANBACK count = 1 while pre > 0 cycle vp = gapstart if vp = gaplim exit if vp = cur_start cycle vp = vp-1 vp = gapstart if vp = gaplim repeat until vp = cur_start or byteinteger(vp-1) = nl count = count+1; pre = pre-1 repeat end ! update vp = cur_lbeg vp = vp-gaplim+gapstart if vp < gaplim <= fp if video = 0 start printline = cur_line; printed = gapstart+fp cycle vp = gaplim if vp = gapstart printstring("**END**") and exit if vp = cur_lim exit if byteinteger(vp) = nl print symbol(byteinteger(vp)) vp = vp+1 print symbol('^') if vp = fp and num = 1 repeat newline return finish swop window if win_top # wtop; endon = 0 r = cur_line-cur_diff; pre = r-cur_win if pre < 0 start; !before start of window if pre > -cur_min and (fscroll # 0 or r>=cur_top) start !worth prefixing while r < cur_top cycle scroll(cur_top,cur_bot,-1); !scroll down r = r+1 repeat if cur_win # r start cur_win = r header(cur_win-1) if cur_win > cur_top finish cycle at(r,0) print symbol(' ') if mark # 0 display line r = r+1; pre = pre+1 repeat until pre >= 0 return finish finish else start pre = r-cur_bot-1 if pre < 0 start; !within window return if indic = 0 or pre # -1 or lend = cur_lim vp = lend+1 finish if pre < cur_min start; !not far ahead if fscroll # 0 start scanback cycle cur_win = cur_win-1 if cur_win > cur_top scroll(cur_top,cur_bot,1) cur_diff = cur_diff+1 at(cur_bot,mark) display line count = count-1 repeat until count = 0 return finish finish finish !Complete refresh pre = cur_min-1 pre = pre//2 if lend # cur_lim scanback r = cur_bot+1-cur_min; !floating window top if r # cur_win start; !changed if r < cur_top start; !sub-window changed if sin = 0 start; !on main sub-window cur_top = r; sec_bot = r-2 sec_min = sec_bot+1 if sec_min > sec_bot+1 sec_min = 1 if sec_min <= 0 sec_win = 0; sec_diff = unknown finish else start; !on sec sub-window cur_bot = cur_min-1 main_top = cur_bot+2; main_win = main_top main_min = main_bot-main_top+1 if main_min > main_bot-main_top+1 main_min = 1 if main_min <= 0 main_diff = unknown r = 0 finish finish if cur_win = offscreen start if sin = 0 start header(cur_top-1) if cur_top > 0 finish else start header(cur_bot+1) if cur_bot < main_bot finish finish cur_win = r header(cur_win-1) if cur_win > cur_top finish cycle at(r,0) print symbol(' ') if mark # 0 display line r = r+1 repeat until r > cur_bot end ! !!!!!!!!!!!!!!!!! Command input routines !!!!!!!!!!!!!!!!!!!!!!!! ! routine PREPARE FOR INPUT if video = 0 start display(0) if printed # gapstart+fp and cur_min # 0 finish else start display(early) ! Show position of pointer fprow = cur_line-cur_diff; fpcol = fp-cur_lbeg !$IF EMAS OR VAX OR APM at(fprow,fpcol) fpsym = ' ' if mark = 0 start fpsym = byteinteger(fp) if fp < lend set shade(intense) if fpsym > ' ' then print symbol(fpsym) c else print symbol('||') set shade(0) finish else start print symbol('~') ! %if vttype # bantam %then print symbol('~') %c ! %else print symbol(esc) %and print symbol(127); !splodge if fp # cur_lbeg and fp <= lend start if fp # gaplim then fpsym = byteinteger(fp-1) c else fpsym = byteinteger(gapstart-1) finish finish fpsym = '_' if fpsym < ' ' !$FINISH finish end; !PREPARE FOR INPUT routine RESTORE FPSYM !$IF EMAS OR VAX OR APM if fpsym >= ' ' start at(fprow,fpcol); print symbol(fpsym) finish !$FINISH end ! routine READ LINE !Read next command input line inpos = freebase; inlim = inpos cycle read symbol(term) exit unless ' ' <= term <= del if term = del start if inlim # inpos start inlim = inlim-1 finish else curprom = ""; ![*maybe corrupt*] finish else start mac(inlim) = term; inlim = inlim+1 finish repeat inlim1 = inlim end ! routinespec split routinespec consolidate constinteger getting=-1,inserting=0,overwriting=1 routine OBTAIN INSERT TEXT(integer mode) integer p at(cur_line-cur_diff,fp-cur_lbeg+mark) p = freebase; traildels = 0 cycle read symbol(term) if term < ' ' start exit unless def(term) < ' ' term = def(term) printsymbol('_') finish else start exit unless term <= del finish if term = del start if p = freebase start if fp > cur_lbeg start if fp > lend start fp = fp-1 finish else if mode # inserting start consolidate if fp = gaplim fp = fp-1 finish else start split gapstart = gapstart-1; cur_lbeg = cur_lbeg+1 oldgapstart = gapstart altmin = gapstart if altmin > gapstart finish finish finish else start p = p-1; traildels = traildels+1 finish finish else start mac(p) = term; p = p+1 traildels = traildels-1 if traildels > 0 finish repeat if mode = getting start p = freebase and term = ':' if p # freebase and mac(freebase) = ':' term = term-256 and return if p = freebase and term # ret finish if p = freebase then idef = null else start idef = p<<limshift+freebase freebase = insertbase; insertbase = idef&posmask finish end ! routine OBTAIN MATCH TEXT prepare for input cat(0,0); print code(code); print symbol('!') curprom = "" clear line mdef = matchbase cycle read symbol(term) exit unless ' ' <= term <= del if term = del start if mdef # matchbase start mdef = mdef-1 finish finish else start mac(mdef) = term; mdef = mdef+1 finish repeat restore fpsym if mdef = matchbase then mdef = null c else mdef = mdef<<limshift+matchbase end ! F i l e m a n i p u l a t i o n r o u t i n e s ! integerfn distance(integer from,to) if gaplim <= to <= cur_lim start from = from+(gaplim-gapstart) unless gaplim <= from <= cur_lim finish else start to = to+(gaplim-gapstart) if gaplim <= from <= cur_lim finish result = to-from end ! routine MOVE BLOCK(integer length,from,to) !Move block of file, dealing with overlap & relocation !The following are relocated: FP, LBEG, LEND, FOUNDPOS, MARKPOS, ! ALTMIN, ALTLIM, ALTLIMLBEG integer reloc,limit reloc = to-from; limit = from+length if from <= fp < limit start fp = fp+reloc; cur_lbeg = cur_lbeg+reloc; !LBEG always relative to FP finish lend = lend+reloc if from <= lend < limit foundpos = foundpos+reloc if from <= foundpos < limit markpos = markpos+reloc if from <= markpos < limit altmin = altmin+reloc if from <= altmin < limit if from <= altlim < limit start altlim = altlim+reloc; altlimlbeg = altlimlbeg+reloc finish while reloc > 0 and length > reloc cycle; !down and bigger than gap length = length-reloc move(reloc,from+length,to+length) repeat move(length,from,to) end !$IF EMAS {%routine COPY ACROSS { move block(cur_lim-gaplim,gaplim,gaplim+gdiff) { gaplim = gaplim+gdiff; oldgaplim = oldgaplim+gdiff { gdiff = 0 { cur_lim = newlim {%end !$FINISH !$IF APM {%constinteger out=2 {%constinteger maxline=256 { {%routine WRITE FILE(%integer from,to) { new_flag = -1 { select output(out) { %while from # to %cycle { print ch(byteinteger(from)); from = from+1 { %repeat { select output(0) {%end !$FINISH routine MAKE ROOM !The gap has become too small: shuffle to enlarge it !$IF APM {!Write out part of the file to create space {%constinteger chunk=mingap+mingap; !(maximum) amount to be expelled {%integer p,diff,top; !??TOP?? { top = cur_start; p = cur_lbeg-gaplim+gapstart { %if p > top+chunk %start { p = top+chunk { top = top+1 %while byteinteger(top+(chunk-1)) # nl { %finish { write file(cur_start,p); !write it out { diff = gapstart-p { move block(diff,p,cur_start) { altmin = altmin-diff %if altmin <= gapstart { gapstart = gapstart-diff { %seturn %if oldgaplim-gapstart >= mingap !$FINISH complain("* Insertions too big *") if new_lim-delmax < mingap !$IF EMAS { copy across %if gdiff # 0 !$FINISH move block(delmax+1-oldgaplim,oldgaplim,oldgaplim+mingap) oldgaplim = oldgaplim+mingap; gaplim = gaplim+mingap cur_lim = cur_lim+mingap newlim = newlim+mingap; delmax = delmax+mingap end !$IF APM {%routine READ FILE {!Read in more of the file (at least one line) {%constinteger upshift=2048 {%integer p,diff,lim {%on %event 9 %start { select input(0) { %return {%finish { %if cur_lim >= old_vmlim-maxline %start; !approaching end of buffer space { make room %if gaplim-gapstart < upshift { diff = cur_lim-gaplim { move block(diff,gaplim,gaplim-upshift) { vp = vp+upshift %if vp >= gaplim { gaplim = gaplim-upshift { cur_lim = cur_lim-upshift { %finish { select input(2) { p = cur_lim { %cycle { read ch(byteinteger(p)) { p = p+1 { %repeat %until byteinteger(p-1) = nl { cur_lim = p { select input(0) {%end !$FINISH ! routine STORE DELETIONS integer l,k !Discard part line delmax = delmax-1 while byteinteger(delmax) # nl cycle l = gaplim-oldgaplim if l+delmax >= new_lim start !$IF EMAS { copy across %if gdiff # 0 !$FINISH k = oldgaplim-gapstart; signal 14 if k <= 0 if k > 1024 start; !a bit much if k > l > 1024 then k = l else k = 1024 finish move block(delmax+1-oldgaplim,oldgaplim,oldgaplim-k) gaplim = gaplim-k; oldgaplim = oldgaplim-k cur_lim = cur_lim-k newlim = newlim-k; delmax = delmax-k l = k if k < l finish move(l,oldgaplim,delmax+1) oldgaplim = oldgaplim+l; delmax = delmax+l repeat until oldgaplim = gaplim end routine ALTER !Note min/max for alteration in situ !$IF EMAS { copy across %if gdiff # 0 !$FINISH if fp < altmin start altmin = fp altline = cur_line; gapline = altline finish if fp > altlim start altlim = fp; altlimlbeg = cur_lbeg finish end ! routine SPLIT !Create gap ahead of FP integer j if fp # gaplim start update if altlim # floor store deletions if oldgaplim < gaplim foundpos = 0 if foundpos < fp < foundpos+foundsize if cur_start <= fp < gapstart start; !fp in upper half !$IF EMAS { copy across %if gdiff # 0 !$FINISH j = gapstart-fp; !amount to shift down gapstart = gapstart-j; gaplim = gaplim-j move block(j,gapstart,gaplim) finish else start; !fp in lower half (old or new) j = fp-gaplim move block(j,gaplim,gapstart) gapstart = gapstart+j; gaplim = gaplim+j finish oldgaplim = gaplim; oldgapstart = gapstart finish if gapstart < altmin start altmin = gapstart altline = cur_line; gapline = altline finish if gaplim > altlim start altlim = gaplim; altlimlbeg = cur_lbeg finish end ! routine BREAK !Break line in two (SPLIT already called) byteinteger(gapstart) = nl; gapstart = gapstart+1 joins = joins-1 markline = markline+1 if markline >= cur_line cur_line = cur_line+1; gapline = gapline+1 cur_lbeg = fp make room if oldgaplim+gdiff-gapstart < mingap end ! routine CONSOLIDATE integer l ! Before moving back etc, ensure that the gap lies on a ! line boundary by copying up the remainder of a split line ! or inserting a newline at end of file return if sin # 0 if gapstart # cus_start and byteinteger(gapstart-1) # nl start store deletions if oldgaplim < gaplim if gaplim # cur_lim start; !not at end of file l = gaplim l = l+1 until byteinteger(l-1) = nl l = l-gaplim move block(l,gaplim,gapstart) gapstart = gapstart+l; gaplim = gaplim+l finish else start alter; !to update ALTMIN break finish oldgapstart = gapstart; oldgaplim = gaplim finish end ! routine SET LEND !$IF APM { read file %if fp = cur_lim !$FINISH lend = fp if lend # cur_lim start lend = lend+1 while byteinteger(lend) # nl finish end ! routine SET LBEG !Establish line start position cur_lbeg = fp cycle if cur_lbeg = gaplim start return if gapstart = cur_start or byteinteger(gapstart-1) = nl cur_lbeg = gapstart cycle cur_lbeg = cur_lbeg-1 repeat until cur_lbeg = cur_start or byteinteger(cur_lbeg-1) = nl cur_lbeg = cur_lbeg+(gaplim-gapstart) return finish return if cur_lbeg = cur_start or byteinteger(cur_lbeg-1) = nl cur_lbeg = cur_lbeg-1 repeat end ! integerfn LINE AFTER !Test Move possible and if so perform it update if altlim # floor result = 0 if lend = cur_lim lend = lend+1 lend = gaplim if lend = gapstart fp = lend; cur_lbeg = fp !$IF APM { read file %if fp = cur_lim !$FINISH if lend # cur_lim start lend = lend+1 while byteinteger(lend) # nl finish cur_line = cur_line+1 result = 1 end ! integerfn LINE BEFORE !Set FP to end of previous line if there is one update if altlim # floor fp = lend if fp > lend consolidate if cur_lbeg < gaplim <= fp fp = cur_lbeg result = 0 if fp = cur_start if fp = gaplim start result = 0 if gapstart = cur_start fp = gapstart finish cur_line = cur_line-1; !there is a line there fp = fp-1; lend = fp set lbeg ! consolidate %if cur_lbeg < gaplim <= fp result = 1 end ! routine EXTEND LINE !Append spaces when FP beyond end of line integer hold hold = fp-lend; fp = lend split while hold > 0 cycle byteinteger(gapstart) = ' '; gapstart = gapstart+1 cur_lbeg = cur_lbeg-1; hold = hold-1 repeat end ! routine INSERT !Insert text specified by IDEF (not null) integer pos,lim pos = idef&posmask; lim = idef>>limshift if fp > lend start fp = lend if mac(pos) = nl extend line finish else split make room if oldgaplim+gdiff-gapstart < mingap cycle if mac(pos) = nl then break else start byteinteger(gapstart) = mac(pos) gapstart = gapstart+1; cur_lbeg = cur_lbeg-1 finish pos = pos+1 repeat until pos = lim end routine OVERWRITE !Overwrite existing text ! with text specified by IDEF (not null) integer pos,lim pos = idef&posmask; lim = idef>>limshift if fp > lend start fp = lend if mac(pos) = nl extend line finish else split make room if oldgaplim+gdiff-gapstart < mingap cycle if mac(pos) = nl start make room if oldgaplim+gdiff-gapstart <= mingap while fp < lend cycle byteinteger(gapstart) = mac(fp) gapstart = gapstart+1; fp = fp+1 repeat if fp # cur_lim start fp = fp+1; cur_lbeg = fp; set lend cur_line = cur_line+1; gapline = gapline+1 altlimlbeg = cur_lbeg if altlim < fp finish finish else if fp < lend then fp = fp+1 c else cur_lbeg = cur_lbeg-1 byteinteger(gapstart) = mac(pos) gapstart = gapstart+1; pos = pos+1 repeat until pos = lim gaplim = fp; altlim = gaplim if altlim < gaplim end routine JOIN ! Erase from FP to end of line AND the line terminator ! (covers Kill, Join, Uncover) integer j if fp > lend then extend line else split j = lend-fp+1 cur_lbeg = cur_lbeg+j; fp = fp+j; gaplim = gaplim+j joins = joins+1 if altlim < gaplim start altlim = gaplim; altlimlbeg = altlim finish set lend markline = markline-1 if markline > cur_line end ! routine SWITCH ! Switch between main and secondary input owninteger maingaplim ![Must scarify GAPLIM on switch to secondary input, as it could ![(on Emas) co-incide with secondary pointer (read SHARED) update if altlim # floor cur_fp = fp; !store markpos = 0; !clear marker sin = sin!!1 if sin # 0 start; !main -> sec main = cur; cur = sec if cur_line < 0 start; !indicator for reset cur_fp = secfile_start cur_lbeg = cur_fp; cur_start = cur_fp cur_lim = secfile_lim cur_line = 1; cur_min = main_bot>>2+1 coerce parameters cur_win = offscreen; cur_diff = unknown finish maingaplim = gaplim; gaplim = cur_start-1; !impossible value finish else start; !sec -> main sec = cur; cur = main gaplim = maingaplim finish fp = cur_fp set lend end ! integerfn MATCHED integer p,pos,lim,k,l p = fp; pos = mdef&posmask; lim = mdef>>limshift cycle k = mac(pos) result = 0 if k = nl l = k!!byteinteger(p) if l # 0 start result = 0 if l&casemask # 0 or symtype(k)&alphanum = 0 finish p = p+1; pos = pos+1 repeat until pos = lim foundpos = fp; foundsize = p-fp result = 1 end ! ! extract next command ! execute: ci = 0 ci = cmax1 if cmax > cmax1 next: s('?'): ci = ci+1 code = r(ci)_code; ref = r(ci)_ref num = r(ci)_count complain("* Alteration not allowed") if sin # 0 and symtype(code)&15 < 8 -> s(code) ! ! Successful return from execution ok: num = num-1 -> next if num = 0 -> s(code) fail: num = 1 ! Failure return no: s('¬'): cycle -> next if num <= 0; !indefinite repetition -> ci = ci+1; !check following cell:- -> next if r(ci)_code = '¬'; !invert -> -> next if r(ci)_code = '?'; !query -> while r(ci)_code # ')' cycle -> next if r(ci)_code = ','; !comma -> ci = r(ci)_ref if r(ci)_code = '(' ci = ci+1 repeat num = r(ci)_count repeat until ci >= cmax -> read if num <= 0 ! !E x e c u t i o n e r r o r ! s(*): ![safety] !suppress report for simple moves as control key macros -> read if control >= 0 and def(control) < 127 c and symtype(def(control))&15 = 10 cat(1,chalf) printstring(" Failure: ") print code(code) if 7 <= symtype(code)&15 <= 9 start; !text matching group print symbol('''') pos = mdef&posmask; hold = pos cycle print symbol('''') and exit if pos = mdef>>limshift print symbol('/') and exit if mac(pos) < ' ' print symbol(mac(pos)) pos = pos+1 repeat until pos-hold >= chalf finish print symbol(nl) error = 1 -> ignore disast: complain("* Insertion(s) too big") ! !I n d i v i d u a l c o m m a n d s ! s('('): !open bracket r(ref)_count = num; !restore count on ')' -> next ! s(')'): !close bracket num = num-1 if num # 0 and num # stopper start r(ci)_count = num; !update ci = ref; !position of '(' finish else start -> read if ci >= cmax finish -> next ! s(','): !comma ci = ref-1; !position of ')' - 1 -> next ! s('P'): display(0) -> ok if num = 1 s('M'): !Move -> no if line after = 0 fp = fp+margin if lend # cur_lim -> ok ! s('}'): !Cursor down hold = fp-cur_lbeg -> no if line after = 0 fp = fp+hold if fp # cur_lim -> ok s('>'): !Cursor right -> no if fp-cur_lbeg >= width or lend = cur_lim fp = fp+1 ->ok ! s('{'): !Cursor up hold = fp-cur_lbeg fp = cur_lbeg+hold and -> no if line before = 0 consolidate if cur_lbeg < gaplim <= fp fp = cur_lbeg+hold -> ok s('#'): !absolute line n code = 'M' num = num-cur_line -> next if num = 0 -> s('M') if num > 0 num = -num; code = 'm' s('m'): !Move back -> no if line before = 0 consolidate if cur_lbeg < gaplim <= fp fp = cur_lbeg if num = 0 start; !M-* consolidate fp = cur_start; fp = gaplim if fp = gapstart cur_lbeg = fp; cur_line = 1 set lend finish fp = fp+margin -> ok ! s('C'): !Case-change with right-shift -> no if fp >= lend holdsym = byteinteger(fp) if symtype(holdsym)&letter # 0 start alter holdsym = holdsym!!casebit byteinteger(fp) = holdsym altlim = fp+1 if altlim <= fp finish ! s('R'): s('l'): !Right-shift -> no if fp >= lend fp = fp+1 -> ok ! s('c'): !Case-change with left-shift fp = lend if fp > lend -> no if fp = cur_lbeg if fp # gaplim then holdsym = byteinteger(fp-1) c else holdsym = byteinteger(gapstart-1) if symtype(holdsym)&letter # 0 start alter if fp = gaplim start gaplim = gaplim-1; oldgaplim = gaplim gapstart = gapstart-1; oldgapstart = gapstart altmin = gapstart if altmin > gapstart finish byteinteger(fp-1) = holdsym!!casebit altmin = fp-1 if altmin >= fp finish s('L'): s('r'): !Left-shift fp = lend if fp > lend s('<'): !Cursor Left consolidate if fp = gaplim -> no if fp = cur_lbeg fp = fp-1 -> ok ! s('E'): !Erase -> no if fp >= lend split cur_lbeg = cur_lbeg+1 fp = fp+1; gaplim = fp altlim = gaplim if altlim < gaplim -> ok ! s('e'): !Erase back fp = lend if fp > lend -> no if fp = cur_lbeg split cur_lbeg = cur_lbeg+1; gapstart = gapstart-1 if gapstart < altmin start altmin = gapstart if gapstart < oldgapstart start oldgapstart = gapstart; oldgaplim = oldgaplim-1 byteinteger(oldgaplim) = byteinteger(oldgapstart) finish finish -> ok ! s('V'): !Verify -> no if fp >= lend if ref = 0 then obtain match text c else if ref # '"' then mdef = def(ref) -> no if mdef # null and matched = 0 -> next ! s('D'): !Delete s('T'): !+ Traverse if ref = 0 then obtain match text c else if ref # '"' then mdef = def(ref) fp1 = fp -> find ! s('U'): !Uncover s('F'): !+Find if ref = 0 then obtain match text c else if ref # '"' then mdef = def(ref) fp1 = fp fp = fp+1 if fp = foundpos find: scope = r(ci)_scope; !number of lines to search -> next if mdef = null holdsym = mac(mdef&posmask); !first symbol of quoted text cycle while fp < lend cycle if (byteinteger(fp)!!holdsym)&casemask = 0 start -> found if matched # 0 finish fp = fp+1 repeat exit if fp = cur_lim scope = scope-1 exit if scope = 0 if code # 'U' start exit if line after = 0 finish else start fp = fp1; fp = lend if fp > lend; join finish fp1 = fp repeat fp = fp1 -> no found: -> ok if code = 'F' fp = fp+foundsize and -> ok if code = 'T' found1: if code # 'U' start; !'D','d' split hold = foundsize finish else start hold = fp-fp1; fp = fp1 split; foundpos = fp+hold finish cur_lbeg = cur_lbeg+hold; fp = fp+hold; gaplim = gaplim+hold altlim = gaplim if altlim < gaplim -> ok ! s('t'): s('d'): s('f'): !Find back fp = lend if fp > lend scope = r(ci)_scope if ref = 0 then obtain match text c else if ref # '"' then mdef = def(ref) -> next if mdef = null holdsym = mac(mdef&posmask); !first symbol of quoted text update cycle while fp = cur_lbeg cycle scope = scope-1 -> no if scope = 0 or line before = 0 repeat consolidate if fp = gaplim fp = fp-1 repeat until (byteinteger(fp)!!holdsym)&casemask = 0 c and matched # 0 -> ok if code = 'f' fp = fp+foundsize and -> ok if code = 't' -> found1 ! constinteger termbit=1<<16, lastbit=1<<15, dummy='a'-1 s('Q'): !Query spelling !$IF APM { complain("Dictionary not available") !$IF EMAS OR VAX if dict = 0 start connect dict(dict) -> ignore if dict = 0 finish if fp = foundpos and foundsize < 0 start; !already Queried fp = fp+1 until symtype(byteinteger(fp))&letter = 0 finish cycle -> no if fp >= lend and line after = 0 holdsym = byteinteger(fp) exit if symtype(holdsym)&letter # 0 fp = fp+1 repeat foundpos = fp; foundsize = -1 fp1 = fp type = termbit>>10 dictpos = integer(dict+(holdsym!casebit)<<2) cycle fp1 = fp1+1; holdsym = byteinteger(fp1)-dummy exit if holdsym <= 0 or holdsym > 26 -> no if dictpos = 0 dictpos = dictpos+dict cycle hold = integer(dictpos) exit if hold&31 = holdsym -> no if hold&lastbit # 0 dictpos = dictpos+4 repeat hold = hold>>5 if hold&31 # 0 start fp1 = fp1+1 -> qno if hold&31+dummy # byteinteger(fp1) finish hold = hold>>5 if hold&31 # 0 start fp1 = fp1+1 -> qno if hold&31+dummy # byteinteger(fp1) finish dictpos = hold>>5&(¬3) repeat -> ok if hold&termbit>>10 # 0 qno: holdsym = byteinteger(fp1) -> ok if symtype(holdsym)&upperordigit # 0 -> no !$FINISH integerfn found closer integer k k = byteinteger(fp)+2; k = ')' if k = '('+2 cycle fp = fp+1 while fp = lend cycle result = 0 if line after = 0 repeat result = 1 if byteinteger(fp) = k if symtype(byteinteger(fp))&opener # 0 start result = 0 if found closer = 0 finish repeat end s('N'): !Next word/element -> no if lend = cur_lim fp = lend if fp > lend holdsym = byteinteger(fp) hold = symtype(holdsym) if hold&alphanum # 0 or holdsym = ' ' start fp = fp+1 while symtype(byteinteger(fp))&alphanum # 0 cycle while fp = lend cycle -> no if line after = 0 repeat exit if symtype(byteinteger(fp))&alphanum # 0 fp = fp+1 repeat foundsize = 0 finish else if hold&opener # 0 start -> no if found closer = 0 foundsize = 1 finish else start cycle fp = fp+1 while fp = lend cycle -> no if line after = 0 repeat repeat until byteinteger(fp) = holdsym foundsize = 1 finish foundpos = fp -> ok ! integerfn found opener integer k k = byteinteger(fp)-2; k = '(' if k = ')'-2 cycle while fp = cur_lbeg cycle result = 0 if line before = 0 repeat consolidate if fp = gaplim fp = fp-1 result = 1 if byteinteger(fp) = k if symtype(byteinteger(fp))&closer # 0 start result = 0 if found opener = 0 finish repeat end s('n'): !Locate previous word/element if fp >= lend start fp = lend; holdsym = ' ' finish else holdsym = byteinteger(fp) hold = symtype(holdsym) if hold&alphanum # 0 or holdsym = ' ' start cycle while fp = cur_lbeg cycle -> no if line before = 0 repeat consolidate if fp = gaplim exit if symtype(byteinteger(fp-1))&alphanum # 0 fp = fp-1 repeat cycle fp = fp-1 exit if fp = cur_lbeg consolidate if fp = gaplim repeat until symtype(byteinteger(fp-1))&alphanum = 0 foundsize = 0 finish else if hold&closer # 0 start -> no if found opener = 0 foundsize = 1 finish else start cycle while fp = cur_lbeg cycle -> no if line before = 0 repeat consolidate if fp = gaplim fp = fp-1 repeat until byteinteger(fp) = holdsym foundsize = 1 finish foundpos = fp -> ok ! s('S'): !Substitute -> no if fp # foundpos if foundsize <= 0 start; !following 'N' etc fp1 = fp fp1 = fp1+1 until symtype(byteinteger(fp1))&alphanum = 0 foundsize = fp1-fp finish split cur_lbeg = cur_lbeg+foundsize; fp = fp+foundsize; gaplim = fp altlim = gaplim if altlim < gaplim ! s('I'): !+Insert -> no if fp-cur_lbeg > width and code # 'S' if ref = 0 start -> over if fp >= lend vgap = wcols - (lend-cur_lbeg+mark) vgap = 10 if vgap < 10 alter display(0) obtain insert text(inserting) !Must ensure update to remove added spaces if idef = null then alter else insert altlim = lend+1; altlimlbeg = altlim ->controlterm if term # ret finish else start idef = def(ref) if ref # '"' -> next if idef = null insert finish -> ok ! !Recovery commands s('o'): !Overwrite back -> no if gapstart <= oldgapstart and gaplim <= oldgaplim if fp # gaplim start update if altlim # floor fp = gaplim cur_line = gapline; set lbeg; set lend finish split if gapstart > oldgapstart start gapstart = gapstart-1 if byteinteger(gapstart) = nl start joins = joins+1 cur_line = cur_line-1; altline = cur_line finish set lbeg; altmin = gapstart finish -> ok if gaplim <= oldgaplim fp = fp-1; gaplim = fp cur_lbeg = cur_lbeg-1 -> ok if byteinteger(fp) # nl joins = joins-1; lend = fp set lbeg -> ok ! s('i'): !Insert back split store deletions if oldgaplim < gaplim ! %if oldgaplim < gaplim %start; !FP was at deletion site ! -> no %if byteinteger(fp-1) = nl ! %finish %else %start -> no if byteinteger(delmax) = nl !$IF EMAS { copy across %if gdiff # 0 !$FINISH oldgaplim = oldgaplim-1; !=GAPLIM & FP byteinteger(oldgaplim) = byteinteger(delmax) delmax = delmax-1 ! %finish fp = fp-1; gaplim = fp cur_lbeg = cur_lbeg-1 -> ok ! s('g'): !Get back split store deletions if oldgaplim < gaplim make room if oldgaplim+gdiff-gapstart < mingap ! %if oldgaplim < gaplim %start ! %cycle ! fp = fp-1 ! joins = joins-1 %and lend = fp %if byteinteger(fp) = nl ! %repeat %until fp = oldgaplim %or byteinteger(fp-1) = nl ! %finish %else %start delmax = delmax-1 while byteinteger(delmax) # nl -> no if delmax = newlim !$IF EMAS { copy across %if gdiff # 0 !$FINISH joins = joins-1; lend = fp-1 cycle fp = fp-1; byteinteger(fp) = byteinteger(delmax) delmax = delmax-1 repeat until byteinteger(delmax) = nl oldgaplim = fp ! %finish gaplim = fp altmin = fp; set lbeg -> ok ! s('O'): !Overwrite -> no if fp-cur_lbeg > width over: if ref = 0 start display(0) obtain insert text(overwriting) if idef = null then alter else overwrite altmin = fp; altlim = lend; !safe assumption -> controlterm if term # ret finish else start idef = def(ref) if ref # '"' -> next if idef = null overwrite finish -> ok ! !!!!!!!!!!!!!!!!!!!!!! Data entry mode !!!!!!!!!!!!!!!!!!!!!! data entry: cycle display(0) if newprom # curprom start curprom = newprom cat(0,0); printstring(curprom) finish obtain insert text(overwriting) if idef # null start -> qread if sin # 0 or lend = cur_lim overwrite if traildels # 0 then altlim = fp+traildels c else altlim = floor and altmin = ceiling; !up-to-date finish exit if term # ret hold = line after fp = fp+margin if lend # cur_lim repeat controlterm: control = term; fpsym = 0 -> again ! !!!!!!!!!!!!!!!!!!!!!!! end of data entry !!!!!!!!!!!!!!!!!!!!! s('G'): !Get (line from terminal) update and consolidate if cur_lbeg < gaplim <= fp fp = cur_lbeg if ref = 0 start split if video # 0 start if video < 0 start display(0) fprow = cur_line-cur_diff scroll(fprow,cur_bot+1,-1) curprom = ""; !lost it finish else start; !Simulate Break & Move back !SPLIT already done break update fp = gapstart-1; cur_lbeg = fp cur_line = cur_line-1 display(0) fprow = cur_line-cur_diff gapstart = gapstart-1 fp = gaplim; cur_lbeg = fp finish finish else printsymbol(':') obtain insert text(getting) if term < 0 start term = term+256 if video # 0 start if video < 0 start scroll(fprow,cur_bot+1,1) finish else start alter; !to set ALT... joins = joins+1 finish finish term = ret and -> no if term = ':' -> controlterm finish insert if idef # null break altlim = floor; altmin = ceiling; !screen up-to-date joins = 0 if video < 0 start; !bring back if fprow = cur_bot start cur_win = cur_win-1 if cur_win > cur_top cur_diff = cur_diff+1 scroll(cur_top,cur_bot+1,1) finish else if edmode >= 0 start cat(0,0); clear line finish finish -> controlterm if term # ret finish else start idef = def(ref) if ref # '"' insert if idef # null break finish -> ok ! s('B'): !Break fp = lend if fp > lend num = 66 if num = 0 or num > 66 split make room if oldgaplim+gdiff-gapstart < mingap break -> ok ! s('k'): !Kill back update if altlim # floor consolidate if cur_lbeg < gaplim <= fp fp = cur_lbeg -> no if fp = cur_start or (fp = gaplim and gapstart = cur_start) cur_line = cur_line-1; !there is a line there split cycle gapstart = gapstart-1 if gapstart < oldgapstart start oldgapstart = oldgapstart-1; oldgaplim = oldgaplim-1 byteinteger(oldgaplim) = byteinteger(oldgapstart) finish repeat until gapstart = cur_start or byteinteger(gapstart-1) = nl altmin = gapstart; joins = 1 -> ok s('K'): !Kill -> no if lend = cur_lim consolidate if cur_lbeg < gaplim <= fp fp = cur_lbeg join -> ok ! s('J'): !Join fp = lend if fp < lend -> no if lend = cur_lim or fp-cur_lbeg > width join -> ok ! constinteger true=1,false=0 integerfn ADJUSTED integer size fp1 = cur_lbeg+margin fp = lend and result = true if fp1 >= lend; !blank line -> fp = fp1 if fp < fp1 cycle fp1 = fp; !last boundary fp = fp+1 while byteinteger(fp) = ' ' fp = fp+1 while byteinteger(fp) > ' ' size = fp-cur_lbeg if size > width start result = false if byteinteger(fp1) # ' ' fp = fp1 result = true finish if fp = lend start fp1 = fp+1 fp1 = gaplim if fp1 = gapstart result = false if fp1 = cur_lim foundpos = fp1 fp1 = fp1+1 while byteinteger(fp1) = ' ' result = false if byteinteger(fp1) = nl or fp1-foundpos < margin foundpos = fp1 fp1 = fp1+1 until byteinteger(fp1) <= ' ' foundsize = fp1-foundpos; size = size+1+foundsize result = true if size > width split join byteinteger(gapstart) = ' '; gapstart = gapstart+1 move(foundsize,foundpos,gapstart) gapstart = gapstart+foundsize; oldgapstart = gapstart fp = foundpos+foundsize gaplim = fp; oldgaplim = gaplim altlim = gaplim if altlim < gaplim cur_lbeg = fp-size finish repeat end; !ADJUSTED s('A'): !Adjust type = adjusted if fp = lend start; !break position is at end of line -> no if line after = 0 finish else start split fp = fp+1; gaplim = fp; !erase space oldgaplim = gaplim; altlim = gaplim if altlim < gaplim break hold = 0 while hold < margin cycle byteinteger(gapstart) = ' '; gapstart = gapstart+1 hold = hold+1 repeat oldgapstart = gapstart cur_lbeg = fp-margin finish -> ok if type # 0 -> no ! s('@'): !'at' Column NUM -> fail if lend = cur_lim hold = width-(lend-fp) num = hold if hold < num hold = fp-cur_lbeg-num -> next if hold = 0 fp = fp-hold and -> next if fp >= lend and fp-hold >= lend split make room if oldgaplim+gdiff-gapstart < mingap cycle if hold < 0 start; !left of it byteinteger(gapstart) = ' '; gapstart = gapstart+1 cur_lbeg = cur_lbeg-1; hold = hold+1 finish else start -> fail if fp = cur_lbeg or byteinteger(gapstart-1) # ' ' gapstart = gapstart-1; cur_lbeg = cur_lbeg+1 altmin = gapstart if altmin > gapstart hold = hold-1 finish repeat until hold = 0 -> next ! routine put number(integer v) put number(v//10) and v = v-v//10*10 if v >= 10 byteinteger(gapstart) = v+'0' gapstart = gapstart+1; cur_lbeg = cur_lbeg-1 end s('-'): s('+'): !Increment Number cycle -> no if fp = lend exit if symtype(byteinteger(fp)) = digit fp = fp+1 repeat split hold = 0 cycle hold = hold*10+byteinteger(fp)-'0' fp = fp+1; cur_lbeg = cur_lbeg+1 repeat until symtype(byteinteger(fp)) # digit gaplim = fp; altlim = gaplim if altlim < gaplim if code = '-' start hold = hold-num; hold = 0 if hold < 0 finish else hold = hold+num put number(hold) -> next s('^'): !Set Marker fp = lend if fp > lend markpos = fp; markline = cur_line if sin = 0 start store deletions if oldgaplim < gaplim oldgapstart = gapstart finish -> ok ! s('='): -> no if markpos = 0 consolidate fp = markpos; cur_line = markline markpos = 0 set lbeg; set lend -> ok s(':'): !Define macro fp1 = markpos if fp1 # 0 start hold = distance(fp1,fp) if hold < 0 start hold = -hold fp1 = fp finish markpos = 0 finish else start -> no if fp # foundpos if foundsize <= 0 start; !following 'N' etc fp1 = fp fp1 = fp1+1 until symtype(byteinteger(fp1))&alphanum = 0 foundsize = fp1-fp finish fp1 = fp; hold = foundsize finish scope = r(ci)_scope release(scope) compress(hold) if macbound-macfree < hold def(scope) = (macfree+hold)<<limshift+macfree while hold > 0 cycle mac(macfree) = byteinteger(fp1) macfree = macfree+1; fp1 = fp1+1 fp1 = gaplim if fp1 = gapstart hold = hold-1 repeat -> next ! s('$'): !switch inputs fp1 = markpos switch if sin = 0 and fp1 # 0 and fp1 # sec_fp start hold = sec_fp hold = fp1 and fp1 = sec_fp if fp1 > hold if fp > lend start fp = lend if byteinteger(fp1) = nl extend line finish else split make room if oldgaplim+gdiff-gapstart < mingap cycle if byteinteger(fp1) = nl then break else start byteinteger(gapstart) = byteinteger(fp1) gapstart = gapstart+1; cur_lbeg = cur_lbeg-1 finish fp1 = fp1+1 repeat until fp1 = hold finish -> next ! ! C o m m a n d i n p u t ! routine GET SYM !Extract next command input symbol !Deal with macro termination if pend # 0 start sym = pend; pend = 0 finish else start while inpos >= inlim cycle sym = ret and return if msp = 0 msp = msp-1 ! inpos = mstack(msp)&posmask; inlim = mstack(msp)>>limshift inlim = mstack(msp); inpos = inlim&posmask; inlim = inlim>>limshift repeat sym = mac(inpos); inpos = inpos+1 finish end ! routine GET NAME(string(maxname)name s) !First symbol in SYM s = "" while ' ' <= sym < 127 cycle s = s.tostring(sym) if length(s) < maxname get sym repeat cat(1,0); !in case of error-report end constinteger nomac=-1, first=0, normal=1 routine GET CODE(integer mode) ! Read command unit to CODE, classifying in TYPE ! Expand macros if MODE >= 0 / Leading element if MODE = 0 integer k cycle get sym until sym # ' ' code = sym if sym < ' ' start; !control type = 1 return if mode > 0; !non-initial code = term finish !Test for printing char version of control sequence if code = '&' start; !control shift get sym; -> err if sym < '@' code = sym&31 if code = esc start get sym if sym = '?' start; !canonical 2nd leadin get sym; sym = sym!!96 finish code = sym+128 finish finish k = def(code) return if mode = nomac exit if k < macro; !not macro macpush(k) mode = normal repeat pend = k>>8; code = k&255 type = symtype(code)&15 return err: type = 1; code = ' ' end ! routine GET TEXT integer pos,lim if sym = '!' start if msp # 0 start; !dummy parameter pos = inpos; lim = inlim msp = msp-1 inpos = mstack(msp)&posmask; inlim = mstack(msp)>>limshift get sym if inpos # inlim get text mstack(msp) = inlim<<limshift+inpos msp = msp+1 inpos = pos; inlim = lim return finish ref = 0 finish else if sym = '"' or 'X' <= sym&95 <= 'Z' start; !text macro ref = sym finish else start ref = nullref; ref = 0 if num # 0; !Insert,etc return if symtype(sym) # 3; !not valid quote -> ref = nullref hold = sym; pos = tlim cycle get sym if sym < ' ' start; !closing quote omitted return if num = 0; !allowed only for I,S pend = sym; sym = hold finish exit if sym = hold return if tlim >= textlim; !** mac(tlim) = sym; tlim = tlim+1 repeat if tlim # pos start; !not null def(reflim) = tlim<<limshift+pos ref = reflim; reflim = reflim+1 finish finish get sym end routine NUMBER !Test for numeric item if symtype(sym)&15 = 0 start type = 0; num = 0 if sym = '*' then get sym else start cycle num = num*10+sym-'0' if num < 100000 get sym repeat until not '0' <= sym <= '9' finish finish end ! routine UNCHAIN ! Insert forward references in left bracket and comma cells cycle ref = chain return if ref = 0 chain = r(ref)_ref r(ref)_ref = ci repeat until r(ref)_code = '(' end ! routine SET OPTIONS integer i,k constinteger showpointer=4 conststring(15)array text(0:optmax) = "Case-matching [", "Line width [", "Left margin [", "Min. window [", "Show position [", "Update [" routine SHOW(integer i) integer j j = value(i) if numeric>>i&1 # 0 then write(j,0) else start k = 1 while i > 0 cycle i = i-1; k = k+1 k = k+1 if numeric>>i&1 = 0 repeat print string(optname(k+j)) finish end cat(1,0) printstring( "RETURN to step through value or 'x' to alter ':' to exit") print symbol(nl) cycle for i = 0,1,optmax cycle cat(0,0) printstring(text(i)) minwin = cur_min; !relevant current setting show(i) printstring("] :") clear line read line get sym if sym # ret start if sym = ':' start save command; !ie last shown return finish num = 0 while sym >= ' ' cycle num = num*10+sym-'0' if '0' <= sym <= '9' get sym repeat if numeric>>i&1 # 0 start value(i) = num if cur_min # minwin start cur_min = minwin cur_win = offscreen; cur_diff = unknown finish finish else start value(i) = value(i)!!1 cur_diff = unknown if i = showpointer finish coerce parameters i = i-1 finish repeat repeat end; !set options routine DEFINE(integer k) integer m,n,pos complain("RETURN cannot be re-defined") if k = ret complain(tostring(k)." cannot be re-defined") unless k < ' ' c or 'X' <= k <= 'Z' or 'a' <= k <= 'z' or k >= 128 release(k) compress(128) if macbound-macfree < 128 get sym until sym # ' ' n = 0 if sym = '"' start n = comlim-combase move(n,mac0+combase,mac0+macfree); macfree = macfree+n finish else start get sym if sym = '='; !optional if sym < ' ' start; !no text if k < ' ' and term # ret and term < ' ' then def(k) = term c else def(k) = ' ' return finish inpos = inpos-1 finish pos = inpos inpos = inpos+1 while inpos < inlim and mac(inpos) >= ' ' m = inpos-pos move(m,mac0+pos,mac0+macfree); macfree = macfree+m def(k) = macfree<<limshift+(macfree-n-m) end routine EXPLAIN(integer k) !K is initial symbol (NOMAC) integer m,control,back conststring(35)array text(' ':127) = "undefined", "prefix for system command", "'ditto' text parameter", "Move to absolute line n", "Switch between input files", "prefix for Special command", "prefix for control character", "a possible text delimiter", "left parenthesis", "right parenthesis", "repeat indefinitely", "Increment Number", "separator for alternatives", "back", "a possible text delimiter", "a possible text delimiter", "repeat indefinitely", "repeat once", "repeat twice", "repeat three times", "repeat four times", "repeat five times", "repeat six times", "repeat seven times", "repeat eight times", "repeat nine times", "Define Macro letter", "reserved", "Cursor Left", "Revert to Marker", "Cursor Right", "ignore failure condition", "Align to column position", "Adjust line length", "Break line in two", "Case-change character", "Delete text", "Erase character", "Find text", "Get text as complete line", "reserved", "Insert text", "Join next line to this", "Kill (delete current line)", "move Left one character", "Move to next line", "locate Next word", "Overwrite with text", "Print line", "Query form", "move Right one character", "Substitute text", "Traverse text", "Uncover (delete up to) text", "Verify text", "reserved", "undefined macro", "undefined macro", "undefined macro", "reserved", "invert failure condition", "reserved", "Set Marker", "reserved", "reserved", "reserved", "reserved", "Case-change character backwards", "reserved", "Erase character backwards", "Find text backwards", "Get back - recover deleted line", "reserved", "Insert back - recover character", "reserved", "Kill previous line", "move Right one character", "Move to previous line", "Next word backwards", "Overwrite back (recover)", "Print previous line", "reserved", "move Left one character", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "Cursor Up", "reserved", "Cursor Down", "reserved", "illegal" cat(1,0) m = def(k) control = 0; control = 1 unless ' ' <= k < del if control # 0 or (m >= macro and sym < ' ') start; !macro (alone) print symbol(k) if control = 0 print symbol('=') print symbol(' ') if m >= macro start; !defined macro macpush(m) get sym; k = sym; m = def(k) get sym finish finish back = 0 if 'A' <= m <= 'W' and sym = '-' start m = m+casebit; get sym; back = 1 finish if sym >= ' ' start; !not single command letter print symbol(k) print symbol('-') if back # 0 cycle print symbol(sym) get sym repeat until sym < ' ' print symbol('/') and msp = 0 if msp # 0 finish else if control # 0 and m = '¬' start print string("¬ : Swop between command/data modes") finish else if control # 0 and m = '1' start printstring("1 : repeat last command line") finish else start print code(m&255) k = m>>8 if k # 0 start if k # '0' start printsymbol(k) finish else start printstring("* (ie ") print code(m&255) printstring(" indefinitely)") finish finish else start printstring(" : "); printstring(text(m)) finish finish print symbol(nl) end; !explain routine OUTPUT KEYDEFS integer i,j,kk,sym for kk = 0,1,255 cycle i = def(kk) if i >= macro start print symbol('%'); print symbol('K') sym = kk if sym < ' ' or sym >= 128 start print symbol('&'); sym = sym+64 if sym >= 128 start sym = kk&127 print symbol('['); !ESC print symbol('?') and sym = sym!!96 if sym < 64 finish finish print symbol(sym); print symbol('=') j = i>>limshift; i = i&posmask while i # j cycle print symbol(mac(i)); i = i+1 repeat print symbol(nl) finish repeat end routine ECHO COMMAND integer pos cat(1,0) if control < 0 start printstring(curprom) pos = combase while pos < comlim cycle print symbol(mac(pos)); pos = pos+1 repeat clear line finish end ! ! I n i t i a l i s a t i o n ! edistart: lastcell_code = ')'; lastcell_count = 1 !Stored text pointers comlim = combase tlim1 = 0 mac0 = addr(mac(0)) !File pointers cur_start = new_start gapstart = cur_start; oldgapstart = gapstart cur_lbeg = old_start; fp = cur_lbeg gaplim = fp; oldgaplim = gaplim cur_lim = old_lim !$IF VAX newlim = cur_lim !$IF EMAS { newlim = new_lim-1024 { gdiff = newlim-cur_lim !$IF APM { newlim = new_lim-1024 !$FINISH delmax = newlim; byteinteger(delmax) = nl if delmax > 0 set lend altlim = floor; ! < any NEW pointer altmin = ceiling; ! > any NEW pointer !Line numbers cur_line = 1 sec_line = -1; !indicator for reset ! !Initialise video info ![!! so that VMODE can, awkwardly, suppress] vmode = vmode!!screenmode!!specialpad vmode = 0 if vdu_fun = 0 set video mode(vmode) set windows cur_bot = wrows-1 cur_min = minwin cur_diff = unknown coerce parameters cat(1,0); printstring(message) ! ! R e a d n e w c o m m a n d l i n e ! comread: !Read command file if present if pre # "" start open in(pre) finish resetread: pre = "" inpos = inlim; msp = 0 read: if markpos = 0 then newprom = prom(sin) c else newprom = prom(sin+2) -> data entry if edmode >= 0 pend = 0; fpsym = 0; control = -1 if inpos = inlim start; !no input available if commandstream = 0 start; !on-line prepare for input if newprom # curprom or video = 0 start curprom = newprom cat(0,0); printstring(curprom) finish cat(0,2); clear line finish read line control = term if inpos = inlim finish !Reset command variables again: chain = 0; cmax = cmax1 !If last match and insert text strings are within text ! string area, they could be overwritten: so they are ! moved to the reserved match and insert sections ![could re-assign instead?] if mdef < textlim<<limshift start hold = mdef>>limshift; mdef = mdef&posmask; hold = hold-mdef move(hold,mac0+mdef,mac0+matchbase) mdef = hold<<limshift+(matchbase<<limshift+matchbase) finish if idef < textlim<<limshift start hold = idef>>limshift; idef = idef&posmask; hold = hold-idef move(hold,mac0+idef,mac0+insertbase) idef = hold<<limshift+(insertbase<<limshift+insertbase) finish ! get code(first) if control >= 0 start; !control key if code = '¬' start; !toggle editing mode edmode = ¬edmode restore fpsym -> resetread finish finish else if code = '-' start def(ret) = def(ret)!!casebit; !toggle direction control = term if inpos = inlim get code(first) finish -> read if type = 1 if type = 0 start; !repetition number sym = code; number -> er2 if sym >= ' ' def(ret) = 'M' -> read if cmax = 0; !no command to repeat r(cmax)_count = num -> restore finish if code = '%' start get sym; code = sym sym = sym&95 ->er2 if code < 'A' get sym until sym # ' ' get sym if sym = '=' -> pc(code&95) finish if control < 0 start; !not control key def(ret) = 'M' cmax = 0; tlim1 = 0; reflim1 = 128 comlim = combase; combase = freebase; freebase = comlim comlim = inlim1 finish ! ! C o m m a n d i n p u t: m a i n l o o p ci = cmax; tlim = tlim1; reflim = reflim1 more: !(command code has been get) -> er5 if type < 4 -> er0 if type < 8 and newlim <= 0; !no changes when Showing ci = ci+1; -> er6 if ci >= cbound num = 1; scope = 0; ref = 0; !defaults get sym; !next symbol without mapping if sym = '-' start code = code!casebit; type = symtype(code)&15 -> er5 if type < 4 code = '-' if code = '+' get sym finish -> c(type) c(8): !Find num = 0 c(7): !+ Delete, Uncover c(9): !+ Traverse, Verify number scope = num num = 0; !as indicator (not I,O,S,G) c(6): !+ Insert, Overwrite, ! Substitute, Get get text -> er4 if ref = nullref and num = 0 num = 1; !restore default c(5): !Erase, Get, etc c(10): !+ Move, Next, Print number -> put c(11): !open bracket, comma ref = chain; chain = ci -> put c(13): !: -> erq unless 'X' <= sym&95 <= 'Z' scope = sym get sym -> put c(14): !close bracket unchain; -> er3 if ref = 0 number r(ref)_count = num c(15): !invert, query put: r(ci)_code = code; r(ci)_ref = ref r(ci)_scope = scope; r(ci)_count = num pend = sym; get code(normal) -> more unless type = 1 ci = ci+1; cmax = ci r(ci) = lastcell unchain; -> er3 if ref # 0 if control < 0 start; !not control key cmax1 = cmax; tlim1 = tlim; reflim1 = reflim if cscroll = 0 start; !can't scroll command window echo command if video # 0 finish else start save command finish error = 0 finish restore: if error # 0 start cat(1,chalf); clear line error = 0 finish sym = ret if sym < ' ' !$IF EMAS OR VAX OR APM if fpsym >= ' ' start at(fprow,fpcol) print symbol(fpsym) at(fprow,fpcol) print symbol(0); !to flush & position video cursor finish !$FINISH -> execute ! routine REPORT(string(255) message) !Make command error report (to right of command text) if edmode < 0 start echo command if cscroll = 0 finish else cat(1,0) printstring(message) end ! er0: report(" "); print code(code) print string(" when Showing") -> erq er3: report(" Brackets") -> erq er4: report(" Text for ") print code(code) -> erq er2: code = sym pc(*): c(*): er5: report(" "); print code(code) -> erq er6: report(" Size") erq: print symbol('?') cmax1 = 0 if ci > 1 print symbol(nl) save command if edmode < 0 and cscroll # 0; !(else REPORT echoed) ignore: close in and commandstream = 0 if commandstream # 0 -> resetread ! ! Percent commands pc('S'): !Secondary input switch if sin # 0 if sym >= ' ' start get name(secfile_name) connect input(secfile) secfile_flag = 0 finish restore fpsym sec_line = -1 switch if secfile_start # secfile_lim -> read pc('G'): !Get command file get name(pre) close in and commandstream = 0 if commandstream # 0 -> comread pc('P'): !Put key definitions get name(pre) open out(pre) if pre # "" pre = "" output keydefs close out -> read pc('U'): !ignore/heed case mapcase = 1 mapcase = 0 and get sym if sym = '-' coerce parameters -> read pc('L'): !Line width number; -> erq if type # 0 width = num coerce parameters -> read pc('M'): !Margin number; -> erq if type # 0 margin = num coerce parameters -> read pc('D'): !Display if sym >= ' ' start number -> erq if type # 0 cur_min = num finish restore fpsym coerce parameters qread: cur_win = offscreen; cur_diff = unknown curprom = "" -> read pc('H'): !Help restore fpsym !$IF EMAS { set video mode(0) { view(helpfile) { set video mode(vmode) { -> qread !$IF VAX complain("Help facility not available") !$FINISH pc('E'): !Environment restore fpsym set options -> qread pc('W'): delmax = newlim -> read pc('X'): pc('Y'): pc('Z'): if sym >= ' ' start; !definition pend = sym define(code) finish else start; !enquiry explain(code) finish -> read pc('Q'): if sym # ret or term # ret start pend = sym; get code(nomac) get sym if sym >= ' ' explain(code) finish else start cycle cat(0,0); printstring("Key (or :): "); clear line read line get code(nomac) get sym if sym >= ' ' exit if code = ':' explain(code) repeat finish curprom = "" -> read pc('K'): !define key(s) if sym # ret or term # ret start pend = sym; get code(nomac) if inpos = inlim start printsymbol('*') unless ' ' <= code < del read line finish get sym until sym # ' ' pend = sym if sym # '=' define(code) finish else start cycle cat(0,0); printstring("Key = defn: "); clear line read line get code(nomac) exit if code = ':' if inpos = inlim start printsymbol('*') unless ' ' <= code < del read line finish get sym until sym # ' ' pend = sym if sym # '=' define(code) repeat finish curprom = "" -> read pc('A'): !Abandon if altline # 0 start printstring(" Abandon complete edit? (y/n) ") read line get sym; -> ignore if sym!casebit # 'y' get sym; -> ignore if sym >= ' ' finish new_flag = -1; altline = 0 pc('C'): !Close restore fpsym switch if sin # 0 consolidate; !in case of insertion at end new_flag = 1 if altline # 0 new_lim = gapstart old_start = gaplim; old_lim = cur_lim pop window; pop window !$IF EMAS OR VAX vt at(vdu_rows-1,0) !$IF APM { gotoxy(0,vdu_rows-1) !$FINISH clear line; print symbol(rt); !to flush set video mode(0) end; !END OF EDI ! !$IF EMAS {%externalroutine VECCE(%string(255) parm) {%integer f,i,same,holesize,tempsize,outhead {%string(255) heading { set parameters(parm) { same = 0; same = 1 %if out_name = in_name { %if out_name # "" %start { f = checkoutputfile(out_name,same) { -> errstop %if f # 0 { %finish { connect input(in) { f = in_flag { -> stop %if f # 0 { connect input(sec) { f = sec_flag { -> stop %if f # 0 { %if out_name # "" %start { holesize = 262144 { %cycle { tempsize = in_lim-in_start + sec_lim-sec_start + holesize { outfile("T#ETEMP",-tempsize,tempsize,0,outhead,f) { %exit %if f=0 { ->errstop %if holesize = 16384; ! 16k - minimum reasonable { holesize = holesize>>1 { %repeat { integer(outhead+12) = 3; !type = character { out_start = outhead+32 { out_lim = out_start+integer(outhead+8)-32 { %finish !$IF VAX integer f,i,same string(255) heading set parameters(cliparam) same = 0; same = 1 if out_name = in_name if out_name = "" start connect input(in); !WITHOUT EXTRA -> stop if in_flag # 0 finish else start ! f = checkquota(out_name) ! %if f&1 = 0 %start ! print string(" *".sysmess(f).": ".out_name) ! -> stop ! %finish if sec_name # "" start connect input(sec) -> stop if sec_flag # 0 in_flag = (sec_lim-sec_start)>>9; !#blocks in sec file finish in_flag = in_flag+20; !EXTRA BLOCKS connect input(in) -> stop if in_flag # 0 out_start = in_vmstart; out_lim = in_vmlim finish !$IF APM {%integer i,same {%string(255) heading {%constinteger STORESIZE=200000 {%byteintegerarray STORE(0:storesize) { set parameters("") { same = 0; same = 1 %if out_name = in_name { out_vmstart = addr(store(0)); out_start = out_vmstart { out_vmlim = out_vmstart+storesize; out_lim = out_vmlim { connect input(in) { %if sec_name # "" %start { sec_vmstart = out_vmstart; out_vmstart = out_vmstart+storesize>>2 { sec_vmlim = out_vmstart-2; ![scared] { sec_start = sec_vmlim-2048; sec_lim = sec_start { connect input(sec) { %finish { in_vmstart = out_vmstart; in_vmlim = out_vmlim { in_start = in_vmlim-2048; in_lim = in_start { open output(2,out_name) { select output(0) !$FINISH if out_name # "" start if in_name # "" start heading = "Editing ".in_name heading = heading." with ".sec_name if sec_name # "" heading = heading." to ".out_name if same = 0 finish else start heading = "Creating ".out_name finish finish else start heading = "Showing ".in_name finish !$IF EMAS OR VAX define video(ttype) !$FINISH ! edi(in,sec,out,heading) ! !OUT_FLAG is negative if edit abandoned, zero if no changes !$IF EMAS OR VAX if out_flag < 0 or (out_flag = 0 and same # 0) start print string(" File unchanged") out_start = 0 finish if out_start # 0 start; !file to be written i = in_lim-in_start; !lower half move(i,in_start,out_lim); ! concatenated to upper out_lim = out_lim+i !$IF EMAS { integer(outhead) = out_lim-outhead; !including header { sendoutput("T#ETEMP",out_name,f) { %if f # 0 %then printstring(" Edited file left in T#ETEMP") %c { %else printstring(in_name." edited to ".out_name) { %finish { -> stop {errstop: { psysmes(73,f) %if f > 0 {stop: { newline { comreg(24) = f; !return code {%end; !OF VECCE { {%externalroutine V200ECCE(%string(255) parm) { ttype = 11; vecce(parm) {%end {%externalroutine BECCE(%string(255) parm) { ttype = 6; vecce(parm) {%end {%externalroutine EECCE(%string(255) parm) { ttype = 13; vecce(parm) {%end {%externalroutine VSHOW(%string(255) parm) { vecce(parm."/.N") {%end { {%externalroutine VRECAP(%string(255) parm) {%systemroutinespec GET JOURNAL(%stringname file, %integername flag) {%string(31) file {%integer flag { get journal(file,flag) { %if flag = 0 %start { %if parm = "" %then vshow(file) %c { %else vecce(file."/".parm) { %finish { %if flag > 0 %then psysmes(75,flag) { comreg(24) = flag; !set return code {%end { {%ENDOFFILE !$IF VAX cycle f = writeout(out_name,out_start,out_start,out_lim,in_vmlim) exit if f = 0 print string(" *".sysmess(f).": ".out_name) newline print string(" Please supply alternative file-name: ") out_name = "" cycle read symbol(i) exit if i = nl out_name = out_name.tostring(i) repeat newline repeat printstring(in_name." edited"); newline if length(in_name) > 30 printstring(" to ".out_name) finish else start deletevm(in_vmstart,in_vmlim) finish deletevm(sec_vmstart,sec_vmlim) if sec_vmstart # 0 stop: newline ENDOFPROGRAM !$IF APM { select output(2) { i = out_start { %while i # out_lim %cycle { print ch(byteinteger(i)); i = i+1 { %repeat { i = in_start { %while i # in_lim %cycle { print ch(byteinteger(i)); i = i+1 { %repeat {%routine COPY REST {%integer k {%on %event 9 %start { %return {%finish {%cycle { read ch(k) { print ch(k) {%repeat {%end { select input(2) { copy rest {stop: {%ENDOFPROGRAM !$FINISH $ Command: *spool *. (14) FM Drive 0 Option 0 (off ) Dir. :0.$ Lib. :0.$ Ecce HEAP HmdDoc ImpEcce STACK I.STRIP *type heap |!h|C|!|?|A|!_|!}|GHEAP 00|!#06|!5U|!-00|!+06|!,[|!R'Z[|!Q|G|!;|!P|!c|!$|!|C|R|!6|!%|R|!C|!&|!|D|!|C|||!|B|!;|!z|P`|!|?|!6`|?|!|¬|!|I`~'#a|!y|C'|W|!|D|!|CU|!,|!|C|!+[|!n'Z|!:|!J[|!l'^|!:|!k|!|F[|!j|G|!:|!e[|!h'^|!:|!_|!|F[|!f|G|!:|!Y|!|F[|!d|G|!:|!S|!|F[|!b|G|!:|!M|!|F[|!`|G|!:|!G|U|!|E|||!|D`?|!|¬|!|E|!|E`|!|B¬|!|F[|!X'^|!:|!|K[|!V'^|!s|!>|!|D[|!S'^|!:|!'|!|E Escape *type i.strip begin { program to strip parity and remove spurious LFs } integer Sym, Total = 0 Print string ("Starting...".snl) Open input (1, ":1.ImpEcce") Open output (1, ":0.I.EcceXX") cycle Read symbol (Sym) Sym = Sym & 16_7f if Sym = 13 then continue Print symbol (Sym) Total = Total + 1 repeat until Sym < 32 and sym # 10 and sym # 13 Close output Print string ("Terminator is "); Write (Sym, 0); New line end of program *drive 2