<> <> <> DIRECTORY Atom, FS, GGError, GGInterfaceTypes, GGModelTypes, GGSessionLog, GGUserInput, IO, Rope; GGSessionLogImpl: CEDAR PROGRAM IMPORTS Atom, FS, GGError, GGUserInput, IO, Rope EXPORTS GGSessionLog = BEGIN CharClass: TYPE = IO.CharClass; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Point: TYPE = GGModelTypes.Point; globalStream: IO.STREAM; SetStream: PUBLIC PROC [stream: IO.STREAM] = { globalStream _ stream; }; EnterAction: PUBLIC PROC [point: Point, action: LIST OF REF ANY, mouseEvent: BOOL] = { IF mouseEvent THEN globalStream.PutF["* [%g, %g] ", [real[point[1]]], [real[point[2]]] ]; FOR actionList: LIST OF REF ANY _ action, actionList.rest UNTIL actionList = NIL DO WITH actionList.first SELECT FROM atom: ATOM => globalStream.PutF["%g", [rope[Atom.GetPName[atom]]]]; n: REF INT => globalStream.PutF["%g", [integer[n^]]]; r: REF REAL => globalStream.PutF["%g", [real[r^]]]; ENDCASE => ERROR; IF actionList.rest = NIL THEN globalStream.PutChar[IO.CR] ELSE globalStream.PutChar[IO.SP]; ENDLOOP; }; OpenFile: PROC [name: Rope.ROPE] RETURNS [f: IO.STREAM, success: BOOL] = { success _ TRUE; <> <<1) File doesn't exist. Print error message.>> <<2) File does exist. File it in. Succeed.>> f _ FS.StreamOpen[name ! FS.Error => { IF error.group = user THEN { success _ FALSE; GGError.Append["Picture file problem: ", oneLiner]; GGError.Append[error.explanation, oneLiner]; } ELSE ERROR; CONTINUE}]; }; PlaybackFromFile: PUBLIC PROC [name: Rope.ROPE, gargoyleData: GargoyleData] = { wdir, fullName: Rope.ROPE; success: BOOL; f: IO.STREAM; wdir _ gargoyleData.originalWorkingDirectory; success _ TRUE; [fullName,,] _ FS.ExpandName[name, wdir ! FS.Error => IF error.group = user THEN { success _ FALSE; CONTINUE; } ]; IF NOT success THEN RETURN; [f, success] _ OpenFile[fullName]; IF NOT success THEN RETURN; WHILE success DO success _ PlayAction[f, gargoyleData]; ENDLOOP; }; AppendAtom: PROC [atom: ATOM, list: LIST OF REF ANY] RETURNS [newList: LIST OF REF ANY] = { l: LIST OF REF ANY _ list; IF l = NIL THEN RETURN[LIST[atom]]; UNTIL l.rest = NIL DO l _ l.rest ENDLOOP; l.rest _ CONS[atom, NIL]; newList _ list; }; 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; }; PlayAction: PROC [f: IO.STREAM, gargoyleData: GargoyleData] RETURNS [success: BOOL] = { c: CHAR; mouseEvent: BOOL; point: Point; good: BOOL; token: REF ANY; action: LIST OF REF ANY; success _ TRUE; c _ IO.GetChar[f !IO.EndOfStream => {success _ FALSE; CONTINUE}]; IF NOT success THEN RETURN; IF c = '* THEN { good _ ReadHorizontalBlank[f]; IF NOT good THEN ERROR; point _ ReadPoint[f]; mouseEvent _ TRUE } ELSE { mouseEvent _ FALSE; IO.Backup[f, c]; }; token _ $Start; UNTIL token = $EndOfLine DO [token] _ ReadSpacesAndAtomOrNum[f]; IF token = $EndOfLine THEN LOOP ELSE action _ AppendToken[token, action] ENDLOOP; GGUserInput.PlayAction[point, action, mouseEvent, gargoyleData]; }; ReadPoint: PUBLIC PROC [f: IO.STREAM] RETURNS [point: Point] = { <,]".>> ReadRope[f, "["]; point[1] _ ReadBlankAndReal[f]; ReadRope[f, ","]; point[2] _ ReadBlankAndReal[f]; ReadRope[f, "]"]; }; ReadBlankAndReal: PUBLIC PROC [f: IO.STREAM] RETURNS [r: REAL] = { <> ReadBlank[f]; r _ ReadReal[f]; }; ReadReal: PUBLIC PROC [f: IO.STREAM] RETURNS [r: REAL] = { <, or . Leaves these terminators on the stream.>> realRope: Rope.ROPE; end: BOOL _ FALSE; [realRope, ----] _ IO.GetTokenRope[f, RealBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {r _ 0.0; RETURN}; IF Rope.Find[realRope, ".", 0, FALSE] = -1 THEN realRope _ Rope.Concat[realRope, ".0"]; r _ IO.GetReal[IO.RIS[realRope]]; }; RealBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM '], ', => RETURN [break]; IO.CR =>RETURN [break]; IO.SP => RETURN [break]; ENDCASE => RETURN [other]; }; ReadBlankAndNAT: PUBLIC PROC [f: IO.STREAM] RETURNS [n: NAT] = { <> ReadBlank[f]; n _ ReadNAT[f]; }; ReadHorizontalBlank: PUBLIC PROC [f: IO.STREAM] RETURNS [good: BOOL] = { <'s, and 's until something else is encountered. Returns good = FALSE if a CR is encountered before anything else>> 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 => {good _ FALSE; RETURN}; IO.TAB, IO.SP => {good _ TRUE; RETURN}; ENDCASE => {good _ TRUE; IO.Backup[f, c]; RETURN}; }; HorizontalBlankProc: SAFE PROC [char: CHAR] RETURNS [CharClass] = { SELECT char FROM IO.TAB, IO.SP => RETURN [other]; ENDCASE => RETURN [break]; }; IsDigit: PROC [c: CHAR] RETURNS [BOOL] = { RETURN[c IN ['0..'9]]; }; ReadSpacesAndAtomOrNum: PUBLIC PROC [f: IO.STREAM] RETURNS [token: REF ANY] = { word: Rope.ROPE; good: BOOL; int: INT; real: REAL; good _ ReadHorizontalBlank[f]; IF NOT good THEN { token _ $EndOfLine; RETURN; }; word _ ReadWord[f]; IF IsDigit[Rope.Fetch[word, 0]] THEN { IF Rope.Find[word, "."] = -1 THEN { -- an integer int _ IO.GetInt[IO.RIS[word]]; token _ NEW[INT _ int]; } ELSE { real _ IO.GetReal[IO.RIS[word]]; token _ NEW[REAL _ real]; }; } ELSE { token _ Atom.MakeAtom[word]; }; }; ReadBlankAndWord: PUBLIC PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { <> ReadBlank[f]; word _ ReadWord[f]; }; ReadBlankAndRope: PUBLIC PROC [f: IO.STREAM, rope: Rope.ROPE] = { ReadBlank[f]; ReadRope[f, rope]; }; ReadBlank: PUBLIC PROC [f: IO.STREAM] = { <'s, 's, and 's until something else is encountered. Doesn't mind if no white space characters are found. Treats comments as white space.>> [] _ IO.SkipWhitespace[f, TRUE]; }; ReadWord: PUBLIC PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { <, , or are encountered. Used to read in a rope which is data. ie the name of a coordinate system from a 3d file.>> [word, ----] _ IO.GetTokenRope[f, WordBreakProc !IO.EndOfStream => {word _ NIL; CONTINUE}]; }; WordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.TAB => RETURN [break]; IO.CR =>RETURN [break]; IO.SP => RETURN [break]; ', => RETURN [break]; '] => RETURN [break]; ') => RETURN [break]; ENDCASE => RETURN [other]; }; ReadNAT: PUBLIC PROC [f: IO.STREAM] RETURNS [n: NAT] = { <, . Leaves these terminators on the stream.>> end: BOOL _ FALSE; intRope: Rope.ROPE; [intRope, ----] _ IO.GetTokenRope[f, NATBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {n _ 1; RETURN}; n _ IO.GetInt[IO.RIS[intRope]]; }; NATBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM '], IO.CR, IO.SP, '., ', => RETURN [break]; ENDCASE => RETURN [other]; }; RopeNotOnTop: PUBLIC SIGNAL [position: NAT, wasThere: Rope.ROPE, notThere: Rope.ROPE] = CODE; ReadRope: PUBLIC 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 RopeNotOnTop [IO.GetIndex[f], NIL, rope]; IF NOT c = Rope.Fetch[rope,i-1] THEN SIGNAL RopeNotOnTop [IO.GetIndex[f], Rope.FromChar[c], rope]; ENDLOOP; }; END.