summaryrefslogtreecommitdiff
path: root/math
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2006-10-11 18:12:39 +0000
committerPierre Schmitz <pierre@archlinux.de>2006-10-11 18:12:39 +0000
commit183851b06bd6c52f3cae5375f433da720d410447 (patch)
treea477257decbf3360127f6739c2f9d0ec57a03d39 /math
MediaWiki 1.7.1 wiederhergestellt
Diffstat (limited to 'math')
-rw-r--r--math/.htaccess1
-rw-r--r--math/.svnignore7
-rw-r--r--math/Makefile64
-rw-r--r--math/README107
-rw-r--r--math/TODO3
-rw-r--r--math/html.ml119
-rw-r--r--math/html.mli5
-rw-r--r--math/lexer.mll93
-rw-r--r--math/mathml.ml20
-rw-r--r--math/mathml.mli1
-rw-r--r--math/parser.mly103
-rw-r--r--math/render.ml33
-rw-r--r--math/render_info.mli20
-rw-r--r--math/tex.mli19
-rw-r--r--math/texutil.ml482
-rw-r--r--math/texutil.mli11
-rw-r--r--math/texvc.ml34
-rw-r--r--math/texvc_cgi.ml62
-rw-r--r--math/texvc_test.ml25
-rw-r--r--math/texvc_tex.ml3
-rw-r--r--math/util.ml17
21 files changed, 1229 insertions, 0 deletions
diff --git a/math/.htaccess b/math/.htaccess
new file mode 100644
index 00000000..3a428827
--- /dev/null
+++ b/math/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/math/.svnignore b/math/.svnignore
new file mode 100644
index 00000000..6aa96403
--- /dev/null
+++ b/math/.svnignore
@@ -0,0 +1,7 @@
+texvc
+texvc_test
+texvc_tex
+*.cmi
+*.cmx
+*.mli
+*~
diff --git a/math/Makefile b/math/Makefile
new file mode 100644
index 00000000..47c40f96
--- /dev/null
+++ b/math/Makefile
@@ -0,0 +1,64 @@
+OBJ=render_info.cmo tex.cmo texutil.cmo parser.cmo lexer.cmo texvc.cmo \
+render_info.cmx tex.cmx texutil.cmx parser.cmx lexer.cmx texvc.cmx \
+lexer.cmi parser.cmi render_info.cmi tex.cmi texutil.cmi texvc.cmi \
+lexer.o parser.o render_info.o tex.o texutil.o texvc.o \
+lexer.ml parser.ml parser.mli texvc texvc.bc texvc_test.cmo \
+texvc_test.cmx texvc_test.cmi texvc_test.o texvc_test util.o \
+util.cmo util.cmx util.cmi texvc_cgi.cmi texvc_cgi texvc_cgi.cmo \
+render.o render.cmi render.cmo render.cmx texvc_tex.cmx \
+texvc_tex.o texvc_tex.cmi texvc_tex html.cmi html.cmo html.cmx \
+html.o mathml.cmi mathml.cmo mathml.cmx mathml.o
+CGIPATH=-I /usr/lib/ocaml/cgi -I /usr/lib/ocaml/netstring -I /usr/lib/ocaml/pcre
+
+all: texvc texvc_test texvc_tex
+texvc.bc: util.cmo parser.cmo html.cmo mathml.cmo texutil.cmo render.cmo lexer.cmo texvc.cmo
+ ocamlc -o $@ unix.cma $^
+texvc: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx render.cmx lexer.cmx texvc.cmx
+ ocamlopt -o $@ unix.cmxa $^
+texvc_test: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx texvc_test.cmx
+ ocamlopt -o $@ $^
+texvc_tex: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx texvc_tex.cmx
+ ocamlopt -o $@ $^
+%.ml: %.mll
+ ocamllex $<
+%.mli %.ml: %.mly
+ ocamlyacc $<
+%.cmo: %.ml
+ ocamlc -c $<
+%.cmx: %.ml
+ ocamlopt -c $<
+%.cmi: %.mli
+ ocamlc -c $<
+texvc_cgi.cmo: texvc_cgi.ml
+ ocamlc -c $(CGIPATH) $<
+texvc_cgi: util.cmo parser.cmo texutil.cmo render.cmo lexer.cmo texvc_cgi.cmo
+ ocamlc -o $@ unix.cma $(CGIPATH) pcre.cma netstring.cma cgi.cma $^
+ chmod g-w $@
+clean:
+ rm -f $(OBJ)
+
+html.cmo: render_info.cmi tex.cmi util.cmo html.cmi
+html.cmx: render_info.cmi tex.cmi util.cmx html.cmi
+html.cmi: tex.cmi
+lexer.cmo: parser.cmi render_info.cmi tex.cmi texutil.cmi
+lexer.cmx: parser.cmx render_info.cmi tex.cmi texutil.cmx
+mathml.cmo: tex.cmi mathml.cmi
+mathml.cmx: tex.cmi mathml.cmi
+mathml.cmi: tex.cmi
+parser.cmo: render_info.cmi tex.cmi parser.cmi
+parser.cmx: render_info.cmi tex.cmi parser.cmi
+parser.cmi: render_info.cmi tex.cmi
+render.cmo: texutil.cmi util.cmo
+render.cmx: texutil.cmx util.cmx
+tex.cmi: render_info.cmi
+texutil.cmo: html.cmi parser.cmi render_info.cmi tex.cmi util.cmo texutil.cmi
+texutil.cmx: html.cmx parser.cmx render_info.cmi tex.cmi util.cmx texutil.cmi
+texutil.cmi: parser.cmi tex.cmi
+texvc.cmo: html.cmi lexer.cmo mathml.cmi parser.cmi render.cmo texutil.cmi util.cmo
+texvc.cmx: html.cmx lexer.cmx mathml.cmx parser.cmx render.cmx texutil.cmx util.cmx
+texvc_cgi.cmo: lexer.cmo parser.cmi render.cmo texutil.cmi util.cmo
+texvc_cgi.cmx: lexer.cmx parser.cmx render.cmx texutil.cmx util.cmx
+texvc_test.cmo: html.cmi lexer.cmo parser.cmi texutil.cmi util.cmo
+texvc_test.cmx: html.cmx lexer.cmx parser.cmx texutil.cmx util.cmx
+texvc_tex.cmo: lexer.cmo parser.cmi texutil.cmi util.cmo
+texvc_tex.cmx: lexer.cmx parser.cmx texutil.cmx util.cmx
diff --git a/math/README b/math/README
new file mode 100644
index 00000000..e58cbf04
--- /dev/null
+++ b/math/README
@@ -0,0 +1,107 @@
+== About texvc ==
+
+texvc takes LaTeX-compatible equations and produces formatted output in
+HTML, MathML, and (via LaTeX/dvips/ImageMagick) rasterized PNG images.
+Input data is parsed and scrutinized for safety, and the output includes
+an estimate of whether the code is simple enough that HTML rendering will
+look acceptable.
+
+The program was written by Tomasz Wegrzanowski for use with MediaWiki;
+it's included as part of the MediaWiki package (http://wikipedia.sf.net)
+and is under the GPL license.
+
+Please report bugs at: http://bugzilla.wikimedia.org/ (under "MediaWiki")
+
+== Setup ==
+
+=== Requirements ===
+
+OCaml 3.06 or later is required to compile texvc; this can be acquired
+from http://caml.inria.fr/ if your system doesn't have it available.
+
+The makefile requires GNU make.
+
+Rasterization is done via LaTeX, dvips, and ImageMagick. These need
+to be installed and in the PATH: latex, dvips, convert
+
+To work properly with rendering non-ASCII Unicode characters, a
+supplemental TeX package is needed (cjk-latex in Debian)
+
+=== Installation ===
+
+Run 'make' (or 'gmake' if GNU make is not your default make). This should
+produce the texvc executable.
+
+If you're using MediaWiki's install.php and have enabled $wgUseTeX in your
+LocalSettings.php, the installer will try to copy texvc into place, in the
+'math' subdirectory under where wiki.phtml is installed.
+
+
+== Usage ==
+
+Normally texvc is called from MediaWiki's Math.php modules and everything
+Just Works. It can be run manually for testing or for use in another app.
+
+=== Command-line parameters ===
+
+ texvc <temp directory> <output directory> <TeX code> <encoding>
+
+Be sure to properly quote the TeX code!
+
+Example:
+
+ texvc /home/wiki/tmp /home/wiki/math "y=x+2" iso-8859-1
+
+=== Output format ===
+
+Status codes and HTML/MathML transformations are returned on stdout.
+A rasterized PNG file will be written to the output directory, named
+for the MD5 hash code.
+
+texvc output format is like this:
+ +%5 ok, but not html or mathml
+ c%5%h ok, conservative html, no mathml
+ m%5%h ok, moderate html, no mathml
+ l%5%h ok, liberal html, no mathml
+ C%5%h\0%m ok, conservative html, with mathml
+ M%5%h\0%m ok, moderate html, with mathml
+ L%5%h\0%m ok, liberal html, with mathml
+ X%5%m ok, no html, with mathml
+ S syntax error
+ E lexing error
+ F%s unknown function %s
+ - other error
+
+ \0 - null character
+ %5 - md5, 32 hex characters
+ %h - html code, without \0 characters
+ %m - mathml code, without \0 characters
+
+
+== Troubleshooting ==
+
+Unforunately, many error conditions with rasterization are not well reported.
+texvc will return as though everything is successful, and the only obvious
+sign of problems for the user is a big X on a wiki page where an equation
+should be.
+
+Try running texvc from the command line to ensure that the software it relies
+upon is all set up.
+
+Ensure that the temporary and math directories exist and can be written to by
+the user account the web server runs under; if you don't control the server,
+you may have to make them world-writable.
+
+== Hacking ==
+
+Before you start hacking on the math package its good to know the workflow,
+which is basically:
+
+1. texvc gets called by includes/Math.php (check out the line begining with "$cmd")
+2. texvc does its magic, which is basically to check for invalid latex code.
+3. texvc takes the user input if valid and creates a latex file containing it, see
+ get_preface in texutil.ml
+4. latex(1) gets called to create a .dvi file, then a .ps file is created from the
+ .dvi file using dvips(1), and finally convert(1) creates a .png file from
+ the .ps file. See render.ml for this process (commenting out the removal of
+ the temporary file is useful for debugging).
diff --git a/math/TODO b/math/TODO
new file mode 100644
index 00000000..bd8d1f4f
--- /dev/null
+++ b/math/TODO
@@ -0,0 +1,3 @@
+* It would be better if PNGs were transparent
+* CJK support
+* Documentation, in particular about instalation of Latex support for Unicode
diff --git a/math/html.ml b/math/html.ml
new file mode 100644
index 00000000..6a24b114
--- /dev/null
+++ b/math/html.ml
@@ -0,0 +1,119 @@
+open Render_info
+open Tex
+open Util
+
+exception Too_difficult_for_html
+type context = CTX_NORMAL | CTX_IT | CTX_RM
+type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL
+
+let conservativeness = ref CONSERVATIVE
+let html_liberal () = conservativeness := LIBERAL
+let html_moderate () = if !conservativeness = CONSERVATIVE then conservativeness := MODERATE else ()
+
+
+let new_ctx = function
+ FONTFORCE_IT -> CTX_IT
+ | FONTFORCE_RM -> CTX_RM
+let font_render lit = function
+ (_, FONT_UFH) -> lit
+ | (_, FONT_UF) -> lit
+ | (CTX_IT,FONT_RTI) -> raise Too_difficult_for_html
+ | (_, FONT_RTI) -> lit
+ | (CTX_IT,FONT_RM) -> "<i>"^lit^"</i>"
+ | (_, FONT_RM) -> lit
+ | (CTX_RM,FONT_IT) -> lit
+ | (_, FONT_IT) -> "<i>"^lit^"</i>"
+
+let rec html_render_flat ctx = function
+ TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); (font_render sh (ctx,ft))^html_render_flat ctx r)
+ | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r
+ | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r
+ | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); (font_render sh (ctx,ft))^html_render_flat ctx r)
+ | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); sh^html_render_flat ctx r)
+ | TEX_FUN1hl (_,(f1,f2),a)::r -> f1^(html_render_flat ctx [a])^f2^html_render_flat ctx r
+ | TEX_FUN1hf (_,ff,a)::r -> (html_render_flat (new_ctx ff) [a])^html_render_flat ctx r
+ | TEX_DECLh (_,ff,a)::r -> (html_render_flat (new_ctx ff) a)^html_render_flat ctx r
+ | TEX_CURLY ls::r -> html_render_flat ctx (ls @ r)
+ | TEX_DQ (a,b)::r -> (html_liberal ();
+ let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+ true, s -> raise Too_difficult_for_html
+ | false, s -> s^"<sub>"^bs^"</sub>")^html_render_flat ctx r
+ | TEX_UQ (a,b)::r -> (html_liberal ();
+ let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+ true, s -> raise Too_difficult_for_html
+ | false, s -> s^"<sup>"^bs^"</sup>")^html_render_flat ctx r
+ | TEX_FQ (a,b,c)::r -> (html_liberal ();
+ (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in
+ match html_render_size ctx a with
+ true, s -> raise Too_difficult_for_html
+ | false, s -> s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>")^html_render_flat ctx r)
+ | TEX_BOX (_,s)::r -> s^html_render_flat ctx r
+ | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html
+ | TEX_FUN1 _::_ -> raise Too_difficult_for_html
+ | TEX_FUN2 _::_ -> raise Too_difficult_for_html
+ | TEX_FUN2h _::_ -> raise Too_difficult_for_html
+ | TEX_FUN2sq _::_ -> raise Too_difficult_for_html
+ | TEX_INFIX _::_ -> raise Too_difficult_for_html
+ | TEX_INFIXh _::_ -> raise Too_difficult_for_html
+ | TEX_MATRIX _::_ -> raise Too_difficult_for_html
+ | TEX_LR _::_ -> raise Too_difficult_for_html
+ | TEX_BIG _::_ -> raise Too_difficult_for_html
+ | [] -> ""
+and html_render_size ctx = function
+ TEX_LITERAL (HTMLABLE_BIG (_,sh)) -> true,sh
+ | x -> false,html_render_flat ctx [x]
+
+let rec html_render_deep ctx = function
+ TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r)
+ | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r)
+ | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r
+ | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r
+ | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); ("",sh,"")::html_render_deep ctx r)
+ | TEX_FUN2h (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r)
+ | TEX_INFIXh (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r)
+ | TEX_CURLY ls::r -> html_render_deep ctx (ls @ r)
+ | TEX_DQ (a,b)::r -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+ true, s -> "","<font size='+2'>"^s^"</font>",bs
+ | false, s -> "",(s^"<sub>"^bs^"</sub>"),"")::html_render_deep ctx r
+ | TEX_UQ (a,b)::r -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+ true, s -> bs,"<font size='+2'>"^s^"</font>",""
+ | false, s -> "",(s^"<sup>"^bs^"</sup>"),"")::html_render_deep ctx r
+ | TEX_FQ (a,b,c)::r -> (html_liberal ();
+ (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in
+ match html_render_size ctx a with
+ true, s -> (cs,"<font size='+2'>"^s^"</font>",bs)
+ | false, s -> ("",(s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>"),""))::html_render_deep ctx r)
+ | TEX_FUN1hl (_,(f1,f2),a)::r -> ("",f1,"")::(html_render_deep ctx [a]) @ ("",f2,"")::html_render_deep ctx r
+ | TEX_FUN1hf (_,ff,a)::r -> (html_render_deep (new_ctx ff) [a]) @ html_render_deep ctx r
+ | TEX_DECLh (_,ff,a)::r -> (html_render_deep (new_ctx ff) a) @ html_render_deep ctx r
+ | TEX_BOX (_,s)::r -> ("",s,"")::html_render_deep ctx r
+ | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html
+ | TEX_FUN1 _::_ -> raise Too_difficult_for_html
+ | TEX_FUN2 _::_ -> raise Too_difficult_for_html
+ | TEX_FUN2sq _::_ -> raise Too_difficult_for_html
+ | TEX_INFIX _::_ -> raise Too_difficult_for_html
+ | TEX_MATRIX _::_ -> raise Too_difficult_for_html
+ | TEX_LR _::_ -> raise Too_difficult_for_html
+ | TEX_BIG _::_ -> raise Too_difficult_for_html
+ | [] -> []
+
+let rec html_render_table = function
+ sf,u,d,("",a,"")::("",b,"")::r -> html_render_table (sf,u,d,(("",a^b,"")::r))
+ | sf,u,d,(("",a,"") as c)::r -> html_render_table (c::sf,u,d,r)
+ | sf,u,d,((_,a,"") as c)::r -> html_render_table (c::sf,true,d,r)
+ | sf,u,d,(("",a,_) as c)::r -> html_render_table (c::sf,u,true,r)
+ | sf,u,d,((_,a,_) as c)::r -> html_render_table (c::sf,true,true,r)
+ | sf,false,false,[] -> mapjoin (function (u,m,d) -> m) (List.rev sf)
+ | sf,true,false,[] -> let ustr,mstr = List.fold_left (fun (us,ms) (u,m,d) -> (us^"<td>"^u^"</td>",ms^"<td>"^u^"</td>"))
+ ("","") (List.rev sf) in
+ "<table><tr align='center' valign='bottom'>" ^ ustr ^ "</tr><tr align='center'>" ^ mstr ^ "</tr></table>"
+ | sf,false,true,[] -> let mstr,dstr = List.fold_left (fun (ms,ds) (u,m,d) -> (ms^"<td>"^m^"</td>",ds^"<td>"^d^"</td>"))
+ ("","") (List.rev sf) in
+ "<table><tr align='center'>" ^ mstr ^ "</tr><tr align='center' valign='top'>" ^ dstr ^ "</tr></table>"
+ | sf,true,true,[] -> let ustr,mstr,dstr = List.fold_left (fun (us,ms,ds) (u,m,d) ->
+ (us^"<td>"^u^"</td>",ms^"<td>"^m^"</td>",ds^"<td>"^d^"</td>")) ("","","") (List.rev sf) in
+ "<table><tr align='center' valign='bottom'>" ^ ustr ^ "</tr><tr align='center'>" ^ mstr ^ "</tr><tr align='center' valign='top'>" ^ dstr ^ "</tr></table>"
+
+let html_render tree = html_render_table ([],false,false,html_render_deep CTX_NORMAL tree)
+
+let render tree = try Some (html_render tree) with _ -> None
diff --git a/math/html.mli b/math/html.mli
new file mode 100644
index 00000000..00b41cf4
--- /dev/null
+++ b/math/html.mli
@@ -0,0 +1,5 @@
+val render : Tex.t list -> string option
+val html_render : Tex.t list -> string
+
+type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL
+val conservativeness : conservativeness_t ref
diff --git a/math/lexer.mll b/math/lexer.mll
new file mode 100644
index 00000000..e5bb1ddf
--- /dev/null
+++ b/math/lexer.mll
@@ -0,0 +1,93 @@
+{
+ open Parser
+ open Render_info
+ open Tex
+}
+let space = [' ' '\t' '\n' '\r']
+let alpha = ['a'-'z' 'A'-'Z']
+let literal_id = ['a'-'z' 'A'-'Z']
+let literal_mn = ['0'-'9']
+let literal_uf_lt = [',' ':' ';' '?' '!' '\'']
+let delimiter_uf_lt = ['(' ')' '.']
+let literal_uf_op = ['+' '-' '*' '=']
+let delimiter_uf_op = ['/' '|']
+let boxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' ' '\128'-'\255']
+let aboxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' ']
+
+rule token = parse
+ space + { token lexbuf }
+ | "\\mbox" space * '{' aboxchars + '}'
+ { let str = Lexing.lexeme lexbuf in
+ let n = String.index str '{' + 1 in
+ BOX ("\\mbox", String.sub str n (String.length str - n - 1)) }
+ | "\\hbox" space * '{' aboxchars + '}'
+ { let str = Lexing.lexeme lexbuf in
+ let n = String.index str '{' + 1 in
+ BOX ("\\hbox", String.sub str n (String.length str - n - 1)) }
+ | "\\vbox" space * '{' aboxchars + '}'
+ { let str = Lexing.lexeme lexbuf in
+ let n = String.index str '{' + 1 in
+ BOX ("\\vbox", String.sub str n (String.length str - n - 1)) }
+ | "\\mbox" space * '{' boxchars + '}'
+ { let str = Lexing.lexeme lexbuf in
+ let n = String.index str '{' + 1 in
+ Texutil.tex_use_nonascii();
+ BOX ("\\mbox", String.sub str n (String.length str - n - 1)) }
+ | "\\hbox" space * '{' boxchars + '}'
+ { let str = Lexing.lexeme lexbuf in
+ let n = String.index str '{' + 1 in
+ Texutil.tex_use_nonascii();
+ BOX ("\\hbox", String.sub str n (String.length str - n - 1)) }
+ | "\\vbox" space * '{' boxchars + '}'
+ { let str = Lexing.lexeme lexbuf in
+ let n = String.index str '{' + 1 in
+ Texutil.tex_use_nonascii();
+ BOX ("\\vbox", String.sub str n (String.length str - n - 1)) }
+ | literal_id { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_IT, str,str,MI,str)) }
+ | literal_mn { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_RM, str,str,MN,str)) }
+ | literal_uf_lt { let str = Lexing.lexeme lexbuf in LITERAL (HTMLABLEC (FONT_UFH, str,str)) }
+ | delimiter_uf_lt { let str = Lexing.lexeme lexbuf in DELIMITER (HTMLABLEC (FONT_UFH, str,str)) }
+ | "-" { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH,"-"," &minus; ",MO,str))}
+ | literal_uf_op { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) }
+ | delimiter_uf_op { let str = Lexing.lexeme lexbuf in DELIMITER (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) }
+ | "\\" alpha + { Texutil.find (Lexing.lexeme lexbuf) }
+ | "\\sqrt" space * "[" { FUN_AR1opt "\\sqrt" }
+ | "\\," { LITERAL (HTMLABLE (FONT_UF, "\\,","&nbsp;")) }
+ | "\\ " { LITERAL (HTMLABLE (FONT_UF, "\\ ","&nbsp;")) }
+ | "\\;" { LITERAL (HTMLABLE (FONT_UF, "\\;","&nbsp;")) }
+ | "\\!" { LITERAL (TEX_ONLY "\\!") }
+ | "\\{" { DELIMITER (HTMLABLEC(FONT_UFH,"\\{","{")) }
+ | "\\}" { DELIMITER (HTMLABLEC(FONT_UFH,"\\}","}")) }
+ | "\\|" { DELIMITER (HTMLABLE (FONT_UFH,"\\|","||")) }
+ | "\\_" { LITERAL (HTMLABLEC(FONT_UFH,"\\_","_")) }
+ | "\\#" { LITERAL (HTMLABLE (FONT_UFH,"\\#","#")) }
+ | "\\%" { LITERAL (HTMLABLE (FONT_UFH,"\\%","%")) }
+ | "\\$" { LITERAL (HTMLABLE (FONT_UFH,"\\$","$")) }
+ | "&" { NEXT_CELL }
+ | "\\\\" { NEXT_ROW }
+ | "\\begin{matrix}" { Texutil.tex_use_ams(); BEGIN__MATRIX }
+ | "\\end{matrix}" { END__MATRIX }
+ | "\\begin{pmatrix}" { Texutil.tex_use_ams(); BEGIN_PMATRIX }
+ | "\\end{pmatrix}" { END_PMATRIX }
+ | "\\begin{bmatrix}" { Texutil.tex_use_ams(); BEGIN_BMATRIX }
+ | "\\end{bmatrix}" { END_BMATRIX }
+ | "\\begin{Bmatrix}" { Texutil.tex_use_ams(); BEGIN_BBMATRIX }
+ | "\\end{Bmatrix}" { END_BBMATRIX }
+ | "\\begin{vmatrix}" { Texutil.tex_use_ams(); BEGIN_VMATRIX }
+ | "\\end{vmatrix}" { END_VMATRIX }
+ | "\\begin{Vmatrix}" { Texutil.tex_use_ams(); BEGIN_VVMATRIX }
+ | "\\end{Vmatrix}" { END_VVMATRIX }
+ | "\\begin{cases}" { Texutil.tex_use_ams(); BEGIN_CASES }
+ | "\\end{cases}" { END_CASES }
+ | '>' { LITERAL (HTMLABLEC(FONT_UFH,">"," &gt; ")) }
+ | '<' { LITERAL (HTMLABLEC(FONT_UFH,"<"," &lt; ")) }
+ | '%' { LITERAL (HTMLABLEC(FONT_UFH,"\\%","%")) }
+ | '$' { LITERAL (HTMLABLEC(FONT_UFH,"\\$","$")) }
+ | '~' { LITERAL (HTMLABLE (FONT_UF, "~","&nbsp;")) }
+ | '[' { DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) }
+ | ']' { SQ_CLOSE }
+ | '{' { CURLY_OPEN }
+ | '}' { CURLY_CLOSE }
+ | '^' { SUP }
+ | '_' { SUB }
+ | eof { EOF }
diff --git a/math/mathml.ml b/math/mathml.ml
new file mode 100644
index 00000000..b6c76af2
--- /dev/null
+++ b/math/mathml.ml
@@ -0,0 +1,20 @@
+open Tex
+open Render_info
+
+type t = TREE_MN of string | TREE_MO of string | TREE_MI of string
+
+let rec make_mathml_tree = function
+ TREE_MN a::otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,b))::itr -> make_mathml_tree(TREE_MN (a^b)::otr,itr)
+ | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,a))::itr -> make_mathml_tree(TREE_MN a::otr,itr)
+ | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MO,a))::itr -> make_mathml_tree(TREE_MO a::otr,itr)
+ | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MI,a))::itr -> make_mathml_tree(TREE_MI a::otr,itr)
+ | otr,TEX_CURLY(crl)::itr -> make_mathml_tree(otr,crl@itr)
+ | otr,[] -> List.rev otr
+ | _ -> failwith "failed to render mathml"
+
+let render_mathml_tree = function
+ TREE_MN s -> "<mn>"^s^"</mn>"
+ | TREE_MI s -> "<mi>"^s^"</mi>"
+ | TREE_MO s -> "<mo>"^s^"</mo>"
+
+let render tree = try Some (Util.mapjoin render_mathml_tree (make_mathml_tree ([],tree))) with _ -> None
diff --git a/math/mathml.mli b/math/mathml.mli
new file mode 100644
index 00000000..fcc2cd4c
--- /dev/null
+++ b/math/mathml.mli
@@ -0,0 +1 @@
+val render : Tex.t list -> string option
diff --git a/math/parser.mly b/math/parser.mly
new file mode 100644
index 00000000..4787db37
--- /dev/null
+++ b/math/parser.mly
@@ -0,0 +1,103 @@
+%{
+ open Tex
+ open Render_info
+
+ let sq_close_ri = HTMLABLEC(FONT_UFH,"]", "]")
+%}
+%token <Render_info.t> LITERAL DELIMITER
+%token <string> FUN_AR2 FUN_INFIX FUN_AR1 DECL FUN_AR1opt BIG
+%token <string*string> BOX
+%token <string*(string*string)> FUN_AR1hl
+%token <string*Render_info.font_force> FUN_AR1hf DECLh
+%token <string*(Tex.t->Tex.t->string*string*string)> FUN_AR2h
+%token <string*(Tex.t list->Tex.t list->string*string*string)> FUN_INFIXh
+%token EOF CURLY_OPEN CURLY_CLOSE SUB SUP SQ_CLOSE NEXT_CELL NEXT_ROW
+%token BEGIN__MATRIX BEGIN_PMATRIX BEGIN_BMATRIX BEGIN_BBMATRIX BEGIN_VMATRIX BEGIN_VVMATRIX BEGIN_CASES
+%token END__MATRIX END_PMATRIX END_BMATRIX END_BBMATRIX END_VMATRIX END_VVMATRIX END_CASES
+%token LEFT RIGHT
+
+%type <Tex.t list> tex_expr
+%start tex_expr
+
+%%
+tex_expr:
+ expr EOF { $1 }
+ | ne_expr FUN_INFIX ne_expr EOF
+ { [TEX_INFIX($2,$1,$3)] }
+ | ne_expr FUN_INFIXh ne_expr EOF
+ { let t,h=$2 in [TEX_INFIXh(t,h,$1,$3)] }
+expr:
+ /* */ { [] }
+ | ne_expr { $1 }
+ne_expr:
+ lit_aq expr { $1 :: $2 }
+ | litsq_aq expr { $1 :: $2 }
+ | DECLh expr { let t,h = $1 in [TEX_DECLh(t,h,$2)] }
+litsq_aq:
+ litsq_zq { $1 }
+ | litsq_dq { let base,downi = $1 in TEX_DQ(base,downi) }
+ | litsq_uq { let base,upi = $1 in TEX_UQ(base,upi)}
+ | litsq_fq { $1 }
+litsq_fq:
+ litsq_dq SUP lit { let base,downi = $1 in TEX_FQ(base,downi,$3) }
+ | litsq_uq SUB lit { let base,upi = $1 in TEX_FQ(base,$3,upi) }
+litsq_uq:
+ litsq_zq SUP lit { $1,$3 }
+litsq_dq:
+ litsq_zq SUB lit { $1,$3 }
+litsq_zq:
+ | SQ_CLOSE { TEX_LITERAL sq_close_ri }
+expr_nosqc:
+ /* */ { [] }
+ | lit_aq expr_nosqc { $1 :: $2 }
+lit_aq:
+ lit { $1 }
+ | lit_dq { let base,downi = $1 in TEX_DQ(base,downi) }
+ | lit_uq { let base,upi = $1 in TEX_UQ(base,upi)}
+ | lit_fq { $1 }
+lit_fq:
+ lit_dq SUP lit { let base,downi = $1 in TEX_FQ(base,downi,$3) }
+ | lit_uq SUB lit { let base,upi = $1 in TEX_FQ(base,$3,upi) }
+lit_uq:
+ lit SUP lit { $1,$3 }
+lit_dq:
+ lit SUB lit { $1,$3 }
+left:
+ LEFT DELIMITER { $2 }
+ | LEFT SQ_CLOSE { sq_close_ri }
+right:
+ RIGHT DELIMITER { $2 }
+ | RIGHT SQ_CLOSE { sq_close_ri }
+lit:
+ LITERAL { TEX_LITERAL $1 }
+ | DELIMITER { TEX_LITERAL $1 }
+ | BIG DELIMITER { TEX_BIG ($1,$2) }
+ | BIG SQ_CLOSE { TEX_BIG ($1,sq_close_ri) }
+ | left expr right { TEX_LR ($1,$3,$2) }
+ | FUN_AR1 lit { TEX_FUN1($1,$2) }
+ | FUN_AR1hl lit { let t,h=$1 in TEX_FUN1hl(t,h,$2) }
+ | FUN_AR1hf lit { let t,h=$1 in TEX_FUN1hf(t,h,$2) }
+ | FUN_AR1opt expr_nosqc SQ_CLOSE lit { TEX_FUN2sq($1,TEX_CURLY $2,$4) }
+ | FUN_AR2 lit lit { TEX_FUN2($1,$2,$3) }
+ | FUN_AR2h lit lit { let t,h=$1 in TEX_FUN2h(t,h,$2,$3) }
+ | BOX { let bt,s = $1 in TEX_BOX (bt,s) }
+ | CURLY_OPEN expr CURLY_CLOSE
+ { TEX_CURLY $2 }
+ | CURLY_OPEN ne_expr FUN_INFIX ne_expr CURLY_CLOSE
+ { TEX_INFIX($3,$2,$4) }
+ | CURLY_OPEN ne_expr FUN_INFIXh ne_expr CURLY_CLOSE
+ { let t,h=$3 in TEX_INFIXh(t,h,$2,$4) }
+ | BEGIN__MATRIX matrix END__MATRIX { TEX_MATRIX ("matrix", $2) }
+ | BEGIN_PMATRIX matrix END_PMATRIX { TEX_MATRIX ("pmatrix", $2) }
+ | BEGIN_BMATRIX matrix END_BMATRIX { TEX_MATRIX ("bmatrix", $2) }
+ | BEGIN_BBMATRIX matrix END_BBMATRIX { TEX_MATRIX ("Bmatrix", $2) }
+ | BEGIN_VMATRIX matrix END_VMATRIX { TEX_MATRIX ("vmatrix", $2) }
+ | BEGIN_VVMATRIX matrix END_VVMATRIX { TEX_MATRIX ("Vmatrix", $2) }
+ | BEGIN_CASES matrix END_CASES { TEX_MATRIX ("cases", $2) }
+matrix:
+ line { [$1] }
+ | line NEXT_ROW matrix { $1::$3 }
+line:
+ expr { [$1] }
+ | expr NEXT_CELL line { $1::$3 }
+;;
diff --git a/math/render.ml b/math/render.ml
new file mode 100644
index 00000000..f070a91e
--- /dev/null
+++ b/math/render.ml
@@ -0,0 +1,33 @@
+let cmd_dvips tmpprefix = "dvips -R -E " ^ tmpprefix ^ ".dvi -f >" ^ tmpprefix ^ ".ps"
+let cmd_latex tmpprefix = "latex " ^ tmpprefix ^ ".tex >/dev/null"
+(* Putting -transparent white in converts arguments will sort-of give you transperancy *)
+let cmd_convert tmpprefix finalpath = "convert -quality 100 -density 120 " ^ tmpprefix ^ ".ps " ^ finalpath ^ " >/dev/null 2>/dev/null"
+
+exception ExternalCommandFailure of string
+
+let render tmppath finalpath outtex md5 =
+ let tmpprefix0 = (string_of_int (Unix.getpid ()))^"_"^md5 in
+ let tmpprefix = (tmppath^"/"^tmpprefix0) in
+ let unlink_all () =
+ begin
+ (* Commenting this block out will aid in debugging *)
+ Sys.remove (tmpprefix ^ ".dvi");
+ Sys.remove (tmpprefix ^ ".aux");
+ Sys.remove (tmpprefix ^ ".log");
+ Sys.remove (tmpprefix ^ ".tex");
+ Sys.remove (tmpprefix ^ ".ps");
+ end in
+ let f = (Util.open_out_unless_exists (tmpprefix ^ ".tex")) in
+ begin
+ output_string f (Texutil.get_preface ());
+ output_string f outtex;
+ output_string f (Texutil.get_footer ());
+ close_out f;
+ if Util.run_in_other_directory tmppath (cmd_latex tmpprefix0) != 0
+ then (unlink_all (); raise (ExternalCommandFailure "latex"))
+ else if (Sys.command (cmd_dvips tmpprefix) != 0)
+ then (unlink_all (); raise (ExternalCommandFailure "dvips"))
+ else if (Sys.command (cmd_convert tmpprefix (finalpath^"/"^md5^".png")) != 0)
+ then (unlink_all (); raise (ExternalCommandFailure "convert"))
+ else unlink_all ()
+ end
diff --git a/math/render_info.mli b/math/render_info.mli
new file mode 100644
index 00000000..d5e7fde9
--- /dev/null
+++ b/math/render_info.mli
@@ -0,0 +1,20 @@
+type font_force =
+ FONTFORCE_IT
+ | FONTFORCE_RM
+type font_class =
+ FONT_IT (* IT default, may be forced to be RM *)
+ | FONT_RM (* RM default, may be forced to be IT *)
+ | FONT_UF (* not affected by IT/RM setting *)
+ | FONT_RTI (* RM - any, IT - not available in HTML *)
+ | FONT_UFH (* in TeX UF, in HTML RM *)
+type math_class =
+ MN
+ | MI
+ | MO
+type t =
+ HTMLABLEC of font_class * string * string
+ | HTMLABLEM of font_class * string * string
+ | HTMLABLE of font_class * string * string
+ | MHTMLABLEC of font_class * string * string * math_class * string
+ | HTMLABLE_BIG of string * string
+ | TEX_ONLY of string
diff --git a/math/tex.mli b/math/tex.mli
new file mode 100644
index 00000000..9e6013df
--- /dev/null
+++ b/math/tex.mli
@@ -0,0 +1,19 @@
+type t =
+ TEX_LITERAL of Render_info.t
+ | TEX_CURLY of t list
+ | TEX_FQ of t * t * t
+ | TEX_DQ of t * t
+ | TEX_UQ of t * t
+ | TEX_LR of Render_info.t * Render_info.t * t list
+ | TEX_BOX of string * string
+ | TEX_BIG of string * Render_info.t
+ | TEX_FUN1 of string * t
+ | TEX_FUN2 of string * t * t
+ | TEX_INFIX of string * t list * t list
+ | TEX_FUN2sq of string * t * t
+ | TEX_FUN1hl of string * (string * string) * t
+ | TEX_FUN1hf of string * Render_info.font_force * t
+ | TEX_FUN2h of string * (t -> t -> string * string * string) * t * t
+ | TEX_INFIXh of string * (t list -> t list -> string * string * string) * t list * t list
+ | TEX_MATRIX of string * t list list list
+ | TEX_DECLh of string * Render_info.font_force * t list
diff --git a/math/texutil.ml b/math/texutil.ml
new file mode 100644
index 00000000..f7678e34
--- /dev/null
+++ b/math/texutil.ml
@@ -0,0 +1,482 @@
+open Parser
+open Render_info
+open Tex
+open Util
+
+let tex_part = function
+ HTMLABLE (_,t,_) -> t
+ | HTMLABLEM (_,t,_) -> t
+ | HTMLABLEC (_,t,_) -> t
+ | MHTMLABLEC (_,t,_,_,_) -> t
+ | HTMLABLE_BIG (t,_) -> t
+ | TEX_ONLY t -> t
+let rec render_tex = function
+ TEX_FQ (a,b,c) -> (render_tex a) ^ "_{" ^ (render_tex b) ^ "}^{" ^ (render_tex c) ^ "}"
+ | TEX_DQ (a,b) -> (render_tex a) ^ "_{" ^ (render_tex b) ^ "}"
+ | TEX_UQ (a,b) -> (render_tex a) ^ "^{" ^ (render_tex b) ^ "}"
+ | TEX_LITERAL s -> tex_part s
+ | TEX_FUN1 (f,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}"
+ | TEX_FUN1hl (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}"
+ | TEX_FUN1hf (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}"
+ | TEX_DECLh (f,_,a) -> "{" ^ f ^ "{" ^ (mapjoin render_tex a) ^ "}}"
+ | TEX_FUN2 (f,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}"
+ | TEX_FUN2h (f,_,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}"
+ | TEX_FUN2sq (f,a,b) -> "{" ^ f ^ "[ " ^ (render_tex a) ^ "]" ^ (render_tex b) ^ "}"
+ | TEX_CURLY (tl) -> "{" ^ (mapjoin render_tex tl) ^ "}"
+ | TEX_INFIX (s,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}"
+ | TEX_INFIXh (s,_,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}"
+ | TEX_BOX (bt,s) -> "{"^bt^"{" ^ s ^ "}}"
+ | TEX_BIG (bt,d) -> "{"^bt^(tex_part d)^"}"
+ | TEX_MATRIX (t,rows) -> "{\\begin{"^t^"}"^(mapjoine "\\\\" (mapjoine "&" (mapjoin render_tex)) rows)^"\\end{"^t^"}}"
+ | TEX_LR (l,r,tl) -> "\\left "^(tex_part l)^(mapjoin render_tex tl)^"\\right "^(tex_part r)
+
+(* Dynamic loading*)
+type encoding_t = LATIN1 | LATIN2 | UTF8
+
+let modules_ams = ref false
+let modules_nonascii = ref false
+let modules_encoding = ref UTF8
+let modules_color = ref false
+
+let tex_use_ams () = modules_ams := true
+let tex_use_nonascii () = modules_nonascii := true
+let tex_use_color () = modules_color := true
+let tex_mod_reset () = (modules_ams := false; modules_nonascii := false; modules_encoding := UTF8; modules_color := false)
+
+let get_encoding = function
+ UTF8 -> "\\usepackage{ucs}\n\\usepackage[utf8]{inputenc}\n"
+ | LATIN1 -> "\\usepackage[latin1]{inputenc}\n"
+ | LATIN2 -> "\\usepackage[latin2]{inputenc}\n"
+
+let get_preface () = "\\nonstopmode\n\\documentclass[12pt]{article}\n" ^
+ (if !modules_nonascii then get_encoding !modules_encoding else "") ^
+ (if !modules_ams then "\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n" else "") ^
+ (if !modules_color then "\\usepackage[dvips,usenames]{color}\n" else "") ^
+ "\\pagestyle{empty}\n\\begin{document}\n$$\n"
+let get_footer () = "\n$$\n\\end{document}\n"
+
+let set_encoding = function
+ "ISO-8859-1" -> modules_encoding := LATIN1
+ | "iso-8859-1" -> modules_encoding := LATIN1
+ | "ISO-8859-2" -> modules_encoding := LATIN2
+ | _ -> modules_encoding := UTF8
+
+(* Turn that into hash table lookup *)
+exception Illegal_tex_function of string
+
+let find = function
+ "\\alpha" -> LITERAL (HTMLABLEC (FONT_UF, "\\alpha ", "&alpha;"))
+ | "\\Alpha" -> LITERAL (HTMLABLEC (FONT_RTI, "A", "&Alpha;"))
+ | "\\beta" -> LITERAL (HTMLABLEC (FONT_UF, "\\beta ", "&beta;"))
+ | "\\Beta" -> LITERAL (HTMLABLEC (FONT_RTI, "B", "&Beta;"))
+ | "\\gamma" -> LITERAL (HTMLABLEC (FONT_UF, "\\gamma ", "&gamma;"))
+ | "\\Gamma" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Gamma ", "&Gamma;"))
+ | "\\delta" -> LITERAL (HTMLABLEC (FONT_UF, "\\delta ", "&delta;"))
+ | "\\Delta" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Delta ", "&Delta;"))
+ | "\\epsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\epsilon ", "&epsilon;"))
+ | "\\Epsilon" -> LITERAL (HTMLABLEC (FONT_RTI, "E", "&Epsilon;"))
+ | "\\varepsilon" -> LITERAL (TEX_ONLY "\\varepsilon ")
+ | "\\zeta" -> LITERAL (HTMLABLEC (FONT_UF, "\\zeta ", "&zeta;"))
+ | "\\Zeta" -> LITERAL (HTMLABLEC (FONT_RTI, "Z", "&Zeta;"))
+ | "\\eta" -> LITERAL (HTMLABLEC (FONT_UF, "\\eta ", "&eta;"))
+ | "\\Eta" -> LITERAL (HTMLABLEC (FONT_RTI, "H", "&Eta;"))
+ | "\\theta" -> LITERAL (HTMLABLEC (FONT_UF, "\\theta ", "&theta;"))
+ | "\\Theta" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Theta ", "&Theta;"))
+ | "\\vartheta" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "&thetasym;"))
+ | "\\thetasym" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "&thetasym;"))
+ | "\\iota" -> LITERAL (HTMLABLEC (FONT_UF, "\\iota ", "&iota;"))
+ | "\\Iota" -> LITERAL (HTMLABLEC (FONT_RTI, "I", "&Iota;"))
+ | "\\kappa" -> LITERAL (HTMLABLEC (FONT_UF, "\\kappa ", "&kappa;"))
+ | "\\Kappa" -> LITERAL (HTMLABLEC (FONT_RTI, "K", "&Kappa;"))
+ | "\\lambda" -> LITERAL (HTMLABLEC (FONT_UF, "\\lambda ", "&lambda;"))
+ | "\\Lambda" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Lambda ", "&Lambda;"))
+ | "\\mu" -> LITERAL (HTMLABLEC (FONT_UF, "\\mu ", "&mu;"))
+ | "\\Mu" -> LITERAL (HTMLABLEC (FONT_RTI, "M", "&Mu;"))
+ | "\\nu" -> LITERAL (HTMLABLEC (FONT_UF, "\\nu ", "&nu;"))
+ | "\\Nu" -> LITERAL (HTMLABLEC (FONT_RTI, "N", "&Nu;"))
+ | "\\pi" -> LITERAL (HTMLABLEC (FONT_UF, "\\pi ", "&pi;"))
+ | "\\Pi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Pi ", "&Pi;"))
+ | "\\varpi" -> LITERAL (TEX_ONLY "\\varpi ")
+ | "\\rho" -> LITERAL (HTMLABLEC (FONT_UF, "\\rho ", "&rho;"))
+ | "\\Rho" -> LITERAL (HTMLABLEC (FONT_RTI, "P", "&Rho;"))
+ | "\\varrho" -> LITERAL (TEX_ONLY "\\varrho ")
+ | "\\sim" -> LITERAL (HTMLABLEC (FONT_UF, "\\sim ", "&tilde;"))
+ | "\\sigma" -> LITERAL (HTMLABLEC (FONT_UF, "\\sigma ", "&sigma;"))
+ | "\\Sigma" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Sigma ", "&Sigma;"))
+ | "\\varsigma" -> LITERAL (TEX_ONLY "\\varsigma ")
+ | "\\tau" -> LITERAL (HTMLABLEC (FONT_UF, "\\tau ", "&tau;"))
+ | "\\Tau" -> LITERAL (HTMLABLEC (FONT_RTI, "T", "&Tau;"))
+ | "\\upsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\upsilon ", "&upsilon;"))
+ | "\\Upsilon" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Upsilon ", "&Upsilon;"))
+ | "\\phi" -> LITERAL (HTMLABLEC (FONT_UF, "\\phi ", "&phi;"))
+ | "\\Phi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Phi ", "&Phi;"))
+ | "\\varphi" -> LITERAL (TEX_ONLY "\\varphi ")
+ | "\\chi" -> LITERAL (HTMLABLEC (FONT_UF, "\\chi ", "&chi;"))
+ | "\\Chi" -> LITERAL (HTMLABLEC (FONT_RTI, "X", "&Chi;"))
+ | "\\psi" -> LITERAL (HTMLABLEC (FONT_UF, "\\psi ", "&psi;"))
+ | "\\Psi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Psi ", "&Psi;"))
+ | "\\omega" -> LITERAL (HTMLABLEC (FONT_UF, "\\omega ", "&omega;"))
+ | "\\Omega" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Omega ", "&Omega;"))
+ | "\\xi" -> LITERAL (HTMLABLEC (FONT_UF, "\\xi ", "&xi;"))
+ | "\\Xi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Xi ", "&Xi;"))
+ | "\\aleph" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "&alefsym;"))
+ | "\\alef" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "&alefsym;"))
+ | "\\alefsym" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "&alefsym;"))
+ | "\\larr" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "&larr;"))
+ | "\\leftarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "&larr;"))
+ | "\\rarr" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "&rarr;"))
+ | "\\to" -> LITERAL (HTMLABLEM (FONT_UF, "\\to ", "&rarr;"))
+ | "\\gets" -> LITERAL (HTMLABLEM (FONT_UF, "\\gets ", "&larr;"))
+ | "\\rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "&rarr;"))
+ | "\\longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longleftarrow ", "&larr;"))
+ | "\\longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longrightarrow ", "&rarr;"))
+ | "\\Larr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "&lArr;"))
+ | "\\lArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "&lArr;"))
+ | "\\Leftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "&lArr;"))
+ | "\\Rarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "&rArr;"))
+ | "\\rArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "&rArr;"))
+ | "\\Rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\Rightarrow ", "&rArr;"))
+ | "\\mapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\mapsto ", "&rarr;"))
+ | "\\longmapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\longmapsto ", "&rarr;"))
+ | "\\Longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longleftarrow ", "&lArr;"))
+ | "\\Longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longrightarrow ", "&rArr;"))
+ | "\\uarr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "&uarr;"))
+ | "\\uparrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "&uarr;"))
+ | "\\uArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "&uArr;"))
+ | "\\Uarr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "&uArr;"))
+ | "\\Uparrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "&uArr;"))
+ | "\\darr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "&darr;"))
+ | "\\downarrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "&darr;"))
+ | "\\dArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "&dArr;"))
+ | "\\Darr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "&dArr;"))
+ | "\\Downarrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "&dArr;"))
+ | "\\updownarrow" -> DELIMITER (TEX_ONLY "\\updownarrow ")
+ | "\\Updownarrow" -> DELIMITER (TEX_ONLY "\\Updownarrow ")
+ | "\\leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "&harr;"))
+ | "\\lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "&harr;"))
+ | "\\harr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "&harr;"))
+ | "\\Leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
+ | "\\Lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
+ | "\\Harr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
+ | "\\lrArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
+ | "\\hAar" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
+ | "\\Longleftrightarrow"->LITERAL (HTMLABLE (FONT_UF, "\\Longleftrightarrow ", "&harr;"))
+ | "\\iff" -> LITERAL (HTMLABLE (FONT_UF, "\\iff ", "&harr;"))
+ | "\\ll" -> LITERAL (TEX_ONLY "\\ll ")
+ | "\\gg" -> LITERAL (TEX_ONLY "\\gg ")
+ | "\\div" -> LITERAL (TEX_ONLY "\\div ")
+ | "\\searrow" -> LITERAL (TEX_ONLY "\\searrow ")
+ | "\\nearrow" -> LITERAL (TEX_ONLY "\\nearrow ")
+ | "\\swarrow" -> LITERAL (TEX_ONLY "\\swarrow ")
+ | "\\nwarrow" -> LITERAL (TEX_ONLY "\\nwarrow ")
+ | "\\sim" -> LITERAL (TEX_ONLY "\\sim ")
+ | "\\simeq" -> LITERAL (TEX_ONLY "\\simeq ")
+ | "\\star" -> LITERAL (TEX_ONLY "\\star ")
+ | "\\ell" -> LITERAL (TEX_ONLY "\\ell ")
+ | "\\P" -> LITERAL (TEX_ONLY "\\P ")
+ | "\\smile" -> LITERAL (TEX_ONLY "\\smile ")
+ | "\\frown" -> LITERAL (TEX_ONLY "\\frown ")
+ | "\\bigcap" -> LITERAL (TEX_ONLY "\\bigcap ")
+ | "\\bigodot" -> LITERAL (TEX_ONLY "\\bigodot ")
+ | "\\bigcup" -> LITERAL (TEX_ONLY "\\bigcup ")
+ | "\\bigotimes" -> LITERAL (TEX_ONLY "\\bigotimes ")
+ | "\\coprod" -> LITERAL (TEX_ONLY "\\coprod ")
+ | "\\bigsqcup" -> LITERAL (TEX_ONLY "\\bigsqcup ")
+ | "\\bigoplus" -> LITERAL (TEX_ONLY "\\bigoplus ")
+ | "\\bigvee" -> LITERAL (TEX_ONLY "\\bigvee ")
+ | "\\biguplus" -> LITERAL (TEX_ONLY "\\biguplus ")
+ | "\\oint" -> LITERAL (TEX_ONLY "\\oint ")
+ | "\\bigwedge" -> LITERAL (TEX_ONLY "\\bigwedge ")
+ | "\\models" -> LITERAL (TEX_ONLY "\\models ")
+ | "\\vdash" -> LITERAL (TEX_ONLY "\\vdash ")
+ | "\\triangle" -> LITERAL (TEX_ONLY "\\triangle ")
+ | "\\bowtie" -> LITERAL (TEX_ONLY "\\bowtie ")
+ | "\\wr" -> LITERAL (TEX_ONLY "\\wr ")
+ | "\\triangleleft" -> LITERAL (TEX_ONLY "\\triangleleft ")
+ | "\\triangleright" -> LITERAL (TEX_ONLY "\\triangleright ")
+ | "\\textvisiblespace" -> LITERAL (TEX_ONLY "\\textvisiblespace ")
+ | "\\ker" -> LITERAL (TEX_ONLY "\\ker ")
+ | "\\lim" -> LITERAL (TEX_ONLY "\\lim ")
+ | "\\limsup" -> LITERAL (TEX_ONLY "\\limsup ")
+ | "\\liminf" -> LITERAL (TEX_ONLY "\\liminf ")
+ | "\\sup" -> LITERAL (TEX_ONLY "\\sup ")
+ | "\\Pr" -> LITERAL (TEX_ONLY "\\Pr ")
+ | "\\hom" -> LITERAL (TEX_ONLY "\\hom ")
+ | "\\arg" -> LITERAL (TEX_ONLY "\\arg ")
+ | "\\dim" -> LITERAL (TEX_ONLY "\\dim ")
+ | "\\inf" -> LITERAL (TEX_ONLY "\\inf ")
+ | "\\circ" -> LITERAL (TEX_ONLY "\\circ ")
+ | "\\hbar" -> LITERAL (TEX_ONLY "\\hbar ")
+ | "\\imath" -> LITERAL (TEX_ONLY "\\imath ")
+ | "\\lnot" -> LITERAL (TEX_ONLY "\\lnot ")
+ | "\\hookrightarrow" -> LITERAL (TEX_ONLY "\\hookrightarrow ")
+ | "\\hookleftarrow" -> LITERAL (TEX_ONLY "\\hookleftarrow ")
+ | "\\mp" -> LITERAL (TEX_ONLY "\\mp ")
+ | "\\approx" -> LITERAL (TEX_ONLY "\\approx ")
+ | "\\propto" -> LITERAL (TEX_ONLY "\\propto ")
+ | "\\flat" -> LITERAL (TEX_ONLY "\\flat ")
+ | "\\sharp" -> LITERAL (TEX_ONLY "\\sharp ")
+ | "\\natural" -> LITERAL (TEX_ONLY "\\natural ")
+ | "\\int" -> LITERAL (HTMLABLE_BIG ("\\int ", "&int;"))
+ | "\\sum" -> LITERAL (HTMLABLE_BIG ("\\sum ", "&sum;"))
+ | "\\prod" -> LITERAL (HTMLABLE_BIG ("\\prod ", "&prod;"))
+ | "\\vdots" -> LITERAL (TEX_ONLY "\\vdots ")
+ | "\\limits" -> LITERAL (TEX_ONLY "\\limits ")
+ | "\\nolimits" -> LITERAL (TEX_ONLY "\\nolimits ")
+ | "\\top" -> LITERAL (TEX_ONLY "\\top ")
+ | "\\sin" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sin ","sin"))
+ | "\\cos" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cos ","cos"))
+ | "\\sinh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sinh ","sinh"))
+ | "\\cosh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cosh ","cosh"))
+ | "\\tan" -> LITERAL (HTMLABLEC(FONT_UFH,"\\tan ","tan"))
+ | "\\tanh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\tanh ","tanh"))
+ | "\\sec" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sec ","sec"))
+ | "\\csc" -> LITERAL (HTMLABLEC(FONT_UFH,"\\csc ","csc"))
+ | "\\arcsin" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arcsin ","arcsin"))
+ | "\\arctan" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arctan ","arctan"))
+ | "\\arccos" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccos}}","arccos")))
+ | "\\arccot" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccot}}","arccot")))
+ | "\\arcsec" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arcsec}}","arcsec")))
+ | "\\arccsc" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccsc}}","arccsc")))
+ | "\\sgn" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{sgn}}","sgn")))
+ | "\\cot" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cot ","cot"))
+ | "\\coth" -> LITERAL (HTMLABLEC(FONT_UFH,"\\coth ","coth"))
+ | "\\log" -> LITERAL (HTMLABLEC(FONT_UFH,"\\log ", "log"))
+ | "\\lg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\lg ", "lg"))
+ | "\\ln" -> LITERAL (HTMLABLEC(FONT_UFH,"\\ln ", "ln"))
+ | "\\exp" -> LITERAL (HTMLABLEC(FONT_UFH,"\\exp ", "exp"))
+ | "\\min" -> LITERAL (HTMLABLEC(FONT_UFH,"\\min ", "min"))
+ | "\\max" -> LITERAL (HTMLABLEC(FONT_UFH,"\\max ", "max"))
+ | "\\gcd" -> LITERAL (HTMLABLEC(FONT_UFH,"\\gcd ", "gcd"))
+ | "\\deg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\deg ", "deg"))
+ | "\\det" -> LITERAL (HTMLABLEC(FONT_UFH,"\\det ", "det"))
+ | "\\bullet" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "&bull;"))
+ | "\\bull" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "&bull;"))
+ | "\\angle" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\angle ", "&ang;")))
+ | "\\dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\dagger ", "&dagger;"))
+ | "\\ddagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "&Dagger;"))
+ | "\\Dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "&Dagger;"))
+ | "\\colon" -> LITERAL (HTMLABLEC(FONT_UFH, "\\colon ", ":"))
+ | "\\Vert" -> DELIMITER (HTMLABLEM(FONT_UFH, "\\Vert ", "||"))
+ | "\\vert" -> DELIMITER (HTMLABLEM(FONT_UFH, "\\vert ", "|"))
+ | "\\wp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "&weierp;"))
+ | "\\weierp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "&weierp;"))
+ | "\\wedge" -> LITERAL (HTMLABLE (FONT_UF, "\\wedge ", "&and;"))
+ | "\\and" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "&and;"))
+ | "\\land" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "&and;"))
+ | "\\vee" -> LITERAL (HTMLABLE (FONT_UF, "\\vee ", "&or;"))
+ | "\\or" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "&or;"))
+ | "\\lor" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "&or;"))
+ | "\\sub" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "&sub;"))
+ | "\\supe" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "&supe;"))
+ | "\\sube" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "&sube;"))
+ | "\\supset" -> LITERAL (HTMLABLE (FONT_UF, "\\supset ", "&sup;"))
+ | "\\subset" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "&sub;"))
+ | "\\supseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "&supe;"))
+ | "\\subseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "&sube;"))
+ | "\\sqsupset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsupset "))
+ | "\\sqsubset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsubset "))
+ | "\\sqsupseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsupseteq "))
+ | "\\sqsubseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsubseteq "))
+ | "\\perp" -> LITERAL (HTMLABLE (FONT_UF, "\\perp ", "&perp;"))
+ | "\\bot" -> LITERAL (HTMLABLE (FONT_UF, "\\bot ", "&perp;"))
+ | "\\lfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\lfloor ", "&lfloor;"))
+ | "\\rfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\rfloor ", "&rfloor;"))
+ | "\\lceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\lceil ", "&lceil;"))
+ | "\\rceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\rceil ", "&rceil;"))
+ | "\\lbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\lbrace ", "{"))
+ | "\\rbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\rbrace ", "}"))
+ | "\\infty" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "&infin;"))
+ | "\\infin" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "&infin;"))
+ | "\\isin" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "&isin;"))
+ | "\\in" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "&isin;"))
+ | "\\ni" -> LITERAL (HTMLABLE (FONT_UF, "\\ni ", "&ni;"))
+ | "\\notin" -> LITERAL (HTMLABLE (FONT_UF, "\\notin ", "&notin;"))
+ | "\\smallsetminus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsetminus "))
+ | "\\And" -> (tex_use_ams (); LITERAL (HTMLABLEM(FONT_UFH, "\\And ", "&nbsp;&amp;&nbsp;")))
+ | "\\forall" -> LITERAL (HTMLABLE (FONT_UFH, "\\forall ", "&forall;"))
+ | "\\exists" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "&exist;"))
+ | "\\exist" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "&exist;"))
+ | "\\equiv" -> LITERAL (HTMLABLEM(FONT_UFH, "\\equiv ", "&equiv;"))
+ | "\\ne" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "&ne;"))
+ | "\\neq" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "&ne;"))
+ | "\\Re" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "&real;"))
+ | "\\real" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "&real;"))
+ | "\\Im" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "&image;"))
+ | "\\image" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "&image;"))
+ | "\\prime" -> LITERAL (HTMLABLE (FONT_UFH,"\\prime ", "&prime;"))
+ | "\\backslash" -> DELIMITER (HTMLABLEM(FONT_UFH,"\\backslash ", "\\"))
+ | "\\setminus" -> LITERAL (HTMLABLEM(FONT_UFH,"\\setminus ", "\\"))
+ | "\\times" -> LITERAL (HTMLABLEM(FONT_UFH,"\\times ", "&times;"))
+ | "\\pm" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "&plusmn;"))
+ | "\\plusmn" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "&plusmn;"))
+ | "\\cdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "&sdot;"))
+ | "\\AA" -> LITERAL (HTMLABLE (FONT_UFH,"\\AA ", "&Aring;"))
+ | "\\cdots" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdots ", "&sdot;&sdot;&sdot;"))
+ | "\\sdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "&sdot;"))
+ | "\\oplus" -> LITERAL (HTMLABLE (FONT_UF, "\\oplus ", "&oplus;"))
+ | "\\otimes" -> LITERAL (HTMLABLE (FONT_UF, "\\otimes ", "&otimes;"))
+ | "\\cap" -> LITERAL (HTMLABLEM(FONT_UF, "\\cap ", "&cap;"))
+ | "\\cup" -> LITERAL (HTMLABLE (FONT_UF, "\\cup ", "&cup;"))
+ | "\\sqcap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcap "))
+ | "\\sqcup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcup "))
+ | "\\empty" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
+ | "\\emptyset" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
+ | "\\O" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
+ | "\\S" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "&sect;"))
+ | "\\sect" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "&sect;"))
+ | "\\nabla" -> LITERAL (HTMLABLE (FONT_UF, "\\nabla ", "&nabla;"))
+ | "\\geq" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "&ge;"))
+ | "\\ge" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "&ge;"))
+ | "\\leq" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "&le;"))
+ | "\\le" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "&le;"))
+ | "\\cong" -> LITERAL (HTMLABLE (FONT_UF, "\\cong ", "&cong;"))
+ | "\\ang" -> LITERAL (HTMLABLE (FONT_UF, "\\angle ", "&ang;"))
+ | "\\part" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "&part;"))
+ | "\\partial" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "&part;"))
+ | "\\ldots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\ldots ", "..."))
+ | "\\dots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\dots ", "..."))
+ | "\\quad" -> LITERAL (HTMLABLE (FONT_UF, "\\quad ","&nbsp;&nbsp;"))
+ | "\\qquad" -> LITERAL (HTMLABLE (FONT_UF, "\\qquad ","&nbsp;&nbsp;&nbsp;&nbsp;"))
+ | "\\mid" -> LITERAL (HTMLABLEM(FONT_UFH,"\\mid ", " | "))
+ | "\\neg" -> LITERAL (HTMLABLEM(FONT_UFH,"\\neg ", "&not;"))
+ | "\\langle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","&lang;"))
+ | "\\rangle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","&rang;"))
+ | "\\lang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","&lang;"))
+ | "\\rang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","&rang;"))
+ | "\\lbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"[","["))
+ | "\\rbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"]","]"))
+ | "\\ddots" -> LITERAL (TEX_ONLY "\\ddots ")
+ | "\\clubs" -> LITERAL (TEX_ONLY "\\clubsuit ")
+ | "\\clubsuit" -> LITERAL (TEX_ONLY "\\clubsuit ")
+ | "\\spades" -> LITERAL (TEX_ONLY "\\spadesuit ")
+ | "\\spadesuit" -> LITERAL (TEX_ONLY "\\spadesuit ")
+ | "\\hearts" -> LITERAL (TEX_ONLY "\\heartsuit ")
+ | "\\heartsuit" -> LITERAL (TEX_ONLY "\\heartsuit ")
+ | "\\diamonds" -> LITERAL (TEX_ONLY "\\diamondsuit ")
+ | "\\diamondsuit" -> LITERAL (TEX_ONLY "\\diamondsuit ")
+ | "\\implies" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\implies ", "&rArr;")))
+ | "\\mod" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mod ", "mod")))
+ | "\\Diamond" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\Diamond ", "&loz;")))
+ | "\\dotsb" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsb ", "&sdot;&sdot;&sdot;")))
+ | "\\reals" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>")))
+ | "\\Reals" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>")))
+ | "\\R" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>")))
+ | "\\cnums" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</b>")))
+ | "\\Complex" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</b>")))
+ | "\\Z" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{Z}", "<b>Z</b>")))
+ | "\\natnums" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "<b>N</b>")))
+ | "\\N" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "<b>N</b>")))
+ | "\\lVert" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\lVert ", "||")))
+ | "\\rVert" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\rVert ", "||")))
+ | "\\nmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nmid "))
+ | "\\lesssim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesssim "))
+ | "\\ngeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeq "))
+ | "\\smallsmile" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsmile "))
+ | "\\smallfrown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallfrown "))
+ | "\\nleftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleftarrow "))
+ | "\\nrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nrightarrow "))
+ | "\\trianglelefteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglelefteq "))
+ | "\\trianglerighteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglerighteq "))
+ | "\\square" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\square "))
+ | "\\checkmark" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\checkmark "))
+ | "\\supsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supsetneq "))
+ | "\\subsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subsetneq "))
+ | "\\Box" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Box "))
+ | "\\nleq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleq "))
+ | "\\upharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonright "))
+ | "\\upharpoonleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonleft "))
+ | "\\downharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonright "))
+ | "\\downharpoonleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonleft "))
+ | "\\rightharpoonup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightharpoonup "))
+ | "\\rightharpoondown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightharpoondown "))
+ | "\\leftharpoonup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftharpoonup "))
+ | "\\leftharpoondown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftharpoondown "))
+ | "\\nless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nless "))
+ | "\\Vdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Vdash "))
+ | "\\vDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vDash "))
+ | "\\varkappa" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varkappa "))
+ | "\\digamma" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\digamma "))
+ | "\\beth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\beth "))
+ | "\\daleth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\daleth "))
+ | "\\gimel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gimel "))
+ | "\\complement" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\complement "))
+ | "\\eth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eth "))
+ | "\\hslash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\hslash "))
+ | "\\mho" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\mho "))
+ | "\\Finv" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Finv "))
+ | "\\Game" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Game "))
+ | "\\varlimsup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varlimsup "))
+ | "\\varliminf" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varliminf "))
+ | "\\varinjlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varinjlim "))
+ | "\\varprojlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varprojlim "))
+ | "\\injlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\injlim "))
+ | "\\projlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\projlim "))
+ | "\\iint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iint "))
+ | "\\iiint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiint "))
+ | "\\iiiint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiiint "))
+ | "\\varnothing" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varnothing "))
+ | "\\left" -> LEFT
+ | "\\right" -> RIGHT
+ | "\\hat" -> FUN_AR1 "\\hat "
+ | "\\widehat" -> FUN_AR1 "\\widehat "
+ | "\\overline" -> FUN_AR1 "\\overline "
+ | "\\overbrace" -> FUN_AR1 "\\overbrace "
+ | "\\underline" -> FUN_AR1 "\\underline "
+ | "\\underbrace" -> FUN_AR1 "\\underbrace "
+ | "\\overleftarrow" -> FUN_AR1 "\\overleftarrow "
+ | "\\overrightarrow" -> FUN_AR1 "\\overrightarrow "
+ | "\\overleftrightarrow"->FUN_AR1 "\\overleftrightarrow "
+ | "\\check" -> FUN_AR1 "\\check "
+ | "\\acute" -> FUN_AR1 "\\acute "
+ | "\\grave" -> FUN_AR1 "\\grave "
+ | "\\bar" -> FUN_AR1 "\\bar "
+ | "\\vec" -> FUN_AR1 "\\vec "
+ | "\\dot" -> FUN_AR1 "\\dot "
+ | "\\ddot" -> FUN_AR1 "\\ddot "
+ | "\\breve" -> FUN_AR1 "\\breve "
+ | "\\tilde" -> FUN_AR1 "\\tilde "
+ | "\\not" -> LITERAL (TEX_ONLY "\\not ")
+ | "\\choose" -> FUN_INFIX "\\choose "
+ | "\\atop" -> FUN_INFIX "\\atop "
+ | "\\binom" -> FUN_AR2 "\\binom "
+ | "\\frac" -> FUN_AR2h ("\\frac ", fun num den -> Html.html_render [num], "<hr style=\"{background: black}\"/>", Html.html_render [den])
+ | "\\cfrac" -> (tex_use_ams (); FUN_AR2h ("\\cfrac ", fun num den -> Html.html_render [num], "<hr style=\"{background: black}\">", Html.html_render [den]))
+ | "\\over" -> FUN_INFIXh ("\\over ", fun num den -> Html.html_render num, "<hr style=\"{background: black}\"/>", Html.html_render den)
+ | "\\sqrt" -> FUN_AR1 "\\sqrt "
+ | "\\pmod" -> FUN_AR1hl ("\\pmod ", ("(mod ", ")"))
+ | "\\bmod" -> FUN_AR1hl ("\\bmod ", ("mod ", ""))
+ | "\\emph" -> FUN_AR1 "\\emph "
+ | "\\texttt" -> FUN_AR1 "\\texttt "
+ | "\\textbf" -> FUN_AR1 "\\textbf "
+ | "\\textit" -> FUN_AR1hf ("\\textit ", FONTFORCE_IT)
+ | "\\textrm" -> FUN_AR1hf ("\\textrm ", FONTFORCE_RM)
+ | "\\rm" -> DECLh ("\\rm ", FONTFORCE_RM)
+ | "\\it" -> DECLh ("\\it ", FONTFORCE_IT)
+ | "\\cal" -> DECL "\\cal "
+ | "\\displaystyle" -> LITERAL (TEX_ONLY "\\displaystyle ")
+ | "\\scriptstyle" -> LITERAL (TEX_ONLY "\\scriptstyle ")
+ | "\\textstyle" -> LITERAL (TEX_ONLY "\\textstyle ")
+ | "\\scriptscriptstyle"-> LITERAL (TEX_ONLY "\\scriptscriptstyle ")
+ | "\\bf" -> DECL "\\bf "
+ | "\\big" -> BIG "\\big "
+ | "\\Big" -> BIG "\\Big "
+ | "\\bigg" -> BIG "\\bigg "
+ | "\\Bigg" -> BIG "\\Bigg "
+ | "\\mathit" -> (tex_use_ams (); FUN_AR1hf ("\\mathit ", FONTFORCE_IT))
+ | "\\mathrm" -> (tex_use_ams (); FUN_AR1hf ("\\mathrm ", FONTFORCE_RM))
+ | "\\mathop" -> (tex_use_ams (); FUN_AR1 "\\mathop ")
+ | "\\boldsymbol" -> (tex_use_ams (); FUN_AR1 "\\boldsymbol ")
+ | "\\bold" -> (tex_use_ams (); FUN_AR1 "\\mathbf ")
+ | "\\Bbb" -> (tex_use_ams (); FUN_AR1 "\\mathbb ")
+ | "\\mathbf" -> (tex_use_ams (); FUN_AR1 "\\mathbf ")
+ | "\\mathsf" -> (tex_use_ams (); FUN_AR1 "\\mathsf ")
+ | "\\mathcal" -> (tex_use_ams (); FUN_AR1 "\\mathcal ")
+ | "\\mathbb" -> (tex_use_ams (); FUN_AR1 "\\mathbb ")
+ | "\\mathfrak" -> (tex_use_ams (); FUN_AR1 "\\mathfrak ")
+ | "\\operatorname" -> (tex_use_ams (); FUN_AR1 "\\operatorname ")
+ | "\\mbox" -> raise (Failure "malformatted \\mbox")
+ | "\\vbox" -> raise (Failure "malformatted \\vbox")
+ | "\\hbox" -> raise (Failure "malformatted \\hbox")
+ | "\\color" -> (tex_use_color (); LITERAL (TEX_ONLY "\\color"))
+ | s -> raise (Illegal_tex_function s)
diff --git a/math/texutil.mli b/math/texutil.mli
new file mode 100644
index 00000000..99d0e4ec
--- /dev/null
+++ b/math/texutil.mli
@@ -0,0 +1,11 @@
+val render_tex : Tex.t -> string
+
+val set_encoding : string -> unit
+val tex_use_nonascii: unit -> unit
+val tex_use_ams: unit -> unit
+
+val get_preface : unit -> string
+val get_footer : unit -> string
+
+exception Illegal_tex_function of string
+val find: string -> Parser.token
diff --git a/math/texvc.ml b/math/texvc.ml
new file mode 100644
index 00000000..abddd3d0
--- /dev/null
+++ b/math/texvc.ml
@@ -0,0 +1,34 @@
+exception LexerException of string
+let lexer_token_safe lexbuf =
+ try Lexer.token lexbuf
+ with Failure s -> raise (LexerException s)
+
+let render tmppath finalpath tree =
+ let outtex = Util.mapjoin Texutil.render_tex tree in
+ let md5 = Digest.to_hex (Digest.string outtex) in
+ begin
+ let mathml = Mathml.render tree
+ and html = Html.render tree
+ in print_string (match (html,!Html.conservativeness,mathml) with
+ None,_,None -> "+" ^ md5
+ | Some h,Html.CONSERVATIVE,None -> "c" ^ md5 ^ h
+ | Some h,Html.MODERATE,None -> "m" ^ md5 ^ h
+ | Some h,Html.LIBERAL,None -> "l" ^ md5 ^ h
+ | Some h,Html.CONSERVATIVE,Some m -> "C" ^ md5 ^ h ^ "\000" ^ m
+ | Some h,Html.MODERATE,Some m -> "M" ^ md5 ^ h ^ "\000" ^ m
+ | Some h,Html.LIBERAL,Some m -> "L" ^ md5 ^ h ^ "\000" ^ m
+ | None,_,Some m -> "X" ^ md5 ^ m
+ );
+ Render.render tmppath finalpath outtex md5
+ end
+let _ =
+ Texutil.set_encoding (try Sys.argv.(4) with _ -> "UTF-8");
+ try render Sys.argv.(1) Sys.argv.(2) (Parser.tex_expr lexer_token_safe (Lexing.from_string Sys.argv.(3)))
+ with Parsing.Parse_error -> print_string "S"
+ | LexerException _ -> print_string "E"
+ | Texutil.Illegal_tex_function s -> print_string ("F" ^ s)
+ | Util.FileAlreadyExists -> print_string "-"
+ | Invalid_argument _ -> print_string "-"
+ | Failure _ -> print_string "-"
+ | Render.ExternalCommandFailure s -> ()
+ | _ -> print_string "-"
diff --git a/math/texvc_cgi.ml b/math/texvc_cgi.ml
new file mode 100644
index 00000000..2e6079fe
--- /dev/null
+++ b/math/texvc_cgi.ml
@@ -0,0 +1,62 @@
+open Netcgi;;
+open Netcgi_types;;
+open Netcgi_env;;
+open Netchannels;;
+
+let cgi = new Netcgi.std_activation ()
+let out = cgi # output # output_string
+let math = cgi # argument_value ~default:"" "math"
+let tmppath = "/home/taw/public_html/wiki/tmp/"
+let finalpath = "/home/taw/public_html/wiki/math/"
+let finalurl = "http://wroclaw.taw.pl.eu.org/~taw/wiki/math/"
+;;
+
+let h_header = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\""^
+ " \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"^
+ "<html><head><title>texvc</title></head><body>"^
+ "<form method=post action=\"http://wroclaw.taw.pl.eu.org/~taw/cgi-bin/newcodebase/math/texvc_cgi\">"^
+ "<textarea name='math' rows=10 cols=80>"
+let h_middle = "</textarea><br /><input type=submit value=\"Preview\" name='preview'></form>"
+let h_footer = "</body></html>\n"
+
+let render tmppath finalpath tree =
+ let outtex = Texutil.mapjoin Texutil.print tree in
+ let md5 = Digest.to_hex (Digest.string outtex) in
+ begin
+ out "<h3>TeX</h3>";
+ out outtex; (* <, & and > should be protected *)
+ (try out ("<h3>HTML</h3>" ^ (Texutil.html_render tree))
+ with _ -> out "<h3>HTML could not be rendered</h3>");
+ try Render.render tmppath finalpath outtex md5;
+ out ("<h3>Image:</h3><img src=\""^finalurl^md5^".png\">")
+ with Util.FileAlreadyExists -> out ("<h3>Image:</h3><img src=\""^finalurl^md5^".png\">")
+ | Failure s -> out ("<h3>Other failure: " ^ s ^ "</h3>")
+ | Render.ExternalCommandFailure "latex" -> out "<h3>latex failed</h3>"
+ | Render.ExternalCommandFailure "dvips" -> out "<h3>dvips failed</h3>"
+ | _ -> out "<h3>Other failure</h3>"
+ end
+;;
+
+cgi#set_header ();;
+
+out h_header;;
+out math;;
+out h_middle;;
+
+exception LexerException of string
+let lexer_token_safe lexbuf =
+ try Lexer.token lexbuf
+ with Failure s -> raise (LexerException s)
+;;
+if math = ""
+then ()
+else try
+ render tmppath finalpath (Parser.tex_expr lexer_token_safe (Lexing.from_string math))
+ with Parsing.Parse_error -> out "<h3>Parse error</h3>"
+ | LexerException s -> out "<h3>Lexing failure</h3>"
+ | Texutil.Illegal_tex_function s -> out ("<h3>Illegal TeX function: " ^ s ^ "</h3>")
+ | Failure s -> out ("<h3>Other failure: " ^ s ^ "</h3>")
+ | _ -> out "<h3>Other failure</h3>"
+;;
+
+out h_footer
diff --git a/math/texvc_test.ml b/math/texvc_test.ml
new file mode 100644
index 00000000..3bce5296
--- /dev/null
+++ b/math/texvc_test.ml
@@ -0,0 +1,25 @@
+exception LexerException of string
+let lexer_token_safe lexbuf =
+ try Lexer.token lexbuf
+ with Failure s -> raise (LexerException s)
+
+let rec foo () =
+ try
+ let line = input_line stdin in
+ (try
+ let tree = Parser.tex_expr lexer_token_safe (Lexing.from_string line) in
+ let out = Util.mapjoin Texutil.render_tex tree in
+ (match Html.render tree with
+ Some _ -> print_string "$^\n"
+ | None -> print_string "$_\n";
+ )
+ with
+ Texutil.Illegal_tex_function s -> print_string ("$T" ^ s ^ " " ^ line ^ "\n")
+ | LexerException s -> print_string ("$L" ^ line ^ "\n")
+ | _ -> print_string ("$ " ^ line ^ "\n"));
+ flush stdout;
+ foo ();
+ with
+ End_of_file -> ()
+;;
+foo ();;
diff --git a/math/texvc_tex.ml b/math/texvc_tex.ml
new file mode 100644
index 00000000..30c0f671
--- /dev/null
+++ b/math/texvc_tex.ml
@@ -0,0 +1,3 @@
+Texutil.set_encoding (try Sys.argv.(2) with _ -> "UTF-8");
+try print_string (Util.mapjoin Texutil.render_tex (Parser.tex_expr Lexer.token (Lexing.from_string Sys.argv.(1))))
+with _ -> ()
diff --git a/math/util.ml b/math/util.ml
new file mode 100644
index 00000000..f0458562
--- /dev/null
+++ b/math/util.ml
@@ -0,0 +1,17 @@
+let mapjoin f l = (List.fold_left (fun a b -> a ^ (f b)) "" l)
+let mapjoine e f = function
+ [] -> ""
+ | h::t -> (List.fold_left (fun a b -> a ^ e ^ (f b)) (f h) t)
+
+exception FileAlreadyExists
+let open_out_unless_exists path =
+ if Sys.file_exists path
+ then raise FileAlreadyExists
+ else open_out path
+
+let run_in_other_directory tmppath cmd =
+ let prevdir = Sys.getcwd () in(
+ Sys.chdir tmppath;
+ let retval = Sys.command cmd in
+ (Sys.chdir prevdir; retval)
+ )