]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/ps2ascii.ps
etherbcm: handle 64-bit host addresses, use PCIWADDR() instead of PADDR()
[plan9front.git] / sys / lib / ghostscript / ps2ascii.ps
1 %    Copyright (C) 1991, 1995, 1996, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2
3 % This software is provided AS-IS with no warranty, either express or
4 % implied.
5
6 % This software is distributed under license and may not be copied,
7 % modified or distributed except as expressly authorized under the terms
8 % of the license contained in the file LICENSE in this distribution.
9
10 % For more information about licensing, please refer to
11 % http://www.ghostscript.com/licensing/. For information on
12 % commercial licensing, go to http://www.artifex.com/licensing/ or
13 % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
16 % $Id: ps2ascii.ps,v 1.10 2004/06/23 09:04:17 igor Exp $
17 % Extract the ASCII text from a PostScript file.  Nothing is displayed.
18 % Instead, ASCII information is written to stdout.  The idea is similar to
19 % Glenn Reid's `distillery', only a lot more simple-minded, and less robust.
20
21 % If SIMPLE is defined, just the text is written, with a guess at line
22 % breaks and word spacing.  If SIMPLE is not defined, lines are written
23 % to stdout as follows:
24 %
25 %       F <height> <width> (<fontname>)
26 %               Indicate the font height and the width of a space.
27 %
28 %       P
29 %               Indicate the end of the page.
30
31 %       S <x> <y> (<string>) <width>
32 %               Display a string.
33 %
34 % <width> and <height> are integer dimensions in units of 1/720".
35 % <x> and <y> are integer coordinates, in units of 1/720", with the origin
36 %   at the lower left.
37 % <string> and <fontname> are strings represented with the standard
38 %   PostScript escape conventions.
39
40 % If COMPLEX is defined, the following additional types of lines are
41 % written to stdout.
42 %
43 %       C <r> <g> <b>
44 %               Indicate the current color.
45 %
46 %       I <x> <y> <width> <height>
47 %               Note the presence of an image.
48 %
49 %       R <x> <y> <width> <height>
50 %               Fill a rectangle.
51 %
52 % <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000.
53 %
54 % Note that future versions of this program (in COMPLEX mode) may add
55 %   other output elements, so programs parsing the output should be
56 %   prepared to ignore elements that they do not recognize.
57
58 % Note that this code will only work in all cases if systemdict is writable
59 % and if `binding' the definitions of operators defined as procedures
60 % is deferred.  For this reason, it is normally invoked with
61 %       gs -q -dNODISPLAY -dDELAYBIND -dWRITESYSTEMDICT ps2ascii.ps
62
63 % Thanks to:
64 %    J Greely <jgreely@cis.ohio-state.edu> for improvements to this code;
65 %    Jerry Whelan <jerryw@abode.ccd.bnl.gov> for motivating other improvements;
66 %    David M. Jones <dmjones@theory.lcs.mit.edu> for improvements noted below.
67
68 %%  Additional modifications by David M. Jones
69 %%  (dmjones@theory.lcs.mit.edu), December 23, 1997
70 %%  
71 %%  (a) Rewrote forall loop at the end of .show.write.  This fixes a
72 %%      stack leakage problem, but the changes are more significant
73 %%      than that.  
74 %% 
75 %%      .char.map includes the names of all characters in the
76 %%      StandardEncoding, ISOLatin1Encoding, OT1Encoding and
77 %%      T1Encoding vectors.  Thus, if the Encoding vector for the
78 %%      current font contains a name that is not in .char.map, it's
79 %%      redundant to check if the Encoding vector is equal to one of
80 %%      the known vectors.  Previous versions of ps2ascii would give
81 %%      up at this point, and substitute an asterisk (*) for the
82 %%      character.  I've taken the liberty of instead using the
83 %%      OT1Encoding vector to translate the character, on the grounds
84 %%      that in the cases I'm most interested in, a font without a
85 %%      useful Encoding vector was most likely created by a DVI to PS
86 %%      converter such as dvips or DVILASER (and OT1Encoding is
87 %%      largely compatible with StandardEncoding anyway).  [Note that
88 %%      this does not make my earlier changes to support dvips (see
89 %%      fix (a) under my 1996 changes) completely obsolete, since
90 %%      there's additional useful information I can extract in that
91 %%      case.]
92 %%      
93 %%      Overall, this should provide better support for some documents
94 %%      (e.g, DVILASER documents will no longer be translated into a
95 %%      series of *'s) without breaking any other documents any worse
96 %%      than they already were broken.
97 %% 
98 %%  (b) Fixed two bugs in dvips.df-tail: (1) changed "dup 127" to "dup
99 %%      128" to fix fencepost error, and (2) gave each font it's own
100 %%      FontName rather than having all fonts share the same name.
101 %%  
102 %%  (c) Added one further refinement to the heuristic for detecting
103 %%      paragraph breaks: do not ever start a new paragraph after a
104 %%      line ending in a hyphen.
105 %% 
106 %%  (d) Added a bunch of missing letters from the T1Encoding,
107 %%      OT1Encoding and ISOLatin1Encoding vectors to .letter.chars to
108 %%      improve hyphen-elimination algorithm.  This still won't help
109 %%      if there's no useful Encoding vector.
110 %% 
111 %%  NOTE: A better solution to the problem of missing Encoding vectors
112 %%  might be to redefine definefont to check whether the Encoding
113 %%  vector is sensible and, if not, replace it by a default.  This
114 %%  would alleviate the need for constant tests in the .show.write
115 %%  loop, as well as automatically solving the problem noted in fix
116 %%  (d) above, and the similar problem with .break.chars.  This should
117 %%  be investigated.  Also, the hyphen-elimination algorithm really
118 %%  needs to be looked at carefully and rethought.
119
120 %%* Modifications to ps2ascii.ps by David M. Jones
121 %%* (dmjones@theory.lcs.mit.edu), June 25-July 8, 1996
122
123 %%* Modifications:
124 %%* 
125 %%* (a) added code to give better support for dvips files by providing
126 %%*     FontBBox's, FontName's and Encoding vectors for downloaded
127 %%*     bitmap fonts.  This is done by using dvips's start-hook to
128 %%*     overwrite the df-tail and D procedures that dvips uses to
129 %%*     define its Type 3 bitmap fonts.  Thus, this change should
130 %%*     provide better support for dvips-generated PS files without
131 %%*     affecting the handling of other documents.
132 %%* 
133 %%* (b) Fixed two bugs that could potentially affect any PS file, not
134 %%*     just those created by dvips: (1) added missing "get" operator
135 %%*     in .show.write and (2) fixed bug that caused a hyphen at the
136 %%*     end of a line to be replaced by a space rather than begin
137 %%*     deleted.  Note that the first bug was a source of stack
138 %%*     leakage, causing ps2ascii to run out of operand stack space
139 %%*     occasionally.
140 %%* 
141 %%*     Search for "%%* BF" to find these modifications.
142 %%*     
143 %%* (c) Improved the heuristic for determining whether a line break
144 %%*     has occurred and whether a line break represents a paragraph
145 %%*     break.  Previously, any change in the vertical position caused
146 %%*     a line break; now a line break is only registered if the
147 %%*     change is larger than the height of the current font.  This
148 %%*     means that superscripts, subscripts, and such things as
149 %%*     shifted accents generated by TeX won't cause line breaks.
150 %%*     Paragraph-recognition is now done by comparing the indentation
151 %%*     of the new line to the indentation of the previous line and by
152 %%*     comparing the vertical distance between the new line and the
153 %%*     previous line to the vertical distance between the previous
154 %%*     line and its predecessor.
155 %%*     
156 %%* (d) Added a hook for renaming the files where stdout and stderr
157 %%*     go.
158 %%* 
159 %%* In general, my additions or changes to the code are described in
160 %%* comments beginning with "%%*".  However, there are numerous other
161 %%* places where I have either re-formatted code or added comments to
162 %%* the code while I was trying to understand it.  These are usually
163 %%* not specially marked.
164 %%* 
165
166 /QUIET true def
167 systemdict wcheck { systemdict } { userdict } ifelse begin
168 /.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse
169 /COMPLEX dup where { pop true } { false } ifelse def
170 /SIMPLE dup where { pop true } { false } ifelse def
171 /setglobal where
172  { pop currentglobal /setglobal load true setglobal }
173  { { } }
174 ifelse
175
176 % Define a way to store and retrieve integers that survives save/restore.
177 /.i.string0 (0               ) def
178 /.i.string .i.string0 length string def
179 /.iget { cvi } bind def
180 /.iput { exch //.i.string exch copy cvs pop } bind def
181 /.inew { //.i.string0 dup length string copy } bind def
182
183 % We only want to redefine operators if they are defined already.
184
185 /codef { 1 index where { pop def } { pop pop } ifelse } def
186
187 % Redefine the end-of-page operators.
188
189 /erasepage { } codef
190 /copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef
191 /showpage { copypage erasepage initgraphics } codef
192
193 % Redefine the fill operators to detect rectangles.
194
195 /.orderrect     % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h>
196  {      % Ensure llx <= urx, lly <= ury.
197    1 index 4 index lt { 4 2 roll } if
198    dup 3 index lt { 3 1 roll exch } if
199    exch 3 index sub exch 2 index sub
200  } odef
201 /.fillcomplex
202  {      % Do a first pass to see if the path is all rectangles in
203         % the output coordinate system.  We don't worry about overlapping
204         % rectangles that might be partially not filled.
205         % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ...
206    mark true mark
207         % Add a final moveto so we pick up any trailing unclosed subpath.
208    0 0 itransform moveto
209     { .coord counttomark 2 gt
210        { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop }  ifelse }
211       if
212     }
213     { .coord }
214     { cleartomark not mark exit }
215     { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect }
216    pathforall cleartomark
217     { .showcolor counttomark 4 idiv
218        { counttomark -4 roll .orderrect
219          (R ) //print .show==4
220        }
221       repeat pop
222     }
223     { cleartomark
224     }
225    ifelse
226  } odef
227 /.fillcheckrect
228  {      % Check whether the current subpath is a rectangle.
229         % If it is, add it to the list of rectangles being accumulated;
230         % if not exit the .fillcomplex loop.
231         % The subpath has not been closed.
232         % Stack: as in .fillcomplex, + newx newy
233    counttomark 10 eq { 9 index 9 index 4 2 roll } if
234    counttomark 12 ne { cleartomark not mark exit } if
235    12 2 roll
236         % Check for the two possible forms of rectangles:
237         %       x0 y0  x0 y1  x1 y1  x1 y0  x0 y0
238         %       x0 y0  x1 y0  x1 y1  x0 y1  x0 y0
239    9 index 2 index eq 9 index 2 index eq and
240    10 index 9 index eq
241     {   % Check for first form.
242       7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and
243     }
244     {   % Check for second form.
245       9 index 8 index eq and
246       8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and
247     }
248    ifelse not { cleartomark not mark exit } if
249         % We have a rectangle.
250    pop pop pop pop 4 2 roll pop pop 8 4 roll
251  } odef
252 /eofill { COMPLEX { .fillcomplex } if newpath } codef
253 /fill { COMPLEX { .fillcomplex } if newpath } codef
254 /rectfill { gsave newpath .rectappend fill grestore } codef
255 /ueofill { gsave newpath uappend eofill grestore } codef
256 /ufill { gsave newpath uappend fill grestore } codef
257
258 % Redefine the stroke operators to detect rectangles.
259
260 /rectstroke
261  { gsave newpath
262    dup type dup /arraytype eq exch /packedarraytype eq or
263     { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse }
264     { .rectappend }
265    ifelse stroke grestore
266  } codef
267 /.strokeline    % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy>
268                 % Note: fromx and fromy are in output coordinates;
269                 % tox and toy are in user coordinates.
270  { .coord 2 copy 6 2 roll .orderrect
271         % Add in the line width.  Assume square or round caps.
272    currentlinewidth 2 div dup .dcoord add abs 1 .max 5 1 roll
273    4 index add 4 1 roll 4 index add 4 1 roll
274    4 index sub 4 1 roll 5 -1 roll sub 4 1 roll
275    (R ) //print .show==4
276  } odef
277 /.strokecomplex
278  {      % Do a first pass to see if the path is all horizontal and vertical
279         % lines in the output coordinate system.
280         % Stack: true mark origx origy curx cury
281    true mark null null null null
282     { .coord 6 2 roll pop pop pop pop 2 copy }
283     { .coord 1 index 4 index eq 1 index 4 index eq or
284        { 4 2 roll pop pop }
285        { cleartomark not mark exit }
286       ifelse
287     }
288     { cleartomark not mark exit }
289     { counttomark -2 roll 2 copy counttomark 2 roll
290       1 index 4 index eq 1 index 4 index eq or
291        { pop pop 2 copy }
292        { cleartomark not mark exit }
293       ifelse
294     }
295    pathforall cleartomark
296    0 currentlinewidth .dcoord 0 eq exch 0 eq or and
297         % Do the second pass to write out the rectangles.
298         % Stack: origx origy curx cury
299     { .showcolor null null null null
300        { 6 2 roll pop pop pop pop 2 copy .coord }
301        { .strokeline }
302        { }
303        { 3 index 3 index .strokeline }
304       pathforall pop pop pop pop
305     }
306    if
307  } odef
308 /stroke { COMPLEX { .strokecomplex } if newpath } codef
309 /ustroke
310  { gsave newpath
311    dup length 6 eq { exch uappend concat } { uappend } ifelse
312    stroke grestore
313  } codef
314
315 % The image operators must read the input and note the dimensions.
316 % Eventually we should redefine these to detect 1-bit-high all-black images,
317 % since this is how dvips does underlining (!).
318
319 /.noteimagerect         % <width> <height> <matrix> .noteimagerect -
320  { COMPLEX
321     { gsave setmatrix itransform 0 0 itransform
322       grestore .coord 4 2 roll .coord .orderrect
323       (I ) //print .show==4
324     }
325     { pop pop pop
326     }
327    ifelse
328  } odef
329 /colorimage where
330  { pop /colorimage
331     { 1 index
332        { dup 6 add index 1 index 6 add index 2 index 5 add index }
333        { 6 index 6 index 5 index }
334       ifelse .noteimagerect gsave nulldevice //colorimage grestore
335     } codef
336  } if
337 /.noteimage             % Arguments as for image[mask]
338  { dup type /dicttype eq
339     { dup /Width get 1 index /Height get 2 index /ImageMatrix get }
340     { 4 index 4 index 3 index }
341    ifelse .noteimagerect
342  } odef
343 /image { .noteimage gsave nulldevice //image grestore } codef
344 /imagemask { .noteimage gsave nulldevice //imagemask grestore } codef
345
346 % Output the current color if necessary.
347 /.color.r .inew def
348   .color.r -1 .iput             % make sure we write the color at the beginning
349 /.color.g .inew def
350 /.color.b .inew def
351 /.showcolor
352  { COMPLEX
353     { currentrgbcolor
354       1000 mul round cvi
355       3 1 roll 1000 mul round cvi
356       exch 1000 mul round cvi
357                 % Stack: b g r
358       dup //.color.r .iget eq
359       2 index //.color.g .iget eq and
360       3 index //.color.b .iget eq and
361        { pop pop pop
362        }
363        { (C ) //print
364          dup //.color.r exch .iput .show==only
365          ( ) //print dup //.color.g exch .iput .show==only
366          ( ) //print dup //.color.b exch .iput .show==only
367          (\n) //print
368        }
369       ifelse
370     }
371    if
372  } bind def
373
374 % Redefine `show'.
375
376 % Set things up so our output will be in tenths of a point, with origin at
377 % lower left.  This isolates us from the peculiarities of individual devices.
378
379 /.show.ident.matrix matrix def
380 /.show.ident {          % - .show.ident <scale> <matrix>
381 %   //.show.ident.matrix defaultmatrix
382 %               % Assume the original transformation is well-behaved.
383 %   0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def
384 %   0.1 dup 3 -1 roll scale
385   gsave initmatrix
386                 % Assume the original transformation is well-behaved...
387   0.1 0 dtransform abs exch abs .max
388   0.1 dup scale .show.ident.matrix currentmatrix
389                 % ... but undo any rotation into landscape orientation.
390   dup 0 get 0 eq {
391     1 get dup abs div 90 mul rotate
392     .show.ident.matrix currentmatrix
393   } if
394   grestore
395 } bind def
396
397 /.coord {               % <x> <y> .coord <x'> <y'>
398   transform .show.ident exch pop itransform
399   exch round cvi exch round cvi
400 } odef
401
402 /.dcoord {              % <dx> <dy> .coord <dx'> <dy'>
403                 % Transforming distances is trickier, because
404                 % the coordinate system might be rotated.
405    .show.ident pop 3 1 roll
406    exch 0 dtransform
407     dup mul exch dup mul add sqrt
408      2 index div round cvi
409    exch 0 exch dtransform
410     dup mul exch dup mul add sqrt
411      3 -1 roll div round cvi
412 } odef
413
414 % Remember the current X, Y, and height.
415 /.show.x .inew def
416 /.show.y .inew def
417 /.show.height .inew def
418
419 % Remember the last character of the previous string; if it was a
420 % hyphen preceded by a letter, we didn't output the hyphen.
421
422 /.show.last (\000) def
423
424 % Remember the current font.
425 /.font.name 130 string def
426 /.font.name.length .inew def
427 /.font.height .inew def
428 /.font.width .inew def
429
430 %%* Also remember indentation of current line and previous vertical
431 %%* skip
432
433 /.show.indent .inew def
434 /.show.dy     .inew def
435
436 % We have to redirect stdout somehow....
437
438 /.show.stdout { (%stdout) (w) file } bind def
439
440 % Make sure writing will work even if a program uses =string.
441 /.show.string =string length string def
442 /.show.=string =string length string def
443 /.show==only
444  { //=string //.show.=string copy pop
445    dup type /stringtype eq
446     { dup length //.show.string length le
447        { dup rcheck { //.show.string copy } if
448        } if
449     } if
450    .show.stdout exch write==only
451    //.show.=string //=string copy pop
452  } odef
453 /.show==4
454  { 4 -1 roll .show==only ( ) //print
455    3 -1 roll .show==only ( ) //print
456    exch .show==only ( ) //print
457    .show==only (\n) //print
458  } odef
459
460 /.showwidth     % Same as stringwidth, but disable COMPLEX so that
461                 % we don't try to detect rectangles during BuildChar.
462  { COMPLEX
463     { /COMPLEX false def stringwidth /COMPLEX true def }
464     { stringwidth }
465    ifelse
466  } odef
467
468 /.showfont      % <string> .showfont <string>
469  { gsave
470         % Try getting the height and width of the font from the FontBBox.
471      currentfont /FontBBox .knownget not { {0 0 0 0} } if
472      aload pop      % llx lly urx ury
473      exch 4 -1 roll % lly ury urx llx
474      sub            % lly ury dx
475      3 1 roll exch  % dx ury lly
476      sub            % dx dy
477      2 copy .max 0 ne
478       { currentfont /FontMatrix get dtransform
479       }
480       { pop pop
481         % Fonts produced by dvips, among other applications, have
482         % BuildChar procedures that bomb out when given unexpected
483         % characters, and there is no way to determine whether a given
484         % character will do this.  So for Type 1 fonts, we measure a
485         % typical character ('X'); for others, we punt.
486         currentfont /FontType get 1 eq
487          { (X) .showwidth pop dup 1.3 mul
488          }
489          {      % No safe way to get the character size.  Punt.
490            0 0
491          }
492         ifelse
493       }
494      ifelse .dcoord exch
495      currentfont /FontName .knownget not { () } if
496      dup type /stringtype ne { //.show.string cvs } if
497    grestore
498         % Stack: height width fontname
499    SIMPLE
500     { pop pop //.show.height exch .iput }
501     { 2 index //.font.height .iget eq
502       2 index //.font.width .iget eq and
503       1 index //.font.name 0 //.font.name.length .iget getinterval eq and
504        { pop pop pop
505        }
506        { (F ) //print
507          3 -1 roll dup //.font.height exch .iput .show==only ( ) //print
508          exch dup //.font.width exch .iput .show==only ( ) //print
509          dup length //.font.name.length exch .iput
510          //.font.name cvs .show==only (\n) //print
511        }
512       ifelse
513     }
514    ifelse
515  } odef
516
517 % Define the letters -- characters which, if they occur followed by a hyphen
518 % at the end of a line, cause the hyphen and line break to be ignored.
519 /.letter.chars 100 dict def
520 mark
521   65 1 90 { dup 32 add } for
522     counttomark
523         { StandardEncoding exch get .letter.chars exch dup put }
524     repeat
525 pop
526
527 %%* Add the rest of the letters from the [O]T1Encoding and
528 %%* ISOLatin1Encoding vectors
529
530 mark
531     /AE
532     /Aacute
533     /Abreve
534     /Acircumflex
535     /Adieresis
536     /Agrave
537     /Aogonek
538     /Aring
539     /Atilde
540     /Cacute
541     /Ccaron
542     /Ccedilla
543     /Dcaron
544     /Eacute
545     /Ecaron
546     /Ecircumflex
547     /Edieresis
548     /Egrave
549     /Eng
550     /Eogonek
551     /Eth
552     /Gbreve
553     /Germandbls 
554     /IJ
555     /Iacute
556     /Icircumflex
557     /Idieresis
558     /Idot
559     /Igrave
560     /Lacute
561     /Lcaron
562     /Lslash
563     /Nacute
564     /Ncaron
565     /Ntilde
566     /OE
567     /Oacute
568     /Ocircumflex
569     /Odieresis
570     /Ograve
571     /Ohungarumlaut
572     /Oslash
573     /Otilde
574     /Racute
575     /Rcaron
576     /Sacute
577     /Scaron
578     /Scedilla
579     /Tcaron
580     /Tcedilla
581     /Thorn
582     /Uacute
583     /Ucircumflex
584     /Udieresis
585     /Ugrave
586     /Uhungarumlaut
587     /Uring
588     /Yacute
589     /Ydieresis
590     /Zacute
591     /Zcaron
592     /Zdot
593     /aacute
594     /abreve
595     /acircumflex
596     /adieresis
597     /ae
598     /agrave
599     /aogonek
600     /aring
601     /atilde
602     /cacute
603     /ccaron
604     /ccedilla
605     /dbar
606     /dcaron
607     /dotlessi
608     /dotlessj
609     /eacute
610     /ecaron
611     /ecircumflex
612     /edieresis
613     /egrave
614     /eng
615     /eogonek
616     /eth
617     /exclamdown
618     /ff
619     /ffi
620     /ffl
621     /fi
622     /fl
623     /gbreve
624     /germandbls
625     /iacute
626     /icircumflex
627     /idieresis
628     /igrave
629     /ij
630     /lacute
631     /lcaron
632     /lslash
633     /nacute
634     /ncaron
635     /ntilde
636     /oacute
637     /ocircumflex
638     /odieresis
639     /oe
640     /ograve
641     /ohungarumlaut
642     /oslash
643     /otilde
644     /questiondown
645     /racute
646     /rcaron
647     /sacute
648     /scaron
649     /scedilla
650     /section
651     /sterling
652     /tcaron
653     /tcedilla
654     /thorn
655     /uacute
656     /ucircumflex
657     /udieresis
658     /ugrave
659     /uhungarumlaut
660     /uring
661     /yacute
662     /ydieresis
663     /zacute
664     /zcaron
665     /zdot
666 counttomark
667     { .letter.chars exch dup put }
668 repeat
669 pop
670
671 % Define a set of characters which, if they occur at the start of a line,
672 % are taken as indicating a paragraph break.
673 /.break.chars 50 dict def
674 mark
675     /bullet /dagger /daggerdbl /periodcentered /section
676     counttomark
677         { .break.chars exch dup put }
678     repeat
679 pop
680
681 % Define character translation to ASCII.
682 % We have to do this for the entire character set.
683
684 /.char.map 500 dict def
685
686 /.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def
687
688 % Encode the printable ASCII characters.
689
690 mark 32 1 126
691  { 1 string dup 0 4 -1 roll put
692    dup 0 get StandardEncoding exch get exch
693  }
694 for .chars.def
695
696         % Encode accents.
697 mark
698     /acute      (')
699     /caron      (^)
700     /cedilla    (,)
701     /circumflex (^)
702     /dieresis   (")
703     /grave      (`)
704     /ring       (*)
705     /tilde      (~)
706 .chars.def
707
708         % Encode the ISO accented characters.
709 mark 192 1 255
710  { ISOLatin1Encoding exch get =string cvs
711    dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval
712    .char.map 2 index known .char.map 2 index known and
713     { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings
714       .char.map 3 1 roll put
715     }
716     { pop pop pop
717     }
718    ifelse
719  }
720 for .chars.def
721
722 % Encode the remaining standard and ISO alphabetic characters.
723
724 mark
725   /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th)
726   /ae (ae) /eth (dh)
727   /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl)
728   /germandbls (ss) /oe (oe) /thorn (th)
729 .chars.def
730
731 % Encode the other standard and ISO characters.
732
733 mark
734   /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#)
735   /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.)
736   /dotlessi (i)
737   /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!)
738   /florin (f) /fraction (/)
739   /guillemotleft (<<) /guillemotright (>>)
740   /guilsinglleft (<) /guilsinglright (>) /hungarumlaut ("") /logicalnot (~)
741   /macron (_) /minus (-) /mu (u) /multiply (*)
742   /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1)
743   /ordfeminine (-a) /ordmasculine (-o)
744   /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-)
745   /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (")
746   /quotesinglbase (,) /quotesingle (') /registered ((R))
747   /section ($) /sterling (#)
748   /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2)
749   /yen (Y)
750 .chars.def
751
752 % Encode a few common Symbol characters.
753
754 mark
755   /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C))
756   /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R))
757   /trademarksans ((TM)) /trademarkserif ((TM))
758 .chars.def
759
760 %%* Add a few characters from StandardEncoding and ISOLatin1Encoding
761 %%* that were missing.
762
763 mark
764     /cent           (c)
765     /guilsinglleft  (<)
766     /guilsinglright (>)
767     /breve          (*)
768     /Lslash         (L/)
769     /lslash         (l/)
770 .chars.def
771
772 %%* Define the OT1Encoding and T1Encoding vectors for use with dvips
773 %%* files.  Unfortunately, there's no way of telling what font is
774 %%* really being used within a dvips document, so we can't provide an
775 %%* appropriate encoding for each individual font.  Instead, we'll
776 %%* just provide support for the two most popular text encodings, the
777 %%* OT1 and T1 encodings, and just accept the fact that any font not
778 %%* using one of those encodings will be rendered as gibberish.
779 %%* 
780 %%* OT1 is Knuth's 7-bit encoding for the CMR text fonts, while T1
781 %%* (aka the Cork encoding) is the 8-bit encoding used by the DC
782 %%* fonts, a preliminary version of the proposed Extended Computer
783 %%* Modern fonts.  Unfortunately, T1 is not a strict extension of OT1;
784 %%* they differ in positions 8#000 through 8#040, 8#074, 8#076, 8#134,
785 %%* 8#137, 8#173, 8#174, 8#175 and 8#177, so we can't use the same
786 %%* vector for both.
787 %%* 
788 %%* Of course, we also can't reliably tell the difference between an
789 %%* OT1-encoded font and a T1-encoded font based on the information in
790 %%* a dvips-created PostScript file.  As a best-guess solution, we'll
791 %%* use the T1 encoding if the font contains any characters in
792 %%* positions above 8#177 and the OT1 encoding if it doesn't.
793
794 /T1Encoding  256 array def
795
796 /OT1Encoding 256 array def
797
798 %%* T1Encoding shares a lot with StandardEncoding, so let's start
799 %%* there.
800
801 StandardEncoding T1Encoding copy pop
802
803 /OT1.encode {
804     counttomark
805     2 idiv
806       { OT1Encoding 3 1 roll put }
807     repeat
808     cleartomark
809 } def
810
811 /T1.encode {
812     counttomark
813     2 idiv
814       { T1Encoding 3 1 roll put }
815     repeat
816     cleartomark
817 } def
818
819 mark
820     8#000 /grave
821     8#001 /acute
822     8#002 /circumflex
823     8#003 /tilde
824     8#004 /dieresis
825     8#005 /hungarumlaut
826     8#006 /ring
827     8#007 /caron
828
829     8#010 /breve
830     8#011 /macron
831     8#012 /dotaccent
832     8#013 /cedilla
833     8#014 /ogonek
834     8#015 /quotesinglbase
835     8#016 /guilsinglleft
836     8#017 /guilsinglright
837
838     8#020 /quotedblleft
839     8#021 /quotedblright
840     8#022 /quotedblbase
841     8#023 /guillemotleft
842     8#024 /guillemotright
843     8#025 /endash
844     8#026 /emdash
845     8#027 /cwm
846
847     8#030 /perthousandzero
848     8#031 /dotlessi
849     8#032 /dotlessj
850     8#033 /ff
851     8#034 /fi
852     8#035 /fl
853     8#036 /ffi
854     8#037 /ffl
855
856 %%  8#040 through 8#176 follow StandardEncoding
857
858     8#177 /hyphen
859 T1.encode
860
861 mark
862     8#200 /Abreve
863     8#201 /Aogonek
864     8#202 /Cacute
865     8#203 /Ccaron
866     8#204 /Dcaron
867     8#205 /Ecaron
868     8#206 /Eogonek
869     8#207 /Gbreve
870     8#210 /Lacute
871     8#211 /Lcaron
872     8#212 /Lslash
873     8#213 /Nacute
874     8#214 /Ncaron
875     8#215 /Eng
876     8#216 /Ohungarumlaut
877     8#217 /Racute
878     8#220 /Rcaron
879     8#221 /Sacute
880     8#222 /Scaron
881     8#223 /Scedilla
882     8#224 /Tcaron
883     8#225 /Tcedilla
884     8#226 /Uhungarumlaut
885     8#227 /Uring
886     8#230 /Ydieresis
887     8#231 /Zacute
888     8#232 /Zcaron
889     8#233 /Zdot
890     8#234 /IJ
891     8#235 /Idot
892     8#236 /dbar
893     8#237 /section
894     8#240 /abreve
895     8#241 /aogonek
896     8#242 /cacute
897     8#243 /ccaron
898     8#244 /dcaron
899     8#245 /ecaron
900     8#246 /eogonek
901     8#247 /gbreve
902     8#250 /lacute
903     8#251 /lcaron
904     8#252 /lslash
905     8#253 /nacute
906     8#254 /ncaron
907     8#255 /eng
908     8#256 /ohungarumlaut
909     8#257 /racute
910     8#260 /rcaron
911     8#261 /sacute
912     8#262 /scaron
913     8#263 /scedilla
914     8#264 /tcaron
915     8#265 /tcedilla
916     8#266 /uhungarumlaut
917     8#267 /uring
918     8#270 /ydieresis
919     8#271 /zacute
920     8#272 /zcaron
921     8#273 /zdot
922     8#274 /ij
923     8#275 /exclamdown
924     8#276 /questiondown
925     8#277 /sterling
926
927     8#300 /Agrave
928     8#301 /Aacute
929     8#302 /Acircumflex
930     8#303 /Atilde
931     8#304 /Adieresis
932     8#305 /Aring
933     8#306 /AE
934     8#307 /Ccedilla
935     8#310 /Egrave
936     8#311 /Eacute
937     8#312 /Ecircumflex
938     8#313 /Edieresis
939     8#314 /Igrave
940     8#315 /Iacute
941     8#316 /Icircumflex
942     8#317 /Idieresis
943     8#320 /Eth
944     8#321 /Ntilde
945     8#322 /Ograve
946     8#323 /Oacute
947     8#324 /Ocircumflex
948     8#325 /Otilde
949     8#326 /Odieresis
950     8#327 /OE
951     8#330 /Oslash
952     8#331 /Ugrave
953     8#332 /Uacute
954     8#333 /Ucircumflex
955     8#334 /Udieresis
956     8#335 /Yacute
957     8#336 /Thorn
958     8#337 /Germandbls 
959
960     8#340 /agrave
961     8#341 /aacute
962     8#342 /acircumflex
963     8#343 /atilde
964     8#344 /adieresis
965     8#345 /aring
966     8#346 /ae
967     8#347 /ccedilla
968     8#350 /egrave
969     8#351 /eacute
970     8#352 /ecircumflex
971     8#353 /edieresis
972     8#354 /igrave
973     8#355 /iacute
974     8#356 /icircumflex
975     8#357 /idieresis
976     8#360 /eth
977     8#361 /ntilde
978     8#362 /ograve
979     8#363 /oacute
980     8#364 /ocircumflex
981     8#365 /otilde
982     8#366 /odieresis
983     8#367 /oe
984     8#370 /oslash
985     8#371 /ugrave
986     8#372 /uacute
987     8#373 /ucircumflex
988     8#374 /udieresis
989     8#375 /yacute
990     8#376 /thorn
991     8#377 /germandbls
992
993 T1.encode
994
995 %%* Now copy OT1Encoding into T1Encoding and make a few changes.
996
997 T1Encoding OT1Encoding copy pop
998
999 mark
1000     8#000 /Gamma
1001     8#001 /Delta
1002     8#002 /Theta
1003     8#003 /Lambda
1004     8#004 /Xi
1005     8#005 /Pi
1006     8#006 /Sigma
1007     8#007 /Upsilon
1008
1009     8#010 /Phi
1010     8#011 /Psi
1011     8#012 /Omega
1012     8#013 /ff
1013     8#014 /fi
1014     8#015 /fl
1015     8#016 /ffi
1016     8#017 /ffl
1017
1018     8#020 /dotlessi
1019     8#021 /dotlessj
1020     8#022 /grave
1021     8#023 /acute
1022     8#024 /caron
1023     8#025 /breve
1024     8#026 /macron
1025     8#027 /ring
1026
1027     8#030 /cedilla
1028     8#031 /germandbls
1029     8#032 /ae
1030     8#033 /oe
1031     8#034 /oslash
1032     8#035 /AE
1033     8#036 /OE
1034     8#037 /Oslash
1035
1036     8#040 /polishslash
1037
1038     8#042 /quotedblright
1039
1040     8#074 /exclamdown
1041     8#076 /questiondown
1042
1043     8#134 /quotedblleft
1044     8#137 /dotaccent
1045
1046     8#173 /endash
1047     8#174 /emdash
1048     8#175 /hungarumlaut
1049     8#177 /dieresis
1050 OT1.encode
1051
1052 %%* And add a few characters from the OT1Encoding
1053
1054 mark
1055     /Gamma              (\\Gamma )
1056     /Delta              (\\Delta )
1057     /Theta              (\\Theta )
1058     /Lambda             (\\Lambda )
1059     /Xi                 (\\Xi )
1060     /Pi                 (\\Pi )
1061     /Sigma              (\\Sigma )
1062     /Upsilon            (\\Upsilon )
1063
1064     /Phi                (\\Phi )
1065     /Psi                (\\Psi )
1066     /Omega              (\\Omega )
1067
1068     /dotlessj           (j)
1069     /ff                 (ff)
1070
1071     /cwm                ()
1072
1073     /perthousandzero    (0)
1074
1075     /polishslash        ()
1076
1077     /Abreve             (A*)
1078     /Aogonek            (A,)
1079     /Cacute             (C')
1080     /Ccaron             (C^)
1081     /Dcaron             (D^)
1082     /Ecaron             (E^)
1083     /Eogonek            (E,)
1084     /Gbreve             (G*)
1085     /Lacute             (L')
1086     /Lcaron             (L^)
1087     /Nacute             (N')
1088     /Ncaron             (N^)
1089     /Eng                (NG)
1090     /Ohungarumlaut      (O"")
1091     /Racute             (R')
1092     /Rcaron             (R^)
1093     /Sacute             (S')
1094     /Scaron             (S^)
1095     /Scedilla           (S,)
1096     /Tcaron             (T^)
1097     /Tcedilla           (T,)
1098     /Uhungarumlaut      (U"")
1099     /Uring              (U*)
1100     /Ydieresis          (Y")
1101     /Zacute             (Z')
1102     /Zcaron             (Z^)
1103     /Zdot               (Z.)
1104     /IJ                 (IJ)
1105     /Idot               (I.)
1106     /dbar               (d-)
1107     /abreve             (a*)
1108     /aogonek            (a,)
1109     /cacute             (c')
1110     /ccaron             (c^)
1111     /dcaron             (d^)
1112     /ecaron             (e^)
1113     /eogonek            (e,)
1114     /gbreve             (g*)
1115     /lacute             (l')
1116     /lcaron             (l^)
1117     /nacute             (n')
1118     /ncaron             (n^)
1119     /eng                (ng)
1120     /ohungarumlaut      (o"")
1121     /racute             (r')
1122     /rcaron             (r^)
1123     /sacute             (s')
1124     /scaron             (s^)
1125     /scedilla           (s,)
1126     /tcaron             (t^)
1127     /tcedilla           (t,)
1128     /uhungarumlaut      (u"")
1129     /uring              (u*)
1130     /zacute             (z')
1131     /zcaron             (z^)
1132     /zdot               (z.)
1133     /ij                 (ij)
1134     /Germandbls         (SS)
1135 .chars.def
1136
1137 %%* We extend the df-tail command to stick in an Encoding vector (see
1138 %%* above for a discussion of the T1 and OT1 encodings), put in a
1139 %%* FontName (which will just be dvips's name for the font, i.e., Fa,
1140 %%* Fb, etc.) and give each font a separate FontBBox instead of
1141 %%* letting them all share a single one.
1142
1143 /dvips.df-tail      % id numcc maxcc df-tail
1144   {
1145     /nn 9 dict N
1146     nn begin
1147         %%  
1148         %%  Choose an encoding based on the highest position occupied.
1149         %%  
1150         dup 128 gt { T1Encoding } { OT1Encoding } ifelse
1151         /Encoding X
1152         /FontType 3 N
1153         %%
1154         %%  It's ok for all the fonts to share a FontMatrix, but they
1155         %%  need to have separate FontBBoxes
1156         %%
1157         /FontMatrix fntrx N
1158         /FontBBox [0 0 0 0] N
1159         string /base X
1160         array /BitMaps X
1161         %%
1162         %%  And let's throw in a FontName for good measure
1163         %%
1164         dup (    ) cvs
1165         %%  
1166         %%  Make sure each font gets it own private FontName.  -- dmj,
1167         %%  12/23/97
1168         %%  
1169         dup length string copy
1170         /FontName X
1171         /BuildChar {CharBuilder} N
1172     end
1173     dup { /foo setfont }
1174        2 array copy cvx N
1175     load
1176        0 nn put
1177     /ctr 0 N
1178     [
1179 } def
1180
1181 %%* This is functionally equivalent to dvips's /D procedure, but it
1182 %%* also calculates the Font Bounding Box while defining the
1183 %%* characters.
1184
1185 /dvips.D   % char-data ch D - : define character bitmap in current font
1186 {
1187     /cc X                           % char-data
1188     dup type /stringtype ne {]} if  % char-data
1189
1190     /ch-xoff where
1191     { pop }
1192     { dup /Cd exch def
1193       /ch-width { Cw } def
1194       /ch-height { Ch } def
1195       /ch-xoff { Cx } def
1196       /ch-yoff { Cy } def
1197       /ch-dx { Cdx } def
1198     } ifelse
1199     /ch-data X
1200     nn /base get cc ctr put     % (adds ctr to cc'th position of BASE)
1201     nn /BitMaps get
1202     ctr
1203     ch-data                     % BitMaps ctr char-data
1204     sf 1 ne {
1205        dup dup length 1 sub dup 2 index S get sf div put
1206     } if
1207     put                         % puts char-data into BitMaps at index ctr
1208     /ctr ctr 1 add N
1209 %%  
1210 %%  Make sure the Font Bounding Box encloses the Bounding Box of the
1211 %%  current character
1212 %%
1213     nn /FontBBox get        % BB
1214
1215     dup                     % calculate new llx
1216     dup 0 get
1217     ch-xoff
1218     .min
1219     0 exch put
1220
1221     dup                     % calculate new lly
1222     dup 1 get
1223     ch-yoff ch-height sub
1224     .min
1225     1 exch put
1226
1227     dup                     % calculate new urx
1228     dup 2 get
1229     ch-dx ch-width add
1230     .max 
1231     2 exch put
1232
1233     dup 3 get               % calculate new ury
1234     ch-yoff
1235     .max 
1236     3 exch put
1237
1238 } def
1239
1240 %%* Define start-hook to replace df-tail and D by our versions.
1241 %%* Unfortunately, the user can redefine start-hook and thus bypass
1242 %%* these changes, but I don't see an obvious way around that.
1243
1244 userdict /start-hook {
1245     TeXDict /df-tail /dvips.df-tail load bind put
1246     TeXDict /D       /dvips.D       load bind put
1247 } put
1248
1249 %%* Introduce a symbolic constant for hyphens.  (Need to make
1250 %%* allowance for hyphen being in different place?)
1251
1252 /.hyphen 45 def
1253
1254 % Write out a string.  If it ends in a letter and a hyphen,
1255 % don't write the hyphen, and set .show.last to a hyphen;
1256 % otherwise, set .show.last to the character (or \000 if it was a hyphen).
1257 /.show.write    % <string>
1258  {
1259     dup length 1 ge
1260         { dup dup length 1 sub get      % string last_char
1261           dup .hyphen eq                % string last_char hyphen?
1262             {                           % string last_char
1263                 1 index length 1 gt
1264                     { 1 index dup length 2 sub get }
1265                     { //.show.last 0 get }
1266                 ifelse                  % string last_char prev-char
1267                 currentfont /Encoding get exch get  % look up prev-char
1268                 //.letter.chars exch known          % is it a letter?
1269                     { % Remove the hyphen           % string last_char
1270                         exch                        % last_char string
1271                         dup length 1 sub            % last_char string len-1
1272                         0 exch getinterval          % last_char string-1
1273                         exch                        % string-1 last_char
1274                     }
1275                     { pop 0 }                       % string 0
1276                 ifelse
1277             }
1278           if
1279           //.show.last 0 3 -1 roll put              % store last_char
1280                                                     % in .show.last
1281                                                     % If .show.last ==
1282                                                     % hyphen, then
1283                                                     % last char of
1284                                                     % previous string
1285                                                     % was a hyphen
1286         }
1287     if                                          % string
1288     currentfont /FontType get 0 ne
1289       {
1290           { % begin forall                          % c
1291             dup                                     % c c
1292             currentfont /Encoding get               % c c vec
1293             exch get                                % c name
1294             dup //.char.map exch known              % c name bool
1295               { exch pop }
1296               { pop OT1Encoding exch get }
1297             ifelse                                  % name
1298             //.char.map exch get                    % translation
1299             .show.stdout exch writestring
1300           }
1301         forall
1302       }
1303       { (\0) dup 0 get 0 eq
1304           { 0 1 put
1305             (%stderr) (w) file dup
1306             (*** Warning: composite font characters dumped without decoding.\n) writestring
1307             closefile
1308           }
1309           { pop
1310           }
1311         ifelse 
1312         .show.stdout exch writestring
1313       }
1314     ifelse
1315 } odef
1316
1317 /.showstring1 {                 % string
1318     currentpoint .coord         % string x y
1319     3 -1 roll dup .showwidth    % x y string dx dy
1320     1 index                     % x y string dx dy dx
1321     0 rmoveto                   % x y string dx dy
1322     .dcoord pop                 % x y string width
1323     SIMPLE
1324       {                         % x y string width
1325         2 index                 % x y string width y
1326         //.show.y .iget         % x y string width y old.y
1327         %%* 
1328         %%* Replaced test "has y changed" by "has y changed by more
1329         %%* than the current font height" so that subscripts and
1330         %%* superscripts won't cause line/paragraph breaks
1331         %%* 
1332          sub abs dup            % x y string width dy dy
1333          //.show.height .iget
1334          gt
1335          {                      % x y string width dy
1336
1337             %%* Vertical position has changed by more than the font
1338             %%* height, so we now try to figure out whether we've
1339             %%* started a new paragraph or merely a new line, using a
1340             %%* variety of heuristics.
1341
1342             %%* If any of the following is true, we start a new
1343             %%* paragraph:
1344
1345             %%* (a) the current vertical shift is more than 1.1 times
1346             %%*     the previous vertical shift, where 1.1 is an
1347             %%*     arbitrarily chosen factor that could probably be
1348             %%*     refined.
1349
1350             dup                 % x y string width dy dy
1351             //.show.dy .iget 1.1 mul
1352             gt
1353             exch
1354
1355             %%* Save the new vertical shift
1356
1357             //.show.dy exch .iput
1358
1359             %%* (b) The vertical shift is more than 1.3 times the
1360             %%*     "size" of the current font.  I've removed this
1361             %%*     test since it's not really very useful.
1362
1363 %%*            //.show.dy .iget
1364 %%*            //.show.height .iget 1.4 mul
1365 %%*            gt                          % x y string width bool
1366 %%*            .show.height .iget 0 gt and % only perform test if font
1367 %%*                                        % height is nonzero
1368 %%*            or
1369
1370             %%* (c) the first character of the new line is one of the
1371             %%*     .break.chars
1372
1373             2 index length      % x y string width newpar? len
1374             0 gt                % x y string width newpar? len>0?
1375               {
1376                 2 index 0 get   % x y string width newpar? s
1377                 currentfont /Encoding get
1378                 exch get        % x y string width newpar? s_enc
1379                 //.break.chars exch known { pop true } if
1380               }
1381             if                  % x y string width newpar?
1382
1383             %%* (d) The indentation of the new line is greater than
1384             %%*     the indentation of the previous line.
1385
1386             4 index
1387             //.show.indent .iget
1388             gt
1389             or
1390
1391             %%* HOWEVER, if the line ends in a hyphen, we do NOT begin
1392             %%* a new paragraph (cf. comment at end of BF2).  --dmj,
1393             %%* 12/23/97
1394
1395             //.show.last 0 get .hyphen ne
1396             and
1397
1398             % newpar?
1399               { (\n\n) }        % Paragraph
1400               {                 % Line
1401                                 %%* 
1402                                 %%* BF2: If last character on a line is
1403                                 %%* a hyphen, we omit the hyphen and
1404                                 %%* run the lines together.  Of
1405                                 %%* course, this will fail if a word
1406                                 %%* with an explicit hyphen (e.g.,
1407                                 %%* X-ray) is split across two lines.
1408                                 %%* Oh, well.  (What should we do
1409                                 %%* about a hyphen that ends a
1410                                 %%* "paragraph"?  Perhaps that should
1411                                 %%* inhibit a paragraph break.)
1412                                 %%*
1413                 //.show.last 0 get .hyphen eq
1414                     { ()  }
1415                     { ( ) }
1416                 ifelse          % x y string width char
1417               }
1418             ifelse
1419             //print
1420
1421             //.show.y 3 index .iput % x y string width
1422             //.show.x 4 index .iput % x y string width
1423             //.show.indent 4 index .iput
1424          }
1425          {                      % x y string width dy
1426                   % If the word processor split a hyphenated word within
1427                   % the same line, put out the hyphen now.
1428             pop
1429             //.show.last 0 get .hyphen eq { (-) //print } if
1430          }
1431         ifelse
1432                                 %%* 
1433                                 %%* If have moved more than 1 point to
1434                                 %%* the right, interpret it as a
1435                                 %%* space?  This need to be looked at
1436                                 %%* more closely.
1437                                 %%* 
1438         3 index                     % x y string width x
1439         //.show.x .iget 10 add gt   % x y string width bool
1440             { ( ) //print }
1441         if
1442                                     % x y string width
1443         4 1 roll                    % width x y string
1444         .show.write pop             % width x
1445         add //.show.x exch .iput    % <empty>
1446       }
1447       { (S ) //print .show==4 }
1448     ifelse
1449 } odef
1450
1451 /.showstring
1452  { dup () eq { pop } { .showstring1 } ifelse
1453  } bind def
1454
1455 % Redefine all the string display operators.
1456
1457 /show {
1458     .showfont
1459     .showcolor
1460     .showstring
1461 } codef
1462
1463 % We define all the other operators in terms of .show1.
1464
1465 /.show1.string ( ) def
1466 /.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef
1467 /ashow
1468  { .showfont .showcolor
1469    { .show1 2 copy rmoveto } forall
1470    pop pop
1471  } codef
1472 /awidthshow
1473  { .showfont .showcolor
1474     { dup .show1 4 index eq { 4 index 4 index rmoveto } if
1475       2 copy rmoveto
1476     }
1477    forall
1478    pop pop pop pop pop
1479  } codef
1480 /widthshow
1481  { .showfont .showcolor
1482    //.show1.string 0 4 -1 roll put
1483     { //.show1.string search not { exit } if
1484       .showstring .showstring
1485       2 index 2 index rmoveto
1486     } loop
1487    .showstring pop pop
1488  } codef
1489 /kshow
1490  { .showfont .showcolor
1491         %**************** Should construct a closure, in case the procedure
1492         %**************** affects the o-stack.
1493     { .show1 dup exec } forall pop
1494  } codef
1495
1496 % We don't really do the right thing with the Level 2 show operators,
1497 % but we do something semi-reasonable.
1498 /xshow { pop show } codef
1499 /yshow { pop show } codef
1500 /xyshow { pop show } codef
1501 /glyphshow
1502  { currentfont /Encoding .knownget not { {} } if
1503    0 1 2 index length 1 sub
1504     {           % Stack: glyph encoding index
1505       2 copy get 3 index eq { exch pop exch pop null exit } if
1506       pop
1507     }
1508    for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse
1509  } codef
1510
1511 end
1512
1513 % Bind the operators we just defined, and all the others if we didn't
1514 % do it before.
1515
1516 DELAYBIND { .bindnow } if
1517
1518 % Make systemdict read-only if it wasn't already.
1519
1520 systemdict wcheck { systemdict readonly pop } if
1521
1522 % Restore the current local/global VM mode.
1523
1524 exec