-- SourceTimeImpl.Mesa -- Last modified by Sandman on July 8, 1980 11:15 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [BytesPerWord, PageSize], BcdDefs USING [VersionStamp, NullVersion], InlineDefs USING [BITAND], SegmentDefs USING [FileHandle, GetFileTimes], SourceTime USING [], StreamDefs USING [CreateByteStream, Read, ReadBlock, StreamHandle], String USING [AppendChar, EquivalentString, StringToDecimal], Storage USING [Pages, FreePages], TimeDefs USING [InvalidTime, PackDT, PackedTime, UnpackedTime]; SourceTimeImpl: PROGRAM IMPORTS InlineDefs, SegmentDefs, StreamDefs, String, Storage, TimeDefs EXPORTS SourceTime = BEGIN OPEN SegmentDefs; -- Obtain creation dates for source files -- NullStamp: BcdDefs.VersionStamp = BcdDefs.NullVersion; NullTime: LONG CARDINAL = NullStamp.time; BufferObject: TYPE = RECORD [p: CARDINAL, s: STRING]; Buffer: TYPE = POINTER TO BufferObject; FindSourceVersion: PUBLIC PROCEDURE [file: FileHandle, getDateFromText: BOOLEAN] RETURNS [date: TimeDefs.PackedTime] = BEGIN OPEN AltoDefs, StreamDefs; stream: StreamHandle ← CreateByteStream[file, Read]; b: BufferObject; found: BOOLEAN ← FALSE; tdate: TimeDefs.PackedTime; IF ~getDateFromText THEN -- obtain date from file header page date ← SegmentDefs.GetFileTimes[file].create ELSE -- obtain date by scanning 1st few lines of file BEGIN b.s ← Storage.Pages[1]; b.s↑ ← [length: 0, maxlength: (PageSize - SIZE[StringBody])*BytesPerWord, text:]; b.s.length ← ReadBlock[stream, @b.s.text, b.s.maxlength/BytesPerWord]*BytesPerWord; b.p ← 0; [found, date] ← GetDate[@b ! TimeDefs.InvalidTime => CONTINUE]; IF found THEN DO [found, tdate] ← GetDate[@b ! TimeDefs.InvalidTime => EXIT]; IF ~found THEN EXIT; IF tdate > date THEN date ← tdate; ENDLOOP; Storage.FreePages[b.s]; END; stream.destroy[stream]; RETURN; END; GetDate: PROCEDURE [b: Buffer] RETURNS [BOOLEAN, TimeDefs.PackedTime] = BEGIN OPEN TimeDefs, String; token: STRING ← [20]; found: BOOLEAN ← FALSE; index: CARDINAL [0..12); u: UnpackedTime ← [0, 0, 0, 0, 0, 0, 0, 0, FALSE]; NextItem[b, token]; WHILE token.length # 0 DO [found, index] ← IsMonth[token]; IF found THEN BEGIN NextItem[b, token]; IF IsNumber[token] THEN BEGIN u.month ← index; u.day ← StringToDecimal[token]; END ELSE LOOP; END ELSE IF IsNumber[token] THEN -- possible Day-Mo-Yr form BEGIN u.day ← StringToDecimal[token]; NextItem[b, token]; [found, index] ← IsMonth[token]; IF found THEN u.month ← index ELSE LOOP; END; IF found THEN BEGIN NextItem[b, token]; IF IsNumber[token] THEN BEGIN u.year ← StringToDecimal[token]; IF u.year < 100 THEN u.year ← u.year + 1900; END ELSE LOOP; NextItem[b, token]; IF IsNumber[token] THEN BEGIN u.hour ← StringToDecimal[token]; NextItem[b, token]; IF IsNumber[token] THEN u.minute ← StringToDecimal[token]; NextItem[b, token]; IF EquivalentString[token, "PM"L] AND u.hour < 12 THEN u.hour ← u.hour + 12 ELSE IF EquivalentString[token, "AM"L] AND u.hour = 12 THEN u.hour ← 0; END; RETURN[TRUE, TimeDefs.PackDT[u, TRUE]] END; NextItem[b, token]; ENDLOOP; RETURN[FALSE, NullTime] END; IsMonth: PROCEDURE [candidate: STRING] RETURNS [BOOLEAN, CARDINAL] = BEGIN Months: ARRAY [0..12) OF STRING = ["JANUARY"L, "FEBRUARY"L, "MARCH"L, "APRIL"L, "MAY"L, "JUNE"L, "JULY"L, "AUGUST"L, "SEPTEMBER"L, "OCTOBER"L, "NOVEMBER"L, "DECEMBER"L]; i, j: CARDINAL; test: STRING; IF candidate.length >= 3 THEN FOR i IN [0..12) DO test ← Months[i]; IF candidate.length <= test.length THEN FOR j IN [0..candidate.length) DO IF CharAnd[candidate[j], 137B] # test[j] THEN EXIT; REPEAT FINISHED => RETURN[TRUE, i]; ENDLOOP; ENDLOOP; RETURN[FALSE, 0] END; CharAnd: PROCEDURE [CHARACTER, WORD] RETURNS [CHARACTER] = InlineDefs.BITAND; IsNumber: PROCEDURE [s: STRING] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; IF s.length = 0 THEN RETURN[FALSE]; FOR i IN [0..s.length) DO IF s[i] ~ IN ['0..'9] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] END; NextItem: PROCEDURE [b: Buffer, token: STRING] = BEGIN c: CHARACTER; token.length ← 0; WHILE b.p < b.s.length DO c ← b.s[b.p]; b.p ← b.p + 1; SELECT c FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9] => IF token.length < token.maxlength THEN String.AppendChar[token, c]; ENDCASE => IF token.length # 0 THEN EXIT; ENDLOOP; RETURN END; END.