// EdBUILD -- Sproull 7/77, Rosen 3/30/78, Chang 7/31/78, Rosen 8/10/78, Chang 10/23/78
// Last Modified October 16, 1979 10:45 AM by Thacker
// Changed Printing program to Sil/P instead of Nppr
// fixed default template for gobble generated wirelists
// fixed main dispatch loop code so that gobble old wirelist filenames were right

// Program to "help keep things straight" in the DA world

// Load: EDBuild-Load.cm
//
(bldr/f EdBuild EdBuilda parsetitle mdi nsilutil ctime fancytemplate stringstreams format)

get "sysdefs.d"
get "altofilesys.d"
get "disks.d"
get "nsil.defs"
//For definitions of SIL file format

structure TERM:
[
switchChar word
phrase @str
switchPhrase @str
]

manifest
[
MaxFileNames=40
FileNameWordLength=20
fpLookSize=6
nBuiltMarks=4
maxBuildAdditions=nBuiltMarks*5+400
BuiltMarkWidth=80
BuiltMarkIncrement=BuiltMarkWidth+
(568-nBuiltMarks*BuiltMarkWidth)/(nBuiltMarks-1)
charItem=1
verLatest=1
]

external
[
ErrorMessage// defined here
reWork
useRoute
revStr
oldRevStr
strWl
strOldWl
strBase
adStr
remCm
fileNameVec
fileNameCount
analyzeNameVec
analyzeNameCount
RunProg
errorS

ParseTitle
// defined elsewhere
CopyCarefully
InsureDiskSpace
RepairComment
UNPACKDT
CopyString
CopyWl
MakeFileNames
MergePN
FindFiles
BackupFiles
ChangeExtension

DefaultArgs
// OS statics
TruncateDiskStream
DeleteFile
FileLength
SetFilePos
ReadBlock
Ws
Wss
sysDisk
Noop
FORMATN
]

static
[
silFiles
glob
com
revStr
oldRevStr
strWl
strOldWl
strBase
adStr
fileNameVec
fileNameCount
unbuiltNameVec
unbuiltNameCount
analyzeNameVec
analyzeNameCount
analyzeAll
useRoute
remCm
reWork
fpTempFile
errorS

NewItem
SpaceTop
]

