-- CTFakeBcdImpl.Mesa, last edit March 21, 1983 5:52 pm
-- procedures to build the fake config in the compile tool
	
DIRECTORY
 BcdDefs: TYPE USING [Base, BCD, CTIndex, CTNull, CTRecord, EXPIndex, 
 	FTIndex, FTNull, FTRecord, FTSelf, GFTIndex, 
	Link, MTIndex, MTRecord, NameRecord, NullVersion, SGIndex, SGRecord, VersionID],
  BcdOps: TYPE USING [BcdBase, MTHandle, NameString, ProcessModules],
  Environment: TYPE USING [wordsPerPage],
  File: TYPE USING [Capability],
  IO: TYPE USING[card, PutF, rope],
  -- CedarLinkerOps: TYPE USING[Export],
  CS: TYPE USING[NewFile, ReadWrite],
  CT: TYPE USING[GenUniqueBcdName, Global, MI, ModuleList],
  CTFakeBcd: TYPE USING[],
  CTLoad: TYPE USING [LoadInfoSeq, Zero],
  PilotLoadStateFormat: TYPE USING [ConfigIndex],
  PilotLoadStateOps: TYPE USING [ConfigIndex, EnterModule, GetMap, 
  		Map, ReleaseLoadState, ReleaseMap, UpdateLoadState],
  PrincOps: TYPE USING[GFTIndex],
  Rope: TYPE USING[Text],
  Space: TYPE USING [Create, Delete, -- ForceOut, -- Handle, LongPointer, Map, 
  	nullHandle, virtualMemory];
				
