VersionMapClassifyImpl.mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Willie-s, March 23, 1992 6:34 pm PST
Spreitze, August 17, 1990 2:55 pm PDT
DIRECTORY
Basics,
BasicTime USING [GMT, ToNSTime],
FileNames,
FS,
IO,
MobDefs,
RefText,
Rope,
VersionMap,
VersionMapClassify;
VersionMapClassifyImpl: CEDAR PROGRAM
IMPORTS BasicTime, FileNames, FS, IO, RefText, Rope, VersionMap
EXPORTS VersionMapClassify
= BEGIN
T Y P E S
GMT: TYPE = BasicTime.GMT;
Map: TYPE = VersionMap.Map;
MapList: TYPE = VersionMap.MapList;
ROPE: TYPE = Rope.ROPE;
RopeList: TYPE = LIST OF ROPE;
STREAM: TYPE = IO.STREAM;
VersionStamp: TYPE = VersionMap.VersionStamp;
NullVersion: VersionStamp = VersionMapClassify.NullVersion;
BadVersion: VersionStamp = VersionMapClassify.BadVersion;
Global variables
KindName: PUBLIC ARRAY VersionMapClassify.KindSet OF ROPE ¬ [
"unknown", "source", "intermediate", "sparc", "sparcOpt", "all" ];
Single file processing
Classify: PUBLIC PROC [name: ROPE] RETURNS [kind: VersionMapClassify.Kind] ~ {
nameWithoutVersion: ROPE ~ FileNames.StripVersionNumber[name];
whichMap, other: ATOM;
[whichMap, other] ¬ VersionMap.MapAtomForName[nameWithoutVersion];
SELECT TRUE FROM
whichMap = $Intermediate => kind ¬ intermediate;
whichMap = $Source => kind ¬ source;
whichMap = $Executable =>
IF other = $opt THEN kind ¬ sparcOpt ELSE kind ¬ sparc;
ENDCASE => kind ¬ source};
CreatedToMimosaVersionStamp: PUBLIC PROC [created: BasicTime.GMT] RETURNS [VersionStamp] = {
RETURN [[BasicTime.ToNSTime[created], 0]]};
ReadVersionStamp: PUBLIC PROC [kind: VersionMapClassify.Kind, fullName: ROPE, created: BasicTime.GMT, rejectServerInaccessible: BOOL] RETURNS [stamp: VersionStamp, whyNot, warning: ROPE] ~ {
bangPos: INT ~ fullName.Index[s2: "!"];
verless: ROPE ~ fullName.Substr[len: bangPos];
SELECT kind FROM
unknown, source => RETURN [CreatedToMimosaVersionStamp[created], NIL, NIL];
intermediate => SELECT TRUE FROM
Rope.Match["*.mob", verless] => RETURN ReadMobStamp[fullName, created, rejectServerInaccessible];
Rope.Match["*.c2c.c", verless] => {
[stamp, whyNot] ¬ ReadCOStamp[fullName, created, rejectServerInaccessible];
warning ¬ NIL; RETURN};
ENDCASE => RETURN [CreatedToMimosaVersionStamp[created], NIL, NIL];
sparc, sparcOpt => {
[stamp, whyNot] ¬ ReadCOStamp[fullName, created, rejectServerInaccessible];
IF whyNot#NIL AND NOT Rope.Match["*.c2c.o", verless] THEN {
stamp ¬ CreatedToMimosaVersionStamp[created];
warning ¬ whyNot.Concat["; create date used for stamp"]; whyNot ¬ NIL}
ELSE warning ¬ NIL;
RETURN};
ENDCASE => ERROR;
};
ReadMobStamp: PROC [fullName: ROPE, created: BasicTime.GMT, rejectServerInaccessible: BOOL] RETURNS [stamp: VersionStamp, whyNot, warning: ROPE ¬ NIL] ~ {
from: IO.STREAM;
mob: MobDefs.Mob;
nRead: INT;
from ¬ FS.StreamOpen[fileName: fullName, wantedCreatedTime: created !FS.Error => IF error.code#$serverInaccessible OR NOT rejectServerInaccessible THEN {whyNot ¬ IO.PutFLR["FS.Open[%g of %g] => Error[%g, %g]", LIST[ [rope[fullName]], [time[created]], [atom[error.code]], [rope[error.explanation]]] ]; GOTO Abort} ];
TRUSTED {nRead ¬ from.UnsafeGetBlock[[base: LOOPHOLE[@mob], count: BYTES[MobDefs.Mob]]]};
from.Close[];
IF nRead # BYTES[MobDefs.Mob] THEN RETURN [BadVersion, IO.PutFLR["%g of %g yielded only %g bytes, instead of %g", LIST[ [rope[fullName]], [time[created]], [integer[nRead]], [integer[BYTES[MobDefs.Mob]]]] ]];
{cvi: CARD ~ LOOPHOLE[mob.versionIdent];
SELECT cvi FROM
CARD[MobDefs.VersionID] => RETURN [mob.version, NIL];
SwapHWords[MobDefs.VersionID] => RETURN [[SwapHWords[mob.version[0]], SwapHWords[mob.version[1]] ], NIL];
ENDCASE => RETURN[BadVersion, IO.PutFLR["%g of %g has unrecognized versionIdent (%08xH) [expected %08xH]", LIST[ [rope[fullName]], [time[created]], [cardinal[cvi]], [cardinal[MobDefs.VersionID]]] ]];
};
EXITS Abort => stamp ¬ BadVersion};
SwapHWords: PROC [c: CARD] RETURNS [CARD] ~ {
n: Basics.LongNumber ~ LOOPHOLE[c];
sn: Basics.LongNumber ~ [pair[hi: n.lo, lo: n.hi]];
RETURN [sn.card];
};
hashMark: ROPE = Rope.Cat["@(", "#)mob", "←version ["]; --broken up to avoid spurrious one
sourceStampByteLimit: INT ¬ 8000;
headerBytes: INT = 4+4*7; -- size of header for .o files
textSizeOffset: INT = 4; -- byte offset of text size field in .o files
ReadCOStamp: PROC [fullName: ROPE, created: BasicTime.GMT, rejectServerInaccessible: BOOL] RETURNS [stamp: VersionStamp, whyNot: ROPE ¬ NIL] ~ {
hashMarkSize: INT = Rope.Length[hashMark];
hashStartChar: CHAR = Rope.Fetch[hashMark, 0];
buf: REF TEXT = RefText.ObtainScratch[nChars: 512];
smallBuf: REF TEXT = NEW[TEXT[hashMarkSize]];
start: INT ¬ 0;
end: INT ¬ sourceStampByteLimit;
index: INT ¬ 0;
baselen: INT;
stream: IO.STREAM;
cp: FS.ComponentPositions;
base: ROPE;
[fullName, cp, ] ¬ FS.ExpandName[fullName];
base ¬ fullName.Substr[start: cp.base.start, len: cp.base.length];
base ¬ base.Substr[len: baselen ¬ base.Index[s2: "."]];
{stream ¬ FS.StreamOpen[fileName: fullName, wantedCreatedTime: created !FS.Error => IF error.code#$serverInaccessible OR NOT rejectServerInaccessible THEN {whyNot ¬ IO.PutFLR["FS.Open[%g of %g] => Error[%g, %g]", LIST[ [rope[fullName]], [time[created]], [atom[error.code]], [rope[error.explanation]]] ]; GOTO NotOpen} ];
{ENABLE {
IO.Error => {whyNot ¬ IO.PutFR["IO.Error while trying to find version stamp in %g of %g", [rope[fullName]], [time[created]] ]; GOTO Abort};
IO.EndOfStream => GOTO Alldun};
IF (NOT stream.EndOf[]) AND IO.PeekChar[self: stream].ORD < 2 THEN {
an object file.
ReadBinaryINT: PROC [stream: IO.STREAM] RETURNS [INT] ~ {
ln: Basics.LongNumber ¬ [card[0]];
ln.hh ¬ IO.GetByte[stream];
ln.hl ¬ IO.GetByte[stream];
ln.lh ¬ IO.GetByte[stream];
ln.ll ¬ IO.GetByte[stream];
RETURN [ln.int]
};
IO.SetIndex[self: stream, index: textSizeOffset];
start ¬ headerBytes + ReadBinaryINT[stream];
end ¬ start + ReadBinaryINT[stream];
IF NOT start IN [0..end) AND end <= IO.GetLength[stream] THEN {
confusion! search whole file.
start ¬ 0;
end ¬ IO.GetLength[stream];
};
};
IO.SetIndex[stream, start];
index ¬ start;
WHILE index < end DO
bytes: INT ¬ IO.GetBlock[self: stream, block: buf];
i: NAT ¬ 0;
needSetIndex: BOOL ¬ FALSE;
IsHashMark: PROC [pos: INT] RETURNS [BOOL] ~ {
IF pos+hashMarkSize <= bytes
THEN {
FOR j: INT ¬ 1, j+1 WHILE j < hashMarkSize DO
IF hashMark.Fetch[j] # buf[pos+j] THEN RETURN [FALSE];
ENDLOOP;
IO.SetIndex[stream, index+pos+hashMarkSize];
needSetIndex ¬ TRUE;
RETURN [TRUE];
}
ELSE {
IO.SetIndex[stream, index+pos];
needSetIndex ¬ TRUE;
[] ¬ IO.GetBlock[self: stream, block: smallBuf];
RETURN [Rope.Equal[hashMark, RefText.TrustTextAsRope[smallBuf]]];
}
};
IF bytes = 0 THEN EXIT;
WHILE i < bytes DO
IF buf[i]=hashStartChar AND IsHashMark[pos: i] THEN {
moduleName: ROPE;
newIndex: INT;
vs: VersionStamp ¬ ALL[0];
vs[0] ¬ stream.GetCard[ !IO.Error => IF ec=SyntaxError OR ec=Overflow THEN GOTO NotReally];
IF stream.GetChar[] # ', THEN GOTO NotReally;
vs[1] ¬ stream.GetCard[ !IO.Error => IF ec=SyntaxError OR ec=Overflow THEN GOTO NotReally];
IF stream.GetChar[] # '] THEN GOTO NotReally;
IF stream.GetChar[] # ' THEN GOTO NotReally;
moduleName ¬ IO.GetTokenRope[stream: stream, breakProc: StopOnQuoteOrNull].token;
IF base.IsPrefix[moduleName, FALSE] AND (baselen = moduleName.Length[] OR moduleName.EqualSubstrs[start1: baselen, s2: ".config", case: FALSE]) THEN {
RefText.ReleaseScratch[buf];
IO.Close[stream];
RETURN [vs]};
newIndex ¬ stream.GetIndex[];
IF newIndex > index + bytes THEN{
index ¬ newIndex;
IO.SetIndex[stream, index];
GOTO GetNextBlock;
};
i ¬ newIndex - index;
EXITS NotReally => i ¬ i};
i ¬ i + 1;
REPEAT
GetNextBlock => LOOP; -- the enclosing WHILE --
ENDLOOP;
index ¬ index + bytes;
IF needSetIndex THEN IO.SetIndex[stream, index];
ENDLOOP;
GOTO Alldun;
EXITS
Alldun => whyNot ¬ IO.PutFR["%g of %g has no version stamp", [rope[fullName]], [time[created]] ];
Abort => stamp ¬ BadVersion};
IO.Close[stream];
EXITS NotOpen => stamp ¬ BadVersion};
RefText.ReleaseScratch[buf];
RETURN [BadVersion, whyNot]};
StopOnQuoteOrNull: IO.BreakProc = {
[char: CHAR] RETURNS [IO.CharClass]
RETURN [IF char = '\000 OR char = '" THEN break ELSE other]
};
ScanName: PROC [name: ROPE] RETURNS [pos,bang,dot: INT] = {
len: INT = Rope.Length[name];
pos ¬ bang ¬ dot ¬ len;
WHILE pos > 0 DO
posM: INT = pos-1;
SELECT Rope.Fetch[name, posM] FROM
'! => bang ¬ dot ¬ posM;
'. => dot ¬ posM;
'>, '/, '] => RETURN;
ENDCASE;
pos ¬ posM;
ENDLOOP;
};
Routines to use the old maps for verification of names
MapListLookup: PUBLIC PROC [mapList: MapList, fullName: ROPE, created: BasicTime.GMT, onlyOne, testCreated, testName: BOOL] RETURNS [found: BOOL ¬ FALSE, fromMap: ROPE ¬ NIL, version: VersionStamp ¬ NullVersion] = {
IF onlyOne THEN {
version ¬ CreatedToMimosaVersionStamp[created];
fromMap ¬ VersionMap.VersionToName[mapList, version].name;
{len: INT ¬ fromMap.Length[];
bang: INT ¬ ScanName[fromMap].bang;
SELECT Rope.Run[fromMap, 0, fullName, 0, FALSE] FROM
=0, <bang => RETURN [FALSE];
ENDCASE => RETURN [TRUE, fromMap, version];
}}
ELSE {
short: ROPE = VersionMap.ShortName[fullName];
rangeList: VersionMap.RangeList ¬
VersionMap.ShortNameToRanges[mapList, short];
WHILE rangeList # NIL DO
range: VersionMap.Range ¬ rangeList.first;
rangeList ¬ rangeList.rest;
WHILE range.len # 0 DO
name: ROPE;
stamp: VersionStamp;
eCreated: BasicTime.GMT;
[name, stamp, eCreated, range] ¬ VersionMap.RangeToEntry[range];
IF testCreated AND created#eCreated THEN LOOP;
IF testName AND NOT Rope.Equal[fullName, name, FALSE] THEN LOOP;
RETURN [TRUE, name, stamp];
ENDLOOP;
ENDLOOP;
At this point we did NOT get a match, so flake out!
found ¬ FALSE;
};
RETURN};
END.