aboutsummaryrefslogtreecommitdiff
path: root/postscript/prologues/grabit.ps
diff options
context:
space:
mode:
Diffstat (limited to 'postscript/prologues/grabit.ps')
-rw-r--r--postscript/prologues/grabit.ps522
1 files changed, 522 insertions, 0 deletions
diff --git a/postscript/prologues/grabit.ps b/postscript/prologues/grabit.ps
new file mode 100644
index 00000000..dab313c5
--- /dev/null
+++ b/postscript/prologues/grabit.ps
@@ -0,0 +1,522 @@
+%
+% 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
+