<<>> <> <> <> <> <> <> <> <> <> <<>> DIRECTORY BasicTime USING [GMT], FS USING [ExpandName, FileInfo, GetInfo, OpenFileFromStream, StreamOpen], <> IO, UXStrings, MobDefs USING [NullVersion, VersionStamp], Mobery USING [EnumerateStampProc, StampTable, StampTableRep, VersionStamp], MoberyPrivate, RefText USING [ObtainScratch, ReleaseScratch, TrustTextAsRope], Rope, SymTab; MoberyImpl: CEDAR MONITOR IMPORTS FS, IO, RefText, Rope, SymTab, UXStrings EXPORTS Mobery, MoberyPrivate = BEGIN <> ROPE: TYPE = Rope.ROPE; VersionStamp: TYPE = Mobery.VersionStamp; NoStamp: PUBLIC ERROR = CODE; StampPatterns: LIST OF ROPE = LIST["mob_version", "c2c_time", "c_stamp"]; hashMark: ROPE = "@(#)"; CacheEntry: TYPE ~ REF CacheEntryRep; CacheEntryRep: TYPE ~ RECORD [ list: LIST OF ROPE, created: BasicTime.GMT ]; sourceStampByteLimit: INT _ 8000; StopOnQuoteOrNull: IO.BreakProc = { <<[char: CHAR] RETURNS [IO.CharClass]>> RETURN [IF char = '\000 OR char = '" THEN break ELSE other] }; cache: SymTab.Ref ~ SymTab.Create[]; FlushCache: PUBLIC PROC ~ { cache.Erase[]; }; objRegs: LIST OF MoberyPrivate.ObjectFileTypeMatcherProc _ NIL; RegisterObjectFileType: PUBLIC PROC[p: MoberyPrivate.ObjectFileTypeMatcherProc] ~ { objRegs _ CONS[p, objRegs]; }; GetStamps: ENTRY PROC [fileName: ROPE] RETURNS [LIST OF ROPE] ~ { ENABLE UNWIND => {}; fullName: ROPE ~ FS.ExpandName[fileName].fullFName; list: LIST OF ROPE; created: BasicTime.GMT; WITH cache.Fetch[fullName].val SELECT FROM x: CacheEntry => { created _ FS.FileInfo[fileName].created; IF created = x.created THEN RETURN [x.list]; }; ENDCASE => NULL; [list: list, created: created] _ GetCOStamps[fullName]; { ce: CacheEntry ~ NEW [CacheEntryRep _ [list: list, created: created]]; [] _ cache.Insert[fullName, ce]; RETURN [ce.list]; }; }; GetCOStamps: PUBLIC PROC [fileName: ROPE] RETURNS [list: LIST OF ROPE, created: BasicTime.GMT] = { <> head: LIST OF ROPE = LIST[NIL]; last: LIST OF ROPE _ head; stream: IO.STREAM = FS.StreamOpen[fileName: fileName, accessOptions: $read]; buf: REF TEXT = RefText.ObtainScratch[nChars: 512]; hashMarkSize: INT = Rope.Length[hashMark]; hashStartChar: CHAR = Rope.Fetch[hashMark, 0]; smallBuf: REF TEXT = NEW[TEXT[hashMarkSize]]; start: INT; end: INT; match: BOOL; index: INT _ 0; created _ FS.GetInfo[FS.OpenFileFromStream[stream]].created; FOR r: LIST OF MoberyPrivate.ObjectFileTypeMatcherProc _ objRegs, r.rest WHILE r # NIL DO [match, start, end] _ r.first[stream]; IF match THEN EXIT; IO.SetIndex[self: stream, index: 0]; ENDLOOP; IF NOT match THEN { <> start _ 0; end _ sourceStampByteLimit; }; IO.SetIndex[self: stream, index: 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 buf[pos] # hashStartChar THEN RETURN [FALSE]; 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 IsHashMark[pos: i] THEN { { token: ROPE = IO.GetTokenRope[stream: stream, breakProc: StopOnQuoteOrNull ! IO.EndOfStream => EXIT].token; newIndex: INT = index + i + hashMarkSize + Rope.Length[token]; last _ last.rest _ LIST[token]; IF newIndex > index + bytes THEN{ index _ newIndex; IO.SetIndex[stream, index]; GOTO GetNextBlock; }; i _ newIndex - index; }; }; i _ i + 1; REPEAT GetNextBlock => LOOP; -- the enclosing WHILE -- ENDLOOP; index _ index + bytes; IF needSetIndex THEN IO.SetIndex[stream, index]; ENDLOOP; RefText.ReleaseScratch[buf]; IO.Close[stream]; RETURN [head.rest, created] }; <> StampTable: TYPE = Mobery.StampTable; StampTableRep: PUBLIC TYPE = RECORD [ name: ROPE, -- name of the current file -- stamps: SymTab.Ref ]; StampPair: TYPE = RECORD [ stampClass: ROPE, -- the stamp class -- stamp: VersionStamp -- its version stamp -- ]; UserData: TYPE = REF UserDataRep; UserDataRep: TYPE = RECORD [ name: ROPE, -- name of the file -- stampList: LIST OF StampPair -- all the stamps -- ]; EnumerateStampTable: PUBLIC PROC [stampTable: StampTable, to: Mobery.EnumerateStampProc] = BEGIN <> DoInner: PROC [key: ROPE, val: REF ANY] RETURNS [stop: BOOL _ FALSE] --SymTab.EachPairAction-- ~ { myData: UserData = NARROW[val]; FOR stampList: LIST OF StampPair _ myData.stampList, stampList.rest WHILE stampList # NIL AND NOT stop DO stamp: StampPair ~ stampList.first; stop _ to[myData.name, stamp.stampClass, stamp.stamp]; ENDLOOP; RETURN [stop: stop]; }; [] _ stampTable.stamps.Pairs[DoInner]; END; InsertInStampTable: PROC [table: StampTable, name, class: ROPE, stamp: VersionStamp] RETURNS [previously: BOOL _ FALSE] ~ { userData: UserData _ NARROW[table.stamps.Fetch[name].val]; IF userData = NIL THEN { userData _ NEW [UserDataRep]; userData.name _ name; userData.stampList _ LIST[[stampClass: class, stamp: stamp]]; IF NOT table.stamps.Insert[name, userData] THEN ERROR; RETURN [previously: FALSE] }; { FOR stampList: LIST OF StampPair _ userData.stampList, stampList.rest WHILE stampList # NIL AND NOT previously DO stampPair: StampPair ~ stampList.first; IF stamp = stampPair.stamp AND Rope.Equal[class, stampPair.stampClass] THEN RETURN [previously: TRUE]; ENDLOOP; userData.stampList _ CONS[StampPair[stampClass: class, stamp: stamp], userData.stampList]; }; RETURN [previously: FALSE]; }; StampFromStampTable: PUBLIC PROC [stampTable: StampTable, fileName: ROPE] RETURNS [stampClass: ROPE, stamp: VersionStamp] = BEGIN <> data: UserData = NARROW [stampTable.stamps.Fetch[fileName].val]; IF data = NIL THEN ERROR NoStamp; FOR stampList: LIST OF StampPair _ data.stampList, stampList.rest WHILE stampList # NIL DO stamp: StampPair ~ stampList.first; RETURN [stamp: stamp.stamp, stampClass: stamp.stampClass]; ENDLOOP; RETURN [stampClass: NIL, stamp: MobDefs.NullVersion] END; Has: PUBLIC PROC [stampTable: StampTable, name: ROPE, class: ROPE _ NIL, stamp: VersionStamp _ MobDefs.NullVersion] RETURNS [found: BOOL _ FALSE] = BEGIN <> data: UserData = NARROW [stampTable.stamps.Fetch[name].val]; IF data = NIL THEN RETURN [found: FALSE]; FOR stampList: LIST OF StampPair _ data.stampList, stampList.rest WHILE stampList # NIL DO stampPair: StampPair ~ stampList.first; IF (class = NIL OR Rope.Equal[class, stampPair.stampClass]) AND (stamp = MobDefs.NullVersion OR stamp = stampPair.stamp) THEN RETURN [found: TRUE]; ENDLOOP; RETURN [found: FALSE] END; ReadStampTable: PUBLIC PROC [fileName: ROPE] RETURNS [stampTable: StampTable] ~ { <> listOfStamps: LIST OF ROPE ~ GetStamps[fileName: fileName]; stampTable _ NEW [StampTableRep _ [ name: fileName, stamps: SymTab.Create[case: TRUE] ]]; FOR stampList: LIST OF ROPE _ listOfStamps, stampList.rest WHILE stampList # NIL DO aStamp: ROPE ~ stampList.first; FOR patternList: LIST OF ROPE _ StampPatterns, patternList.rest WHILE patternList # NIL DO pattern: ROPE ~ patternList.first; patternLen: INT ~ pattern.Length[]; IF pattern.Equal[aStamp.Substr[len: patternLen]] THEN { restOfString: ROPE ~ aStamp.Substr[start: patternLen+1]; name: ROPE; stamp: MobDefs.VersionStamp; [stamp: stamp, name: name] _ VersionAndNameFromString[restOfString]; IF name = NIL THEN RETURN [stampTable: NIL]; [] _ InsertInStampTable[table: stampTable, name: name, class: pattern, stamp: stamp]; }; ENDLOOP; ENDLOOP; RETURN [stampTable: stampTable]; }; StampTableSubset: PUBLIC PROC [tab1, tab2: StampTable] RETURNS [BOOL] = { subset: BOOL _ TRUE; SeeDiff: PROC [name, stampClass: ROPE, stamp: Mobery.VersionStamp] RETURNS [BOOL] ~ {subset _ FALSE; RETURN [TRUE]}; EnumerateStampTableDifference[tab1, tab2, SeeDiff]; RETURN [subset]}; EnumerateStampTableDifference: PUBLIC PROC [tab1, tab2: StampTable, to: Mobery.EnumerateStampProc] = { CheckOne: PROC [name, stampClass: ROPE, stamp: Mobery.VersionStamp] RETURNS [BOOL] --Mobery.EnumerateStampProc-- ~ { IF NOT Has[tab2, name, stampClass, stamp] THEN RETURN to[name, stampClass, stamp]; RETURN [FALSE]; }; EnumerateStampTable[tab1, CheckOne]; RETURN}; StampAndNameFromFile: PUBLIC PROC [fileName: ROPE] RETURNS [stamp: MobDefs.VersionStamp _ MobDefs.NullVersion, name: ROPE _ NIL] ~ { <> <> listOfStamps: LIST OF ROPE ~ GetStamps[fileName: fileName]; FOR stampList: LIST OF ROPE _ listOfStamps, stampList.rest WHILE stampList # NIL DO aStamp: ROPE ~ stampList.first; FOR patternList: LIST OF ROPE _ StampPatterns, patternList.rest WHILE patternList # NIL DO pattern: ROPE ~ patternList.first; patternLen: INT ~ pattern.Length[]; IF pattern.Equal[aStamp.Substr[len: patternLen]] THEN { restOfString: ROPE ~ aStamp.Substr[start: patternLen+1]; [stamp: stamp, name: name] _ VersionAndNameFromString[restOfString !IO.EndOfStream, IO.Error => GOTO NotThisOne]; RETURN; EXITS NotThisOne => name _ name}; ENDLOOP; ENDLOOP; }; <<>> VersionAndNameFromString: PUBLIC PROC [aRope: ROPE] RETURNS [stamp: MobDefs.VersionStamp, name: ROPE] ~ { <> MyBreakProc: IO.BreakProc ~ { RETURN[SELECT char FROM IN [IO.NUL .. IO.SP] => sepr, '[, '], '(, '), '{, '}, '", '+, '-, '*, '/, '@, '_, ',, ':, '; => break, ENDCASE => other] }; aStream: IO.STREAM ~ IO.RIS[aRope]; token: ROPE; [] _ aStream.SkipWhitespace[]; [token: token] _ aStream.GetTokenRope[MyBreakProc]; IF NOT token.Equal["["] THEN ERROR; -- this should not happen -- stamp[0] _ aStream.GetCard[]; [token: token] _ aStream.GetTokenRope[MyBreakProc]; IF NOT token.Equal[","] THEN ERROR; -- this should not happen -- stamp[1] _ aStream.GetCard[]; [token: token] _ aStream.GetTokenRope[MyBreakProc]; IF NOT token.Equal["]"] THEN ERROR; -- this should not happen -- name _ aStream.GetID[! IO.EndOfStream, IO.Error => { name _ NIL; CONTINUE }; ]; RETURN [stamp: stamp, name: name]; }; END.