CTFakeBcdImpl: PROGRAM 
IMPORTS BcdOps, -- CedarLinkerOps, -- CS, CT, CTLoad, IO, PilotLoadStateOps, Space
EXPORTS CTFakeBcd  = {
	
-- no MDS usage!
	
MTPAGE: CARDINAL = (SIZE[BcdDefs.BCD]/Environment.wordsPerPage) + 1;
nmtp: CARDINAL = 20;
FTPAGE: CARDINAL = MTPAGE + nmtp;
nftp: CARDINAL = 6;
SGPAGE: CARDINAL = FTPAGE + nftp;
nsgp: CARDINAL = 6;
CTPAGE: CARDINAL = SGPAGE + nsgp;
nctp: CARDINAL = 1;
SSPAGE: CARDINAL = CTPAGE + nctp;
nssp: CARDINAL = 16;
EXPAGE: CARDINAL = SSPAGE + nssp;
nexp: CARDINAL = 3;
BCDPAGES: CARDINAL = EXPAGE + nexp;

-- also updates the load state with the modules
BuildFakeBcd: PUBLIC PROC[g: CT.Global] = {
	bcdSpace: Space.Handle ← Space.nullHandle;
	{
	ENABLE UNWIND => 
		IF bcdSpace ~= Space.nullHandle THEN Space.Delete[bcdSpace];
	Cbcdbase: BcdOps.BcdBase;
	Cctb, Cmtb, Csgb, Cftb, Cetb: BcdDefs.Base;
	Cmti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex];
	Cfti: BcdDefs.FTIndex ← FIRST[BcdDefs.FTIndex];
	Csgi: BcdDefs.SGIndex ← FIRST[BcdDefs.SGIndex];
	Ceti: BcdDefs.EXPIndex ← FIRST[BcdDefs.EXPIndex];
	Cnamei: CARDINAL;
	Cnamestring: BcdOps.NameString;
	Cngfi: CARDINAL ← 1;
	
	ProcAnalyze: PROC[mi: CT.MI] = {
		sgb, ftb: BcdDefs.Base;
		bcdbase: BcdOps.BcdBase;
		namestring: BcdOps.NameString;
		
			ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
				RETURNS[stop: BOOL] = {
			rgfi: PrincOps.GFTIndex;
			stop ← FALSE;
			Check[Cmti + MTRecordLength[mth], Cbcdbase.mtLimit];
			Cmtb[Cmti] ← mth↑;
			Cmtb[Cmti].name ← NewName[namestring, mth.name];
			Cmtb[Cmti].gfi ← Cngfi;
			Cmtb[Cmti].extension ← direct[length: 0, frag:];
			IF mth.gfi >= mi.loadInfoSeq.dummymapseq.size THEN ERROR;
			-- this has previously been done in 
			--	CedarLoaderImpl.CreateGlobalFrames
			-- we do it here to set the map for the fake config
			rgfi ← mi.loadInfoSeq.dummymapseq[mth.gfi].ind;
			FOR i: CARDINAL IN [0 .. mth.ngfi) DO
				PilotLoadStateOps.EnterModule[rgfi+i, [resolved: TRUE, 
					config: g.configindex, gfi: Cngfi+i]];
				ENDLOOP;
			Cngfi ← Cngfi + mth.ngfi;
			Check[Cfti + SIZE[BcdDefs.FTRecord], Cbcdbase.ftLimit];
			IF mth.file = BcdDefs.FTSelf THEN {
				-- get info from header
				Cftb[Cfti] ← [NewName[namestring, bcdbase.source], 
					bcdbase.version];
				Cmtb[Cmti].file ← Cfti;
				Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
				}
			ELSE IF mth.file = BcdDefs.FTNull THEN {
				Cmtb[Cmti].file ← BcdDefs.FTNull;
				}
			ELSE {
				Cftb[Cfti] ← ftb[mth.file];
				Cftb[Cfti].name ← NewName[namestring, 
					ftb[mth.file].name];
				Cmtb[Cmti].file ← Cfti;
				Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
				};
			Check[Csgi + SIZE[BcdDefs.SGRecord], Cbcdbase.sgLimit];
			Csgb[Csgi] ← sgb[mth.sseg];
			Cmtb[Cmti].sseg ← Csgi;
			Check[Cfti + SIZE[BcdDefs.FTRecord], Cbcdbase.ftLimit];
			IF Csgb[Csgi].file = BcdDefs.FTSelf THEN {
				-- if self then the symbols are in the config's file
				Cftb[Cfti] ← [NewString[mi.bcdFileName], 
					bcdbase.version];
				Csgb[Csgi].file ← Cfti;
				Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
				}
			ELSE IF Csgb[Csgi].file = BcdDefs.FTNull THEN {
				Csgb[Csgi].file ← BcdDefs.FTNull;
				}
			ELSE {
				Cftb[Cfti] ← ftb[Csgb[Csgi].file];
				Cftb[Cfti].name ← NewName[namestring, 
					ftb[Csgb[Csgi].file].name];
				Csgb[Csgi].file ← Cfti;
				Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
				};
			Csgi ← Csgi + SIZE[BcdDefs.SGRecord];
			Cmti ← Cmti + SIZE[BcdDefs.MTRecord[direct]];
			Cbcdbase.nModules ← Cbcdbase.nModules + 1;
			};
			
		IF mi.loadInfoSeq = NIL THEN RETURN;
		bcdbase ← mi.loadInfoSeq.bcdbase;
		sgb ← LOOPHOLE[bcdbase + bcdbase.sgOffset, BcdDefs.Base];
		ftb ← LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base];
		namestring ← LOOPHOLE[bcdbase + bcdbase.ssOffset];
		[] ← BcdOps.ProcessModules[bcdbase, ForEachModule];
		};
		
	NewName: PROC[namestring: BcdOps.NameString, oldname: BcdDefs.NameRecord]
			RETURNS[newname: BcdDefs.NameRecord] = {
		newname ← LOOPHOLE[Cnamei];
		Check[(Cnamei + namestring.size[oldname] + 1)/2 + 1, Cbcdbase.ssLimit];
		Cnamestring.size[newname] ← namestring.size[oldname];
		FOR i: CARDINAL IN [0 .. Cnamestring.size[newname]) DO
			Cnamestring.string.text[newname + i] ←
				namestring.string.text[oldname + i];
			ENDLOOP;
		Cnamei ← Cnamei + Cnamestring.size[newname] + 1;
		};
		
	NewString: PROC[oldrope: Rope.Text] RETURNS[newname: BcdDefs.NameRecord] = {
		oldstring: LONG STRING ← LOOPHOLE[oldrope];
		newname ← LOOPHOLE[Cnamei];
		Check[(Cnamei + oldstring.length + 1)/2, Cbcdbase.ssLimit];
		Cnamestring.size[newname] ← oldstring.length;
		FOR i: CARDINAL IN [0 .. Cnamestring.size[newname]) DO
			Cnamestring.string.text[newname + i] ← oldstring[i];
			ENDLOOP;
		Cnamei ← Cnamei + Cnamestring.size[newname] + 1;
		};
		
	
	{
	cap: File.Capability;
	map: PilotLoadStateOps.Map;
	bcdSpace ← Space.Create[size: BCDPAGES, parent: Space.virtualMemory];
	g.fakeBcdFileName ← CT.GenUniqueBcdName["FakeConfig"];
	cap ← CS.NewFile[g.fakeBcdFileName, CS.ReadWrite, BCDPAGES];
	Space.Map[space: bcdSpace, window: [cap, 1]];
	Cbcdbase ← Space.LongPointer[bcdSpace];
	[] ← CTLoad.Zero[Cbcdbase, BCDPAGES * Environment.wordsPerPage];
	Cbcdbase.versionIdent ← BcdDefs.VersionID;
	Cbcdbase.nPages ← BCDPAGES;
	Cbcdbase.version  ← BcdDefs.NullVersion;
	Cbcdbase.nConfigs ← 1;
	Cbcdbase.nModules ← 0;
	Cbcdbase.extended ← TRUE;	-- to keep the RT happy
	Cbcdbase.nImports ← Cbcdbase.nExports ← 0;
	-- all the Limit vars are set to 0
	Cbcdbase.impOffset ← Cbcdbase.evOffset ← 0;
	Cbcdbase.spOffset ← Cbcdbase.ntOffset ← Cbcdbase.typOffset ← 0;
	Cbcdbase.tmOffset ← Cbcdbase.fpOffset ← 0;
	Cbcdbase.ctOffset ← CTPAGE * Environment.wordsPerPage;
	Cbcdbase.mtOffset ← MTPAGE * Environment.wordsPerPage;
	Cbcdbase.sgOffset ← SGPAGE * Environment.wordsPerPage;
	Cbcdbase.ftOffset ← FTPAGE * Environment.wordsPerPage;
	Cbcdbase.expOffset ← EXPAGE * Environment.wordsPerPage;
	Cbcdbase.ssOffset ← SSPAGE * Environment.wordsPerPage;
	Cnamei ← 0;
	Cctb ← LOOPHOLE[Cbcdbase + Cbcdbase.ctOffset, BcdDefs.Base];
	Cmtb ← LOOPHOLE[Cbcdbase + Cbcdbase.mtOffset, BcdDefs.Base];
	Csgb ← LOOPHOLE[Cbcdbase + Cbcdbase.sgOffset, BcdDefs.Base];
	Cftb ← LOOPHOLE[Cbcdbase + Cbcdbase.ftOffset, BcdDefs.Base];
	Cetb ← LOOPHOLE[Cbcdbase + Cbcdbase.expOffset, BcdDefs.Base];
	Cnamestring ← LOOPHOLE[Cbcdbase + Cbcdbase.ssOffset, BcdDefs.Base];
	Cbcdbase.ctLimit ← FIRST[BcdDefs.CTIndex] + SIZE[BcdDefs.CTRecord];
	Cbcdbase.mtLimit ← LOOPHOLE[nmtp * Environment.wordsPerPage];
	Cbcdbase.ftLimit ← LOOPHOLE[nftp * Environment.wordsPerPage];
	Cbcdbase.sgLimit ← LOOPHOLE[nsgp * Environment.wordsPerPage];
	Cbcdbase.expLimit ← LOOPHOLE[nexp * Environment.wordsPerPage];
	Cbcdbase.ssLimit ← LOOPHOLE[nssp * Environment.wordsPerPage];
	LOOPHOLE[Cnamestring+1, LONG POINTER TO CARDINAL]↑ ← (Cbcdbase.ssLimit-2)*2;	-- the maxlength of namestring
	Cnamestring.string.length ← Cnamestring.string.maxlength;
	 
	Cctb[FIRST[BcdDefs.CTIndex]] ← [name: NewString[g.fakeBcdFileName], 
		namedInstance: FALSE, file: BcdDefs.FTNull, config: BcdDefs.CTNull, 
		nControls: 0, controls:];
	
	-- that sets all the booleans to FALSE, etc.
	FOR l: CT.ModuleList ← g.moduleList, l.rest UNTIL l = NIL DO
		ProcAnalyze[l.first];
		ENDLOOP;
	
	Cbcdbase.firstdummy ← Cngfi;	-- # gfi's needed for the modules in the config
	Cbcdbase.mtLimit ← Cmti;
	Cbcdbase.ftLimit ← Cfti;
	Cbcdbase.sgLimit ← Csgi;
	Cbcdbase.expLimit ← Ceti;
	Cbcdbase.ssLimit ← (Cnamei/2)+1;
	
	g.fakebcdspace ← bcdSpace;
	-- now insert the new bcdbase
	-- newer version of BcdOps
	PilotLoadStateOps.UpdateLoadState[g.configindex, LOOPHOLE[Cbcdbase]];
	map ← PilotLoadStateOps.GetMap[g.configindex];
	-- CedarLinkerOps.Export[LOOPHOLE[Cbcdbase], map];
	PilotLoadStateOps.ReleaseMap[map];
	PilotLoadStateOps.ReleaseLoadState[];
	g.dout.PutF["Total # of gfi's needed to load: %s.\n", IO.card[Cngfi]];
	-- this ForceOut is expensive, only need it for debugging
	-- Space.ForceOut[bcdSpace];
	g.dout.PutF["Fake bcd written out on %s\n", IO.rope[g.fakeBcdFileName]];
	}}};
	