let BuildMain() be
[
Ws("EdBUILD October 16, 1979")
fpTempFile=table [ 0;0;0;0;0 ]

let v =vec MaxFileNames*fpLookSize
silFiles = v

let s=OpenFile("Com.Cm", ksTypeReadOnly,1,0,fpComCm)
let buildV=vec (size TERM/16)
ParseTerm(s, buildV)
let tentative=false
analyzeAll=false
useRoute=false
reWork = false
errorS = 0
let Bstep=1
//Which step to do next?
for i=1 to buildV>>TERM.switchPhrase.length do
[
let c=buildV>>TERM.switchPhrase.char↑i
if c eq $t % c eq $T then tentative=true
if c eq $a % c eq $A then analyzeAll = true
if c eq $r % c eq $R then useRoute = true
if c eq $g % c eq $G then useRoute = false
if c eq $c % c eq $C then reWork = true
if $1 le c & c le $9 then Bstep=c-$0
]
if tentative then
[
if Bstep eq 3 then Bstep=4 // don’t merge pin numbers
if Bstep gr 4 then finish
]
if Bstep gr 8 then finish

//At this point, BUILD/xx has been parsed -- s remains poised for
// rest of command line.

let flagletter=selecton Bstep into
[
case 1: case 2: $A//Analyze
case 3: case 4: $G
//Route or Gobble
case 5: case 6: case 7: $P
//Print
case 8: $F
//Ftp
]

fileNameCount=0
unbuiltNameCount = 0
analyzeNameCount = 0
let fileNameVecT=vec (FileNameWordLength+1)*MaxFileNames
let uNVT = vec MaxFileNames
fileNameVec=fileNameVecT
unbuiltNameVec = uNVT
let aNVT = vec MaxFileNames
analyzeNameVec = aNVT
let p=fileNameVec+MaxFileNames
for i=0 to MaxFileNames-1 do
[
@p=0//No string yet
fileNameVec!i = p
p=p+FileNameWordLength
]

let strBaseT = vec FileNameWordLength
//Holds file BASE name
strBase = strBaseT
//Set up by MakeFileNmaes
let strWlT = vec FileNameWordLength
//Holds BASE01.wl
strWl = strWlT
//Set up by MakeFileNmaes
let strOldWlT = vec FileNameWordLength
//Holds BASE-OldRev.wl
strOldWl = strOldWlT
//Set up by MakeFileNmaes
let comT=vec 100; @comT=0; com=comT
//Holds local commands, switches
let globT=vec 10; @globT=0; glob=globT
//Holds global switches
let revStrT=vec 10; @revStrT=0; revStr=revStrT
//Holds revision string
let oldRevStrT=vec 10; @oldRevStrT=0; oldRevStr=oldRevStrT
//Holds old revision string
let adStrT=vec 10; @adStrT=0; adStr=adStrT
//Holds OLDtoNew.ad

while ParseTerm(s, buildV) do
[
if buildV>>TERM.switchChar eq 0 then
[
//File name
MoveBlock(fileNameVec!fileNameCount, lv buildV>>TERM.phrase, FileNameWordLength)
fileNameCount=fileNameCount+1
if fileNameCount eq MaxFileNames then CallSwat("Too many file names")
loop
]

let c=buildV>>TERM.switchPhrase.char↑1
if c ge $a then c=c-$a+$A
if c eq $G & buildV>>TERM.switchChar eq $\ then reWork=true
if c eq flagletter then
[
let swstr=nil
let global=buildV>>TERM.phrase.length eq 0
test global then
[
if glob>>str.length eq 0 then AppendC(buildV>>TERM.switchChar, glob)
swstr=glob
] or [
AppendC($*s, com)
AppendS(lv buildV>>TERM.phrase, com)
if buildV>>TERM.switchPhrase.length ne 1 then
AppendC(buildV>>TERM.switchChar, com)
swstr=com
]
for i=2 to buildV>>TERM.switchPhrase.length do
AppendC(buildV>>TERM.switchPhrase.char↑i, swstr)
loop
]
//Must be some sort of switch for BUILD
if c eq $R then MoveBlock(revStr, lv buildV>>TERM.phrase, 10)
if c eq $O then MoveBlock(oldRevStr, lv buildV>>TERM.phrase, 10)
]
Closes(s)

// Finished parsing Com.Cm.
// File names recorded in fileNameVec, fileNameCount
// Global switch string in "glob"
// Local switch commands in "com"

remCm=OpenFile("Rem.Cm",ksTypeWriteOnly,1,0,fpRemCm)

// Now dispatch to the proper routine -- will write stuff into Rem.Cm

[
switchon Bstep into
[
case 1:
[ CopyCarefully("Com.cm", "Build.cm")
let Estr = vec FileNameWordLength
MoveBlock(Estr, fileNameVec!0, FileNameWordLength)
ChangeExtension(Estr, ".er")
let Erf = OpenFile(Estr,ksTypeReadOnly,1)
if Erf ne 0 then DeleteFile(Estr)
MarkBuilt() ]; endcase
case 2:
[ let anafile = OpenFile("Analyze.Run",ksTypeReadOnly,0)
if ((analyzeAll)%(unbuiltNameCount gr 0))&(anafile eq 0) then
CallSwat("Can not open file Analyze.Run!")
Closes(anafile)
RunProg((analyzeAll? "Analyze", (unbuiltNameCount gr 0? "Analyze",
"// Comment - No analysis required")), 0,
(analyzeAll? analyzeNameVec, unbuiltNameVec),
(analyzeAll? analyzeNameCount, unbuiltNameCount),
AddErFileName)
break ]; endcase
case 3: MergePN(); endcase
case 4:
[ let gobfile = OpenFile((useRoute?"Route.Run","Gobble.Run"),ksTypeReadOnly,0)
if (gobfile eq 0) then
CallSwat("Can not open file Route.Run/Gobble.Run!")
Closes(gobfile)
MakeFileNames()
if reWork then test CopyCarefully(strOldWl,strWl)
ifso Ws(" Copy OldRev-WL file into WL")
ifnot CallSwat("couldn’t copy OldRev-WL file", strOldWl)
let Estr = vec FileNameWordLength
MoveBlock(Estr, fileNameVec!0, FileNameWordLength)
ChangeExtension(Estr, ".er")
let Erf = OpenFile(Estr,ksTypeReadOnly,1)
if Erf ne 0 then Closes(Erf)
if Erf ne 0 then CheckPrevErrors(".er", 1)
FindSilFiles()
RunProg((useRoute? "Route", "Gobble"), ".nl",analyzeNameVec,
analyzeNameCount,AddReworkSwitch)
break ]; endcase
case 5:
[ MakeFileNames()
FindSilFiles()
RunProg("Analyze/P", 0,analyzeNameVec,
analyzeNameCount) ]; break
case 6: [ if useRoute then CheckPrevErrors(".re", 1)
CopyWl() ]
endcase
case 7: [ RunProg("Sil/P", 0); break ]; endcase
case 8: [ BackupFiles(); break ]; endcase
]
Bstep=Bstep+1
] repeat

Puts(remCm, $*n)

// Now copy into Rem.Cm the continuation command : the
// original contents of Com.Cm, updated with a step switch.

let s=OpenFile("Com.Cm", ksTypeReadOnly,1,0,fpComCm)
ParseTerm(s, buildV)
let j=0
let len=buildV>>TERM.switchPhrase.length
for i=1 to len do
[
let c=buildV>>TERM.switchPhrase.char↑i
if $0 le c & c le $9 then j=i
]
if j eq 0 then [ j=len+1; buildV>>TERM.switchPhrase.length=j ]
buildV>>TERM.switchChar=$/
buildV>>TERM.switchPhrase.char↑j=Bstep+1+$0
WriteTerm(remCm, buildV)
while ParseTerm(s, buildV) do WriteTerm(remCm, buildV)
Puts(remCm, $*n)
Closes(s)
Closes(remCm)
if errorS ne 0 then Closes(errorS)
finish
]

