home *** CD-ROM | disk | FTP | other *** search
/ Internet Magazine 2002 February / INTERNET88.ISO / pc / software / windows / bits / pdf995 / data1.cab / Program_Executable_Files / res / ps2ascii.ps < prev    next >
Encoding:
Text File  |  2001-12-08  |  44.8 KB  |  1,511 lines

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