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