| % |
| % Dump a PostScript object, occasionally in a form that can be sent back |
| % through the interpreter. Similiar to Adobe's == procedure, but output |
| % is usually easier to read. No binding so operators like rcheck and exec |
| % can be conviently redefined. |
| % |
| |
| /GrabitDict 100 dict dup begin |
| |
| /recursive true def |
| /scratchstring 200 string def |
| /slowdown 100 def |
| |
| /column 0 def |
| /lastcolumn 80 def |
| /level 0 def |
| /multiline 100 array def |
| /nextname 0 def |
| /arraylength 0 def |
| /lengthonly false def |
| |
| /GrabitSetup { |
| counttomark {OmitNames exch true put} repeat pop |
| 0 0 moveto % for hardcopy output |
| } def |
| |
| /OmitNames 30 dict def % ignore these names |
| /OtherDicts 200 dict def % unrecognized dictionaries |
| |
| % |
| % All strings returned to the host go through Print. First pass through an |
| % array has lengthonly set to true. |
| % |
| |
| /Print { |
| dup type /stringtype ne {scratchstring cvs} if |
| lengthonly { |
| length arraylength add /arraylength exch def |
| }{ |
| dup length column add /column exch def |
| print flush |
| slowdown {1 pop} repeat |
| } ifelse |
| } def |
| |
| /Indent {level {( ) Print} repeat} def |
| /Newline {(\n) Print lengthonly not {/column 0 def} if} def |
| |
| /NextLevel {/level level 1 add def multiline level 0 put} def |
| /LastLevel {/level level 1 sub def} def |
| |
| % |
| % Make a unique name for each unrecognized dictionary and remember the name |
| % and dictionary in OtherDicts. |
| % |
| |
| /Register { |
| dup type /dicttype eq { |
| /nextname nextname 1 add def |
| dup (UnknownDict ) dup |
| (UnknownDict) length nextname ( ) cvs putinterval |
| 0 (UnknownDict) length nextname ( ) cvs length add getinterval cvn |
| exch OtherDicts 3 1 roll put |
| } if |
| } def |
| |
| % |
| % Replace array or dictionary values by known names. Lookups are in the |
| % standard PostScript dictionaries and in OtherDicts. If found replace |
| % the value by the name and make it executable so nametype omits the |
| % leading /. |
| % |
| |
| /Replace { |
| false |
| 1 index type /dicttype eq {pop true} if |
| 1 index type /arraytype eq 2 index xcheck not and {pop true} if |
| { |
| false |
| [userdict systemdict statusdict serverdict OtherDicts] { |
| { |
| 3 index eq |
| {exch pop exch pop cvx true exit} |
| {pop} |
| ifelse |
| } forall |
| dup {exit} if |
| } forall |
| pop |
| } if |
| } def |
| |
| % |
| % Simple type handlers. In some cases (e.g. savetype) what's returned can't |
| % be sent back through the interpreter. |
| % |
| |
| /booleantype {{(true )}{(false )} ifelse Print} def |
| /marktype {pop (mark ) Print} def |
| /nulltype {pop (null ) Print} def |
| /integertype {Print ( ) Print} def |
| /realtype {Print ( ) Print} def |
| /filetype {pop (-file- ) Print} def |
| /fonttype {pop (-fontID- ) Print} def |
| /savetype {pop (-saveobj- ) Print} def |
| |
| % |
| % Special formatting for operators is enabled if the flag in multiline |
| % (for the current level) is set to 1. In that case each operator, after |
| % being printed, is looked up in OperatorDict. If found the value is used |
| % as an index into the OperatorProcs array and the object at that index |
| % is retrieved and executed. Currently only used to choose the operators |
| % that end a line. |
| % |
| |
| /operatortype { |
| dup Print ( ) Print |
| multiline level get 1 eq { |
| scratchstring cvs cvn dup OperatorDict exch known { |
| OperatorDict exch get |
| OperatorProcs exch get exec |
| }{ |
| pop |
| column lastcolumn gt {Newline Indent} if |
| } ifelse |
| }{pop} ifelse |
| } def |
| |
| % |
| % Executable names are passed to operatortype. Non-executable names get a |
| % leading /. |
| % |
| |
| /nametype { |
| dup xcheck { |
| operatortype |
| }{ |
| (/) Print Print ( ) Print |
| } ifelse |
| } def |
| |
| % |
| % Arrays are processed in two passes. The first computes the length of the |
| % string returned to the host without any special formatting. If it extends |
| % past the last column special formatting is enabled by setting a flag in |
| % array multiline. Arrays are processed in a for loop so the last element |
| % easily recognized. At that point special fortmatting is disabled. |
| % |
| |
| /packedarraytype {arraytype} def |
| |
| /arraytype { |
| NextLevel |
| lengthonly not { |
| /lengthonly true def |
| /arraylength 0 def |
| dup dup type exec |
| arraylength 20 gt arraylength column add lastcolumn gt and { |
| multiline level 1 put |
| } if |
| /lengthonly false def |
| } if |
| |
| dup rcheck not { |
| (-array- ) Print pop |
| }{ |
| dup xcheck {({)}{([)} ifelse Print |
| multiline level get 0 ne {Newline Indent}{( ) Print} ifelse |
| 0 1 2 index length 1 sub { |
| 2 copy exch length 1 sub eq multiline level get 1 eq and { |
| multiline level 2 put |
| } if |
| 2 copy get exch pop |
| dup type /dicttype eq { |
| Replace |
| dup type /dicttype eq { |
| dup Register Replace |
| recursive { |
| 2 copy cvlit |
| /def load 3 1 roll |
| count 3 roll |
| } if |
| exch pop |
| } if |
| } if |
| dup type exec |
| dup xcheck not multiline level get 1 eq and { |
| 0 index type /arraytype eq |
| 1 index type /packedarray eq or |
| 1 index type /stringtype eq or {Newline Indent} if |
| } if |
| } for |
| multiline level get 0 ne {Newline LastLevel Indent NextLevel} if |
| xcheck {(} )}{(] )} ifelse Print |
| } ifelse |
| LastLevel |
| } def |
| |
| % |
| % Dictionary handler. Try to replace the value by a name before processing |
| % the dictionary. |
| % |
| |
| /dicttype { |
| dup |
| rcheck not { |
| (-dictionary- ) Print pop |
| }{ |
| dup maxlength Print ( dict dup begin) Print Newline |
| NextLevel |
| { |
| 1 index OmitNames exch known { |
| pop pop |
| }{ |
| Indent |
| Replace % arrays and dicts by known names |
| Register % new dictionaries in OtherDicts |
| exch |
| cvlit dup type exec % key first - force a / |
| dup type exec % then the value |
| (def) Print Newline |
| } ifelse |
| } forall |
| LastLevel |
| Indent |
| (end ) Print |
| } ifelse |
| } def |
| |
| % |
| % Strings containing characters not in AsciiDict are returned in hex. All |
| % others are ASCII strings and use AsciiDict for character mapping. |
| % |
| |
| /onecharstring ( ) def |
| /twocharstring ( ) def |
| |
| /stringtype { |
| dup |
| rcheck not { |
| (-string- ) Print |
| }{ |
| /hexit false def |
| dup { |
| onecharstring 0 3 -1 roll put |
| AsciiDict onecharstring cvn known not { |
| /hexit true def exit |
| } if |
| } forall |
| |
| hexit {(<)}{(\()} ifelse Print |
| 0 1 2 index length 1 sub { |
| 2 copy 1 getinterval exch pop |
| hexit { |
| 0 get /n exch def |
| n -4 bitshift 16#F and 16 twocharstring cvrs pop |
| n 16#F and twocharstring 1 1 getinterval 16 exch cvrs pop |
| twocharstring |
| }{cvn AsciiDict exch get} ifelse |
| Print |
| column lastcolumn gt { |
| hexit not {(\\) Print} if |
| Newline |
| } if |
| } for |
| hexit {(> )}{(\) )} ifelse Print |
| } ifelse |
| pop |
| } def |
| |
| % |
| % ASCII characters and replacement strings. Ensures the returned string will |
| % reproduce the original when passed through the scanner. Strings containing |
| % characters not in this list should be returned as hex strings. |
| % |
| |
| /AsciiDict 128 dict dup begin |
| (\n) cvn (\\n) def |
| (\r) cvn (\\r) def |
| (\t) cvn (\\t) def |
| (\b) cvn (\\b) def |
| (\f) cvn (\\f) def |
| ( ) cvn ( ) def |
| (!) cvn (!) def |
| (") cvn (") def |
| (#) cvn (#) def |
| ($) cvn ($) def |
| (%) cvn (\\%) def |
| (&) cvn (&) def |
| (') cvn (') def |
| (\() cvn (\\\() def |
| (\)) cvn (\\\)) def |
| (*) cvn (*) def |
| (+) cvn (+) def |
| (,) cvn (,) def |
| (-) cvn (-) def |
| (.) cvn (.) def |
| (/) cvn (/) def |
| (0) cvn (0) def |
| (1) cvn (1) def |
| (2) cvn (2) def |
| (3) cvn (3) def |
| (4) cvn (4) def |
| (5) cvn (5) def |
| (6) cvn (6) def |
| (7) cvn (7) def |
| (8) cvn (8) def |
| (9) cvn (9) def |
| (:) cvn (:) def |
| (;) cvn (;) def |
| (<) cvn (<) def |
| (=) cvn (=) def |
| (>) cvn (>) def |
| (?) cvn (?) def |
| (@) cvn (@) def |
| (A) cvn (A) def |
| (B) cvn (B) def |
| (C) cvn (C) def |
| (D) cvn (D) def |
| (E) cvn (E) def |
| (F) cvn (F) def |
| (G) cvn (G) def |
| (H) cvn (H) def |
| (I) cvn (I) def |
| (J) cvn (J) def |
| (K) cvn (K) def |
| (L) cvn (L) def |
| (M) cvn (M) def |
| (N) cvn (N) def |
| (O) cvn (O) def |
| (P) cvn (P) def |
| (Q) cvn (Q) def |
| (R) cvn (R) def |
| (S) cvn (S) def |
| (T) cvn (T) def |
| (U) cvn (U) def |
| (V) cvn (V) def |
| (W) cvn (W) def |
| (X) cvn (X) def |
| (Y) cvn (Y) def |
| (Z) cvn (Z) def |
| ([) cvn ([) def |
| (\\) cvn (\\\\) def |
| (]) cvn (]) def |
| (^) cvn (^) def |
| (_) cvn (_) def |
| (`) cvn (`) def |
| (a) cvn (a) def |
| (b) cvn (b) def |
| (c) cvn (c) def |
| (d) cvn (d) def |
| (e) cvn (e) def |
| (f) cvn (f) def |
| (g) cvn (g) def |
| (h) cvn (h) def |
| (i) cvn (i) def |
| (j) cvn (j) def |
| (k) cvn (k) def |
| (l) cvn (l) def |
| (m) cvn (m) def |
| (n) cvn (n) def |
| (o) cvn (o) def |
| (p) cvn (p) def |
| (q) cvn (q) def |
| (r) cvn (r) def |
| (s) cvn (s) def |
| (t) cvn (t) def |
| (u) cvn (u) def |
| (v) cvn (v) def |
| (w) cvn (w) def |
| (x) cvn (x) def |
| (y) cvn (y) def |
| (z) cvn (z) def |
| ({) cvn ({) def |
| (|) cvn (|) def |
| (}) cvn (}) def |
| (~) cvn (~) def |
| end def |
| |
| % |
| % OperatorDict can help format procedure listings. The value assigned to each |
| % name is used as an index into the OperatorProcs array. The procedure at that |
| % index is fetched and executed after the named operator is printed. What's in |
| % OperatorDict is a matter of taste rather than correctness. The default list |
| % represents our choice of which of Adobe's operators should end a line. |
| % |
| |
| /OperatorProcs [{} {Newline Indent}] def |
| |
| /OperatorDict 250 dict def |
| |
| OperatorDict /arc 1 put |
| OperatorDict /arcn 1 put |
| OperatorDict /ashow 1 put |
| OperatorDict /awidthshow 1 put |
| OperatorDict /banddevice 1 put |
| OperatorDict /begin 1 put |
| OperatorDict /charpath 1 put |
| OperatorDict /clear 1 put |
| OperatorDict /cleardictstack 1 put |
| OperatorDict /cleartomark 1 put |
| OperatorDict /clip 1 put |
| OperatorDict /clippath 1 put |
| OperatorDict /closefile 1 put |
| OperatorDict /closepath 1 put |
| OperatorDict /concat 1 put |
| OperatorDict /copypage 1 put |
| OperatorDict /curveto 1 put |
| OperatorDict /def 1 put |
| OperatorDict /end 1 put |
| OperatorDict /eoclip 1 put |
| OperatorDict /eofill 1 put |
| OperatorDict /erasepage 1 put |
| OperatorDict /exec 1 put |
| OperatorDict /exit 1 put |
| OperatorDict /fill 1 put |
| OperatorDict /flattenpath 1 put |
| OperatorDict /flush 1 put |
| OperatorDict /flushfile 1 put |
| OperatorDict /for 1 put |
| OperatorDict /forall 1 put |
| OperatorDict /framedevice 1 put |
| OperatorDict /grestore 1 put |
| OperatorDict /grestoreall 1 put |
| OperatorDict /gsave 1 put |
| OperatorDict /handleerror 1 put |
| OperatorDict /if 1 put |
| OperatorDict /ifelse 1 put |
| OperatorDict /image 1 put |
| OperatorDict /imagemask 1 put |
| OperatorDict /initclip 1 put |
| OperatorDict /initgraphics 1 put |
| OperatorDict /initmatrix 1 put |
| OperatorDict /kshow 1 put |
| OperatorDict /lineto 1 put |
| OperatorDict /loop 1 put |
| OperatorDict /moveto 1 put |
| OperatorDict /newpath 1 put |
| OperatorDict /nulldevice 1 put |
| OperatorDict /pathforall 1 put |
| OperatorDict /print 1 put |
| OperatorDict /prompt 1 put |
| OperatorDict /put 1 put |
| OperatorDict /putinterval 1 put |
| OperatorDict /quit 1 put |
| OperatorDict /rcurveto 1 put |
| OperatorDict /renderbands 1 put |
| OperatorDict /repeat 1 put |
| OperatorDict /resetfile 1 put |
| OperatorDict /restore 1 put |
| OperatorDict /reversepath 1 put |
| OperatorDict /rlineto 1 put |
| OperatorDict /rmoveto 1 put |
| OperatorDict /rotate 1 put |
| OperatorDict /run 1 put |
| OperatorDict /scale 1 put |
| OperatorDict /setcachedevice 1 put |
| OperatorDict /setcachelimit 1 put |
| OperatorDict /setcacheparams 1 put |
| OperatorDict /setcharwidth 1 put |
| OperatorDict /setdash 1 put |
| OperatorDict /setdefaulttimeouts 1 put |
| OperatorDict /setdostartpage 1 put |
| OperatorDict /seteescratch 1 put |
| OperatorDict /setflat 1 put |
| OperatorDict /setfont 1 put |
| OperatorDict /setgray 1 put |
| OperatorDict /sethsbcolor 1 put |
| OperatorDict /setidlefonts 1 put |
| OperatorDict /setjobtimeout 1 put |
| OperatorDict /setlinecap 1 put |
| OperatorDict /setlinejoin 1 put |
| OperatorDict /setlinewidth 1 put |
| OperatorDict /setmargins 1 put |
| OperatorDict /setmatrix 1 put |
| OperatorDict /setmiterlimit 1 put |
| OperatorDict /setpacking 1 put |
| OperatorDict /setpagetype 1 put |
| OperatorDict /setprintname 1 put |
| OperatorDict /setrgbcolor 1 put |
| OperatorDict /setsccbatch 1 put |
| OperatorDict /setsccinteractive 1 put |
| OperatorDict /setscreen 1 put |
| OperatorDict /settransfer 1 put |
| OperatorDict /show 1 put |
| OperatorDict /showpage 1 put |
| OperatorDict /start 1 put |
| OperatorDict /stop 1 put |
| OperatorDict /store 1 put |
| OperatorDict /stroke 1 put |
| OperatorDict /strokepath 1 put |
| OperatorDict /translate 1 put |
| OperatorDict /widthshow 1 put |
| OperatorDict /write 1 put |
| OperatorDict /writehexstring 1 put |
| OperatorDict /writestring 1 put |
| |
| end def |
| |
| % |
| % Put an object on the stack and call Grabit. Output continues until stack |
| % is empty. For example, |
| % |
| % /letter load Grabit |
| % |
| % prints a listing of the letter procedure. |
| % |
| |
| /Grabit { |
| /saveobj save def |
| GrabitDict begin |
| { |
| count 0 eq {exit} if |
| count {dup type exec} repeat |
| (\n) print flush |
| } loop |
| end |
| currentpoint % for hardcopy output |
| saveobj restore |
| moveto |
| } def |
| |