Synch to Gnus 200310230600.
[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" "asis"
281                               "url"))
282             (goto-char (match-beginning 0))
283             (delete-char 1)
284             (insert "\\gnus"))
285            ((member command '("acronym"))
286             (latexi-exchange-command (concat "gnus" command) (downcase arg)))
287            ((member command '("copyright" "footnote" "TeX"))
288             (goto-char (match-beginning 0))
289             (delete-char 1)
290             (insert "\\"))
291            ((member command '("dots"))
292             (goto-char (match-beginning 0))
293             (delete-region (match-beginning 0) (match-end 0))
294             (insert "..."))
295            ((eq (aref command 0) ?@)
296             (goto-char (match-beginning 0))
297             (delete-char 2)
298             (insert "duppat{}"))
299            (t
300             (error "Unknown command (file %s line %d): %s"
301                    file
302                    (save-excursion
303                      (widen)
304                      (1+ (count-lines (point-min) (progn
305                                                     (beginning-of-line)
306                                                     (point)))))
307                    command))))))
308     (latexi-translate-string "$" "\\gnusdollar{}")
309     (latexi-translate-string "&" "\\gnusampersand{}")
310     (latexi-translate-string "%" "\\gnuspercent{}")
311     (latexi-translate-string "#" "\\gnushash{}")
312     (latexi-translate-string "^" "\\gnushat{}")
313     (latexi-translate-string "~" "\\gnustilde{}")
314     (latexi-translate-string "_" "\\gnusunderline{}")
315     (latexi-translate-string "¬" "\\gnusnot{}")
316     (goto-char (point-min))
317     (while (search-forward "duppat{}" nil t)
318       (replace-match "@" t t))
319     (latexi-translate-string "@@" "@")
320     (latexi-translate-string "<" "\\gnusless{}")
321     (latexi-translate-string ">" "\\gnusgreater{}")
322     (goto-char (point-min))
323     (search-forward "label{Top}" nil t)
324     (while (re-search-forward "\\\\[ntr]\\b" nil t)
325       (when (save-match-data
326               (or (not (save-excursion
327                          (search-backward "begin{verbatim}" nil t)))
328                   (> (save-excursion
329                        (search-backward "end{verbatim"))
330                      (save-excursion
331                        (search-backward "begin{verbatim}")))))
332         (goto-char (match-beginning 0))
333         (delete-char 1)
334         (insert "\\gnusbackslash{}")))
335     (latexi-translate-string "\\\\" "\\gnusbackslash{}")
336     (goto-char (point-min))
337     (while (re-search-forward "\\\\[][{}]" nil t)
338       (goto-char (match-beginning 0))
339       (delete-char 1))
340     (latexi-contributors)
341     (let ((coding-system-for-write 'iso-8859-1))
342       (write-region (point-min) (point-max) (concat file ".latexi")))))
343
344 (defun latexi-translate-string (in out)
345   (let (yes)
346     (goto-char (point-min))
347     (search-forward "label{Top}" nil t)
348     (while (search-forward in nil t)
349       (when (save-match-data
350               (or (not (save-excursion
351                          (search-backward "begin{verbatim}" nil t)))
352                   (> (save-excursion
353                        (re-search-backward "end{verbatim}\\|end{verse}"))
354                      (save-excursion
355                        (re-search-backward
356                         "begin{verbatim}\\|begin{verse}")))))
357         (replace-match out t t)))))
358
359 (defun latexi-contributors ()
360   (goto-char (point-min))
361   (when (re-search-forward "^Also thanks to the following" nil t)
362     (forward-line 2)
363     (narrow-to-region
364      (point)
365      (1- (search-forward "\n\n")))
366     (when (re-search-backward "^and" nil t)
367       (latexi-strip-line))
368     (goto-char (point-min))
369     (while (re-search-forward "[.,] *$" nil t)
370       (replace-match "" t t))
371     (goto-char (point-min))
372     (let (names)
373       (while (not (eobp))
374         (push (buffer-substring (point) (progn (end-of-line) (point)))
375               names)
376         (forward-line 1))
377       (delete-region (point-min) (point-max))
378       (insert "\\begin{tabular}{lll}\n")
379       (setq names (nreverse (delete "" names)))
380       (while names
381         (insert (pop names) " & " (or (pop names) "\\mbox{}") 
382                 " & " (or (pop names) "\\mbox{}") 
383                 "\\\\\n"))
384       (insert "\\end{tabular}\n")
385       (widen))))
386