1 ;;; bbdb-print.el -- for printing BBDB databases using TeX.
3 ;;; Authors: Boris Goldowsky <boris@cs.rochester.edu>
4 ;;; Dirk Grunwald <grunwald@cs.colorado.edu>
5 ;;; Luigi Semenzato <luigi@paris.cs.berkeley.edu>
6 ;;; Copyright (C) 1993 Boris Goldowsky
7 ;;; Version: 3.92; 4Jan95
9 ;;; This file is part of the bbdb-print extensions to the Insidious
10 ;;; Big Brother Database, which is for use with GNU Emacs.
12 ;;; The Insidious Big Brother Database is free software; you can redistribute
13 ;;; it and/or modify it under the terms of the GNU General Public License as
14 ;;; published by the Free Software Foundation; either version 1, or (at your
15 ;;; option) any later version.
17 ;;; BBDB is distributed in the hope that it will be useful, but WITHOUT ANY
18 ;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 ;;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with GNU Emacs; see the file COPYING. If not, write to
24 ;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
28 ;;; In the *BBDB* buffer, type P to convert the listing to TeX
29 ;;; format. It will prompt you for a filename. Then run TeX on that
30 ;;; file and print it out.
32 ;;; Bbdb-print understands one new bbdb field: tex-name. If it
33 ;;; exists, this will be used for the printed listing instead of the
34 ;;; name field of that record. This is designed for entering names
35 ;;; with lots of accents that would mess up mailers, or when for any
36 ;;; reason you want the printed version of the name to be different
37 ;;; from the version that appears on outgoing mail and in the *BBDB*
38 ;;; buffer. You may want to add tex-name to a omit list of the variable
39 ;;; bbdb-display-layout-alist so you only see it in the printout.
40 ;;; tex-name is exempted from the usual special-character quoting done by
41 ;;; bbdb-print; it is used verbatim.
43 ;;; Not all fields or records need be printed. To not print a certain
44 ;;; field, add it to `bbdb-print-omit-fields' (which see). If after eliding
45 ;;; fields a record contains no interesting information, it will not
46 ;;; be printed at all; the variable `bbdb-print-require' determines
47 ;;; what is meant by "interesting" information. You can also restrict
48 ;;; printing to just the records currently in the *BBDB* buffer by
49 ;;; using *P instead of P.
51 ;;; There are various options for the way the formatting is done; most
52 ;;; are controlled by the variable bbdb-print-alist. See its
53 ;;; documentation for the allowed options.
56 ;; $Id: bbdb-print.el,v 1.7 2007-02-23 20:24:08 fenk Exp $
61 ;;; Put this file somewhere on your load-path. Put bbdb-print.tex and
62 ;;; bbdb-cols.tex somewhere on your TEXINPUTS path, or put absolute
63 ;;; pathnames into the variable bbdb-print-format-files (which see). Put
64 ;;; (add-hook 'bbdb-load-hook (function (lambda () (require 'bbdb-print))))
65 ;;; into your .emacs, or autoload it.
67 ;;; This program was adapted for BBDB by Boris Goldowsky
68 ;;; <boris@cs.rochester.edu> and Dirk Grunwald
69 ;;; <grunwald@cs.colorado.edu> using a TeX format designed by Luigi
70 ;;; Semenzato <luigi@paris.cs.berkeley.edu>.
71 ;;; We are also grateful to numerous people on the bbdb-info
72 ;;; mailing list for suggestions and bug reports.
81 (defcustom bbdb-print-file-name "~/bbdb.tex"
82 "*Default file name for printouts of BBDB database."
83 :group 'bbdb-utilities-print
86 (defcustom bbdb-print-omit-fields '(omit tex-name aka mail-alias)
87 "*List of fields NOT to print in address list.
88 See also bbdb-print-require."
89 :group 'bbdb-utilities-print
90 :type '(repeat (symbol :tag "Field to exclude")))
92 (defcustom bbdb-print-require '(or address phone)
93 "*What fields are required for printing a record.
94 This is evaluated for each record, and the record will be printed only
95 if it returns non-nil. The symbols name, company, net, phone,
96 address, and notes will be set to appropriate values when this is
97 evaluated; they will be nil if the field does not exist or is elided.
99 The value of this variable can be any lisp expression, but typically
100 it will be used for a boolean combination of the field variables, as
101 in the following simple examples:
103 Print only people whose phone numbers are known:
104 (setq bbdb-print-require 'phone)
105 Print people whose names AND companies are known:
106 (setq bbdb-print-require '(and name company))
107 Print people whose names, and either addresses OR phone numbers are known:
108 (setq bbdb-print-require '(and name (or address phone)))."
109 :group 'bbdb-utilities-print
110 :type '(choice (const :tag "Print all records" t)
111 (symbol :tag "Print all records with this field" phone)
112 (sexp :tag "Print only when this evaluates to non-nil"
113 '(or phone address phone))))
115 (defun bbdb-print-field-shown-p (field)
116 (not (memq field bbdb-print-omit-fields)))
118 (define-widget 'bbdb-print-alist-widget 'repeat
119 "For use in Customize"
121 (cons :tag "Column specification" :value (column . 1)
122 (const :tag "Column mode" column)
123 (radio-button-choice (const :tag "One column" 1)
124 (const :tag "Two columns" 2)
125 (const :tag "Three columns" 3)
126 (const :tag "Four columns" 4)
127 (const :tag "Quad" quad)
128 (const :tag "Grid" grid)))
129 (cons :tag "Separator specification" :value (separator . 0)
130 (const :tag "Separator" separator)
131 (radio-button-choice (const :tag "None" 0)
132 (const :tag "Line" 1)
133 (const :tag "Boxed letters" 2)
134 (const :tag "Large boxed letters" 3)
135 (const :tag "Large letters" 4)
136 (const :tag "Letters with lines" 5)
137 (const :tag "Letters with suits" 6)
138 (const :tag "Boxed letters with suits" 7)))
139 (cons :tag "Omit certain area codes"
140 :value (omit-area-code . ,(concat "^("
141 (if (integerp bbdb-default-area-code)
142 (int-to-string bbdb-default-area-code)
144 (const :tag "Omit certain area codes" omit-area-code)
145 (regexp :tag "Pattern to omit"))
146 (cons :tag "Phone number location" :value (phone-on-first-line . t)
147 (const :tag "Phone number location" phone-on-first-line)
148 (choice (const :tag "First home number on same line as name" t)
149 (const :tag "Don't put the phone number on the name line" nil)
150 (regexp :tag "Use phone number whose location matches" "^work$")))
151 (cons :tag "Limit included phone numbers" :value (n-phones . 3)
152 (const :tag "Limit included phone numbers" n-phones)
153 (integer :tag "Maximum number to include" 3))
154 (cons :tag "Limit included addresses" :value (n-addresses . 3)
155 (const :tag "Limit included addresses" n-addresses)
156 (integer :tag "Maximum number to include" 3))
157 (cons :tag "Include additional TeX input files" :value (include-files . nil)
158 (const :tag "Additional TeX input files to include" include-files)
159 (repeat (file :tag "TeX file to include")))
160 (cons :tag "Font type selection" :value (ps-fonts . nil)
161 (const :tag "Select font type" ps-fonts)
162 (choice (const :tag "Use standard TeX fonts" nil)
163 (const :tag "Use Postscript fonts" t)))
164 (cons :tag "Font size selection" :value (font-size . 10)
165 (const :tag "Select font size" font-size)
166 (integer :tag "Font size in points" 10))
167 (cons :tag "Page height selection" :value (v-size . nil)
168 (const :tag "Select page height" v-size)
169 (choice (const :tag "Use TeX default" nil)
170 (string :tag "Height (must be valid TeX dimension)" "9in")))
171 (cons :tag "Page width selection" :value (h-size . nil)
172 (const :tag "Select page width" h-size)
173 (choice (const :tag "Use TeX default" nil)
174 (string :tag "Width (must be valid TeX dimension)" "6in")))
175 (cons :tag "Vertical offset (top margin)" :value (voffset . nil)
176 (const :tag "Select vertical offset (top margin)" voffset)
177 (choice (const :tag "Use TeX default" nil)
178 (string :tag "Vertical offset (must be valid TeX dimension)" "1in")))
179 (cons :tag "Horizontal offset (left margin)" :value (hoffset . nil)
180 (const :tag "Select horizontal offset (left margin)" hoffset)
181 (choice (const :tag "Use TeX default" nil)
182 (string :tag "Horizontal offset (must be valid TeX dimension)" "1in")))
183 (cons :tag "Quad format height" :value (quad-vsize . "")
184 (const :tag "Select height for quad format pages" quad-vsize)
185 (string :tag "Height (must be valid TeX dimension)"))
186 (cons :tag "Quad format width" :value (quad-hsize . "")
187 (const :tag "Select width for quad format pages" quad-hsize)
188 (string :tag "Width (must be valid TeX dimension)")))))
190 (defcustom bbdb-print-alist
191 `((omit-area-code . ,(concat "^(" (if (integerp bbdb-default-area-code)
192 (int-to-string bbdb-default-area-code)
194 (phone-on-first-line . "^[ \t]*$")
197 (quad-hsize . "3.15in")
198 (quad-vsize . "4.5in"))
199 "*Formatting options for `bbdb-print', all formats.
200 This is an alist of the form ((option1 . value1) (option2 . value2) ...)
202 You can have separate settings for brief and non-brief printouts;
203 see the variables `bbdb-print-brief-alist' and `bbdb-print-full-alist'.
204 Settings there will override the common settings in this variable.
206 The possible options and legal values are:
207 - columns: 1, 2, 3, 4 or 'quad (4 little 2-column pages per sheet)
208 or 'grid (12 credit-card-sized pages per sheet).
209 - separator: 0-7, the style of heading for each letter.
210 0=none, 1=line, 2=boxed letters, 3=large boxed letters, 4=large letters,
211 5=letters with lines, 6=letters with suits, 7=boxed letters with suits.
212 - omit-area-code: a regular expression matching area codes to omit.
213 - phone-on-first-line: t means to put first phone number on the same
214 line with the name, nil means just the name. A string means to
215 use the first phone number whose \"location\" matches that string,
216 which should be a valid regular expression.
217 - n-phones: maximum number of phone numbers to include.
218 - n-addresses: maximum number of addresses to include.
219 - include-files: list of TeX files to \\input. If these filenames are not
220 absolute, the files must be located somewhere that TeX will find them.
221 - ps-fonts: nonnil means to use them, nil to use standard TeX fonts.
222 - font-size: in points, any integer (assuming fonts in that size exist!).
223 - hsize, vsize: horizontal dimension of pages. String value can be any valid
224 TeX dimension, or nil to use TeX's default.
225 - hoffset, voffset: shift TeX's output rightward (downward) by this distance
226 (any TeX dimension). Nil or 0 uses TeX's default positioning.
227 - quad-hsize, quad-vsize: for the quad format, horizontal and
228 vertical size of the little pages. These must be strings which
229 are valid TeX dimensions, eg \"10cm\"."
230 :group 'bbdb-utilities-print
231 :type 'bbdb-print-alist-widget)
233 (defcustom bbdb-print-full-alist
236 (include-files "bbdb-print" "bbdb-cols"))
237 "*Extra options for `bbdb-print' non-brief format.
238 These supplement or override entries in `bbdb-print-alist'; see description
239 of possible contents there."
240 :group 'bbdb-utilities-print
241 :type 'bbdb-print-alist-widget)
243 (defcustom bbdb-print-brief-alist
248 (include-files "bbdb-print-brief" "bbdb-cols"))
249 "*Extra Options for `bbdb-print', brief format.
250 These supplement or override entries in `bbdb-print-alist'; see description
251 of possible contents there."
252 :group 'bbdb-utilities-print
253 :type 'bbdb-print-alist-widget)
255 (defconst bbdb-print-filofax-alist
256 (append '((font-size . 12)
261 bbdb-print-full-alist)
262 "Example setup for making pages for a Filofax binder.")
265 (defcustom bbdb-print-prolog
266 (concat "%%%% ====== Phone/Address list in -*-TeX-*- Format =====\n"
267 "%%%% produced by bbdb-print, version 3.0\n\n")
268 "*TeX statements to include at the beginning of the `bbdb-print' file."
269 :group 'bbdb-utilities-print
270 :type '(text :format "%t:\n%v"))
272 (defcustom bbdb-print-epilog "\\endaddresses\n\\bye\n"
273 "*TeX statements to include at the end of the `bbdb-print' file."
274 :group 'bbdb-utilities-print
275 :type '(text :format "%t:\n%v"))
277 (defcustom bbdb-print-net 'primary
278 "*Indicates whether only the primary or all email addresses are printed.
279 Symbol `primary' means print the primary email address only.
280 Symbol `all' means print all email addresses."
281 :group 'bbdb-utilities-print
282 :type '(choice (const primary)
287 (defsubst bbdb-print-if-not-blank (string &rest more)
288 "If STRING is not null, then return it concatenated
289 with rest of arguments. If it is null, then all arguments are
290 ignored and the null string is returned."
291 (if (or (null string) (equal "" string))
293 (apply 'concat string more)))
296 (defun bbdb-print (visible-records to-file brief)
297 "Make a TeX file for printing out the bbdb database.\\<bbdb-mode-map>
298 If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-print]\" is \
299 used instead of simply \"\\[bbdb-print]\", then includes only the
300 people currently in the *BBDB* buffer. With a prefix argument, makes
301 a brief \(one-line-per-entry) printout.
303 There are various variables for customizing the content & format of
304 the printout, notably the variables `bbdb-print-alist' and
305 `bbdb-print-require'. See the file bbdb-print.el for more information."
306 (interactive (list (bbdb-do-all-records-p)
307 (read-file-name "Print To File: "
308 (file-name-directory bbdb-print-file-name)
311 (file-name-nondirectory bbdb-print-file-name))
313 (setq bbdb-print-file-name (expand-file-name to-file))
314 (let* ((alist (append (if brief bbdb-print-brief-alist bbdb-print-full-alist)
316 (records (if (not visible-records)
318 (set-buffer bbdb-buffer-name)
319 (mapcar 'car bbdb-records)))
320 (psstring (if (cdr (assoc 'ps-fonts alist))
322 (columns (cdr (assoc 'columns alist)))
324 (pofl (cdr (assoc 'phone-on-first-line alist)))
325 (n-phones (cdr (assoc 'n-phones alist)))
326 (n-addresses (cdr (assoc 'n-addresses alist))))
327 (find-file bbdb-print-file-name)
328 (widen) (erase-buffer)
329 (insert bbdb-print-prolog)
330 (let ((dimens '(hsize vsize hoffset voffset))
333 (setq val (cdr (assoc (car dimens) alist)))
335 (insert (format "\\%s=%s\n" (car dimens) val)))
336 (setq dimens (cdr dimens))))
337 (let ((infiles (cdr (assoc 'include-files alist))))
339 (insert (format "\\input %s\n" (car infiles)))
340 (setq infiles (cdr infiles))))
341 (insert (format "\n\\set%ssize{%d}\n"
342 psstring (cdr (assoc 'font-size alist)))
343 (format "\\setseparator{%d}\n"
344 (cdr (assoc 'separator alist)))
345 (cond ((eq 'quad columns)
346 (format "\\quadformat{%s}{%s}"
347 (cdr (assoc 'quad-hsize alist))
348 (cdr (assoc 'quad-vsize alist))))
349 ((eq 'grid columns) "\\grid")
350 ((= 4 columns) "\\fourcol")
351 ((= 3 columns) "\\threecol")
352 ((= 2 columns) "\\twocol")
353 ((= 1 columns) "\\onecol"))
354 ;; catcodes are font-encoding specific !
355 ;; Add more if you know them
356 (if (equal psstring "ps")
358 ;; Adobe Times and Courier
362 "\\catcode`ß=\\active\\chardefß=\"FF"))
363 "\n\n\\beginaddresses\n")
366 (bbdb-print-format-record (car records) current-letter
367 brief pofl n-phones n-addresses))
368 (setq records (cdr records)))
369 (insert bbdb-print-epilog)
370 (goto-char (point-min))))
372 (defvar bbdb-address-print-formatting-alist
373 '((bbdb-address-is-continental . bbdb-print-format-address-continental)
374 (nil . bbdb-print-format-address-default))
375 "Alist of address identifying and address formatting functions for printing.
376 The key is an identifying function which accepts an address. The
377 associated value is a formatting function which inserts the formatted
378 address in the current buffer. If the identifying function returns
379 non-nil, the formatting function is called. The nil key is a default
380 value will allways calls the associated formatting function. Therefore
381 you should always have (nil . bbdb-print-format-address-default) as the
382 last element in the alist.
384 The functions must take one argument, the address.
386 See also `bbdb-address-formatting-alist'.")
388 (defun bbdb-print-format-address-continental (addr)
389 "Insert formated continental address ADDR in current buffer for printing.
390 This format is used in western Europe, for example.
392 This function is a possible formatting function for
393 `bbdb-address-print-formatting-alist'.
395 The result looks like this:
404 (bbdb-print-tex-quote
407 (mapconcat (function (lambda(str)
408 (if (= 0 (length (bbdb-string-trim str)))
410 (concat str"\\\\\n"))))
411 (bbdb-address-streets addr)
413 (let ((c (bbdb-address-city addr))
414 (s (bbdb-address-state addr))
415 (z (bbdb-address-zip addr)))
416 (if (or (> (length c) 0)
419 (concat z (if (and (> (length z) 0)
420 (> (length c) 0)) " " "")
421 c (if (and (or (> (length z) 0)
423 (> (length s) 0)) ", " "")
425 (bbdb-print-if-not-blank (bbdb-address-country addr) "\\\\\n"))
428 (defun bbdb-print-format-address-default (addr)
429 "Insert formated address ADDR in current buffer for printing.
430 This is the default format; it is used in the US, for example.
432 This function is a possible formatting function for
433 `bbdb-address-print-formatting-alist'.
435 The result looks like this:
444 (bbdb-print-tex-quote
447 (mapconcat (function (lambda(str)
448 (if (= 0 (length (bbdb-string-trim str)))
450 (concat str "\\\\\n"))))
451 (bbdb-address-streets addr)
453 (let ((c (bbdb-address-city addr))
454 (s (bbdb-address-state addr))
455 (z (bbdb-address-zip addr)))
456 (if (or (> (length c) 0)
459 (concat c (if (and (> (length c) 0)
460 (> (length s) 0)) ", " "")
461 s (if (and (or (> (length c) 0)
463 (> (length z) 0)) " " "")
465 (bbdb-print-if-not-blank (bbdb-address-country addr) "\\\\\n"))
468 (defun bbdb-print-format-record (record current-letter
469 brief pofl n-phones n-addresses)
470 "Insert the bbdb RECORD in TeX format.
471 Second arg CURRENT-LETTER is the first letter of the sortkey of the previous
472 record. If this is non-nil and RECORD begins differently, a section heading is
473 output. If CURRENT-LETTER is t always produces a heading.
474 3rd argument BRIEF is for 1-line-per-record printouts.
475 Args 3-5 PHONE-ON-FIRST-LINE, N-PHONES, and N-ADDRESSES are the respective
476 values from `bbdb-print-alist'.
478 The return value is the new CURRENT-LETTER."
480 (bbdb-debug (if (bbdb-record-deleted-p record)
481 (error "plus ungood: tex formatting deleted record")))
484 (substring (concat (bbdb-record-sortkey record) "?") 0 1))
485 (name (and (bbdb-print-field-shown-p 'name)
486 (or (bbdb-record-getprop record 'tex-name)
487 (bbdb-print-tex-quote
488 (bbdb-record-name record)))))
489 (company (and (bbdb-print-field-shown-p 'company)
490 (bbdb-record-company record)))
491 (net (and (bbdb-print-field-shown-p 'net)
492 (bbdb-record-net record)))
493 (phone (and (bbdb-print-field-shown-p 'phone)
494 (bbdb-record-phones record)))
495 (address (and (bbdb-print-field-shown-p 'address)
496 (bbdb-record-addresses record)))
497 (notes (bbdb-record-raw-notes record)))
499 (if (not (eval bbdb-print-require))
500 nil ; lacks required fields
502 ;; Section header, if neccessary.
504 (if (and current-letter
505 (not (string-equal first-letter current-letter)))
506 (insert (format "\\goodbreak\n\\separator{%s}\n%%\n"
507 (bbdb-print-tex-quote (upcase first-letter)))))
509 (insert "\\beginrecord\n")
511 ;; if there is no name, use company instead
512 (if (and (not name) company)
513 (setq name (bbdb-print-tex-quote company)
516 (let ((rightside ""))
519 (setq rightside (bbdb-print-phone-string (car phone))
522 (let ((p (bbdb-print-front-if
523 (function (lambda (ph)
524 (string-match pofl (aref ph 0))))
527 (setq rightside (bbdb-print-phone-string (car p))
529 (insert (format "\\firstline{%s}{%s}\n"
531 (bbdb-print-tex-quote rightside))))
534 (insert (format "\\comp{%s}\n" (bbdb-print-tex-quote company))))
539 (setq phone (bbdb-print-firstn (- n-phones (if pofl 1 0))
543 (let ((place (aref (car phone) 0))
544 (number (bbdb-print-phone-string (car phone))))
545 (insert (format "\\phone{%s%s}\n"
546 (bbdb-print-tex-quote
547 (bbdb-print-if-not-blank place ": "))
548 (bbdb-print-tex-quote number))))
549 (insert (format "\\phone{}\n")))
550 (setq phone (cdr phone)))
553 ;; Make all dots legal line-breaks.
557 (cond ((eq bbdb-print-net 'primary)
559 ((eq bbdb-print-net 'all)
567 (setq net-addr (bbdb-print-tex-quote net-addr))
569 (while (string-match "\\." net-addr start)
571 (concat (substring net-addr 0 (match-beginning 0))
573 (substring net-addr (match-end 0))))
574 (setq start (+ 2 (match-end 0)))))
578 ;; Addresses. FUTURE: If none left, should use phones instead.
582 (bbdb-print-firstn n-addresses address brief)))
584 (bbdb-format-address (car address) 'printing)
585 (setq address (cdr address)))
590 (setq notes (list (cons 'notes notes))))
592 (let ((thisnote (car notes)))
593 (if (bbdb-print-field-shown-p (car thisnote))
595 (if (eq 'notes (car thisnote))
596 (insert (format "\\notes{%s}\n" (bbdb-print-tex-quote
598 (insert (format "\\note{%s}{%s}\n"
599 (bbdb-print-tex-quote (symbol-name
601 (bbdb-print-tex-quote (cdr thisnote))))))))
602 (setq notes (cdr notes)))
604 ;; Mark end of the record.
606 (insert "\\endrecord\n%\n")
607 (setq current-letter first-letter)))
611 (defun bbdb-print-phone-string (phone)
612 "Format PHONE-NUMBER as a string, obeying omit-area-code setting.
613 Omit-area-code is one of the allowed symbols in `bbdb-print-alist', which see."
614 (let ((str (bbdb-phone-string phone))
615 (omit (cdr (assoc 'omit-area-code bbdb-print-alist))))
616 (if (and omit (string-match omit str))
617 (substring str (match-end 0))
620 (defun bbdb-print-front-if (func list)
621 "Move first elt of LIST satisfying FUNC to front.
622 The car of the returned list is the first element that returned nonnil;
623 The cdr is the rest of the list.
624 But if the FUNC returns nil for every elements of the LIST, returns nil."
625 (cond ((null list) nil)
626 ((funcall func (car list))
628 ((let ((rest (bbdb-print-front-if func (cdr list))))
631 (cons (car list) (cdr rest))))))))
633 (defun bbdb-print-firstn (n list force)
634 "The first N elements of LIST.
635 If 3rd arg FORCE is nonnil, will extend the list to length N if necessary, by
636 adding nil's. If N is nil, just returns LIST."
637 (cond ((null n) list)
638 ((null list) (if force (make-list n nil) nil))
640 (t (cons (car list) (bbdb-print-firstn (1- n) (cdr list) force)))))
642 (defun bbdb-print-tex-quote (string)
643 "Quote any unquoted TeX special characters that appear in STRING.
644 In other words, # alone will be replaced by \\#, but \\^ will be left for
645 TeX to process as an accent."
648 (set-buffer (get-buffer-create " bbdb-print-tex-quote"))
651 (goto-char (point-min))
653 (cond ((looking-at "[<>=]+")
654 (replace-match "$\\&$"))
655 ((and (looking-at "[#$%&_]")
656 (not (eq ?\\ (char-after (1- (point))))))
659 ((and (looking-at "~")
660 (not (eq ?\\ (char-after (1- (point))))))
664 ((and (looking-at "[{}]")
665 (not (eq ?\\ (char-after (1- (point))))))
669 (t (forward-char 1))))
673 (provide 'bbdb-print)
675 ;;; bbdb-print ends here.