-- CedarMapsBuilderImpl.mesa
-- Russ Atkinson, November 10, 1982 2:51 pm

DIRECTORY
Rope USING [Concat, Fetch, ROPE, Size, Substr],
SymTab,
VersionMap,
VersionMapBuilder;

CedarMapsBuilderImpl: CEDAR PROGRAM
IMPORTS Rope, SymTab, VersionMap, VersionMapBuilder
-- EXPORTS CedarMapsBuilder
= BEGIN OPEN Rope;

Map: TYPE = VersionMap.Map;

sourceName: ROPE ← "CedarSource.VersionMap";
symbolsName: ROPE ← "CedarSymbols.VersionMap";
defaultUpdateName: ROPE ← "Release.VersionMapFile";

MakeCedarMaps: PROC
[mergeMap,oldSourceMap,oldSymbolsMap: Map ← NIL, overwrite: BOOLFALSE] = {
-- step 1: read old maps & the update map
mergeLen: INT ← mergeMap.Length[];
mapIndex: INT ← 0;
newSourceMap: Map ← NIL;
newSymbolsMap: Map ← NIL;

-- step 2: invert the update map
invertTab: SymTab.Ref ← InvertMap[mergeMap];
oldFilter: VersionMapBuilder.FilterProc = {
-- [name: ROPE] RETURNS [ok: BOOL]
RETURN [NOT invertTab.Fetch[StripOffVersion[name]].found]
};

-- step 3: make new maps
newSourceMap ← MakeMergedMap
[oldSourceMap, mergeMap, oldFilter, VersionMapBuilder.NonBCDFilter];
newSymbolsMap ← MakeMergedMap
[oldSymbolsMap, mergeMap, oldFilter, VersionMapBuilder.OnlyBCDFilter];

-- step 4: save the maps
newSourceMap.SaveMapToFile
[sourceName.Concat[IF overwrite THEN "" ELSE "$"]];
newSymbolsMap.SaveMapToFile
[symbolsName.Concat[IF overwrite THEN "" ELSE "$"]];

};

MakeMergedMap: PROC
[oldMap, mergeMap: Map ← NIL, oldfilter, mergeFilter: VersionMapBuilder.FilterProc ← NIL]
RETURNS [newMap: Map ← NIL] = {
getNext: VersionMapBuilder.EachProc = {
-- [data: REF] RETURNS [stamp: TimeStamp.Stamp, name: ROPE]
IF oldMap # NIL THEN
{WHILE index < oldMap.Length[] DO
[stamp, name] ← oldMap.Fetch[index];
index ← index + 1;
IF oldfilter = NIL OR oldfilter[name] THEN RETURN;
ENDLOOP;
oldMap ← NIL;
index ← 0;
};
WHILE index <= mergeMap.Length[] DO
[stamp, name] ← mergeMap.Fetch[index];
index ← index + 1;
IF mergeFilter = NIL OR mergeFilter[name] THEN RETURN;
ENDLOOP;
name ← NIL; -- this stops the enumeration
};
index: INT ← 0;
prefix: ROPEIF oldMap = NIL THEN NIL ELSE oldMap.GetPrefix[];
IF prefix.Size[] = 0 AND mergeMap # NIL THEN prefix ← mergeMap.GetPrefix[];
RETURN [VersionMapBuilder.GenerateMapFromProc[getNext, NIL, prefix]];
};

InvertMap: PROC [map: Map] RETURNS [tab: SymTab.Ref] = {
mapLen: INT ← map.Length[];
tab ← SymTab.Create[mapLen, FALSE];
FOR index: INT IN [0..mapLen) DO
name: ROPE ← map.FetchName[index];
[] ← tab.Store[StripOffVersion[name], name];
ENDLOOP;
};

StripOffVersion: PROC [name: ROPE] RETURNS [ROPE] = {
FOR i: INT DECREASING IN [0..name.Size[]) DO
IF name.Fetch[i] = '! THEN
RETURN [name.Substr[0, i]];
ENDLOOP;
RETURN [name];
};

END.