// GPARSE.SR Paragraph parsing and unparsing
get "BRAVO.DF"
get "CHAR.DF"
get "GINN.DF"
get "DISPLAY.DF"
get "HEAP.DF"
// Incoming procedures
external
[
bsearch
getint
binsearcha
getvch
putvch
mapscrcp
errhlt
stcopy
stnum
stappend
stsize
insertstring
deletea
hpalloca
hpalloc
move
movec
enww
ugt
ult
readsel
stequal
cpadjust2
invalidatedisplay
receivechange
backscan
specstate
nextspecstate
gcspecs
freespec
ckspecs
cpadjustlist
wipedoc
makepara
deletepara
createdocp
bubblesegs
growlist
discardspecs
acquirespecs
replacespec
forgetspec
nulltrailer
uadjust
specdetails
setpagecp
pagecp
cppage
macpage
makepage
makespec
cpc
]
// Incoming statics
external
[
xleftmargstd
xrightmargstd
rgpara
rgspec
rgdlfirst
rgdllast
rgmaxdl
macww
rgdoc
vdoc
vcp
vchremain
rgmaccp
rgcpfdispl
rgcplast
vxleftmarg
vxrightmarg
cpscrt
vdlhint
vinsertk
mdoc
mphd
rgfcode
rgview
rgprogram
vmakelock
vpzone
]
// Outgoing procedures
external
[
parsespec
unparsespec
cppara
cpparabounds
parabounds
paradetails
setparacp
paracp
setparaspec
gotparaspec
paraspec
macpara
lastparacp
wholeparas
]
// Outgoing statics
// Local statics
// Paragraph format is
where has no CRs
// and trailer format is ctrlZ then "jn7b12B14u7bU" then CR
// means 5 changes starting with Justified text,
// 7 chars later turn on Bold
// 12 chars later turn off bold
// 14 chars later turn on Ul
// 7 chars later turn on Bold and turn off ul
// n means no change since last version; N means has changed
// there is an optional change count in front of the trailer;
// if not present it is estimated
let parsespec(doc, para, mail, okrobdisplay; numargs N) = valof
[
let num = nil
let tex, b, e = nil, nil, nil
tex = paracp(doc, para)
e = paracp(doc, para+1) - 1
unless backscan(doc, e, true, chtrailer) do errhlt("MTR")
b = vcp
if ult(b, tex) then errhlt("MTX")
vcp = b + 1
vchremain = 0 ;
vdoc = doc ;
let char = getvch() ;
let siz = $0 le char & char le $9? 3 + getint(doc, 10, char, lv char), (e-b+1) rshift 1
let lim = siz + 2
if vmakelock then
if ugt((2*lim+specbase)*(mail? 3,2)+displaybuf,
vpzone >> ZONE.cfree) then
resultis -1
let spec = makespec(lim, N eq 4 & okrobdisplay)
spec >> SPEC.trailerlength = e + 1 - b
setparaspec(doc, para, spec)
spec >> SPEC.dent = 0
spec >> SPEC.lmarg = 0
spec >> SPEC.rmarg = 0
let info = spec + firstformat
let looks = spec + specbase
let changes = looks + lim
let tfs = 0
let tlook = 0
[
let fcode = 0 le char & char le 127? rgfcode ! char, -1
let w = fcode << FCODE.wordn
let bn = fcode << FCODE.bitn
let m = #100000 rshift bn
let un = fcode << FCODE.un
switchon fcode << FCODE.kind into
[
case knormal:
spec >> SPEC.marker = un ;
char = getvch() ; loop
case kdigit:
num = getint(doc, 10, char, lv char) ;
looks ! tfs = tlook
tfs = tfs + 1
if tfs ge siz then errhlt("TMS")
looks ! tfs = tlook
changes ! tfs = num + changes ! (tfs-1)
loop
case kcr: break
case klook: tlook = un? tlook & not m, tlook % m
endcase
case kquad: info ! w = bn ; endcase
case kmeasure:
num = getint(doc,10,$0,lv char)
info ! w = num
loop // $$ bug fix
default: errhlt("UFC")
]
char = getvch() ;
] repeat
looks ! tfs = tlook
siz = tex eq b? 2, tfs+3
if siz gr lim then errhlt("TmS") ;
spec >> LIST.siz = siz
changes ! (siz-2) = b-tex
changes ! (siz-1) = e+1-tex
if mail then receivechange(mail, doc, para)
resultis gotparaspec(doc, para)
]
and unparsespec(doc, para, spec) = valof
[
if vinsertk % not spec >> SPEC.dirty % rgprogram ! doc then
resultis spec
spec >> SPEC.dirty = 0
let str = vec (maxtrailerl+1)/2 ;
let stn = vec (maxtrailerl+1)/2 +4 ;
stcopy(str, "") ;
let siz, looks, changes = nil, nil, nil
specdetails(spec, lv siz)
let rcpold = 0 ;
let tfold = 0 ;
let tfnew, tfdif, rcpnew = nil,nil,nil
unparsespec2(spec >> SPEC.dent, "d", str, stn)
unparsespec2(spec >> SPEC.lmarg, "l", str, stn)
unparsespec2(spec >> SPEC.rmarg, "r", str, stn)
unparsespec3(spec >> SPEC.quad, 0, table[ 0; $j; $c ] , str)
stappend(str, "N");
let last = siz - 3;
for tfs = 0 to last do
[
rcpnew = changes ! tfs ;
tfnew = looks ! tfs ;
tfdif = tfnew xor tfold ;
if tfdif then
[
if tfs then
[
stnum(stn, rcpnew - rcpold)
stappend(str, stn) ;
]
for char = $A to $z do
if (rgfcode ! char) << FCODE.kind eq klook then
[
let fcode = rgfcode ! char
let m = #100000 rshift (fcode << FCODE.bitn)
let un = fcode << FCODE.un? 0, m
if (tfdif & m) ne 0 & (tfnew & m) eq un then
[
let onecharstring = #400 + char
stappend(str, lv onecharstring)
]
]
tfold = tfnew
rcpold = rcpnew ;
]
]
let tex, b, e = nil, nil, nil
parabounds(doc, para, lv tex, lv b, lv e)
let hstart = b+1
let hfinish = e-1
let newhlen = stsize(str) + 2
if newhlen eq spec >> SPEC.trailerlength then
[
if newhlen eq 2 then resultis spec
readsel(stn, doc, hstart, hfinish, maxtrailerl)
if stequal(str, stn) then resultis spec
]
if ((rgview ! doc) & looktrailermask) ne 0 then
invalidatedisplay(doc, b, vdlhint)
if cpc(hstart, hfinish) le 0 then deletea(doc, hstart, hfinish)
insertstring(doc, hstart, str)
spec = gotparaspec(doc, para)
spec >> SPEC.trailerlength = newhlen
specdetails(spec, lv siz)
changes ! (siz-1) = newhlen + b-tex
resultis spec
]
and unparsespec2(relativevalue, char, str, stn) be
[
if relativevalue eq 0 then return
stappend(str, char)
stnum(stn, relativevalue)
stappend(str, stn)
]
and unparsespec3(itsfmt, stdfmt, chartable, str) be
[
if itsfmt eq stdfmt then return
let x = "X"
x >> rh = chartable!itsfmt
stappend(str, x)
]
and cppara(doc, cp) = bsearch(rgpara ! doc, cp)
and cpparabounds(doc, cp, ptextstart, ptrailerstart, ptrailerend) =
parabounds(doc, cppara(doc, cp),
ptextstart, ptrailerstart, ptrailerend)
and parabounds(doc, para, ptextstart, ptrailerstart, ptrailerend) = valof
[
let spec = paraspec(doc, para)
@ptextstart = paracp(doc, para)
@ptrailerend = paracp(doc, para+1) - 1
@ptrailerstart = @ptrailerend - spec >> SPEC.trailerlength + 1
resultis para
]
and paradetails(doc, para, vector, cp1, cp2, cp3, cp4;numargs N) be
[
// To use:
// let spec,siz,looks,changes[,rcp1,r1[,rcp2,r2[,...]]] = nil,nil,...,nil
// paradetails(doc,para,lv spec[,cp1[,cp2[,...]]])
// r ge siz-2 means rcp is in the trailer
let tex = paracp(doc, para)
let spec = paraspec(doc, para)
vector ! 0 = spec
let siz = specdetails(spec, vector+1)
let j = 4
for i = 0 to N-3 do
[
let rcp = ((lv cp1)!i) - tex
vector ! j = rcp
vector ! (j+1) = rcp ls 0? 0, binsearcha(vector!3, siz-1, rcp)
j = j + 2
]
]
and setparacp(doc, para, cp) be
(rgpara ! doc) ! (para + listbase) = cp
and paracp(doc, para) = valof
[
// Inverse of cppara
// Given a para, find the cp of the start of its text
resultis (rgpara ! doc) ! (para + listbase)
]
and setparaspec(doc, para, spec) be
[
if spec & not spec << odd then
[
spec >> SPEC.doc = doc
spec >> SPEC.para = para
]
(rgspec ! doc) ! (para + listbase) = spec
]
and gotparaspec(doc, para) = (rgspec ! doc) ! (para + listbase)
and paraspec(doc, para) = valof
[
// Given a paragraph number within a document, find its spec --
// if none exists, invoke a parse to create one.
let w = (rgspec!doc)!(para+listbase) ;
if w & not w << odd then resultis w ;
resultis parsespec(doc, para, w)
]
and macpara(doc) = (rgpara ! doc) >> LIST.siz
and lastparacp(doc) = paracp(doc, macpara(doc)-2)
and wholeparas(doc, cp1, cp2) =
cp1 eq paracp(doc, cppara(doc, cp1)) &
cp2+1 eq paracp(doc, cppara(doc, cp2+1))? -1, 0