<> <> <> <> <> <<>> DIRECTORY Atom USING [MakeAtom], Commander, CommandTool USING [ArgumentVector, Parse], Convert USING [RealFromRope], FS, Imager USING [Context, ConcatT], ImagerInterpress USING [Close, Create, DoPage, Ref], ImagerTransformation USING [Scale, PreRotate, PreScale, PreScale2, PreTranslate, Transformation], Interpress USING [DoPage, LogProc, Master, Open], IO, IPMaster USING [BYTE, CopySegment, Error, GetHeader, GetSkeleton, GetToken, ImagerVariable, IntFromSequenceData, MapParts, Node, Op, OpFromRope, PartActionType, PutInt, PutOp, PutRational, PutReal, PutSequence, PutSequenceText, RealFromSequenceData, RopeFromImagerVariable, RopeFromOp, SequenceType, Skeleton, SkipBytes, Token, Version, VersionFromRope], RefText USING [InlineAppendChar, ObtainScratch, ReleaseScratch, ReserveChars, TrustTextAsRope], Rope; IPUtilsImpl: CEDAR PROGRAM IMPORTS Atom, Commander, CommandTool, Convert, FS, Imager, ImagerInterpress, ImagerTransformation, Interpress, IO, IPMaster, RefText, Rope ~ BEGIN OPEN IPMaster; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; Version: TYPE ~ IPMaster.Version; UtilErrorDesc: TYPE ~ RECORD [code: ATOM, index: INT, explanation: ROPE]; UtilError: ERROR[error: UtilErrorDesc] ~ CODE; Open: PUBLIC PROC [name: ROPE] RETURNS [STREAM] ~ { stream: STREAM ~ FS.StreamOpen[name, $read, rawStreamOptions]; header: ROPE ~ IPMaster.GetHeader[stream, "Interpress/"]; encoding: ATOM _ NIL; version: Version _ [0, 0]; class: ATOM _ NIL; classVersion: Version _ [0, 0]; count: NAT _ 0; headerPart: IPMaster.PartActionType ~ { SELECT count FROM 0 => encoding _ Atom.MakeAtom[Rope.Substr[base, start, len]]; 1 => version _ IPMaster.VersionFromRope[base, start, len]; 2 => class _ Atom.MakeAtom[Rope.Substr[base, start, len]]; 3 => classVersion _ IPMaster.VersionFromRope[base, start, len]; ENDCASE => quit _ TRUE; count _ count+1; }; [] _ IPMaster.MapParts[base: header, delimiter: '/, action: headerPart]; SELECT encoding FROM $Xerox => NULL; ENDCASE => ERROR IPMaster.Error[[code: $invalidEncoding, explanation: IO.PutFR1["%g is not a valid encoding type.", IO.atom[encoding]]]]; RETURN[stream]; }; Create: PUBLIC PROC [name: ROPE] RETURNS [STREAM] ~ { stream: STREAM ~ FS.StreamOpen[name, $create]; stream.PutRope["Interpress/Xerox/2.1 "]; RETURN[stream]; }; ExtractPage: PROC [toName, fromName: ROPE, n: NAT] ~ { OPEN IPMaster; CopyNode: PROC [to: STREAM, from: STREAM, node: Node] ~ { CopySegment[to: to, from: from, start: node.index, length: node.length]; }; from: STREAM ~ Open[fromName]; skeleton: Skeleton ~ GetSkeleton[from]; to: STREAM ~ Create[toName]; PutOp[to, beginBlock]; CopyNode[to, from, skeleton.topBlock.preamble]; CopyNode[to, from, skeleton.topBlock[n-1]]; PutOp[to, endBlock]; IO.Close[to]; IO.Close[from]; }; State: TYPE ~ {null, op, id, plus, minus, star, int, rat1, rat2, rat, dot, real1, realF, real2, real3, realE, str1, vec1, com1, com2, file1, file2, note1, note2, single, string, vector, comment, insertFile, annotation}; FinalState: TYPE ~ State[single..State.LAST]; -- these terminate scanning <<>> OpenWritten: PROC [name: ROPE] RETURNS [STREAM] ~ { RETURN[FS.StreamOpen[name]] }; GetWrittenToken: PROC [stream: STREAM] RETURNS [state: State, rope: ROPE, index: INT] ~ { scratch: REF TEXT ~ RefText.ObtainScratch[100]; s: State _ null; r: ROPE _ NIL; i: INT _ 0; action: PROC [state: State, text: REF TEXT, index: INT] RETURNS [BOOL] ~ { s _ state; r _ Rope.FromRefText[text]; i _ index; RETURN[TRUE]; }; [] _ MapWrittenTokens[stream, scratch, action]; RefText.ReleaseScratch[scratch]; RETURN[state: s, rope: r, index: i]; }; MapWrittenTokens: PROC [stream: STREAM, buffer: REF TEXT, action: PROC [state: State, text: REF TEXT, index: INT] RETURNS [BOOL] ] RETURNS [quit: BOOL _ FALSE] ~ { char: CHAR; peeked: BOOL _ FALSE; Cleanup: PROC ~ { IF peeked THEN { IO.Backup[stream, char]; peeked _ FALSE } }; UNTIL quit DO state: State _ null; index: INT _ IO.GetIndex[stream]; text: REF TEXT _ buffer; text.length _ 0; UNTIL state IN FinalState DO -- scan a token IF peeked THEN { index _ index-1; peeked _ FALSE } ELSE char _ IO.GetChar[stream ! IO.EndOfStream => EXIT]; SELECT state FROM null => SELECT char FROM <=' => { index _ index+1; LOOP }; -- skip white space IN['0..'9] => state _ int; -- begin number IN['A..'Z] => state _ op; -- begin op IN['a..'z] => state _ id; -- begin identifier '< => state _ str1; -- begin string '( => state _ vec1; -- begin largeVector '+ => state _ plus; -- might begin number or insertfile '- => state _ minus; -- might begin number or annotation '* => state _ star; -- might begin comment '. => state _ dot; -- might begin real ENDCASE => state _ single; -- single char op => SELECT char FROM -- A..Z | op ( A..Z | 0..9 ) IN['A..'Z], IN['0..'9] => NULL; IN['a..'z], '- => state _ id; ENDCASE => GOTO Back; id => SELECT char FROM -- a..z | op ( a..z | - ) | id ( a..z | A..Z | 0..9 | - ) IN['a..'z], IN['A..'Z], IN['0..'9], '- => NULL; ENDCASE => GOTO Back; plus => SELECT char FROM -- + IN['0..'9] => state _ int; '+ => state _ file1; '. => state _ real1; ENDCASE => GOTO Back; minus => SELECT char FROM -- - IN['0..'9] => state _ int; '- => state _ note1; '. => state _ real1; ENDCASE => GOTO Back; star => SELECT char FROM -- * '* => state _ com1; ENDCASE => GOTO Back; int => SELECT char FROM -- ?( + | - ) 0..9 | int 0..9 IN['0..'9] => NULL; '/ => state _ rat1; '. => state _ realF; 'E, 'e => state _ real2; ENDCASE => GOTO Back; rat1 => SELECT char FROM -- int / IN['0..'9] => state _ rat; '+, '- => state _ rat2; ENDCASE => GOTO Back; rat2 => SELECT char FROM -- int / ( + | - ) IN['0..'9] => state _ rat; ENDCASE => GOTO Back; rat => SELECT char FROM -- int / ?( + | - ) 0..9 | rat 0..9 IN['0..'9] => NULL; ENDCASE => GOTO Back; dot => SELECT char FROM -- . IN['0..'9] => state _ realF; ENDCASE => GOTO Back; real1 => SELECT char FROM -- ( + | - ) . IN['0..'9] => state _ realF; ENDCASE => GOTO Back; realF => SELECT char FROM -- int . | ( + | - ) . 0..9 | realF 0..9 IN['0..'9] => NULL; 'E, 'e => state _ real2; ENDCASE => GOTO Back; real2 => SELECT char FROM -- ( int | realF ) ( E | e ) IN['0..'9] => state _ realE; '+, '- => state _ real3; ENDCASE => GOTO Back; real3 => SELECT char FROM -- ( int | realF ) ( E | e ) ( + | - ) IN['0..'9] => state _ realE; ENDCASE => GOTO Back; realE => SELECT char FROM -- ( int | realF ) ( E | e ) ?( + | - ) 0..9 | realE 0..9 IN['0..'9] => NULL; ENDCASE => GOTO Back; str1 => SELECT char FROM -- < ... '> => state _ string; -- < ... > ENDCASE => NULL; vec1 => SELECT char FROM -- ( ... ') => state _ vector; -- ( ... ) ENDCASE => NULL; com1 => SELECT char FROM -- * * ... '* => state _ com2; ENDCASE => NULL; com2 => SELECT char FROM -- * * ... * '* => state _ comment; -- * * ... * * ENDCASE => state _ com1; file1 => SELECT char FROM -- + + ... '+ => state _ file2; ENDCASE => NULL; file2 => SELECT char FROM -- + + ... + '+ => state _ insertFile; -- + + ... + + ENDCASE => state _ file1; note1 => SELECT char FROM -- - - ... '- => state _ note2; ENDCASE => NULL; note2 => SELECT char FROM -- - - ... - '- => state _ annotation; -- - - ... - - ENDCASE => state _ note1; ENDCASE => ERROR; -- unknown state text _ RefText.InlineAppendChar[to: text, from: char]; REPEAT Back => peeked _ TRUE; ENDLOOP; quit _ action[state: state, text: text, index: index ! UNWIND => Cleanup[]]; IF state=null THEN EXIT; ENDLOOP; IF peeked THEN Cleanup[]; }; IntFromText: PROC [text: REF TEXT, start: NAT _ 0, len: NAT _ NAT.LAST] RETURNS [INT] ~ { rem: NAT ~ text.length-start; sign: CHAR _ '+; card: LONG CARDINAL _ 0; magL: LONG CARDINAL ~ INT.LAST; magF: LONG CARDINAL ~ magL+1; FOR i: NAT IN[start..start+MIN[len, rem]) DO char: CHAR ~ text[i]; SELECT char FROM IN['0..'9] => IF card<=magF/10 THEN card _ card*10+(char-'0) ELSE GOTO Overflow; ENDCASE => IF i=start THEN sign _ char ELSE GOTO SyntaxError; ENDLOOP; SELECT sign FROM '+ => IF card<=magL THEN RETURN[card] ELSE GOTO Overflow; '- => IF card<=magF THEN RETURN[-card] ELSE GOTO Overflow; ENDCASE => GOTO SyntaxError; EXITS SyntaxError => ERROR --UtilError[$syntaxError]--; Overflow => ERROR --UtilError[$overflow]--; }; MapString: PROC [text: REF TEXT, action: PROC [CHAR]] ~ { state: {begin, body, esc1, esc2, esc3, end} _ begin; FOR i: NAT IN[0..text.length) DO char: CHAR ~ text[i]; val: [0..377B]; SELECT state FROM begin => SELECT char FROM '< => state _ body; ENDCASE => GOTO SyntaxError; body => SELECT char FROM '> => state _ end; '\\ => state _ esc1; ENDCASE => action[char]; esc1 => SELECT char FROM IN['0..'3] => { val _ char-'0; state _ esc2 }; 'N, 'n, 'R, 'r => { action['\n]; state _ body }; 'T, 't => { action['\t]; state _ body }; 'B, 'b => { action['\b]; state _ body }; 'F, 'f => { action['\f]; state _ body }; 'L, 'l => { action['\l]; state _ body }; '\\ => { action['\\]; state _ body }; '\' => { action['\']; state _ body }; '\" => { action['\"]; state _ body }; ENDCASE => GOTO SyntaxError; esc2 => SELECT char FROM IN['0..'7] => { val _ val*8+(char-'0); state _ esc3 }; ENDCASE => GOTO SyntaxError; esc3 => SELECT char FROM IN['0..'7] => { val _ val*8+(char-'0); action[VAL[val]]; state _ body }; ENDCASE => GOTO SyntaxError; end => GOTO SyntaxError; ENDCASE => ERROR; ENDLOOP; IF state#end THEN GOTO SyntaxError; EXITS SyntaxError => ERROR --UtilError[$syntaxError]--; }; <> <> <> <> <> <