!*********************************************************************** !* !* OPER handler for an interactive terminal !* !* Copyright (C) R.D. Eager University of Kent MCMLXXXV !* !*********************************************************************** ! ! !*********************************************************************** !* !* Record and array formats !* !*********************************************************************** ! recordformat comf(integer ocptype,ipldev,sblks,sepgs,ndiscs, dlvnaddr,gpctabsize,gpca,sfctabsize,sfca,sfck,dirsite, dcodeda,suplvn,tojday,date0,date1,date2, time0,time1,time2,epagesize,users,cattad,servaad, byteinteger nsacs,resv1,sacport1,sacport0, nocps,resv2,ocpport1,ocpport0, integer itint,contypea,gpcconfa,fpcconfa,sfcconfa, blkaddr,ration,smacs,trans,longinteger kmon, integer ditaddr,smacpos,supvsn,pstva,secsfrmn,secstocd, sync1dest,sync2dest,asyncdest,maxprocs,inspersec,elaphead, commsreca,storeaad,procaad,sfcctad,drumtad,tslice,feps, maxcbt,performad,sp1,sp2,sp3,sp4,sp5,sp6, lstl,lstb,pstl,pstb,hkeys,hoot,sim,clkx,clky,clkz, hbit,slaveoff,inhssr,sdr1,sdr2,sdr3, sdr4,sesr,hoffbit,blockzbit,blkshift,blksize,end) recordformat iostatf(integer inpos,string (15) intmess) recordformat itf(integer inbase,inlength,inpointer,outbase, outlength,outpointer,outbusy,omwaiting,inttwaiting, jnbase,jncur,jnmax,lastfree,spare5,spare6,spare7) recordformat lpicf(string (6) owner,string (11) file, byteinteger fsys,integer hisno, addr,screens,srce) recordformat pe(integer dest,srce, (integer p1,p2,p3,p4,p5,p6 or c string (23) message or c integer picno,fsys,screen,string (11) file)) recordformat rf(integer conad,filetype,datastart,dataend) recordformat scf(byteintegerarray header(1:8),text(1:40)) ! ownintegerarrayformat tablef(0:43) ownrecord (scf)arrayformat scaf(1:24) ! ! !*********************************************************************** !* !* Constants !* !*********************************************************************** ! constantinteger no = 0, yes = 1 constantinteger stopped = 0, running = 1 ! Clock states constantinteger sysprocs = 5; ! Number of permanent 'system' processes constantbyteinteger null = x'00' constantbyteinteger cr = x'0d' constantbyteinteger flash = x'11' constantbyteinteger eom = x'19' ! constantinteger default refresh interval = 5 ! Seconds constantinteger default seconds per tick = 3 ! constantinteger elapsed int service = x'000a0000' constantinteger single kick act = 2 ! constantinteger oper service = x'00320000' constantinteger update log act = 7 constantinteger parse com act = 14 ! constantlonginteger int mask = x'0382000a0382000a' ! INT: A,C,Q,W,X,Y,a,c,q,w,x,y constantrecord (comf)name com = x'80c00000' ! Supervisor communication segment constantinteger first local picture = 4 constantinteger last local picture = 5 ! constantinteger maxlcom = 5; ! Number of local commands constantstring (2)array lcom(1:maxlcom) = "R","MF","M","U","ST" ! constantstring (1) snl = " " constantstring (4) lpsv = "LPSV" ! constantbyteintegerarray screen size(0:1) = 21,24 constantbyteintegerarray initial page(0:last local picture) = c 2,0,0,0,0(last local picture-first local picture+1) ! ! !*********************************************************************** !* !* Owns !* !*********************************************************************** ! owninteger clock status owninteger message status owninteger my sync1 dest owninteger prompt service owninteger refresh interval owninteger seconds per tick owninteger operlog altered ownstring (31) command erase screen ownstring (31) command erase line ownstring (31) command move to prompt ownstring (31) command move to input line ownstring (31) command move to bottom line ownstring (40) promptstring ownrecord (pe) clockp ownrecord (iostatf)name iostat ownrecord (itf)name it ownintegerarray current picture(0:1) ownintegerarray current page(0:1) ownintegerarray resident picture(0:3) ownstring (255) oldmode ownrecord (scf)array buffs(1:24,0:1) ownrecord (lpicf)array local picture(first local picture:last local picture) ! ! !*********************************************************************** !* !* Director references !* !*********************************************************************** ! externalintegerfunctionspec dloweracr(integer newacr) externalroutinespec dpoff(record (pe)name p) externalroutinespec dpon(record (pe)name p) externalroutinespec dtoff(record (pe)name p) ! ! !*********************************************************************** !* !* Subsystem references !* !*********************************************************************** ! systemroutinespec connect(string (31) file,integer mode,hole, prot,record (rf)name r,integername flag) systemroutinespec console(integer ep,integername start,len) systemroutinespec etoi(integer ad,l) systemstringfunctionspec failuremessage(integer mess) systemstringfunctionspec itos(integer n) externalstringfunctionspec modestr systemroutinespec move(integer length,from,to) systemintegerfunctionspec parmap externalroutinespec prompt(string (255) s) systemintegerfunctionspec pstoi(string (63) s) systemroutinespec reroutecontingency(integer ep,class, longinteger mask, routine ontrap, integername flag) systemroutinespec sdisconnect(string (31) file,integer fsys, integername flag) systemroutinespec setfname(string (63) s) externalroutinespec setmode(string (255) s) systemroutinespec setpar(string (255) s) externalroutinespec set return code(integer i) systemroutinespec signal(integer ep,p1,p2,integername flag) systemstringfunctionspec spar(integer n) systemroutinespec uctranslate(integer ad,len) externalintegerfunctionspec uinfi(integer entry) externalstringfunctionspec vduc(integer x,y) externalstringfunctionspec vdus(integer n) ! externalroutinespec messages(string (255) s) ! ! !*********************************************************************** !* !* Other external references !* !*********************************************************************** ! systemroutinespec mon(string (255) s) ! ! !*********************************************************************** !* !* Service routines !* !*********************************************************************** ! routine clear screen ! Clear the screen in a terminal-independent manner. integer ad,len ! ad = addr(command erase screen) + 1 len = length(command erase screen) console(10,ad,len) end ; ! of clear screen ! !----------------------------------------------------------------------- ! routine clear pending prompts ! Send a plausible reply to any system process awaiting a reply to a ! prompt, so that it does not lock up if the program is left without the ! user typing a reply. integer procno string (15) s record (pe) p ! return if prompt service = 0; ! No pending prompt procno = (prompt service >> 16) - com_sync1dest if procno = 1 then s = ":" else start if procno = 3 then s = "PROMPT OFF" else c s = "XXX" finish p_srce = 7 p_dest = prompt service p_message = s.snl dpon(p) end ; ! of clear pending prompts ! !----------------------------------------------------------------------- ! routine await clock tick ! Wait for the pending clock tick to arrive, so that it doesn't suddenly ! arrive on another program run. record (pe) p ! cycle p = 0 dpoff(p) exit if (p_dest & x'ff') = 31 repeat end ; ! of await clock tick ! !----------------------------------------------------------------------- ! routine initialise terminal integer aitbuffer,aiostat,len,ad string (255) work ! console(13,aitbuffer,aiostat); ! Get vital terminal addresses if aitbuffer = 0 then start printstring("Not an interactive terminal".snl) set return code(1000) stop finish ! command erase screen = vdus(1) command erase line = vdus(3) command move to prompt = vduc(40,21) command move to input line = vduc(40,22) command move to bottom line = vduc(40,23) message status = uinfi(22) messages("OFF") prompt(tostring(cr)) iostat == record(aiostat) it == record(aitbuffer) oldmode = modestr setmode("GRAPH,CANCEL=64"); ! Set cancel to '@' work = vdus(5); ! Initialisation string if length(work) # 0 then start ad = addr(work) + 1 len = length(work) console(10,ad,len) finish end ; ! of initialise terminal ! !----------------------------------------------------------------------- ! routine finalise terminal setmode(oldmode) clear screen if message status = 0 then start messages("ON") finish end ; ! of finalise terminal ! !----------------------------------------------------------------------- ! routine init resident pictures integerarrayname gpctab ! gpctab == array(com_gpca,tablef) ! resident picture(0) = gpctab(41); ! 'L' resident picture(1) = gpctab(42); ! 'P' resident picture(2) = gpctab(43) + 2048;! 'S' resident picture(3) = gpctab(43) + 3072;! 'V' end ; ! of init resident pictures ! !----------------------------------------------------------------------- ! routine init local pictures integer i record (lpicf)name lpic ! for i = first local picture,1,last local picture cycle lpic == local picture(i) lpic = 0 repeat end ; ! of init local pictures ! !----------------------------------------------------------------------- ! routine init picture buffers integer screen,line,i string (31) work byteintegerarrayname hd record (scf)arrayname buff ! for screen = 0,1,1 cycle buff == array(addr(buffs(1,screen)_header(1)),scaf) for line = 1,1,24 cycle work = vduc((screen!!1)*40,line-1) hd == buff(line)_header if length(work) > 8 then start printstring("Terminal not suitable".snl) set return code(1000) stop finish ! for i = 1,1,length(work) cycle hd(i) = charno(work,i) repeat hd(i) = null for i = length(work)+1,1,8 repeat current picture(screen) = -1 current page(screen) = -1 repeat end ; ! of init picture buffers ! !----------------------------------------------------------------------- ! string (6)function from(integer source) integer proc, q, r string (6) user ! proc = (source >> 16) - com_sync1dest result = "" unless proc > 0 q = (proc-1)//3 r = proc - 1 - 3*q move(6,resident picture(1)+41*(q+5)+13*r+12,addr(user)+1) length(user) = 6 etoi(addr(user)+1,6) uctranslate(addr(user)+1,6) result = user end ; ! of from ! !----------------------------------------------------------------------- ! routine transfer line(string (40) s) integer ad,len string (255) work ! work <- command move to bottom line.command erase line.s.c command move to input line.command erase line ad = addr(work) + 1 len = length(work) console(10,ad,len) end ; ! of transfer line ! !----------------------------------------------------------------------- ! routine update operlog(string (23) s) record (pe) p ! p_dest = oper service!update log act p_srce = 0 p_message = s dpon(p) operlog altered = yes end ; ! of update operlog ! !----------------------------------------------------------------------- ! routine report picture off(integer owner,picture) ! A local picture is about to go off the screen. Tell its owner that it ! need no longer be updated. record (pe) p ! p_dest = owner p_picno = picture dpon(p) end ; ! of report picture off ! !----------------------------------------------------------------------- ! routine check picture off(integer screen) ! A screen is about to be changed. If it currently displays a local ! picture, report it off and disconnect it if it is no longer on any ! screen. integer picture,flag record (lpicf)name lpic ! if 0 <= screen <= 1 then start picture = current picture(screen) if first local picture <= picture <= last local picture then start lpic == local picture(picture) lpic_screens = lpic_screens - 1 if lpic_screens <= 0 then start sdisconnect(lpic_owner.".".lpic_file,lpic_fsys,flag) lpic = 0 finish report picture off(lpic_srce,lpic_hisno) finish finish end ; ! of check picture off ! !----------------------------------------------------------------------- ! routine oper message(string (40) mes,integer doflash) integer l,max string (23) s ! if doflash = yes then max = 22 else max = 23 cycle s <- mes if flash = yes then charno(s,23) = flash update operlog(s) l = length(mes) - max exit unless l > 0 length(mes) = l move(l,addr(mes)+max+1,addr(mes)+1) repeat end ; ! of oper message ! !----------------------------------------------------------------------- ! routine local command(string (40) s) integer i,doflash string (40) comm,param switch csw(1:maxlcom) ! if length(s) <= 1 then start transfer line(s) return finish s = substring(s,2,length(s)) ! comm = s while length(comm) # 0 and charno(comm,1) = ' ' cycle if length(comm) = 1 then comm = "" else start comm = substring(comm,2,length(comm)) finish repeat s = s." ".comm while s -> s.(" ").comm unless s -> comm.(" ").param then start comm = s param = "" finish ! for i = 1,1,maxlcom cycle if comm = lcom(i) then -> csw(i) repeat transfer line("** Illegal local command") return ! csw(1): ! (R)efresh rate if param = "" then start refresh interval = default refresh interval else i = pstoi(param) if 5 <= i <= 600 then start refresh interval = i transfer line("** OK") finish else transfer line("** Invalid value") finish return ! csw(2): ! (M)essage to OPERLOG and (F)lash doflash = yes -> csw3a ! csw(3): ! (M)essage to OPERLOG doflash = no csw3a: oper message(param,doflash) transfer line("** Message sent") return ! csw(4): ! (U)sers - number of i = com_users - sysprocs i = 1 if i < 1 param = "** ".itos(i)." User" if i > 1 then param = param."s" transfer line(param) return ! csw(5): ! (S)econds per (T)ick if param = "" then start seconds per tick = default seconds per tick else i = pstoi(param) if 2 <= i <= 20 then start seconds per tick = i transfer line("** OK") finish else transfer line("** Invalid value") finish clockp_p2 = seconds per tick return ! end ; ! of local command ! !----------------------------------------------------------------------- ! externalroutine ontrap(integer class,subclass) integer flag,i ! console(7,flag,flag); ! Kill output check picture off(i) for i = 0,1,1; ! Disconnect any local pictures clear pending prompts finalise terminal if clock status = running then await clock tick signal(3,class,subclass,flag); ! Get the Subsystem to do the rest end ; ! of ontrap ! !----------------------------------------------------------------------- ! routine set prompt(string (15) s,integer srce) promptstring <- s if srce # 0 then start srce = srce >> 16 promptstring <- promptstring." from ".itos(srce-com_sync1dest) finish end ; ! of set prompt ! !----------------------------------------------------------------------- ! routine display prompt integer ad,len string (255) work ! work <- command move to prompt.command erase line.promptstring.c command move to input line ad = addr(work) + 1 len = length(work) console(10,ad,len) end ; ! of display prompt ! !----------------------------------------------------------------------- ! routine display picture(integer screen,picture,reqpage) ! Display page 'reqpage' of 'picture' on 'screen' of the virtual OPER. integer picad,size,ad,len,i,picmax,picsize,page record (scf)arrayname buff ! return unless 0 <= picture <= last local picture and 0 <= screen <= 1 if picture < first local picture then start picad = resident picture(picture) else picad = local picture(picture)_addr finish return if picad = 0 page = reqpage page = initial page(picture) if page = -1 ! len = integer(picad) size = screen size(screen) picsize = size*41 ! buff == array(addr(buffs(1,screen)_header(1)),scaf) picad = picad + 8 picmax = picad + len picad = picad + picsize*page while picad > picmax cycle ; ! Picture may have shrunk picad = picad - picsize page = page - 1 repeat if picad + picsize > picmax and page > 0 then picad = picmax - picsize ! if current picture(screen) = picture and c current page(screen) = page and c reqpage >= 0 then return current picture(screen) = picture current page(screen) = page ! for i = 1,1,size cycle ad = addr(buff(i)_text(1)) move(40,picad,ad) etoi(ad,40) if picture < first local picture ! Local pictures are ISO picad = picad + 41 repeat ! ad = addr(buff(1)) len = size*48 console(10,ad,len) if picture = 0 then operlog altered = no end ; ! of display picture ! !----------------------------------------------------------------------- ! routine display new page(integer screen,change) integer newpage ! return unless 0 <= screen <= 1 newpage = current page(screen) + change if newpage < 0 then newpage = 0 display picture(screen,current picture(screen),newpage) end ; ! of display new page ! !----------------------------------------------------------------------- ! routine readline(stringname s) integer c,l ! on event 9 start ; ! Trap 'Input Ended' s = "*" return finish ! s = "" cycle readch(c) if c = eom then start s = "*" return finish exit if c = nl s <- s.tostring(c) repeat ! cycle l = length(s) exit if l = 0 or charno(s,l) # ' ' length(s) = l - 1 repeat end ; ! of readline ! !----------------------------------------------------------------------- ! integerfunction same(integer ad1,ad2) *ldtb _x'18000028'; ! Byte descriptor, bound 40 *lda _ad1; ! Form desc to first string *cyd _0; ! Copy to ACC for compare *lda _ad2; ! Form desc to second string *cps _l =dr ; ! Compare them *jcc _8,<equal>; ! Jump if they are the same result = no ! equal: result = yes end ; ! of same ! !----------------------------------------------------------------------- ! routine update picture(integer picture) integer screen,picad,picmax,size,i,len,page,ad,copyad,picbase,picsize integer flag,from,to,step,adinc,uad byteintegerarray pcopy(1:24*41) byteintegerarray update buffer(1:24*48) record (scf)arrayname buff ! return unless 0 <= picture <= last local picture if picture < first local picture then start picbase = resident picture(picture) else picbase = local picture(picture)_addr finish return if picbase = 0 len = integer(picbase) picbase = picbase + 8 picmax = picbase + len ! for screen = 0,1,1 cycle continue unless current picture(screen) = picture flag = no size = screen size(screen) picsize = size*41 buff == array(addr(buffs(1,screen)_header(1)),scaf) page = current page(screen) picad = picbase + picsize*page while picad > picmax cycle picad = picad - picsize page = page - 1 repeat current page(screen) = page if picad + picsize > picmax and page > 0 then picad = picmax - picsize copyad = addr(pcopy(1)) move(picsize,picad,copyad) etoi(copyad,picsize) if picture < first local picture ! Local pictures are ISO ! if picture = 0 then start from = size to = 1 step = -1 adinc = -41 copyad = copyad + (size - 1)*41 else from = 1 to = size step = 1 adinc = 41 finish uad = addr(update buffer(1)) for i = from,step,to cycle ad = addr(buff(i)_text(1)) if same(copyad,ad) = no then start flag = yes move(40,copyad,ad) move(48,addr(buff(i)_header(1)),uad) uad = uad + 48 finish copyad = copyad + adinc repeat ! if flag = yes then start ; ! Fire the update ad = addr(update buffer(1)) len = uad - ad console(10,ad,len) if picture = 0 then operlog altered = no finish repeat end ; ! of update picture ! ! !*********************************************************************** !* !* O P E R !* !*********************************************************************** ! externalroutine oper(string (255) parms) integer flag,done useful work,dact,refresh counter,screen,i,l integer new prompt service,pic string (6) owner string (31) work1,work2 string (40) line string (63) s record (pe) p record (rf) rr record (lpicf)name lpic switch act(0:31) ! setpar(parms) if parmap > 1 then start flag = 263; ! Wrong number of parameters -> err finish ! if parmap = 1 then start work1 = spar(1); ! Refresh rate refresh interval = pstoi(work1) unless 5 <= refresh interval <= 600 then start flag = 202; ! Invalid parameter setfname(work1) -> err finish finish else refresh interval = default refresh interval ! clock status = stopped my sync1 dest = uinfi(7) prompt service = 0 refresh counter = 0 seconds per tick = default seconds per tick operlog altered = no mon(vdus(0)); ! Terminal name init picture buffers flag = dloweracr(2); ! Raise privilege reroutecontingency(3,65,int mask,ontrap,flag) ! Catch INT: messages initialise terminal clear screen init resident pictures init local pictures display picture(1,1,-1); ! Display process list on screen 1 display picture(0,0,-1); ! Display OPER log on screen 0 set prompt("COMMAND:",0) display prompt clockp_srce = 0 clockp_dest = elapsed int service!single kick act clockp_p1 = my sync1 dest!31; ! My activity number for reply clockp_p2 = seconds per tick dpon(clockp); ! Request initial clock tick clock status = running ! cycle done useful work = no if iostat_inpos # it_inpointer then start ! There is some input readline(line) if length(line) # 0 or prompt service # 0 then start exit if line = ".END" or line = ".end" or c line = "Q" or line = "q" or c line = "*" done useful work = yes if length(line) # 0 and charno(line,1) = '!' then start local command(line) continue finish length(line) = 23 if length(line) > 23 transfer line(line) new prompt service = 0 if prompt service = 0 then start p_dest = oper service!parse com act else p_dest = prompt service update operlog(line) l = length(line) if l # 0 and charno(line,l) = '&' then start charno(line,l) = ' ' set prompt("CONTINUE:",prompt service) new prompt service = prompt service else if l > 22 then l = 22 charno(line,l + 1) = nl length(line) = l + 1 set prompt("COMMAND:",0) finish display prompt finish p_srce = 7 p_message = line dpon(p) prompt service = new prompt service ! Done after 'dpon' in case of interruption finish else display prompt finish p_dest = 0 dtoff(p) if p_dest = 0 and done useful work = no then dpoff(p) dact = p_dest & x'ff'; ! May be zero if the 'dtoff' didn't find anything ! -> act(dact) ! act(0): ! Null action continue ! act(31): ! Clock tick clock status = stopped refresh counter = refresh counter + seconds per tick if refresh counter >= refresh interval then start refresh counter = 0 for screen = 0,1,1 cycle update picture(current picture(screen)) repeat display prompt else if operlog altered = yes then start update picture(0) display prompt finish finish dpon(clockp); ! Request fresh clock tick clock status = running continue ! act(1): ! Output string act(7): ! String to OPER log update operlog(p_message) continue ! act(6): ! Display local picture unless 0 <= p_screen <= 1 then start ! Screen out of bounds report picture off(p_srce,p_picno) ! Owner will have incremented refresh count continue finish ! owner = from(p_srce); ! For file handling ! pic = current picture(p_screen); ! Current contents of screen if pic >= first local picture and c local picture(pic)_owner = owner and c local picture(pic)_file = p_file then start report picture off(p_srce,p_picno) ! Decrement refresh count as above continue finish ! ! A new picture is about to go onto the requested screen ! check picture off(p_screen); ! It may be a local picture at present ! ! Select a free local picture descriptor (there is always one) ! i = first local picture cycle lpic == local picture(i) if lpic_screens > 0 then start ; ! In use exit if lpic_owner = owner and lpic_file = p_file finish else l = i i = i + 1 i = l and exit if i > last local picture repeat lpic == local picture(i) ! if lpic_screens <= 0 then start ; ! Not currently showing - connect it lpic_owner = owner lpic_file = p_file lpic_fsys = p_fsys connect(lpic_owner.".".lpic_file,9,0,(lpic_fsys<<8)!x'80',rr,flag) if flag # 0 then start s = failuremessage(flag) s = substring(s,2,length(s)) length(s) = 40 if length(s) > 40 transfer line(s) continue finish lpic_addr = rr_conad + 24; ! Avoid header but keep length lpic_screens = 1 lpic_hisno = p_picno lpic_srce = p_srce finish else lpic_screens = lpic_screens + 1 display picture(p_screen,i,-1) display prompt continue ! act(19): ! Request for picture change if p_picno < 0 then start ; ! Translate symbolic picture name if lpsv -> work1.(string(addr(p_p3))).work2 then start p_picno = length(work1) finish finish continue if p_picno >= first local picture check picture off(p_screen); ! Screen may be showing a local picture display picture(p_p2,p_picno,-1) display prompt continue ! act(18): ! Request for page change display new page(p_p2,p_picno) display prompt continue ! act(8): ! Prompt prompt service = p_srce set prompt(p_message,prompt service) display prompt continue repeat ! check picture off(i) for i = 0,1,1 clear pending prompts finalise terminal if clock status = running then await clock tick set return code(0) return ! err: printstring(snl."OPER fails -".failuremessage(flag)) set return code(flag) stop end ; ! of oper endoffile