diff lisp/packages/ps-print.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/packages/ps-print.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,2085 @@
+;;; ps-print.el --- Jim's Pretty-Good PostScript Generator for Emacs 19.
+
+;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+
+;; Author: Jim Thompson <thompson@wg2.waii.com>
+;; Keywords: print, PostScript
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; LCD Archive Entry:
+;; ps-print|James C. Thompson|thompson@wg2.waii.com|
+;; Jim's Pretty-Good PostScript Generator for Emacs 19 (ps-print)|
+;; 26-Feb-1994|2.8|~/packages/ps-print.el|
+
+;; Baseline-version: 2.8.  (Jim's last change version -- this
+;; file may have been edited as part of Emacs without changes to the
+;; version number.  When reporting bugs, please also report the
+;; version of Emacs, if any, that ps-print was distributed with.)
+
+;;; Synched up with: FSF 19.30.
+
+;;; Commentary:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 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 or Lucid Emacs, together with a fontifying package such as
+;; font-lock or hilit.
+;;
+;; Using ps-print
+;; --------------
+;;
+;; The Commands
+;;
+;; Ps-print provides eight commands for generating PostScript images
+;; of Emacs buffers:
+;;
+;;        ps-print-buffer
+;;        ps-print-buffer-with-faces
+;;        ps-print-region
+;;        ps-print-region-with-faces
+;;        ps-spool-buffer
+;;        ps-spool-buffer-with-faces
+;;        ps-spool-region
+;;        ps-spool-region-with-faces
+;;
+;; These commands all perform essentially the same function: they
+;; generate PostScript images suitable for printing on a PostScript
+;; printer or displaying with GhostScript.  These commands are
+;; collectively referred to as "ps-print- commands".
+;;
+;; The word "print" or "spool" in the command name determines when the
+;; PostScript image is sent to the printer:
+;;
+;;        print      - The PostScript image is immediately sent to the
+;;                     printer;
+;;
+;;        spool      - The PostScript image is saved temporarily in an
+;;                     Emacs buffer.  Many images may be spooled locally
+;;                     before printing them.  To send the spooled images
+;;                     to the printer, use the command ps-despool.
+;;
+;; 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-hooks 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.
+;;
+;; The word "buffer" or "region" in the command name determines how
+;; much of the buffer is printed:
+;;
+;;        buffer     - Print the entire buffer.
+;;
+;;        region     - Print just the current region.
+;;
+;; The -with-faces suffix on the command name means that the command
+;; will include font, color, and underline information in the
+;; PostScript image, so the printed image can look as pretty as the
+;; buffer.  The ps-print- commands without the -with-faces suffix
+;; don't include font, color, or underline information; images printed
+;; with these commands aren't as pretty, but are faster to generate.
+;;
+;; Two ps-print- command examples:
+;;
+;;        ps-print-buffer             - print the entire buffer,
+;;                                      without font, color, or
+;;                                      underline information, and
+;;                                      send it immediately to the
+;;                                      printer.
+;;
+;;        ps-spool-region-with-faces  - print just the current region;
+;;                                      include font, color, and
+;;                                      underline information, and
+;;                                      spool the image in Emacs to
+;;                                      send to the printer later.
+;;
+;;
+;; Invoking Ps-Print
+;;
+;; To print your buffer, type
+;;
+;;        M-x ps-print-buffer
+;;
+;; or substitute one of the other seven ps-print- commands.  The
+;; command will generate the PostScript image and print or spool it as
+;; specified.  By giving the command a prefix argument
+;;
+;;        C-u M-x ps-print-buffer
+;;
+;; it will save the PostScript image to a file instead of sending it
+;; to the printer; you will be prompted for the name of the file to
+;; save the image to.  The prefix argument is ignored by the commands
+;; that spool their images, but you may save the spooled images to a
+;; file by giving a prefix argument to ps-despool:
+;;
+;;        C-u M-x ps-despool
+;;
+;; When invoked this way, ps-despool will prompt you for the name of
+;; the file to save to.
+;;
+;; Any of the ps-print- commands can be bound to keys; I recommend
+;; binding ps-spool-buffer-with-faces, ps-spool-region-with-faces, and
+;; ps-despool.  Here are the bindings I use on my Sun 4 keyboard:
+;;
+;;   (global-set-key 'f22 'ps-spool-buffer-with-faces) ;f22 is prsc
+;;   (global-set-key '(shift f22) 'ps-spool-region-with-faces)
+;;   (global-set-key '(control f22) 'ps-despool)
+;;
+;;
+;; The Printer Interface
+;;
+;; The variables ps-lpr-command and ps-lpr-switches determine what
+;; command is used to send the PostScript images to the printer, and
+;; what arguments to give the command.  These are analogous to lpr-
+;; command and lpr-switches.
+;;
+;; NOTE: ps-lpr-command and ps-lpr-switches take their initial values
+;;       from the variables lpr-command and lpr-switches.  If you have
+;;       lpr-command set to invoke a pretty-printer such as enscript,
+;;       then ps-print won't work properly.  ps-lpr-command must name
+;;       a program that does not format the files it prints.
+;;
+;;
+;; How Ps-Print Deals With Fonts
+;;
+;; The ps-print-*-with-faces commands attempt to determine which faces
+;; should be printed in bold or italic, but their guesses aren't
+;; always right.  For example, you might want to map colors into faces
+;; so that blue faces print in bold, and red faces in italic.
+;;
+;; It is possible to force ps-print to consider specific faces bold or
+;; italic, no matter what font they are displayed in, by setting the
+;; variables ps-bold-faces and ps-italic-faces.  These variables
+;; contain lists of faces that ps-print should consider bold or
+;; italic; to set them, put code like the following into your .emacs
+;; file:
+;;
+;; 	(setq ps-bold-faces '(my-blue-face))
+;;      (setq ps-italic-faces '(my-red-face))
+;;
+;; Faces like bold-italic that are both bold and italic should go in
+;; *both* lists.
+;;
+;; Ps-print does not attempt to guess the sizes of fonts; all text is
+;; rendered using the Courier font family, in 10 point size.  To
+;; change the font family, change the variables ps-font, ps-font-bold,
+;; ps-font-italic, and ps-font-bold-italic; fixed-pitch fonts work
+;; best, but are not required.  To change the font size, change the
+;; variable ps-font-size.
+;;
+;; If you change the font family or size, you MUST also change the
+;; variables ps-line-height, ps-avg-char-width, and ps-space-width, or
+;; ps-print cannot correctly place line and page breaks.
+;;
+;; Ps-print keeps internal lists of which fonts are bold and which are
+;; italic; these lists are built the first time you invoke ps-print.
+;; For the sake of efficiency, the lists are built only once; the same
+;; lists are referred in later invokations of ps-print.
+;;
+;; Because these lists are built only once, it's possible for them to
+;; get out of sync, if a face changes, or if new faces are added.  To
+;; get the lists back in sync, you can set the variable
+;; ps-build-face-reference to t, and the lists will be rebuilt the
+;; next time ps-print is invoked.
+;;
+;;
+;; How Ps-Print Deals With Color
+;;
+;; Ps-print detects faces with foreground and background colors
+;; defined and embeds color information in the PostScript image.  The
+;; default foreground and background colors are defined by the
+;; variables ps-default-fg and ps-default-bg.  On black-and-white
+;; printers, colors are displayed in grayscale.  To turn off color
+;; output, set ps-print-color-p to nil.
+;;
+;;
+;; Headers
+;;
+;; Ps-print can print headers at the top of each page; the default
+;; headers contain the following four items: on the left, the name of
+;; the buffer and, if the buffer is visiting a file, the file's
+;; directory; on the right, the page number and date of printing.  The
+;; default headers look something like this:
+;;
+;;     ps-print.el                                         1/21
+;;     /home/jct/emacs-lisp/ps/new                     94/12/31
+;; 
+;; When printing on duplex printers, left and right are reversed so
+;; that the page numbers are toward the outside.
+;;
+;; Headers are configurable.  To turn them off completely, set
+;; ps-print-header to nil.  To turn off the header's gaudy framing
+;; box, set ps-print-header-frame to nil.  Page numbers are printed in
+;; "n/m" format, indicating page n of m pages; to omit the total page
+;; count and just print the page number, set ps-show-n-of-n to nil.
+;;
+;; The amount of information in the header can be changed by changing
+;; the number of lines.  To show less, set ps-header-lines to 1, and
+;; the header will show only the buffer name and page number.  To show
+;; more, set ps-header-lines to 3, and the header will show the time of
+;; printing below the date.
+;;
+;; To change the content of the headers, change the variables
+;; ps-left-header and ps-right-header.  These variables are lists,
+;; specifying top-to-bottom the text to display on the left or right
+;; side of the header.  Each element of the list should be a string or
+;; a symbol.  Strings are inserted directly into the PostScript
+;; arrays, and should contain the PostScript string delimiters '(' and
+;; ')'.
+;;
+;; Symbols in the header format lists can either represent functions
+;; or variables.  Functions are called, and should return a string to
+;; show in the header.  Variables should contain strings to display in
+;; the header.  In either case, function or variable, the PostScript
+;; strings delimeters are added by ps-print, and should not be part of
+;; the returned value.
+;;
+;; Here's an example: say we want the left header to display the text
+;;
+;;     Moe
+;;     Larry
+;;     Curly
+;;
+;; where we have a function to return "Moe"
+;;
+;;     (defun moe-func ()
+;;       "Moe")
+;;
+;; a variable specifying "Larry"
+;;
+;;     (setq larry-var "Larry")
+;;
+;; and a literal for "Curly".  Here's how ps-left-header should be
+;; set:
+;;
+;;     (setq ps-left-header (list 'moe-func 'larry-var "(Curly)"))
+;;
+;; Note that Curly has the PostScript string delimiters inside his
+;; quotes -- those aren't misplaced lisp delimiters!  Without them,
+;; PostScript would attempt to call the undefined function Curly,
+;; which would result in a PostScript error.  Since most printers
+;; don't report PostScript errors except by aborting the print job,
+;; this kind of error can be hard to track down.  Consider yourself
+;; warned.
+;;
+;;
+;; Duplex Printers
+;;
+;; If you have a duplex-capable printer (one that prints both sides of
+;; the paper), set ps-spool-duplex to t.  Ps-print will insert blank
+;; pages to make sure each buffer starts on the correct side of the
+;; paper.  Don't forget to set ps-lpr-switches to select duplex
+;; printing for your printer.
+;; 
+;;
+;; Paper Size
+;;
+;; The variable ps-paper-type determines the size of paper ps-print
+;; formats for; it should contain one of the symbols ps-letter,
+;; ps-legal, or ps-a4.  The default is ps-letter.
+;;
+;; 
+;; Installing ps-print
+;; -------------------
+;;
+;; 1. Place ps-print.el somewhere in your load-path and byte-compile
+;;    it.  You can ignore all byte-compiler warnings; they are the
+;;    result of multi-Emacs support.  This step is necessary only if
+;;    you're installing your own ps-print; if ps-print came with your
+;;    copy of Emacs, this been done already.
+;;
+;; 2. Place in your .emacs file the line
+;;
+;;        (require 'ps-print)
+;;
+;;    to load ps-print.  Or you may cause any of the ps-print commands
+;;    to be autoloaded with an autoload command such as:
+;;
+;;      (autoload 'ps-print-buffer "ps-print"
+;;        "Generate and print a PostScript image of the buffer..." t)
+;;
+;; 3. Make sure that the variables ps-lpr-command and ps-lpr-switches
+;;    contain appropriate values for your system; see the usage notes
+;;    below and the documentation of these variables.
+;; 
+;; New since version 1.5
+;; ---------------------
+;; Color output capability.
+;;
+;; Automatic detection of font attributes (bold, italic).
+;;
+;; Configurable headers with page numbers.
+;;
+;; Slightly faster.
+;;
+;; Support for different paper sizes.
+;;
+;; Better conformance to PostScript Document Structure Conventions.
+;;
+;;
+;; Known bugs and limitations of ps-print:
+;; --------------------------------------
+;; Although color printing will work in XEmacs 19.12, it doesn't work
+;; well; in particular, bold or italic fonts don't print in the right
+;; background color.
+;;
+;; Invisible properties aren't correctly ignored in XEmacs 19.12.
+;;
+;; Automatic font-attribute detection doesn't work well, especially
+;; with hilit19 and older versions of get-create-face.  Users having
+;; problems with auto-font detection should use the lists ps-italic-
+;; faces and ps-bold-faces and/or turn off automatic detection by
+;; setting ps-auto-font-detect to nil.
+;;
+;; Automatic font-attribute detection doesn't work with XEmacs 19.12
+;; in tty mode; use the lists ps-italic-faces and ps-bold-faces
+;; instead.
+;;
+;; Still too slow; could use some hand-optimization.
+;;
+;; ASCII Control characters other than tab, linefeed and pagefeed are
+;; not handled.
+;;
+;; Default background color isn't working.
+;;
+;; Faces are always treated as opaque.
+;;
+;; Epoch and Emacs 18 not supported.  At all.
+;;
+;;
+;; Features to add:
+;; ---------------
+;; 2-up and 4-up capability.
+;;
+;; Line numbers.
+;;
+;; Wide-print (landscape) capability.
+;;
+;;
+;; Acknowledgements
+;; ----------------
+;; Thanks to Kevin Rodgers <kevinr@ihs.com> for adding support for
+;; color and the invisible property.
+;;
+;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
+;; the initial port to Emacs 19.  His code is no longer part of
+;; ps-print, but his work is still appreciated.
+;;
+;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
+;; for adding underline support.  Their code also is no longer part of
+;; ps-print, but their efforts are not forgotten.
+;;
+;; Thanks also to all of you who mailed code to add features to
+;; ps-print; although I didn't use your code, I still appreciate your
+;; sharing it with me.
+;;
+;; Thanks to all who mailed comments, encouragement, and criticism.
+;; Thanks also to all who responded to my survey; I had too many
+;; responses to reply to them all, but I greatly appreciate your
+;; interest.
+;;
+;; Jim
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Code:
+
+(defconst ps-print-version "2.8"
+  "ps-print.el,v 2.8 1995/05/04 12:06:10 jct Exp
+
+Jim's last change version -- this file may have been edited as part of
+Emacs without changes to the version number.  When reporting bugs,
+please also report the version of Emacs, if any, that ps-print was
+distributed with.
+
+Please send all bug fixes and enhancements to
+	Jim Thompson <thompson@wg2.waii.com>.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; User Variables:
+
+(defvar ps-lpr-command lpr-command
+  "*The shell command for printing a PostScript file.")
+
+(defvar ps-lpr-switches lpr-switches
+  "*A list of extra switches to pass to `ps-lpr-command'.")
+
+(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-*' commands will insert blank pages
+as needed between print jobs so that the next buffer printed will
+start on the right page.  Also, if headers are turned on, the headers
+will be reversed on duplex printers so that the page numbers fall to
+the left on even-numbered pages.")
+
+;;;###autoload
+(defvar ps-paper-type 'ps-letter
+  "*Specifies the size of paper to format for.  Should be one of
+`ps-letter', `ps-legal', or `ps-a4'.")
+
+(defvar ps-print-header t
+  "*Non-nil means print a header at the top of each page.
+By default, the header displays the buffer name, page number, and, if
+the buffer is visiting a file, the file's directory.  Headers are
+customizable by changing variables `ps-header-left' and
+`ps-header-right'.")
+
+(defvar ps-print-header-frame t
+  "*Non-nil means draw a gaudy frame around the header.")
+
+(defvar ps-show-n-of-n t
+  "*Non-nil means show page numbers as N/M, meaning page N of M.
+Note: page numbers are displayed as part of headers, see variable
+`ps-print-headers'.")
+
+;;;###autoload
+(defvar ps-print-color-p (and (or (fboundp 'x-color-values)	; fsf
+				  (fboundp 'color-instance-rgb-components))
+					; xemacs
+			      (fboundp 'float))
+; Printing color requires both floating point and x-color-values.
+  "*If non-nil, print the buffer's text in color.")
+
+(defvar ps-default-fg '(0.0 0.0 0.0)
+  "*RGB values of the default foreground color.  Defaults to black.")
+
+(defvar ps-default-bg '(1.0 1.0 1.0)
+  "*RGB values of the default background color.  Defaults to white.")
+
+(defvar ps-font-size 10
+  "*Font size, in points, for generating Postscript.")
+
+(defvar ps-font "Courier"
+  "*Font family name for ordinary text, when generating Postscript.")
+
+(defvar ps-font-bold "Courier-Bold"
+  "*Font family name for bold text, when generating Postscript.")
+
+(defvar ps-font-italic "Courier-Oblique"
+  "*Font family name for italic text, when generating Postscript.")
+
+(defvar ps-font-bold-italic "Courier-BoldOblique"
+  "*Font family name for bold italic text, when generating Postscript.")
+
+(defvar ps-avg-char-width (if (fboundp 'float) 5.6 6)
+  "*The average width, in points, of a character, for generating Postscript.
+This is the value that ps-print uses to determine the length,
+x-dimension, of the text it has printed, and thus affects the point at
+which long lines wrap around.  If you change the font or
+font size, you will probably have to adjust this value to match.")
+
+(defvar ps-space-width (if (fboundp 'float) 5.6 6)
+  "*The width of a space character, for generating Postscript.
+This value is used in expanding tab characters.")
+
+(defvar ps-line-height (if (fboundp 'float) 11.29 11)
+  "*The height of a line, for generating Postscript.
+This is the value that ps-print uses to determine the height,
+y-dimension, of the lines of text it has printed, and thus affects the
+point at which page-breaks are placed.  If you change the font or font
+size, you will probably have to adjust this value to match.  The
+line-height is *not* the same as the point size of the font.")
+
+(defvar ps-auto-font-detect t
+  "*Non-nil means automatically detect bold/italic face attributes.
+nil means rely solely on the lists `ps-bold-faces', `ps-italic-faces',
+and `ps-underlined-faces'.")
+
+(defvar ps-bold-faces '()
+  "*A list of the \(non-bold\) faces that should be printed in bold font.
+This applies to generating Postscript.")
+
+(defvar ps-italic-faces '()
+  "*A list of the \(non-italic\) faces that should be printed in italic font.
+This applies to generating Postscript.")
+
+(defvar ps-underlined-faces '()
+  "*A list of the \(non-underlined\) faces that should be printed underlined.
+This applies to generating Postscript.")
+
+(defvar ps-header-lines 2
+  "*Number of lines to display in page header, when generating Postscript.")
+(make-variable-buffer-local 'ps-header-lines)
+
+(defvar ps-left-header
+  (list 'ps-get-buffer-name 'ps-header-dirpart)
+  "*The items to display on the right part of the page header.
+This applies to generating Postscript.
+
+The value should be a list of strings and symbols, each representing an
+entry in the PostScript array HeaderLinesLeft.
+
+Strings are inserted unchanged into the array; those representing
+PostScript string literals should be delimited with PostScript string
+delimiters '(' and ')'.
+
+For symbols with bound functions, the function is called and should
+return a string to be inserted into the array.  For symbols with bound
+values, the value should be a string to be inserted into the array.
+In either case, function or variable, the string value has PostScript
+string delimiters added to it.")
+(make-variable-buffer-local 'ps-left-header)
+
+(defvar ps-right-header
+  (list "/pagenumberstring load" 'time-stamp-yy/mm/dd 'time-stamp-hh:mm:ss)
+  "*The items to display on the left part of the page header.
+This applies to generating Postscript.
+
+See the variable `ps-left-header' for a description of the format of
+this variable.")
+(make-variable-buffer-local 'ps-right-header)
+
+(defvar ps-razzle-dazzle t
+  "*Non-nil means report progress while formatting buffer.")
+
+(defvar ps-adobe-tag "%!PS-Adobe-1.0\n"
+  "*Contains the header line identifying the output as PostScript.
+By default, `ps-adobe-tag' contains the standard identifier.  Some
+printers require slightly different versions of this line.")
+
+(defvar ps-build-face-reference t
+  "*Non-nil means build the reference face lists.
+
+Ps-print sets this value to nil after it builds its internal reference
+lists of bold and italic faces.  By settings its value back to t, you
+can force ps-print to rebuild the lists the next time you invoke one
+of the ...-with-faces commands.
+
+You should set this value back to t after you change the attributes of
+any face, or create new faces.  Most users shouldn't have to worry
+about its setting, though.")
+
+(defvar ps-always-build-face-reference nil
+  "*Non-nil means always rebuild the reference face lists.
+
+If this variable is non-nil, ps-print will rebuild its internal
+reference lists of bold and italic faces *every* time one of the
+-with-faces commands is called.  Most users shouldn't need to set this
+variable.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; User commands
+
+;;;###autoload
+(defun ps-print-buffer (&optional filename)
+  "Generate and print a PostScript image of the buffer.
+
+When called with a numeric prefix argument (C-u), prompts 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."
+
+  (interactive (list (ps-print-preprint current-prefix-arg)))
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript)
+  (ps-do-despool filename))
+
+
+;;;###autoload
+(defun ps-print-buffer-with-faces (&optional filename)
+  "Generate and print a PostScript image of the buffer.
+
+Like `ps-print-buffer', but includes font, color, and underline
+information in the generated image."
+  (interactive (list (ps-print-preprint current-prefix-arg)))
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript-with-faces)
+  (ps-do-despool filename))
+
+
+;;;###autoload
+(defun ps-print-region (from to &optional filename)
+  "Generate and print a PostScript image of the region.
+
+Like `ps-print-buffer', but prints just the current region."
+
+  (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript)
+  (ps-do-despool filename))
+
+
+;;;###autoload
+(defun ps-print-region-with-faces (from to &optional filename)
+  "Generate and print a PostScript image of the region.
+
+Like `ps-print-region', but includes font, color, and underline
+information in the generated image."
+
+  (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript-with-faces)
+  (ps-do-despool filename))
+
+
+;;;###autoload
+(defun ps-spool-buffer ()
+  "Generate and spool a PostScript image of the buffer.
+
+Like `ps-print-buffer' except that the PostScript image is saved in a
+local buffer to be sent to the printer later.
+
+Use the command `ps-despool' to send the spooled images to the printer."
+  (interactive)
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript))
+
+
+;;;###autoload
+(defun ps-spool-buffer-with-faces ()
+  "Generate and spool a PostScript image of the buffer.
+
+Like `ps-spool-buffer', but includes font, color, and underline
+information in the generated image.
+
+Use the command `ps-despool' to send the spooled images to the printer."
+
+  (interactive)
+  (ps-generate (current-buffer) (point-min) (point-max)
+	       'ps-generate-postscript-with-faces))
+
+
+;;;###autoload
+(defun ps-spool-region (from to)
+  "Generate a PostScript image of the region and spool locally.
+
+Like `ps-spool-buffer', but spools just the current region.
+
+Use the command `ps-despool' to send the spooled images to the printer."
+  (interactive "r")
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript))
+
+
+;;;###autoload
+(defun ps-spool-region-with-faces (from to)
+  "Generate a PostScript image of the region and spool locally.
+
+Like `ps-spool-region', but includes font, color, and underline
+information in the generated image.
+
+Use the command `ps-despool' to send the spooled images to the printer."
+  (interactive "r")
+  (ps-generate (current-buffer) from to
+	       'ps-generate-postscript-with-faces))
+
+;;;###autoload
+(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 (list (ps-print-preprint current-prefix-arg)))
+  (ps-do-despool filename))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Utility functions and variables:
+
+(defvar ps-print-emacs-type
+  (cond ((string-match "XEmacs" emacs-version) 'xemacs)
+	((string-match "Lucid" emacs-version) 'lucid)
+	((string-match "Epoch" emacs-version) 'epoch)
+	(t 'emacs)))
+
+(if (or (eq ps-print-emacs-type 'lucid)
+	(eq ps-print-emacs-type 'xemacs))
+    (if (< emacs-minor-version 12)
+	(setq ps-print-color-p nil))
+  (require 'faces))			; face-font, face-underline-p,
+					; x-font-regexp
+
+(defun xemacs-color-device ()
+  (if (and (eq ps-print-emacs-type 'xemacs)
+	   (>= emacs-minor-version 12))
+      (eq (device-class) 'color)
+    t))
+
+(require 'time-stamp)
+
+(defvar ps-print-prologue "% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
+% If the ISOLatin1Encoding vector isn't known, define it.
+/ISOLatin1Encoding where { pop } {
+% Define the ISO Latin-1 encoding vector.
+% The first half is the same as the standard encoding,
+% except for minus instead of hyphen at code 055.
+/ISOLatin1Encoding
+StandardEncoding 0 45 getinterval aload pop
+    /minus
+StandardEncoding 46 82 getinterval aload pop
+%*** NOTE: the following are missing in the Adobe documentation,
+%*** but appear in the displayed table:
+%*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
+% \20x
+    /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+    /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+    /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
+    /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
+% \24x
+    /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
+% \30x
+    /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
+% \34x
+    /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
+256 packedarray def
+} ifelse
+
+/reencodeFontISO { %def
+  dup
+  length 5 add dict			% Make a new font (a new dict
+					% the same size as the old
+					% one) with room for our new
+					% symbols.
+
+  begin					% Make the new font the
+					% current dictionary.
+
+
+    { 1 index /FID ne
+      { def } { pop pop } ifelse
+    } forall				% Copy each of the symbols
+					% from the old dictionary to
+					% the new except for the font
+					% ID.
+
+    /Encoding ISOLatin1Encoding def	% Override the encoding with
+					% the ISOLatin1 encoding.
+
+    % Use the font's bounding box to determine the ascent, descent,
+    % and overall height; don't forget that these values have to be
+    % transformed using the font's matrix.
+    FontBBox
+    FontMatrix transform /Ascent exch def pop
+    FontMatrix transform /Descent exch def pop
+    /FontHeight Ascent Descent sub def
+
+    % Define these in case they're not in the FontInfo (also, here
+    % they're easier to get to.
+    /UnderlinePosition 1 def
+    /UnderlineThickness 1 def
+
+    % Get the underline position and thickness if they're defined.
+    currentdict /FontInfo known {
+      FontInfo
+
+      dup /UnderlinePosition known {
+	dup /UnderlinePosition get
+	0 exch FontMatrix transform exch pop
+	/UnderlinePosition exch def
+      } if
+
+      dup /UnderlineThickness known {
+	/UnderlineThickness get
+	0 exch FontMatrix transform exch pop
+	/UnderlineThickness exch def
+      } if
+
+    } if
+
+    currentdict				% Leave the new font on the
+					% stack
+
+    end					% Stop using the font as the
+					% current dictionary.
+
+    definefont				% Put the font into the font
+					% dictionary
+
+    pop					% Discard the returned font.
+} bind def
+
+/Font {
+  findfont exch scalefont reencodeFontISO
+} def
+
+/F {					% Font select
+  findfont
+  dup /Ascent get /Ascent exch def
+  dup /Descent get /Descent exch def
+  dup /FontHeight get /FontHeight exch def
+  dup /UnderlinePosition get /UnderlinePosition exch def
+  dup /UnderlineThickness get /UnderlineThickness exch def
+  setfont
+} def
+
+/FG /setrgbcolor load def
+
+/bg false def
+/BG {
+  dup /bg exch def
+  { mark 4 1 roll ] /bgcolor exch def } if
+} def
+
+/dobackground {				% width --
+  currentpoint
+  gsave
+    newpath
+    moveto
+    0 Ascent rmoveto
+    dup 0 rlineto
+    0 Descent Ascent sub rlineto
+    neg 0 rlineto
+    closepath
+    bgcolor aload pop setrgbcolor
+    fill
+  grestore
+} def
+
+/dobackgroundstring {			% string --
+  stringwidth pop
+  dobackground
+} def
+
+/dounderline {				% fromx fromy --
+  currentpoint
+  gsave
+    UnderlineThickness setlinewidth
+    4 2 roll
+    UnderlinePosition add moveto
+    UnderlinePosition add lineto
+    stroke
+  grestore
+} def
+
+/eolbg {
+  currentpoint pop
+  PrintWidth LeftMargin add exch sub dobackground
+} def
+
+/eolul {
+  currentpoint exch pop
+  PrintWidth LeftMargin add exch dounderline
+} def
+
+/SL {					% Soft Linefeed
+  bg { eolbg } if
+  ul { eolul } if
+  currentpoint LineHeight sub LeftMargin exch moveto pop
+} def
+
+/HL /SL load def			% Hard Linefeed
+
+/sp1 { currentpoint 3 -1 roll } def
+
+% Some debug
+/dcp { currentpoint exch 40 string cvs print (, ) print = } def
+/dp { print 2 copy
+   exch 40 string cvs print (, ) print = } def
+
+/S {
+  bg { dup dobackgroundstring } if
+  ul { sp1 } if
+  show
+  ul { dounderline } if
+} def
+
+/W {
+  ul { sp1 } if
+  ( ) stringwidth			% Get the width of a space
+  pop					% Discard the Y component
+  mul					% Multiply the width of a
+					% space by the number of
+					% spaces to plot
+  bg { dup dobackground } if
+  0 rmoveto
+  ul { dounderline } if
+} def
+
+/BeginDSCPage {
+  /vmstate save def
+} def
+
+/BeginPage {
+  PrintHeader {
+    PrintHeaderFrame { HeaderFrame } if
+    HeaderText
+  } if
+  LeftMargin
+  BottomMargin PrintHeight add
+  moveto				% move to where printing will
+					% start.
+} def
+
+/EndPage {
+  bg { eolbg } if
+  ul { eolul } if
+  showpage				% Spit out a page
+} def
+
+/EndDSCPage {
+  vmstate restore
+} def
+
+/ul false def
+
+/UL { /ul exch def } def
+
+/h0 14 /Helvetica-Bold Font
+/h1 12 /Helvetica Font
+
+/h1 F
+
+/HeaderLineHeight FontHeight def
+/HeaderDescent Descent def
+/HeaderPad 2 def
+
+/SetHeaderLines {
+  /HeaderOffset TopMargin 2 div def
+  /HeaderLines exch def
+  /HeaderHeight HeaderLines HeaderLineHeight mul HeaderPad 2 mul add def
+  /PrintHeight PrintHeight HeaderHeight sub def
+} def
+
+/HeaderFrameStart {
+  LeftMargin BottomMargin PrintHeight add HeaderOffset add
+} def
+
+/HeaderFramePath {
+  PrintWidth 0 rlineto
+  0 HeaderHeight rlineto
+  PrintWidth neg 0 rlineto
+  0 HeaderHeight neg rlineto
+} def
+
+/HeaderFrame {
+  gsave
+    0.4 setlinewidth
+    HeaderFrameStart moveto
+    1 -1 rmoveto
+    HeaderFramePath
+    0 setgray fill
+    HeaderFrameStart moveto
+    HeaderFramePath
+    gsave 0.9 setgray fill grestore
+    gsave 0 setgray stroke grestore
+  grestore
+} def
+
+/HeaderStart {
+  HeaderFrameStart
+  exch HeaderPad add exch
+  HeaderLineHeight HeaderLines 1 sub mul add HeaderDescent sub HeaderPad add
+} def
+
+/strcat {
+  dup length 3 -1 roll dup length dup 4 -1 roll add string dup
+  0 5 -1 roll putinterval
+  dup 4 2 roll exch putinterval
+} def
+
+/pagenumberstring {
+  PageNumber 32 string cvs
+  ShowNofN {
+    (/) strcat
+    PageCount 32 string cvs strcat
+  } if
+} def
+
+/HeaderText {
+  HeaderStart moveto
+
+  HeaderLinesRight HeaderLinesLeft
+  Duplex PageNumber 1 and 0 eq and { exch } if
+
+  {
+    aload pop
+    exch F
+    gsave
+      dup xcheck { exec } if
+      show
+    grestore
+    0 HeaderLineHeight neg rmoveto
+  } forall
+
+  HeaderStart moveto
+
+   {
+    aload pop
+    exch F
+    gsave
+      dup xcheck { exec } if
+      dup stringwidth pop
+      PrintWidth exch sub HeaderPad 2 mul sub 0 rmoveto
+      show
+    grestore
+    0 HeaderLineHeight neg rmoveto
+  } forall
+} def
+
+/ReportFontInfo {
+  2 copy
+  /t0 3 1 roll Font
+  /t0 F
+  /lh FontHeight def
+  /sw ( ) stringwidth pop def
+  /aw (01234567890abcdefghijklmnopqrstuvwxyz) dup length exch
+  stringwidth pop exch div def
+  /t1 12 /Helvetica-Oblique Font
+  /t1 F
+  72 72 moveto
+  gsave
+    (For ) show
+    128 string cvs show
+    ( ) show
+    32 string cvs show
+    ( point, the line height is ) show
+    lh 32 string cvs show
+    (, the space width is ) show
+    sw 32 string cvs show
+    (,) show
+  grestore
+  0 FontHeight neg rmoveto
+  (and a crude estimate of average character width is ) show
+  aw 32 string cvs show
+  (.) show
+  showpage
+} def
+
+% 10 /Courier ReportFontInfo
+")
+
+;; Start Editing Here:
+
+(defvar ps-source-buffer nil)
+(defvar ps-spool-buffer-name "*PostScript*")
+(defvar ps-spool-buffer nil)
+
+(defvar ps-output-head nil)
+(defvar ps-output-tail nil)
+
+(defvar ps-page-count 0)
+(defvar ps-showpage-count 0)
+
+(defvar ps-current-font 0)
+(defvar ps-current-underline-p nil)
+(defvar ps-default-color (if ps-print-color-p ps-default-fg)) ; black
+(defvar ps-current-color ps-default-color)
+(defvar ps-current-bg nil)
+
+(defvar ps-razchunk 0)
+
+(defvar ps-color-format (if (eq ps-print-emacs-type 'emacs)
+
+			    ;;Emacs understands the %f format; we'll
+			    ;;use it to limit color RGB values to
+			    ;;three decimals to cut down some on the
+			    ;;size of the PostScript output.
+			    "%0.3f %0.3f %0.3f"
+
+			  ;; Lucid emacsen will have to make do with
+			  ;; %s (princ) for floats.
+			  "%s %s %s"))
+
+;; These values determine how much print-height to deduct when headers
+;; are turned on.  This is a pretty clumsy way of handling it, but
+;; it'll do for now.
+(defvar ps-header-title-line-height (if (fboundp 'float) 16.0 16));Helvetica 14
+(defvar ps-header-line-height (if (fboundp 'float) 13.7 14));Helvetica 12
+(defvar ps-header-pad 2)
+
+;; LetterSmall 7.68 inch 10.16 inch
+;; Tabloid 11.0 inch 17.0 inch
+;; Ledger 17.0 inch 11.0 inch
+;; Statement 5.5 inch 8.5 inch
+;; Executive 7.5 inch 10.0 inch
+;; A3 11.69 inch 16.5 inch
+;; A4Small 7.47 inch 10.85 inch
+;; B4 10.125 inch 14.33 inch
+;; B5 7.16 inch 10.125 inch
+
+;; All page dimensions are in PostScript points.
+
+(defvar ps-left-margin 72)		; 1 inch
+(defvar ps-right-margin 72)		; 1 inch
+(defvar ps-bottom-margin 36)		; 1/2 inch
+(defvar ps-top-margin 72)		; 1 inch
+
+;; Letter 8.5 inch x 11.0 inch
+(defvar ps-letter-page-height 792)	; 11 inches
+(defvar ps-letter-page-width 612)	; 8.5 inches
+
+;; Legal 8.5 inch x 14.0 inch
+(defvar ps-legal-page-height 1008)	; 14.0 inches
+(defvar ps-legal-page-width 612)	; 8.5 inches
+
+;; A4 8.26 inch x 11.69 inch
+(defvar ps-a4-page-height 842)	; 11.69 inches
+(defvar ps-a4-page-width 595)	; 8.26 inches
+
+(defvar ps-pages-alist
+  (list (list 'ps-letter ps-letter-page-width ps-letter-page-height)
+	(list 'ps-legal ps-legal-page-width ps-legal-page-height)
+	(list 'ps-a4 ps-a4-page-width ps-a4-page-height)))
+
+;; Define some constants to index into the page lists.
+(defvar ps-page-width-i 1)
+(defvar ps-page-height-i 2)
+
+(defvar ps-page-dimensions nil)
+(defvar ps-print-width nil)
+(defvar ps-print-height nil)
+
+(defvar ps-height-remaining)
+(defvar ps-width-remaining)
+
+(defvar ps-ref-bold-faces nil)
+(defvar ps-ref-italic-faces nil)
+(defvar ps-ref-underlined-faces nil)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Internal functions
+
+(defun ps-get-page-dimensions ()
+  (setq ps-page-dimensions (assq ps-paper-type ps-pages-alist))
+  (let ((ps-page-width (nth ps-page-width-i ps-page-dimensions))
+	(ps-page-height (nth ps-page-height-i ps-page-dimensions)))
+    (setq ps-print-height (- ps-page-height ps-top-margin ps-bottom-margin))
+    (setq ps-print-width (- ps-page-width ps-left-margin ps-right-margin))))
+
+(defun ps-print-preprint (&optional filename)
+  (if (and filename
+	   (or (numberp filename)
+	       (listp filename)))
+      (let* ((name (concat (buffer-name) ".ps"))
+	     (prompt (format "Save PostScript to file: (default %s) "
+			     name)))
+	(read-file-name prompt default-directory
+			name nil))))
+
+;; The following functions implement a simple list-buffering scheme so
+;; that ps-print doesn't have to repeatedly switch between buffers
+;; while spooling.  The functions ps-output and ps-output-string build
+;; up the lists; the function ps-flush-output takes the lists and
+;; insert its contents into the spool buffer (*PostScript*).
+
+(defun ps-output-string-prim (string)
+  (insert "(")				;insert start-string delimiter
+  (save-excursion			;insert string
+    (insert string))
+
+  ;; Find and quote special characters as necessary for PS
+  (while (re-search-forward "[()\\]" nil t)
+    (save-excursion
+      (forward-char -1)
+      (insert "\\")))
+
+  (goto-char (point-max))
+  (insert ")"))				;insert end-string delimiter
+
+(defun ps-init-output-queue ()
+  (setq ps-output-head (list ""))
+  (setq ps-output-tail ps-output-head))
+
+(defun ps-output (&rest args)
+  (setcdr ps-output-tail args)
+  (while (cdr ps-output-tail)
+    (setq ps-output-tail (cdr ps-output-tail))))
+
+(defun ps-output-string (string)
+  (ps-output t string))
+
+(defun ps-flush-output ()
+  (save-excursion
+    (set-buffer ps-spool-buffer)
+    (goto-char (point-max))
+    (while ps-output-head
+      (let ((it (car ps-output-head)))
+	(if (not (eq t it))
+	    (insert it)
+	  (setq ps-output-head (cdr ps-output-head))
+	  (ps-output-string-prim (car ps-output-head))))
+      (setq ps-output-head (cdr ps-output-head))))
+  (ps-init-output-queue))
+
+(defun ps-insert-file (fname)
+  (ps-flush-output)
+
+  ;; Check to see that the file exists and is readable; if not, throw
+  ;; and error.
+  (if (not (file-readable-p fname))
+      (error "Could not read file `%s'" fname))
+
+  (save-excursion
+    (set-buffer ps-spool-buffer)
+    (goto-char (point-max))
+    (insert-file fname)))
+    
+;; These functions insert the arrays that define the contents of the
+;; headers.
+
+(defun ps-generate-header-line (fonttag &optional content)
+  (ps-output "  [ " fonttag " ")
+  (cond
+   ;; Literal strings should be output as is -- the string must
+   ;; contain its own PS string delimiters, '(' and ')', if necessary.
+   ((stringp content)
+    (ps-output content))
+
+   ;; Functions are called -- they should return strings; they will be
+   ;; inserted as strings and the PS string delimiters added.
+   ((and (symbolp content) (fboundp content))
+    (ps-output-string (funcall content)))
+
+   ;; Variables will have their contents inserted.  They should
+   ;; contain strings, and will be inserted as strings.
+   ((and (symbolp content) (boundp content))
+    (ps-output-string (symbol-value content)))
+
+   ;; Anything else will get turned into an empty string.
+   (t
+    (ps-output-string "")))
+  (ps-output " ]\n"))
+
+(defun ps-generate-header (name contents)
+  (ps-output "/" name " [\n")
+  (if (> ps-header-lines 0)
+      (let ((count 1))
+	(ps-generate-header-line "/h0" (car contents))
+	(while (and (< count ps-header-lines)
+		    (setq contents (cdr contents)))
+	  (ps-generate-header-line "/h1" (car contents))
+	  (setq count (+ count 1)))
+	(ps-output "] def\n"))))
+
+(defun ps-output-boolean (name bool)
+  (ps-output (format "/%s %s def\n" name (if bool "true" "false"))))
+
+(defun ps-begin-file ()
+  (setq ps-showpage-count 0)
+
+  (ps-output ps-adobe-tag)
+  (ps-output "%%Title: " (buffer-name) "\n") ;Take job name from name of
+					;first buffer printed
+  (ps-output "%%Creator: " (user-full-name) "\n")
+  (ps-output "%%CreationDate: " 
+	     (time-stamp-hh:mm:ss) " " (time-stamp-mon-dd-yyyy) "\n")
+  (ps-output "%% DocumentFonts: Helvetica Helvetica-Bold "
+	     ps-font " " ps-font-bold " " ps-font-italic " "
+	     ps-font-bold-italic "\n")
+  (ps-output "%%Pages: (atend)\n")
+  (ps-output "%%EndComments\n\n")
+
+  (ps-output-boolean "Duplex" ps-spool-duplex)
+  (ps-output-boolean "PrintHeader" ps-print-header)
+  (ps-output-boolean "PrintHeaderFrame" ps-print-header-frame)
+  (ps-output-boolean "ShowNofN" ps-show-n-of-n)
+
+  (ps-output (format "/LeftMargin %d def\n" ps-left-margin))
+  (ps-output (format "/RightMargin %d def\n" ps-right-margin))
+  (ps-output (format "/BottomMargin %d def\n" ps-bottom-margin))
+  (ps-output (format "/TopMargin %d def\n" ps-top-margin))
+
+  (ps-get-page-dimensions)
+  (ps-output (format "/PrintWidth %d def\n" ps-print-width))
+  (ps-output (format "/PrintHeight %d def\n" ps-print-height))
+  
+  (ps-output (format "/LineHeight %s def\n" ps-line-height))
+  
+  (ps-output ps-print-prologue)
+
+  (ps-output (format "/f0 %d /%s Font\n" ps-font-size ps-font))
+  (ps-output (format "/f1 %d /%s Font\n" ps-font-size ps-font-bold))
+  (ps-output (format "/f2 %d /%s Font\n" ps-font-size ps-font-italic))
+  (ps-output (format "/f3 %d /%s Font\n" ps-font-size
+		     ps-font-bold-italic))
+
+  (ps-output "%%EndPrologue\n"))
+
+(defun ps-header-dirpart ()
+  (let ((fname (buffer-file-name)))
+    (if fname
+	(if (string-equal (buffer-name) (file-name-nondirectory fname))
+	    (file-name-directory fname)
+	  fname)
+      "")))
+
+(defun ps-get-buffer-name ()
+  ;; Indulge me this little easter egg:
+  (if (string= (buffer-name) "ps-print.el")
+      "Hey, Cool!  It's ps-print.el!!!"
+    (buffer-name)))
+
+(defun ps-begin-job ()
+  (setq ps-page-count 0))
+
+(defun ps-end-file ()
+  (ps-output "%%Trailer\n")
+  (ps-output "%%Pages: " (format "%d\n" ps-showpage-count)))
+
+(defun ps-next-page ()
+  (ps-end-page)
+  (ps-flush-output)
+  (ps-begin-page))
+
+(defun ps-begin-page (&optional dummypage)
+  (ps-get-page-dimensions)
+  (setq ps-width-remaining ps-print-width)
+  (setq ps-height-remaining ps-print-height)
+
+  ;; If headers are turned on, deduct the height of the header from
+  ;; the print height remaining.  Clumsy clumsy clumsy.
+  (if ps-print-header
+      (setq ps-height-remaining
+	    (- ps-height-remaining
+	       ps-header-title-line-height
+	       (* ps-header-line-height (- ps-header-lines 1))
+	       (* 2 ps-header-pad))))
+
+  (setq ps-page-count (+ ps-page-count 1))
+
+  (ps-output "\n%%Page: " 
+	     (format "%d %d\n" ps-page-count (+ 1 ps-showpage-count)))
+  (ps-output "BeginDSCPage\n")
+  (ps-output (format "/PageNumber %d def\n" ps-page-count))
+  (ps-output "/PageCount 0 def\n")
+
+  (if ps-print-header
+      (progn
+	(ps-generate-header "HeaderLinesLeft" ps-left-header)
+	(ps-generate-header "HeaderLinesRight" ps-right-header)
+	(ps-output (format "%d SetHeaderLines\n" ps-header-lines))))
+
+  (ps-output "BeginPage\n")
+  (ps-set-font ps-current-font)
+  (ps-set-bg ps-current-bg)
+  (ps-set-color ps-current-color)
+  (ps-set-underline ps-current-underline-p))
+
+(defun ps-end-page ()
+  (setq ps-showpage-count (+ 1 ps-showpage-count))
+  (ps-output "EndPage\n")
+  (ps-output "EndDSCPage\n"))
+
+(defun ps-dummy-page ()
+  (setq ps-showpage-count (+ 1 ps-showpage-count))
+  (ps-output "%%Page: " (format "- %d\n" ps-showpage-count)
+	     "BeginDSCPage
+/PrintHeader false def
+BeginPage
+EndPage
+EndDSCPage\n"))
+	    
+(defun ps-next-line ()
+  (if (< ps-height-remaining ps-line-height)
+      (ps-next-page)
+    (setq ps-width-remaining ps-print-width)
+    (setq ps-height-remaining (- ps-height-remaining ps-line-height))
+    (ps-hard-lf)))
+
+(defun ps-continue-line ()
+  (if (< ps-height-remaining ps-line-height)
+      (ps-next-page)
+    (setq ps-width-remaining ps-print-width)
+    (setq ps-height-remaining (- ps-height-remaining ps-line-height))
+    (ps-soft-lf)))
+
+(defun ps-hard-lf ()
+  (ps-output "HL\n"))
+
+(defun ps-soft-lf ()
+  (ps-output "SL\n"))
+
+(defun ps-find-wrappoint (from to char-width)
+  (let ((avail (truncate (/ ps-width-remaining char-width)))
+	(todo (- to from)))
+    (if (< todo avail)
+	(cons to (* todo char-width))
+      (cons (+ from avail) ps-width-remaining))))
+
+(defun ps-basic-plot-string (from to &optional bg-color)
+  (let* ((wrappoint (ps-find-wrappoint from to ps-avg-char-width))
+	 (to (car wrappoint))
+	 (string (buffer-substring from to)))
+    (ps-output-string string)
+    (ps-output " S\n")			;
+    wrappoint))
+
+(defun ps-basic-plot-whitespace (from to &optional bg-color)
+  (let* ((wrappoint (ps-find-wrappoint from to ps-space-width))
+	 (to (car wrappoint)))
+
+    (ps-output (format "%d W\n" (- to from)))
+    wrappoint))
+
+(defun ps-plot (plotfunc from to &optional bg-color)
+  (while (< from to)
+    (let* ((wrappoint (funcall plotfunc from to bg-color))
+	   (plotted-to (car wrappoint))
+	   (plotted-width (cdr wrappoint)))
+      (setq from plotted-to)
+      (setq ps-width-remaining (- ps-width-remaining plotted-width))
+      (if (< from to)
+	  (ps-continue-line))))
+  (if ps-razzle-dazzle
+      (let* ((q-todo (- (point-max) (point-min)))
+	     (q-done (- (point) (point-min)))
+	     (chunkfrac (/ q-todo 8))
+	     (chunksize (if (> chunkfrac 1000) 1000 chunkfrac)))
+	(if (> (- q-done ps-razchunk) chunksize)
+	    (let (foo)
+	      (setq ps-razchunk q-done)
+	      (setq foo
+		    (if (< q-todo 100)
+			(/ (* 100 q-done) q-todo)
+		      (/ q-done (/ q-todo 100))))
+	      (message "Formatting...%d%%" foo))))))
+
+(defun ps-set-font (font)
+  (setq ps-current-font font)
+  (ps-output (format "/f%d F\n" ps-current-font)))
+
+(defvar ps-print-color-scale nil)
+
+(defun ps-set-bg (color)
+  (if (setq ps-current-bg color)
+      (ps-output (format ps-color-format (nth 0 color) (nth 1 color)
+			 (nth 2 color))
+		 " true BG\n")
+    (ps-output "false BG\n")))
+
+(defun ps-set-color (color)
+  (if (setq ps-current-color color)
+      nil
+    (setq ps-current-color ps-default-fg))
+  (ps-output (format ps-color-format (nth 0 ps-current-color)
+		     (nth 1 ps-current-color) (nth 2 ps-current-color))
+	     " FG\n"))
+
+(defun ps-set-underline (underline-p)
+  (ps-output (if underline-p "true" "false") " UL\n")
+  (setq ps-current-underline-p underline-p))
+
+(defun ps-plot-region (from to font fg-color &optional bg-color underline-p)
+
+  (if (not (equal font ps-current-font))
+      (ps-set-font font))
+  
+  ;; Specify a foreground color only if one's specified and it's
+  ;; different than the current.
+  (if (not (equal fg-color ps-current-color))
+      (ps-set-color fg-color))
+  
+  (if (not (equal bg-color ps-current-bg))
+      (ps-set-bg bg-color))
+  
+  ;; Toggle underlining if different.
+  (if (not (equal underline-p ps-current-underline-p))
+      (ps-set-underline underline-p))
+
+  ;; Starting at the beginning of the specified region...
+  (save-excursion
+    (goto-char from)
+
+    ;; ...break the region up into chunks separated by tabs, linefeeds,
+    ;; and pagefeeds, and plot each chunk.
+    (while (< from to)
+      (if (re-search-forward "[\t\n\f]" to t)
+          (let ((match (char-after (match-beginning 0))))
+            (cond
+	     ((= match ?\t)
+	      (let ((linestart
+		     (save-excursion (beginning-of-line) (point))))
+		(ps-plot 'ps-basic-plot-string from (- (point) 1)
+			 bg-color)
+		(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))
+			     bg-color))))
+
+	     ((= match ?\n)
+	      (ps-plot 'ps-basic-plot-string from (- (point) 1)
+		       bg-color)
+	      (ps-next-line)
+	      )
+
+	     ((= match ?\f)
+	      (ps-plot 'ps-basic-plot-string from (- (point) 1)
+		       bg-color)
+	      (ps-next-page)))
+            (setq from (point)))
+        (ps-plot 'ps-basic-plot-string from to bg-color)
+        (setq from to)))))
+
+(defun ps-color-value (x-color-value)
+  ;; Scale 16-bit X-COLOR-VALUE to PostScript color value in [0, 1] interval.
+  (/ x-color-value ps-print-color-scale))
+
+(defun ps-color-values (x-color)
+  (cond ((fboundp 'x-color-values)
+	 (x-color-values x-color))
+	((and (fboundp 'color-instance-rgb-components)
+	      (xemacs-color-device))
+	 (color-instance-rgb-components
+	  (if (color-instance-p x-color) x-color
+	    (if (color-specifier-p x-color)
+		(make-color-instance (color-name x-color))
+	      (make-color-instance x-color)))))
+	(t (error "No available function to determine X color values."))))
+
+(defun ps-face-attributes (face)
+  (let ((differs (face-differs-from-default-p face)))
+    (list (memq face ps-ref-bold-faces)
+	  (memq face ps-ref-italic-faces)
+	  (memq face ps-ref-underlined-faces)
+	  (and differs (face-foreground face))
+	  (and differs (face-background face)))))
+
+(defun ps-face-attribute-list (face-or-list)
+  (if (listp face-or-list)
+      (let (bold-p italic-p underline-p foreground background face-attr face)
+	(while face-or-list
+	  (setq face (car face-or-list))
+	  (setq face-attr (ps-face-attributes face))
+	  (setq bold-p (or bold-p (nth 0 face-attr)))
+	  (setq italic-p (or italic-p (nth 1 face-attr)))
+	  (setq underline-p (or underline-p (nth 2 face-attr)))
+	  (if foreground
+	      nil
+	    (setq foreground (nth 3 face-attr)))
+	  (if background
+	      nil
+	    (setq background (nth 4 face-attr)))
+	  (setq face-or-list (cdr face-or-list)))
+	(list bold-p italic-p underline-p foreground background))
+
+    (ps-face-attributes face-or-list)))
+
+(defun ps-plot-with-face (from to face)
+  (if face
+      (let* ((face-attr (ps-face-attribute-list face))
+	     (bold-p (nth 0 face-attr))
+	     (italic-p (nth 1 face-attr))
+	     (underline-p (nth 2 face-attr))
+	     (foreground (nth 3 face-attr))
+	     (background (nth 4 face-attr))
+	     (fg-color (if (and ps-print-color-p
+				(xemacs-color-device) 
+				foreground)
+			   (mapcar 'ps-color-value
+				   (ps-color-values foreground))
+			 ps-default-color))
+	     (bg-color (if (and ps-print-color-p
+				(xemacs-color-device)
+				background)
+			   (mapcar 'ps-color-value
+				   (ps-color-values background)))))
+	(ps-plot-region from to
+			(cond ((and bold-p italic-p) 3)
+			      (italic-p 2)
+			      (bold-p 1)
+			      (t 0))
+;			(or fg-color '(0.0 0.0 0.0))
+			fg-color
+			bg-color underline-p))
+    (goto-char to)))
+
+
+(defun ps-emacs-face-kind-p (face kind kind-regex kind-list)
+  (let ((frame-font (face-font face))
+	(face-defaults (face-font face t)))
+    (or
+     ;; Check FACE defaults:
+     (and (listp face-defaults)
+	  (memq kind face-defaults))
+
+     ;; Check the user's preferences
+     (memq face kind-list))))
+
+(defun ps-xemacs-face-kind-p (face kind kind-regex kind-list)
+  (let* ((frame-font
+	  (or (face-font-instance face) (face-font-instance 'default)))
+	 (kind-cons (and frame-font
+			 (assq kind (font-instance-properties frame-font))))
+	 (kind-spec (cdr-safe kind-cons))
+	 (case-fold-search t))
+
+    (or (and kind-spec (string-match kind-regex kind-spec))
+	;; Kludge-compatible:
+	(memq face kind-list))))
+
+(defun ps-face-bold-p (face)
+  (if (eq ps-print-emacs-type 'emacs)
+      (ps-emacs-face-kind-p face 'bold "-\\(bold\\|demibold\\)-"
+			  ps-bold-faces)
+    (ps-xemacs-face-kind-p face 'WEIGHT_NAME "bold\\|demibold"
+			   ps-bold-faces)))
+
+(defun ps-face-italic-p (face)
+  (if (eq ps-print-emacs-type 'emacs)
+      (ps-emacs-face-kind-p face 'italic "-[io]-" ps-italic-faces)
+    (or
+     (ps-xemacs-face-kind-p face 'ANGLE_NAME "i\\|o" ps-italic-faces)
+     (ps-xemacs-face-kind-p face 'SLANT "i\\|o" ps-italic-faces))))
+
+(defun ps-face-underlined-p (face)
+  (or (face-underline-p face)
+      (memq face ps-underlined-faces)))
+
+;; Ensure that face-list is fbound.
+(or (fboundp 'face-list) (defalias 'face-list 'list-faces))
+
+(defun ps-build-reference-face-lists ()
+  (if ps-auto-font-detect
+      (let ((faces (face-list))
+	    the-face)
+	(setq ps-ref-bold-faces nil
+	      ps-ref-italic-faces nil
+	      ps-ref-underlined-faces nil)
+	(while faces
+	  (setq the-face (car faces))
+	  (if (ps-face-italic-p the-face)
+	      (setq ps-ref-italic-faces
+		    (cons the-face ps-ref-italic-faces)))
+	  (if (ps-face-bold-p the-face)
+	      (setq ps-ref-bold-faces
+		    (cons the-face ps-ref-bold-faces)))
+	  (if (ps-face-underlined-p the-face)
+	      (setq ps-ref-underlined-faces
+		    (cons the-face ps-ref-underlined-faces)))
+	  (setq faces (cdr faces))))
+    (setq ps-ref-bold-faces ps-bold-faces)
+    (setq ps-ref-italic-faces ps-italic-faces)
+    (setq ps-ref-underlined-faces ps-underlined-faces))
+  (setq ps-build-face-reference nil))
+
+(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 ps-print-ensure-fontified (start end)
+  (if (and (boundp 'lazy-lock-mode) lazy-lock-mode)
+      (if (fboundp 'lazy-lock-fontify-region)
+          (lazy-lock-fontify-region start end)
+        (lazy-lock-fontify-buffer))))
+
+(defun ps-generate-postscript-with-faces (from to)
+  ;; Build the reference lists of faces if necessary.
+  (if (or ps-always-build-face-reference
+	  ps-build-face-reference)
+      (progn
+	(message "Collecting face information...")
+	(ps-build-reference-face-lists)))
+  ;; Set the color scale.  We do it here instead of in the defvar so
+  ;; that ps-print can be dumped into emacs.  This expression can't be
+  ;; evaluated at dump-time because X isn't initialized.
+  (setq ps-print-color-scale
+	(if (and ps-print-color-p (xemacs-color-device))
+	    (float (car (ps-color-values "white")))
+	  1.0))
+  ;; Generate some PostScript.
+  (save-restriction
+    (narrow-to-region from to)
+    (let ((face 'default)
+	  (position to))
+      (ps-print-ensure-fontified from to)
+      (cond ((or (eq ps-print-emacs-type 'lucid) (eq ps-print-emacs-type 'xemacs))
+	   ;; Build the list of extents...
+	   (let ((a (cons 'dummy nil))
+		 record type extent extent-list)
+	     (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.
+	       ;; XEmacs 19.12: for some reason, we're getting into a
+	       ;; situation in which some of the records have
+	       ;; positions less than 'from'.  Since we've narrowed
+	       ;; the buffer, this'll generate errors.  This is a
+	       ;; hack, but don't call ps-plot-with-face unless from >
+	       ;; point-min.
+	       (if (and (>= from (point-min))
+			(<= position (point-max)))
+		   (ps-plot-with-face from position face))
+	     
+	       (cond
+		((eq type 'push)
+		 (if (extent-face extent)
+		     (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)))))
+
+	    ((eq ps-print-emacs-type 'emacs)
+	     (let ((property-change from)
+		   (overlay-change from))
+	       (while (< from to)
+		 (if (< property-change to) ; Don't search for property change
+					; unless previous search succeeded.
+		     (setq property-change
+			   (next-property-change from nil to)))
+		 (if (< overlay-change to) ; Don't search for overlay change
+					; unless previous search succeeded.
+		     (setq overlay-change
+			   (min (next-overlay-change from) to)))
+		 (setq position
+		       (min property-change overlay-change))
+		 (setq face
+		       (cond ((get-text-property from 'invisible) nil)
+			     ((get-text-property from 'face))
+			     (t 'default)))
+		 (let ((overlays (overlays-at from))
+		       (face-priority -1)) ; text-property
+		   (while overlays
+		     (let* ((overlay (car overlays))
+			    (overlay-face (overlay-get overlay 'face))
+			    (overlay-invisible (overlay-get overlay 'invisible))
+			    (overlay-priority (or (overlay-get overlay
+							       'priority)
+						  0)))
+		       (if (and (or overlay-invisible overlay-face)
+				(> overlay-priority face-priority))
+			   (setq face (cond (overlay-invisible nil)
+					    ((and face overlay-face)))
+				 face-priority overlay-priority)))
+		     (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 nil))
+
+(defun ps-generate (buffer from to genfunc)
+  (let ((from (min to from))
+	(to (max to from)))
+    (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-spool-buffer (get-buffer-create ps-spool-buffer-name))
+      (ps-init-output-queue)
+      (let (safe-marker completed-safely needs-begin-file)
+	(unwind-protect
+	    (progn
+	      (set-buffer ps-spool-buffer)
+	    
+	      ;; Get a marker and make it point to the current end of the
+	      ;; buffer,  If an error occurs, we'll delete everything from
+	      ;; the end of this marker onwards.
+	      (setq safe-marker (make-marker))
+	      (set-marker safe-marker (point-max))
+	    
+	      (goto-char (point-min))
+	      (if (looking-at (regexp-quote "%!PS-Adobe-1.0"))
+		  nil
+		(setq needs-begin-file t))
+	      (save-excursion
+		(set-buffer ps-source-buffer)
+		(if needs-begin-file (ps-begin-file))
+		(ps-begin-job)
+		(ps-begin-page))
+	      (set-buffer ps-source-buffer)
+	      (funcall genfunc from to)
+	      (ps-end-page)
+	    
+	      (if (and ps-spool-duplex
+		       (= (mod ps-page-count 2) 1))
+		  (ps-dummy-page))
+	      (ps-flush-output)
+	    
+	      ;; Back to the PS output buffer to set the page count
+	      (set-buffer ps-spool-buffer)
+	      (goto-char (point-max))
+	      (while (re-search-backward "^/PageCount 0 def$" nil t)
+		(replace-match (format "/PageCount %d def" ps-page-count) t))
+
+	      ;; Setting this variable tells the unwind form that the
+	      ;; the postscript was generated without error.
+	      (setq completed-safely t))
+
+	  ;; Unwind form: If some bad mojo ocurred while generating
+	  ;; postscript, delete all the postscript that was generated.
+	  ;; This protects the previously spooled files from getting
+	  ;; corrupted.
+	  (if (and (markerp safe-marker) (not completed-safely))
+	      (progn
+		(set-buffer ps-spool-buffer)
+		(delete-region (marker-position safe-marker) (point-max))))))
+
+      (if ps-razzle-dazzle
+	  (message "Formatting...done")))))
+
+(defun ps-do-despool (filename)
+  (if (or (not (boundp 'ps-spool-buffer))
+	  (not ps-spool-buffer))
+      (message "No spooled PostScript to print")
+    (ps-end-file)
+    (ps-flush-output)
+    (if filename
+	(save-excursion
+	  (if ps-razzle-dazzle
+	      (message "Saving..."))
+	  (set-buffer ps-spool-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-spool-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-spool-buffer)))
+
+(defun ps-kill-emacs-check ()
+  (let (ps-buffer)
+    (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)))
+
+;;; Sample Setup Code:
+
+;; This stuff is for anybody that's brave enough to look this far,
+;; and able to figure out how to use it.  It isn't really part of ps-
+;; print, but I'll leave it here in hopes it might be useful:
+
+;; WARNING!!! The following code is *sample* code only. Don't use it
+;; unless you understand what it does!
+
+(defmacro ps-prsc () (list 'if (list 'eq 'ps-print-emacs-type ''emacs)
+			   [f22] ''f22))
+(defmacro ps-c-prsc () (list 'if (list 'eq 'ps-print-emacs-type ''emacs)
+			     [C-f22]
+			     ''(control f22)))
+(defmacro ps-s-prsc () (list 'if (list 'eq 'ps-print-emacs-type ''emacs)
+			     [S-f22]
+			     ''(shift f22)))
+
+;; Look in an article or mail message for the Subject: line.  To be
+;; placed in ps-left-headers.
+(defun ps-article-subject ()
+  (save-excursion
+    (goto-char (point-min))
+    (if (re-search-forward "^Subject:[ \t]+\\(.*\\)$")
+	(buffer-substring (match-beginning 1) (match-end 1))
+      "Subject ???")))
+
+;; Look in an article or mail message for the From: line.  Sorta-kinda
+;; understands RFC-822 addresses and can pull the real name out where
+;; it's provided.  To be placed in ps-left-headers.
+(defun ps-article-author ()
+  (save-excursion
+    (goto-char (point-min))
+    (if (re-search-forward "^From:[ \t]+\\(.*\\)$")
+	(let ((fromstring (buffer-substring (match-beginning 1) (match-end 1))))
+	  (cond
+
+	   ;; Try first to match addresses that look like
+	   ;; thompson@wg2.waii.com (Jim Thompson)
+	   ((string-match ".*[ \t]+(\\(.*\\))" fromstring)
+	    (substring fromstring (match-beginning 1) (match-end 1)))
+
+	   ;; Next try to match addresses that look like
+	   ;; Jim Thompson <thompson@wg2.waii.com>
+	   ((string-match "\\(.*\\)[ \t]+<.*>" fromstring)
+	    (substring fromstring (match-beginning 1) (match-end 1)))
+
+	   ;; Couldn't find a real name -- show the address instead.
+	   (t fromstring)))
+      "From ???")))
+
+;; A hook to bind to gnus-Article-prepare-hook.  This will set the ps-
+;; left-headers specially for gnus articles.  Unfortunately, gnus-
+;; article-mode-hook is called only once, the first time the *Article*
+;; buffer enters that mode, so it would only work for the first time
+;; we ran gnus.  The second time, this hook wouldn't get set up.  The
+;; only alternative is gnus-article-prepare-hook.
+(defun ps-gnus-article-prepare-hook ()
+  (setq ps-header-lines 3)
+  (setq ps-left-header
+	;; The left headers will display the article's subject, its
+	;; author, and the newsgroup it was in.
+	(list 'ps-article-subject 'ps-article-author 'gnus-newsgroup-name)))
+
+;; A hook to bind to vm-mode-hook to locally bind prsc and set the ps-
+;; left-headers specially for mail messages.  This header setup would
+;; also work, I think, for RMAIL.
+(defun ps-vm-mode-hook ()
+  (local-set-key (ps-prsc) 'ps-vm-print-message-from-summary)
+  (setq ps-header-lines 3)
+  (setq ps-left-header
+	;; The left headers will display the message's subject, its
+	;; author, and the name of the folder it was in.
+	(list 'ps-article-subject 'ps-article-author 'buffer-name)))
+
+;; Every now and then I forget to switch from the *Summary* buffer to
+;; the *Article* before hitting prsc, and a nicely formatted list of
+;; article subjects shows up at the printer.  This function, bound to
+;; prsc for the gnus *Summary* buffer means I don't have to switch
+;; buffers first.
+(defun ps-gnus-print-article-from-summary ()
+  (interactive)
+  (if (get-buffer "*Article*")
+      (save-excursion
+	(set-buffer "*Article*")
+	(ps-spool-buffer-with-faces))))
+
+;; See ps-gnus-print-article-from-summary.  This function does the
+;; same thing for vm.
+(defun ps-vm-print-message-from-summary ()
+  (interactive)
+  (if vm-mail-buffer
+      (save-excursion
+	(set-buffer vm-mail-buffer)
+	(ps-spool-buffer-with-faces))))
+
+;; A hook to bind to bind to gnus-summary-setup-buffer to locally bind
+;; prsc.
+(defun ps-gnus-summary-setup ()
+  (local-set-key (ps-prsc) 'ps-gnus-print-article-from-summary))
+
+;; Look in an article or mail message for the Subject: line.  To be
+;; placed in ps-left-headers.
+(defun ps-info-file ()
+  (save-excursion
+    (goto-char (point-min))
+    (if (re-search-forward "File:[ \t]+\\([^, \t\n]*\\)")
+	(buffer-substring (match-beginning 1) (match-end 1))
+      "File ???")))
+
+;; Look in an article or mail message for the Subject: line.  To be
+;; placed in ps-left-headers.
+(defun ps-info-node ()
+  (save-excursion
+    (goto-char (point-min))
+    (if (re-search-forward "Node:[ \t]+\\([^,\t\n]*\\)")
+	(buffer-substring (match-beginning 1) (match-end 1))
+      "Node ???")))
+
+(defun ps-info-mode-hook ()
+  (setq ps-left-header
+	;; The left headers will display the node name and file name.
+	(list 'ps-info-node 'ps-info-file)))
+
+;; WARNING! The following function is a *sample* only, and is *not*
+;; meant to be used as a whole unless you understand what the effects
+;; will be!  (In fact, this is a copy if my setup for ps-print -- I'd
+;; be very surprised if it was useful to *anybody*, without
+;; modification.)
+
+(defun ps-jts-ps-setup ()
+  (global-set-key (ps-prsc) 'ps-spool-buffer-with-faces) ;f22 is prsc
+  (global-set-key (ps-s-prsc) 'ps-spool-region-with-faces)
+  (global-set-key (ps-c-prsc) 'ps-despool)
+  (add-hook 'gnus-article-prepare-hook 'ps-gnus-article-prepare-hook)
+  (add-hook 'gnus-summary-mode-hook 'ps-gnus-summary-setup)
+  (add-hook 'vm-mode-hook 'ps-vm-mode-hook)
+  (add-hook 'vm-mode-hooks 'ps-vm-mode-hook)
+  (add-hook 'Info-mode-hook 'ps-info-mode-hook)
+  (setq ps-spool-duplex t)
+  (setq ps-print-color-p nil)
+  (setq ps-lpr-command "lpr")
+  (setq ps-lpr-switches '("-Jjct,duplex_long")))
+
+(provide 'ps-print)
+
+;;; ps-print.el ends here