!TITLE Subsystem maintenance utilities ! ! ! This package is a collection of utility commands which are primarily ! intended for supporting and maintaining the Edinburgh Subsystem. ! ! ! Subjects covered are: ! ! 1 Updating members of pdfiles ! 2 Messages of the day ! 3 Altering the ALERT time ! 4 Subsystem basefiles ! 5 Subsystem option files ! 6 Checking partitioned files ! ! ! !STOP ! ! !*********************************************************************** !* !* Subsystem maintenance utilities !* !* Copyright (C) R.D. Eager University of Kent MCMLXXXIII !* !*********************************************************************** ! ! !*********************************************************************** !* !* Constants !* !*********************************************************************** ! constantinteger no = 0, yes = 1 ! constantinteger exclude data entries = yes ! constantinteger background = 0, foreground = 1, both = 2 constantinteger ssobjfiletype = 1 constantinteger sscharfiletype = 3 constantinteger ssoptfiletype = 9 constantinteger alertsize = 27; ! Size of 'alert' part of message of the day constantinteger segsize = x'00040000' constantinteger abasefile = x'00800000' ! Address of basefile when loaded constantinteger abaseobj = x'00800020';! Address of basefile object when loaded constantbyteinteger em = 25; ! End of file character constantstring (1) snl = " " constantstring (6) owner = "SUBSYS" constantstring (11) defaultpd = "SYSTEM" ! For UPDATEPD command constantstring (11) defaultactivedir = "SS#DIR" constantstring (10) tempdir = "T#TEMPDIR" constantstring (11)array messagefile(background:both) = c "BMESSAGE","FMESSAGE","FMESSAGE" constantstring (8)array opname(background:both) = c "SETBMESS","SETFMESS","SETBOTH" constantstring (8) saname = "SETALERT" ! constantstring (10)array bkeys(1:2) = "BRACKETS","NOBRACKETS" constantbyteintegerarray bvalues(1:2) = 1,2 constantstring (8)array ekeys(1:3) = "NOECHO","PARTECHO","FULLECHO" constantbyteintegerarray evalues(1:3) = 0,1,2 constantstring (10)array jkeys(1:3) = "NORECALL","TEMPRECALL","PERMRECALL" constantbyteintegerarray jvalues(1:3) = 0,1,2 constantstring (12)array lkeys(1:2) = "BLANKLINES","NOBLANKLINES" constantbyteintegerarray lvalues(1:2) = 0,1 ! constantinteger maxrec = 682; ! BASE records in 8 pages constantlonginteger descdr = x'b100000000000000' constantinteger prime = 251 if exclude data entries = no then start constantinteger data = 1 finish constantinteger code = 2 ! ! !*********************************************************************** !* !* Record and array formats !* !*********************************************************************** ! recordformat basef(string (31) entry, (longinteger desc or integer dr0,dr1), integer type,downlink) recordformat contf(integer dataend,datastart,psize,filetype, sum,datetime,sp0,sp1,mark,sp2,sp3,astk,sp4, sp5,itwidth,ldelim,rdelim,journal, searchdircount,arraydiag,initworksize,sp6, itinsize,itoutsize,nobl,istk, longinteger initparms,integer dataecho, terminal,i23,i24,i25,i26,i27,i28,i29,i30,i31, recdiag, string (31) fstartfile,bstartfile,preloadfile, moddir,cfaults,cprompt,dprompt,s8,s9,s10,s11,s12, s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23,s24,s25, s26,s27,s28,s29,s30,s31,s32, string (31)array searchdir(1:16)) recordformat dirinff(string (6) user,string (31) batchfile, integer mark,fsys,procno,isuff,reason,batchid, sessiclim,scidensad,scidens,operno,aiostat, scdate,sync1dest,sync2dest,asyncdest,aacctrec, aicrevs,string (15) batchiden, string (31) basefile,integer previc,itaddr0, itaddr1,itaddr2,itaddr3,itaddr4,streamid,dident, scarcity,preemptat,string (11) spoolrfile, integer resunits,sesslen,priority,decks,drives, uend) recordformat ld1f(integer link,loc,string (31) iden) recordformat ld4f(integer link,disp,l,a,string (31) iden) recordformat lhf(integer first,last,nbytes) recordformat hf(integer dataend,datastart,filesize,filetype, sum,datetime, (integer format,records or c integer adir,count or c integer lda,ofm)) recordformat ofmf(integer start,len,props) recordformat pdf(integer start,string (11) name, integer hole,s5,s6,s7) recordformat rf(integer conad,filetype,datastart,dataend) ! ownintegerarrayformat ldataf(0:15) ownintegerarrayformat nlhaf(0:prime-1) ownrecord (ofmf)arrayformat ofmaf(1:7) ownrecord (basef)arrayformat basefaf(0:maxrec) ownrecord (lhf)array lh(0:prime-1) ownrecord (pdf)arrayformat pdaf(1:4095) ! ! !*********************************************************************** !* !* Subsystem references !* !*********************************************************************** ! systemroutinespec changeaccess(string (31) file,integer mode, integername flag) systemintegermapspec comreg(integer i) systemroutinespec connect(string (31) file,integer mode,hole, prot,record (rf)name r,integername flag) externalstringfunctionspec date systemroutinespec destroy(string (31) file,integername flag) systemroutinespec disconnect(string (31) file,integername flag) systemstringfunctionspec failuremessage(integer mess) systemroutinespec fill(integer length,from,filler) systemstringfunctionspec htos(integer value,places) systemintegerfunctionspec iocp(integer ep,parm) systemstringfunctionspec itos(integer n) systemroutinespec moddirfile(integer ep,string (31) dirfile,entry, filename,integer type,dr0,dr1, integername flag) systemroutinespec modpdfile(integer ep,string (31) pdfile, string (11) member,string (31) infile, integername flag) systemroutinespec move(integer length,from,to) systemroutinespec newgen(string (31) file,newfile,integername flag) systemstringfunctionspec nexttemp systemroutinespec outfile(string (31) file,integer size,hole, prot,integername conad,flag) externalintegerfunctionspec outpos systemintegerfunctionspec parmap systemroutinespec permit(string (31) file,string (6) user, integer mode,integername flag) externalroutinespec prompt(string (255) s) systemintegerfunctionspec pstoi(string (63) s) systemroutinespec setfname(string (63) s) systemroutinespec setpar(string (255) s) externalroutinespec set return code(integer i) systemroutinespec setwork(integername ad,flag) systemstringfunctionspec spar(integer n) systemroutinespec uctranslate(integer ad,len) externalintegerfunctionspec uinfi(integer entry) externalstringfunctionspec uinfs(integer entry) ! externalroutinespec cherish(string (255) s) externalroutinespec parm(string (255) s) ! ! !*********************************************************************** !* !* Service routines !* !*********************************************************************** ! stringfunction specmessage(integer flag) ! Yields a local error message. switch sw(1000:1002) ! -> sw(flag) ! sw(1000): result = "Catastrophic failure" sw(1001): result = "May be used only by ".owner sw(1002): result = "Entry SSDATELINKED not found" end ; ! of specmessage ! !----------------------------------------------------------------------- ! routine fail(string (15) op,integer flag) ! Prints an error message, and stops. selectoutput(0) printstring(snl.op." fails -") if flag < 1000 then start printstring(failuremessage(flag)) else printstring(" ".specmessage(flag).snl) finish set return code(flag) stop end ; ! of fail ! !----------------------------------------------------------------------- ! routine checkuser(string (15) op) if uinfs(1) # owner then fail(op,1000) end ; ! of checkuser ! !----------------------------------------------------------------------- ! routine readline(stringname s) integer c ! on event 9 start s = tostring(em) c = iocp(12,0); ! Clear 'Input Ended' return finish ! s = "" cycle readsymbol(c) exit if c = nl s <- s.tostring(c) repeat ! while length(s) > 0 cycle if charno(s,length(s)) # ' ' then exit length(s) = length(s) - 1 repeat end ; ! of readline ! !----------------------------------------------------------------------- ! integerfunction getval(string (255) pr,integer min,max,default,mult) integer i,j string (255) s ! j = default if j & x'3ff' = 0 then start j = j >> 10 s = "K" finish else s = "" prompt(pr." [".itos(j).s."]: ") ! cycle readline(s) result = default if s = "" i = pstoi(s) if i < 0 then start printstring("Invalid number".snl) continue finish i = i*mult if min <= i <= max then result = i printstring("Number outside permitted range".snl) repeat end ; ! of getval ! !----------------------------------------------------------------------- ! integerfunction get setting(string (255) pr,integer nsettings, stringarrayname keys, byteintegerarrayname values, string (31) default) integer i string (255) s ! prompt(pr." [".default."]: ") cycle readline(s) uctranslate(addr(s)+1,length(s)) s = default if s = "" for i = 1,1,nsettings cycle if s = keys(i) then result = values(i) repeat printstring("Invalid setting".snl) repeat end ; ! of get setting ! !----------------------------------------------------------------------- ! string (255)function getstr(string (255) pr,integer maxlen, string (255) default) string (255) s ! cycle prompt(pr." [".default."]: ") readline(s) uctranslate(addr(s)+1,length(s)) if s = "." then result = "" result = default if s = "" if length(s) <= maxlen then result = s printstring("Reply must not exceed ".itos(maxlen)." characters".snl) repeat end ; ! of getstr ! !----------------------------------------------------------------------- ! integerfunction roundup(integer n,r) r = r - 1 result = (n+r) & (¬r) end ; ! of roundup ! !----------------------------------------------------------------------- ! routine connect or create(string (11) file,record (rf)name rr, string (15) op) integer flag,conad record (hf)name r ! connect(file,1,0,0,rr,flag) if flag = 218 then start ; ! File does not exist - create it printstring("There is no ".file." file".snl) printstring("It is being created".snl.snl) outfile(file,4096,0,0,conad,flag) if flag = 0 then start r == record(conad) r_filetype = sscharfiletype permit(file,"",1,flag); ! Set EEP = R cherish(file) fill(alertsize-1,conad+r_datastart,' ') byteinteger(conad+r_datastart+alertsize-1) = nl r_dataend = r_datastart + alertsize finish connect(file,1,0,0,rr,flag) finish if flag # 0 then fail(op,flag) end ; ! of connect or create ! !----------------------------------------------------------------------- ! routine printmessage(integer conad,string (7) type) integer i,j record (hf)name r ! r == record(conad) j = r_datastart + alertsize if j >= r_dataend then start printstring("The ".type." message is null".snl) else printstring("The ".type." message is:-".snl.snl) for i = conad+j,1,conad+r_dataend-1 cycle printsymbol(byteinteger(i)) repeat finish newline end ; ! of print message ! !----------------------------------------------------------------------- ! routine setmessage(stringname parms,integer type,mode) integer flag,conad,count,j string (11) file,tempfile string (15) op string (255) line record (rf) rr record (hf)name r ! set return code(1000) file = messagefile(type) op = opname(mode) checkuser(op) ! setpar(parms) if parmap # 0 then start flag = 263; ! Wrong number of parameters -> err finish ! connect or create(file,rr,op) printmessage(rr_conad,"current") ! tempfile = "T#".nexttemp cycle printstring("Type new message - terminated by :".snl) ! loop: prompt("Message: ") outfile(tempfile,4096,0,0,conad,flag) -> err if flag # 0 r == record(conad) r_filetype = sscharfiletype move(alertsize,rr_conad+rr_datastart,conad+r_datastart) count = r_datastart + alertsize cycle readline(line) exit if line = ":" or line = "*" or line = tostring(em) if length(line) = 255 then length(line) = 254 line = line.snl j = length(line) if count + j >= r_filesize then start printstring("Message too long - try again".snl) -> loop finish move(j,addr(line)+1,conad+count) count = count + j repeat r_dataend = count printmessage(conad,"new") prompt("OK? ") readline(line) until line # "" uctranslate(addr(line)+1,1) exit if charno(line,1) = 'Y' repeat ! newgen(tempfile,file,flag) -> err if flag # 0 printstring("New ".file." in use".snl) set return code(0) return ! err: fail(op,flag) end ; ! of setmessage ! !----------------------------------------------------------------------- ! integerfunction hash(string (31) name,integer hashconst) ! Hash function for new style directories. integer a,j,w,l,a1,a2 ! a = addr(name) l = byteinteger(a) if l > 8 then start ; ! Close up last 4 to first 4 a1 = a + 5 a2 = a + l - 3 byteinteger(a1+j) = byteinteger(a2+j) for j = 3,-1,0 finish else name = name."<>#@!+&" w = byteinteger(a+1)*71+byteinteger(a+2)*47+byteinteger(a+3)*97+ c byteinteger(a+4)*79+byteinteger(a+5)*29+byteinteger(a+6)*37+ c byteinteger(a+7)*53+byteinteger(a+8)*59 result = w - (w//hashconst)*hashconst end ; ! of hash ! !----------------------------------------------------------------------- ! routine makeoldbasedir(string (31) basefile,tempdir,integername flag) integer type,dirlength record (rf) rr record (hf)name h integerarray base(0:7) ! moddirfile(10,tempdir,"","",0,759,1164,flag) ! Create directory -> err if flag # 0 connect(tempdir,1,0,0,rr,flag) -> err if flag # 0 h == record(rr_conad) dirlength = h_filesize ! connect(basefile,1,0,0,rr,flag) -> err if flag # 0 ! ! Set BASE(2) to the address of the base GLA, forming a pseudo object ! file map ! if exclude data entries = yes then type = 4 else type = 7 base(2) = roundup(abasefile+rr_dataend+dirlength,segsize) moddirfile(type,tempdir,"",basefile."_BASEOBJECT",0,addr(base(1)),0,flag) err: end ; ! of makeoldbasedir ! !----------------------------------------------------------------------- ! routine makenewbasedir(string (31) basefile,tempdir,integername flag) integer i,freead,j,bgla,l,len8,nextfree,ichain,objconad,link,ad,len integer ntot,nreq,nconad,conad record (rf) rr record (hf)name h record (ld1f)name ld1 record (basef)arrayname base record (ofmf)arrayname ofm integerarrayname ldata,nlh if exclude data entries = no then start longinteger desc record (ld4f)name ld4 finish ! connect(basefile."_BASEOBJECT",1,0,0,rr,flag) return if flag # 0 objconad = rr_conad h == record(objconad) ldata == array(objconad+h_lda,ldataf) ofm == array(objconad+h_ofm+4,ofmaf) bgla = abaseobj + ofm(2)_start; ! GLAP base ! conad = 0 setwork(conad,flag) -> err if flag # 0 h == record(conad) fill(x'7fd0',conad+h_datastart,x'ff') base == array(conad+h_datastart,basefaf) nextfree = 0 for i = 0,1,prime-1 cycle lh(i) = 0 lh(i)_first = -1 repeat ! ! Code entries ! link = ldata(1) while link # 0 cycle ld1 == record(objconad+link) l = hash(ld1_iden,prime) len8 = (length(ld1_iden)+9) & x'fffffff8' ! 1 for type byte, 1 for length byte ! + 7 for double word aligning lh(l)_nbytes = lh(l)_nbytes + len8 + 8 if nextfree > maxrec then start flag = 291; ! Too many entries -> err finish base(nextfree)_entry = ld1_iden ! base(nextfree)_desc = descdr!(ld1_loc & x'00ffffff') + bgla base(nextfree)_type = code if lh(l)_first < 0 then start lh(l)_first = nextfree lh(l)_last = nextfree lh(l)_nbytes = lh(l)_nbytes + 8; ! For double word terminator else ichain = lh(l)_last base(ichain)_downlink = nextfree lh(l)_last = nextfree finish nextfree = nextfree + 1 link = ld1_link repeat ! ! Data entries ! if exclude data entries = no then start link = ldata(4) while link # 0 cycle ld4 == record(objconad+link) l = hash(ld4_iden,prime) len8 = (length(ld4_iden)+9) & x'fffffff8' lh(l)_nbytes = lh(l)_nbytes + len8 + 8 if nextfree > maxrec then start flag = 291; ! Too many entries -> err finish base(nextfree)_entry = ld4_iden desc = ld4_l desc = (desc<<32)!ld4_disp base(nextfree)_desc = desc base(nextfree)_type = data if lh(l)_first < 0 then start lh(l)_first = nextfree lh(l)_last = nextfree lh(l)_nbytes = lh(l)_nbytes + 8 ! For double word terminator else ichain = lh(l)_last base(ichain)_downlink = nextfree lh(l)_last = nextfree finish nextfree = nextfree + 1 link = ld4_link repeat finish ! ! Now find out how much space required for directory ! ntot = 1040; ! 32 for headers, 1008 for listheads ntot = ntot + lh(i)_nbytes for i = 0,1,prime-1 nreq = roundup(ntot,4096); ! Page aligned printstring(basefile."_BASEOBJECT contains ".itos(nextfree)) printstring(" entries requiring a ".itos(nreq>>12)." page directory".snl) nextfree = nextfree - 1 ! ! Create temp dir ! outfile(tempdir,nreq,0,0,nconad,flag) -> err if flag # 0 h == record(nconad) h_dataend = ntot nlh == array(nconad+h_datastart,nlhaf) freead = nconad + 1040; ! First 8 aligned byte for chains for i = prime-1,-1,0 cycle unless lh(i)_first < 0 then start nlh(i) = freead - nconad; ! Offset from start of file j = lh(i)_first while j >= 0 cycle ad = addr(base(j)_entry) len = byteinteger(ad) move(len+1,ad,freead); ! Move entry name byteinteger(freead+len+1) = base(j)_type freead = (freead+len+9) & x'fffffff8' ! Double word align - +1 for type longinteger(freead) = base(j)_desc freead = freead + 8 j = base(j)_downlink repeat longinteger(freead) = 0; ! Chain terminator freead = freead + 8 finish repeat ! err: end ; ! of makenewbasedir ! ! !*********************************************************************** !* !* U P D A T E P D !* !*********************************************************************** ! !<Updating members of pdfiles ! ! The command UPDATEPD is used to add a new member to, update an ! existing member in, or delete a member from, a pdfile which may be in ! use by other processes. ! ! The command takes the form: ! ! UPDATEPD(pdfile_member,option) ! ! where:- ! ! pdfile_member - specifies the member to be operated on ! option - if null, the member must already exist ! - if N, the member must not already ! exist ! - if D, the old member is simply deleted ! ! ! ! ! ! It is assumed that any file which is to be a replacement for a member ! has the same name as the member itself, and resides in the same ! process. ! ! Since the most common use of this utility is to update members of ! SUBSYS.SYSTEM, the pdfile part of the parameter defaults to SYSTEM. !> ! externalroutine updatepd(string (255) parms) integer flag,conad,savedt,option string (11) member,tempfile string (31) file,s record (rf) rr record (hf)name ir,or ! set return code(1000) setpar(parms) if 1 # parmap # 3 then start flag = 263; ! Wrong number of parameters -> err finish if parmap & 2 # 0 then start s <- spar(2) if "D" # s # "N" then start setfname(s) flag = 202; ! Invalid parameter -> err finish option = charno(s,1) finish else option = 'Z'; ! Dummy value s <- spar(1) unless s -> file.("_").member then start setfname(parms) flag = 202; ! Invalid parameter -> err finish ! if file = "" then file = defaultpd ! unless option = 'D' then start connect(member,1,0,0,rr,flag) -> err if flag # 0 finish connect(file."_".member,1,0,0,rr,flag) -> err if flag # 0 and option # 'N' if flag = 0 and option = 'N' then start flag = 287; ! Member already exists -> err finish connect(file,1,0,0,rr,flag) -> err if flag # 0 ir == record(rr_conad) ! ! Make temporary copy of pdfile ! tempfile = "T#".nexttemp outfile(tempfile,ir_filesize,0,0,conad,flag) -> err if flag # 0 or == record(conad) savedt = or_datetime; ! Save creation date over copy move(ir_filesize,rr_conad,conad); ! Take the copy or_datetime = savedt; ! Restore date ! ! Delete any existing copy of member. Ignore failures, except in the ! case of the 'D' option. ! modpdfile(2,tempfile,member,"",flag) if flag # 0 and option = 'D' then -> err ! ! Insert new copy of member if appropriate ! modpdfile(1,tempfile,member,member,flag) unless option = 'D' -> err if flag # 0 ! ! Put new copy of pdfile into service ! newgen(tempfile,file,flag) -> err if flag # 0 printstring("Member ".file."_".member) if option = 'D' then s = "destroyed" if option = 'N' then s = "inserted" if option = 'Z' then s = "replaced" printstring(" ".s.snl) set return code(0) stop ! err: fail("UPDATEPD",flag) end ; ! of updatepd ! ! !*********************************************************************** !* !* S E T F M E S S !* !*********************************************************************** ! !<Messages of the day ! ! ! Three commands are provided to alter the 'messages of the day' which ! are displayed at process start-up. These are described in the ! following Sections: ! ! !<Changing the foreground message ! ! ! ! The command SETFMESS is used to change the 'message of the day' ! displayed to foreground users when they log on. This special command ! is necessary to avoid problems if the file is currently in use, and to ! avoid disturbing the first line of the message, which always carries ! the date and time of the most recent ALERT text. ! ! SETFMESS takes no parameters. The user is prompted for the message, ! which should be terminated by a colon (:) on a line on its own. An ! opportunity is then given to amend the message if it is not ! satisfactory. !> ! externalroutine setfmess(string (255) parms) setmessage(parms,foreground,foreground) end ; ! of setfmess ! ! !*********************************************************************** !* !* S E T B M E S S !* !*********************************************************************** ! !<Changing the background message ! ! ! ! The command SETBMESS is used to change the 'message of the day' ! displayed to background users when their job starts. This special ! command is necessary to avoid problems if the file is currently in ! use, and to avoid disturbing the first line of the message, which ! always carries the date and time of the most recent ALERT text. ! ! SETBMESS takes no parameters. The user is prompted for the message, ! which should be terminated by a colon (:) on a line on its own. An ! opportunity is then given to amend the message if it is not ! satisfactory. !> ! externalroutine setbmess(string (255) parms) setmessage(parms,background,background) end ; ! of setbmess ! ! !*********************************************************************** !* !* S E T B O T H !* !*********************************************************************** ! !<Changing both messages ! ! ! ! The command SETBOTH is used to change both 'messages of the day' ! displayed to users on process start-up. This special command is ! necessary to avoid problems if the file is currently in use, and to ! avoid disturbing the first line of the message, which always carries ! the date and time of the most recent ALERT text. ! ! SETBOTH takes no parameters. The user is prompted for the message, ! which should be terminated by a colon (:) on a line on its own. An ! opportunity is then given to amend the message if it is not ! satisfactory. !> !> ! externalroutine setboth(string (255) parms) integer flag,conad string (11) tempfile record (rf) rr ! setmessage(parms,foreground,both) ! tempfile = "T#".nexttemp connect(messagefile(foreground),1,0,0,rr,flag) -> err if flag # 0 outfile(tempfile,4096,0,0,conad,flag) -> err if flag # 0 move(4096,rr_conad,conad) ! newgen(tempfile,messagefile(background),flag) -> err if flag # 0 ! printstring("New ".messagefile(background)." in use".snl) set return code(0) stop ! err: fail(opname(both),flag) end ; ! of setboth ! ! !*********************************************************************** !* !* S E T A L E R T !* !*********************************************************************** ! !<Altering the ALERT time ! ! ! ! The command SETALERT is used to alter the date and time given in the ! 'Latest ALERT' message which forms a permanent part of the message of ! the day, for both foreground and background users. ! ! SETALERT takes up to two parameters:- ! ! 1) The time to be used in the message. Exactly four characters are ! expected, i.e.: hhmm. If this parameter is omitted, a prompt is ! issued for it. ! ! 2) The date to be used in the message. Standard EMAS date format is ! assumed, i.e.: dd/mm/yy. If this parameter is omitted, the ! current date is assumed. !> ! externalroutine setalert(string (255) parms) integer conad,i,savedt,flag string (11) file,tempfile string (255) astring,d,t record (rf) rr record (hf)name or ! set return code(1000) checkuser(saname) setpar(parms) if parmap > 3 then start flag = 263; ! Wrong number of parameters -> err finish t = spar(1) d = spar(2) if d = "" then d = date if length(d) # 8 then start setfname(d) flag = 202; ! Invalid parameter -> err finish cycle if t = "" then start prompt("Time: ") readline(t) until t # "" finish if length(t) = 4 then exit printstring("Invalid time".snl) t = "" repeat astring = "Latest ALERT=".d." ".t.snl ! for i = background,1,foreground cycle file = messagefile(i) connect or create(file,rr,saname) tempfile = "T#".nexttemp outfile(tempfile,4096,0,0,conad,flag) -> err if flag # 0 or == record(conad) savedt = or_datetime; ! Save creation date over copy move(4096,rr_conad,conad); ! Take the copy or_datetime = savedt; ! Restore date move(alertsize,addr(astring)+1,conad+or_datastart) newgen(tempfile,file,flag) -> err if flag # 0 repeat printstring(astring.snl) set return code(0) stop ! err: fail(saname,flag) end ; ! of setalert ! ! !*********************************************************************** !* !* M A K E B A S E F I L E !* !*********************************************************************** ! !<Subsystem basefiles ! ! ! ! The subsystem resides in a file which is commonly called the ! 'basefile'. ! ! This Section describes the structure of the basefile, and how to ! create a new one. ! ! ! !<Basefile structure ! ! ! The basefile for the subsystem is a partitioned file which contains ! three members: ! ! a) The subsystem object file, with the code fixed up (using the FIX ! utility) to start at segment 32, and the GLA fixed up to start at ! the next free segment after the code. ! ! b) A default 'option' file, connected and used in the absence of the ! user's own option file. When the user sets a non-default option, a ! copy of the default file is made (as SS#OPT), and the modified ! option included in the copy. ! ! c) A directory file, containing the entry points found in the ! subsystem object file. This is the first directory searched by the ! loader. !> !<The MAKEBASEFILE command ! ! ! This command takes up to four parameters. These are: ! ! ! 1) The name of the subsystem object file to be used for input. ! ! 2) The name of the default option file to be included in the completed ! basefile. ! ! 3) The destination of the completed basefile. ! ! 4) The type of loader used by the basefile. Possible values are: ! ! OLD or NEW ! ! If any of these parameters is omitted, a prompt is issued for it. !> !> ! externalroutine makebasefile(string (255) parms) integer flag,objconad,link,glastart string (3) loadertype string (31) baseobject,optionfile,basefile record (rf) rr integerarrayname ldata record (dirinff)name dirinf record (ld4f)name ld4 record (hf)name h record (ofmf)arrayname ofm ! set return code(1000) setpar(parms) if parmap > 7 then start flag = 263; ! Wrong number of parameters -> err finish ! baseobject = spar(1) optionfile = spar(2) basefile = spar(3) ! prompt("Object file: ") readline(baseobject) while baseobject = "" prompt("Option file: ") readline(optionfile) while optionfile = "" prompt("Basefile: ") readline(basefile) while basefile = "" prompt("Loader: ") cycle readline(loadertype) uctranslate(addr(loadertype)+1,length(loadertype)) repeat until loadertype = "OLD" or loadertype = "NEW" or loadertype = tostring(em) ! destroy(basefile,flag); ! Ignore flag modpdfile(4,basefile,"","",flag); ! Create empty pdfile -> err if flag # 0 ! connect(baseobject,1,0,0,rr,flag) -> err if flag # 0 if rr_filetype # ssobjfiletype then start setfname(baseobject) flag = 267; ! Invalid filetype -> err finish modpdfile(1,basefile,"BASEOBJECT",baseobject,flag) ! Insert member - order is critical -> err if flag # 0 ! connect(optionfile,1,0,0,rr,flag) -> err if flag # 0 if rr_filetype # ssoptfiletype then start setfname(optionfile) flag = 267; ! Invalid filetype -> err finish modpdfile(1,basefile,"OPTIONFILE",optionfile,flag) ! Insert member -> err if flag # 0 ! destroy(tempdir,flag); ! Ignore flag ! if loadertype # "NEW" then start makeoldbasedir(basefile,tempdir,flag) else makenewbasedir(basefile,tempdir,flag) finish ! -> err if flag # 0 ! ! Copy directory into basefile ! modpdfile(1,basefile,"BASEDIR",tempdir,flag) -> err if flag # 0 destroy(tempdir,flag); ! Ignore flag ! ! Now locate the external integer SSDATELINKED, and fill in the version ! of the current system call table in Director ! dirinf == record(uinfi(10)) connect(basefile."_BASEOBJECT",1,0,0,rr,flag) -> err if flag # 0 changeaccess(basefile,3,flag); ! To write to member -> err if flag # 0 objconad = rr_conad h == record(objconad) ofm == array(objconad+h_ofm+4,ofmaf); ! Object file map glastart = ofm(2)_start ldata == array(objconad+h_lda,ldataf) link = ldata(4) while link # 0 cycle ; ! Search data entry list ld4 == record(objconad+link) if ld4_iden = "SSDATELINKED" then start integer(objconad+glastart+ld4_disp) = dirinf_scdate integer(objconad) = x'1b800010'; ! Jump over header of BASEOBJECT -> found finish link = ld4_link repeat flag = 1002 -> err ! found: disconnect(basefile,flag) set return code(0) stop ! err: fail("MAKEBASEFILE",flag) end ; ! of makebasefile ! ! !*********************************************************************** !* !* M A K E O P T I O N F I L E !* !*********************************************************************** ! !<Subsystem option files ! ! ! The subsystem makes use of a file containing 'options' set by the user ! to tailor his process to his own needs. This Section describes how the ! initial option file used by the Subsystem is created, and explains the ! entries in it. ! ! !<Making the file ! ! The command MAKEOPTIONFILE takes a single parameter, which is the name ! of the option file to be generated. If this parameter is omitted, a ! prompt is issued for it. ! ! A series of prompts is then issued. A value for the appropriate option ! may then be given, or the default setting invoked by simply typing ! 'return'. ! The default setting is displayed in brackets as part of the prompt. ! ! The only exception to all this is the initial PARM setting - see ! Section 5.2.1. !> !<Description of options ! ! ! ! ! ! Some of the values stored in the option file are integers, and others ! are strings. Generally, they describe items such as the size of a ! particular workfile, terminal characteristics, directory search lists, ! etc. ! ! ! The rest of this Section describes each option in detail. ! !PAGE ! !<Initial PARM setting ! ! The value of this option is made the current PARM setting at log-on. ! MAKEOPTIONFILE uses the value actually in force when the option file ! is being created, as this saves it from having to decode large numbers ! of PARM keywords. !> !<Auxiliary stack size ! ! The auxiliary stack is a separate file which is used to store large ! data areas in user programs, due to the limitations on the size of the ! run-time stack in the ICL 2900 series. ! ! Keyword: AUXSTACKSIZE ! ! Default value: 128 Kbytes !> !<Initialised stack size ! ! The initialised stack is a pre-allocated part of the user stack. It ! must be at least 32 Kbytes smaller than the user stack as a whole. It ! is used as a data area by FORTRAN programs, but need only be ! pre-allocated if it is intended to load FORTRAN programs from other ! programs. ! ! Keyword: INITSTACKSIZE ! ! Default value: 100 Kbytes !> !<Interactive terminal width ! ! Subsystem commands such as ANALYSE and FILES assume the terminal width ! given by this option when planning their output. ! ! Keyword: ITWIDTH ! ! Default value: 80 !> !<Array diagnostic level ! ! When a diagnostic traceback is given for a program, the number of ! elements of each array which are actually printed is given by this ! option. ! ! Keyword: ARRAYDIAG ! ! Default value: 10 !> !<Record diagnostic level ! ! When a diagnostic traceback is given for a program, the number of ! items in each record which are actually printed is given by this ! option. ! ! Keyword: RECDIAG ! ! Default value: 10 !> !<The session workfile ! ! Many subsystem commands (particularly the compilers) make use of a ! common workfile. The size of the workfile is determined by this option ! setting. ! ! Keyword: INITWORKSIZE ! ! Default value: 256 Kbytes !> !<Interactive terminal buffers ! ! The subsystem requires two buffers for interactive terminal I/O. One ! is used solely for input, and the other solely for output. Two ! options are provided in order that the sizes of these buffers may be ! altered. ! ! Keyword (input): ITINSIZE ! ! Default value (input) : 1 Kbyte ! ! ! Keyword (output): ITOUTSIZE ! ! Default value (output): 3 Kbytes ! !> !<Terminal type ! ! The terminal/screen control package (used by screen editors, etc.) ! uses this option to determine how an interactive terminal is to be ! driven. ! ! In general, this option will not be set by means of the OPTION ! command, although the keyword TERMINAL is provided. It is expected ! that users will select the appropriate terminal type (which is an ! integer) by means of a special command. ! ! The default value supplied is zero, which should correspond to ! 'unspecified video'. ! !> !<Brackets/Nobrackets ! ! There are two different command formats which are accepted by the ! subsystem: ! ! a) Spaces in commands are not significant, and any parameters must be ! enclosed in brackets. ! ! b) Spaces in commands are not allowed, since one or more spaces are ! used to separate the command from its parameters, which should not ! be enclosed in brackets. ! ! The actual format accepted depends on this option. ! ! Keywords: BRACKETS and NOBRACKETS ! ! Default value: BRACKETS ! !> !<Recall of terminal I/O ! ! The subsystem provides facilities for storing and retrieving ! transactions on an interactive terminal. The three possible values for ! this option are: ! ! NORECALL - nothing is stored ! TEMPRECALL - the current session is stored ! PERMRECALL - the last few sessions are stored ! ! Default value: TEMPRECALL !> !<Suppression of blank lines ! ! This option is provided to enable all blank lines output to the ! terminal to be suppressed. ! ! Keywords: BLANKLINES and NOBLANKLINES ! ! Default value: BLANKLINES !> !<Echoing of OBEY files ! ! When an OBEY file is being processed, the subsystem may or may not ! 'echo' the resulting transactions on the user's terminal. This option ! controls the amount echoed. The possible settings are: ! ! NOECHO - nothing at all is echoed ! PARTECHO - only 'Command:' lines are echoed ! FULLECHO - all input is echoed, including program input ! ! Default value: PARTECHO ! ! Batch jobs are treated by the subsystem as if they are effectively ! OBEY files for the purposes of this option. !> !<Foreground start-up file ! ! This option allows the user to nominate a file of commands which are ! to be OBEYed on foreground process start-up. ! ! Keywords: NOFSTARTFILE and FSTARTFILE ! ! Default value: NOFSTARTFILE !> !<Background start-up file ! ! This option allows the user to nominate a file of commands which are ! to be OBEYed on background process start-up. ! ! Keywords: NOBSTARTFILE and BSTARTFILE ! ! Default value: NOBSTARTFILE !> !<Pre-loading file ! ! This option allows the user to nominate object files which are to be ! 'pre-loaded' on process start-up. It is not currently implemented. !> !<Active directory ! ! This option selects the file which is to be used as the 'active ! directory' for the INSERT and REMOVE commands, and associated actions. ! This is the first user directory searched by the loader, immediately ! after searching the session directory (see Section 4.1). ! ! Keyword: ACTIVEDIR ! ! Default value: SS#DIR !> !<Compiler fault file ! ! This option allows the user to select another file, in addition to the ! compiler listing file, to which compilation fault messages may be ! sent. A value of '.NULL' is equivalent to a null string (NOCFAULTS). ! ! Keyword: CFAULTS ! ! Default value: .OUT !> !<Command prompt ! ! This option allows the user to select an alternative prompt for ! commands solicited by the Subsystem. The maximum length is 31 ! characters. ! ! Keyword: CPROMPT ! ! Default value: Command: !> !<Data prompt ! ! This option allows the user to select an alternative default prompt ! for data solicited by user programs. The maximum length is 31 ! characters. ! ! Keyword: DPROMPT ! ! Default value: Data: !> !<Search directories ! ! Up to 16 additional directories may be added to the search list for a ! process. They are searched immediately after the active directory. ! ! Keywords: SEARCHDIR and REMOVEDIR ! ! Default value: No search directories !> !> !> ! externalroutine makeoptionfile(string (255) parms) integer flag,conad,i string (31) file string (255) s record (contf)name c ! set return code(1000) setpar(parms) if parmap > 1 then start flag = 263; ! Wrong number of parameters -> err finish file <- spar(1) if file = "" then start prompt("Option file: ") readline(file) finish ! outfile(file,4096,0,0,conad,flag) -> err if flag # 0 c == record(conad) c_dataend = 4096 c_filetype = ssoptfiletype ! fill(c_dataend-c_datastart,conad+c_datastart,x'ff') ! Fill whole file with -1 fill(5*32,conad+c_datastart+128,0); ! Clear used strings fill(16*32,addr(c_searchdir(1)),0); ! Set all search directories to null c_mark = 4; ! Mark four option file format ! ! Fill in the installation-dependent values ! c_initparms = longinteger(addr(comreg(27))) printstring("Init "); parm("?") c_astk = getval("Aux stack",64<<10,1024<<10,128<<10,1024) c_istk = getval("Init stack",0,((252-32)<<10),100<<10,1024) c_itwidth = getval("IT width",20,132,80,1) c_arraydiag = getval("Arraydiag",0,1000,10,1) c_recdiag = getval("Recdiag",0,1000,10,1) c_initworksize = getval("Initworksize",256<<10,1024<<10,256<<10,1024) c_itinsize = getval("IT insize",1<<10,16<<10,1<<10,1024) c_itoutsize = getval("IT outsize",1<<10,16<<10,3<<10,1024) c_terminal = getval("Terminal",-1,100,4,1) ! flag = get setting("(No)Brackets",2,bkeys,bvalues,"BRACKETS") if flag = 1 then start c_ldelim = '(' c_rdelim = ')' else c_ldelim = ' ' c_rdelim = nl finish c_journal = get setting("Recall",3,jkeys,jvalues,"TEMPRECALL") c_nobl = get setting("(No)Blanks",2,lkeys,lvalues,"BLANKLINES") c_dataecho = get setting("Echo",3,ekeys,evalues,"PARTECHO") ! c_fstartfile = getstr("Fstartfile",31,"") c_bstartfile = getstr("Bstartfile",31,"") c_preloadfile = getstr("Preloadfile",31,"") c_moddir = getstr("Activedir",31,defaultactivedir) c_cfaults = getstr("Cfaults",31,".OUT") c_cfaults = "" if c_cfaults = ".NULL" c_cprompt = getstr("Cprompt",31,"Command:") c_dprompt = getstr("Dprompt",31,"Data:") ! for i = 1,1,16 cycle prompt("Searchdir ".itos(i).": ") ask: readline(s) uctranslate(addr(s)+1,length(s)) if s = "" or s = ".END" then start c_searchdircount = i - 1 exit finish if length(s) > 31 then start printstring("Reply must not exceed 31 characters".snl) -> ask finish c_searchdir(i) = s repeat ! disconnect(file,flag) printstring("Finished".snl) set return code(0) stop ! err: fail("MAKEOPTIONFILE",flag) end ; ! of makeoptionfile ! ! !*********************************************************************** !* !* C H E C K P D !* !*********************************************************************** ! !<Checking partitioned files ! ! Partitioned files greater than 256 Kbytes in size present special ! problems if they contain members which are object files. An object ! file that crosses a 256 Kbyte boundary may not execute correctly, so ! the action of the subsystem loader is to make a copy of such a member, ! and execute that. This is clearly inefficient. The CHECKPD command ! provides facilities for identifying such problem members. It also ! flags other conditions which cause the loader to make a copy of an ! object file. ! ! The command takes exactly one parameter, the meaning of which is given ! in the following subsections. ! !<Finding the offsets of members ! ! If CHECKPD is given the name of a partitioned file, it simply lists ! the relative offset (in hexadecimal) of each member of that file. !> !<Checking for possible problems ! ! If CHECKPD is given the name of a single member of a partitioned file, ! it determines whether either of two conditions would force the ! subsystem to copy the file when attempting to load it. These ! conditions are: ! ! a) The code of the member crosses a 256 Kbyte boundary ! ! b) The code of the member is not shareable (possible for converted ICL ! object files) !> !> ! externalroutine checkpd(string (255) parms) integer flag,conad,i string (11) member string (31) pdfile,file record (rf) rr record (hf)name or record (pdf)name pd record (hf)name pr record (ofmf)arrayname ofm record (pdf)arrayname pda ! set return code(1000) setpar(parms) if parmap # 1 then start flag = 263; ! Wrong number of parameters -> err finish file <- spar(1) ! connect(file,1,0,0,rr,flag) -> err if flag # 0 ! if file -> pdfile.("_").member then start connect(file,1,0,0,rr,flag) -> err if flag # 0 conad = rr_conad or == record(conad) if or_filetype # ssobjfiletype then start printstring("Member ".member." is not an object file".snl) -> ok finish ofm == array(conad+or_ofm+4,ofmaf); ! Object file map if (conad+ofm(1)_start) >> 18 # c (conad+ofm(1)_start+ofm(1)_len) >> 18 then start printstring("Code of member ".member.c " crosses a 256 Kbyte boundary".snl) -> ok finish if ofm(1)_props & 1 # 0 then start printstring("Code of member ".member." is not shareable".snl) -> ok finish printstring("No problems with member ".member.snl) -> ok else conad = rr_conad pr == record(conad) pda == array(conad+pr_adir,pdaf) i = 1 while i <= pr_count cycle pd == pda(i) printstring(pd_name) spaces(15-outpos) printstring("X".htos(pd_start,6).snl) i = i + 1 repeat finish ! ok: set return code(0) stop ! err: fail("CHECKPD",flag) end ; ! of checkpd endoffile