home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 September / PCWorld_2002-09_cd.bin / Software / Vyzkuste / pdfedit / pdf995.exe / pdf995 / res / convert / ps2ascii.ps < prev    next >
Encoding:
Text File  |  2002-04-03  |  44.6 KB  |  1,509 lines

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