DIRECTORY Alloc: TYPE USING [Create, Chunkify, Destroy, Failure, Reset, TableInfo], Ascii: TYPE USING [Lower], BasicTime: TYPE USING [GMT, Now, Period, ToNSTime], BcdBindDefs: TYPE USING [RelocHandle], BcdComData: TYPE USING [aborted, bcdName, binderVersion, codeName, commandArgs, copyCode, copySymbols, currentName, debug, errors, errorStream, literals, logStream, nConfigs, nErrors, nExports, nImports, nModules, nPages, nWarnings, objectStamp, op, outputFile, outputFti, rootName, sourceName, sourceStream, sourceVersion, symbolName, table, textIndex, warnings], BcdControlDefs: TYPE USING [BindRoot, BuildSemanticEntries, LoadRoot, WriteBcd, PrintBcd, PrintRelocations, PrintSemanticEntries, PrintTree], BcdDefs: TYPE USING [BinderNTables, httype, MTNull, NullName, sstype, treetype, VersionStamp], BcdErrorDefs: TYPE USING [Finalize, GetModule, GetSti, Initialize], BcdFileDefs: TYPE USING [BuildFileTable, EraseFileTable], BcdLiterals: TYPE USING [Create, Finalize, SealLiterals], BcdParseData: TYPE, BcdUtilDefs: TYPE USING [EnterFile, Init, Reset], Commander: TYPE USING [Handle, Register], CommandUtil: TYPE USING [Echo, Failed, GetNthPair, ListLength, PairList, Parse, SetExtension], DebuggerSwap: TYPE USING [CallDebugger], FileViewerOps: TYPE USING [WaitUntilSaved, ShowLog], FS: TYPE USING [Close, Create, Delete, Error, ExpandName, nullOpenFile, Open, OpenFile, StreamFromOpenFile, FileInfo], HashOps: TYPE USING [Finalize, Initialize], IO: TYPE USING [char, Close, CreateStream, CreateStreamProcs, int, Put, PutChar, PutF, PutRope, rope, SetLength, STREAM, StreamProcs, time, RIS], Loader: TYPE USING [BCDBuildTime], OSMiscOps: TYPE USING [MergeStamps, TimeToStamp], P1: TYPE USING [InstallParseTable, Parse], PrincOpsUtils: TYPE USING [Codebase], Process: TYPE USING [CheckForAbort], Rope: TYPE USING [Equal, Fetch, Find, Flatten, Length, ROPE, Substr, Cat], Symbols: TYPE USING [stNull], Tree: TYPE USING [Link], TreeOps: TYPE USING [PopTree, Finalize, Initialize], UserProfile: TYPE USING [Token, Boolean]; BcdControl: PROGRAM IMPORTS Alloc, Ascii, BasicTime, BcdControlDefs, BcdErrorDefs, BcdFileDefs, BcdLiterals, BcdParseData, BcdUtilDefs, Commander, CommandUtil, DebuggerSwap, FileViewerOps, FS, HashOps, IO, Loader, OSMiscOps, P1, PrincOpsUtils, Process, Rope, TreeOps, UserProfile, data: BcdComData = BEGIN EquivalentRope: PROC[s1, s2: Rope.ROPE] RETURNS[BOOL] ~ { RETURN[s1.Equal[s2, FALSE]]}; log: IO.STREAM _ NIL; logFile: FS.OpenFile _ FS.nullOpenFile; SetLogStream: PROC ~ { logFile _ FS.Create["Binder.Log"]; log _ FS.StreamFromOpenFile[logFile, $write]; log.SetLength[0]}; LogRope: PROC[s: Rope.ROPE] ~ {log.PutRope[s]}; LogChar: PROC[c: CHAR] ~ {log.PutChar[c]}; LogNumber: PROC[n: INTEGER] ~ {log.Put[IO.int[n]]}; renamedOutput: BOOL _ FALSE; RepeatCommand: PROC[s: IO.STREAM] ~ { s.PutRope["\nBinding "]; s.PutRope[data.sourceName]; IF renamedOutput THEN {s.PutRope[", BCD to "]; s.PutRope[data.bcdName]}; IF data.copyCode THEN { s.PutRope[", code to "]; s.PutRope[IF data.codeName = NIL THEN "BCD" ELSE data.codeName]}; IF data.copySymbols THEN { s.PutRope[", symbols to "]; s.PutRope[IF data.symbolName = NIL THEN "BCD" ELSE data.symbolName]}; s.PutChar['\n]}; errorName: Rope.ROPE _ NIL; errorFile: FS.OpenFile _ FS.nullOpenFile; errorStream: IO.STREAM _ NIL; errorStreamProcs: REF IO.StreamProcs _ NIL; SetErrorName: PROC ~ { IF errorName = NIL THEN { errorName _ CommandUtil.SetExtension[data.rootName, "errlog"]} }; DummyErrorStream: PROC[ putProc: SAFE PROC[self: IO.STREAM, char: CHAR]] RETURNS[IO.STREAM] ~ { IF errorStreamProcs = NIL THEN errorStreamProcs _ IO.CreateStreamProcs[ variety: $output, class: $DummyErrorStream, putChar: putProc ]; RETURN[IO.CreateStream[errorStreamProcs, NIL]]}; OpenErrorStream: PROC ~ { IF errorName = NIL THEN SetErrorName[]; IF errorFile = FS.nullOpenFile THEN errorFile _ FS.Create[errorName]; errorStream _ FS.StreamFromOpenFile[errorFile, $write]; errorStream.SetLength[0]; WriteHerald[errorStream, errorName]; RepeatCommand[errorStream]}; CloseErrorStream: PROC ~ INLINE {IF data.errorStream # NIL THEN ErrorDestroy[]}; ErrorPut: SAFE PROC[self: IO.STREAM, char: CHAR] ~ TRUSTED { IF errorStream = NIL THEN OpenErrorStream[]; errorStream.PutChar[char]}; ErrorDestroy: PROC ~ { IF errorFile # FS.nullOpenFile AND errorStream # NIL THEN { errorStream.Close[]; errorStream _ NIL} }; WriteHerald: PROC[stream: IO.STREAM, id: Rope.ROPE] ~ { stream.Put[IO.rope["Cedar 6.0 Binder of "], IO.time[Loader.BCDBuildTime[]]]; IF id.Length[] # 0 THEN stream.Put[IO.rope[id], IO.rope[" -- "]]; stream.Put[IO.time[], IO.char['\n]]}; Logger: PROC[proc: PROC[log: IO.STREAM]] = { proc[data.errorStream]}; sourceFile, bcdFile: FS.OpenFile _ FS.nullOpenFile; GetRoot: PROC[s: Rope.ROPE] RETURNS[Rope.ROPE] ~ { dotIndex: INT _ Rope.Find[s, "."]; IF dotIndex > -1 THEN s _ Rope.Substr[s, 0, dotIndex]; RETURN[s]}; StandardDefaults: PACKED ARRAY CHAR ['a..'z] OF BOOL ~ [ FALSE, -- A Copy all (code and symbols) FALSE, -- B Unused TRUE , -- C Copy code FALSE, -- D Call debugger error FALSE, -- E Unused FALSE, -- F Unused TRUE , -- G TRUE => errlog goes to binder.log, FALSE => use root.errlog FALSE, -- H Unused FALSE, -- I Unused FALSE, -- J Unused FALSE, -- K Unused FALSE, -- L Unused FALSE, -- M Unused FALSE, -- N Unused FALSE, -- O Unused FALSE, -- P Pause after config with errors FALSE, -- Q Unused FALSE, -- R Unused FALSE, -- S Copy symbols FALSE, -- T Unused FALSE, -- U Unused FALSE, -- V Unused FALSE, -- W Pause after config with warnings FALSE, -- X Copy compressed symbols (not implemented) FALSE, -- Y Unused FALSE -- Z Unused ]; Bind: SAFE PROC[cmd: Commander.Handle] RETURNS[result: REF _ NIL, msg: Rope.ROPE _ NIL] ~ TRUSTED { results: CommandUtil.PairList; switches: Rope.ROPE; key, value: Rope.ROPE; anyErrors, anyWarnings: BOOL _ FALSE; localPause: BOOL; cmdStream: IO.STREAM; defaultSwitches: PACKED ARRAY CHAR['a..'z] OF BOOL _ StandardDefaults; defaultDebugPass: CARDINAL _ CARDINAL.LAST; localSwitches: PACKED ARRAY CHAR['a..'z] OF BOOL; debugPass: CARDINAL; cmd.commandLine _ Rope.Cat[UserProfile.Token["Binder.Switches"], " ", cmd.commandLine]; cmdStream _ IO.RIS[cmd.commandLine]; data.sourceName _ data.bcdName _ data.codeName _ data.symbolName _ NIL; SetLogStream[]; WriteHerald[log, NIL]; data.op _ $bind; data.table _ NIL; DO { Initialize: PROC ~ { weights: ARRAY [0..BcdDefs.BinderNTables) OF Alloc.TableInfo _ [ -- empirical (SDD) [4], [2], [10], [4], [5], [4], [4], [4], [2], [1], [4], [4], [4], [2], [4], [2], [4], [5], [1], [1]]; RepeatCommand[log]; data.errors _ data.warnings _ data.aborted _ FALSE; data.nErrors _ data.nWarnings _ 0; data.textIndex _ 0; data.currentName _ BcdDefs.NullName; IF data.table = NIL THEN { data.table _ Alloc.Create[weights~DESCRIPTOR[weights]]; (data.table).Chunkify[BcdDefs.treetype]} ELSE (data.table).Reset[]; HashOps.Initialize[data.table, BcdDefs.httype, BcdDefs.sstype]; TreeOps.Initialize[data.table]; BcdUtilDefs.Init[data.table]; data.literals _ BcdLiterals.Create[]; BcdErrorDefs.Initialize[]; errorStream _ NIL}; Finalize: PROC ~ { TreeOps.Finalize[]; HashOps.Finalize[]; BcdErrorDefs.Finalize[]; (data.literals).Finalize[]; BcdUtilDefs.Reset[]; (data.table).Reset[]; anyErrors _ data.errors OR anyErrors; anyWarnings _ data.warnings OR anyWarnings; IF data.aborted THEN LogRope["Binding aborted\n"] ELSE IF data.errors THEN LogRope["Errors detected; BCD not written\n"] ELSE { IF data.nConfigs > 1 THEN { LogNumber[data.nConfigs]; LogRope[" configs, "]}; LogNumber[data.nModules]; LogRope[" modules, "]; LogNumber[data.nImports]; LogRope[" imports, "]; LogNumber[data.nExports]; LogRope[" exports, "]; LogNumber[data.nPages]; LogRope[" pages, "]; LogNumber[BasicTime.Period[from: startTime, to: BasicTime.Now[]]]; LogRope[" seconds\n"]}; IF errorStream # NIL THEN { LogRope["See "]; LogRope[data.rootName]; LogRope[".errlog\n"]}; IF log # data.errorStream THEN CloseErrorStream[]; IF errorName = NIL THEN { SetErrorName[]; }; (data.sourceStream).Close[]; sourceFile _ FSClose[sourceFile]; bcdFile _ FSClose[bcdFile]; IF data.nErrors # 0 OR data.aborted THEN FS.Delete[data.bcdName ! FS.Error => TRUSTED {CONTINUE}]; data.outputFile _ FS.nullOpenFile; IF data.nErrors = 0 THEN cmd.out.Put[IO.rope["no errors"]] ELSE cmd.out.Put[IO.int[data.nErrors], IO.rope[" errors"]]; IF data.nWarnings # 0 THEN cmd.out.Put[IO.rope[", "], IO.int[data.nWarnings], IO.rope[" warnings"]]; cmd.out.Put[IO.char['\n]]; data.sourceName _ data.bcdName _ data.codeName _ data.symbolName _ NIL; errorName _ NIL}; Debug: PROC[printRel, printBcd: BOOL] ~ { BcdControlDefs.PrintTree[root]; BcdControlDefs.PrintSemanticEntries[]; IF printRel THEN BcdControlDefs.PrintRelocations[relocationHead]; IF printBcd THEN BcdControlDefs.PrintBcd[]}; parsed: BOOL; root: Tree.Link; first: BOOL _ TRUE; relocationHead: BcdBindDefs.RelocHandle; startTime: BasicTime.GMT; needFileTableErase: BOOL; localSwitches _ defaultSwitches; localPause _ FALSE; debugPass _ defaultDebugPass; renamedOutput _ FALSE; data.aborted _ FALSE; [data.sourceName, data.commandArgs, results, switches] _ CommandUtil.Parse[s: cmdStream ! CommandUtil.Failed => {GOTO badSyntax}]; IF data.sourceName = NIL AND switches = NIL THEN EXIT; -- done binding LogRope["\nCommand: "]; CommandUtil.Echo[ d~log, operator~data.sourceName, argList~data.commandArgs, resultList~results, switches~switches]; IF data.sourceName = NIL THEN GOTO globalSwitches; FOR n: CARDINAL IN [0..CommandUtil.ListLength[results]) DO [key, value] _ CommandUtil.GetNthPair[list~results, n~n]; SELECT TRUE FROM (key = NIL), EquivalentRope[key, "bcd"] => { data.bcdName _ value; renamedOutput _ TRUE}; EquivalentRope[key, "code"] => { data.codeName _ value; localSwitches['c] _ TRUE}; EquivalentRope[key, "symbols"] => { data.symbolName _ value; localSwitches['s] _ TRUE}; ENDCASE => GO TO badSemantics; ENDLOOP; data.rootName _ GetRoot[ (IF data.bcdName # NIL THEN data.bcdName ELSE data.sourceName)]; IF switches # NIL THEN { sense: BOOL _ TRUE; length: INT _ switches.Length[]; FOR i: INT IN [0..length) DO c: CHAR ~ switches.Fetch[i]; SELECT c FROM '-, '~ => sense _ ~sense; IN ['a..'z] => {localSwitches[c] _ sense; sense _ TRUE}; IN ['A..'Z] => {localSwitches[Ascii.Lower[c]] _ sense; sense _ TRUE}; '! => {DebuggerSwap.CallDebugger[NIL]; sense _ TRUE}; IN ['1..'4] => {debugPass _ c-'0; sense _ TRUE}; ENDCASE; ENDLOOP; }; data.sourceName _ CommandUtil.SetExtension[data.sourceName, "config"]; FileViewerOps.WaitUntilSaved[data.sourceName, cmd.out ! ABORTED => {data.aborted _ TRUE; EXIT}]; IF data.bcdName = NIL THEN data.bcdName _ data.rootName; data.bcdName _ CommandUtil.SetExtension[data.bcdName, "bcd"]; data.copyCode _ (localSwitches['c] OR localSwitches['a]); data.copySymbols _ (localSwitches['s] OR localSwitches['x] OR localSwitches['a]); IF localSwitches['x] THEN LogRope["\nSymbol compression not available in this version"]; IF data.copyCode AND data.codeName # NIL THEN { data.codeName _ CommandUtil.SetExtension[data.codeName, "code"]; IF EquivalentRope[data.codeName, data.bcdName] THEN data.codeName _ NIL; }; IF data.copySymbols AND ~(localSwitches['a] AND data.symbolName = NIL) THEN { data.symbolName _ CommandUtil.SetExtension[data.symbolName, "symbols"]; IF EquivalentRope[data.symbolName, data.bcdName] THEN data.symbolName _ NIL; }; cmd.out.Put[IO.rope["Binding: "], IO.rope[data.rootName]]; FOR c: CHAR IN ['a..'z] DO IF localSwitches[c] # StandardDefaults[c] THEN { IF first THEN {first _ FALSE; cmd.out.PutChar['/]}; IF StandardDefaults[c] THEN cmd.out.PutChar['-]; cmd.out.PutChar[c]}; ENDLOOP; startTime _ BasicTime.Now[]; sourceFile _ FS.nullOpenFile; errorFile _ data.outputFile _ FS.nullOpenFile; data.sourceStream _ NIL; sourceFile _ FS.Open[data.sourceName ! FS.Error => TRUSTED {CONTINUE}]; IF sourceFile # NIL THEN { data.sourceStream _ FS.StreamFromOpenFile[sourceFile]; data.sourceVersion _ BcdDefs.VersionStamp[ net~0, host~0, time~BasicTime.ToNSTime[FS.FileInfo[data.sourceName].created]]; }; IF data.sourceStream = NIL THEN GOTO noSource; data.outputFile _ bcdFile _ FS.Create[data.bcdName ! FS.Error => TRUSTED {CONTINUE}]; data.logStream _ log; data.errorStream _ IF localSwitches['g] THEN log ELSE DummyErrorStream[putProc~ErrorPut]; localPause _ localSwitches['p]; data.debug _ localSwitches['d]; localSwitches['g] _ localSwitches['p] _ localSwitches['d] _ FALSE; data.objectStamp _ OSMiscOps.TimeToStamp[data.sourceVersion]; data.objectStamp _ OSMiscOps.MergeStamps[ data.objectStamp, OSMiscOps.TimeToStamp[[0, 0, LOOPHOLE[localSwitches]]]]; data.objectStamp _ OSMiscOps.MergeStamps[ data.objectStamp, OSMiscOps.TimeToStamp[data.binderVersion]]; Initialize[]; BEGIN ENABLE { BcdErrorDefs.GetModule => RESUME [BcdDefs.MTNull, 0]; BcdErrorDefs.GetSti => RESUME [Symbols.stNull]; Alloc.Failure => { data.errors _ TRUE; IF ~data.debug THEN { LogRope["Storage Overflow\n"]; GOTO Overflow}}; UNWIND => {IF needFileTableErase THEN BcdFileDefs.EraseFileTable[]; Finalize[]}; }; needFileTableErase _ FALSE; Process.CheckForAbort[]; cmd.out.PutRope[". "]; -- pass 1 [complete~parsed, nErrors~data.nErrors] _ P1.Parse[data.sourceStream, Logger, TRUE]; IF ~parsed THEN GO TO Failed; IF data.nErrors > 0 THEN data.errors _ TRUE; root _ TreeOps.PopTree[]; BcdControlDefs.BuildSemanticEntries[root]; data.outputFti _ BcdUtilDefs.EnterFile[LOOPHOLE[Rope.Flatten[data.bcdName]]]; BcdFileDefs.BuildFileTable[data.table]; needFileTableErase _ TRUE; IF debugPass <= 1 THEN Debug[printRel~FALSE, printBcd~FALSE]; Process.CheckForAbort[]; cmd.out.PutRope[". "]; -- pass 2 relocationHead _ BcdControlDefs.LoadRoot[root]; (data.literals).SealLiterals[]; IF debugPass <= 2 THEN Debug[printRel~TRUE, printBcd~TRUE]; Process.CheckForAbort[]; cmd.out.PutRope[". "]; -- pass 3 BcdControlDefs.BindRoot[relocationHead]; IF debugPass <= 3 THEN Debug[printRel~FALSE, printBcd~TRUE]; IF ~data.errors THEN { Process.CheckForAbort[]; cmd.out.PutRope[". "]; -- pass 4 BcdControlDefs.WriteBcd[root]}; BcdFileDefs.EraseFileTable[]; EXITS Overflow => NULL; Failed => data.errors _ TRUE; END; Finalize[]; EXITS noSource => { LogRope["\nCan't open "]; LogRope[data.sourceName]; LogChar['\n]; IO.PutF[cmd.out, " -- can't open %g\n", [rope[data.sourceName]] ]; data.errors _ anyErrors _ TRUE}; globalSwitches => { sense: BOOL _ TRUE; length: INT _ switches.Length[]; FOR i: INT IN [0..length) DO c: CHAR ~ switches.Fetch[i]; SELECT c FROM '-, '~ => sense _ ~sense; '! => DebuggerSwap.CallDebugger[NIL]; IN ['a..'z] => {defaultSwitches[c] _ sense; sense _ TRUE}; IN ['A..'Z] => {defaultSwitches[Ascii.Lower[c]] _ sense; sense _ TRUE}; IN ['1..'5] => {defaultDebugPass _ c-'0; sense _ TRUE}; ENDCASE => EXIT; ENDLOOP}; badSemantics => { data.errors _ anyErrors _ TRUE; LogRope["\n -- Illegal command"]}; }; IF data.aborted THEN EXIT; -- stop binding IF (data.errors OR (data.warnings AND localSwitches['w])) AND localPause THEN EXIT; REPEAT badSyntax => {anyErrors _ data.errors _ TRUE; LogRope["-- Illegal syntax"]}; ENDLOOP; IF data.table # NIL THEN {Alloc.Destroy[data.table]; data.table _ NIL}; IO.Close[log]; logFile _ FS.nullOpenFile; cmd.out.PutRope["End of binding\n"]; IF data.aborted OR anyErrors OR anyWarnings THEN result _ $Failure; FileViewerOps.ShowLog[fileName: FS.ExpandName["Binder.log"].fullFName, destroyIt: result # $Failure, createIconic: UserProfile.Boolean["Compiler.IconicLogs", FALSE], blinkIfIconic: UserProfile.Boolean["Compiler.IconicLogs", FALSE]]; }; FSClose: PROC[fh: FS.OpenFile] RETURNS[FS.OpenFile] = { IF fh # FS.nullOpenFile THEN FS.Close[fh ! FS.Error => IF error.code = $invalidOpenFile THEN CONTINUE]; RETURN[FS.nullOpenFile]}; Init: PROC ~ { START data; data.binderVersion _ [net~0Ch, host~0Bh, time~000F0003h]; -- Cedar release P1.InstallParseTable[LOOPHOLE[PrincOpsUtils.Codebase[LOOPHOLE[BcdParseData]]]]; Commander.Register["Binder", Bind, "Bind a list of configurations."]}; Init[]; END. ²BcdControl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Satterthwaite on March 4, 1986 2:29:37 pm PST Maxwell, August 29, 1983 2:52 pm Russ Atkinson, March 7, 1985 1:02:15 am PST Paul Rovner, January 11, 1984 4:19 pm Rick Beach, April 3, 1985 11:38:18 am PST Command Gathering And Logging Error Logging IF fbh = NIL AND feedback.create # NIL THEN fbh _ feedback.create[system~"Binder"L, herald~herald]; File Bookkeeping Switches Command interface main loop OSMiscOps.DeleteFile[errorName]; IF feedback.finishItem # NIL THEN ... encode switches, binder version (see BcdLoad processing also) Global binder initialization data.binderVersion _ OSMiscOps.ImageId[]; Κ3˜codešœ™Kšœ Οmœ1™—˜K˜——š œžœ˜Kšœ žœžœžœžœžœžœžœžœ˜Gšžœžœžœ˜šœžœ˜(Kšœ˜Kšœ˜Kšœ˜Kšœ˜——Kšžœžœ žœ˜0K˜—š œžœ˜Kšžœ žœžœ˜'Kšžœ žœžœ žœ˜EKšœ7˜7Kšœ˜K˜BK˜—Kš  œžœžœžœžœžœ˜PK˜š œžœžœžœžœžœžœ˜˜>—šžœžœžœžœ˜/Kšœ@˜@Kšžœ-žœž˜HKšœ˜—š žœžœžœžœžœ˜MKšœG˜GKšžœ/žœž˜LKšœ˜—K˜Kšœ žœžœ˜:šžœžœžœ ž˜šžœ(žœ˜0Kšžœžœ žœ˜3Kšžœžœ˜0Kšœ˜—Kšžœ˜K˜—K˜K˜Kšœ žœ˜Kšœžœ˜.Kšœžœ˜Kš œ žœžœ žœžœ˜Gšžœžœžœ˜Kšœ6˜6˜*Kšœ'žœ%˜N—Kšœ˜—Kšžœžœžœžœ ˜.Kš œžœžœ žœžœ˜UK˜K˜˜Kšžœžœžœ$˜F—K˜K˜Kšœ<žœ˜BK˜˜=Kšœ=™=˜)Kšœ/žœ˜J—˜)K˜=K˜——˜ K˜—šž˜šžœ˜Kšœžœ˜5Kšœžœ˜/˜Kšœžœ˜šžœ žœ˜Kšœžœ ˜/——Kšžœžœžœ+˜PKšœ˜K˜—Kšœžœ˜Kšœ˜Kšœ‘ ˜ KšœNžœ˜TKšžœ žœžœžœ˜Kšžœžœžœ˜,K˜K˜*K˜Kšœ'žœ˜MK˜'K˜Kšœžœ˜šžœžœžœ žœ˜=K˜—Kšœ˜Kšœ‘ ˜ K˜/˜K˜—šžœžœžœ žœ˜;K˜—Kšœ˜Kšœ‘ ˜ K˜(K˜šžœžœžœ žœ˜rTW