rsc | 13f7391 | 2004-05-15 23:45:13 +0000 | [diff] [blame] | 1 | % |
| 2 | % Dump a PostScript object, occasionally in a form that can be sent back |
| 3 | % through the interpreter. Similiar to Adobe's == procedure, but output |
| 4 | % is usually easier to read. No binding so operators like rcheck and exec |
| 5 | % can be conviently redefined. |
| 6 | % |
| 7 | |
| 8 | /GrabitDict 100 dict dup begin |
| 9 | |
| 10 | /recursive true def |
| 11 | /scratchstring 200 string def |
| 12 | /slowdown 100 def |
| 13 | |
| 14 | /column 0 def |
| 15 | /lastcolumn 80 def |
| 16 | /level 0 def |
| 17 | /multiline 100 array def |
| 18 | /nextname 0 def |
| 19 | /arraylength 0 def |
| 20 | /lengthonly false def |
| 21 | |
| 22 | /GrabitSetup { |
| 23 | counttomark {OmitNames exch true put} repeat pop |
| 24 | 0 0 moveto % for hardcopy output |
| 25 | } def |
| 26 | |
| 27 | /OmitNames 30 dict def % ignore these names |
| 28 | /OtherDicts 200 dict def % unrecognized dictionaries |
| 29 | |
| 30 | % |
| 31 | % All strings returned to the host go through Print. First pass through an |
| 32 | % array has lengthonly set to true. |
| 33 | % |
| 34 | |
| 35 | /Print { |
| 36 | dup type /stringtype ne {scratchstring cvs} if |
| 37 | lengthonly { |
| 38 | length arraylength add /arraylength exch def |
| 39 | }{ |
| 40 | dup length column add /column exch def |
| 41 | print flush |
| 42 | slowdown {1 pop} repeat |
| 43 | } ifelse |
| 44 | } def |
| 45 | |
| 46 | /Indent {level {( ) Print} repeat} def |
| 47 | /Newline {(\n) Print lengthonly not {/column 0 def} if} def |
| 48 | |
| 49 | /NextLevel {/level level 1 add def multiline level 0 put} def |
| 50 | /LastLevel {/level level 1 sub def} def |
| 51 | |
| 52 | % |
| 53 | % Make a unique name for each unrecognized dictionary and remember the name |
| 54 | % and dictionary in OtherDicts. |
| 55 | % |
| 56 | |
| 57 | /Register { |
| 58 | dup type /dicttype eq { |
| 59 | /nextname nextname 1 add def |
| 60 | dup (UnknownDict ) dup |
| 61 | (UnknownDict) length nextname ( ) cvs putinterval |
| 62 | 0 (UnknownDict) length nextname ( ) cvs length add getinterval cvn |
| 63 | exch OtherDicts 3 1 roll put |
| 64 | } if |
| 65 | } def |
| 66 | |
| 67 | % |
| 68 | % Replace array or dictionary values by known names. Lookups are in the |
| 69 | % standard PostScript dictionaries and in OtherDicts. If found replace |
| 70 | % the value by the name and make it executable so nametype omits the |
| 71 | % leading /. |
| 72 | % |
| 73 | |
| 74 | /Replace { |
| 75 | false |
| 76 | 1 index type /dicttype eq {pop true} if |
| 77 | 1 index type /arraytype eq 2 index xcheck not and {pop true} if |
| 78 | { |
| 79 | false |
| 80 | [userdict systemdict statusdict serverdict OtherDicts] { |
| 81 | { |
| 82 | 3 index eq |
| 83 | {exch pop exch pop cvx true exit} |
| 84 | {pop} |
| 85 | ifelse |
| 86 | } forall |
| 87 | dup {exit} if |
| 88 | } forall |
| 89 | pop |
| 90 | } if |
| 91 | } def |
| 92 | |
| 93 | % |
| 94 | % Simple type handlers. In some cases (e.g. savetype) what's returned can't |
| 95 | % be sent back through the interpreter. |
| 96 | % |
| 97 | |
| 98 | /booleantype {{(true )}{(false )} ifelse Print} def |
| 99 | /marktype {pop (mark ) Print} def |
| 100 | /nulltype {pop (null ) Print} def |
| 101 | /integertype {Print ( ) Print} def |
| 102 | /realtype {Print ( ) Print} def |
| 103 | /filetype {pop (-file- ) Print} def |
| 104 | /fonttype {pop (-fontID- ) Print} def |
| 105 | /savetype {pop (-saveobj- ) Print} def |
| 106 | |
| 107 | % |
| 108 | % Special formatting for operators is enabled if the flag in multiline |
| 109 | % (for the current level) is set to 1. In that case each operator, after |
| 110 | % being printed, is looked up in OperatorDict. If found the value is used |
| 111 | % as an index into the OperatorProcs array and the object at that index |
| 112 | % is retrieved and executed. Currently only used to choose the operators |
| 113 | % that end a line. |
| 114 | % |
| 115 | |
| 116 | /operatortype { |
| 117 | dup Print ( ) Print |
| 118 | multiline level get 1 eq { |
| 119 | scratchstring cvs cvn dup OperatorDict exch known { |
| 120 | OperatorDict exch get |
| 121 | OperatorProcs exch get exec |
| 122 | }{ |
| 123 | pop |
| 124 | column lastcolumn gt {Newline Indent} if |
| 125 | } ifelse |
| 126 | }{pop} ifelse |
| 127 | } def |
| 128 | |
| 129 | % |
| 130 | % Executable names are passed to operatortype. Non-executable names get a |
| 131 | % leading /. |
| 132 | % |
| 133 | |
| 134 | /nametype { |
| 135 | dup xcheck { |
| 136 | operatortype |
| 137 | }{ |
| 138 | (/) Print Print ( ) Print |
| 139 | } ifelse |
| 140 | } def |
| 141 | |
| 142 | % |
| 143 | % Arrays are processed in two passes. The first computes the length of the |
| 144 | % string returned to the host without any special formatting. If it extends |
| 145 | % past the last column special formatting is enabled by setting a flag in |
| 146 | % array multiline. Arrays are processed in a for loop so the last element |
| 147 | % easily recognized. At that point special fortmatting is disabled. |
| 148 | % |
| 149 | |
| 150 | /packedarraytype {arraytype} def |
| 151 | |
| 152 | /arraytype { |
| 153 | NextLevel |
| 154 | lengthonly not { |
| 155 | /lengthonly true def |
| 156 | /arraylength 0 def |
| 157 | dup dup type exec |
| 158 | arraylength 20 gt arraylength column add lastcolumn gt and { |
| 159 | multiline level 1 put |
| 160 | } if |
| 161 | /lengthonly false def |
| 162 | } if |
| 163 | |
| 164 | dup rcheck not { |
| 165 | (-array- ) Print pop |
| 166 | }{ |
| 167 | dup xcheck {({)}{([)} ifelse Print |
| 168 | multiline level get 0 ne {Newline Indent}{( ) Print} ifelse |
| 169 | 0 1 2 index length 1 sub { |
| 170 | 2 copy exch length 1 sub eq multiline level get 1 eq and { |
| 171 | multiline level 2 put |
| 172 | } if |
| 173 | 2 copy get exch pop |
| 174 | dup type /dicttype eq { |
| 175 | Replace |
| 176 | dup type /dicttype eq { |
| 177 | dup Register Replace |
| 178 | recursive { |
| 179 | 2 copy cvlit |
| 180 | /def load 3 1 roll |
| 181 | count 3 roll |
| 182 | } if |
| 183 | exch pop |
| 184 | } if |
| 185 | } if |
| 186 | dup type exec |
| 187 | dup xcheck not multiline level get 1 eq and { |
| 188 | 0 index type /arraytype eq |
| 189 | 1 index type /packedarray eq or |
| 190 | 1 index type /stringtype eq or {Newline Indent} if |
| 191 | } if |
| 192 | } for |
| 193 | multiline level get 0 ne {Newline LastLevel Indent NextLevel} if |
| 194 | xcheck {(} )}{(] )} ifelse Print |
| 195 | } ifelse |
| 196 | LastLevel |
| 197 | } def |
| 198 | |
| 199 | % |
| 200 | % Dictionary handler. Try to replace the value by a name before processing |
| 201 | % the dictionary. |
| 202 | % |
| 203 | |
| 204 | /dicttype { |
| 205 | dup |
| 206 | rcheck not { |
| 207 | (-dictionary- ) Print pop |
| 208 | }{ |
| 209 | dup maxlength Print ( dict dup begin) Print Newline |
| 210 | NextLevel |
| 211 | { |
| 212 | 1 index OmitNames exch known { |
| 213 | pop pop |
| 214 | }{ |
| 215 | Indent |
| 216 | Replace % arrays and dicts by known names |
| 217 | Register % new dictionaries in OtherDicts |
| 218 | exch |
| 219 | cvlit dup type exec % key first - force a / |
| 220 | dup type exec % then the value |
| 221 | (def) Print Newline |
| 222 | } ifelse |
| 223 | } forall |
| 224 | LastLevel |
| 225 | Indent |
| 226 | (end ) Print |
| 227 | } ifelse |
| 228 | } def |
| 229 | |
| 230 | % |
| 231 | % Strings containing characters not in AsciiDict are returned in hex. All |
| 232 | % others are ASCII strings and use AsciiDict for character mapping. |
| 233 | % |
| 234 | |
| 235 | /onecharstring ( ) def |
| 236 | /twocharstring ( ) def |
| 237 | |
| 238 | /stringtype { |
| 239 | dup |
| 240 | rcheck not { |
| 241 | (-string- ) Print |
| 242 | }{ |
| 243 | /hexit false def |
| 244 | dup { |
| 245 | onecharstring 0 3 -1 roll put |
| 246 | AsciiDict onecharstring cvn known not { |
| 247 | /hexit true def exit |
| 248 | } if |
| 249 | } forall |
| 250 | |
| 251 | hexit {(<)}{(\()} ifelse Print |
| 252 | 0 1 2 index length 1 sub { |
| 253 | 2 copy 1 getinterval exch pop |
| 254 | hexit { |
| 255 | 0 get /n exch def |
| 256 | n -4 bitshift 16#F and 16 twocharstring cvrs pop |
| 257 | n 16#F and twocharstring 1 1 getinterval 16 exch cvrs pop |
| 258 | twocharstring |
| 259 | }{cvn AsciiDict exch get} ifelse |
| 260 | Print |
| 261 | column lastcolumn gt { |
| 262 | hexit not {(\\) Print} if |
| 263 | Newline |
| 264 | } if |
| 265 | } for |
| 266 | hexit {(> )}{(\) )} ifelse Print |
| 267 | } ifelse |
| 268 | pop |
| 269 | } def |
| 270 | |
| 271 | % |
| 272 | % ASCII characters and replacement strings. Ensures the returned string will |
| 273 | % reproduce the original when passed through the scanner. Strings containing |
| 274 | % characters not in this list should be returned as hex strings. |
| 275 | % |
| 276 | |
| 277 | /AsciiDict 128 dict dup begin |
| 278 | (\n) cvn (\\n) def |
| 279 | (\r) cvn (\\r) def |
| 280 | (\t) cvn (\\t) def |
| 281 | (\b) cvn (\\b) def |
| 282 | (\f) cvn (\\f) def |
| 283 | ( ) cvn ( ) def |
| 284 | (!) cvn (!) def |
| 285 | (") cvn (") def |
| 286 | (#) cvn (#) def |
| 287 | ($) cvn ($) def |
| 288 | (%) cvn (\\%) def |
| 289 | (&) cvn (&) def |
| 290 | (') cvn (') def |
| 291 | (\() cvn (\\\() def |
| 292 | (\)) cvn (\\\)) def |
| 293 | (*) cvn (*) def |
| 294 | (+) cvn (+) def |
| 295 | (,) cvn (,) def |
| 296 | (-) cvn (-) def |
| 297 | (.) cvn (.) def |
| 298 | (/) cvn (/) def |
| 299 | (0) cvn (0) def |
| 300 | (1) cvn (1) def |
| 301 | (2) cvn (2) def |
| 302 | (3) cvn (3) def |
| 303 | (4) cvn (4) def |
| 304 | (5) cvn (5) def |
| 305 | (6) cvn (6) def |
| 306 | (7) cvn (7) def |
| 307 | (8) cvn (8) def |
| 308 | (9) cvn (9) def |
| 309 | (:) cvn (:) def |
| 310 | (;) cvn (;) def |
| 311 | (<) cvn (<) def |
| 312 | (=) cvn (=) def |
| 313 | (>) cvn (>) def |
| 314 | (?) cvn (?) def |
| 315 | (@) cvn (@) def |
| 316 | (A) cvn (A) def |
| 317 | (B) cvn (B) def |
| 318 | (C) cvn (C) def |
| 319 | (D) cvn (D) def |
| 320 | (E) cvn (E) def |
| 321 | (F) cvn (F) def |
| 322 | (G) cvn (G) def |
| 323 | (H) cvn (H) def |
| 324 | (I) cvn (I) def |
| 325 | (J) cvn (J) def |
| 326 | (K) cvn (K) def |
| 327 | (L) cvn (L) def |
| 328 | (M) cvn (M) def |
| 329 | (N) cvn (N) def |
| 330 | (O) cvn (O) def |
| 331 | (P) cvn (P) def |
| 332 | (Q) cvn (Q) def |
| 333 | (R) cvn (R) def |
| 334 | (S) cvn (S) def |
| 335 | (T) cvn (T) def |
| 336 | (U) cvn (U) def |
| 337 | (V) cvn (V) def |
| 338 | (W) cvn (W) def |
| 339 | (X) cvn (X) def |
| 340 | (Y) cvn (Y) def |
| 341 | (Z) cvn (Z) def |
| 342 | ([) cvn ([) def |
| 343 | (\\) cvn (\\\\) def |
| 344 | (]) cvn (]) def |
| 345 | (^) cvn (^) def |
| 346 | (_) cvn (_) def |
| 347 | (`) cvn (`) def |
| 348 | (a) cvn (a) def |
| 349 | (b) cvn (b) def |
| 350 | (c) cvn (c) def |
| 351 | (d) cvn (d) def |
| 352 | (e) cvn (e) def |
| 353 | (f) cvn (f) def |
| 354 | (g) cvn (g) def |
| 355 | (h) cvn (h) def |
| 356 | (i) cvn (i) def |
| 357 | (j) cvn (j) def |
| 358 | (k) cvn (k) def |
| 359 | (l) cvn (l) def |
| 360 | (m) cvn (m) def |
| 361 | (n) cvn (n) def |
| 362 | (o) cvn (o) def |
| 363 | (p) cvn (p) def |
| 364 | (q) cvn (q) def |
| 365 | (r) cvn (r) def |
| 366 | (s) cvn (s) def |
| 367 | (t) cvn (t) def |
| 368 | (u) cvn (u) def |
| 369 | (v) cvn (v) def |
| 370 | (w) cvn (w) def |
| 371 | (x) cvn (x) def |
| 372 | (y) cvn (y) def |
| 373 | (z) cvn (z) def |
| 374 | ({) cvn ({) def |
| 375 | (|) cvn (|) def |
| 376 | (}) cvn (}) def |
| 377 | (~) cvn (~) def |
| 378 | end def |
| 379 | |
| 380 | % |
| 381 | % OperatorDict can help format procedure listings. The value assigned to each |
| 382 | % name is used as an index into the OperatorProcs array. The procedure at that |
| 383 | % index is fetched and executed after the named operator is printed. What's in |
| 384 | % OperatorDict is a matter of taste rather than correctness. The default list |
| 385 | % represents our choice of which of Adobe's operators should end a line. |
| 386 | % |
| 387 | |
| 388 | /OperatorProcs [{} {Newline Indent}] def |
| 389 | |
| 390 | /OperatorDict 250 dict def |
| 391 | |
| 392 | OperatorDict /arc 1 put |
| 393 | OperatorDict /arcn 1 put |
| 394 | OperatorDict /ashow 1 put |
| 395 | OperatorDict /awidthshow 1 put |
| 396 | OperatorDict /banddevice 1 put |
| 397 | OperatorDict /begin 1 put |
| 398 | OperatorDict /charpath 1 put |
| 399 | OperatorDict /clear 1 put |
| 400 | OperatorDict /cleardictstack 1 put |
| 401 | OperatorDict /cleartomark 1 put |
| 402 | OperatorDict /clip 1 put |
| 403 | OperatorDict /clippath 1 put |
| 404 | OperatorDict /closefile 1 put |
| 405 | OperatorDict /closepath 1 put |
| 406 | OperatorDict /concat 1 put |
| 407 | OperatorDict /copypage 1 put |
| 408 | OperatorDict /curveto 1 put |
| 409 | OperatorDict /def 1 put |
| 410 | OperatorDict /end 1 put |
| 411 | OperatorDict /eoclip 1 put |
| 412 | OperatorDict /eofill 1 put |
| 413 | OperatorDict /erasepage 1 put |
| 414 | OperatorDict /exec 1 put |
| 415 | OperatorDict /exit 1 put |
| 416 | OperatorDict /fill 1 put |
| 417 | OperatorDict /flattenpath 1 put |
| 418 | OperatorDict /flush 1 put |
| 419 | OperatorDict /flushfile 1 put |
| 420 | OperatorDict /for 1 put |
| 421 | OperatorDict /forall 1 put |
| 422 | OperatorDict /framedevice 1 put |
| 423 | OperatorDict /grestore 1 put |
| 424 | OperatorDict /grestoreall 1 put |
| 425 | OperatorDict /gsave 1 put |
| 426 | OperatorDict /handleerror 1 put |
| 427 | OperatorDict /if 1 put |
| 428 | OperatorDict /ifelse 1 put |
| 429 | OperatorDict /image 1 put |
| 430 | OperatorDict /imagemask 1 put |
| 431 | OperatorDict /initclip 1 put |
| 432 | OperatorDict /initgraphics 1 put |
| 433 | OperatorDict /initmatrix 1 put |
| 434 | OperatorDict /kshow 1 put |
| 435 | OperatorDict /lineto 1 put |
| 436 | OperatorDict /loop 1 put |
| 437 | OperatorDict /moveto 1 put |
| 438 | OperatorDict /newpath 1 put |
| 439 | OperatorDict /nulldevice 1 put |
| 440 | OperatorDict /pathforall 1 put |
| 441 | OperatorDict /print 1 put |
| 442 | OperatorDict /prompt 1 put |
| 443 | OperatorDict /put 1 put |
| 444 | OperatorDict /putinterval 1 put |
| 445 | OperatorDict /quit 1 put |
| 446 | OperatorDict /rcurveto 1 put |
| 447 | OperatorDict /renderbands 1 put |
| 448 | OperatorDict /repeat 1 put |
| 449 | OperatorDict /resetfile 1 put |
| 450 | OperatorDict /restore 1 put |
| 451 | OperatorDict /reversepath 1 put |
| 452 | OperatorDict /rlineto 1 put |
| 453 | OperatorDict /rmoveto 1 put |
| 454 | OperatorDict /rotate 1 put |
| 455 | OperatorDict /run 1 put |
| 456 | OperatorDict /scale 1 put |
| 457 | OperatorDict /setcachedevice 1 put |
| 458 | OperatorDict /setcachelimit 1 put |
| 459 | OperatorDict /setcacheparams 1 put |
| 460 | OperatorDict /setcharwidth 1 put |
| 461 | OperatorDict /setdash 1 put |
| 462 | OperatorDict /setdefaulttimeouts 1 put |
| 463 | OperatorDict /setdostartpage 1 put |
| 464 | OperatorDict /seteescratch 1 put |
| 465 | OperatorDict /setflat 1 put |
| 466 | OperatorDict /setfont 1 put |
| 467 | OperatorDict /setgray 1 put |
| 468 | OperatorDict /sethsbcolor 1 put |
| 469 | OperatorDict /setidlefonts 1 put |
| 470 | OperatorDict /setjobtimeout 1 put |
| 471 | OperatorDict /setlinecap 1 put |
| 472 | OperatorDict /setlinejoin 1 put |
| 473 | OperatorDict /setlinewidth 1 put |
| 474 | OperatorDict /setmargins 1 put |
| 475 | OperatorDict /setmatrix 1 put |
| 476 | OperatorDict /setmiterlimit 1 put |
| 477 | OperatorDict /setpacking 1 put |
| 478 | OperatorDict /setpagetype 1 put |
| 479 | OperatorDict /setprintname 1 put |
| 480 | OperatorDict /setrgbcolor 1 put |
| 481 | OperatorDict /setsccbatch 1 put |
| 482 | OperatorDict /setsccinteractive 1 put |
| 483 | OperatorDict /setscreen 1 put |
| 484 | OperatorDict /settransfer 1 put |
| 485 | OperatorDict /show 1 put |
| 486 | OperatorDict /showpage 1 put |
| 487 | OperatorDict /start 1 put |
| 488 | OperatorDict /stop 1 put |
| 489 | OperatorDict /store 1 put |
| 490 | OperatorDict /stroke 1 put |
| 491 | OperatorDict /strokepath 1 put |
| 492 | OperatorDict /translate 1 put |
| 493 | OperatorDict /widthshow 1 put |
| 494 | OperatorDict /write 1 put |
| 495 | OperatorDict /writehexstring 1 put |
| 496 | OperatorDict /writestring 1 put |
| 497 | |
| 498 | end def |
| 499 | |
| 500 | % |
| 501 | % Put an object on the stack and call Grabit. Output continues until stack |
| 502 | % is empty. For example, |
| 503 | % |
| 504 | % /letter load Grabit |
| 505 | % |
| 506 | % prints a listing of the letter procedure. |
| 507 | % |
| 508 | |
| 509 | /Grabit { |
| 510 | /saveobj save def |
| 511 | GrabitDict begin |
| 512 | { |
| 513 | count 0 eq {exit} if |
| 514 | count {dup type exec} repeat |
| 515 | (\n) print flush |
| 516 | } loop |
| 517 | end |
| 518 | currentpoint % for hardcopy output |
| 519 | saveobj restore |
| 520 | moveto |
| 521 | } def |
| 522 | |