DIRECTORY Atom, Convert, Imager, IO, RefText, Rope, SessionLog, SimpleFeedback, SlackProcess, Vector2; SessionLogImpl: CEDAR PROGRAM IMPORTS Atom, Convert, IO, RefText, Rope, SimpleFeedback EXPORTS SessionLog = BEGIN SyntaxError: SIGNAL [position: NAT, wasThere: Rope.ROPE, notThere: Rope.ROPE] = CODE; Complain: PROC [r: Rope.ROPE] = { SimpleFeedback.Append[$SessionLog, oneLiner, $Error, r]; SimpleFeedback.Blink[$SessionLog, $Error]; }; recentEnterActionError: BOOL ¬ FALSE; EnterAction: PUBLIC PROC [f: IO.STREAM, action: LIST OF REF ANY] = { ioError: Rope.ROPE; BEGIN ENABLE IO.Error => {ioError ¬ DescribeIOError[ec]; GOTO IOError}; FOR actionList: LIST OF REF ANY ¬ action, actionList.rest UNTIL actionList = NIL DO IF actionList.first=NIL THEN f.PutRope["\"\""] -- assume its an empty rope ELSE WITH actionList.first SELECT FROM atom: ATOM => f.PutF1["%g", [rope[Atom.GetPName[atom]]]]; n: REF INT => f.PutF1["%g", [integer[n­]]]; r: REF REAL => f.PutF1["%g", [real[r­]]]; c: REF CHAR => f.PutF1["'%g", [character[c­]]]; cd: REF CARD => f.PutF1["%g", [cardinal[cd­]]]; rope: Rope.ROPE => f.PutF1["\"%g\"", [rope[rope]]]; refText: REF TEXT => f.PutF1["\"%g\"", [text[refText]]]; refPoint: REF Vector2.VEC => f.PutF["[%g, %g]", [real[refPoint.x]], [real[refPoint.y]]]; refRect: REF Imager.Rectangle => f.PutFL["[%g %g %g %g]", LIST[[real[refRect.x]], [real[refRect.y]], [real[refRect.w]], [real[refRect.h]]] ]; ENDCASE; -- shouldn't happen, but don't do anything bad IF actionList.rest = NIL THEN f.PutChar['\n] ELSE f.PutChar[IO.SP]; ENDLOOP; recentEnterActionError ¬ FALSE; EXITS IOError => { IF NOT recentEnterActionError THEN Complain[Rope.Cat["IO.Error (", ioError, ") during SessionLog.EnterAction"]]; recentEnterActionError ¬ TRUE; -- don't Complain again until some call to EnterAction succeeds }; END; }; DescribeIOError: PROC [ec: IO.ErrorCode] RETURNS [rope: Rope.ROPE] = { rope ¬ SELECT ec FROM Null => "Null", NotImplementedForThisStream => "NotImplementedForThisStream", StreamClosed => "StreamClosed", Failure => "Failure", IllegalBackup => "IllegalBackup", BufferOverflow => "BufferOverflow", BadIndex => "BadIndex", SyntaxError => "SyntaxError", Overflow => "Overflow", PFInvalidCode => "PFInvalidCode", PFInvalidPFProcs => "PFInvalidPFProcs", PFCantBindConversionProc => "PFCantBindConversionProc", PFFormatSyntaxError => "PFFormatSyntaxError", PFTypeMismatch => "PFTypeMismatch", PFUnprintableValue => "PFUnprintableValue", ENDCASE => "unknown"; }; PlayScript: PUBLIC PROC [f: IO.STREAM, clientData: REF ANY, notifyProc: SlackProcess.ActionProc] = { endOfStream: BOOL ¬ FALSE; WHILE NOT endOfStream DO endOfStream ¬ PlayAction[f, clientData, notifyProc]; ENDLOOP; }; recentPlayActionError: BOOL ¬ FALSE; PlayAction: PUBLIC PROC [f: IO.STREAM, clientData: REF ANY, notifyProc: SlackProcess.ActionProc] RETURNS [endOfStream: BOOL ¬ FALSE] = { ioError: Rope.ROPE; BEGIN ENABLE IO.Error => {ioError ¬ DescribeIOError[ec]; GOTO IOError}; c: CHAR; mouseEvent: BOOL; point: Vector2.VEC; good: BOOL; token: REF ANY; actionList: LIST OF REF; ReadBlank[f]; c ¬ IO.GetChar[f !IO.EndOfStream => {endOfStream ¬ TRUE; CONTINUE}]; IF endOfStream THEN RETURN; IF c = '* THEN { atom: ATOM; refPoint: REF Vector2.VEC; good ¬ ReadHorizontalBlank[f]; IF NOT good THEN ERROR; point ¬ ReadPoint[f]; refPoint ¬ NEW[Vector2.VEC ¬ point]; token ¬ ReadSpacesAndToken[f]; atom ¬ NARROW[token]; UNTIL token = $EndOfLine DO token ¬ ReadSpacesAndToken[f]; ENDLOOP; actionList ¬ LIST[atom, refPoint]; } ELSE { mouseEvent ¬ FALSE; IO.Backup[f, c]; token ¬ $Start; UNTIL token = $EndOfLine DO token ¬ ReadSpacesAndToken[f]; IF token = $EndOfLine THEN LOOP; actionList ¬ AppendToken[token, actionList] ENDLOOP; }; notifyProc[clientData, actionList]; EXITS IOError => { IF NOT recentPlayActionError THEN Complain[Rope.Cat["IO.Error (", ioError, ") during SessionLog.PlayAction"]]; recentPlayActionError ¬ TRUE; -- don't Complain again until some call to PlayAction succeeds }; END; }; AppendToken: PROC [token: REF ANY, list: LIST OF REF ANY] RETURNS [newList: LIST OF REF ANY] = { l: LIST OF REF ANY ¬ list; IF l = NIL THEN RETURN[LIST[token]]; UNTIL l.rest = NIL DO l ¬ l.rest ENDLOOP; l.rest ¬ CONS[token, NIL]; newList ¬ list; }; IsDigitOrOp: PROC [c: CHAR] RETURNS [BOOL] = { RETURN[c IN ['0..'9] OR c = '- OR c = '+]; }; ReadSpacesAndToken: PROC [f: IO.STREAM] RETURNS [token: REF ANY] = { word: Rope.ROPE; good: BOOL; int: INT; card: CARD; real: REAL; firstChar: CHAR; good ¬ ReadHorizontalBlank[f]; IF NOT good THEN { token ¬ $EndOfLine; RETURN; }; firstChar ¬ IO.PeekChar[f]; SELECT TRUE FROM firstChar = '" => { token ¬ f.GetRopeLiteral[]; }; firstChar = '' => { [] ¬ f.GetChar[]; token ¬ NEW[CHAR ¬ f.GetChar[]]; }; firstChar = '[ => { x, y, w, h: REAL; nextChar: CHAR; ReadRope[f, "["]; x ¬ ReadBlankAndReal[f]; nextChar ¬ IO.PeekChar[f]; SELECT TRUE FROM nextChar = ', => { ReadRope[f, ","]; y ¬ ReadBlankAndReal[f]; ReadRope[f, "]"]; token ¬ NEW[Vector2.VEC ¬ [x, y]]; }; ENDCASE => { y ¬ ReadBlankAndReal[f]; w ¬ ReadBlankAndReal[f]; h ¬ ReadBlankAndReal[f]; ReadRope[f, "]"]; token ¬ NEW[Imager.Rectangle ¬ [x, y, w, h]]; }; }; IsDigitOrOp[firstChar] => { word ¬ ReadBlankAndWord[f]; IF Rope.Find[word, "."] = -1 THEN { -- an integer IF Rope.Fetch[word, 0] = '- THEN { int ¬ IO.GetInt[IO.RIS[word]]; token ¬ NEW[INT ¬ int]; } ELSE { card ¬ IO.GetCard[IO.RIS[word]]; IF card > 2147483647 THEN token ¬ NEW[CARD ¬ card] -- too big to fit in an INT ELSE token ¬ NEW[INT ¬ card]; }; } ELSE { real ¬ IO.GetReal[IO.RIS[word]]; token ¬ NEW[REAL ¬ real]; }; }; ENDCASE => { word ¬ ReadBlankAndWord[f]; token ¬ Atom.MakeAtom[word]; }; }; ReadLine: PROC [f: IO.STREAM] RETURNS [line: Rope.ROPE] = { LineBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = { SELECT char FROM IO.CR, IO.LF =>RETURN [break]; ENDCASE => RETURN [other]; }; end: BOOL ¬ FALSE; [line, ----] ¬ IO.GetTokenRope[f, LineBreakProc !IO.EndOfStream => {end ¬ TRUE; CONTINUE}]; IF end THEN {line ¬ NIL; RETURN}; }; ReadSpaceAndChar: PROC [f: IO.STREAM] RETURNS [token: REF ANY] = { c: CHAR; good: BOOL; c ¬ IO.GetChar[f !IO.EndOfStream => ERROR]; c ¬ IO.GetChar[f !IO.EndOfStream => ERROR]; good ¬ ReadHorizontalBlank[f]; IF good THEN ERROR; token ¬ NEW[CHAR ¬ c]; }; ReadBlank: PROC [f: IO.STREAM] = { [] ¬ IO.SkipWhitespace[f, TRUE]; }; ReadHorizontalBlank: PROC [f: IO.STREAM] RETURNS [good: BOOL] = { HorizontalBlankProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM IO.TAB, IO.SP => RETURN [other]; ENDCASE => RETURN [break]; }; whiteSpace: Rope.ROPE; c: CHAR; end: BOOL ¬ FALSE; good ¬ TRUE; [whiteSpace, ----] ¬ IO.GetTokenRope[f, HorizontalBlankProc !IO.EndOfStream => {end ¬ TRUE; CONTINUE}]; IF end THEN {good ¬ FALSE; RETURN}; c ¬ Rope.Fetch[whiteSpace, 0]; SELECT c FROM IO.CR, IO.LF => good ¬ FALSE; IO.TAB, IO.SP => { -- there was some whitespace nextC: CHAR ¬ IO.PeekChar[f]; IF nextC = IO.CR OR nextC = IO.LF THEN { -- the whitespace comes at the end of a line good ¬ FALSE; [] ¬ IO.GetChar[f]; } ELSE good ¬ TRUE; -- normal whitespace }; ENDCASE => {good ¬ TRUE; IO.Backup[f, c]}; -- there was no whitespace }; ReadBlankAndReal: PROC [f: IO.STREAM] RETURNS [r: REAL] = { ReadBlank[f]; r ¬ ReadReal[f]; }; ReadReal: PROC [f: IO.STREAM] RETURNS [r: REAL] = { RealBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM '), '], ', => RETURN [break]; IO.CR, IO.LF =>RETURN [break]; IO.SP => RETURN [break]; ENDCASE => RETURN [other]; }; realText, buffer: REF TEXT; end: BOOL ¬ FALSE; buffer ¬ RefText.ObtainScratch[50]; [realText, ----] ¬ IO.GetToken[f, RealBreakProc, buffer !IO.EndOfStream => {end ¬ TRUE; CONTINUE}]; IF end THEN {r ¬ 0.0; RETURN}; IF RefText.Find[realText, ".", 0, FALSE] = -1 THEN realText ¬ RefText.Append[realText, ".0"]; r ¬ Convert.RealFromRope[RefText.TrustTextAsRope[realText]]; RefText.ReleaseScratch[buffer]; }; ReadPoint: PROC [f: IO.STREAM] RETURNS [point: Vector2.VEC] = { ReadBlank[f]; ReadRope[f, "["]; point.x ¬ ReadBlankAndReal[f]; ReadRope[f, ","]; point.y ¬ ReadBlankAndReal[f]; ReadRope[f, "]"]; }; ReadRope: PROC [f: IO.STREAM, rope: Rope.ROPE] = { c: CHAR; endofstream: BOOL ¬ FALSE; FOR i: INT IN[1..Rope.Length[rope]] DO c ¬ IO.GetChar[f ! IO.EndOfStream => {endofstream ¬ TRUE; CONTINUE}]; IF endofstream THEN SIGNAL SyntaxError [IO.GetIndex[f], NIL, rope]; IF NOT c = Rope.Fetch[rope,i-1] THEN SIGNAL SyntaxError [IO.GetIndex[f], Rope.FromChar[c], rope]; ENDLOOP; }; ReadBlankAndWord: PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { ReadBlank[f]; word ¬ ReadWord[f]; }; ReadWord: PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { WordBreakProc: PROC [char: CHAR] RETURNS [IO.CharClass] = { SELECT char FROM IO.TAB => RETURN [break]; IO.CR, IO.LF =>RETURN [break]; IO.SP => RETURN [break]; ', => RETURN [break]; '] => RETURN [break]; ') => RETURN [break]; ENDCASE => RETURN [other]; }; [word, ----] ¬ IO.GetTokenRope[f, WordBreakProc !IO.EndOfStream => {word ¬ NIL; CONTINUE}]; }; END. ώ SessionLogImpl.mesa Copyright Σ 1986, 1987, 1992 by Xerox Corporation. All rights reserved. Last edited by Bier on November 4, 1987 4:39:10 pm PST Pier, October 28, 1987 11:39:17 am PST Bier, March 13, 1991 5:26 pm PST Michael Plass, March 25, 1992 11:27 am PST Christian Jacobi, October 2, 1992 11:46 am PDT Contents: Routines recording and playing back a record of an interactive session. SessionLog is intended to be used with SlackProcess in systems built according to the new user interface architecture (see SlackProcessDoc and AtomButtonsDoc). Recording Playing Back For compatibility with the old style of script. End of compatibility. Parsing Reads a rope UNTIL is encountered. Reads, 's, 's, and 's until something else is encountered. Doesn't mind if no white space characters are found. Treats comments as white space. Reads 's, and 's until something else is encountered. Returns good = FALSE if a CR or LF is encountered before non-white space A convenience function. Equivalent to ReadBlank[f]; r _ ReadReal[f]; Reads digits up to the next ), ], , or . Leaves these terminators on the stream. Assumes the next rope on the stream will be of the form "[,]". Removes the given rope from the top of the stream. Used to remove formatting words and phrases from 3d files. We are not interested in these strings but only in the data in between them. Signals SyntaxError if some other rope is on top. Used to read in a rope which is data. Κs•NewlineDelimiter –(cedarcode) style™code™Kšœ Οeœ=™HK™6K™&K™ K™*K™.K™KšΟnœλ™σK™—šΟk ˜ KšœŸœC˜\—K˜šžœŸœŸ˜KšŸœŸœ˜8KšŸœ Ÿ˜—K˜Iprocš ž œŸœ ŸœŸœŸœŸœ˜UIheadšΟb ™ šžœŸœ Ÿœ˜!K•StartOfExpansion-[message: ROPE, clearFirst: BOOL _ FALSE]˜8K–-[message: ROPE, clearFirst: BOOL _ FALSE]˜*K˜K˜—šœŸœŸœ˜%K˜—šž œŸœŸœŸœŸœ ŸœŸœŸœ˜DKšœŸœ˜šŸ˜KšŸœŸœ*Ÿœ ˜AšŸœ ŸœŸœŸœŸœŸœŸœŸ˜SKšŸœŸœŸœΟc˜JšŸœŸœŸœŸ˜&KšœŸœ/˜9KšœŸœŸœ!˜+KšœŸœŸœ˜)KšœŸœŸœ$˜/KšœŸœŸœ#˜/Kšœ Ÿœ$˜3Kšœ ŸœŸœ'˜8Kšœ Ÿœ Ÿœ?˜XKšœ Ÿœ.ŸœO˜KšŸœ‘.˜7—KšŸœŸœŸœ˜,KšŸœ ŸœŸœ˜KšŸœ˜—KšœŸœ˜šŸ˜˜ šŸœŸœŸ˜"K˜M—KšœŸœ‘?˜^K˜——KšŸœ˜—K˜K˜—šžœŸœŸœ Ÿœ˜FšœŸœŸ˜K˜K˜=K˜K˜K˜!K˜#K˜K˜K˜K˜!K˜'K˜7K˜-K˜#K˜+KšŸœ˜—K˜—Mš  ™ šž œŸœŸœŸœŸœŸœŸœ*˜dKšœ ŸœŸœ˜šŸœŸœ Ÿ˜K˜4KšŸœ˜—K˜K˜—šœŸœŸœ˜$K˜—šž œŸœŸœŸœŸœŸœŸœ'ŸœŸœŸœ˜ˆKšœŸœ˜šŸ˜KšŸœŸœ*Ÿœ ˜AKšœŸœ˜Kšœ Ÿœ˜KšœŸœ˜KšœŸœ˜ KšœŸœŸœ˜Kšœ ŸœŸœŸœ˜K˜K˜ Kš /™/šœŸœ ˜KšœŸœŸœŸœ˜3—KšŸœ ŸœŸœ˜šŸœŸœ˜KšœŸœ˜ Kšœ Ÿœ Ÿœ˜K˜KšŸœŸœŸœŸœ˜K˜Kšœ Ÿœ Ÿœ ˜$K˜KšœŸœ˜šŸœŸ˜K˜KšŸœ˜—Kšœ Ÿœ˜"K˜—Kš ™šŸœ˜Kšœ Ÿœ˜KšŸœ˜K˜šŸœŸ˜K˜KšŸœŸœŸœ˜ K˜+KšŸœ˜—K˜—K˜#šŸ˜˜ šŸœŸœŸ˜!K˜L—KšœŸœ‘>˜\K˜——KšŸœ˜—K˜K˜—šž œŸœ ŸœŸœŸœŸœŸœŸœŸœ ŸœŸœŸœŸœ˜`Kš œŸœŸœŸœŸœ˜Kš ŸœŸœŸœŸœŸœ ˜$KšŸœ ŸœŸœ Ÿœ˜)Kšœ ŸœŸœ˜K˜K˜—K˜™K™—š ž œŸœŸœŸœŸœ˜.KšŸœŸœ ŸœŸœ ˜*K˜K˜—šžœŸœŸœŸœŸœ ŸœŸœ˜DKšœ Ÿœ˜KšœŸœ˜ KšœŸœ˜ KšœŸœ˜ KšœŸœ˜ Kšœ Ÿœ˜K˜šŸœŸœŸœ˜K˜KšŸœ˜K˜—Kšœ Ÿœ ˜KšŸœŸœŸ˜˜Kšœ  œ˜K˜—˜K˜KšœŸœŸœ˜ K˜—˜Kšœ Ÿœ˜Kšœ Ÿœ˜L˜L˜Lšœ Ÿœ ˜šŸœŸœŸ˜˜L˜L˜L˜KšœŸœ Ÿœ ˜"L˜—šŸœ˜ L˜L˜L˜L˜KšœŸœ"˜-L˜——K˜—˜Kšœ œ˜šŸœŸœ‘ ˜1– [base: ROPE, index: INT _ 0]šŸœŸœ˜"KšœŸœŸœŸœ˜KšœŸœŸœ˜K˜—šŸœ˜KšœŸœ ŸœŸœ˜ Kš ŸœŸœ ŸœŸœ ‘˜NKšŸœ ŸœŸœ ˜K˜—K˜—šŸœ˜KšœŸœ ŸœŸœ˜ KšœŸœŸœ ˜K˜—K˜—šŸœ˜ Kšœ œ˜K˜K˜—K˜K˜—š žœŸœŸœŸœŸœ Ÿœ˜;Lšœ ŸœŸœ™'š ž œŸœŸœŸœŸœŸœ˜@šŸœŸ˜Lš ŸœŸœŸœŸœŸœ ˜LšŸœŸœ ˜—L˜—LšœŸœŸœ˜šœ‘œŸœ˜/LšœŸœŸœŸœ˜+—LšŸœŸœ ŸœŸœ˜!L˜L˜—šžœŸœŸœŸœŸœ ŸœŸœ˜BKšœŸœ˜KšœŸœ˜ KšœŸœ ŸœŸœ˜+KšœŸœ ŸœŸœ˜+K˜KšŸœŸœŸœ˜KšœŸœŸœ˜K˜K˜—šž œŸœŸœŸœ˜"L™‘LšœŸœŸœ˜ L˜L˜—š žœŸœŸœŸœŸœŸœ˜AL™ŒšžœŸœŸœŸœŸœŸœŸœ˜NšŸœŸ˜Lš ŸœŸœŸœŸœŸœ ˜ LšŸœŸœ ˜—L˜—LšœŸœ˜LšœŸœ˜LšœŸœŸœ˜LšœŸœ˜ šœ ‘œŸœ$˜;LšœŸœŸœŸœ˜+—LšŸœŸœ ŸœŸœ˜#L˜šŸœŸ˜ Lš ŸœŸœŸœŸœ Ÿœ˜š ŸœŸœŸœŸœ‘˜/LšœŸœŸœ ˜šŸœ ŸœŸœŸœ ŸœŸœŸœ‘,˜ULšœŸœ˜ LšœŸœ ˜L˜—LšŸœŸœ‘˜&L˜—LšŸœ ŸœŸœ‘˜E—L˜L˜K™—š žœŸœŸœŸœŸœŸœ˜;L™EL˜ L˜L˜L˜—š žœŸœŸœŸœŸœŸœ˜3L™dšž œŸœŸœŸœŸœŸœŸœ˜HšŸœŸ˜LšœŸœ ˜Lš ŸœŸœŸœŸœŸœ ˜LšŸœŸœŸœ ˜LšŸœŸœ ˜—L˜—LšœŸœ˜LšœŸœŸœ˜L˜#šœ ‘œŸœ"˜7LšœŸœŸœŸœ˜+—LšŸœŸœ Ÿœ˜LšŸœ ŸœŸœ+˜]L˜