and AddErFileName() be ComFile(0, ".er/E")

and AddReworkSwitch() be if reWork & useRoute then WSS(remCm,"/C")

and MarkBuilt() be
[
let silFiles = FindSilFiles()
for i=0 to fileNameCount-1 do
[
let s=OpenFile(fileNameVec!i,ksTypeReadWrite,0,0,silFiles+i*fpLookSize+1)
if s eq 0 then CallSwat("Cannot open .SIL file",fileNameVec!i)
let isLogic = isLogicFile(fileNameVec!i)
let a=FileLength(s)/2; Resets(s)
let base=@#335
if Usc(a+base+maxBuildAdditions+2000, lv base) gr 0 then
CallSwat("Too much space required for SIL file")
InsureDiskSpace(maxBuildAdditions)
@#335=base+a+maxBuildAdditions
ReadBlock(s, base, a)
let endP=base+a
let alreadyBuilt=(@base eq 34563b)
@base = 34563b
//Mark built
let titV=vec 200
for pass=0 to 3 do
//Parse title area, once with old hdg, once with new.
[
if (pass eq 0) % (pass eq 2) do ParseTitle(0, titV, 200)
let p=base+1
while p ne endP do
[
let a=ParseTitle(1, titV, p)
if pass eq 1 & a ne 0 then
[
let newP=vec 60
MakeNewTitle(a,newP,p,i,alreadyBuilt,isLogic)
let ol=Length(p)
let nl=Length(newP)
if nl gr ol then
[
let diff=nl-ol
let q=endP
[ q!diff=q!0; q=q-1 ] repeatuntil q eq p
]
if ol gr nl then
[
let diff=ol-nl
let q=p
[ q!0=q!diff; q=q+1 ] repeatuntil q eq endP
]
endP=endP+nl-ol
MoveBlock(p, newP, nl)
]
p=p+Length(p)
]
]
test alreadyBuilt
ifnot for i=0 to nBuiltMarks-1 do
[
endP>>item.link=-1
endP>>item.xmin=i*BuiltMarkIncrement
endP>>item.xmax=i*BuiltMarkIncrement+BuiltMarkWidth
endP>>item.ymax=BuildYmax
endP>>item.ymin=BuildYmax-7
endP>>item.font=14
endP=endP+Length(endP)
]
ifso if isLogic then
[
let nlFileName = vec 30
CopyString(nlFileName,fileNameVec!i)
ChangeExtension(nlFileName,".nl")
let nlFile=OpenFile(nlFileName,ksTypeReadWrite,charItem,verLatest)
alreadyBuilt = nlFile? RepairComment(nlFile,titV),false
]
Resets(s)
WriteBlock(s, base, endP-base)
TruncateDiskStream(s)
@#335=base
Closes(s)
unless (alreadyBuilt %(not isLogic)) do
[
unbuiltNameVec!unbuiltNameCount = fileNameVec!i
unbuiltNameCount = unbuiltNameCount+1
]
]

]

and FindSilFiles() = valof
[
// let silFiles=vec MaxFileNames*fpLookSize
FindFiles(fileNameVec, silFiles, fileNameCount)
for i=0 to fileNameCount-1 do
[
if isLogicFile(fileNameVec!i) do
[
analyzeNameVec!analyzeNameCount = fileNameVec!i
analyzeNameCount = analyzeNameCount+1
]
]
resultis silFiles
]

