!*********************************************************************** !* !* Program to write an unlabelled tape !* !* R.D. Eager University of Kent MCMLXXXIII !* !*********************************************************************** ! constantinteger version = 3; ! Major version number constantinteger edit = 1; ! Edit number within major version ! !*********************************************************************** !* !* Constants !* !*********************************************************************** ! constantinteger no = 0, yes = 1 constantinteger ascii = 0, ebcdic = 1 constantinteger defaultrecsize = 80 constantinteger maxrecsize = 262143 constantinteger defaultblocksize = 800 constantinteger maxblocksize = 262143 constantinteger defaultthreshold = 10 constantinteger maxthreshold = 1000 constantinteger sscharfiletype = 3 constantinteger maxfile = 999; ! Maximum number of files per tape constantinteger listchan = 80; ! Channel for listing of files written constantinteger tapechan = 1 constantbyteinteger nl = 10 constantstring (1) snl = " " constantinteger keymax = 8; ! Number of parameter keywords constantstring (9)array keys(1:keymax) = c "TAPE", "STARTFILE", "LISTING", "CODE", "RECSIZE", "BLOCKSIZE", "THRESHOLD", "VERSION" ! !*********************************************************************** !* !* Record formats !* !*********************************************************************** ! recordformat descf(integer dr0,dr1 or c longinteger dr) recordformat fdf(integer link,dsnum,byteinteger status,accessroute, valid action,cur state,mode of use,mode,file org, dev code,rec type,flags,lm,rm,integer asvar,arec, recsize,minrec,maxrec,maxsize,lastrec,conad,currec, cur,end,transfers,darecnum,cursize,datastart, string (31) iden,integer keydesc0,keydesc1, recsizedesc0,recsizedesc1,byteinteger f77flag, f77form,f77access,f77status,integer f77recl,f77nrec, idaddr,byteinteger f77blank,f77ufd,spare1,spare2) recordformat hf(integer dataend,datastart,filesize,filetype, sum,datetime,format,records) recordformat rf(integer conad,filetype,datastart,dataend) ! ! !*********************************************************************** !* !* Subsystem references !* !*********************************************************************** ! systemroutinespec connect(string (31) file,integer mode,hole, prot,record (rf)name r,integername flag) externalstringfunctionspec date systemroutinespec define(integer chan,string (31) iden, integername afd,flag) systemroutinespec disconnect(string (31) file,integername flag) systemstringfunctionspec failuremessage(integer mess) externalintegerfunctionspec instream systemintegerfunctionspec iocp(integer ep,parm) systemroutinespec itoe(integer ad,l) systemstringfunctionspec itos(integer n) systemintegermapspec mapssfd(integer dsnum) externalintegerfunctionspec outpos externalintegerfunctionspec outstream externalroutinespec prompt(string (255) s) systemintegerfunctionspec pstoi(string (63) s) systemroutinespec setfname(string (63) s) externalroutinespec set return code(integer i) externalstringfunctionspec time systemroutinespec uctranslate(integer ad,len) ! ! !*********************************************************************** !* !* Magnetic tape interface routines !* !*********************************************************************** ! externalroutinespec askmag(integer channel,string (7) vol, integername flag) externalroutinespec rewindmag(integer channel) externalroutinespec skiptmmag(integer channel,n) externalroutinespec writemag(integer channel,ad,len,integername flag) externalroutinespec writetmmag(integer chan,integername flag) externalroutinespec unloadmag(integer channel) ! ! !*********************************************************************** !* !* Service routines !* !*********************************************************************** ! routine clearstream(integer chan) ! Clears out a channel definition, but does not give an error if the ! channel was not defined. record (fdf)name f ! if mapssfd(chan) # 0 then start f == record(mapssfd(chan)) if f_status = 0 then start mapssfd(chan) = 0 f_dsnum = 0; ! Mark descriptor as free finish finish end ; ! of clearstream ! !----------------------------------------------------------------------- ! routine closestream(integer chan) ! Private version of 'closestream'. Does not give an error if the ! operation fails. integer flag ! return unless instream # chan # outstream flag = iocp(16,chan) end ; ! of closestream ! !----------------------------------------------------------------------- ! integerfunction matchstrings(stringname a,string (255) b) integer l ! l = length(a) if length(b) < l then result = 0 length(b) = l if a = b then result = yes else result = no end ; ! of matchstrings ! !----------------------------------------------------------------------- ! integerfunction paramdecode(string (255) param,integer pmax, stringarrayname keys,pars) integer i,pnum,pn,res,c,parptr,parleng string (255) wksp ! !----------------------------------------------------------------------- ! integerfunction findkey integer f,i ! if length(wksp) = 0 then result = -2;! Missing keyword f = 0 for i = 1,1,pmax cycle if matchstrings(wksp,keys(i)) = yes then start unless f = 0 then result = -1 f = i finish repeat result = f end ; ! of findkey ! !----------------------------------------------------------------------- ! integerfunction getpar integer c,inpr ! inpr = 0 wksp = "" ! cycle parptr = parptr + 1 if parptr > parleng then result = -1 c = charno(param,parptr) if c = ',' or c = '=' then result = c wksp = wksp.tostring(c) repeat end ; ! of getpar ! !----------------------------------------------------------------------- ! for i = 1,1,pmax cycle pars(i) = ""; ! Initialise repeat parptr = 0 pnum = 1 parleng = length(param) ! cycle c = getpar res = 0 if c # '=' then start pn = pnum else pn = findkey if pn = 0 then res = 322; ! Unknown keyword if pn = -1 then res = 321; ! Ambiguous keyword if pn = -2 then res = 325; ! Missing keyword c = getpar if c = '=' then res = 320; ! Format error finish if pn > pmax then res = 323; ! Too many parameters if res = 0 then start if wksp # "" # pars(pn) then res = 324 ! Duplicated parameter pars(pn) = wksp finish if res # 0 then result = res if c = -1 then result = 0; ! Finished, all OK pnum = pnum + 1 repeat end ; ! of paramdecode ! !----------------------------------------------------------------------- ! string (63)function specmessage(integer n) switch mes(1000:1002) ! -> mes(n) ! mes(1000): result = "Failed to claim tape" mes(1001): result = "Tape write error" mes(1002): result = "Incompatible block and record sizes" end ; ! of specmessage ! !----------------------------------------------------------------------- ! routine fail(integer n) selectoutput(0) printstring(snl."WRULTAPE fails -") if n < 1000 then start printstring(failuremessage(n)) else printstring(specmessage(n).snl) finish closestream(listchan) clearstream(listchan) set return code(n) stop end ; ! of fail ! !----------------------------------------------------------------------- ! routine readline(stringname s) integer c ! on event 9 start s = ".END" return finish ! s = "" cycle cycle readsymbol(c) exit if c = nl s <- s.tostring(c) repeat ! while length(s) > 0 cycle c = charno(s,length(s)) exit unless c = ' ' length(s) = length(s) - 1 repeat ! exit unless length(s) = 0 repeat uctranslate(addr(s)+1,length(s)) end ; ! of readline ! !----------------------------------------------------------------------- ! routine warn(string (255) s) s <- "Warning - ".s selectoutput(0) printstring(s) selectoutput(listchan) printstring(s) end ; ! of warn ! !----------------------------------------------------------------------- ! routine write block(integer ad,len,code) integer flag ! if code = ebcdic then itoe(ad,len) writemag(tapechan,ad,len,flag) if flag # 0 then fail(1001) end ; ! of write block ! !----------------------------------------------------------------------- ! integerfunction write file(integer conad,code,recsize,blocksize, threshold,string (31) file) integer start,i,ad,len,records,truncations,count record (descf) fdesc,tdesc,tempdesc string (63) mes byteintegerarray buf(1:blocksize) record (hf)name r ! r == record(conad) start = conad + r_datastart len = r_dataend - r_datastart ! ! Set bound check inhibit, so that MODD works sensibly ! *cpsr _i i = i!x'400' *mpsr _i ! ! Set up addresses for copying into the buffer ! fdesc_dr0 = x'18000000'!len fdesc_dr1 = start ad = addr(buf(1)) ! ! Main copy loop ! records = 0 count = 0 truncations = 0 cycle *lb _nl; ! Character for scan *ld _fdesc *jat _11,<endoffile>; ! *jzdl_endoffile *swne _l =dr ; ! Scan to end of line *jat _11,<eof>; ! *JZDL_EOF *modd _1; ! Move past newline eof: *std _tempdesc i = tempdesc_dr1-fdesc_dr1-1; ! Length of line, excluding newline records = records + 1 if i > recsize then start if truncations < threshold then start mes = "File ".file." - record ".itos(records)." truncated".snl warn(mes) finish truncations = truncations + 1 i = recsize finish fdesc_dr0 = x'18000000'!i; ! Descriptor to line if count = 0 then start ; ! New buffer load - reset descriptor tdesc_dr1 = ad finish tdesc_dr0 = x'18000000'!recsize *lsd _fdesc *ld _tdesc *mv _l =dr ,0,32; ! Move and space fill *std _tdesc; ! Update address count = count + recsize if count >= blocksize then start write block(ad,count,code) count = 0 finish *lsd _tempdesc; ! Update descriptor to input file *st _fdesc repeat ! endoffile: if count # 0 then write block(ad,count,code) if truncations > threshold then start mes = "Total of ".itos(truncations)." records truncated".snl warn(mes) finish result = records end ; ! of write file ! ! !*********************************************************************** !* !* W R U L T A P E !* !*********************************************************************** ! externalroutine wrultape(string (255) parms) stringname vol,fs,out,cs,rs,bs,ts,vs integer flag,startfile,fileno,failures,code,recsize,blocksize,threshold integer records,afd string (63) input,name,work record (rf) rr string (255)array options(1:keymax) ! flag = paramdecode(parms,keymax,keys,options) -> err if flag # 0 vol == options(1) fs == options(2) out == options(3) cs == options(4) rs == options(5) bs == options(6) ts == options(7) vs == options(8) ! if vol = "" then start flag = 263; ! Wrong number of parameters -> err finish unless 1 <= length(vol) <= 6 then start setfname(keys(1)) flag = 326; ! Invalid value for TAPE parameter -> err finish ! if fs # "" then start ; ! Starting file specified startfile = pstoi(fs) unless 1 <= startfile <= maxfile then start setfname(keys(2)) flag = 326; ! Invalid value for STARTFILE parameter -> err finish finish else startfile = 1 ! out = "T#LIST" if out = "" ! cs = "ASCII" if cs = "" if matchstrings(cs,"ISO") = yes then cs = "ASCII" if matchstrings(cs,"ASCII") = yes then start code = ascii else if matchstrings(cs,"EBCDIC") = yes then start code = ebcdic else setfname(keys(4)) flag = 326; ! Invalid value for CODE parameter -> err finish finish ! if rs # "" then start ; ! Record size specified recsize = pstoi(rs) unless 1 <= recsize <= maxrecsize then start setfname(keys(5)) flag = 326; ! Invalid value for RECSIZE parameter -> err finish finish else recsize = defaultrecsize ! if bs # "" then start ; ! Block size specified blocksize = pstoi(bs) unless 1 <= blocksize <= maxblocksize then start setfname(keys(6)) flag = 326; ! Invalid value for BLOCKSIZE parameter -> err finish finish else blocksize = defaultblocksize ! if ts # "" then start ; ! Error threshold specified threshold = pstoi(ts) unless 1 <= threshold <= maxthreshold then start setfname(keys(7)) flag = 326; ! Invalid value for THRESHOLD parameter -> err finish finish else threshold = defaultthreshold ! if vs # "" then start if matchstrings(vs,"NO") = no then start if matchstrings(vs,"YES") = yes then start printstring("Version: E".itos(version).".".itos(edit).snl) else setfname(keys(8)) flag = 326; ! Invalid value for VERSION parameter -> err finish finish finish ! if blocksize//recsize*recsize # blocksize then fail(1002) ! Incompatible values ! askmag(tapechan,vol."*",flag) if flag # 0 then start setfname(vol) flag = 1000; ! Failed to claim tape -> err finish rewindmag(tapechan) ! define(listchan,out,afd,flag) -> err if flag # 0 selectoutput(listchan) newlines(2) printstring("Unlabelled multi-file tape ".vol.c " written at ".time." on ".date) newlines(2) printstring(" File File name ".c "Records".snl) newlines(2) ! fileno = startfile - 1 skiptmmag(tapechan,fileno) failures = 0 cycle prompt("File: ") readline(input) exit if input = ".END" connect(input,1,0,0,rr,flag) if flag = 0 then start if rr_filetype # sscharfiletype then start setfname(input) flag = 267; ! Invalid filetype finish finish if flag # 0 then start warn(failuremessage(flag)) failures = failures + 1 continue finish fileno = fileno + 1 records = write file(rr_conad,code,recsize,blocksize,threshold,input) writetmmag(tapechan,flag) ! -> tapeerr if flag # 0 write(fileno,6) spaces(10) name = input if name -> work.(".").name then start ; finish printstring(name) spaces(40-outpos) write(records,11) newline disconnect(input,flag) repeat ! if fileno = 0 then start writetmmag(tapechan,flag) -> tapeerr if flag # 0 finish ! writetmmag(tapechan,flag); ! Double tape mark to terminate -> tapeerr if flag # 0 ! newline selectoutput(0) closestream(listchan) clearstream(listchan) if failures # 0 then start printstring(itos(failures)." file") if failures # 1 then printsymbol('s') printstring(" failed to copy".snl) finish printstring("Tape written".snl) unloadmag(tapechan) set return code(-failures) stop ! tapeerr: ! unloadmag(tapechan) flag = 1001; ! Tape write error ! err: fail(flag) end ; ! of wrultape endoffile