! PRINT {RWT, January 1991} adapted from the recently revised
! COPY program which automatically switches between filestores
option "-low-nodiag-nocheck"
include "inc:fs.imp"
include "inc:util.imp"
include "inc:fsutil.imp"
! Ether comms
routine ackwait(integer port)
integer bit=1<<port,marktime=cputime+1000,deadline = marktime+14000
cycle
returnif ack&bit#0
printsymbol('.') and marktime=marktime+1000 if cputime>marktime
repeatuntil cputime>deadline
printline("No ACK/NAK"); signal 9
end
routine dtxwait(integer port)
integer bit=1<<port,marktime=cputime+1000,deadline=marktime+6500
cycle
returnif dtx&bit#0
printsymbol('.') and marktime=marktime+1000 if cputime>marktime
repeatuntil cputime>deadline
printline("No response"); signal 9
end
predicate nacked(integer port)
integer bit=1<<port
falseif nak&bit=0; nak = nak&¬bit; true
end
predicate gotack(integer port)
on 9 start ; false ; finish
ackwait(port); falseif nacked(port); true
end
predicate gotdtx(integer port)
on 9 start ; false ; finish
dtxwait(port); true
end
! Filestore comms
routine disconnect
byte disc = {4}12
returnif rdte=0; rdte = 0; rsap = 0
etherwrite(lsap,disc,1); ackwait(lsap); returnif nacked(lsap)
end
routine connect
string (255)s
integer port
byte con = 2
on 9 start
printline(event_message); return
finish
rsap = 0; fsport = lsap; etheropen(lsap,rdte<<8)
etherwrite(lsap,con,1); ackwait(lsap)
if nacked(lsap) start
printstring("No Ack from station "); phex2(rdte); newline; return
finish
dtxwait(lsap)
length(s) = etherread(lsap,charno(s,1),80)
port = charno(s,1)-'0'
if port<0 start
printline(substring(s,3,length(s))); return
finish
etheropen(lsap,rdte<<8+port)
! check connection
while dtx&1#0 cycle
length(s) = etherread(0,charno(s,1),255)
printline("Spurious port 0 packet ignored")
repeat
s = "M0".snl; etherwrite(lsap,charno(s,1),3)
unless gotack(lsap) start
printline("No M0 ack"); return
finish
unless gotdtx(lsap) start
printline("No M0 response"); return
finish
length(s) = etherread(lsap,charno(s,1),255)
s = "G0".snl; etherwrite(lsap,charno(s,1),3)
unless gotack(lsap) start
printline("No G0 ack"); return
finish
unless gotdtx(lsap) start
printline("No G0 response"); return
finish
length(s) = etherread(lsap,charno(s,1),255)
while charno(s,1)='-' cycle
printline("Ignoring duplicate response")
unless gotdtx(lsap) start
printline("No duplicate response"); return
finish
length(s) = etherread(lsap,charno(s,1),255)
repeat
rsap = port
end
begin
recordformat f(byte ldte,lsap,rdte,rsap)
@#ldte record (f)cur
record (f)array portinfo(1:31)
integer original=cur_lsap,i,inport=original,outport=original
constinteger lpi=1,cpi=2,qual=3
constinteger lpinormal=2{6}, cpinormal=1{12}, qualnormal=0{draft}
byte lpival=lpinormal,cpival=cpinormal,qualval=qualnormal,banner=1
string (255)thisone,therest,filename
routine setparam(integer parameter,value)
printsymbol(27); printsymbol('?')
printsymbol(parameter+' '); printsymbol(value+' ')
end
routine select(integer port)
owninteger uno=0
uno = userno if userno#0
userno = 0
userno = uno if port=1
cur = portinfo(port); fsport = port
end
integerfn allocate port
integer i
for i = 1,1,31 cycle
if portinfo(i)_rdte=rdte start
select(i)
result = i
finish
repeat
for i = 2,1,31 cycle
if portinfo(i)_rdte=0 start
lsap = i; fsport = i
connect; select(original) andresult = 0 if rsap=0
portinfo(i) = cur
result = i
finish
repeat
select(original); printline("No free local ports"); result = 0
end
integerfn access(routine open(integer stream,string (255)filename),
string (255)filename)
! Result 0 after error report if failed, otherwise result is port number.
! Parse the filename to determine which filestore is meant, selecting the
! appropriate port, connecting if necessary. Then open the file. If this
! fails with "owner not found" (i.e. event_extra=12), and the filestore in
! question was B or C, then try instead on C or B.
ownbytearray dtetable('A':'Z')=16_14,16_15,16_1B,0(*)
string (255)server,rawfilename
integer dte,port,retried=0,k
on 3 start
selectoutput(0); select(original)
retried = 1 unless event_extra=12
if retried=0 start
if dte=dtetable('B') or dte=dtetable('C') start
dte = dtetable('B')+dtetable('C')-dte
finishelse retried=1
finish
if retried#0 start
printline(event_message); result = 0
finish
retried = 1
finish
select(original)
if retried=0 start {first time parse filename}
dte = rdte; rawfilename = filename
if filename -> server.("::").rawfilename start
retried = 1 {no retrying if server specified explicitly}
k = charno(server,1)&95 unless server=""
if length(server)=1 and 'A'<=k<='Z' start
dte = dtetable(k)
else
dte = 0
while server#"" cycle
k = charno(server,1); server = substring(server,2,length(server))
if '0'<=k<='9' start
dte = dte<<4-'0'+k
else
k = k&95; exitunless 'A'<=k<='F'
dte = dte<<4-'A'+k+10
finish
repeat
finish
if dte=0 start
no: select(original); printstring("Unknown server ")
printline(filename); result = 0
finish
finish
finish
rdte = dte; port = allocate port; ->no if port=0
select(port); open(1,rawfilename); selectoutput(0)
result = port
end
routine transfer
bytearray buf(0:4095)
integer n=0,k=nl,i
on 9 start
closeinput
select(outport); selectoutput(1)
for i = 0,1,n-1 cycle
k = buf(i); printsymbol(k)
repeat
newline unless k=nl
selectoutput(0)
return
finish
cycle
select(inport); selectinput(1)
n = 0
cycle
readsymbol(buf(n)); n = n+1
repeatuntil n=4096
select(outport); selectoutput(1)
for i = 0,1,n-1 cycle
k = buf(i); printsymbol(k)
repeat
repeat
end
! Draw box around text
constinteger maxwidth=80,maxheight=71
string (maxwidth)array line(1:maxheight)
integer p=1,max=0
routine newbox
p = 1; max = 0
end
routine add(string (maxwidth)s)
! Add line S to the box
returnif p>maxheight-2 or length(s)>=maxwidth-2
max = length(s) if length(s)>max
line(p) = s; p = p+1
end
routine enbox(integer margin)
! MARGIN is number of spaces wanted between text and horizontal border.
! For vertical equivalent, user is obliged to call ADD("") appropriately.
! For multiple borders, ENBOX may be called repeatedly.
integer i
string (maxwidth)name s
returnif p>maxheight-1 or (1+margin)*2+max>=maxwidth
for i = p-1,-1,1 cycle
s == line(i+1)
s = "|"
s = s." " while length(s)<=margin
s = s.line(i)
s = s." " while length(s)<=2*margin+max
s = s."|"
repeat
s == line(1)
s = "+"; s = s."-" while length(s)<=2*margin+max
s = s."+"
line(p+1) = s
p = p+2; max = (1+margin)*2+max
end
routine printbox(integer pos)
! POS>0 aligns it to the left, with an extra POS-1 spaces.
! POS<0 aligns it to the right, (-POS)-1 spaces from the RH margin.
! POS=0 aligns it to the middle.
integer i
if pos>0 then pos = pos-1 -
elseif pos<0 then pos = pos-max+maxwidth+1 -
else pos = (maxwidth-max)>>1
for i = 1,1,p-1 cycle
spaces(pos); printstring(line(i)); newline
repeat
end
routine print(string (255)file)
inport = access(openinput,file); returnif inport=0
outport = access(openoutput,"c::lp:!".currentuser)
if outport=0 start
select(inport); selectinput(1); closeinput
select(original); return
finish
printstring("Printing ".file); newline
select(outport); selectoutput(1)
setparam(lpi,lpival)
setparam(cpi,cpival)
setparam(qual,qualval)
transfer
selectoutput(1)
setparam(lpi,lpinormal) unless lpival=lpinormal
setparam(cpi,cpinormal) unless cpival=cpinormal
setparam(qual,qualnormal) unless qual=qualnormal
unless banner=0 start
printsymbol(12)
printstring("THIS SHOULD BE THE FIRST LINE ON THE PAGE"); newlines(3)
! 3 lines so far
newbox
add("IMPORTANT:")
add("Please check whether the top-of-form is set correctly, with the above")
add("'first line' appearing immediately adjacent to, but not overlapping,")
add("the inter-sheet perforations. If it is wrong, PLEASE CORRECT IT NOW,")
add("as follows:")
add("* Raise the hood.")
add("* Raise the platen lever on your left. This unlocks the tractor feed")
add(" mechanism, allowing you to adjust the paper alignment by rotating")
add(" the black knob on your right.")
add("* Move the paper until the inter-sheet perforations are in line with")
add(" the middle of the black plastic 'gates' which hold the paper to the")
add(" tractor feed mechanism. A little 'nose' poking out of each of the")
add(" two gates marks the place.")
add("* Lower the platen lever to re-engage the motor drive.")
add("* NOW FOR THE CLEVER BIT: While holding down the reset button, press")
add(" the form feed button once. This is a special 'partial-form-feed'")
add(" instruction which tells the printer to advance the paper by the")
add(" difference between the sheet length and the distance from the")
add(" top-of-form position and the alignment 'noses'.")
add("* Lower the hood. Press the on-line button.")
enbox(1); printbox(0)
! plus 20 plus 2 = 25 lines so far
newlines(50-25)
! 50 lines so far
newbox
select(original)
add(datetime)
add("The file just printed was ".file)
add("It was sent by ".currentuser)
select(outport)
enbox(1); enbox(1); enbox(1); printbox(0)
finish
closeoutput; selectoutput(0)
end
on 0 start
select(original); selectoutput(0); printstring("*Aborted")
select(inport); select(original) if inport=0
selectinput(1); closeinput
select(outport); select(original) if outport=0
selectoutput(1); resetoutput; closeoutput
select(original); selectoutput(0); newline
return
finish
portinfo(i) = 0 for i = 1,1,31
portinfo(original) = cur
therest = cliparam.","
while therest -> thisone.(",").therest cycle
filename = ""
defineparam("File",filename,0)
defineenumparam("c10,c12,c13,c17 - cpi",cpival,0)
defineenumparam("l3,l4,l6,l8 - lpi",lpival,0)
defineenumparam("draft,,letter - quality",qualval,0)
defineenumparam("nobanner,banner - trailer",banner,0)
processparameters(thisone)
continueif filename=""
filename = currentdirectory.":".filename unless filename -> (":")
print(filename); select(original)
repeat
for i = 1,1,31 cycle
select(i); disconnect unless i=original
repeat
select(original)
end