and isLogicFile(str) = valof
[
let j = 0
for i = 1 to str>>str.length do [ if str>>str.char↑i eq $. then break; j = i ]
if (str>>str.char↑(j) ge $0) & (str>>str.char↑(j) le $9) &
(str>>str.char↑(j-1) ge $0) & (str>>str.char↑(j-1) le $9) then resultis true
resultis false
]

and MakeNewTitle(what, newP, oldP, file, alreadyBuilt,isLogic) be
[
MoveBlock(newP, oldP, Length(oldP))
let oldS=lv oldP>>item.string
let newS=lv newP>>item.string
if what eq 4 then
[
newS>>str.length=0
if file ls 9 then AppendC($0, newS)
//Two digits!!
AppendN(file+1, newS)
let num=true
for i=1 to oldS>>str.length do
[
let c=oldS>>str.char↑i
if num ne 0 & c ge $0 & c le $9 then loop
num=false
AppendC(c, newS)
]
return
]
if what eq 1 then MoveBlock(newS, fileNameVec!file, FileNameWordLength)
if what eq 2 & revStr>>str.length ne 0 then
test isLogic
ifso
[
verifyRevision(newS,oldRevStr,file)
MoveBlock(newS, revStr, FileNameWordLength)
]
ifnot
verifyRevision(newS,revStr,file)
if what eq 3 & alreadyBuilt ne 0 then return
if what eq 3 then GetDateString(newS)
// But preserve capitalization, etc of original.
if StEq(newS, oldS, nil) then MoveBlock(newS, oldS, oldS>>str.length/2+1)
]

and verifyRevision(newS,revision,file) be
[
unless StEq(newS,revision) do
[
let str = vec FileNameWordLength+20
str!0 = 0
AppendS("*n ",str)
AppendS(fileNameVec!file,str)
AppendS(" does not have the correct Revision",str)
ErrorMessage(str)
]
]

and ComFile(nam, ext; numargs na) be
[
if na eq 1 then ext=0
let str=vec FileNameWordLength
MoveBlock(str, (nam? nam,fileNameVec!0), FileNameWordLength)
if ext then ChangeExtension(str, ext)
WSS(remCm, " ")
WSS(remCm, str)
]


and CheckPrevErrors(ext, limit) be
[
let str = vec FileNameWordLength
MoveBlock(str, fileNameVec!0, FileNameWordLength)
ChangeExtension(str, ext)
let file = OpenFile(str, ksTypeReadOnly, charItem)
if file eq 0 then CallSwat("Can not open error file", str)
if file ne 0 then
[
Gets(file)
if ((Gets(file)-$0) gr limit) then
[
Ws(FORMATN("*nEdBuild aborted due to error indicated in <S>", str))
finish
]
Closes(file)
]
]

and RunProg(progName, ext, nameVec, nameCount, AddEarlyParams; numargs na) be
[
DefaultArgs(lv na, 2, fileNameVec, fileNameCount, Noop)
WSS(remCm, progName)
WSS(remCm, glob)
AddEarlyParams()
WSS(remCm, com)
if ext eq -1 then return
for i=0 to nameCount-1 do
[
let p=nameVec!i
Puts(remCm, $*s)
let q=vec FileNameWordLength
MoveBlock(q, p, FileNameWordLength)
if ext then ChangeExtension(q, ext)
WSS(remCm, q)
]
]

and ChangeExtension(str, ext) be
[
let j=0
for i=1 to str>>str.length do [ if str>>str.char↑i eq $. then break; j=i ]
str>>str.length=j
AppendS(ext, str)
]


and ParseTerm(s, v) = valof
[
let reading = false
let intoStr=lv v>>TERM.phrase
Zero(v, (size TERM/16))
until Endofs(s) do
[
let c=Gets(s)
if c eq $*s % c eq $*t % c eq $*n then
[
if reading then resultis true
loop
]
if c eq $/ % c eq $\ then
[
v>>TERM.switchChar=c
intoStr=lv v>>TERM.switchPhrase
loop
]
AppendC(c, intoStr)
reading = true
]
resultis reading
]

and WriteTerm(s, v) be
[
Puts(s, $*s)
WSS(s, lv v>>TERM.phrase)
if v>>TERM.switchChar eq 0 then return
Puts(s, v>>TERM.switchChar)
WSS(s, lv v>>TERM.switchPhrase)
]

and GetDateString(s) be
[
let uv=vec 7
UNPACKDT(0, uv)
@s=0
AppendN(uv!1+1, s)
//Month
AppendC($/, s)
AppendN(uv!2, s)
//Day
AppendC($/, s)
AppendN(uv!0-1900, s)
//Year
]