; 
; This file contains conversion functions that convert troff -me format to the
; equvalient LaTeX.  The conversion is much like that done in ./me2html.el,
; q.v.  Given the similarity between troff -me and LaTex, the conversion here
; is pretty straightforward.  One thing we don't have yet is a troff convetion
; for forward refs, as in LaTeX.  As soon as that convetion is fully defined
; and implemented, it can be converted to the equivalent in LaTeX.
;
;

(load "~gfisher/emacs/lib/misc.el")
(defvar no-latex-header-footer nil)
(defvar default-figure-width "4.75in")

(defun dot () (point))

(defun me2latex ()
"Convert -me formatting commands to their latex equivalents."
    (interactive)
    (me2latex1 t)
)

(defun me2latex1 (no-header)
    (interactive)
    (setq case-fold-search nil)
    (message (buffer-name))
    (message "%d" (buffer-size))
    (beginning-of-buffer)
;   (convert-html-escape-chars)
;   (beginning-of-buffer)
    (replace-string "\n.br\n" "\n\\linebreak\n")  ;Do this first since numerous
						  ;.br's are added below
    (beginning-of-buffer)
    (replace-string "\n.hbr" "")
    (beginning-of-buffer)
    (replace-string "\n.nf" "\n\\begin{verbatim}")
    (beginning-of-buffer)
    (replace-string "\n.fi" "\n\\end{verbatim}")
    (beginning-of-buffer)
    (replace-regexp "\n.(i.*" "\n\\\\begin{display}{0ex}")
    (beginning-of-buffer)
    (replace-regexp "\n.)i.*" "\n\\\\end{display}")
    (beginning-of-buffer)
    (replace-regexp "\n.(l F.*" "\n\\\\begindisplay")
    (beginning-of-buffer)
    (replace-regexp "\n.)l F.I" "\n\\\\end{display}")
    (beginning-of-buffer)
    ; NOTE: .na is now global, so no explicit .ad or na commands appear in
    ;        conversions of .(n, (l, and .(t.
    (replace-regexp "\n.(n.*" "\n\\\begin{display}{0ex}\n\\begin{verbatim}")
    (beginning-of-buffer)
    (replace-regexp "\n.)n.*" "\n\\end{verbatim}\n\\end{display}")
    (beginning-of-buffer)
    (replace-regexp "\n.(l.*" "\n\\\begin{display}{0ex}\n\\begin{verbatim}")
    (beginning-of-buffer)
    (replace-regexp "\n.)l.*" "\n\\end{verbatim}\n\\end{display}")
    (beginning-of-buffer)
    (replace-string "\n.(t 0" "\n\\begin{alltt}")
    (beginning-of-buffer)
    (replace-string "\n.)t 0" "\n\\end{alltt}")
    (beginning-of-buffer)
    (replace-string "\n.(t" "\n\\\begin{display}{0ex}\n\\begin{alltt}")
    (beginning-of-buffer)
    (replace-string "\n.)t" "\n\\end{display}\n\\end{alltt}")
    (beginning-of-buffer)
    (replace-string "\n.bp" "\n\\pagebreak")
    (beginning-of-buffer)
    (replace-string "\n.TS" "\n.br\n<pre>\n.TS")
    (beginning-of-buffer)
    (replace-string "\n.TE" "\n.br\n.TE\n</pre>\n.br")
    (beginning-of-buffer)
    (replace-string "\n.pp" "\n")
    (beginning-of-buffer)
    (replace-string "\n.lp" "\n")
    (beginning-of-buffer)
; This didnt work.  See new .(S ... .)S macro pair in html.me
;   (replace-regexp "\\.sz \\(+\\|-\\)\\(.*\\)" ".br\n<font size=\\1\\2>\n.br")
;   (replace-regexp "\\.(S \\(.*\\)" ".br\n<font size=\\1>\n.br")
;   (beginning-of-buffer)
;   (replace-string "\n.)S" "\n.br\n</font>\n.br")

    (beginning-of-buffer)
    (convert-font-size)
    (beginning-of-buffer)
    (convert-font "B" "bf" "")
    (beginning-of-buffer)
    (convert-font "I" "em" "")
    (beginning-of-buffer)
    (convert-font "(BI" "bf {em" "}")
    (beginning-of-buffer)
    (convert-font "C" "tt" "")
    (beginning-of-buffer)
    (convert-font "(CI" "em {tt" "}")
    (beginning-of-buffer)
    (convert-font "(CB" "bf {tt " "}")
    (beginning-of-buffer)
    (convert-font "H" "tt" "")
    (beginning-of-buffer)
    (convert-font "(HI" "em {tt" "}")
    (beginning-of-buffer)
    (convert-font "(HB" "bf {tt" "}")

    (beginning-of-buffer)
    (replace-regexp "\n\\.sp \\([.0-9]*\\).*" "\n\\\\sp{\\1ex}")
    (beginning-of-buffer)
    (replace-string "\n.sp\n" "\n\\spn")
    (beginning-of-buffer)
    (convert-figures)
    (beginning-of-buffer)
    (convert-sections)
    (beginning-of-buffer)
    (convert-lists)
    (beginning-of-buffer)
    (convert-centering)
    (beginning-of-buffer)
    (convert-footnotes)
    (beginning-of-buffer)
    (convert-cites)
    (beginning-of-buffer)
    (convert-header-footer no-header)
    (beginning-of-buffer)
    (convert-raw-latex-block)
    (echo-file)
)

(defun convert-sections ()
    (interactive)
    (replace-regexp "\\.sh 1 \"\\(.*\\)\"" "\\\\section {\\1}")
    (beginning-of-buffer)
    (replace-regexp "\\.sh 2 \"\\(.*\\)\"" "\\\\subsection {\\1}")
    (beginning-of-buffer)
    (replace-regexp "\\.sh 3 \"\\(.*\\)\"" "\\\\subsubsection {\\1}")
    (beginning-of-buffer)
    (replace-regexp "\\.sh 4 \"\\(.*\\)\"" "\\\\paragraph {\\1}")
    (beginning-of-buffer)
    (replace-regexp "\\.sh 5 \"\\(.*\\)\"" "\\\\subparagraph {\\1}")
)

(defun unhtml ()
    (unhtitle)
    (unanchor)
    (echo-file)
)

(defun convert-font-size ()
"Convert -me .(S ... )S font size change to the (weaker) equivalent latex
explcit commands like small, large, etc."
    (interactive)
    (while (search-forward "\n.(S " nil t)
      (progn
	(setq d (dot))
	(forward-char 1)
	(setq sign (buffer-substring d (dot)))
	(setq size (string-to-int (get-next-int)))
	(beginning-of-line)
	(kill-line 1)
	(if (string= sign "-")
	    (cond ( (>= size 4) (insert-string "{\\tiny \n") )
		  ( (= size 3) (insert-string "{\\scriptsize \n") )
		  ( (= size 2) (insert-string "{\\footnotesize \n") )
		  ( (= size 1) (insert-string "{\\small \n") )
	    )
	    (cond ( (= size 1) (insert-string "{\\large \n") )
		  ( (= size 2) (insert-string "{\\Large \n") )
		  ( (= size 3) (insert-string "{\\LARGE \n") )
		  ( (= size 4) (insert-string "{\\huge \n") )
		  ( (>= size 5) (insert-string "{\\Huge \n") )
	    )
	 )
      )
    )
    (beginning-of-buffer)
    (replace-string "\n.)S" "\n}")
)

(defun convert-font (mf lf ef)
  "Convert a -me font-change segment to the equivalent latex."
    (interactive "sme font spec (what follows \\f): 
shtml start font command: 
shtml end font command: ")
    (beginning-of-buffer)
    (while (search-forward (concat "\\f" mf) nil t)
      (progn
	(backward-delete-char (+ 2 (length mf)))
	(insert-string (concat "{\\" lf " "))
	(if (not (search-forward "\\fP" nil t))
	  (progn
	    (message "%s%d" "missing \\fP at position" (dot))
	    (what-line)))
	(backward-delete-char 3)
	(insert-string (concat "}" ef ""))
      )
    )
)

(defun get-next-int ()
 (interactive)
  (setq m (dot))
  (move-over-digits)
  (buffer-substring m (dot))
)

(defun move-over-digits ()
  (interactive)
  (while (isdigit (following-char)) (forward-char 1))
)

(defun isdigit (c)
  (interactive)
  (and (>= c ?0) (<= c ?9))
)

(defun move-over-whitespace ()
"Move forward over any whitespace chars in from of dot."
  (interactive)
  (while (equal (char-syntax (following-char)) ? ) (forward-char 1))
)


(defun convert-figures ()
"Convert -me figures of the form .(F ... PIC ... .)F to latex equivalent form
\begin{figure} ... \psfig ... \caption ... \end{figure}."
    (interactive)
    (setq fignum 1)
    (while (search-forward-regexp "\n.(F \"\\(.*\\)\"" nil t)

	;Now sitting at end of .(F line with match-string holding caption
	(setq m (match-string 1))

	;Convert .(F to \begin{figure} and insert fignum label
	(beginning-of-line)
	(kill-line 1)
	(insert-string "\\begin{figure}\n")
        (insert-string
	    (concat "\\label{F"
		    (int-to-string fignum)
		    "}\n"))
        (setq fignum (1+ fignum))

	;Now sitting at beginning of .PIC line; convert it to ...\\pspic... .
	(forward-word 1)
	(move-over-whitespace)
	(setq d (dot))
	(to-space-or-eol)
	(setq filename (buffer-substring d (dot)))
	(if (not (eolp))
	  (progn
	    (setq d (dcot))
	    (search-backward " ")
	    (setq width (buffer-substring (dot) d))
	  )
	  (setq width default-figure-width)
	)
	(beginning-of-line)
	(kill-line 1)
	(insert-string
	    (concat "\\centerline{\\psfig{figure="
		    filename
		    ".ps,width="
		    width
		    "}}\n"))

	;Now sitting at beginning of .)F line; insert caption and convert .)F
	;to \\end{figure}
	(kill-line 1)
	(insert-string (concat "\\caption{"
			       m
			       "\}\n\\end{figure}\n"))
    )

    ;Having put succesive labels in each figure, now go baack and convert the
    ;\n(FI refs to \ref{Fn}.  Note that we assume here that all troff fig refs
    ;abide the convention that they precede the .(F.  Any of the commands like
    ;.nr FJ \n(FI wont be converted properly.  The best thing to do in this
    ;regard is to implement a latex-style ref prococessing pass for troff in
    ;emacs.  Alternatively, we could do some emacs hacking to convert (very)
    ;conventional uses of FJ-style number regs to latex refs.  Either of this
    ;is future work.
    (beginning-of-buffer)
    (setq fignum 1)
    (while (search-forward "\\n(FI" nil t)
        (backward-delete-char 4)
	(insert-string
	   (concat "ref{F"
		   (int-to-string fignum)
		   "}"))
	(setq fignum (1+ fignum))
    )
)

(defun to-space-or-eol ()
    (search-forward-regexp " \\|\n")
    (backward-char 1)
)

(defun convert-lists ()
"Convert -me numbered and bulleted lists to latex format, using list and enum
environments."
    (interactive)
    (while (search-forward-regexp
		 "\n\.(E[ ]*\\([.0-9]*\\)[v ]*\\([0-9]*\\)" nil t)
        (setq spacing (match-string 1))
	(setq indent (match-string 2))
	(if (string= spacing "") (setq spacing "0"))
	(if (string= indent "") (setq indent "0"))
	(beginning-of-line)
	(kill-line 1)
	(insert-string
	   (concat "\\begin{enum}{"
		   spacing
		   "ex}{"
		   indent
		   "em}\n"))
    )
    (beginning-of-buffer)
    (replace-regexp "\n.)E.*" "\n\\\\end{enum}")

    (beginning-of-buffer)
    (while (search-forward-regexp
		 "\n\.(L \\([1AaIi]\\)[ ]*\\([.0-9]*\\)[v ]*\\([0-9]*\\)"
		 nil t)
        (setq style (match-string 1))
        (setq spacing (match-string 2))
	(setq indent (match-string 3))
	(if (or (string= style "") (string= style "1")) (setq style "one"))
	(if (string= spacing "") (setq spacing "0"))
	(if (string= indent "") (setq indent "0"))
	(beginning-of-line)
	(kill-line 1)
	(insert-string
	    (concat "\\begin{list"
		    style
		    "}{"
		    spacing
		    "ex}{"
		    indent
		    "em}\n"))
    )

    (beginning-of-buffer)
    (while (search-forward-regexp
		 "\n\.)L \\([1AaIi]\\).*" nil t)
        (setq style (match-string 1))
	(if (or (string= style "") (string= style "1")) (setq style "one"))
	(beginning-of-line)
	(kill-line 1)
	(insert-string
	    (concat "\\end{list" style "}\n"))
    )

    (beginning-of-buffer)
    (replace-string "\n.ee" "\n\\item")
    (beginning-of-buffer)
    (replace-string "\n.le" "\n\\item")
)

(defun convert-centering ()
"Convert -me centering of the form \".(C ... )C\" to latex equivalent form
\begin{center} ... \end{center}."
    (interactive)
    (replace-string "\n.(C" "\n\\begin{center}")
    (beginning-of-buffer)
    (replace-string "\n.)C" "\n\\end{center}")
    (beginning-of-buffer)
    (replace-regexp "\n.(TI.*" "\n\\\\begin{center}")
    (beginning-of-buffer)
    (replace-regexp "\n.)TI.*" "\n\\\\end{center}")
)

(defun convert-footnotes ()
"Convert -me footnotes of the form \\* ... \".(f ... .)f\" to latex equivalent
form \\footnotemark ... \\footnotetext{...}."
    (interactive)
    (replace-string "\\*" "\\footnotemark")
    (beginning-of-buffer)
    (replace-string "\n.(f" "\n\\footnotetext{")
    (beginning-of-buffer)
    (replace-string "\n.)f" "\n}")
)

(defun convert-cites ()
"Convert -me cites of the form .[ ... .] to the latext equvalent \cite{...}."
    (interactive)
    (replace-regexp "\n\.\\[.*\n\\[.*\n" "\n\\\\cite{")
    (beginning-of-buffer)
    (replace-regexp "\n\.\\[.*\n" "\n\\\\cite{")
    (beginning-of-buffer)
    (replace-regexp "\n\.\\]\\(.*\\)\\]" "}\\1")
    (beginning-of-buffer)
    (replace-regexp "\n\.\\]\\(.*\\)" "}")

    ;Next stuff s inefficient, but as unual easier than fancy scanning.
    (beginning-of-buffer)
    (replace-regexp
      "\\(\\\\cite.*\\)}\n\\\\cite{\\(.*\\)}\n\\\\cite{\\(.*\\)}\n\\\\cite{\\(.*\\)}"
      "\\1,\\2,\\3,\\4")
    (beginning-of-buffer)
    (replace-regexp "\\(\\\\cite.*\\)}\n\\\\cite{\\(.*\\)}\n\\\\cite{\\(.*\\)}"
		    "\\1,\\2,\\3}")
    (beginning-of-buffer)
    (replace-regexp "\\(\\\\cite.*\\)}\n\\\\cite{\\(.*\\)}" "\\1,\\2}")

    (replace-regexp "\n\..*\"References\"\n.*\n\\\\cite{$LIST$}"
	    "\n\\\\bibliographystyle{acm}\n\\\\bibliography{references}"))

(defun convert-html-escape-chars ()
"Convert non-html usages <, >, and  & to &lt, &gt, and &amp, respectively.
See restrictions on html command sequencens in doc at top of me2html.el.
Serious hack in this regard is not converting ]> to ]%lt since ]> is
a troff refer macro.

12jan98 note: evidently &amp is not needed anymore -- Netscape 4 (at least)
interprets & straight."
    (interactive)
;   (while (re-search-forward "[^\\]<\\|[^\\]>\\|&" nil t)
    (while (re-search-forward "[^\\]<\\|[^\\]>" nil t)
      (convert-one-html-escape-char)
    )
    ; Next two lines cause cant get "[^]]>\\|" to work in preceding re-search.
    (beginning-of-buffer)
    (replace-string "]&gt" "]>")
    (beginning-of-buffer)
    (replace-string "]&lt" "]<")
)

(defun preceding-preceding-char (n)
 (progn
  (interactive)
  (backward-char n)
  (setq ch (preceding-char))
  (forward-char n)
  ch))

(defun convert-one-html-escape-char ()
    (interactive)
    (if (and (= (preceding-char) ?<) (= (preceding-preceding-char 1) ?\n))
	(forward-line 1)
        (progn
	  (if (or
	       (and
		(= (preceding-char) ?&)
		(= (preceding-preceding-char 1) ?\\))
	       (and
		(= (preceding-char) ?>)
		(= (preceding-preceding-char 1) ?-)
;		(= (preceding-preceding-char 2) ?\()
;		(= (preceding-preceding-char 3) ?\\)
	       )
	      )
	      nil
	      (progn
		(if (= (preceding-char) ?<)
		    (setq ch "lt")
		    (if (= (preceding-char) ?>)
			(setq ch "gt")
			(if (= (preceding-char) ?&)
			    (setq ch "amp")
			)
		    )
		 )
		(backward-delete-char 1)
		(insert-string "&" ch)
)))))


(defun echo-file ()
  "Run this in batch mode to test streaming through emacs."
    (interactive)
    (message "$$$$$$$$$$$$$$$$$$$ REAL BEGINNING $$$$$$$$$$$$$$$$$$$")
    (while (not (eobp))
      (progn
	(setq d (dot))
	(end-of-line)
	(message "%s" (buffer-substring d (dot)))
	(beginning-of-line)
	(forward-line 1)
      )
    )
)

(defun unhtitle ()
    (interactive)
    (search-forward "<title>" nil t)
    (search-backward "<")
    (setq dot (dot))
    (search-forward "</title>" nil t)
    (next-line 1)
    (beginning-of-line)
    (kill-region dot (dot))
)

(defun convert-tbl
"Convert a troff tbl-style table to the equivalent html.  The current
implementation is limited to tbl tables with exactly one formatting row."
  (interactive)
  (while (search-forward "\n.TS" nil t)
    (convert-tlb1)
  )
)

(defun convert-tbl1
"Work doer for convert-tbl.  Context is end of .TS line"
  (interactive)
  (next-line 1)
  (end-of-line);
  (if (= (preceding-char) ?;))
)

(defun convert-header-footer (no-header)
"Convert the troff header ending in \"... end header\" to the approporate
latex header.  Add an \\end{document} to the end of the document."
    (interactive)
    (beginning-of-buffer)
    (setq d (dot))
    (search-forward "... end header\n" nil t)
    (kill-region d (dot))
    (if (not no-header)
      (progn
	(insert
	    (concat 
		"\\documentclass[titlepage]{article}\n"
		"\n"
		"\\input{psfig.sty}\n"
		"\\input{lists}\n"
		"\n"
		"% Next line for local printing only\n"
		"% \\setlength{\\topmargin}{1in}\n"
		"\n"
		"\\begin{document}\n"))

	(end-of-buffer)
	(insert "\n\\end {document}\n")
      )
      (delete-blank-lines)
    )
)

(defun convert-raw-latex-block ()
"Convert troff .(La ... .)La to just ... .  I.e., insert raw latex commands as
is"
    (interactive)
    (while (search-forward ".(La" nil t)
	(beginning-of-line)
	(kill-line 1)
	(search-forward ".)La")
	(beginning-of-line)
	(kill-line 1)
    )
)