-- VersionPack.Mesa Edited by Sandman on July 8, 1980 9:02 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [BytesPerWord, PageSize], BcdDefs USING [BCD, FTIndex, FTRecord, VersionID, VersionStamp, Base], BcdOps USING [NameString], FastDirDefs USING [ LookupItem, ScanDir, AllFileSwitches, Cap, StripExtension, FileType, GetExtension, ItemHandle], ImageDefs USING [StopMesa], ImageFormat USING [VersionID], IODefs USING [ CR, ReadChar, ReadID, SP, WriteChar, WriteDecimal, WriteLine, WriteOctal, WriteString], SegmentDefs USING [ DeleteFileSegment, FileSegmentAddress, FileSegmentHandle, InsertFile, MoveFileSegment, NewFileSegment, Read, SwapIn, Unlock], StreamDefs USING [ CreateByteStream, NewByteStream, Read, ReadBlock, StreamHandle], StringDefs USING [ AppendChar, AppendSubString, EquivalentString, StringToDecimal, SubStringDescriptor], Storage USING [Pages, FreePages], TimeDefs USING [ AppendDayTime, DefaultTime, InvalidTime, PackDT, PackedTime, UnpackDT, UnpackedTime]; VersionPack: PROGRAM IMPORTS FastDirDefs, ImageDefs, IODefs, SegmentDefs, StreamDefs, StringDefs, Storage, TimeDefs = BEGIN OPEN IODefs, StreamDefs, StringDefs; BcdBase: TYPE = POINTER TO BcdDefs.BCD; UnpackedTime: TYPE = TimeDefs.UnpackedTime; BinaryVersion: VersionProc = BEGIN OPEN SegmentDefs; bcd: BcdBase; seg: FileSegmentHandle ← NewFileSegment[ InsertFile[@info.fp, Read], 1, 1, Read]; SwapIn[seg]; bcd ← FileSegmentAddress[seg]; SELECT bcd.versionIdent FROM BcdDefs.VersionID => BEGIN PrintVersion[bcd.version]; WriteChar[CR]; IF type = bcd AND verbose THEN BEGIN IF bcd.nPages > 1 THEN BEGIN Unlock[seg]; MoveFileSegment[seg, 1, bcd.nPages]; SwapIn[seg]; bcd ← FileSegmentAddress[seg]; END; PrintFileVersions[bcd]; END; END; ImageFormat.VersionID => BEGIN PrintVersion[bcd.version]; WriteChar[CR]; END; ENDCASE => BEGIN WriteString[" unknown version ID "L]; WriteDecimal[bcd.versionIdent]; WriteChar[CR]; END; Unlock[seg]; DeleteFileSegment[seg]; RETURN END; BufferObject: TYPE = RECORD [p: CARDINAL, s: STRING]; Buffer: TYPE = POINTER TO BufferObject; SourceDate: VersionProc = BEGIN OPEN AltoDefs; LI: TYPE = LONG INTEGER; date, tdate: TimeDefs.PackedTime; b: BufferObject; stream: StreamHandle; found: BOOLEAN ← FALSE; stream ← CreateByteStream[SegmentDefs.InsertFile[@info.fp, Read], Read]; 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 BEGIN DO [found, tdate] ← GetDate[@b ! TimeDefs.InvalidTime => EXIT]; IF ~found THEN EXIT; IF LOOPHOLE[tdate, LI] > LOOPHOLE[date, LI] THEN date ← tdate; ENDLOOP; WriteChar[' ]; PrintDate[TimeDefs.UnpackDT[date]]; END ELSE WriteString[" ?"L]; WriteChar[CR]; Storage.FreePages[b.s]; stream.destroy[stream]; RETURN END; GetDate: PROCEDURE [b: Buffer] RETURNS [BOOLEAN, TimeDefs.PackedTime] = BEGIN 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; END; RETURN[TRUE, TimeDefs.PackDT[u, TRUE]] END; NextItem[b, token]; ENDLOOP; RETURN[FALSE, TimeDefs.DefaultTime] 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 FastDirDefs.Cap[candidate[j]] # test[j] THEN EXIT; REPEAT FINISHED => RETURN[TRUE, i]; ENDLOOP; ENDLOOP; RETURN[FALSE, 0] END; IsNumber: PROCEDURE [s: STRING] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; 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 AppendChar[token, c]; ENDCASE => IF token.length # 0 THEN EXIT; ENDLOOP; RETURN END; PrintFileVersions: PROCEDURE [bcd: BcdBase] = BEGIN OPEN BcdDefs; line: STRING ← [40]; filename: SubStringDescriptor; fti: FTIndex; ftb: Base = LOOPHOLE[bcd + bcd.ftOffset]; stb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset]; FOR fti ← FIRST[FTIndex], fti + SIZE[FTRecord] UNTIL fti = bcd.ftLimit DO OPEN f: @ftb[fti]; filename ← SubStringDescriptor[@stb.string, f.name, stb.size[f.name]]; line.length ← 0; WriteChar[' ]; PrintVersion[f.version]; WriteChar[' ]; AppendSubString[line, @filename]; WriteLine[line]; ENDLOOP; RETURN END; PrintVersion: PROCEDURE [stamp: BcdDefs.VersionStamp] = BEGIN WriteChar[' ]; PrintDate[TimeDefs.UnpackDT[stamp.time]]; WriteChar[' ]; WriteOctal[stamp.net]; WriteChar['#]; WriteOctal[stamp.host]; WriteChar['#]; END; PrintDate: PROCEDURE [dt: UnpackedTime] = BEGIN tmp: STRING ← [40]; TimeDefs.AppendDayTime[tmp, dt]; WriteString[tmp]; END; -- command line stuff NextFile: PROCEDURE [token: STRING] RETURNS [BOOLEAN]; ReadFromCmdFile: PROCEDURE [token: STRING] RETURNS [BOOLEAN] = BEGIN RETURN[ReadCmdStream[cmdstream, token]] END; ReadFromKeyboard: PROCEDURE [token: STRING] RETURNS [BOOLEAN] = BEGIN WriteString["File: "L]; ReadID[token]; WriteChar[CR]; RETURN[token.length # 0]; END; ReadCmdStream: PROCEDURE [stream: StreamHandle, token: STRING] RETURNS [BOOLEAN] = BEGIN c: CHARACTER; token.length ← 0; WHILE ~stream.endof[stream] DO c ← stream.get[stream]; SELECT c FROM SP => IF token.length # 0 THEN EXIT; CR => EXIT; ENDCASE => AppendChar[token, c]; ENDLOOP; RETURN[token.length # 0]; END; cmdstream: StreamHandle; SetCommandInput: PROCEDURE = BEGIN cmdstream ← NewByteStream["Com.Cm"L, Read]; [] ← ReadCmdStream[cmdstream, name]; StripSwitches[name]; -- mesa.image [] ← ReadCmdStream[cmdstream, name]; IF interactive ← cmdstream.endof[cmdstream] THEN BEGIN cmdstream.destroy[cmdstream]; NextFile ← ReadFromKeyboard; END ELSE NextFile ← ReadFromCmdFile; RETURN END; StripSwitches: PROCEDURE [token: STRING] = BEGIN i, j: CARDINAL; option: BOOLEAN ← TRUE; FOR i IN [0..token.length) DO IF token[i] = '/ THEN BEGIN FOR j IN (i..token.length) DO SELECT token[ j] FROM '~, '- => option ← ~option; 'p, 'P => BEGIN pause ← option; option ← TRUE END; 'v, 'V => BEGIN verbose ← option; option ← TRUE END; ENDCASE; ENDLOOP; token.length ← i; END; ENDLOOP; RETURN END; -- main program VersionProc: TYPE = PROCEDURE [ info: FastDirDefs.ItemHandle, type: FastDirDefs.FileType]; dateproc: ARRAY FastDirDefs.FileType OF VersionProc = [SourceDate, BinaryVersion, SourceDate, BinaryVersion, BinaryVersion, BinaryVersion]; i: FastDirDefs.FileType; name: STRING ← [100]; interactive: BOOLEAN; pause, pauseDflt: BOOLEAN ← FALSE; verbose, verboseDflt: BOOLEAN ← FALSE; item: FastDirDefs.ItemHandle; SetCommandInput[]; FastDirDefs.ScanDir[FastDirDefs.AllFileSwitches, ]; pauseDflt ← pause; verboseDflt ← verbose; WriteChar[CR]; WHILE NextFile[name] DO pause ← pauseDflt; verbose ← verboseDflt; StripSwitches[name]; IF name.length = 0 THEN BEGIN pauseDflt ← pause; verboseDflt ← verbose; IF interactive THEN WriteChar[CR]; END ELSE BEGIN FastDirDefs.StripExtension[name, NIL]; IF ~interactive THEN WriteLine[name]; FOR i IN FastDirDefs.FileType DO IF (item ← FastDirDefs.LookupItem[name, i]) # NIL THEN BEGIN WriteChar[' ]; WriteString[FastDirDefs.GetExtension[i]]; WriteChar[':]; dateproc[i][item, i]; END; ENDLOOP; WriteChar[CR]; IF pause THEN [] ← ReadChar[]; END; ENDLOOP; ImageDefs.StopMesa[]; END.