gnus.texi (Top): Add SASL.
[gnus] / texi / texi2latex.el
1 ;;; texi2latex.el --- convert a texi file into a LaTeX file.
2 ;; Copyright (C) 1996, 2004 Lars Magne Ingebrigtsen
3
4 (require 'cl)
5
6 (defun latexi-discard-until (string)
7   (let ((beg (match-beginning 0)))
8     (unless (re-search-forward (concat "^@end +" string "[ \t]*\n") nil t)
9       (error "No end: %s" string))
10     (delete-region beg (match-end 0))))
11
12 (defun latexi-strip-line ()
13   (delete-region (progn (beginning-of-line) (point))
14                  (progn (forward-line 1) (point))))
15
16 (defun latexi-switch-line (command arg)
17   (latexi-strip-line)
18   (insert (format "\\%s{%s}\n" command arg)))
19
20 (defun latexi-index-command (command arg)
21   (latexi-strip-line)
22   (insert (format "\\gnus%sindex{%s}\n" 
23                   (if (equal command "kindex") "k" "")
24                   arg)))
25
26 (defun latexi-begin-command (command)
27   (latexi-strip-line)
28   (insert (format "\\begin{%s}\n" command)))
29
30 (defun latexi-exchange-command (command arg)
31   (delete-region (match-beginning 0) (match-end 0))
32   (insert (format "\\%s{%s}" command arg)))
33
34 (defun latexi-translate ()
35   "Translate."
36   (interactive)
37   (latexi-translate-file "gnus")
38   (latexi-translate-file "gnus-faq")
39   (latexi-translate-file "message" t)
40   (latexi-translate-file "emacs-mime" t)
41   (latexi-translate-file "sieve" t)
42   (latexi-translate-file "pgg" t)
43   (latexi-translate-file "sasl" t))
44
45 (defun latexi-translate-file (file &optional as-a-chapter)
46   "Translate file a LaTeX file."
47   (let ((item-string "")
48         (item-stack nil)
49         (list-stack nil)
50         (latexi-buffer (get-buffer-create "*LaTeXi*"))
51         verbatim
52         (regexp 
53          (concat 
54             "@\\([^{} \t\n]+\\)"
55             "\\(\\( +\\(.*$\\)\\|[ \t]*$\\)\\|{\\([^}]*\\)}\\)"))
56         (cur (find-file-noselect (concat (or (getenv "srcdir") ".") 
57                                          "/" file ".texi")))
58         (times 3)
59         (chapter 0)
60         command arg)
61     (pop-to-buffer latexi-buffer)
62     (buffer-disable-undo)
63     (erase-buffer)
64     (insert-buffer-substring cur)
65     (goto-char (point-min))
66     (latexi-strip-line)
67     (latexi-translate-string "%@{" "\\gnuspercent{}\\gnusbraceleft{}")
68     (latexi-translate-string "%@}" "\\gnuspercent{}\\gnusbraceright{}")
69     (latexi-translate-string "%1@{" "\\gnuspercent{}1\\gnusbraceright{}")
70     (latexi-translate-string "@*" "\\newline{}")
71     (latexi-translate-string "S@{" "S\\gnusbraceleft{}")
72     (latexi-translate-string "@code{\\222}" "@code{\\gnusbackslash{}222}")
73     (latexi-translate-string "@code{\\264}" "@code{\\gnusbackslash{}264}")
74     (latexi-translate-string "@samp{\\Deleted}" "@samp{\\gnusbackslash{}Deleted}")
75     (latexi-translate-string "@samp{\\Seen}" "@samp{\\gnusbackslash{}Seen}")
76     (latexi-translate-string "@file{c:\\myhome}" "@file{c:\\gnusbackslash{}myhome}")
77 ;    (while (re-search-forward "{\"[^\"]*\\(\\\\\\)[^\"]*\"}\\\\" nil t)
78 ;      (replace-match "\\verb+\\\\+ " t t))
79     (while (not (zerop (decf times)))
80       (goto-char (point-min))
81       (while (re-search-forward regexp nil t)
82         (setq command (match-string 1))
83         (if (match-beginning 3)
84             (progn
85               (setq arg (or (match-string 4) ""))
86               (save-match-data
87                 (when (string-match "[ \t]+$" arg)
88                   (setq arg (substring arg 0 (match-beginning 0)))))
89               (cond 
90                ((member command '("c" "comment"))
91                 (if (string-match "@icon" (or arg ""))
92                     (progn
93                       (beginning-of-line)
94                       (delete-region (point) (+ (point) 4))
95                       (insert "\\gnus"))
96                   (delete-region (match-beginning 0) 
97                                  (progn (end-of-line) (point))))
98                 (if (equal arg "@head")
99                     (insert "\\gnusinteresting")))
100                ((member command '("setfilename" "set"
101                                   "synindex" "setchapternewpage"
102                                   "summarycontents" "bye"
103                                   "top" "iftex" "cartouche" 
104                                   "iflatex" "finalout" "vskip"
105                                   "dircategory" "group" "syncodeindex"))
106                 (latexi-strip-line))
107                ((member command '("menu" "tex" "ifinfo" "ignore" 
108                                   "ifnottex" "direntry"))
109                 (latexi-discard-until command))
110                ((member command '("subsection" "subsubsection"))
111                 (if as-a-chapter
112                     (latexi-switch-line (format "sub%s" command) arg)
113                   (latexi-switch-line command arg)))
114                ((member command '("heading"))
115                 (if as-a-chapter
116                     (latexi-switch-line "subsection*" arg)
117                   (latexi-switch-line "section*" arg)))
118                ((member command '("subheading"))
119                 (if as-a-chapter
120                     (latexi-switch-line "subsubsection*" arg)
121                   (latexi-switch-line "subsection*" arg)))
122                ((member command '("subsubheading"))
123                 (if as-a-chapter
124                     (latexi-switch-line "subsubsubsection*" arg)
125                   (latexi-switch-line "subsubsection*" arg)))
126                ((member command '("chapter"))
127                 (if (string-match "Index" arg)
128                     (latexi-strip-line)
129                   (if as-a-chapter
130                       (latexi-switch-line "gnussection" arg)
131                     (latexi-switch-line 
132                      (format 
133                       "gnus%s{%s}" command
134                       (format "\\epsfig{figure=ps/new-herd-%d,scale=.5}"
135                               (if (> (incf chapter) 9) 9 chapter)))
136                      arg))))
137                ((member command '("section"))
138                 (if as-a-chapter
139                     (latexi-switch-line "subsection" arg)
140                   (latexi-switch-line (format "gnus%s" command) arg)))
141                ((member command '("cindex" "findex" "kindex" "vindex"))
142                 (latexi-index-command command arg))
143                ((member command '("*"))
144                 (delete-char -2)
145                 (insert "\\\\"))
146                ((equal command "sp")
147                 (replace-match "" t t))
148                ((equal command ":")
149                 (replace-match "" t t))
150                ((member command '("deffn" "defvar" "defun"))
151                 (replace-match "" t t))
152                ((equal command "node")
153                 (latexi-strip-line)
154                 (unless (string-match "Index" arg)
155                   (insert (format "\\label{%s}\n" arg))))
156                ((equal command "contents")
157                 (latexi-strip-line)
158                 ;;(insert (format "\\tableofcontents\n" arg))
159                 )
160                ((member command '("titlepage"))
161                 (latexi-begin-command command))
162                ((member command '("lisp" "example" "smallexample" "display"))
163                 (latexi-strip-line)
164                 (insert (format "\\begin{verbatim}\n"))
165                 (setq verbatim (point)))
166                ((member command '("center"))
167                 (latexi-strip-line)
168                 (insert (format "\\begin{%s}%s\\end{%s}\n"
169                                 command arg command)))
170                ((member command '("end"))
171                 (cond
172                  ((member arg '("titlepage"))
173                   (latexi-strip-line)
174                   (insert (format "\\end{%s}\n" arg)))
175                  ((equal arg "quotation")
176                   (latexi-strip-line)
177                   (insert (format "\\end{verse}\n")))
178                  ((member arg '("lisp" "example" "smallexample" "display"))
179                   (latexi-strip-line)
180                   (save-excursion
181                     (save-restriction
182                       (narrow-to-region verbatim (point))
183                       (goto-char (point-min))
184                       (while (search-forward "@{" nil t)
185                         (replace-match "{" t t))
186                       (goto-char (point-min))
187                       (while (search-forward "@}" nil t)
188                         (replace-match "}" t t))))
189                   (setq verbatim nil)
190                   (insert "\\end{verbatim}\n"))
191                  ((member arg '("table"))
192                   (setq item-string (pop item-stack))
193                   (latexi-strip-line)
194                   (insert (format "\\end{%slist}\n" (pop list-stack))))
195                  ((member arg '("itemize" "enumerate"))
196                   (setq item-string (pop item-stack))
197                   (latexi-strip-line)
198                   (insert (format "\\end{%s}\n" arg)))
199                  ((member arg '("iflatex" "iftex" "cartouche" "group"))
200                   (latexi-strip-line))
201                  ((member arg '("deffn" "defvar" "defun"))
202                   (latexi-strip-line))
203                  (t
204                   (error "Unknown end arg: %s" arg))))
205                ((member command '("table"))
206                 (push item-string item-stack)
207                 (push (substring arg 1) list-stack)
208                 (setq item-string 
209                       (format "[@%s{%%s}]" (car list-stack)))
210                 (latexi-strip-line)
211                 (insert (format "\\begin{%slist}\n" (car list-stack))))
212                ((member command '("itemize" "enumerate"))
213                 (push item-string item-stack)
214                 (cond 
215                  ((member arg '("@bullet"))
216                   (setq item-string "[\\gnusbullet]"))
217                  (t
218                   (setq item-string "")))
219                 (latexi-strip-line)
220                 (insert (format "\\begin{%s}\n" command)))
221                ((member command '("item"))
222                 (latexi-strip-line)
223                 (insert (format "\\%s%s\n" command (format item-string arg))))
224                ((equal command "itemx")
225                 (latexi-strip-line)
226                 (insert (format "\\gnusitemx{%s}\n" (format item-string arg))))
227                ((eq (aref command 0) ?@)
228                 (goto-char (match-beginning 0))
229                 (delete-char 2)
230                 (insert "duppat{}"))
231                ((equal command "settitle")
232                 (latexi-strip-line)
233                 (if (not as-a-chapter)
234                     (insert 
235                      (format "\\newcommand{\\gnustitlename}{%s}\n" arg))))
236                ((equal command "title")
237                 (latexi-strip-line)
238                 (insert (format "\\gnustitlename{%s}\n" arg)))
239                ((equal command "author")
240                 (latexi-strip-line)
241                 (insert (format "\\gnusauthor{%s}\n" arg)))
242                ((equal command "quotation")
243                 (latexi-begin-command "verse"))
244                ((equal command "page")
245                 (latexi-strip-line)
246                 (insert (format "\\newpage\n" arg)))
247                ((equal command "'s")
248                 (goto-char (match-beginning 0))
249                 (delete-char 1))
250                ((equal command "include")
251                 (latexi-strip-line)
252                 (string-match "\\.texi" arg)
253                 (insert (format "\\input{%s.latexi}\n" 
254                                 (substring arg 0 (match-beginning 0)))))
255                ((equal command "noindent")
256                 (latexi-strip-line)
257                 (insert "\\noindent\n"))
258                ((equal command "printindex")
259                 (latexi-strip-line)
260                 ;;(insert 
261                 ;; (format 
262                 ;;  "\\begin{theindex}\\input{gnus.%s}\\end{theindex}\n" arg))
263                 )
264                (t
265                 (error "Unknown command (file %s line %d): %s"
266                        file
267                        (save-excursion
268                          (widen)
269                          (1+ (count-lines (point-min) (progn
270                                                         (beginning-of-line)
271                                                         (point)))))
272                        command))))
273           ;; These are commands with {}.
274           (setq arg (match-string 5))
275           (cond 
276            ((member command '("anchor"))
277             (latexi-strip-line))
278            ((member command '("ref" "xref" "pxref"))
279             (latexi-exchange-command (concat "gnus" command) arg))
280            ((member command '("sc" "file" "dfn" "emph" "kbd" "key" "uref"
281                               "code" "samp" "var" "strong" "i"
282                               "result" "email" "env" "r" "command" "asis"
283                               "url"))
284             (goto-char (match-beginning 0))
285             (delete-char 1)
286             (insert "\\gnus"))
287            ((member command '("acronym"))
288             (latexi-exchange-command (concat "gnus" command) (downcase arg)))
289            ((member command '("copyright" "footnote" "TeX"))
290             (goto-char (match-beginning 0))
291             (delete-char 1)
292             (insert "\\"))
293            ((member command '("dots"))
294             (goto-char (match-beginning 0))
295             (delete-region (match-beginning 0) (match-end 0))
296             (insert "..."))
297            ((eq (aref command 0) ?@)
298             (goto-char (match-beginning 0))
299             (delete-char 2)
300             (insert "duppat{}"))
301            (t
302             (error "Unknown command (file %s line %d): %s"
303                    file
304                    (save-excursion
305                      (widen)
306                      (1+ (count-lines (point-min) (progn
307                                                     (beginning-of-line)
308                                                     (point)))))
309                    command))))))
310     (latexi-translate-string "$" "\\gnusdollar{}")
311     (latexi-translate-string "&" "\\gnusampersand{}")
312     (latexi-translate-string "%" "\\gnuspercent{}")
313     (latexi-translate-string "#" "\\gnushash{}")
314     (latexi-translate-string "^" "\\gnushat{}")
315     (latexi-translate-string "~" "\\gnustilde{}")
316     (latexi-translate-string "_" "\\gnusunderline{}")
317     (latexi-translate-string "¬" "\\gnusnot{}")
318     (goto-char (point-min))
319     (while (search-forward "duppat{}" nil t)
320       (replace-match "@" t t))
321     (latexi-translate-string "@@" "@")
322     (latexi-translate-string "<" "\\gnusless{}")
323     (latexi-translate-string ">" "\\gnusgreater{}")
324     (goto-char (point-min))
325     (search-forward "label{Top}" nil t)
326     (while (re-search-forward "\\\\[ntr]\\b" nil t)
327       (when (save-match-data
328               (or (not (save-excursion
329                          (search-backward "begin{verbatim}" nil t)))
330                   (> (save-excursion
331                        (search-backward "end{verbatim"))
332                      (save-excursion
333                        (search-backward "begin{verbatim}")))))
334         (goto-char (match-beginning 0))
335         (delete-char 1)
336         (insert "\\gnusbackslash{}")))
337     (latexi-translate-string "\\\\" "\\gnusbackslash{}")
338     (goto-char (point-min))
339     (while (re-search-forward "\\\\[][{}]" nil t)
340       (goto-char (match-beginning 0))
341       (delete-char 1))
342     (latexi-contributors)
343     (let ((coding-system-for-write 'iso-8859-1))
344       (write-region (point-min) (point-max) (concat file ".latexi")))))
345
346 (defun latexi-translate-string (in out)
347   (let (yes)
348     (goto-char (point-min))
349     (search-forward "label{Top}" nil t)
350     (while (search-forward in nil t)
351       (when (save-match-data
352               (or (not (save-excursion
353                          (search-backward "begin{verbatim}" nil t)))
354                   (> (save-excursion
355                        (re-search-backward "end{verbatim}\\|end{verse}"))
356                      (save-excursion
357                        (re-search-backward
358                         "begin{verbatim}\\|begin{verse}")))))
359         (replace-match out t t)))))
360
361 (defun latexi-contributors ()
362   (goto-char (point-min))
363   (when (re-search-forward "^Also thanks to the following" nil t)
364     (forward-line 2)
365     (narrow-to-region
366      (point)
367      (1- (search-forward "\n\n")))
368     (when (re-search-backward "^and" nil t)
369       (latexi-strip-line))
370     (goto-char (point-min))
371     (while (re-search-forward "[.,] *$" nil t)
372       (replace-match "" t t))
373     (goto-char (point-min))
374     (let (names)
375       (while (not (eobp))
376         (push (buffer-substring (point) (progn (end-of-line) (point)))
377               names)
378         (forward-line 1))
379       (delete-region (point-min) (point-max))
380       (insert "\\begin{tabular}{lll}\n")
381       (setq names (nreverse (delete "" names)))
382       (while names
383         (insert (pop names) " & " (or (pop names) "\\mbox{}") 
384                 " & " (or (pop names) "\\mbox{}") 
385                 "\\\\\n"))
386       (insert "\\end{tabular}\n")
387       (widen))))
388