(xmenu_show): Don't look in menubar for core.height if no menu bar.
[bpt/emacs.git] / lisp / ps-print.el
1 ;; Jim's Pretty-Good PostScript Generator for Emacs 19 (ps-print).
2 ;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3
4 ;; Author: James C. Thompson <thompson@wg2.waii.com>
5 ;; Keywords: faces, postscript, printing
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to
21 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 ;; Acknowledgements
24 ;; ----------------
25 ;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
26 ;; the Emacs 19 port.
27 ;;
28 ;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
29 ;; for adding underline support and title code. (Titling will appear
30 ;; in the next release.)
31 ;;
32 ;; Thanks to Heiko Muenkel, muenkel@tnt.uni-hannover.de, for showing
33 ;; me how to handle ISO-8859/1 characters.
34 ;;
35 ;; Code to handle ISO-8859/1 characters borrowed from the mp prologue
36 ;; file mp.pro.ps, used with permission of Rich Burridge of Sun
37 ;; Microsystems (Rich.Burridge@eng.sun.com).
38
39 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40 ;;
41 ;; About ps-print:
42 ;; --------------
43 ;; This package provides printing of Emacs buffers on PostScript
44 ;; printers; the buffer's bold and italic text attributes are
45 ;; preserved in the printer output. Ps-print is intended for use with
46 ;; Emacs 19 (Lucid or FSF) and a fontifying package such as font-lock
47 ;; or hilit.
48 ;;
49 ;; Installing ps-print:
50 ;; -------------------
51 ;; Place ps-print somewhere in your load-path and byte-compile it.
52 ;; Load ps-print with (require 'ps-print).
53 ;;
54 ;; Using ps-print:
55 ;; --------------
56 ;; The variables ps-bold-faces and ps-italic-faces *must* contain
57 ;; lists of the faces that you wish to print in bold or italic font.
58 ;; These variables already contain some default values, but most users
59 ;; will probably have to add some of their own. To add a face to one
60 ;; of these lists, put code something like the following into your
61 ;; .emacs startup file:
62 ;;
63 ;; (setq ps-bold-faces (cons 'my-bold-face ps-bold-faces))
64 ;;
65 ;; Ps-print's printer interface is governed by the variables ps-lpr-
66 ;; command and ps-lpr-switches; these are analogous to the variables
67 ;; lpr-command and lpr-switches in the Emacs lpr package.
68 ;;
69 ;; To use ps-print, invoke the command ps-print-buffer-with-faces.
70 ;; This will generate a PostScript image of the current buffer and
71 ;; send it to the printer. Precede this command with a numeric prefix
72 ;; (C-u), and the PostScript output will be saved in a file; you will
73 ;; be prompted for a filename. Also see the functions ps-print-
74 ;; buffer, ps-print-region, and ps-print-region-with-faces.
75 ;;
76 ;; I recommend binding ps-print-buffer-with-faces to a key sequence;
77 ;; on a Sun 4 keyboard, for example, you can bind to the PrSc key (aka
78 ;; r22):
79 ;;
80 ;; (global-set-key 'f22 'ps-print-buffer-with-faces)
81 ;; (global-set-key '(shift f22) 'ps-print-region-with-faces)
82 ;;
83 ;; Or, as I now prefer, you can also bind the ps-spool- functions to
84 ;; keys; here's my bindings:
85 ;;
86 ;; (global-set-key 'f22 'ps-spool-buffer-with-faces)
87 ;; (global-set-key '(shift f22) 'ps-spool-region-with-faces)
88 ;; (global-set-key '(control f22) 'ps-despool)
89 ;;
90 ;; Using ps-print with other Emacses:
91 ;; ---------------------------------
92 ;; Although it was intended for use with Emacs 19, ps-print will also work
93 ;; with Emacs version 18; you won't get fancy fontified output, but it
94 ;; should work.
95 ;;
96 ;; A few words about support:
97 ;; -------------------------
98 ;; Despite its appearance, with comment blocks, usage instructions, and
99 ;; documentation strings, ps-print is not a supported package. That's all
100 ;; a masquerade. Ps-print is something I threw together in my spare time--
101 ;; an evening here, a Saturday there--to make my printouts look like my
102 ;; Emacs buffers. It works, but is not complete.
103 ;;
104 ;; Unfortunately, supporting elisp code is not my job and, now that I have
105 ;; what I need out of ps-print, additional support is going to be up to
106 ;; you, the user. But that's the spirit of Emacs, isn't it? I call on
107 ;; all who use this package to help in developing it further. If you
108 ;; notice a bug, fix it and send me the patches. If you add a feature,
109 ;; again, send me the patches. I will collect all such contributions and
110 ;; periodically post the updates to the appropriate places.
111 ;;
112 ;; A few more words about support:
113 ;; ------------------------------
114 ;; The response to my call for public support of ps-print has been
115 ;; terrific. With the exception of the spooling mechanism, all the new
116 ;; features in this version of ps-print were contributed by users. I have
117 ;; some contributed code for printing headers that I'll add to the next
118 ;; release of ps-print, but there are still other features that users can
119 ;; write. See the "Features to Add" list a little further on, and keep
120 ;; that elisp rolling in.
121 ;;
122 ;; Please send all bug fixes and enhancements to me, thompson@wg2.waii.com.
123 ;;
124 ;; New in version 1.5
125 ;; ------------------
126 ;; Support for Emacs 19. Works with both overlays and text
127 ;; properties.
128 ;;
129 ;; Underlining.
130 ;;
131 ;; Local spooling; see function ps-spool-buffer.
132 ;;
133 ;; Support for ISO8859-1 character set.
134 ;;
135 ;; Page breaks are now handled correctly.
136 ;;
137 ;; Percentages reported while formatting are now correct.
138 ;;
139 ;; Known bugs and limitations of ps-print:
140 ;; --------------------------------------
141 ;; Slow. (Byte-compiling helps.)
142 ;;
143 ;; The PostScript needs review/cleanup/enhancing by a PS expert.
144 ;;
145 ;; ASCII Control characters other than tab, linefeed and pagefeed are
146 ;; not handled.
147 ;;
148 ;; The mechanism for determining whether a stretch of characters
149 ;; should be printed bold, italic, or plain is crude and extremely
150 ;; limited.
151 ;;
152 ;; Faces are always treated as opaque.
153 ;;
154 ;; Font names are hardcoded.
155 ;;
156 ;; Epoch not fully supported.
157 ;;
158 ;; Tested with only one PostScript printer.
159 ;;
160 ;; Features to add:
161 ;; ---------------
162 ;; Line numbers.
163 ;;
164 ;; Simple headers with date, filename, and page numbers.
165 ;;
166 ;; Gaudy headers a`la enscript and mp.
167 ;;
168 ;; 2-up and 4-up capability.
169 ;;
170 ;; Wide-print capability.
171 ;;
172
173 ;;; Code:
174
175 (defconst ps-print-version (substring "$Revision: 1.5 $" 11 -2)
176 "$Id: ps-print.el,v 1.5 1994/04/22 13:25:18 jct Exp $
177
178 Please send all bug fixes and enhancements to Jim Thompson,
179 thompson@wg2.waii.com.")
180
181 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182 (defvar ps-lpr-command (if (memq system-type
183 '(usg-unix-v hpux silicon-graphics-unix))
184 "lp" "lpr")
185 "The shell command for printing a PostScript file.")
186
187 (defvar ps-lpr-switches nil
188 "A list of extra switches to pass to ps-lpr-command.")
189
190 (defvar ps-bold-faces
191 '(bold
192 bold-italic
193 font-lock-function-name-face
194 message-headers
195 )
196 "A list of the faces that should be printed italic.")
197
198 (defvar ps-italic-faces
199 '(italic
200 bold-italic
201 font-lock-function-name-face
202 font-lock-string-face
203 font-lock-comment-face
204 message-header-contents
205 message-highlighted-header-contents
206 message-cited-text
207 )
208 "A list of the faces that should be printed bold.")
209
210 (defvar ps-underline-faces
211 '(underline
212 font-lock-string-face)
213 "A list of the faces that should be printed underline.")
214
215 (defvar ps-razzle-dazzle t
216 "Non-nil means report progress while formatting buffer")
217
218 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
219
220 (defun ps-print-buffer (&optional filename)
221
222 "Generate and print a PostScript image of the buffer.
223
224 When called with a numeric prefix argument (C-u), prompt the user for
225 the name of a file to save the PostScript image in, instead of sending
226 it to the printer.
227
228 More specifically, the FILENAME argument is treated as follows: if it
229 is nil, send the image to the printer. If FILENAME is a string, save
230 the PostScript image in a file with that name. If FILENAME is a
231 number, prompt the user for the name of the file to save in.
232
233 The image is rendered using the PostScript font Courier.
234
235 See also: ps-print-buffer-with-faces
236 ps-spool-buffer
237 ps-spool-buffer-with-faces"
238
239 (interactive "P")
240 (setq filename (ps-preprint filename))
241 (ps-generate (current-buffer) (point-min) (point-max)
242 'ps-generate-postscript)
243 (ps-do-despool filename))
244
245
246 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
247
248 (defun ps-print-buffer-with-faces (&optional filename)
249
250 "Generate and print a PostScript image of the buffer.
251
252 This function works like ps-print-buffer, with the additional benefit
253 that any bold/italic formatting information present in the buffer
254 (contained in extents and faces) will be retained in the PostScript
255 image. In other words, WYSIAWYG -- What You See Is (Almost) What You
256 Get.
257
258 Ps-print uses three lists to determine which faces should be printed
259 bold, italic, and/or underlined; the lists are named ps-bold-faces, ps-
260 italic-faces, and ps-underline-faces. A given face should appear on as
261 many lists as are appropriate; for example, face bold-italic is in both
262 the lists ps-bold-faces and ps-italic-faces. The lists are pre-built
263 with the standard bold, italic, and bold-italic faces, with font-lock's
264 faces, and with the faces used by gnus and rmail.
265
266 The image is rendered using the PostScript fonts Courier, Courier-Bold,
267 Courier-Oblique, and Courier-BoldOblique.
268
269 See also: ps-print-buffer
270 ps-spool-buffer
271 ps-spool-buffer-with-faces."
272
273 (interactive "P")
274 (setq filename (ps-preprint filename))
275 (ps-generate (current-buffer) (point-min) (point-max)
276 'ps-generate-postscript-with-faces)
277 (ps-do-despool filename))
278
279 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
280
281 (defun ps-print-region (from to &optional filename)
282
283 "Generate and print a PostScript image of the region.
284
285 When called with a numeric prefix argument (C-u), prompt the user for
286 the name of a file to save the PostScript image in, instead of sending
287 it to the printer.
288
289 This function is essentially the same as ps-print-buffer except that it
290 prints just a region, and not the entire buffer. For more information,
291 see the function ps-print-buffer.
292
293 See also: ps-print-region-with-faces
294 ps-spool-region
295 ps-spool-region-with-faces"
296
297 (interactive "r\nP")
298 (setq filename (ps-preprint filename))
299 (ps-generate (current-buffer) from to
300 'ps-generate-postscript)
301 (ps-do-despool filename))
302
303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
304
305 (defun ps-print-region-with-faces (from to &optional filename)
306
307 "Generate and print a PostScript image of the region.
308
309 This function is essentially the same as ps-print-buffer except that it
310 prints just a region, and not the entire buffer. See the functions
311 ps-print-region and ps-print-buffer-with-faces for
312 more information.
313
314 See also: ps-print-region
315 ps-spool-region
316 ps-spool-region-with-faces"
317
318 (interactive "r\nP")
319 (setq filename (ps-preprint filename))
320 (ps-generate (current-buffer) from to
321 'ps-generate-postscript-with-faces)
322 (ps-do-despool filename))
323
324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
325
326 (defun ps-spool-buffer ()
327
328 "Generate and spool a PostScript image of the buffer.
329
330 This function is essentially the same as function ps-print-buffer
331 except that the PostScript image is saved in a local buffer to be sent
332 to the printer later.
333
334 Each time you call one of the ps-spool- functions, the generated
335 PostScript is appended to a buffer named *PostScript*; to send the
336 spooled PostScript to the printer, or save it to a file, use the command
337 ps-despool.
338
339 If the variable ps-spool-duplex is non-nil, then the spooled PostScript
340 is padded with blank pages, when needed, so that each printed buffer
341 will start on a front page when printed on a duplex printer (a printer
342 that prints on both sides on the paper). Users of non-duplex printers
343 will want to leave ps-spool-duplex nil.
344
345 The spooling mechanism was designed for printing lots of small files
346 (mail messages or netnews articles) to save paper that would otherwise
347 be wasted on banner pages, and to make it easier to find your output at
348 the printer (it's easier to pick up one 50-page printout than to find 50
349 single-page printouts).
350
351 Ps-print has a hook in the kill-emacs-hook list so that you won't
352 accidently quit from Emacs while you have unprinted PostScript waiting
353 in the spool buffer. If you do attempt to exit with spooled PostScript,
354 you'll be asked if you want to print it, and if you decline, you'll be
355 asked to confirm the exit; this is modeled on the confirmation that
356 Emacs uses for modified buffers.
357
358 See also: ps-despool
359 ps-print-buffer
360 ps-print-buffer-with-faces
361 ps-spool-buffer-with-faces"
362
363 (interactive)
364 (ps-generate (current-buffer) (point-min) (point-max)
365 'ps-generate-postscript))
366
367 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
368
369 (defun ps-spool-buffer-with-faces ()
370
371 "Generate and spool PostScript image of the buffer.
372
373 This function is essentially the same as function ps-print-buffer-with-
374 faces except that the PostScript image is saved in a local buffer to be
375 sent to the printer later.
376
377 Use the function ps-despool to send the spooled images to the printer.
378 See the function ps-spool-buffer for a description of the spooling
379 mechanism.
380
381 See also: ps-despool
382 ps-spool-buffer
383 ps-print-buffer
384 ps-print-buffer-with-faces"
385
386 (interactive)
387 (ps-generate (current-buffer) (point-min) (point-max)
388 'ps-generate-postscript-with-faces))
389
390 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
391
392 (defun ps-spool-region (from to)
393
394 "Generate PostScript image of the region and spool locally.
395
396 This function is essentially the same as function ps-print-region except
397 that the PostScript image is saved in a local buffer to be sent to the
398 printer later.
399
400 Use the function ps-despool to send the spooled images to the printer.
401 See the function ps-spool-buffer for a description of the spooling
402 mechanism.
403
404 See also: ps-despool
405 ps-spool-buffer
406 ps-print-buffer
407 ps-print-buffer-with-faces"
408
409 (interactive "r")
410 (ps-generate (current-buffer) from to
411 'ps-generate-postscript))
412
413 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
414
415 (defun ps-spool-region-with-faces (from to)
416
417 "Generate PostScript image of the region and spool locally.
418
419 This function is essentially the same as function ps-print-region-with-
420 faces except that the PostScript image is saved in a local buffer to be
421 sent to the printer later.
422
423 Use the function ps-despool to send the spooled images to the printer.
424 See the function ps-spool-buffer for a description of the spooling
425 mechanism.
426
427 See also: ps-despool
428 ps-spool-buffer
429 ps-print-buffer
430 ps-print-buffer-with-faces"
431
432 (interactive "r")
433 (ps-generate (current-buffer) from to
434 'ps-generate-postscript-with-faces))
435
436 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
437
438 (defvar ps-spool-duplex nil ; Not many people have duplex
439 ; printers, so default to nil.
440 "*Non-nil indicates spooling is for a two-sided printer.
441 For a duplex printer, the ps-spool functions will insert blank pages
442 as needed between print jobs so that the next buffer printed will
443 start on the right page.")
444
445 (defun ps-despool (&optional filename)
446 "Send the spooled PostScript to the printer.
447
448 When called with a numeric prefix argument (C-u), prompt the user for
449 the name of a file to save the spooled PostScript in, instead of sending
450 it to the printer.
451
452 More specifically, the FILENAME argument is treated as follows: if it
453 is nil, send the image to the printer. If FILENAME is a string, save
454 the PostScript image in a file with that name. If FILENAME is a
455 number, prompt the user for the name of the file to save in."
456
457 (interactive "P")
458
459 ;; If argument FILENAME is nil, send the image to the printer; if
460 ;; FILENAME is a string, save the PostScript image in that filename;
461 ;; if FILENAME is a number, prompt the user for the name of the file
462 ;; to save in.
463
464 (setq filename (ps-preprint filename))
465 (ps-do-despool filename))
466
467 ;; Here end the definitions that users need to know about; proceed
468 ;; further at your own risk!
469 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
470
471 (defun ps-kill-emacs-check ()
472 (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
473 (buffer-modified-p ps-buffer))
474 (if (y-or-n-p "Unprinted PostScript waiting... print now? ")
475 (ps-despool)))
476
477 (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
478 (buffer-modified-p ps-buffer))
479 (if (yes-or-no-p "Unprinted PostScript waiting; exit anyway? ")
480 nil
481 (error "Unprinted PostScript"))))
482
483 (if (fboundp 'add-hook)
484 (add-hook 'kill-emacs-hook 'ps-kill-emacs-check)
485 (if kill-emacs-hook
486 (message "Won't override existing kill-emacs-hook.")
487 (setq kill-emacs-hook 'ps-kill-emacs-check)))
488
489 (defun ps-preprint (&optional filename)
490 (if (and filename
491 (or (numberp filename)
492 (listp filename)))
493 (setq filename
494 (let* ((name (concat (buffer-name) ".ps"))
495 (prompt (format "Save PostScript to file: (default %s) "
496 name)))
497 (read-file-name prompt default-directory
498 name nil)))))
499
500 (defvar ps-spool-buffer-name "*PostScript*")
501
502 (defvar ps-col 0)
503 (defvar ps-row 0)
504 (defvar ps-xpos 0)
505 (defvar ps-ypos 0)
506
507 (defvar ps-chars-per-line 80)
508 (defvar ps-lines-per-page 66)
509
510 (defvar ps-page-start-ypos 745)
511 (defvar ps-line-start-xpos 40)
512
513 (defvar ps-char-xpos-inc 6)
514 (defvar ps-line-ypos-inc 11)
515
516 (defvar ps-current-font 0)
517
518 (defvar ps-multiple nil)
519 (defvar ps-virtual-page-number 0)
520
521 (defun ps-begin-file ()
522 (save-excursion
523 (set-buffer ps-output-buffer)
524 (goto-char (point-min))
525 (setq ps-real-page-number 1)
526 (insert
527 "%!PS-Adobe-1.0
528
529 /S /show load def
530 /M /moveto load def
531 /L { gsave newpath 3 1 roll 1 sub M 0 rlineto closepath stroke grestore } def
532
533 /F{$fd exch get setfont}def
534
535 /StartPage{/svpg save def}def
536 /EndPage{svpg restore showpage}def
537
538 /SetUpFonts
539 {dup/$fd exch array def{findfont exch scalefont $fd 3 1 roll put}repeat}def
540
541 % Define /ISOLatin1Encoding only if it's not already there.
542 /ISOLatin1Encoding where { pop save true }{ false } ifelse
543 /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus
544 StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute
545 /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring
546 /cedilla /.notdef /hungarumlaut /ogonek /caron /space /exclamdown /cent
547 /sterling /currency /yen /brokenbar /section /dieresis /copyright
548 /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron
549 /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph
550 /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright
551 /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute
552 /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute
553 /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth
554 /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply
555 /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn
556 /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae
557 /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute
558 /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex
559 /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex
560 /udieresis /yacute /thorn /ydieresis ] def
561 { restore } if
562
563 /reencodeISO { %def
564 findfont dup length dict begin
565 { 1 index /FID ne { def }{ pop pop } ifelse } forall
566 /Encoding ISOLatin1Encoding def
567 currentdict end definefont pop
568 } bind def
569
570 /CourierISO /Courier reencodeISO
571 /Courier-ObliqueISO /Courier-Oblique reencodeISO
572 /Courier-BoldISO /Courier-Bold reencodeISO
573 /Courier-BoldObliqueISO /Courier-BoldOblique reencodeISO
574
575 3 10 /Courier-BoldObliqueISO
576 2 10 /Courier-ObliqueISO
577 1 10 /Courier-BoldISO
578 0 10 /CourierISO
579 4 SetUpFonts
580
581 .4 setlinewidth
582 ")))
583
584 (defun ps-end-file ()
585 )
586
587 (defun ps-next-page ()
588 (ps-end-page)
589 (ps-begin-page)
590 (ps-set-font ps-current-font)
591 (ps-init-page))
592
593 (defun ps-top-of-page () (ps-next-page))
594
595 (defun ps-init-page ()
596 (setq ps-row 0)
597 (setq ps-col 0)
598 (setq ps-ypos ps-page-start-ypos)
599 (setq ps-xpos ps-line-start-xpos)
600 (ps-set-font))
601
602 (defun ps-begin-page ()
603 (save-excursion
604 (set-buffer ps-output-buffer)
605 (goto-char (point-max))
606 (insert (format "%%%%Page: ? %d\n" ps-real-page-number))
607 (setq ps-real-page-number (+ 1 ps-real-page-number))
608 (insert "StartPage\n0.4 setlinewidth\n")))
609
610 (defun ps-end-page ()
611 (save-excursion
612 (set-buffer ps-output-buffer)
613 (goto-char (point-max))
614 (insert "EndPage\n")))
615
616 (defun ps-next-line ()
617 (setq ps-row (+ ps-row 1))
618 (if (>= ps-row ps-lines-per-page)
619 (ps-next-page)
620 (setq ps-col 0)
621 (setq ps-xpos ps-line-start-xpos)
622 (setq ps-ypos (- ps-ypos ps-line-ypos-inc))))
623
624 (defun ps-continue-line ()
625 (ps-next-line))
626
627 (defvar ps-source-buffer nil)
628 (defvar ps-output-buffer nil)
629
630 (defun ps-basic-plot-string (from to &optional underline-p)
631 (setq text (buffer-substring from to))
632 (save-excursion
633 (set-buffer ps-output-buffer)
634 (goto-char (point-max))
635 (setq count (- to from))
636
637 (if underline-p
638 (insert (format "%d %d %d L\n" ps-xpos ps-ypos
639 (* count ps-char-xpos-inc))))
640
641 (insert (format "%d %d M (" ps-xpos ps-ypos))
642 (save-excursion
643 (insert text))
644
645 (while (re-search-forward "[()\\]" nil t)
646 (save-excursion
647 (forward-char -1)
648 (insert "\\")))
649
650 (end-of-line)
651 (insert ") S\n")
652
653 (setq ps-xpos (+ ps-xpos (* count ps-char-xpos-inc)))))
654
655 (defun ps-basic-plot-whitespace (from to underline-p)
656 (setq count (- to from))
657 (setq ps-xpos (+ ps-xpos (* count ps-char-xpos-inc))))
658
659 (defun ps-plot (plotfunc from to &optional underline-p)
660
661 (while (< from to)
662 (setq count (- to from))
663 ;; Test to see whether this region will fit on the current line
664 (if (<= (+ ps-col count) ps-chars-per-line)
665 (progn
666 ;; It fits; plot it.
667 (funcall plotfunc from to underline-p)
668 (setq from to))
669
670 ;; It needs to be wrapped; plot part of it, then loop
671 (setq chars-that-will-fit (- ps-chars-per-line ps-col))
672 (funcall plotfunc from (+ from chars-that-will-fit))
673
674 (ps-continue-line)
675
676 (setq from (+ from chars-that-will-fit))))
677
678 (if ps-razzle-dazzle
679 (let* ((q-todo (- (point-max) (point-min)))
680 (q-done (- to (point-min)))
681 (chunkfrac (/ q-todo 8))
682 (chunksize (if (> chunkfrac 10000) 10000 chunkfrac)))
683 (if (> (- q-done ps-razchunk) chunksize)
684 (progn
685 (setq ps-razchunk q-done)
686 (setq foo
687 (if (< q-todo 100)
688 (* (/ q-done q-todo) 100)
689 (setq basis (/ q-todo 100))
690 (/ q-done basis)))
691
692 (message "Formatting... %d%%" foo))))))
693
694 (defun ps-set-font (&optional font)
695 (save-excursion
696 (set-buffer ps-output-buffer)
697 (goto-char (point-max))
698 (insert (format "%d F\n" (if font font ps-current-font))))
699 (if font
700 (setq ps-current-font font)))
701
702 (defun ps-plot-region (from to font &optional underline-p)
703
704 (ps-set-font font)
705
706 (save-excursion
707 (goto-char from)
708 (while (< from to)
709 (if (re-search-forward "[\t\n\014]" to t)
710 (let ((match (char-after (match-beginning 0))))
711 (cond
712 ((= match ?\n)
713 (ps-plot 'ps-basic-plot-string from (- (point) 1) underline-p)
714 (ps-next-line))
715
716 ((= match ?\t)
717 (ps-plot 'ps-basic-plot-string from (- (point) 1) underline-p)
718 (setq linestart (save-excursion (beginning-of-line) (point)))
719 (forward-char -1)
720 (setq from (+ linestart (current-column)))
721 (if (re-search-forward "[ \t]+" to t)
722 (ps-plot 'ps-basic-plot-whitespace from
723 (+ linestart (current-column)))))
724
725 ((= match ?\014)
726 (ps-plot 'ps-basic-plot-string from (- (point) 1) underline-p)
727 (ps-top-of-page)))
728 (setq from (point)))
729
730 (ps-plot 'ps-basic-plot-string from to underline-p)
731 (setq from to)))))
732
733 (defun ps-format-buffer ()
734 (interactive)
735
736 (setq ps-source-buffer (current-buffer))
737 (setq ps-output-buffer (get-buffer-create "%PostScript%"))
738
739 (save-excursion
740 (set-buffer ps-output-buffer)
741 (delete-region (point-max) (point-min)))
742
743 (ps-begin-file)
744 (ps-begin-page)
745 (ps-init-page)
746
747 (ps-plot-region (point-min) (point-max) 0)
748
749 (ps-end-page)
750 (ps-end-file)
751 )
752
753 (defun ps-mapper (extent list)
754 (nconc list (list (list (extent-start-position extent) 'push extent)
755 (list (extent-end-position extent) 'pull extent)))
756 nil)
757
758 (defun ps-sorter (a b)
759 (< (car a) (car b)))
760
761 (defun ps-extent-sorter (a b)
762 (< (extent-priority a) (extent-priority b)))
763
764 (defun overlay-priority (p)
765 (if (setq priority (overlay-get p 'priority)) priority 0))
766
767 (defun ps-overlay-sorter (a b)
768 (> (overlay-priority a) (overlay-priority b)))
769
770 (defun ps-plot-with-face (from to face)
771
772 (setq bold-p (memq face ps-bold-faces))
773 (setq italic-p (memq face ps-italic-faces))
774 (setq underline-p (memq face ps-underline-faces))
775
776 (cond
777 ((and bold-p italic-p)
778 (ps-plot-region from to 3 underline-p))
779 (italic-p
780 (ps-plot-region from to 2 underline-p))
781 (bold-p
782 (ps-plot-region from to 1 underline-p))
783 (t
784 (ps-plot-region from to 0 underline-p))))
785
786
787 (defun ps-generate-postscript-with-faces (from to)
788
789 (save-restriction
790 (narrow-to-region from to)
791 (setq face 'default)
792
793 (cond ((string-match "Lucid" emacs-version)
794 ;; Build the list of extents...
795 (let ((a (cons 'dummy nil)))
796 (map-extents 'ps-mapper nil from to a)
797 (setq a (cdr a))
798 (setq a (sort a 'ps-sorter))
799
800 (setq extent-list nil)
801
802 ;; Loop through the extents...
803 (while a
804 (setq record (car a))
805
806 (setq position (car record))
807 (setq record (cdr record))
808
809 (setq type (car record))
810 (setq record (cdr record))
811
812 (setq extent (car record))
813
814 ;; Plot up to this record.
815 (ps-plot-with-face from position face)
816
817 (cond
818 ((eq type 'push)
819 (setq extent-list (sort (cons extent extent-list)
820 'ps-extent-sorter)))
821
822 ((eq type 'pull)
823 (setq extent-list (sort (delq extent extent-list)
824 'ps-extent-sorter))))
825
826 (setq face
827 (if extent-list
828 (extent-face (car extent-list))
829 'default))
830
831 (setq from position)
832 (setq a (cdr a)))))
833
834 ((string-match "^19" emacs-version)
835
836 (while (< from to)
837
838 (setq prop-position
839 (if (setq p (next-property-change from))
840 (if (> p to) to p)
841 to))
842
843 (setq over-position
844 (if (setq p (next-overlay-change from))
845 (if (> p to) to p)
846 to))
847
848 (setq position
849 (if (< prop-position over-position)
850 prop-position
851 over-position))
852
853 (setq face
854 (if (setq f (get-text-property from 'face)) f 'default))
855
856 (if (setq overlays (overlays-at from))
857 (progn
858 (setq overlays (sort overlays 'ps-overlay-sorter))
859 (while overlays
860 (if (setq face (overlay-get (car overlays) 'face))
861 (setq overlays nil)
862 (setq overlays (cdr overlays))))))
863
864 ;; Plot up to this record.
865 (ps-plot-with-face from position face)
866
867 (setq from position))))
868
869 (ps-plot-with-face from to face)))
870
871 (defun ps-generate-postscript (from to)
872 (ps-plot-region from to 0))
873
874 (defun ps-generate (buffer from to genfunc)
875
876 (save-restriction
877 (narrow-to-region from to)
878 (if ps-razzle-dazzle
879 (message "Formatting... %d%%" (setq ps-razchunk 0)))
880
881 (set-buffer buffer)
882 (setq ps-source-buffer buffer)
883 (setq ps-output-buffer (get-buffer-create ps-spool-buffer-name))
884
885 (unwind-protect
886 (progn
887
888 (set-buffer ps-output-buffer)
889 (goto-char (point-min))
890 (if (looking-at (regexp-quote "%!PS-Adobe-1.0"))
891 (ps-set-font ps-current-font)
892 (ps-begin-file))
893 (ps-begin-page)
894 (ps-init-page)
895
896 (goto-char (point-max))
897 (if (and ps-spool-duplex
898 (re-search-backward "^%%Page")
899 (looking-at "^%%Page.*[24680]$"))
900 (ps-next-page))
901
902 (set-buffer ps-source-buffer)
903 (funcall genfunc from to)
904
905 (ps-end-page)))
906
907 (if ps-razzle-dazzle
908 (message "Formatting... Done."))))
909
910 (defun ps-do-despool (filename)
911
912 (if (or (not (boundp 'ps-output-buffer))
913 (not ps-output-buffer))
914 (message "No spooled PostScript to print.")
915
916 (ps-end-file)
917
918 (if filename
919 (save-excursion
920 (if ps-razzle-dazzle
921 (message "Saving..."))
922
923 (set-buffer ps-output-buffer)
924 (setq filename (expand-file-name filename))
925 (write-region (point-min) (point-max) filename)
926
927 (if ps-razzle-dazzle
928 (message "Wrote %s" filename)))
929
930 ;; Else, spool to the printer
931 (if ps-razzle-dazzle
932 (message "Printing..."))
933
934 (save-excursion
935 (set-buffer ps-output-buffer)
936 (apply 'call-process-region
937 (point-min) (point-max) ps-lpr-command nil 0 nil
938 ps-lpr-switches))
939
940 (if ps-razzle-dazzle
941 (message "Printing... Done.")))
942
943 (kill-buffer ps-output-buffer)))
944
945 (defun ps-testpattern ()
946 (setq foo 1)
947 (while (< foo 60)
948 (insert "|" (make-string foo ?\ ) (format "%d\n" foo))
949 (setq foo (+ 1 foo))))
950
951 (defun pts (stuff)
952 (save-excursion
953 (set-buffer "*scratch*")
954 (goto-char (point-max))
955 (insert "---------------------------------\n"
956 (symbol-name stuff) ":\n"
957 (prin1-to-string (symbol-value stuff))
958 "\n")))
959
960 (provide 'ps-print)
961
962 ;; ps-print.el ends here