| % | 
 | % 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 | 
 |  |