changeset 7257:3759ad84023b

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Sun, 01 May 1994 22:09:01 +0000
parents 0f06f87f3c3b
children 68c7b93914fe
files lisp/ps-print.el
diffstat 1 files changed, 962 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/ps-print.el	Sun May 01 22:09:01 1994 +0000
@@ -0,0 +1,962 @@
+;; Jim's Pretty-Good PostScript Generator for Emacs 19 (ps-print).
+;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+;; Author: James C. Thompson <thompson@wg2.waii.com>
+;; Keywords: faces, postscript, printing
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; Acknowledgements
+;; ----------------
+;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
+;; the Emacs 19 port.
+;;
+;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
+;; for adding underline support and title code.  (Titling will appear
+;; in the next release.)
+;;
+;; Thanks to Heiko Muenkel, muenkel@tnt.uni-hannover.de, for showing
+;; me how to handle ISO-8859/1 characters.
+;;
+;; Code to handle ISO-8859/1 characters borrowed from the mp prologue
+;; file mp.pro.ps, used with permission of Rich Burridge of Sun
+;; Microsystems (Rich.Burridge@eng.sun.com).
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; About ps-print:
+;; --------------
+;; This package provides printing of Emacs buffers on PostScript
+;; printers; the buffer's bold and italic text attributes are
+;; preserved in the printer output.  Ps-print is intended for use with
+;; Emacs 19 (Lucid or FSF) and a fontifying package such as font-lock
+;; or hilit.
+;; 
+;; Installing ps-print:
+;; -------------------
+;; Place ps-print somewhere in your load-path and byte-compile it.
+;; Load ps-print with (require 'ps-print).
+;;
+;; Using ps-print:
+;; --------------
+;; The variables ps-bold-faces and ps-italic-faces *must* contain
+;; lists of the faces that you wish to print in bold or italic font.
+;; These variables already contain some default values, but most users
+;; will probably have to add some of their own.  To add a face to one
+;; of these lists, put code something like the following into your
+;; .emacs startup file:
+;;
+;;   (setq ps-bold-faces (cons 'my-bold-face ps-bold-faces))
+;;
+;; Ps-print's printer interface is governed by the variables ps-lpr-
+;; command and ps-lpr-switches; these are analogous to the variables
+;; lpr-command and lpr-switches in the Emacs lpr package.
+;;
+;; To use ps-print, invoke the command ps-print-buffer-with-faces.
+;; This will generate a PostScript image of the current buffer and
+;; send it to the printer.  Precede this command with a numeric prefix
+;; (C-u), and the PostScript output will be saved in a file; you will
+;; be prompted for a filename.  Also see the functions ps-print-
+;; buffer, ps-print-region, and ps-print-region-with-faces.
+;;
+;; I recommend binding ps-print-buffer-with-faces to a key sequence;
+;; on a Sun 4 keyboard, for example, you can bind to the PrSc key (aka
+;; r22):
+;;
+;;   (global-set-key 'f22 'ps-print-buffer-with-faces)
+;;   (global-set-key '(shift f22) 'ps-print-region-with-faces)
+;;
+;; Or, as I now prefer, you can also bind the ps-spool- functions to
+;; keys; here's my bindings:
+;;
+;;   (global-set-key 'f22 'ps-spool-buffer-with-faces)
+;;   (global-set-key '(shift f22) 'ps-spool-region-with-faces)
+;;   (global-set-key '(control f22) 'ps-despool)
+;;
+;; Using ps-print with other Emacses:
+;; ---------------------------------
+;; Although it was intended for use with Emacs 19, ps-print will also work
+;; with Emacs version 18; you won't get fancy fontified output, but it
+;; should work.
+;; 
+;; A few words about support:
+;; -------------------------
+;; Despite its appearance, with comment blocks, usage instructions, and
+;; documentation strings, ps-print is not a supported package.  That's all
+;; a masquerade.  Ps-print is something I threw together in my spare time--
+;; an evening here, a Saturday there--to make my printouts look like my
+;; Emacs buffers.  It works, but is not complete.
+;;
+;; Unfortunately, supporting elisp code is not my job and, now that I have
+;; what I need out of ps-print, additional support is going to be up to
+;; you, the user.  But that's the spirit of Emacs, isn't it?  I call on
+;; all who use this package to help in developing it further. If you
+;; notice a bug, fix it and send me the patches.  If you add a feature,
+;; again, send me the patches.  I will collect all such contributions and
+;; periodically post the updates to the appropriate places.
+;;
+;; A few more words about support:
+;; ------------------------------
+;; The response to my call for public support of ps-print has been
+;; terrific.  With the exception of the spooling mechanism, all the new
+;; features in this version of ps-print were contributed by users.  I have
+;; some contributed code for printing headers that I'll add to the next
+;; release of ps-print, but there are still other features that users can
+;; write.  See the "Features to Add" list a little further on, and keep
+;; that elisp rolling in.
+;;
+;; Please send all bug fixes and enhancements to me, thompson@wg2.waii.com.
+;;
+;; New in version 1.5
+;; ------------------
+;; Support for Emacs 19.  Works with both overlays and text
+;; properties.
+;;
+;; Underlining.
+;;
+;; Local spooling; see function ps-spool-buffer.
+;;
+;; Support for ISO8859-1 character set.
+;;
+;; Page breaks are now handled correctly.
+;;
+;; Percentages reported while formatting are now correct.
+;;
+;; Known bugs and limitations of ps-print:
+;; --------------------------------------
+;; Slow.  (Byte-compiling helps.)
+;;
+;; The PostScript needs review/cleanup/enhancing by a PS expert.
+;; 
+;; ASCII Control characters other than tab, linefeed and pagefeed are
+;; not handled.
+;;
+;; The mechanism for determining whether a stretch of characters
+;; should be printed bold, italic, or plain is crude and extremely
+;; limited.
+;;
+;; Faces are always treated as opaque.
+;;
+;; Font names are hardcoded.
+;;
+;; Epoch not fully supported.
+;;
+;; Tested with only one PostScript printer.
+;;
+;; Features to add:
+;; ---------------
+;; Line numbers.
+;;
+;; Simple headers with date, filename, and page numbers.
+;;
+;; Gaudy headers a`la enscript and mp.
+;;
+;; 2-up and 4-up capability.
+;;
+;; Wide-print capability.
+;;
+
+;;; Code:
+
+(defconst ps-print-version  (substring "$Revision: 1.5 $" 11 -2)
+  "$Id: ps-print.el,v 1.5 1994/04/22 13:25:18 jct Exp $
+
+Please send all bug fixes and enhancements to Jim Thompson,
+thompson@wg2.waii.com.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defvar ps-lpr-command (if (memq system-type
+				 '(usg-unix-v hpux silicon-graphics-unix))
+			   "lp" "lpr")
+  "The shell command for printing a PostScript file.")
+
+(defvar ps-lpr-switches nil
+  "A list of extra switches to pass to ps-lpr-command.")
+
+(defvar ps-bold-faces
+  '(bold
+    bold-italic
+    font-lock-function-name-face
+    message-headers
+    )
+  "A list of the faces that should be printed italic.")
+
+(defvar ps-italic-faces
+  '(italic
+    bold-italic
+    font-lock-function-name-face
+    font-lock-string-face
+    font-lock-comment-face
+    message-header-contents
+    message-highlighted-header-contents
+    message-cited-text
+    )
+  "A list of the faces that should be printed bold.")
+
+(defvar ps-underline-faces
+  '(underline
+    font-lock-string-face)
+  "A list of the faces that should be printed underline.")
+
+(defvar ps-razzle-dazzle t
+  "Non-nil means report progress while formatting buffer")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-print-buffer (&optional filename)
+
+"Generate and print a PostScript image of the buffer.
+
+When called with a numeric prefix argument (C-u), prompt the user for
+the name of a file to save the PostScript image in, instead of sending
+it to the printer.
+
+More specifically, the FILENAME argument is treated as follows: if it
+is nil, send the image to the printer.  If FILENAME is a string, save
+the PostScript image in a file with that name.  If FILENAME is a
+number, prompt the user for the name of the file to save in.
+
+The image is rendered using the PostScript font Courier.
+
+See also: ps-print-buffer-with-faces
+          ps-spool-buffer
+          ps-spool-buffer-with-faces"
+
+  (interactive "P")
+  (setq filename (ps-preprint filename))
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript)
+  (ps-do-despool filename))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-print-buffer-with-faces (&optional filename)
+
+"Generate and print a PostScript image of the buffer.
+
+This function works like ps-print-buffer, with the additional benefit
+that any bold/italic formatting information present in the buffer
+(contained in extents and faces) will be retained in the PostScript
+image. In other words, WYSIAWYG -- What You See Is (Almost) What You
+Get.
+
+Ps-print uses three lists to determine which faces should be printed
+bold, italic, and/or underlined; the lists are named ps-bold-faces, ps-
+italic-faces, and ps-underline-faces.  A given face should appear on as
+many lists as are appropriate; for example, face bold-italic is in both
+the lists ps-bold-faces and ps-italic-faces.  The lists are pre-built
+with the standard bold, italic, and bold-italic faces, with font-lock's
+faces, and with the faces used by gnus and rmail.
+
+The image is rendered using the PostScript fonts Courier, Courier-Bold,
+Courier-Oblique, and Courier-BoldOblique.
+
+See also: ps-print-buffer
+          ps-spool-buffer
+          ps-spool-buffer-with-faces."
+
+  (interactive "P")
+  (setq filename (ps-preprint filename))
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript-with-faces)
+  (ps-do-despool filename))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-print-region (from to &optional filename)
+
+"Generate and print a PostScript image of the region.
+
+When called with a numeric prefix argument (C-u), prompt the user for
+the name of a file to save the PostScript image in, instead of sending
+it to the printer.
+
+This function is essentially the same as ps-print-buffer except that it
+prints just a region, and not the entire buffer.  For more information,
+see the function ps-print-buffer.
+
+See also: ps-print-region-with-faces
+          ps-spool-region
+          ps-spool-region-with-faces"
+  
+  (interactive "r\nP")
+  (setq filename (ps-preprint filename))
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript)
+  (ps-do-despool filename))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-print-region-with-faces (from to &optional filename)
+
+"Generate and print a PostScript image of the region.
+
+This function is essentially the same as ps-print-buffer except that it
+prints just a region, and not the entire buffer.  See the functions
+ps-print-region and ps-print-buffer-with-faces for
+more information.
+
+See also: ps-print-region
+          ps-spool-region
+          ps-spool-region-with-faces"
+  
+  (interactive "r\nP")
+  (setq filename (ps-preprint filename))
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript-with-faces)
+  (ps-do-despool filename))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-spool-buffer ()
+
+"Generate and spool a PostScript image of the buffer.
+
+This function is essentially the same as function ps-print-buffer
+except that the PostScript image is saved in a local buffer to be sent
+to the printer later.
+
+Each time you call one of the ps-spool- functions, the generated
+PostScript is appended to a buffer named *PostScript*; to send the
+spooled PostScript to the printer, or save it to a file, use the command
+ps-despool.
+
+If the variable ps-spool-duplex is non-nil, then the spooled PostScript
+is padded with blank pages, when needed, so that each printed buffer
+will start on a front page when printed on a duplex printer (a printer
+that prints on both sides on the paper).  Users of non-duplex printers
+will want to leave ps-spool-duplex nil.
+
+The spooling mechanism was designed for printing lots of small files
+(mail messages or netnews articles) to save paper that would otherwise
+be wasted on banner pages, and to make it easier to find your output at
+the printer (it's easier to pick up one 50-page printout than to find 50
+single-page printouts).
+
+Ps-print has a hook in the kill-emacs-hook list so that you won't
+accidently quit from Emacs while you have unprinted PostScript waiting
+in the spool buffer.  If you do attempt to exit with spooled PostScript,
+you'll be asked if you want to print it, and if you decline, you'll be
+asked to confirm the exit; this is modeled on the confirmation that
+Emacs uses for modified buffers.
+
+See also: ps-despool
+          ps-print-buffer
+          ps-print-buffer-with-faces
+          ps-spool-buffer-with-faces"
+
+  (interactive)
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-spool-buffer-with-faces ()
+
+"Generate and spool PostScript image of the buffer.
+
+This function is essentially the same as function ps-print-buffer-with-
+faces except that the PostScript image is saved in a local buffer to be
+sent to the printer later.
+
+Use the function ps-despool to send the spooled images to the printer.
+See the function ps-spool-buffer for a description of the spooling
+mechanism.
+
+See also: ps-despool
+          ps-spool-buffer
+          ps-print-buffer
+          ps-print-buffer-with-faces"
+
+  (interactive)
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript-with-faces))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-spool-region (from to)
+
+"Generate PostScript image of the region and spool locally.
+
+This function is essentially the same as function ps-print-region except
+that the PostScript image is saved in a local buffer to be sent to the
+printer later.
+
+Use the function ps-despool to send the spooled images to the printer.
+See the function ps-spool-buffer for a description of the spooling
+mechanism.
+
+See also: ps-despool
+          ps-spool-buffer
+          ps-print-buffer
+          ps-print-buffer-with-faces"
+
+  (interactive "r")
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-spool-region-with-faces (from to)
+
+"Generate PostScript image of the region and spool locally.
+
+This function is essentially the same as function ps-print-region-with-
+faces except that the PostScript image is saved in a local buffer to be
+sent to the printer later.
+
+Use the function ps-despool to send the spooled images to the printer.
+See the function ps-spool-buffer for a description of the spooling
+mechanism.
+
+See also: ps-despool
+          ps-spool-buffer
+          ps-print-buffer
+          ps-print-buffer-with-faces"
+
+  (interactive "r")
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript-with-faces))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar ps-spool-duplex nil		; Not many people have duplex
+					; printers, so default to nil.
+  "*Non-nil indicates spooling is for a two-sided printer.
+For a duplex printer, the ps-spool functions will insert blank pages
+as needed between print jobs so that the next buffer printed will
+start on the right page.")
+
+(defun ps-despool (&optional filename)
+  "Send the spooled PostScript to the printer.
+
+When called with a numeric prefix argument (C-u), prompt the user for
+the name of a file to save the spooled PostScript in, instead of sending
+it to the printer.
+
+More specifically, the FILENAME argument is treated as follows: if it
+is nil, send the image to the printer.  If FILENAME is a string, save
+the PostScript image in a file with that name.  If FILENAME is a
+number, prompt the user for the name of the file to save in."
+
+  (interactive "P")
+
+;; If argument FILENAME is nil, send the image to the printer; if
+;; FILENAME is a string, save the PostScript image in that filename;
+;; if FILENAME is a number, prompt the user for the name of the file
+;; to save in.
+
+  (setq filename (ps-preprint filename))
+  (ps-do-despool filename))
+
+;; Here end the definitions that users need to know about; proceed
+;; further at your own risk!
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ps-kill-emacs-check ()
+  (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
+	   (buffer-modified-p ps-buffer))
+      (if (y-or-n-p "Unprinted PostScript waiting... print now? ")
+	  (ps-despool)))
+
+  (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
+	   (buffer-modified-p ps-buffer))
+      (if (yes-or-no-p "Unprinted PostScript waiting; exit anyway? ")
+	  nil
+	(error "Unprinted PostScript"))))
+
+(if (fboundp 'add-hook)
+    (add-hook 'kill-emacs-hook 'ps-kill-emacs-check)
+  (if kill-emacs-hook
+      (message "Won't override existing kill-emacs-hook.")
+    (setq kill-emacs-hook 'ps-kill-emacs-check)))
+
+(defun ps-preprint (&optional filename)
+  (if (and filename
+	   (or (numberp filename)
+	       (listp filename)))
+      (setq filename
+	    (let* ((name (concat (buffer-name) ".ps"))
+		   (prompt (format "Save PostScript to file: (default %s) "
+				   name)))
+	      (read-file-name prompt default-directory
+			      name nil)))))
+
+(defvar ps-spool-buffer-name "*PostScript*")
+
+(defvar ps-col 0)
+(defvar ps-row 0)
+(defvar ps-xpos 0)
+(defvar ps-ypos 0)
+
+(defvar ps-chars-per-line 80)
+(defvar ps-lines-per-page 66)
+
+(defvar ps-page-start-ypos 745)
+(defvar ps-line-start-xpos 40)
+
+(defvar ps-char-xpos-inc 6)
+(defvar ps-line-ypos-inc 11)
+
+(defvar ps-current-font 0)
+
+(defvar ps-multiple nil)
+(defvar ps-virtual-page-number 0)
+
+(defun ps-begin-file ()
+  (save-excursion
+    (set-buffer ps-output-buffer)
+    (goto-char (point-min))
+    (setq ps-real-page-number 1)
+    (insert
+"%!PS-Adobe-1.0
+
+/S /show load def
+/M /moveto load def
+/L { gsave newpath 3 1 roll 1 sub M 0 rlineto closepath stroke grestore } def
+
+/F{$fd exch get setfont}def
+
+/StartPage{/svpg save def}def
+/EndPage{svpg restore showpage}def
+
+/SetUpFonts
+ {dup/$fd exch array def{findfont exch scalefont $fd 3 1 roll put}repeat}def
+
+% Define /ISOLatin1Encoding only if it's not already there.
+/ISOLatin1Encoding where { pop save true }{ false } ifelse
+/ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus
+  StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute
+  /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring
+  /cedilla /.notdef /hungarumlaut /ogonek /caron /space /exclamdown /cent
+  /sterling /currency /yen /brokenbar /section /dieresis /copyright
+  /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron
+  /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph
+  /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright
+  /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute
+  /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute
+  /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth
+  /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply
+  /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn
+  /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae
+  /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute
+  /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex
+  /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex
+  /udieresis /yacute /thorn /ydieresis ] def
+{ restore } if
+
+/reencodeISO { %def
+  findfont dup length dict begin
+    { 1 index /FID ne { def }{ pop pop } ifelse } forall
+    /Encoding ISOLatin1Encoding def
+    currentdict end definefont pop
+} bind def
+
+/CourierISO /Courier          	      	     reencodeISO
+/Courier-ObliqueISO /Courier-Oblique  	     reencodeISO
+/Courier-BoldISO /Courier-Bold        	     reencodeISO
+/Courier-BoldObliqueISO /Courier-BoldOblique reencodeISO
+
+3 10 /Courier-BoldObliqueISO
+2 10 /Courier-ObliqueISO
+1 10 /Courier-BoldISO
+0 10 /CourierISO
+4 SetUpFonts
+
+.4 setlinewidth
+")))
+
+(defun ps-end-file ()
+  )
+
+(defun ps-next-page ()
+  (ps-end-page)
+  (ps-begin-page)
+  (ps-set-font ps-current-font)
+  (ps-init-page))
+
+(defun ps-top-of-page () (ps-next-page))
+
+(defun ps-init-page ()
+  (setq ps-row 0)
+  (setq ps-col 0)
+  (setq ps-ypos ps-page-start-ypos)
+  (setq ps-xpos ps-line-start-xpos)
+  (ps-set-font))
+
+(defun ps-begin-page ()
+  (save-excursion
+    (set-buffer ps-output-buffer)
+    (goto-char (point-max))
+    (insert (format "%%%%Page: ? %d\n" ps-real-page-number))
+    (setq ps-real-page-number (+ 1 ps-real-page-number))
+    (insert "StartPage\n0.4 setlinewidth\n")))
+
+(defun ps-end-page ()
+  (save-excursion
+    (set-buffer ps-output-buffer)
+    (goto-char (point-max))
+    (insert "EndPage\n")))
+
+(defun ps-next-line ()
+  (setq ps-row (+ ps-row 1))
+  (if (>= ps-row ps-lines-per-page)
+      (ps-next-page)
+    (setq ps-col 0)
+    (setq ps-xpos ps-line-start-xpos)
+    (setq ps-ypos (- ps-ypos ps-line-ypos-inc))))
+
+(defun ps-continue-line ()
+  (ps-next-line))
+
+(defvar ps-source-buffer nil)
+(defvar ps-output-buffer nil)
+
+(defun ps-basic-plot-string (from to &optional underline-p)
+  (setq text (buffer-substring from to))
+  (save-excursion
+    (set-buffer ps-output-buffer)
+    (goto-char (point-max))
+    (setq count (- to from))
+
+    (if underline-p
+	(insert (format "%d %d %d L\n" ps-xpos ps-ypos
+			(* count ps-char-xpos-inc))))
+  
+    (insert (format "%d %d M (" ps-xpos ps-ypos))
+    (save-excursion
+      (insert text))
+
+    (while (re-search-forward "[()\\]" nil t)
+      (save-excursion
+        (forward-char -1)
+        (insert "\\")))
+    
+    (end-of-line)
+    (insert ") S\n")
+
+    (setq ps-xpos (+ ps-xpos (* count ps-char-xpos-inc)))))
+
+(defun ps-basic-plot-whitespace (from to underline-p)
+  (setq count (- to from))
+  (setq ps-xpos (+ ps-xpos (* count ps-char-xpos-inc))))
+
+(defun ps-plot (plotfunc from to &optional underline-p)
+
+  (while (< from to)
+    (setq count (- to from))
+    ;; Test to see whether this region will fit on the current line
+    (if (<= (+ ps-col count) ps-chars-per-line)
+        (progn
+          ;; It fits; plot it.
+          (funcall plotfunc from to underline-p)
+          (setq from to))
+    
+      ;; It needs to be wrapped;  plot part of it, then loop
+      (setq chars-that-will-fit (- ps-chars-per-line ps-col))
+      (funcall plotfunc from (+ from chars-that-will-fit))
+      
+      (ps-continue-line)
+      
+      (setq from (+ from chars-that-will-fit))))
+
+  (if ps-razzle-dazzle
+      (let* ((q-todo (- (point-max) (point-min)))
+	     (q-done (- to (point-min)))
+	     (chunkfrac (/ q-todo 8))
+	     (chunksize (if (> chunkfrac 10000) 10000 chunkfrac)))
+	(if (> (- q-done ps-razchunk) chunksize)
+	    (progn
+	      (setq ps-razchunk q-done)
+	      (setq foo
+		    (if (< q-todo 100)
+			(* (/ q-done q-todo) 100)
+		      (setq basis (/ q-todo 100))
+		      (/ q-done basis)))
+
+	      (message "Formatting... %d%%" foo))))))
+
+(defun ps-set-font (&optional font)
+  (save-excursion
+    (set-buffer ps-output-buffer)
+    (goto-char (point-max))
+    (insert (format "%d F\n" (if font font ps-current-font))))
+  (if font
+      (setq ps-current-font font)))
+
+(defun ps-plot-region (from to font &optional underline-p)
+
+  (ps-set-font font)
+
+  (save-excursion
+    (goto-char from)
+    (while (< from to)
+      (if (re-search-forward "[\t\n\014]" to t)
+          (let ((match (char-after (match-beginning 0))))
+            (cond
+             ((= match ?\n)
+              (ps-plot 'ps-basic-plot-string from (- (point) 1) underline-p)
+              (ps-next-line))
+
+             ((= match ?\t)
+              (ps-plot 'ps-basic-plot-string from (- (point) 1) underline-p)
+	      (setq linestart (save-excursion (beginning-of-line) (point)))
+              (forward-char -1)
+              (setq from (+ linestart (current-column)))
+              (if (re-search-forward "[ \t]+" to t)
+                  (ps-plot 'ps-basic-plot-whitespace from
+			   (+ linestart (current-column)))))
+
+             ((= match ?\014)
+              (ps-plot 'ps-basic-plot-string from (- (point) 1) underline-p)
+              (ps-top-of-page)))
+            (setq from (point)))
+
+        (ps-plot 'ps-basic-plot-string from to underline-p)
+        (setq from to)))))
+
+(defun ps-format-buffer ()
+  (interactive)
+
+  (setq ps-source-buffer (current-buffer))
+  (setq ps-output-buffer (get-buffer-create "%PostScript%"))
+
+  (save-excursion
+    (set-buffer ps-output-buffer)
+    (delete-region (point-max) (point-min)))
+
+  (ps-begin-file)
+  (ps-begin-page)
+  (ps-init-page)
+
+  (ps-plot-region (point-min) (point-max) 0)
+
+  (ps-end-page)
+  (ps-end-file)
+  )
+
+(defun ps-mapper (extent list)
+  (nconc list (list (list (extent-start-position extent) 'push extent)
+                    (list (extent-end-position extent) 'pull extent)))
+  nil)
+
+(defun ps-sorter (a b)
+  (< (car a) (car b)))
+
+(defun ps-extent-sorter (a b)
+  (< (extent-priority a) (extent-priority b)))
+
+(defun overlay-priority (p)
+  (if (setq priority (overlay-get p 'priority)) priority 0))
+
+(defun ps-overlay-sorter (a b)
+  (> (overlay-priority a) (overlay-priority b)))
+
+(defun ps-plot-with-face (from to face)
+
+  (setq bold-p (memq face ps-bold-faces))
+  (setq italic-p (memq face ps-italic-faces))
+  (setq underline-p (memq face ps-underline-faces))
+
+  (cond
+   ((and bold-p italic-p)
+    (ps-plot-region from to 3 underline-p))
+   (italic-p
+    (ps-plot-region from to 2 underline-p))
+   (bold-p
+    (ps-plot-region from to 1 underline-p))
+   (t
+    (ps-plot-region from to 0 underline-p))))
+
+
+(defun ps-generate-postscript-with-faces (from to)
+
+  (save-restriction
+    (narrow-to-region from to)
+    (setq face 'default)
+
+    (cond ((string-match "Lucid" emacs-version)
+	   ;; Build the list of extents...
+	   (let ((a (cons 'dummy nil)))
+	     (map-extents 'ps-mapper nil from to a)
+	     (setq a (cdr a))
+	     (setq a (sort a 'ps-sorter))
+	   
+	     (setq extent-list nil)
+	   
+	     ;; Loop through the extents...
+	     (while a
+	       (setq record (car a))
+	     
+	       (setq position (car record))
+	       (setq record (cdr record))
+	     
+	       (setq type (car record))
+	       (setq record (cdr record))
+	     
+	       (setq extent (car record))
+	     
+	       ;; Plot up to this record.
+	       (ps-plot-with-face from position face)
+	     
+	       (cond
+		((eq type 'push)
+		 (setq extent-list (sort (cons extent extent-list)
+					 'ps-extent-sorter)))
+	      
+		((eq type 'pull)
+		 (setq extent-list (sort (delq extent extent-list)
+					 'ps-extent-sorter))))
+	     
+	       (setq face
+		     (if extent-list
+			 (extent-face (car extent-list))
+		       'default))
+	     
+	       (setq from position)
+	       (setq a (cdr a)))))
+
+	  ((string-match "^19" emacs-version)
+	 
+	   (while (< from to)
+	   
+	     (setq prop-position
+		   (if (setq p (next-property-change from))
+		       (if (> p to) to p)
+		     to))
+
+	     (setq over-position
+		   (if (setq p (next-overlay-change from))
+		       (if (> p to) to p)
+		     to))
+
+	     (setq position
+		   (if (< prop-position over-position)
+		       prop-position
+		     over-position))
+
+	     (setq face
+		   (if (setq f (get-text-property from 'face)) f 'default))
+
+	     (if (setq overlays (overlays-at from))
+		 (progn
+		   (setq overlays (sort overlays 'ps-overlay-sorter))
+		   (while overlays
+		     (if (setq face (overlay-get (car overlays) 'face))
+			 (setq overlays nil)
+		       (setq overlays (cdr overlays))))))
+	   
+	     ;; Plot up to this record.
+	     (ps-plot-with-face from position face)
+	   
+	     (setq from position))))
+
+    (ps-plot-with-face from to face)))
+
+(defun ps-generate-postscript (from to)
+  (ps-plot-region from to 0))
+
+(defun ps-generate (buffer from to genfunc)
+
+  (save-restriction
+    (narrow-to-region from to)
+    (if ps-razzle-dazzle
+	(message "Formatting... %d%%" (setq ps-razchunk 0)))
+
+    (set-buffer buffer)
+    (setq ps-source-buffer buffer)
+    (setq ps-output-buffer (get-buffer-create ps-spool-buffer-name))
+
+    (unwind-protect
+	(progn
+	
+	  (set-buffer ps-output-buffer)
+	  (goto-char (point-min))
+	  (if (looking-at (regexp-quote "%!PS-Adobe-1.0"))
+	      (ps-set-font ps-current-font)
+	    (ps-begin-file))
+	  (ps-begin-page)
+	  (ps-init-page)
+	
+	  (goto-char (point-max))
+	  (if (and ps-spool-duplex
+		   (re-search-backward "^%%Page")
+		   (looking-at "^%%Page.*[24680]$"))
+	      (ps-next-page))
+	    
+	  (set-buffer ps-source-buffer)
+	  (funcall genfunc from to)
+
+	  (ps-end-page)))
+
+    (if ps-razzle-dazzle
+	(message "Formatting... Done."))))
+
+(defun ps-do-despool (filename)
+
+  (if (or (not (boundp 'ps-output-buffer))
+	  (not ps-output-buffer))
+      (message "No spooled PostScript to print.")
+    
+    (ps-end-file)
+  
+    (if filename
+	(save-excursion
+	  (if ps-razzle-dazzle
+	      (message "Saving..."))
+	  
+	  (set-buffer ps-output-buffer)
+	  (setq filename (expand-file-name filename))
+	  (write-region (point-min) (point-max) filename)
+	
+	  (if ps-razzle-dazzle
+	      (message "Wrote %s" filename)))
+
+      ;; Else, spool to the printer
+      (if ps-razzle-dazzle
+	  (message "Printing..."))
+    
+      (save-excursion
+	(set-buffer ps-output-buffer)
+	(apply 'call-process-region
+	       (point-min) (point-max) ps-lpr-command nil 0 nil
+	       ps-lpr-switches))
+
+      (if ps-razzle-dazzle
+	  (message "Printing... Done.")))
+
+    (kill-buffer ps-output-buffer)))
+
+(defun ps-testpattern ()
+  (setq foo 1)
+  (while (< foo 60)
+    (insert "|" (make-string foo ?\ ) (format "%d\n" foo))
+    (setq foo (+ 1 foo))))
+
+(defun pts (stuff)
+  (save-excursion
+    (set-buffer "*scratch*")
+    (goto-char (point-max))
+    (insert "---------------------------------\n"
+            (symbol-name stuff) ":\n"
+            (prin1-to-string (symbol-value stuff))
+            "\n")))
+
+(provide 'ps-print)
+
+;; ps-print.el ends here