Check: PROC[val, limit: UNSPECIFIED] = {
	IF LOOPHOLE[val, CARDINAL] >= LOOPHOLE[limit, CARDINAL] THEN ERROR;
	};
	
MTRecordLength: PROC[mth: BcdOps.MTHandle] RETURNS[len: CARDINAL] = {
	RETURN[WITH m: mth SELECT FROM
		direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link],
		indirect => SIZE[BcdDefs.MTRecord[indirect]],
		multiple => SIZE[BcdDefs.MTRecord[multiple]],
		ENDCASE => ERROR];
	};
	
}.
	
	
	
	-- no longer needed
	AddToExports: PROC[interfaceseq: CTLoad.InterfaceSeq] = {
		Check[Cfti + SIZE[BcdDefs.FTRecord], Cbcdbase.ftLimit];
		Check[Ceti + SIZE[BcdDefs.EXPRecord] + interfaceseq.size, Cbcdbase.expLimit];
		Cftb[Cfti] ← [name: NewString[interfaceseq.name], version: interfaceseq.bcdVers];
		Cetb[Ceti] ← [name: NewString[interfaceseq.name], size: interfaceseq.size,
			port: interface, namedInstance: FALSE, typeExported: FALSE,
			file: Cfti, links: ];
		FOR i: CARDINAL IN [0 .. Cetb[Ceti].size) DO
			Cetb[Ceti].links[i] ← interfaceseq[i].blink;
			ENDLOOP;
		Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
		Ceti ← Ceti + SIZE[BcdDefs.EXPRecord] + interfaceseq.size;
		Cbcdbase.nExports ← Cbcdbase.nExports + 1;
		};
			-- now put exports in export table
	{
	mi: CT.MI;
	FOR l: CT.ModuleList ← g.moduleList, l.rest UNTIL l = NIL DO
		mi ← l.first;
		IF mi.exportedInterface THEN {
			FOR l: LIST OF CTLoad.InterfaceSeq ← g.moduleExports, l.rest UNTIL l = NIL DO
				IF l.first.bcdVers = mi.bcdVers THEN {
					AddToExports[l.first];
					EXIT;
					};
				REPEAT
				FINISHED => {
					g.ttyout.PutF["Error - cannot find %s exported by this program.\n",
						IO.rope[mi.bcdFileName]];
					};
				ENDLOOP;
			};
		ENDLOOP;
	};