-- CrossPackControl.mesa
-- Last edited by Lewis on 29-Mar-82 16:44:44
-- Last edited by Satterthwaite, January 12, 1983 12:12 pm
DIRECTORY
Alloc: TYPE USING [
Chunkify, Create, defaultChunkType, Destroy, Failure, Overflow, Reset,
TableInfo],
BcdDefs: TYPE USING [VersionStamp],
CharIO: TYPE USING [PutChar, PutDecimal, PutLine, PutString],
CIFS: TYPE USING [OpenFile, Close, Error, GetFC, Open, create, read, write],
CodePackProcs: TYPE USING [Determine, Destroy],
CommandUtil: TYPE USING [
CommandObject, CopyString, Failed, FreePairList, FreeString, GetNthPair,
ListLength, PairList, Parse, SetExtension],
ConvertUnsafe: TYPE USING [ToRope],
Exec: TYPE USING [AddCommand, commandLine],
ExecOps: TYPE USING [CheckForAbort, Command, Outcome],
FileStream: TYPE USING [Create, GetLeaderProperties, SetLength],
HashOps: TYPE USING [Initialize, Finalize],
Heap: TYPE USING [Create, Delete, FreeNode, MakeNode],
Inline: TYPE USING [BITXOR, HighByte, LowByte, LowHalf],
ModuleSymbols: TYPE USING [Initialize, Finalize],
PackagerDefs: TYPE USING [
nullSourceIndex, GlobalData, GlobalDataRecord, packagerNTables,
packhttype, packsstype],
PackCode: TYPE USING [
ComputeCodePlacement, Finalize, PackError, WriteBcdToFile,
WriteCodeToBcdFile],
PackDebug: TYPE USING [
Initialize, Finalize, PrintConfigTree, PrintSourceBcd, PrintTree,
PrintProcessingOrder],
PackParseData: TYPE,
P1: TYPE USING [InstallParseTable, Parse],
ProcessingOrder: TYPE USING [Determine, Destroy],
ProcessorFace: TYPE USING [processorID],
PackList : TYPE USING [Print],
Rope: TYPE USING [ROPE, Fetch, Length],
Runtime: TYPE USING [GetBcdTime, GetTableBase],
SemanticEntry: TYPE USING [BuildSemanticEntries],
SourceBcd: TYPE USING [
BuildConfigTree, CTreeIndex, DestroyConfigTree, nullCTreeIndex,
Load, Unload, BadSourceBcd, moduleCount],
Stream: TYPE USING [
Delete, DeleteProcedure, Handle, Object, PutBlock, PutByteProcedure, PutByte,
PutProcedure],
Strings: TYPE USING [
AppendChar, AppendString, EquivalentSubString, String, SubStringDescriptor],
Time: TYPE USING [Append, AppendCurrent, Current, Unpack],
TreeOps: TYPE USING [Initialize, Finalize, PopTree];
PackControl: MONITOR
IMPORTS
Alloc, CharIO, CIFS, CodePackProcs, CommandUtil, ConvertUnsafe, Exec, ExecOps,
FileStream, HashOps, Heap, Inline, ModuleSymbols, PackCode, PackDebug,
PackParseData, P1, ProcessingOrder, ProcessorFace, PackList, Rope, Runtime,
SemanticEntry, SourceBcd, Stream, Strings, Time, TreeOps
EXPORTS PackagerDefs
SHARES ProcessorFace = {
-- utilities
EquivalentString: PROC [s1, s2: Strings.String] RETURNS [BOOL] ~ {
ssd1: Strings.SubStringDescriptor ← [base~s1, offset~0, length~s1.length];
ssd2: Strings.SubStringDescriptor ← [base~s2, offset~0, length~s2.length];
RETURN [Strings.EquivalentSubString[@ssd1, @ssd2]]};
GetFile: PROC [name: Strings.String, access: {read, write}] RETURNS [CIFS.OpenFile] ~ {
RETURN [CIFS.Open[
ConvertUnsafe.ToRope[name],
IF access=$read THEN CIFS.read ELSE CIFS.create+CIFS.write]]};
GetNetAndHost: PROC RETURNS [net, host: CARDINAL] ~ {
sum: UNSPECIFIED ~ Inline.BITXOR[
ProcessorFace.processorID.a, Inline.BITXOR[
ProcessorFace.processorID.b, ProcessorFace.processorID.c]];
net ← LOOPHOLE[Inline.HighByte[sum]];
host ← LOOPHOLE[Inline.LowByte[sum]]};
-- Packager log
logFile: CIFS.OpenFile;
log: Stream.Handle ← NIL;
OpenLogStream: PROC ~ INLINE {
logFile ← GetFile["/local/Packager.log"L, $write];
log ← FileStream.Create[logFile.GetFC];
FileStream.SetLength[log, 0]};
CloseLogStream: PROC ~ INLINE {
Stream.Delete[log]; CIFS.Close[logFile]; logFile ← NIL};
LogString: PROC [s: Strings.String] ~ {CharIO.PutString[log, s]};
LogRope: PROC [r: Rope.ROPE] ~ {
FOR i: INT IN [0..r.Length) DO CharIO.PutChar[log, r.Fetch[i]] ENDLOOP};
LogLine: PROC [s: Strings.String] ~ {LogString[s]; LogChar['\n]};
LogChar: PROC [c: CHAR] ~ {CharIO.PutChar[log, c]};
LogDecimal: PROC [n: CARDINAL] ~ {CharIO.PutDecimal[log, n]};
-- Command gathering/echoing
args, results: CommandUtil.PairList;
switches: Strings.String;
globalPause, localPause, listPacks: BOOL;
debugPass: CARDINAL;
WriteHerald: PROC [s: Stream.Handle, id: Strings.String←NIL] ~ {
OPEN Time, CharIO;
herald: STRING ← [80];
Strings.AppendString[herald, "Cedar Trinity Cross Packager of "L];
Time.Append[herald, Time.Unpack[[gd.packagerVersion.time]]];
herald.length ← herald.length-3;
PutString[s, herald]; PutChar[s, '\n];
IF id # NIL THEN {PutString[s, id]; PutString[s, " -- "L]};
herald.length ← 0; Time.AppendCurrent[herald]; PutLine[s, herald]};
RepeatCommand: PROC [s: Stream.Handle] ~ {
OPEN CharIO;
PutString[s, "\nPackaging "L];
PutString[s, gd.sourceBcdName];
PutString[s, " according to "L];
PutString[s, gd.packName];
PutString[s, "\nOutput to "L];
PutString[s, gd.outputBcdName];
PutChar[s, '\n];
IF listPacks THEN {
PutString[s, "Code and frame pack listing to "L];
PutString[s, gd.packListFileName]; PutChar[s, '\n]};
IF gd.printMap THEN {
PutString[s, "Code and frame pack map to "L];
PutString[s, gd.mapFileName]; PutChar[s, '\n]};
PutChar[s, '\n]};
-- Error logging
errorFile: CIFS.OpenFile ← NIL;
errorStream: Stream.Handle ← NIL;
errorStreamObject: Stream.Object;
OpenErrorStream: PROC ~ {
errorName: Strings.String ← CommandUtil.CopyString[
gd.rootName, 1+("errlog"L).length];
errorName ← CommandUtil.SetExtension[errorName, "errlog"L];
errorFile ← GetFile[errorName, $write];
errorStream ← FileStream.Create[errorFile.GetFC];
FileStream.SetLength[errorStream, 0];
WriteHerald[errorStream, errorName];
RepeatCommand[errorStream];
errorName ← CommandUtil.FreeString[errorName]};
CloseErrorStream: PROC ~ {
IF errorStream # NIL THEN {errorStream.Delete[]; errorStream ← NIL};
IF errorFile # NIL THEN {CIFS.Close[errorFile]; errorFile ← NIL}};
ErrorPut: Stream.PutByteProcedure ~ {
IF errorStream = NIL THEN OpenErrorStream[];
errorStream.PutByte[byte]};
ErrorPutBlock: Stream.PutProcedure
--[sH: Handle, block: Block, endPhysicalRecord: BOOL]-- ~ {
IF errorStream = NIL THEN OpenErrorStream[];
errorStream.PutBlock[block, endPhysicalRecord]};
ErrorDestroy: Stream.DeleteProcedure --[sH: Stream.Handle]-- ~ {
CloseErrorStream[]};
Logger: PROC [proc: PROC [log: Stream.Handle]] = {
proc[gd.errorStream]};
SetRoot: PROC [root, s: Strings.String] ~ {
root.length ← 0;
FOR i: CARDINAL IN [0..s.length) DO
IF s[i] = '. THEN EXIT;
Strings.AppendChar[root, s[i]];
ENDLOOP};
SetFileName: PROC [fileName, extension: Strings.String] RETURNS [Strings.String] ~ {
root: Strings.String ~
(IF fileName = NIL THEN
CommandUtil.CopyString[gd.rootName, 1+extension.length]
ELSE fileName);
RETURN [CommandUtil.SetExtension[root, extension]]};
TimeSince: PROC [start: LONG CARDINAL] RETURNS [elapsedTime: LONG CARDINAL] ~ {
RETURN [Time.Current[] - start]};
-- #### THIS MAIN PROCEDURE IS CALLED TO DO PACKAGING ####
globalData: PUBLIC PackagerDefs.GlobalData ← @gd;
gd: PackagerDefs.GlobalDataRecord; -- local copy of globalData
DoPackaging: ENTRY PROC [cmd: ExecOps.Command] RETURNS [ExecOps.Outcome] ~ {
ENABLE {
CIFS.Error => TRUSTED {
-- name: Strings.String ← "unknown";
-- LogString["Problem in accessing file: "L];
-- LogLine[name];
LogRope[error]; LogChar['\n];
GOTO FileProblem};
UNWIND => {NULL}};
RETURN [DoPackagingInternal[cmd]];
EXITS
FileProblem => RETURN [$errors];
};
DoPackagingInternal: PROC [cmd: ExecOps.Command] RETURNS [ExecOps.Outcome] ~ {
theCommand: CommandUtil.CommandObject ← [pos~0, len~0, data~cmd];
key, value: Strings.String;
abortRequested: BOOL ← FALSE;
globalErrors, globalWarnings: BOOL ← FALSE;
parsed, aborted: BOOL;
packagerStartTime: LONG CARDINAL;
Initialize: PROC ~ {
IF gd.ownTable = NIL THEN {
weights: ARRAY [0..PackagerDefs.packagerNTables) OF Alloc.TableInfo ← [
[16, FALSE[32]], [2, FALSE[8]], [4, FALSE[12]], [1, FALSE[1]],
[2, FALSE[8]], [1, FALSE[1]], [4, FALSE[8]], [1, FALSE[2]],
[4, FALSE[12]], [1, FALSE[1]], [1, FALSE[1]], [1, FALSE[1]],
[1, FALSE[1]], [1, FALSE[1]], [1, FALSE[1]], [1, FALSE[1]],
[1, FALSE[1]], [12, FALSE[24]], [1, FALSE[1]], [1, FALSE[1]],
[8, FALSE[12]], [12, FALSE[24]], [12, FALSE[24]], [4, FALSE[8]],
[4, FALSE[8]], [12, FALSE[24]]];
gd.ownTable ← Alloc.Create[weights~DESCRIPTOR[weights]];
(gd.ownTable).Chunkify[table~Alloc.defaultChunkType]}
ELSE (gd.ownTable).Reset[];
IF gd.debug THEN PackDebug.Initialize[];
TreeOps.Initialize[gd.ownTable, gd.zone];
HashOps.Initialize[gd.ownTable, PackagerDefs.packhttype, PackagerDefs.packsstype];
gd.errors ← gd.warnings ← aborted ← FALSE;
gd.nErrors ← gd.nWarnings ← 0;
gd.textIndex ← PackagerDefs.nullSourceIndex};
Finalize: PROC ~ {
HashOps.Finalize[];
TreeOps.Finalize[];
IF gd.debug THEN PackDebug.Finalize[];
IF abortRequested THEN LogLine["Packaging aborted"L]
ELSE IF gd.errors THEN LogLine["Errors detected; Bcd not written"L]
ELSE {
LogDecimal[Inline.LowHalf[TimeSince[packagerStartTime]]];
LogLine[" seconds"L]};
IF errorStream # NIL THEN {
LogString["See "L]; LogString[gd.rootName]; LogLine[".errlog"L]};
CloseErrorStream[];
(gd.ownTable).Reset[]};
packFile, packListFile, mapFile: CIFS.OpenFile ← NIL;
OpenFiles: PROC ~ {
packFile ← GetFile[gd.packName, $read];
gd.sourceBcdFile ← GetFile[gd.sourceBcdName, $read];
gd.outputBcdFile ← GetFile[gd.outputBcdName, $write];
IF listPacks THEN packListFile ← GetFile[gd.packListFileName, $write];
IF gd.printMap THEN mapFile ← GetFile[gd.mapFileName, $write]};
CloseFiles: PROC ~ {
IF gd.packStream # NIL THEN gd.packStream.Delete[];
IF packFile # NIL THEN {CIFS.Close[packFile]; packFile ← NIL};
IF gd.packListStream # NIL THEN gd.packListStream.Delete[];
IF packListFile # NIL THEN {CIFS.Close[packListFile]; packListFile ← NIL};
IF gd.mapStream # NIL THEN gd.mapStream.Delete[];
IF mapFile # NIL THEN {CIFS.Close[mapFile]; mapFile ← NIL};
IF gd.outputBcdFile # NIL THEN {
IF gd.nErrors # 0 THEN {
-- MFile.SetAccess[
-- gd.outputBcdFile, delete ! MFile.Error => GOTO cantDelete];
-- MFile.Delete[gd.outputBcdFile ! MFile.Error => CONTINUE];
GOTO cantDelete
EXITS cantDelete => NULL}
ELSE CIFS.Close[gd.outputBcdFile];
gd.outputBcdFile ← NIL};
IF gd.sourceBcdFile # NIL THEN {
CIFS.Close[gd.sourceBcdFile];
gd.sourceBcdFile ← NIL}};
IF cmd = NIL THEN ERROR;
WHILE theCommand.data[theCommand.len] # '\n DO
theCommand.len ← theCommand.len + 1;
ENDLOOP;
gd.zone ← NIL; gd.ownTable ← NIL;
globalPause ← TRUE;
listPacks ← FALSE;
gd.packagerVersion.time ← Runtime.GetBcdTime[];
gd.packagerVersion.net ← gd.packagerVersion.host ← 0;
[gd.network, gd.host] ← GetNetAndHost[];
BEGIN
ENABLE {
UNWIND => {
IF gd.ownTable # NIL THEN {
Alloc.Destroy[gd.ownTable]; gd.ownTable ← NIL};
IF gd.zone # NIL THEN {Heap.Delete[gd.zone]; gd.zone ← NIL};
CloseFiles[]};
Alloc.Overflow => {RESUME [8]}};
OpenLogStream[];
WriteHerald[log];
DO -- until no more Packager commands
BEGIN
configTreeRoot: SourceBcd.CTreeIndex ← SourceBcd.nullCTreeIndex;
IF gd.zone = NIL THEN {
gd.zone ← Heap.Create[initial~50, increment~10, swapUnit~10];
gd.rootName ← gd.zone.NEW[StringBody[100]]};
gd.packName ← gd.sourceBcdName ← NIL;
gd.outputBcdName ← gd.packListFileName ← NIL;
gd.mapFileName ← NIL;
gd.debug ← FALSE; debugPass ← CARDINAL.LAST;
gd.printMap ← listPacks ← FALSE;
localPause ← FALSE;
[gd.packName, args, results, switches] ← CommandUtil.Parse[
s~@theCommand,
opX~1+("pack"L).length, resultX~1+("list"L).length
! CommandUtil.Failed => {GO TO BadCommandLineSyntax}];
IF gd.packName = NIL AND switches = NIL THEN EXIT; -- done packaging
IF gd.packName = NIL THEN GO TO GlobalSwitches;
SetRoot[gd.rootName, gd.packName];
FOR i: CARDINAL IN [0..results.ListLength) DO
[key, value] ← results.GetNthPair[n~i];
SELECT TRUE FROM
(key = NIL), EquivalentString[key, "output"L] =>
gd.outputBcdName ← CommandUtil.CopyString[
s~value, extra~(".bcd"L).length];
EquivalentString[key, "list"L] => {
listPacks ← TRUE;
gd.packListFileName ← CommandUtil.CopyString[
s~value, extra~(".list"L).length]};
EquivalentString[key, "map"L] => {
gd.printMap ← TRUE;
gd.mapFileName ← CommandUtil.CopyString[
s~value, extra~(".map"L).length]};
ENDCASE => GO TO BadCommandLineSemantics;
ENDLOOP;
FOR i: CARDINAL IN [0..args.ListLength) DO
[key, value] ← args.GetNthPair[n~i];
SELECT TRUE FROM
(key = NIL), EquivalentString[key, "input"L] =>
gd.sourceBcdName ← CommandUtil.CopyString[
s~value, extra~(".bcd"L).length];
ENDCASE => GO TO BadCommandLineSemantics;
ENDLOOP;
IF switches # NIL THEN {
i: CARDINAL ← 0;
sense: BOOL ← TRUE;
WHILE i < switches.length DO
c: CHAR ~ switches[i];
SELECT c FROM
'-, '~ => sense ← ~sense;
'l, 'L => {listPacks ← sense; sense ← TRUE};
'm, 'M => {gd.printMap ← sense; sense ← TRUE};
'p, 'P => {localPause ← sense; sense ← TRUE};
'b, 'B => sense ← TRUE; -- no longer necessary
'd, 'D => {gd.debug ← sense; sense ← TRUE};
IN ['0..'5] => {debugPass ← c.ORD-'0.ORD; sense ← TRUE};
ENDCASE;
i ← i + 1;
ENDLOOP;
switches ← CommandUtil.FreeString[switches]};
IF gd.sourceBcdName = NIL THEN GOTO NoSourceBcdFileGiven;
gd.packName ← SetFileName[gd.packName, "pack"L];
gd.sourceBcdName ← SetFileName[gd.sourceBcdName, "bcd"L];
gd.outputBcdName ← SetFileName[gd.outputBcdName, "bcd"L];
IF listPacks THEN
gd.packListFileName ← SetFileName[gd.packListFileName, "list"L];
IF gd.printMap THEN gd.mapFileName ← SetFileName[gd.mapFileName, "map"L];
RepeatCommand[log];
packagerStartTime ← Time.Current[];
gd.sourceBcdFile ← gd.outputBcdFile ← NIL;
gd.packStream ← gd.packListStream ← gd.mapStream ← NIL;
OpenFiles[ ! CIFS.Error => TRUSTED {CONTINUE}];
IF packFile = NIL THEN GO TO CantFindPackFile
ELSE {
gd.packStream ← FileStream.Create[packFile.GetFC];
gd.packVersion ← BcdDefs.VersionStamp[
net~0, host~0, time~FileStream.GetLeaderProperties[gd.packStream].create];
packFile ← NIL};
IF gd.sourceBcdFile = NIL THEN GO TO CantFindSourceBcdFile;
IF gd.outputBcdFile = NIL THEN GO TO CantOpenObjectBcdFile;
IF listPacks THEN {
IF packListFile = NIL THEN packListFile ← GetFile[gd.packListFileName, $write];
gd.packListStream ← FileStream.Create[packListFile.GetFC]};
IF gd.printMap THEN {
IF mapFile = NIL THEN mapFile ← GetFile[gd.mapFileName, $write];
gd.mapStream ← FileStream.Create[mapFile.GetFC]};
gd.logStream ← NIL;
errorStream ← NIL;
errorStreamObject ← [ -- install private putByte and destroy procedures
options~TRASH,
getByte~TRASH, putByte~ErrorPut,
getWord~TRASH, putWord~TRASH,
get~TRASH, put~ErrorPutBlock,
setSST~TRASH, sendAttention~TRASH, waitAttention~TRASH,
delete~ErrorDestroy];
gd.errorStream ← @errorStreamObject;
Initialize[];
BEGIN
ENABLE {
Alloc.Failure => {
gd.errors ← TRUE;
IF ~gd.debug THEN {LogLine["Storage Overflow"L]; GOTO StorageOverflow}};
UNWIND => Finalize[]};
IF ExecOps.CheckForAbort[] THEN GO TO Abort;
SourceBcd.Load[ ! SourceBcd.BadSourceBcd => {GO TO InvalidSourceBcd}];
LogString["Parsing"L];
[complete~parsed, nErrors~gd.nErrors] ← P1.Parse[gd.packStream, gd.zone, Logger];
IF gd.nErrors # 0 THEN gd.errors ← TRUE;
IF ~parsed THEN GO TO ParseFailed;
IF debugPass <= 1 THEN PackDebug.PrintTree[];
IF ExecOps.CheckForAbort[] THEN GO TO Abort;
IF ~gd.errors THEN {
gd.root ← TreeOps.PopTree[];
LogString["...Building semantic entries"L];
configTreeRoot ← SourceBcd.BuildConfigTree[];
SemanticEntry.BuildSemanticEntries[];
IF debugPass <= 2 THEN {
PackDebug.PrintSourceBcd[];
PackDebug.PrintConfigTree[configTreeRoot];
PackDebug.PrintTree[]};
IF ExecOps.CheckForAbort[] THEN GO TO Abort;
IF ~gd.errors THEN {
LogString["...Determining packs"L];
ProcessingOrder.Determine[];
IF debugPass <= 3 THEN PackDebug.PrintProcessingOrder[configTreeRoot];
IF ExecOps.CheckForAbort[] THEN GO TO Abort;
ModuleSymbols.Initialize[SourceBcd.moduleCount];
IF ~gd.errors THEN {
CodePackProcs.Determine[configTreeRoot];
IF ExecOps.CheckForAbort[] THEN GO TO Abort;
IF ~gd.errors THEN {
IF listPacks THEN PackList.Print[];
LogString["...Computing code placement"L];
PackCode.ComputeCodePlacement[
! PackCode.PackError => {IF reason=$SegmentTooBig THEN GO TO dont}];
IF ExecOps.CheckForAbort[] THEN GO TO Abort;
LogString["...Writing Bcd"L];
PackCode.WriteBcdToFile[];
PackCode.WriteCodeToBcdFile[];
EXITS dont => PackCode.Finalize[]}}}};
EXITS
StorageOverflow => NULL;
ParseFailed => gd.errors ← aborted ← TRUE;
InvalidSourceBcd => gd.errors ← aborted ← TRUE;
Abort => abortRequested ← TRUE;
END;
CodePackProcs.Destroy[];
ProcessingOrder.Destroy[];
ModuleSymbols.Finalize[];
SourceBcd.DestroyConfigTree[configTreeRoot];
SourceBcd.Unload[];
LogChar['\n];
Finalize[];
EXITS
NoSourceBcdFileGiven => {
LogLine["\nNo source BCD file given\n"L];
gd.errors ← TRUE};
CantFindPackFile => {
LogString["\nCan't find pack file "L];
LogLine[gd.packName];
gd.errors ← TRUE};
CantFindSourceBcdFile => {
LogString["\nCan't find source Bcd "L];
LogLine[gd.sourceBcdName];
gd.errors ← TRUE};
CantOpenObjectBcdFile => {
LogString["\nCan't open output Bcd "L];
LogLine[gd.outputBcdName];
gd.errors ← TRUE};
GlobalSwitches => {
sense: BOOL ← TRUE;
FOR i: CARDINAL IN [0..switches.length) DO
c: CHAR ~ switches[i];
SELECT c FROM
'-, '~ => sense ← ~sense;
'b, 'B => sense ← TRUE; -- ignored
'p, 'P => {globalPause ← sense; sense ← TRUE};
ENDCASE => EXIT;
ENDLOOP;
switches ← CommandUtil.FreeString[switches]};
BadCommandLineSemantics => {
LogLine[" -- Illegal Packager command"L];
gd.errors ← TRUE};
END;
CloseFiles[];
gd.packName ← CommandUtil.FreeString[gd.packName];
gd.sourceBcdName ← CommandUtil.FreeString[gd.sourceBcdName];
gd.outputBcdName ← CommandUtil.FreeString[gd.outputBcdName];
IF listPacks THEN
gd.packListFileName ← CommandUtil.FreeString[gd.packListFileName];
IF gd.printMap THEN gd.mapFileName ← CommandUtil.FreeString[gd.mapFileName];
results ← CommandUtil.FreePairList[results];
args ← CommandUtil.FreePairList[args];
IF gd.errors THEN globalErrors ← TRUE;
IF gd.warnings THEN globalWarnings ← TRUE;
IF abortRequested THEN EXIT; -- stop Packager
IF gd.errors OR gd.warnings THEN {
IF localPause THEN {globalPause ← TRUE; EXIT}};
REPEAT
BadCommandLineSyntax => {
LogLine["\n-- Illegal Packager command syntax"L];
gd.errors ← globalErrors ← TRUE};
ENDLOOP;
END;
IF gd.ownTable # NIL THEN {Alloc.Destroy[gd.ownTable]; gd.ownTable ← NIL};
IF gd.zone # NIL THEN {Heap.Delete[gd.zone]; gd.zone ← NIL};
CloseLogStream[];
RETURN [SELECT TRUE FROM
abortRequested => $aborted,
globalErrors => $errors,
globalWarnings => $warnings,
ENDCASE => $ok];
}; -- of procedure DoPackagingInternal
-- MAIN BODY CODE
CallPackager: PROC ~ {
nChars: CARDINAL ~ (Exec.commandLine.s.length-Exec.commandLine.i) + 1;
command: ExecOps.Command ← Heap.MakeNode[n~(nChars+1)/2];
j: CARDINAL ← 0;
FOR i: CARDINAL IN [Exec.commandLine.i..Exec.commandLine.s.length) DO
command[j] ← Exec.commandLine.s[i]; j ← j+1;
ENDLOOP;
command[j] ← '\n;
[] ← DoPackaging[command];
Heap.FreeNode[p~command]};
InitializeSelf: PROC ~ {
P1.InstallParseTable[Runtime.GetTableBase[LOOPHOLE[PackParseData]]];
Exec.AddCommand[name~"CrossPackager.~", proc~CallPackager]};
InitializeSelf[];
}.