home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / GhostScript / !GhostScr / 6_01 / lib / ps2ascii.ps < prev    next >
Text File  |  2000-03-09  |  44KB  |  1,510 lines

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