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