home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.006 / xemacs-1 / lib / xemacs-19.13 / lisp / packages / ps-print.el < prev    next >
Encoding:
Text File  |  1995-08-18  |  67.1 KB  |  2,079 lines

  1. ;;; ps-print.el --- Jim's Pretty-Good PostScript Generator for Emacs 19.
  2.  
  3. ;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
  4.  
  5. ;; Author: Jim Thompson <thompson@wg2.waii.com>
  6. ;; Keywords: print, PostScript
  7.  
  8. ;; This file is part of XEmacs.
  9.  
  10. ;; XEmacs is free software; you can redistribute it and/or modify it
  11. ;; under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation; either version 2, or (at your option)
  13. ;; any later version.
  14.  
  15. ;; XEmacs is distributed in the hope that it will be useful, but
  16. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18. ;; General Public License for more details.
  19.  
  20. ;; You should have received a copy of the GNU General Public License
  21. ;; along with XEmacs; see the file COPYING.  If not, write to the Free
  22. ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24. ;; LCD Archive Entry:
  25. ;; ps-print|James C. Thompson|thompson@wg2.waii.com|
  26. ;; Jim's Pretty-Good PostScript Generator for Emacs 19 (ps-print)|
  27. ;; 26-Feb-1994|2.8|~/packages/ps-print.el|
  28.  
  29. ;; Baseline-version: 2.8.  (Jim's last change version -- this
  30. ;; file may have been edited as part of Emacs without changes to the
  31. ;; version number.  When reporting bugs, please also report the
  32. ;; version of Emacs, if any, that ps-print was distributed with.)
  33.  
  34. ;;; Commentary:
  35.  
  36. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  37. ;;
  38. ;; About ps-print
  39. ;; --------------
  40. ;; This package provides printing of Emacs buffers on PostScript
  41. ;; printers; the buffer's bold and italic text attributes are
  42. ;; preserved in the printer output.  Ps-print is intended for use with
  43. ;; Emacs 19 or Lucid Emacs, together with a fontifying package such as
  44. ;; font-lock or hilit.
  45. ;;
  46. ;; Using ps-print
  47. ;; --------------
  48. ;;
  49. ;; The Commands
  50. ;;
  51. ;; Ps-print provides eight commands for generating PostScript images
  52. ;; of Emacs buffers:
  53. ;;
  54. ;;        ps-print-buffer
  55. ;;        ps-print-buffer-with-faces
  56. ;;        ps-print-region
  57. ;;        ps-print-region-with-faces
  58. ;;        ps-spool-buffer
  59. ;;        ps-spool-buffer-with-faces
  60. ;;        ps-spool-region
  61. ;;        ps-spool-region-with-faces
  62. ;;
  63. ;; These commands all perform essentially the same function: they
  64. ;; generate PostScript images suitable for printing on a PostScript
  65. ;; printer or displaying with GhostScript.  These commands are
  66. ;; collectively referred to as "ps-print- commands".
  67. ;;
  68. ;; The word "print" or "spool" in the command name determines when the
  69. ;; PostScript image is sent to the printer:
  70. ;;
  71. ;;        print      - The PostScript image is immediately sent to the
  72. ;;                     printer;
  73. ;;
  74. ;;        spool      - The PostScript image is saved temporarily in an
  75. ;;                     Emacs buffer.  Many images may be spooled locally
  76. ;;                     before printing them.  To send the spooled images
  77. ;;                     to the printer, use the command ps-despool.
  78. ;;
  79. ;; The spooling mechanism was designed for printing lots of small
  80. ;; files (mail messages or netnews articles) to save paper that would
  81. ;; otherwise be wasted on banner pages, and to make it easier to find
  82. ;; your output at the printer (it's easier to pick up one 50-page
  83. ;; printout than to find 50 single-page printouts).
  84. ;; 
  85. ;; Ps-print has a hook in the kill-emacs-hooks so that you won't
  86. ;; accidently quit from Emacs while you have unprinted PostScript
  87. ;; waiting in the spool buffer.  If you do attempt to exit with
  88. ;; spooled PostScript, you'll be asked if you want to print it, and if
  89. ;; you decline, you'll be asked to confirm the exit; this is modeled
  90. ;; on the confirmation that Emacs uses for modified buffers.
  91. ;;
  92. ;; The word "buffer" or "region" in the command name determines how
  93. ;; much of the buffer is printed:
  94. ;;
  95. ;;        buffer     - Print the entire buffer.
  96. ;;
  97. ;;        region     - Print just the current region.
  98. ;;
  99. ;; The -with-faces suffix on the command name means that the command
  100. ;; will include font, color, and underline information in the
  101. ;; PostScript image, so the printed image can look as pretty as the
  102. ;; buffer.  The ps-print- commands without the -with-faces suffix
  103. ;; don't include font, color, or underline information; images printed
  104. ;; with these commands aren't as pretty, but are faster to generate.
  105. ;;
  106. ;; Two ps-print- command examples:
  107. ;;
  108. ;;        ps-print-buffer             - print the entire buffer,
  109. ;;                                      without font, color, or
  110. ;;                                      underline information, and
  111. ;;                                      send it immediately to the
  112. ;;                                      printer.
  113. ;;
  114. ;;        ps-spool-region-with-faces  - print just the current region;
  115. ;;                                      include font, color, and
  116. ;;                                      underline information, and
  117. ;;                                      spool the image in Emacs to
  118. ;;                                      send to the printer later.
  119. ;;
  120. ;;
  121. ;; Invoking Ps-Print
  122. ;;
  123. ;; To print your buffer, type
  124. ;;
  125. ;;        M-x ps-print-buffer
  126. ;;
  127. ;; or substitute one of the other seven ps-print- commands.  The
  128. ;; command will generate the PostScript image and print or spool it as
  129. ;; specified.  By giving the command a prefix argument
  130. ;;
  131. ;;        C-u M-x ps-print-buffer
  132. ;;
  133. ;; it will save the PostScript image to a file instead of sending it
  134. ;; to the printer; you will be prompted for the name of the file to
  135. ;; save the image to.  The prefix argument is ignored by the commands
  136. ;; that spool their images, but you may save the spooled images to a
  137. ;; file by giving a prefix argument to ps-despool:
  138. ;;
  139. ;;        C-u M-x ps-despool
  140. ;;
  141. ;; When invoked this way, ps-despool will prompt you for the name of
  142. ;; the file to save to.
  143. ;;
  144. ;; Any of the ps-print- commands can be bound to keys; I recommend
  145. ;; binding ps-spool-buffer-with-faces, ps-spool-region-with-faces, and
  146. ;; ps-despool.  Here are the bindings I use on my Sun 4 keyboard:
  147. ;;
  148. ;;   (global-set-key 'f22 'ps-spool-buffer-with-faces) ;f22 is prsc
  149. ;;   (global-set-key '(shift f22) 'ps-spool-region-with-faces)
  150. ;;   (global-set-key '(control f22) 'ps-despool)
  151. ;;
  152. ;;
  153. ;; The Printer Interface
  154. ;;
  155. ;; The variables ps-lpr-command and ps-lpr-switches determine what
  156. ;; command is used to send the PostScript images to the printer, and
  157. ;; what arguments to give the command.  These are analogous to lpr-
  158. ;; command and lpr-switches.
  159. ;;
  160. ;; NOTE: ps-lpr-command and ps-lpr-switches take their initial values
  161. ;;       from the variables lpr-command and lpr-switches.  If you have
  162. ;;       lpr-command set to invoke a pretty-printer such as enscript,
  163. ;;       then ps-print won't work properly.  ps-lpr-command must name
  164. ;;       a program that does not format the files it prints.
  165. ;;
  166. ;;
  167. ;; How Ps-Print Deals With Fonts
  168. ;;
  169. ;; The ps-print-*-with-faces commands attempt to determine which faces
  170. ;; should be printed in bold or italic, but their guesses aren't
  171. ;; always right.  For example, you might want to map colors into faces
  172. ;; so that blue faces print in bold, and red faces in italic.
  173. ;;
  174. ;; It is possible to force ps-print to consider specific faces bold or
  175. ;; italic, no matter what font they are displayed in, by setting the
  176. ;; variables ps-bold-faces and ps-italic-faces.  These variables
  177. ;; contain lists of faces that ps-print should consider bold or
  178. ;; italic; to set them, put code like the following into your .emacs
  179. ;; file:
  180. ;;
  181. ;;     (setq ps-bold-faces '(my-blue-face))
  182. ;;      (setq ps-italic-faces '(my-red-face))
  183. ;;
  184. ;; Faces like bold-italic that are both bold and italic should go in
  185. ;; *both* lists.
  186. ;;
  187. ;; Ps-print does not attempt to guess the sizes of fonts; all text is
  188. ;; rendered using the Courier font family, in 10 point size.  To
  189. ;; change the font family, change the variables ps-font, ps-font-bold,
  190. ;; ps-font-italic, and ps-font-bold-italic; fixed-pitch fonts work
  191. ;; best, but are not required.  To change the font size, change the
  192. ;; variable ps-font-size.
  193. ;;
  194. ;; If you change the font family or size, you MUST also change the
  195. ;; variables ps-line-height, ps-avg-char-width, and ps-space-width, or
  196. ;; ps-print cannot correctly place line and page breaks.
  197. ;;
  198. ;; Ps-print keeps internal lists of which fonts are bold and which are
  199. ;; italic; these lists are built the first time you invoke ps-print.
  200. ;; For the sake of efficiency, the lists are built only once; the same
  201. ;; lists are referred in later invokations of ps-print.
  202. ;;
  203. ;; Because these lists are built only once, it's possible for them to
  204. ;; get out of sync, if a face changes, or if new faces are added.  To
  205. ;; get the lists back in sync, you can set the variable
  206. ;; ps-build-face-reference to t, and the lists will be rebuilt the
  207. ;; next time ps-print is invoked.
  208. ;;
  209. ;;
  210. ;; How Ps-Print Deals With Color
  211. ;;
  212. ;; Ps-print detects faces with foreground and background colors
  213. ;; defined and embeds color information in the PostScript image.  The
  214. ;; default foreground and background colors are defined by the
  215. ;; variables ps-default-fg and ps-default-bg.  On black-and-white
  216. ;; printers, colors are displayed in grayscale.  To turn off color
  217. ;; output, set ps-print-color-p to nil.
  218. ;;
  219. ;;
  220. ;; Headers
  221. ;;
  222. ;; Ps-print can print headers at the top of each page; the default
  223. ;; headers contain the following four items: on the left, the name of
  224. ;; the buffer and, if the buffer is visiting a file, the file's
  225. ;; directory; on the right, the page number and date of printing.  The
  226. ;; default headers look something like this:
  227. ;;
  228. ;;     ps-print.el                                         1/21
  229. ;;     /home/jct/emacs-lisp/ps/new                     94/12/31
  230. ;; 
  231. ;; When printing on duplex printers, left and right are reversed so
  232. ;; that the page numbers are toward the outside.
  233. ;;
  234. ;; Headers are configurable.  To turn them off completely, set
  235. ;; ps-print-header to nil.  To turn off the header's gaudy framing
  236. ;; box, set ps-print-header-frame to nil.  Page numbers are printed in
  237. ;; "n/m" format, indicating page n of m pages; to omit the total page
  238. ;; count and just print the page number, set ps-show-n-of-n to nil.
  239. ;;
  240. ;; The amount of information in the header can be changed by changing
  241. ;; the number of lines.  To show less, set ps-header-lines to 1, and
  242. ;; the header will show only the buffer name and page number.  To show
  243. ;; more, set ps-header-lines to 3, and the header will show the time of
  244. ;; printing below the date.
  245. ;;
  246. ;; To change the content of the headers, change the variables
  247. ;; ps-left-header and ps-right-header.  These variables are lists,
  248. ;; specifying top-to-bottom the text to display on the left or right
  249. ;; side of the header.  Each element of the list should be a string or
  250. ;; a symbol.  Strings are inserted directly into the PostScript
  251. ;; arrays, and should contain the PostScript string delimiters '(' and
  252. ;; ')'.
  253. ;;
  254. ;; Symbols in the header format lists can either represent functions
  255. ;; or variables.  Functions are called, and should return a string to
  256. ;; show in the header.  Variables should contain strings to display in
  257. ;; the header.  In either case, function or variable, the PostScript
  258. ;; strings delimeters are added by ps-print, and should not be part of
  259. ;; the returned value.
  260. ;;
  261. ;; Here's an example: say we want the left header to display the text
  262. ;;
  263. ;;     Moe
  264. ;;     Larry
  265. ;;     Curly
  266. ;;
  267. ;; where we have a function to return "Moe"
  268. ;;
  269. ;;     (defun moe-func ()
  270. ;;       "Moe")
  271. ;;
  272. ;; a variable specifying "Larry"
  273. ;;
  274. ;;     (setq larry-var "Larry")
  275. ;;
  276. ;; and a literal for "Curly".  Here's how ps-left-header should be
  277. ;; set:
  278. ;;
  279. ;;     (setq ps-left-header (list 'moe-func 'larry-var "(Curly)"))
  280. ;;
  281. ;; Note that Curly has the PostScript string delimiters inside his
  282. ;; quotes -- those aren't misplaced lisp delimiters!  Without them,
  283. ;; PostScript would attempt to call the undefined function Curly,
  284. ;; which would result in a PostScript error.  Since most printers
  285. ;; don't report PostScript errors except by aborting the print job,
  286. ;; this kind of error can be hard to track down.  Consider yourself
  287. ;; warned.
  288. ;;
  289. ;;
  290. ;; Duplex Printers
  291. ;;
  292. ;; If you have a duplex-capable printer (one that prints both sides of
  293. ;; the paper), set ps-spool-duplex to t.  Ps-print will insert blank
  294. ;; pages to make sure each buffer starts on the correct side of the
  295. ;; paper.  Don't forget to set ps-lpr-switches to select duplex
  296. ;; printing for your printer.
  297. ;; 
  298. ;;
  299. ;; Paper Size
  300. ;;
  301. ;; The variable ps-paper-type determines the size of paper ps-print
  302. ;; formats for; it should contain one of the symbols ps-letter,
  303. ;; ps-legal, or ps-a4.  The default is ps-letter.
  304. ;;
  305. ;; 
  306. ;; Installing ps-print
  307. ;; -------------------
  308. ;;
  309. ;; 1. Place ps-print.el somewhere in your load-path and byte-compile
  310. ;;    it.  You can ignore all byte-compiler warnings; they are the
  311. ;;    result of multi-Emacs support.  This step is necessary only if
  312. ;;    you're installing your own ps-print; if ps-print came with your
  313. ;;    copy of Emacs, this been done already.
  314. ;;
  315. ;; 2. Place in your .emacs file the line
  316. ;;
  317. ;;        (require 'ps-print)
  318. ;;
  319. ;;    to load ps-print.  Or you may cause any of the ps-print commands
  320. ;;    to be autoloaded with an autoload command such as:
  321. ;;
  322. ;;      (autoload 'ps-print-buffer "ps-print"
  323. ;;        "Generate and print a PostScript image of the buffer..." t)
  324. ;;
  325. ;; 3. Make sure that the variables ps-lpr-command and ps-lpr-switches
  326. ;;    contain appropriate values for your system; see the usage notes
  327. ;;    below and the documentation of these variables.
  328. ;; 
  329. ;; New since version 1.5
  330. ;; ---------------------
  331. ;; Color output capability.
  332. ;;
  333. ;; Automatic detection of font attributes (bold, italic).
  334. ;;
  335. ;; Configurable headers with page numbers.
  336. ;;
  337. ;; Slightly faster.
  338. ;;
  339. ;; Support for different paper sizes.
  340. ;;
  341. ;; Better conformance to PostScript Document Structure Conventions.
  342. ;;
  343. ;;
  344. ;; Known bugs and limitations of ps-print:
  345. ;; --------------------------------------
  346. ;; Although color printing will work in XEmacs 19.12, it doesn't work
  347. ;; well; in particular, bold or italic fonts don't print in the right
  348. ;; background color.
  349. ;;
  350. ;; Invisible properties aren't correctly ignored in XEmacs 19.12.
  351. ;;
  352. ;; Automatic font-attribute detection doesn't work well, especially
  353. ;; with hilit19 and older versions of get-create-face.  Users having
  354. ;; problems with auto-font detection should use the lists ps-italic-
  355. ;; faces and ps-bold-faces and/or turn off automatic detection by
  356. ;; setting ps-auto-font-detect to nil.
  357. ;;
  358. ;; Automatic font-attribute detection doesn't work with XEmacs 19.12
  359. ;; in tty mode; use the lists ps-italic-faces and ps-bold-faces
  360. ;; instead.
  361. ;;
  362. ;; Still too slow; could use some hand-optimization.
  363. ;;
  364. ;; ASCII Control characters other than tab, linefeed and pagefeed are
  365. ;; not handled.
  366. ;;
  367. ;; Default background color isn't working.
  368. ;;
  369. ;; Faces are always treated as opaque.
  370. ;;
  371. ;; Epoch and Emacs 18 not supported.  At all.
  372. ;;
  373. ;;
  374. ;; Features to add:
  375. ;; ---------------
  376. ;; 2-up and 4-up capability.
  377. ;;
  378. ;; Line numbers.
  379. ;;
  380. ;; Wide-print (landscape) capability.
  381. ;;
  382. ;;
  383. ;; Acknowledgements
  384. ;; ----------------
  385. ;; Thanks to Kevin Rodgers <kevinr@ihs.com> for adding support for
  386. ;; color and the invisible property.
  387. ;;
  388. ;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
  389. ;; the initial port to Emacs 19.  His code is no longer part of
  390. ;; ps-print, but his work is still appreciated.
  391. ;;
  392. ;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
  393. ;; for adding underline support.  Their code also is no longer part of
  394. ;; ps-print, but their efforts are not forgotten.
  395. ;;
  396. ;; Thanks also to all of you who mailed code to add features to
  397. ;; ps-print; although I didn't use your code, I still appreciate your
  398. ;; sharing it with me.
  399. ;;
  400. ;; Thanks to all who mailed comments, encouragement, and criticism.
  401. ;; Thanks also to all who responded to my survey; I had too many
  402. ;; responses to reply to them all, but I greatly appreciate your
  403. ;; interest.
  404. ;;
  405. ;; Jim
  406. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  407.  
  408. ;;; Code:
  409.  
  410. (defconst ps-print-version "2.8"
  411.   "ps-print.el,v 2.8 1995/05/04 12:06:10 jct Exp
  412.  
  413. Jim's last change version -- this file may have been edited as part of
  414. Emacs without changes to the version number.  When reporting bugs,
  415. please also report the version of Emacs, if any, that ps-print was
  416. distributed with.
  417.  
  418. Please send all bug fixes and enhancements to
  419.     Jim Thompson <thompson@wg2.waii.com>.")
  420.  
  421. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  422. ;; User Variables:
  423.  
  424. (defvar ps-lpr-command lpr-command
  425.   "*The shell command for printing a PostScript file.")
  426.  
  427. (defvar ps-lpr-switches lpr-switches
  428.   "*A list of extra switches to pass to `ps-lpr-command'.")
  429.  
  430. (defvar ps-spool-duplex nil        ; Not many people have duplex
  431.                     ; printers, so default to nil.
  432.   "*Non-nil indicates spooling is for a two-sided printer.
  433. For a duplex printer, the `ps-spool-*' commands will insert blank pages
  434. as needed between print jobs so that the next buffer printed will
  435. start on the right page.  Also, if headers are turned on, the headers
  436. will be reversed on duplex printers so that the page numbers fall to
  437. the left on even-numbered pages.")
  438.  
  439. (defvar ps-paper-type 'ps-letter
  440.   "*Specifies the size of paper to format for.  Should be one of
  441. `ps-letter', `ps-legal', or `ps-a4'.")
  442.  
  443. (defvar ps-print-header t
  444.   "*Non-nil means print a header at the top of each page.
  445. By default, the header displays the buffer name, page number, and, if
  446. the buffer is visiting a file, the file's directory.  Headers are
  447. customizable by changing variables `ps-header-left' and
  448. `ps-header-right'.")
  449.  
  450. (defvar ps-print-header-frame t
  451.   "*Non-nil means draw a gaudy frame around the header.")
  452.  
  453. (defvar ps-show-n-of-n t
  454.   "*Non-nil means show page numbers as N/M, meaning page N of M.
  455. Note: page numbers are displayed as part of headers, see variable
  456. `ps-print-headers'.")
  457.  
  458. (defvar ps-print-color-p (and (or (fboundp 'x-color-values)    ; fsf
  459.                   (fboundp 'color-instance-rgb-components))
  460.                     ; xemacs
  461.                   (fboundp 'float))
  462. ; Printing color requires both floating point and x-color-values.
  463.   "*If non-nil, print the buffer's text in color.")
  464.  
  465. (defvar ps-default-fg '(0.0 0.0 0.0)
  466.   "*RGB values of the default foreground color.  Defaults to black.")
  467.  
  468. (defvar ps-default-bg '(1.0 1.0 1.0)
  469.   "*RGB values of the default background color.  Defaults to white.")
  470.  
  471. (defvar ps-font-size 10
  472.   "*Font size, in points, for generating Postscript.")
  473.  
  474. (defvar ps-font "Courier"
  475.   "*Font family name for ordinary text, when generating Postscript.")
  476.  
  477. (defvar ps-font-bold "Courier-Bold"
  478.   "*Font family name for bold text, when generating Postscript.")
  479.  
  480. (defvar ps-font-italic "Courier-Oblique"
  481.   "*Font family name for italic text, when generating Postscript.")
  482.  
  483. (defvar ps-font-bold-italic "Courier-BoldOblique"
  484.   "*Font family name for bold italic text, when generating Postscript.")
  485.  
  486. (defvar ps-avg-char-width (if (fboundp 'float) 5.6 6)
  487.   "*The average width, in points, of a character, for generating Postscript.
  488. This is the value that ps-print uses to determine the length,
  489. x-dimension, of the text it has printed, and thus affects the point at
  490. which long lines wrap around.  If you change the font or
  491. font size, you will probably have to adjust this value to match.")
  492.  
  493. (defvar ps-space-width (if (fboundp 'float) 5.6 6)
  494.   "*The width of a space character, for generating Postscript.
  495. This value is used in expanding tab characters.")
  496.  
  497. (defvar ps-line-height (if (fboundp 'float) 11.29 11)
  498.   "*The height of a line, for generating Postscript.
  499. This is the value that ps-print uses to determine the height,
  500. y-dimension, of the lines of text it has printed, and thus affects the
  501. point at which page-breaks are placed.  If you change the font or font
  502. size, you will probably have to adjust this value to match.  The
  503. line-height is *not* the same as the point size of the font.")
  504.  
  505. (defvar ps-auto-font-detect t
  506.   "*Non-nil means automatically detect bold/italic face attributes.
  507. nil means rely solely on the lists `ps-bold-faces', `ps-italic-faces',
  508. and `ps-underlined-faces'.")
  509.  
  510. (defvar ps-bold-faces '()
  511.   "*A list of the \(non-bold\) faces that should be printed in bold font.
  512. This applies to generating Postscript.")
  513.  
  514. (defvar ps-italic-faces '()
  515.   "*A list of the \(non-italic\) faces that should be printed in italic font.
  516. This applies to generating Postscript.")
  517.  
  518. (defvar ps-underlined-faces '()
  519.   "*A list of the \(non-underlined\) faces that should be printed underlined.
  520. This applies to generating Postscript.")
  521.  
  522. (defvar ps-header-lines 2
  523.   "*Number of lines to display in page header, when generating Postscript.")
  524. (make-variable-buffer-local 'ps-header-lines)
  525.  
  526. (defvar ps-left-header
  527.   (list 'ps-get-buffer-name 'ps-header-dirpart)
  528.   "*The items to display on the right part of the page header.
  529. This applies to generating Postscript.
  530.  
  531. The value should be a list of strings and symbols, each representing an
  532. entry in the PostScript array HeaderLinesLeft.
  533.  
  534. Strings are inserted unchanged into the array; those representing
  535. PostScript string literals should be delimited with PostScript string
  536. delimiters '(' and ')'.
  537.  
  538. For symbols with bound functions, the function is called and should
  539. return a string to be inserted into the array.  For symbols with bound
  540. values, the value should be a string to be inserted into the array.
  541. In either case, function or variable, the string value has PostScript
  542. string delimiters added to it.")
  543. (make-variable-buffer-local 'ps-left-header)
  544.  
  545. (defvar ps-right-header
  546.   (list "/pagenumberstring load" 'time-stamp-yy/mm/dd 'time-stamp-hh:mm:ss)
  547.   "*The items to display on the left part of the page header.
  548. This applies to generating Postscript.
  549.  
  550. See the variable `ps-left-header' for a description of the format of
  551. this variable.")
  552. (make-variable-buffer-local 'ps-right-header)
  553.  
  554. (defvar ps-razzle-dazzle t
  555.   "*Non-nil means report progress while formatting buffer.")
  556.  
  557. (defvar ps-adobe-tag "%!PS-Adobe-1.0\n"
  558.   "*Contains the header line identifying the output as PostScript.
  559. By default, `ps-adobe-tag' contains the standard identifier.  Some
  560. printers require slightly different versions of this line.")
  561.  
  562. (defvar ps-build-face-reference t
  563.   "*Non-nil means build the reference face lists.
  564.  
  565. Ps-print sets this value to nil after it builds its internal reference
  566. lists of bold and italic faces.  By settings its value back to t, you
  567. can force ps-print to rebuild the lists the next time you invoke one
  568. of the ...-with-faces commands.
  569.  
  570. You should set this value back to t after you change the attributes of
  571. any face, or create new faces.  Most users shouldn't have to worry
  572. about its setting, though.")
  573.  
  574. (defvar ps-always-build-face-reference nil
  575.   "*Non-nil means always rebuild the reference face lists.
  576.  
  577. If this variable is non-nil, ps-print will rebuild its internal
  578. reference lists of bold and italic faces *every* time one of the
  579. -with-faces commands is called.  Most users shouldn't need to set this
  580. variable.")
  581.  
  582. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  583. ;; User commands
  584.  
  585. ;;;###autoload
  586. (defun ps-print-buffer (&optional filename)
  587.   "Generate and print a PostScript image of the buffer.
  588.  
  589. When called with a numeric prefix argument (C-u), prompts the user for
  590. the name of a file to save the PostScript image in, instead of sending
  591. it to the printer.
  592.  
  593. More specifically, the FILENAME argument is treated as follows: if it
  594. is nil, send the image to the printer.  If FILENAME is a string, save
  595. the PostScript image in a file with that name.  If FILENAME is a
  596. number, prompt the user for the name of the file to save in."
  597.  
  598.   (interactive (list (ps-print-preprint current-prefix-arg)))
  599.   (ps-generate (current-buffer) (point-min) (point-max)
  600.            'ps-generate-postscript)
  601.   (ps-do-despool filename))
  602.  
  603.  
  604. ;;;###autoload
  605. (defun ps-print-buffer-with-faces (&optional filename)
  606.   "Generate and print a PostScript image of the buffer.
  607.  
  608. Like `ps-print-buffer', but includes font, color, and underline
  609. information in the generated image."
  610.   (interactive (list (ps-print-preprint current-prefix-arg)))
  611.   (ps-generate (current-buffer) (point-min) (point-max)
  612.            'ps-generate-postscript-with-faces)
  613.   (ps-do-despool filename))
  614.  
  615.  
  616. ;;;###autoload
  617. (defun ps-print-region (from to &optional filename)
  618.   "Generate and print a PostScript image of the region.
  619.  
  620. Like `ps-print-buffer', but prints just the current region."
  621.  
  622.   (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
  623.   (ps-generate (current-buffer) from to
  624.            'ps-generate-postscript)
  625.   (ps-do-despool filename))
  626.  
  627.  
  628. ;;;###autoload
  629. (defun ps-print-region-with-faces (from to &optional filename)
  630.   "Generate and print a PostScript image of the region.
  631.  
  632. Like `ps-print-region', but includes font, color, and underline
  633. information in the generated image."
  634.  
  635.   (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
  636.   (ps-generate (current-buffer) from to
  637.            'ps-generate-postscript-with-faces)
  638.   (ps-do-despool filename))
  639.  
  640.  
  641. ;;;###autoload
  642. (defun ps-spool-buffer ()
  643.   "Generate and spool a PostScript image of the buffer.
  644.  
  645. Like `ps-print-buffer' except that the PostScript image is saved in a
  646. local buffer to be sent to the printer later.
  647.  
  648. Use the command `ps-despool' to send the spooled images to the printer."
  649.   (interactive)
  650.   (ps-generate (current-buffer) (point-min) (point-max)
  651.            'ps-generate-postscript))
  652.  
  653.  
  654. ;;;###autoload
  655. (defun ps-spool-buffer-with-faces ()
  656.   "Generate and spool a PostScript image of the buffer.
  657.  
  658. Like `ps-spool-buffer', but includes font, color, and underline
  659. information in the generated image.
  660.  
  661. Use the command `ps-despool' to send the spooled images to the printer."
  662.  
  663.   (interactive)
  664.   (ps-generate (current-buffer) (point-min) (point-max)
  665.            'ps-generate-postscript-with-faces))
  666.  
  667.  
  668. ;;;###autoload
  669. (defun ps-spool-region (from to)
  670.   "Generate a PostScript image of the region and spool locally.
  671.  
  672. Like `ps-spool-buffer', but spools just the current region.
  673.  
  674. Use the command `ps-despool' to send the spooled images to the printer."
  675.   (interactive "r")
  676.   (ps-generate (current-buffer) from to
  677.            'ps-generate-postscript))
  678.  
  679.  
  680. ;;;###autoload
  681. (defun ps-spool-region-with-faces (from to)
  682.   "Generate a PostScript image of the region and spool locally.
  683.  
  684. Like `ps-spool-region', but includes font, color, and underline
  685. information in the generated image.
  686.  
  687. Use the command `ps-despool' to send the spooled images to the printer."
  688.   (interactive "r")
  689.   (ps-generate (current-buffer) from to
  690.            'ps-generate-postscript-with-faces))
  691.  
  692. ;;;###autoload
  693. (defun ps-despool (&optional filename)
  694.   "Send the spooled PostScript to the printer.
  695.  
  696. When called with a numeric prefix argument (C-u), prompt the user for
  697. the name of a file to save the spooled PostScript in, instead of sending
  698. it to the printer.
  699.  
  700. More specifically, the FILENAME argument is treated as follows: if it
  701. is nil, send the image to the printer.  If FILENAME is a string, save
  702. the PostScript image in a file with that name.  If FILENAME is a
  703. number, prompt the user for the name of the file to save in."
  704.   (interactive (list (ps-print-preprint current-prefix-arg)))
  705.   (ps-do-despool filename))
  706.  
  707. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  708. ;; Utility functions and variables:
  709.  
  710. (if (featurep 'emacs-vers)
  711.     nil
  712.   (defvar emacs-type (cond ((string-match "XEmacs" emacs-version) 'xemacs)
  713.                ((string-match "Lucid" emacs-version) 'lucid)
  714.                ((string-match "Epoch" emacs-version) 'epoch)
  715.                (t 'fsf))))
  716.  
  717. (if (or (eq emacs-type 'lucid)
  718.     (eq emacs-type 'xemacs))
  719.     (if (< emacs-minor-version 12)
  720.     (setq ps-print-color-p nil))
  721.   (require 'faces))            ; face-font, face-underline-p,
  722.                     ; x-font-regexp
  723.  
  724. (defun xemacs-color-device ()
  725.   (if (and (eq emacs-type 'xemacs)
  726.        (>= emacs-minor-version 12))
  727.       (eq (device-class) 'x)
  728.     t))    
  729.  
  730. (require 'time-stamp)
  731.  
  732. (defvar ps-print-prologue "% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
  733. % If the ISOLatin1Encoding vector isn't known, define it.
  734. /ISOLatin1Encoding where { pop } {
  735. % Define the ISO Latin-1 encoding vector.
  736. % The first half is the same as the standard encoding,
  737. % except for minus instead of hyphen at code 055.
  738. /ISOLatin1Encoding
  739. StandardEncoding 0 45 getinterval aload pop
  740.     /minus
  741. StandardEncoding 46 82 getinterval aload pop
  742. %*** NOTE: the following are missing in the Adobe documentation,
  743. %*** but appear in the displayed table:
  744. %*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
  745. % \20x
  746.     /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
  747.     /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
  748.     /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
  749.     /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
  750. % \24x
  751.     /space /exclamdown /cent /sterling
  752.     /currency /yen /brokenbar /section
  753.     /dieresis /copyright /ordfeminine /guillemotleft
  754.     /logicalnot /hyphen /registered /macron
  755.     /degree /plusminus /twosuperior /threesuperior
  756.     /acute /mu /paragraph /periodcentered
  757.     /cedilla /onesuperior /ordmasculine /guillemotright
  758.     /onequarter /onehalf /threequarters /questiondown
  759. % \30x
  760.     /Agrave /Aacute /Acircumflex /Atilde
  761.     /Adieresis /Aring /AE /Ccedilla
  762.     /Egrave /Eacute /Ecircumflex /Edieresis
  763.     /Igrave /Iacute /Icircumflex /Idieresis
  764.     /Eth /Ntilde /Ograve /Oacute
  765.     /Ocircumflex /Otilde /Odieresis /multiply
  766.     /Oslash /Ugrave /Uacute /Ucircumflex
  767.     /Udieresis /Yacute /Thorn /germandbls
  768. % \34x
  769.     /agrave /aacute /acircumflex /atilde
  770.     /adieresis /aring /ae /ccedilla
  771.     /egrave /eacute /ecircumflex /edieresis
  772.     /igrave /iacute /icircumflex /idieresis
  773.     /eth /ntilde /ograve /oacute
  774.     /ocircumflex /otilde /odieresis /divide
  775.     /oslash /ugrave /uacute /ucircumflex
  776.     /udieresis /yacute /thorn /ydieresis
  777. 256 packedarray def
  778. } ifelse
  779.  
  780. /reencodeFontISO { %def
  781.   dup
  782.   length 5 add dict            % Make a new font (a new dict
  783.                     % the same size as the old
  784.                     % one) with room for our new
  785.                     % symbols.
  786.  
  787.   begin                    % Make the new font the
  788.                     % current dictionary.
  789.  
  790.  
  791.     { 1 index /FID ne
  792.       { def } { pop pop } ifelse
  793.     } forall                % Copy each of the symbols
  794.                     % from the old dictionary to
  795.                     % the new except for the font
  796.                     % ID.
  797.  
  798.     /Encoding ISOLatin1Encoding def    % Override the encoding with
  799.                     % the ISOLatin1 encoding.
  800.  
  801.     % Use the font's bounding box to determine the ascent, descent,
  802.     % and overall height; don't forget that these values have to be
  803.     % transformed using the font's matrix.
  804.     FontBBox
  805.     FontMatrix transform /Ascent exch def pop
  806.     FontMatrix transform /Descent exch def pop
  807.     /FontHeight Ascent Descent sub def
  808.  
  809.     % Define these in case they're not in the FontInfo (also, here
  810.     % they're easier to get to.
  811.     /UnderlinePosition 1 def
  812.     /UnderlineThickness 1 def
  813.  
  814.     % Get the underline position and thickness if they're defined.
  815.     currentdict /FontInfo known {
  816.       FontInfo
  817.  
  818.       dup /UnderlinePosition known {
  819.     dup /UnderlinePosition get
  820.     0 exch FontMatrix transform exch pop
  821.     /UnderlinePosition exch def
  822.       } if
  823.  
  824.       dup /UnderlineThickness known {
  825.     /UnderlineThickness get
  826.     0 exch FontMatrix transform exch pop
  827.     /UnderlineThickness exch def
  828.       } if
  829.  
  830.     } if
  831.  
  832.     currentdict                % Leave the new font on the
  833.                     % stack
  834.  
  835.     end                    % Stop using the font as the
  836.                     % current dictionary.
  837.  
  838.     definefont                % Put the font into the font
  839.                     % dictionary
  840.  
  841.     pop                    % Discard the returned font.
  842. } bind def
  843.  
  844. /Font {
  845.   findfont exch scalefont reencodeFontISO
  846. } def
  847.  
  848. /F {                    % Font select
  849.   findfont
  850.   dup /Ascent get /Ascent exch def
  851.   dup /Descent get /Descent exch def
  852.   dup /FontHeight get /FontHeight exch def
  853.   dup /UnderlinePosition get /UnderlinePosition exch def
  854.   dup /UnderlineThickness get /UnderlineThickness exch def
  855.   setfont
  856. } def
  857.  
  858. /FG /setrgbcolor load def
  859.  
  860. /bg false def
  861. /BG {
  862.   dup /bg exch def
  863.   { mark 4 1 roll ] /bgcolor exch def } if
  864. } def
  865.  
  866. /dobackground {                % width --
  867.   currentpoint
  868.   gsave
  869.     newpath
  870.     moveto
  871.     0 Ascent rmoveto
  872.     dup 0 rlineto
  873.     0 Descent Ascent sub rlineto
  874.     neg 0 rlineto
  875.     closepath
  876.     bgcolor aload pop setrgbcolor
  877.     fill
  878.   grestore
  879. } def
  880.  
  881. /dobackgroundstring {            % string --
  882.   stringwidth pop
  883.   dobackground
  884. } def
  885.  
  886. /dounderline {                % fromx fromy --
  887.   currentpoint
  888.   gsave
  889.     UnderlineThickness setlinewidth
  890.     4 2 roll
  891.     UnderlinePosition add moveto
  892.     UnderlinePosition add lineto
  893.     stroke
  894.   grestore
  895. } def
  896.  
  897. /eolbg {
  898.   currentpoint pop
  899.   PrintWidth LeftMargin add exch sub dobackground
  900. } def
  901.  
  902. /eolul {
  903.   currentpoint exch pop
  904.   PrintWidth LeftMargin add exch dounderline
  905. } def
  906.  
  907. /SL {                    % Soft Linefeed
  908.   bg { eolbg } if
  909.   ul { eolul } if
  910.   currentpoint LineHeight sub LeftMargin exch moveto pop
  911. } def
  912.  
  913. /HL /SL load def            % Hard Linefeed
  914.  
  915. /sp1 { currentpoint 3 -1 roll } def
  916.  
  917. % Some debug
  918. /dcp { currentpoint exch 40 string cvs print (, ) print = } def
  919. /dp { print 2 copy
  920.    exch 40 string cvs print (, ) print = } def
  921.  
  922. /S {
  923.   bg { dup dobackgroundstring } if
  924.   ul { sp1 } if
  925.   show
  926.   ul { dounderline } if
  927. } def
  928.  
  929. /W {
  930.   ul { sp1 } if
  931.   ( ) stringwidth            % Get the width of a space
  932.   pop                    % Discard the Y component
  933.   mul                    % Multiply the width of a
  934.                     % space by the number of
  935.                     % spaces to plot
  936.   bg { dup dobackground } if
  937.   0 rmoveto
  938.   ul { dounderline } if
  939. } def
  940.  
  941. /BeginDSCPage {
  942.   /vmstate save def
  943. } def
  944.  
  945. /BeginPage {
  946.   PrintHeader {
  947.     PrintHeaderFrame { HeaderFrame } if
  948.     HeaderText
  949.   } if
  950.   LeftMargin
  951.   BottomMargin PrintHeight add
  952.   moveto                % move to where printing will
  953.                     % start.
  954. } def
  955.  
  956. /EndPage {
  957.   bg { eolbg } if
  958.   ul { eolul } if
  959.   showpage                % Spit out a page
  960. } def
  961.  
  962. /EndDSCPage {
  963.   vmstate restore
  964. } def
  965.  
  966. /ul false def
  967.  
  968. /UL { /ul exch def } def
  969.  
  970. /h0 14 /Helvetica-Bold Font
  971. /h1 12 /Helvetica Font
  972.  
  973. /h1 F
  974.  
  975. /HeaderLineHeight FontHeight def
  976. /HeaderDescent Descent def
  977. /HeaderPad 2 def
  978.  
  979. /SetHeaderLines {
  980.   /HeaderOffset TopMargin 2 div def
  981.   /HeaderLines exch def
  982.   /HeaderHeight HeaderLines HeaderLineHeight mul HeaderPad 2 mul add def
  983.   /PrintHeight PrintHeight HeaderHeight sub def
  984. } def
  985.  
  986. /HeaderFrameStart {
  987.   LeftMargin BottomMargin PrintHeight add HeaderOffset add
  988. } def
  989.  
  990. /HeaderFramePath {
  991.   PrintWidth 0 rlineto
  992.   0 HeaderHeight rlineto
  993.   PrintWidth neg 0 rlineto
  994.   0 HeaderHeight neg rlineto
  995. } def
  996.  
  997. /HeaderFrame {
  998.   gsave
  999.     0.4 setlinewidth
  1000.     HeaderFrameStart moveto
  1001.     1 -1 rmoveto
  1002.     HeaderFramePath
  1003.     0 setgray fill
  1004.     HeaderFrameStart moveto
  1005.     HeaderFramePath
  1006.     gsave 0.9 setgray fill grestore
  1007.     gsave 0 setgray stroke grestore
  1008.   grestore
  1009. } def
  1010.  
  1011. /HeaderStart {
  1012.   HeaderFrameStart
  1013.   exch HeaderPad add exch
  1014.   HeaderLineHeight HeaderLines 1 sub mul add HeaderDescent sub HeaderPad add
  1015. } def
  1016.  
  1017. /strcat {
  1018.   dup length 3 -1 roll dup length dup 4 -1 roll add string dup
  1019.   0 5 -1 roll putinterval
  1020.   dup 4 2 roll exch putinterval
  1021. } def
  1022.  
  1023. /pagenumberstring {
  1024.   PageNumber 32 string cvs
  1025.   ShowNofN {
  1026.     (/) strcat
  1027.     PageCount 32 string cvs strcat
  1028.   } if
  1029. } def
  1030.  
  1031. /HeaderText {
  1032.   HeaderStart moveto
  1033.  
  1034.   HeaderLinesRight HeaderLinesLeft
  1035.   Duplex PageNumber 1 and 0 eq and { exch } if
  1036.  
  1037.   {
  1038.     aload pop
  1039.     exch F
  1040.     gsave
  1041.       dup xcheck { exec } if
  1042.       show
  1043.     grestore
  1044.     0 HeaderLineHeight neg rmoveto
  1045.   } forall
  1046.  
  1047.   HeaderStart moveto
  1048.  
  1049.    {
  1050.     aload pop
  1051.     exch F
  1052.     gsave
  1053.       dup xcheck { exec } if
  1054.       dup stringwidth pop
  1055.       PrintWidth exch sub HeaderPad 2 mul sub 0 rmoveto
  1056.       show
  1057.     grestore
  1058.     0 HeaderLineHeight neg rmoveto
  1059.   } forall
  1060. } def
  1061.  
  1062. /ReportFontInfo {
  1063.   2 copy
  1064.   /t0 3 1 roll Font
  1065.   /t0 F
  1066.   /lh FontHeight def
  1067.   /sw ( ) stringwidth pop def
  1068.   /aw (01234567890abcdefghijklmnopqrstuvwxyz) dup length exch
  1069.   stringwidth pop exch div def
  1070.   /t1 12 /Helvetica-Oblique Font
  1071.   /t1 F
  1072.   72 72 moveto
  1073.   gsave
  1074.     (For ) show
  1075.     128 string cvs show
  1076.     ( ) show
  1077.     32 string cvs show
  1078.     ( point, the line height is ) show
  1079.     lh 32 string cvs show
  1080.     (, the space width is ) show
  1081.     sw 32 string cvs show
  1082.     (,) show
  1083.   grestore
  1084.   0 FontHeight neg rmoveto
  1085.   (and a crude estimate of average character width is ) show
  1086.   aw 32 string cvs show
  1087.   (.) show
  1088.   showpage
  1089. } def
  1090.  
  1091. % 10 /Courier ReportFontInfo
  1092. ")
  1093.  
  1094. ;; Start Editing Here:
  1095.  
  1096. (defvar ps-source-buffer nil)
  1097. (defvar ps-spool-buffer-name "*PostScript*")
  1098. (defvar ps-spool-buffer nil)
  1099.  
  1100. (defvar ps-output-head nil)
  1101. (defvar ps-output-tail nil)
  1102.  
  1103. (defvar ps-page-count 0)
  1104. (defvar ps-showpage-count 0)
  1105.  
  1106. (defvar ps-current-font 0)
  1107. (defvar ps-current-underline-p nil)
  1108. (defvar ps-default-color (if ps-print-color-p ps-default-fg)) ; black
  1109. (defvar ps-current-color ps-default-color)
  1110. (defvar ps-current-bg nil)
  1111.  
  1112. (defvar ps-razchunk 0)
  1113.  
  1114. (defvar ps-color-format (if (eq emacs-type 'fsf)
  1115.  
  1116.                 ;;Emacs understands the %f format; we'll
  1117.                 ;;use it to limit color RGB values to
  1118.                 ;;three decimals to cut down some on the
  1119.                 ;;size of the PostScript output.
  1120.                 "%0.3f %0.3f %0.3f"
  1121.  
  1122.               ;; Lucid emacsen will have to make do with
  1123.               ;; %s (princ) for floats.
  1124.               "%s %s %s"))
  1125.  
  1126. ;; These values determine how much print-height to deduct when headers
  1127. ;; are turned on.  This is a pretty clumsy way of handling it, but
  1128. ;; it'll do for now.
  1129. (defvar ps-header-title-line-height (if (fboundp 'float) 16.0 16));Helvetica 14
  1130. (defvar ps-header-line-height (if (fboundp 'float) 13.7 14));Helvetica 12
  1131. (defvar ps-header-pad 2)
  1132.  
  1133. ;; LetterSmall 7.68 inch 10.16 inch
  1134. ;; Tabloid 11.0 inch 17.0 inch
  1135. ;; Ledger 17.0 inch 11.0 inch
  1136. ;; Statement 5.5 inch 8.5 inch
  1137. ;; Executive 7.5 inch 10.0 inch
  1138. ;; A3 11.69 inch 16.5 inch
  1139. ;; A4Small 7.47 inch 10.85 inch
  1140. ;; B4 10.125 inch 14.33 inch
  1141. ;; B5 7.16 inch 10.125 inch
  1142.  
  1143. ;; All page dimensions are in PostScript points.
  1144.  
  1145. (defvar ps-left-margin 72)        ; 1 inch
  1146. (defvar ps-right-margin 72)        ; 1 inch
  1147. (defvar ps-bottom-margin 36)        ; 1/2 inch
  1148. (defvar ps-top-margin 72)        ; 1 inch
  1149.  
  1150. ;; Letter 8.5 inch x 11.0 inch
  1151. (defvar ps-letter-page-height 792)    ; 11 inches
  1152. (defvar ps-letter-page-width 612)    ; 8.5 inches
  1153.  
  1154. ;; Legal 8.5 inch x 14.0 inch
  1155. (defvar ps-legal-page-height 1008)    ; 14.0 inches
  1156. (defvar ps-legal-page-width 612)    ; 8.5 inches
  1157.  
  1158. ;; A4 8.26 inch x 11.69 inch
  1159. (defvar ps-a4-page-height 842)    ; 11.69 inches
  1160. (defvar ps-a4-page-width 595)    ; 8.26 inches
  1161.  
  1162. (defvar ps-pages-alist
  1163.   (list (list 'ps-letter ps-letter-page-width ps-letter-page-height)
  1164.     (list 'ps-legal ps-legal-page-width ps-legal-page-height)
  1165.     (list 'ps-a4 ps-a4-page-width ps-a4-page-height)))
  1166.  
  1167. ;; Define some constants to index into the page lists.
  1168. (defvar ps-page-width-i 1)
  1169. (defvar ps-page-height-i 2)
  1170.  
  1171. (defvar ps-page-dimensions nil)
  1172. (defvar ps-print-width nil)
  1173. (defvar ps-print-height nil)
  1174.  
  1175. (defvar ps-height-remaining)
  1176. (defvar ps-width-remaining)
  1177.  
  1178. (defvar ps-ref-bold-faces nil)
  1179. (defvar ps-ref-italic-faces nil)
  1180. (defvar ps-ref-underlined-faces nil)
  1181.  
  1182. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1183. ;; Internal functions
  1184.  
  1185. (defun ps-get-page-dimensions ()
  1186.   (setq ps-page-dimensions (assq ps-paper-type ps-pages-alist))
  1187.   (let ((ps-page-width (nth ps-page-width-i ps-page-dimensions))
  1188.     (ps-page-height (nth ps-page-height-i ps-page-dimensions)))
  1189.     (setq ps-print-height (- ps-page-height ps-top-margin ps-bottom-margin))
  1190.     (setq ps-print-width (- ps-page-width ps-left-margin ps-right-margin))))
  1191.  
  1192. (defun ps-print-preprint (&optional filename)
  1193.   (if (and filename
  1194.        (or (numberp filename)
  1195.            (listp filename)))
  1196.       (let* ((name (concat (buffer-name) ".ps"))
  1197.          (prompt (format "Save PostScript to file: (default %s) "
  1198.                  name)))
  1199.     (read-file-name prompt default-directory
  1200.             name nil))))
  1201.  
  1202. ;; The following functions implement a simple list-buffering scheme so
  1203. ;; that ps-print doesn't have to repeatedly switch between buffers
  1204. ;; while spooling.  The functions ps-output and ps-output-string build
  1205. ;; up the lists; the function ps-flush-output takes the lists and
  1206. ;; insert its contents into the spool buffer (*PostScript*).
  1207.  
  1208. (defun ps-output-string-prim (string)
  1209.   (insert "(")                ;insert start-string delimiter
  1210.   (save-excursion            ;insert string
  1211.     (insert string))
  1212.  
  1213.   ;; Find and quote special characters as necessary for PS
  1214.   (while (re-search-forward "[()\\]" nil t)
  1215.     (save-excursion
  1216.       (forward-char -1)
  1217.       (insert "\\")))
  1218.  
  1219.   (goto-char (point-max))
  1220.   (insert ")"))                ;insert end-string delimiter
  1221.  
  1222. (defun ps-init-output-queue ()
  1223.   (setq ps-output-head (list ""))
  1224.   (setq ps-output-tail ps-output-head))
  1225.  
  1226. (defun ps-output (&rest args)
  1227.   (setcdr ps-output-tail args)
  1228.   (while (cdr ps-output-tail)
  1229.     (setq ps-output-tail (cdr ps-output-tail))))
  1230.  
  1231. (defun ps-output-string (string)
  1232.   (ps-output t string))
  1233.  
  1234. (defun ps-flush-output ()
  1235.   (save-excursion
  1236.     (set-buffer ps-spool-buffer)
  1237.     (goto-char (point-max))
  1238.     (while ps-output-head
  1239.       (let ((it (car ps-output-head)))
  1240.     (if (not (eq t it))
  1241.         (insert it)
  1242.       (setq ps-output-head (cdr ps-output-head))
  1243.       (ps-output-string-prim (car ps-output-head))))
  1244.       (setq ps-output-head (cdr ps-output-head))))
  1245.   (ps-init-output-queue))
  1246.  
  1247. (defun ps-insert-file (fname)
  1248.   (ps-flush-output)
  1249.  
  1250.   ;; Check to see that the file exists and is readable; if not, throw
  1251.   ;; and error.
  1252.   (if (not (file-readable-p fname))
  1253.       (error "Could not read file `%s'" fname))
  1254.  
  1255.   (save-excursion
  1256.     (set-buffer ps-spool-buffer)
  1257.     (goto-char (point-max))
  1258.     (insert-file fname)))
  1259.     
  1260. ;; These functions insert the arrays that define the contents of the
  1261. ;; headers.
  1262.  
  1263. (defun ps-generate-header-line (fonttag &optional content)
  1264.   (ps-output "  [ " fonttag " ")
  1265.   (cond
  1266.    ;; Literal strings should be output as is -- the string must
  1267.    ;; contain its own PS string delimiters, '(' and ')', if necessary.
  1268.    ((stringp content)
  1269.     (ps-output content))
  1270.  
  1271.    ;; Functions are called -- they should return strings; they will be
  1272.    ;; inserted as strings and the PS string delimiters added.
  1273.    ((and (symbolp content) (fboundp content))
  1274.     (ps-output-string (funcall content)))
  1275.  
  1276.    ;; Variables will have their contents inserted.  They should
  1277.    ;; contain strings, and will be inserted as strings.
  1278.    ((and (symbolp content) (boundp content))
  1279.     (ps-output-string (symbol-value content)))
  1280.  
  1281.    ;; Anything else will get turned into an empty string.
  1282.    (t
  1283.     (ps-output-string "")))
  1284.   (ps-output " ]\n"))
  1285.  
  1286. (defun ps-generate-header (name contents)
  1287.   (ps-output "/" name " [\n")
  1288.   (if (> ps-header-lines 0)
  1289.       (let ((count 1))
  1290.     (ps-generate-header-line "/h0" (car contents))
  1291.     (while (and (< count ps-header-lines)
  1292.             (setq contents (cdr contents)))
  1293.       (ps-generate-header-line "/h1" (car contents))
  1294.       (setq count (+ count 1)))
  1295.     (ps-output "] def\n"))))
  1296.  
  1297. (defun ps-output-boolean (name bool)
  1298.   (ps-output (format "/%s %s def\n" name (if bool "true" "false"))))
  1299.  
  1300. (defun ps-begin-file ()
  1301.   (setq ps-showpage-count 0)
  1302.  
  1303.   (ps-output ps-adobe-tag)
  1304.   (ps-output "%%Title: " (buffer-name) "\n") ;Take job name from name of
  1305.                     ;first buffer printed
  1306.   (ps-output "%%Creator: " (user-full-name) "\n")
  1307.   (ps-output "%%CreationDate: " 
  1308.          (time-stamp-hh:mm:ss) " " (time-stamp-mon-dd-yyyy) "\n")
  1309.   (ps-output "%% DocumentFonts: Helvetica Helvetica-Bold "
  1310.          ps-font " " ps-font-bold " " ps-font-italic " "
  1311.          ps-font-bold-italic "\n")
  1312.   (ps-output "%%Pages: (atend)\n")
  1313.   (ps-output "%%EndComments\n\n")
  1314.  
  1315.   (ps-output-boolean "Duplex" ps-spool-duplex)
  1316.   (ps-output-boolean "PrintHeader" ps-print-header)
  1317.   (ps-output-boolean "PrintHeaderFrame" ps-print-header-frame)
  1318.   (ps-output-boolean "ShowNofN" ps-show-n-of-n)
  1319.  
  1320.   (ps-output (format "/LeftMargin %d def\n" ps-left-margin))
  1321.   (ps-output (format "/RightMargin %d def\n" ps-right-margin))
  1322.   (ps-output (format "/BottomMargin %d def\n" ps-bottom-margin))
  1323.   (ps-output (format "/TopMargin %d def\n" ps-top-margin))
  1324.  
  1325.   (ps-get-page-dimensions)
  1326.   (ps-output (format "/PrintWidth %d def\n" ps-print-width))
  1327.   (ps-output (format "/PrintHeight %d def\n" ps-print-height))
  1328.   
  1329.   (ps-output (format "/LineHeight %s def\n" ps-line-height))
  1330.   
  1331.   (ps-output ps-print-prologue)
  1332.  
  1333.   (ps-output (format "/f0 %d /%s Font\n" ps-font-size ps-font))
  1334.   (ps-output (format "/f1 %d /%s Font\n" ps-font-size ps-font-bold))
  1335.   (ps-output (format "/f2 %d /%s Font\n" ps-font-size ps-font-italic))
  1336.   (ps-output (format "/f3 %d /%s Font\n" ps-font-size
  1337.              ps-font-bold-italic))
  1338.  
  1339.   (ps-output "%%EndPrologue\n"))
  1340.  
  1341. (defun ps-header-dirpart ()
  1342.   (let ((fname (buffer-file-name)))
  1343.     (if fname
  1344.     (if (string-equal (buffer-name) (file-name-nondirectory fname))
  1345.         (file-name-directory fname)
  1346.       fname)
  1347.       "")))
  1348.  
  1349. (defun ps-get-buffer-name ()
  1350.   ;; Indulge me this little easter egg:
  1351.   (if (string= (buffer-name) "ps-print.el")
  1352.       "Hey, Cool!  It's ps-print.el!!!"
  1353.     (buffer-name)))
  1354.  
  1355. (defun ps-begin-job ()
  1356.   (setq ps-page-count 0))
  1357.  
  1358. (defun ps-end-file ()
  1359.   (ps-output "%%Trailer\n")
  1360.   (ps-output "%%Pages: " (format "%d\n" ps-showpage-count)))
  1361.  
  1362. (defun ps-next-page ()
  1363.   (ps-end-page)
  1364.   (ps-flush-output)
  1365.   (ps-begin-page))
  1366.  
  1367. (defun ps-begin-page (&optional dummypage)
  1368.   (ps-get-page-dimensions)
  1369.   (setq ps-width-remaining ps-print-width)
  1370.   (setq ps-height-remaining ps-print-height)
  1371.  
  1372.   ;; If headers are turned on, deduct the height of the header from
  1373.   ;; the print height remaining.  Clumsy clumsy clumsy.
  1374.   (if ps-print-header
  1375.       (setq ps-height-remaining
  1376.         (- ps-height-remaining
  1377.            ps-header-title-line-height
  1378.            (* ps-header-line-height (- ps-header-lines 1))
  1379.            (* 2 ps-header-pad))))
  1380.  
  1381.   (setq ps-page-count (+ ps-page-count 1))
  1382.  
  1383.   (ps-output "\n%%Page: " 
  1384.          (format "%d %d\n" ps-page-count (+ 1 ps-showpage-count)))
  1385.   (ps-output "BeginDSCPage\n")
  1386.   (ps-output (format "/PageNumber %d def\n" ps-page-count))
  1387.   (ps-output "/PageCount 0 def\n")
  1388.  
  1389.   (if ps-print-header
  1390.       (progn
  1391.     (ps-generate-header "HeaderLinesLeft" ps-left-header)
  1392.     (ps-generate-header "HeaderLinesRight" ps-right-header)
  1393.     (ps-output (format "%d SetHeaderLines\n" ps-header-lines))))
  1394.  
  1395.   (ps-output "BeginPage\n")
  1396.   (ps-set-font ps-current-font)
  1397.   (ps-set-bg ps-current-bg)
  1398.   (ps-set-color ps-current-color)
  1399.   (ps-set-underline ps-current-underline-p))
  1400.  
  1401. (defun ps-end-page ()
  1402.   (setq ps-showpage-count (+ 1 ps-showpage-count))
  1403.   (ps-output "EndPage\n")
  1404.   (ps-output "EndDSCPage\n"))
  1405.  
  1406. (defun ps-dummy-page ()
  1407.   (setq ps-showpage-count (+ 1 ps-showpage-count))
  1408.   (ps-output "%%Page: " (format "- %d\n" ps-showpage-count)
  1409.          "BeginDSCPage
  1410. /PrintHeader false def
  1411. BeginPage
  1412. EndPage
  1413. EndDSCPage\n"))
  1414.         
  1415. (defun ps-next-line ()
  1416.   (if (< ps-height-remaining ps-line-height)
  1417.       (ps-next-page)
  1418.     (setq ps-width-remaining ps-print-width)
  1419.     (setq ps-height-remaining (- ps-height-remaining ps-line-height))
  1420.     (ps-hard-lf)))
  1421.  
  1422. (defun ps-continue-line ()
  1423.   (if (< ps-height-remaining ps-line-height)
  1424.       (ps-next-page)
  1425.     (setq ps-width-remaining ps-print-width)
  1426.     (setq ps-height-remaining (- ps-height-remaining ps-line-height))
  1427.     (ps-soft-lf)))
  1428.  
  1429. (defun ps-hard-lf ()
  1430.   (ps-output "HL\n"))
  1431.  
  1432. (defun ps-soft-lf ()
  1433.   (ps-output "SL\n"))
  1434.  
  1435. (defun ps-find-wrappoint (from to char-width)
  1436.   (let ((avail (truncate (/ ps-width-remaining char-width)))
  1437.     (todo (- to from)))
  1438.     (if (< todo avail)
  1439.     (cons to (* todo char-width))
  1440.       (cons (+ from avail) ps-width-remaining))))
  1441.  
  1442. (defun ps-basic-plot-string (from to &optional bg-color)
  1443.   (let* ((wrappoint (ps-find-wrappoint from to ps-avg-char-width))
  1444.      (to (car wrappoint))
  1445.      (string (buffer-substring from to)))
  1446.     (ps-output-string string)
  1447.     (ps-output " S\n")            ;
  1448.     wrappoint))
  1449.  
  1450. (defun ps-basic-plot-whitespace (from to &optional bg-color)
  1451.   (let* ((wrappoint (ps-find-wrappoint from to ps-space-width))
  1452.      (to (car wrappoint)))
  1453.  
  1454.     (ps-output (format "%d W\n" (- to from)))
  1455.     wrappoint))
  1456.  
  1457. (defun ps-plot (plotfunc from to &optional bg-color)
  1458.   (while (< from to)
  1459.     (let* ((wrappoint (funcall plotfunc from to bg-color))
  1460.        (plotted-to (car wrappoint))
  1461.        (plotted-width (cdr wrappoint)))
  1462.       (setq from plotted-to)
  1463.       (setq ps-width-remaining (- ps-width-remaining plotted-width))
  1464.       (if (< from to)
  1465.       (ps-continue-line))))
  1466.   (if ps-razzle-dazzle
  1467.       (let* ((q-todo (- (point-max) (point-min)))
  1468.          (q-done (- (point) (point-min)))
  1469.          (chunkfrac (/ q-todo 8))
  1470.          (chunksize (if (> chunkfrac 1000) 1000 chunkfrac)))
  1471.     (if (> (- q-done ps-razchunk) chunksize)
  1472.         (let (foo)
  1473.           (setq ps-razchunk q-done)
  1474.           (setq foo
  1475.             (if (< q-todo 100)
  1476.             (/ (* 100 q-done) q-todo)
  1477.               (/ q-done (/ q-todo 100))))
  1478.           (message "Formatting...%d%%" foo))))))
  1479.  
  1480. (defun ps-set-font (font)
  1481.   (setq ps-current-font font)
  1482.   (ps-output (format "/f%d F\n" ps-current-font)))
  1483.  
  1484. (defvar ps-print-color-scale nil)
  1485.  
  1486. (defun ps-set-bg (color)
  1487.   (if (setq ps-current-bg color)
  1488.       (ps-output (format ps-color-format (nth 0 color) (nth 1 color)
  1489.              (nth 2 color))
  1490.          " true BG\n")
  1491.     (ps-output "false BG\n")))
  1492.  
  1493. (defun ps-set-color (color)
  1494.   (if (setq ps-current-color color)
  1495.       nil
  1496.     (setq ps-current-color ps-default-fg))
  1497.   (ps-output (format ps-color-format (nth 0 ps-current-color)
  1498.              (nth 1 ps-current-color) (nth 2 ps-current-color))
  1499.          " FG\n"))
  1500.  
  1501. (defun ps-set-underline (underline-p)
  1502.   (ps-output (if underline-p "true" "false") " UL\n")
  1503.   (setq ps-current-underline-p underline-p))
  1504.  
  1505. (defun ps-plot-region (from to font fg-color &optional bg-color underline-p)
  1506.  
  1507.   (if (not (equal font ps-current-font))
  1508.       (ps-set-font font))
  1509.   
  1510.   ;; Specify a foreground color only if one's specified and it's
  1511.   ;; different than the current.
  1512.   (if (not (equal fg-color ps-current-color))
  1513.       (ps-set-color fg-color))
  1514.   
  1515.   (if (not (equal bg-color ps-current-bg))
  1516.       (ps-set-bg bg-color))
  1517.   
  1518.   ;; Toggle underlining if different.
  1519.   (if (not (equal underline-p ps-current-underline-p))
  1520.       (ps-set-underline underline-p))
  1521.  
  1522.   ;; Starting at the beginning of the specified region...
  1523.   (save-excursion
  1524.     (goto-char from)
  1525.  
  1526.     ;; ...break the region up into chunks separated by tabs, linefeeds,
  1527.     ;; and pagefeeds, and plot each chunk.
  1528.     (while (< from to)
  1529.       (if (re-search-forward "[\t\n\f]" to t)
  1530.           (let ((match (char-after (match-beginning 0))))
  1531.             (cond
  1532.          ((= match ?\t)
  1533.           (let ((linestart
  1534.              (save-excursion (beginning-of-line) (point))))
  1535.         (ps-plot 'ps-basic-plot-string from (- (point) 1)
  1536.              bg-color)
  1537.         (forward-char -1)
  1538.         (setq from (+ linestart (current-column)))
  1539.         (if (re-search-forward "[ \t]+" to t)
  1540.             (ps-plot 'ps-basic-plot-whitespace
  1541.                  from (+ linestart (current-column))
  1542.                  bg-color))))
  1543.  
  1544.          ((= match ?\n)
  1545.           (ps-plot 'ps-basic-plot-string from (- (point) 1)
  1546.                bg-color)
  1547.           (ps-next-line)
  1548.           )
  1549.  
  1550.          ((= match ?\f)
  1551.           (ps-plot 'ps-basic-plot-string from (- (point) 1)
  1552.                bg-color)
  1553.           (ps-next-page)))
  1554.             (setq from (point)))
  1555.         (ps-plot 'ps-basic-plot-string from to bg-color)
  1556.         (setq from to)))))
  1557.  
  1558. (defun ps-color-value (x-color-value)
  1559.   ;; Scale 16-bit X-COLOR-VALUE to PostScript color value in [0, 1] interval.
  1560.   (/ x-color-value ps-print-color-scale))
  1561.  
  1562. (defun ps-color-values (x-color)
  1563.   (cond ((fboundp 'x-color-values)
  1564.      (x-color-values x-color))
  1565.     ((and (fboundp 'color-instance-rgb-components)
  1566.           (xemacs-color-device))
  1567.      (color-instance-rgb-components
  1568.       (if (color-instance-p x-color) x-color
  1569.         (if (color-specifier-p x-color)
  1570.         (make-color-instance (color-name x-color))
  1571.           (make-color-instance x-color)))))
  1572.     (t (error "No available function to determine X color values."))))
  1573.  
  1574. (defun ps-face-attributes (face)
  1575.   (let ((differs (face-differs-from-default-p face)))
  1576.     (list (memq face ps-ref-bold-faces)
  1577.       (memq face ps-ref-italic-faces)
  1578.       (memq face ps-ref-underlined-faces)
  1579.       (and differs (face-foreground face))
  1580.       (and differs (face-background face)))))
  1581.  
  1582. (defun ps-face-attribute-list (face-or-list)
  1583.   (if (listp face-or-list)
  1584.       (let (bold-p italic-p underline-p foreground background face-attr face)
  1585.     (while face-or-list
  1586.       (setq face (car face-or-list))
  1587.       (setq face-attr (ps-face-attributes face))
  1588.       (setq bold-p (or bold-p (nth 0 face-attr)))
  1589.       (setq italic-p (or italic-p (nth 1 face-attr)))
  1590.       (setq underline-p (or underline-p (nth 2 face-attr)))
  1591.       (if foreground
  1592.           nil
  1593.         (setq foreground (nth 3 face-attr)))
  1594.       (if background
  1595.           nil
  1596.         (setq background (nth 4 face-attr)))
  1597.       (setq face-or-list (cdr face-or-list)))
  1598.     (list bold-p italic-p underline-p foreground background))
  1599.  
  1600.     (ps-face-attributes face-or-list)))
  1601.  
  1602. (defun ps-plot-with-face (from to face)
  1603.   (if face
  1604.       (let* ((face-attr (ps-face-attribute-list face))
  1605.          (bold-p (nth 0 face-attr))
  1606.          (italic-p (nth 1 face-attr))
  1607.          (underline-p (nth 2 face-attr))
  1608.          (foreground (nth 3 face-attr))
  1609.          (background (nth 4 face-attr))
  1610.          (fg-color (if (and ps-print-color-p
  1611.                 (xemacs-color-device) 
  1612.                 foreground)
  1613.                (mapcar 'ps-color-value
  1614.                    (ps-color-values foreground))
  1615.              ps-default-color))
  1616.          (bg-color (if (and ps-print-color-p
  1617.                 (xemacs-color-device)
  1618.                 background)
  1619.                (mapcar 'ps-color-value
  1620.                    (ps-color-values background)))))
  1621.     (ps-plot-region from to
  1622.             (cond ((and bold-p italic-p) 3)
  1623.                   (italic-p 2)
  1624.                   (bold-p 1)
  1625.                   (t 0))
  1626. ;            (or fg-color '(0.0 0.0 0.0))
  1627.             fg-color
  1628.             bg-color underline-p))
  1629.     (goto-char to)))
  1630.  
  1631.  
  1632. (defun ps-fsf-face-kind-p (face kind kind-regex kind-list)
  1633.   (let ((face-defaults (face-font face t)))
  1634.     (or
  1635.      ;; Check FACE defaults:
  1636.      (and (listp face-defaults)
  1637.       (memq kind face-defaults))
  1638.  
  1639.      ;; Check the user's preferences
  1640.      (memq face kind-list))))
  1641.  
  1642. (defun ps-xemacs-face-kind-p (face kind kind-regex kind-list)
  1643.   (let* ((frame-font
  1644.       (or (face-font-instance face) (face-font-instance 'default)))
  1645.      (kind-cons (and frame-font
  1646.              (assq kind (font-instance-properties frame-font))))
  1647.      (kind-spec (cdr-safe kind-cons))
  1648.      (case-fold-search t))
  1649.  
  1650.     (or (and kind-spec (string-match kind-regex kind-spec))
  1651.     ;; Kludge-compatible:
  1652.     (memq face kind-list))))
  1653.  
  1654. (defun ps-face-bold-p (face)
  1655.   (if (eq emacs-type 'fsf)
  1656.       (ps-fsf-face-kind-p face 'bold "-\\(bold\\|demibold\\)-"
  1657.               ps-bold-faces)
  1658.     (ps-xemacs-face-kind-p face 'WEIGHT_NAME "bold\\|demibold"
  1659.                ps-bold-faces)))
  1660.  
  1661. (defun ps-face-italic-p (face)
  1662.   (if (eq emacs-type 'fsf)
  1663.       (ps-fsf-face-kind-p face 'italic "-[io]-" ps-italic-faces)
  1664.     (or
  1665.      (ps-xemacs-face-kind-p face 'ANGLE_NAME "i\\|o" ps-italic-faces)
  1666.      (ps-xemacs-face-kind-p face 'SLANT "i\\|o" ps-italic-faces))))
  1667.  
  1668. (defun ps-face-underlined-p (face)
  1669.   (or (face-underline-p face)
  1670.       (memq face ps-underlined-faces)))
  1671.  
  1672. ;; Ensure that face-list is fbound.
  1673. (or (fboundp 'face-list) (defalias 'face-list 'list-faces))
  1674.  
  1675. (defun ps-build-reference-face-lists ()
  1676.   (if ps-auto-font-detect
  1677.       (let ((faces (face-list))
  1678.         the-face)
  1679.     (setq ps-ref-bold-faces nil
  1680.           ps-ref-italic-faces nil
  1681.           ps-ref-underlined-faces nil)
  1682.     (while faces
  1683.       (setq the-face (car faces))
  1684.       (if (ps-face-italic-p the-face)
  1685.           (setq ps-ref-italic-faces
  1686.             (cons the-face ps-ref-italic-faces)))
  1687.       (if (ps-face-bold-p the-face)
  1688.           (setq ps-ref-bold-faces
  1689.             (cons the-face ps-ref-bold-faces)))
  1690.       (if (ps-face-underlined-p the-face)
  1691.           (setq ps-ref-underlined-faces
  1692.             (cons the-face ps-ref-underlined-faces)))
  1693.       (setq faces (cdr faces))))
  1694.     (setq ps-ref-bold-faces ps-bold-faces)
  1695.     (setq ps-ref-italic-faces ps-italic-faces)
  1696.     (setq ps-ref-underlined-faces ps-underlined-faces))
  1697.   (setq ps-build-face-reference nil))
  1698.  
  1699. (defun ps-mapper (extent list)
  1700.   (nconc list (list (list (extent-start-position extent) 'push extent)
  1701.                     (list (extent-end-position extent) 'pull extent)))
  1702.   nil)
  1703.  
  1704. (defun ps-sorter (a b)
  1705.   (< (car a) (car b)))
  1706.  
  1707. (defun ps-extent-sorter (a b)
  1708.   (< (extent-priority a) (extent-priority b)))
  1709.  
  1710. (defun ps-print-ensure-fontified (start end)
  1711.   (if (and (boundp 'lazy-lock-mode) lazy-lock-mode)
  1712.       (if (fboundp 'lazy-lock-fontify-region)
  1713.           (lazy-lock-fontify-region start end)
  1714.         (lazy-lock-fontify-buffer))))
  1715.  
  1716. (defun ps-generate-postscript-with-faces (from to)
  1717.   ;; Build the reference lists of faces if necessary.
  1718.   (if (or ps-always-build-face-reference
  1719.       ps-build-face-reference)
  1720.       (progn
  1721.     (message "Collecting face information...")
  1722.     (ps-build-reference-face-lists)))
  1723.   ;; Set the color scale.  We do it here instead of in the defvar so
  1724.   ;; that ps-print can be dumped into emacs.  This expression can't be
  1725.   ;; evaluated at dump-time because X isn't initialized.
  1726.   (setq ps-print-color-scale
  1727.     (if (and ps-print-color-p (xemacs-color-device))
  1728.         (float (car (ps-color-values "white")))
  1729.       1.0))
  1730.   ;; Generate some PostScript.
  1731.   (save-restriction
  1732.     (narrow-to-region from to)
  1733.     (let ((face 'default)
  1734.       (position to))
  1735.       (ps-print-ensure-fontified from to)
  1736.       (cond ((or (eq emacs-type 'lucid) (eq emacs-type 'xemacs))
  1737.        ;; Build the list of extents...
  1738.        (let ((a (cons 'dummy nil))
  1739.          record type extent extent-list)
  1740.          (map-extents 'ps-mapper nil from to a)
  1741.          (setq a (cdr a))
  1742.          (setq a (sort a 'ps-sorter))
  1743.        
  1744.          (setq extent-list nil)
  1745.        
  1746.          ;; Loop through the extents...
  1747.          (while a
  1748.            (setq record (car a))
  1749.          
  1750.            (setq position (car record))
  1751.            (setq record (cdr record))
  1752.          
  1753.            (setq type (car record))
  1754.            (setq record (cdr record))
  1755.          
  1756.            (setq extent (car record))
  1757.          
  1758.            ;; Plot up to this record.
  1759.            ;; XEmacs 19.12: for some reason, we're getting into a
  1760.            ;; situation in which some of the records have
  1761.            ;; positions less than 'from'.  Since we've narrowed
  1762.            ;; the buffer, this'll generate errors.  This is a
  1763.            ;; hack, but don't call ps-plot-with-face unless from >
  1764.            ;; point-min.
  1765.            (if (and (>= from (point-min))
  1766.             (<= position (point-max)))
  1767.            (ps-plot-with-face from position face))
  1768.          
  1769.            (cond
  1770.         ((eq type 'push)
  1771.          (if (extent-face extent)
  1772.              (setq   extent-list (sort (cons extent extent-list)
  1773.                            'ps-extent-sorter))))
  1774.           
  1775.         ((eq type 'pull)
  1776.          (setq extent-list (sort (delq extent extent-list)
  1777.                      'ps-extent-sorter))))
  1778.          
  1779.            (setq face
  1780.              (if extent-list
  1781.              (extent-face (car extent-list))
  1782.                'default))
  1783.          
  1784.            (setq from position)
  1785.            (setq a (cdr a)))))
  1786.  
  1787.         ((eq emacs-type 'fsf)
  1788.          (let ((property-change from)
  1789.            (overlay-change from))
  1790.            (while (< from to)
  1791.          (if (< property-change to) ; Don't search for property change
  1792.                     ; unless previous search succeeded.
  1793.              (setq property-change
  1794.                (next-property-change from nil to)))
  1795.          (if (< overlay-change to) ; Don't search for overlay change
  1796.                     ; unless previous search succeeded.
  1797.              (setq overlay-change
  1798.                (min (next-overlay-change from) to)))
  1799.          (setq position
  1800.                (min property-change overlay-change))
  1801.          (setq face
  1802.                (cond ((get-text-property from 'invisible) nil)
  1803.                  ((get-text-property from 'face))
  1804.                  (t 'default)))
  1805.          (let ((overlays (overlays-at from))
  1806.                (face-priority -1)) ; text-property
  1807.            (while overlays
  1808.              (let* ((overlay (car overlays))
  1809.                 (overlay-face (overlay-get overlay 'face))
  1810.                 (overlay-invisible (overlay-get overlay 'invisible))
  1811.                 (overlay-priority (or (overlay-get overlay
  1812.                                    'priority)
  1813.                           0)))
  1814.                (if (and (or overlay-invisible overlay-face)
  1815.                 (> overlay-priority face-priority))
  1816.                (setq face (cond (overlay-invisible nil)
  1817.                         ((and face overlay-face)))
  1818.                  face-priority overlay-priority)))
  1819.              (setq overlays (cdr overlays))))
  1820.          ;; Plot up to this record.
  1821.          (ps-plot-with-face from position face)
  1822.          (setq from position)))))
  1823.       (ps-plot-with-face from to face))))  
  1824.  
  1825. (defun ps-generate-postscript (from to)
  1826.   (ps-plot-region from to 0 nil))
  1827.  
  1828. (defun ps-generate (buffer from to genfunc)
  1829.   (let ((from (min to from))
  1830.     (to (max to from)))
  1831.     (save-restriction
  1832.       (narrow-to-region from to)
  1833.       (if ps-razzle-dazzle
  1834.       (message "Formatting...%d%%" (setq ps-razchunk 0)))
  1835.       (set-buffer buffer)
  1836.       (setq ps-source-buffer buffer)
  1837.       (setq ps-spool-buffer (get-buffer-create ps-spool-buffer-name))
  1838.       (ps-init-output-queue)
  1839.       (let (safe-marker completed-safely needs-begin-file)
  1840.     (unwind-protect
  1841.         (progn
  1842.           (set-buffer ps-spool-buffer)
  1843.         
  1844.           ;; Get a marker and make it point to the current end of the
  1845.           ;; buffer,  If an error occurs, we'll delete everything from
  1846.           ;; the end of this marker onwards.
  1847.           (setq safe-marker (make-marker))
  1848.           (set-marker safe-marker (point-max))
  1849.         
  1850.           (goto-char (point-min))
  1851.           (if (looking-at (regexp-quote "%!PS-Adobe-1.0"))
  1852.           nil
  1853.         (setq needs-begin-file t))
  1854.           (save-excursion
  1855.         (set-buffer ps-source-buffer)
  1856.         (if needs-begin-file (ps-begin-file))
  1857.         (ps-begin-job)
  1858.         (ps-begin-page))
  1859.           (set-buffer ps-source-buffer)
  1860.           (funcall genfunc from to)
  1861.           (ps-end-page)
  1862.         
  1863.           (if (and ps-spool-duplex
  1864.                (= (mod ps-page-count 2) 1))
  1865.           (ps-dummy-page))
  1866.           (ps-flush-output)
  1867.         
  1868.           ;; Back to the PS output buffer to set the page count
  1869.           (set-buffer ps-spool-buffer)
  1870.           (goto-char (point-max))
  1871.           (while (re-search-backward "^/PageCount 0 def$" nil t)
  1872.         (replace-match (format "/PageCount %d def" ps-page-count) t))
  1873.  
  1874.           ;; Setting this variable tells the unwind form that the
  1875.           ;; the postscript was generated without error.
  1876.           (setq completed-safely t))
  1877.  
  1878.       ;; Unwind form: If some bad mojo ocurred while generating
  1879.       ;; postscript, delete all the postscript that was generated.
  1880.       ;; This protects the previously spooled files from getting
  1881.       ;; corrupted.
  1882.       (if (and (markerp safe-marker) (not completed-safely))
  1883.           (progn
  1884.         (set-buffer ps-spool-buffer)
  1885.         (delete-region (marker-position safe-marker) (point-max))))))
  1886.  
  1887.       (if ps-razzle-dazzle
  1888.       (message "Formatting...done")))))
  1889.  
  1890. (defun ps-do-despool (filename)
  1891.   (if (or (not (boundp 'ps-spool-buffer))
  1892.       (not ps-spool-buffer))
  1893.       (message "No spooled PostScript to print")
  1894.     (ps-end-file)
  1895.     (ps-flush-output)
  1896.     (if filename
  1897.     (save-excursion
  1898.       (if ps-razzle-dazzle
  1899.           (message "Saving..."))
  1900.       (set-buffer ps-spool-buffer)
  1901.       (setq filename (expand-file-name filename))
  1902.       (write-region (point-min) (point-max) filename)
  1903.       (if ps-razzle-dazzle
  1904.           (message "Wrote %s" filename)))
  1905.       ;; Else, spool to the printer
  1906.       (if ps-razzle-dazzle
  1907.       (message "Printing..."))
  1908.       (save-excursion
  1909.     (set-buffer ps-spool-buffer)
  1910.     (apply 'call-process-region
  1911.            (point-min) (point-max) ps-lpr-command nil 0 nil
  1912.            ps-lpr-switches))
  1913.       (if ps-razzle-dazzle
  1914.       (message "Printing...done")))
  1915.     (kill-buffer ps-spool-buffer)))
  1916.  
  1917. (defun ps-kill-emacs-check ()
  1918.   (let (ps-buffer)
  1919.     (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
  1920.          (buffer-modified-p ps-buffer))
  1921.     (if (y-or-n-p "Unprinted PostScript waiting; print now? ")
  1922.         (ps-despool)))
  1923.     (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
  1924.          (buffer-modified-p ps-buffer))
  1925.     (if (yes-or-no-p "Unprinted PostScript waiting; exit anyway? ")
  1926.         nil
  1927.       (error "Unprinted PostScript")))))
  1928.  
  1929. (if (fboundp 'add-hook)
  1930.     (add-hook 'kill-emacs-hook 'ps-kill-emacs-check)
  1931.   (if kill-emacs-hook
  1932.       (message "Won't override existing kill-emacs-hook")
  1933.     (setq kill-emacs-hook 'ps-kill-emacs-check)))
  1934.  
  1935. ;;; Sample Setup Code:
  1936.  
  1937. ;; This stuff is for anybody that's brave enough to look this far,
  1938. ;; and able to figure out how to use it.  It isn't really part of ps-
  1939. ;; print, but I'll leave it here in hopes it might be useful:
  1940.  
  1941. ;; WARNING!!! The following code is *sample* code only. Don't use it
  1942. ;; unless you understand what it does!
  1943.  
  1944. (defmacro ps-prsc () (list 'if (list 'eq 'emacs-type ''fsf) [f22] ''f22))
  1945. (defmacro ps-c-prsc () (list 'if (list 'eq 'emacs-type ''fsf) [C-f22]
  1946.                  ''(control f22)))
  1947. (defmacro ps-s-prsc () (list 'if (list 'eq 'emacs-type ''fsf) [S-f22]
  1948.                  ''(shift f22)))
  1949.  
  1950. ;; Look in an article or mail message for the Subject: line.  To be
  1951. ;; placed in ps-left-headers.
  1952. (defun ps-article-subject ()
  1953.   (save-excursion
  1954.     (goto-char (point-min))
  1955.     (if (re-search-forward "^Subject:[ \t]+\\(.*\\)$")
  1956.     (buffer-substring (match-beginning 1) (match-end 1))
  1957.       "Subject ???")))
  1958.  
  1959. ;; Look in an article or mail message for the From: line.  Sorta-kinda
  1960. ;; understands RFC-822 addresses and can pull the real name out where
  1961. ;; it's provided.  To be placed in ps-left-headers.
  1962. (defun ps-article-author ()
  1963.   (save-excursion
  1964.     (goto-char (point-min))
  1965.     (if (re-search-forward "^From:[ \t]+\\(.*\\)$")
  1966.     (let ((fromstring (buffer-substring (match-beginning 1) (match-end 1))))
  1967.       (cond
  1968.  
  1969.        ;; Try first to match addresses that look like
  1970.        ;; thompson@wg2.waii.com (Jim Thompson)
  1971.        ((string-match ".*[ \t]+(\\(.*\\))" fromstring)
  1972.         (substring fromstring (match-beginning 1) (match-end 1)))
  1973.  
  1974.        ;; Next try to match addresses that look like
  1975.        ;; Jim Thompson <thompson@wg2.waii.com>
  1976.        ((string-match "\\(.*\\)[ \t]+<.*>" fromstring)
  1977.         (substring fromstring (match-beginning 1) (match-end 1)))
  1978.  
  1979.        ;; Couldn't find a real name -- show the address instead.
  1980.        (t fromstring)))
  1981.       "From ???")))
  1982.  
  1983. ;; A hook to bind to gnus-Article-prepare-hook.  This will set the ps-
  1984. ;; left-headers specially for gnus articles.  Unfortunately, gnus-
  1985. ;; article-mode-hook is called only once, the first time the *Article*
  1986. ;; buffer enters that mode, so it would only work for the first time
  1987. ;; we ran gnus.  The second time, this hook wouldn't get set up.  The
  1988. ;; only alternative is gnus-article-prepare-hook.
  1989. (defun ps-gnus-article-prepare-hook ()
  1990.   (setq ps-header-lines 3)
  1991.   (setq ps-left-header
  1992.     ;; The left headers will display the article's subject, its
  1993.     ;; author, and the newsgroup it was in.
  1994.     (list 'ps-article-subject 'ps-article-author 'gnus-newsgroup-name)))
  1995.  
  1996. ;; A hook to bind to vm-mode-hook to locally bind prsc and set the ps-
  1997. ;; left-headers specially for mail messages.  This header setup would
  1998. ;; also work, I think, for RMAIL.
  1999. (defun ps-vm-mode-hook ()
  2000.   (local-set-key (ps-prsc) 'ps-vm-print-message-from-summary)
  2001.   (setq ps-header-lines 3)
  2002.   (setq ps-left-header
  2003.     ;; The left headers will display the message's subject, its
  2004.     ;; author, and the name of the folder it was in.
  2005.     (list 'ps-article-subject 'ps-article-author 'buffer-name)))
  2006.  
  2007. ;; Every now and then I forget to switch from the *Summary* buffer to
  2008. ;; the *Article* before hitting prsc, and a nicely formatted list of
  2009. ;; article subjects shows up at the printer.  This function, bound to
  2010. ;; prsc for the gnus *Summary* buffer means I don't have to switch
  2011. ;; buffers first.
  2012. (defun ps-gnus-print-article-from-summary ()
  2013.   (interactive)
  2014.   (if (get-buffer "*Article*")
  2015.       (save-excursion
  2016.     (set-buffer "*Article*")
  2017.     (ps-spool-buffer-with-faces))))
  2018.  
  2019. ;; See ps-gnus-print-article-from-summary.  This function does the
  2020. ;; same thing for vm.
  2021. (defun ps-vm-print-message-from-summary ()
  2022.   (interactive)
  2023.   (if vm-mail-buffer
  2024.       (save-excursion
  2025.     (set-buffer vm-mail-buffer)
  2026.     (ps-spool-buffer-with-faces))))
  2027.  
  2028. ;; A hook to bind to bind to gnus-summary-setup-buffer to locally bind
  2029. ;; prsc.
  2030. (defun ps-gnus-summary-setup ()
  2031.   (local-set-key (ps-prsc) 'ps-gnus-print-article-from-summary))
  2032.  
  2033. ;; Look in an article or mail message for the Subject: line.  To be
  2034. ;; placed in ps-left-headers.
  2035. (defun ps-info-file ()
  2036.   (save-excursion
  2037.     (goto-char (point-min))
  2038.     (if (re-search-forward "File:[ \t]+\\([^, \t\n]*\\)")
  2039.     (buffer-substring (match-beginning 1) (match-end 1))
  2040.       "File ???")))
  2041.  
  2042. ;; Look in an article or mail message for the Subject: line.  To be
  2043. ;; placed in ps-left-headers.
  2044. (defun ps-info-node ()
  2045.   (save-excursion
  2046.     (goto-char (point-min))
  2047.     (if (re-search-forward "Node:[ \t]+\\([^,\t\n]*\\)")
  2048.     (buffer-substring (match-beginning 1) (match-end 1))
  2049.       "Node ???")))
  2050.  
  2051. (defun ps-info-mode-hook ()
  2052.   (setq ps-left-header
  2053.     ;; The left headers will display the node name and file name.
  2054.     (list 'ps-info-node 'ps-info-file)))
  2055.  
  2056. ;; WARNING! The following function is a *sample* only, and is *not*
  2057. ;; meant to be used as a whole unless you understand what the effects
  2058. ;; will be!  (In fact, this is a copy if my setup for ps-print -- I'd
  2059. ;; be very surprised if it was useful to *anybody*, without
  2060. ;; modification.)
  2061.  
  2062. (defun ps-jts-ps-setup ()
  2063.   (global-set-key (ps-prsc) 'ps-spool-buffer-with-faces) ;f22 is prsc
  2064.   (global-set-key (ps-s-prsc) 'ps-spool-region-with-faces)
  2065.   (global-set-key (ps-c-prsc) 'ps-despool)
  2066.   (add-hook 'gnus-article-prepare-hook 'ps-gnus-article-prepare-hook)
  2067.   (add-hook 'gnus-summary-mode-hook 'ps-gnus-summary-setup)
  2068.   (add-hook 'vm-mode-hook 'ps-vm-mode-hook)
  2069.   (add-hook 'vm-mode-hooks 'ps-vm-mode-hook)
  2070.   (add-hook 'Info-mode-hook 'ps-info-mode-hook)
  2071.   (setq ps-spool-duplex t)
  2072.   (setq ps-print-color-p nil)
  2073.   (setq ps-lpr-command "lpr")
  2074.   (setq ps-lpr-switches '("-Jjct,duplex_long")))
  2075.  
  2076. (provide 'ps-print)
  2077.  
  2078. ;;; ps-print.el ends here
  2079.