1##
2## File: webtex.perl   by  Ross Moore <ross@mpce.mq.edu.au>
3##
4#################################################################
5##
6##  work done at the Geometry Center, University of Minnesota
7##  commenced during a visit to:
8##
9##  The National Science Foundation,
10##  Science and Technology Research Center for the
11##  Computation and Visualization of Geometric Structures
12##  funded by  NSF/DMS89-20161
13##
14#################################################################
15
16package main;
17#
18
19# configuration variable defaults
20
21$WEBEQ_OLD = 1 unless $WEBEQ_OLD;	# default until new version is available
22$WEBEQ_MML_ONLY = '' unless $WEBEQ_MML_ONLY;
23$WEBEQ_APP_ONLY = '' unless $WEBEQ_APP_ONLY;
24$WEBEQ_IMG_ONLY = '' unless $WEBEQ_IMG_ONLY;
25$WEBEQ_APPMML = 1  unless ($WEBEQ_APPMML);
26$WEBEQ_NOIMG  = '' unless ($WEBEQ_NOIMG);
27
28
29# Package options
30
31sub do_webtex_old { $WEBEQ_OLD = 1; }
32sub do_webtex_new { $WEBEQ_OLD = ''; }
33
34sub do_webtex_mmlonly { $WEBEQ_MML_ONLY = 1;
35	$WEBEQ_IMG_ONLY = $WEBEQ_APP_ONLY = ''; }
36sub do_webtex_apponly { $WEBEQ_APP_ONLY = 1;
37	$WEBEQ_MML_ONLY = $WEBEQ_IMG_ONLY = ''; }
38sub do_webtex_imgonly { $WEBEQ_IMG_ONLY = 1;
39	$WEBEQ_MML_ONLY = $WEBEQ_APP_ONLY = ''; }
40sub do_webtex_mmlapp { $WEBEQ_APPMML = 0; $WEBEQ_IMG_ONLY = ''; }
41sub do_webtex_appmml { $WEBEQ_APPMML = 1; $WEBEQ_IMG_ONLY = ''; }
42sub do_webtex_noimg  { $WEBEQ_NOIMG  = 1; $WEBEQ_IMG_ONLY = ''; }
43
44
45sub do_webtex_white { $WEBEQ_BKG = 'ffffff'; }
46
47sub do_webtex_text { $WEBEQ_MIME = ' TYPE="text/mathml"'; }
48sub do_webtex_application { $WEBEQ_MIME = ' TYPE="application/mathml"'; }
49
50## Mathematics environments
51
52
53#
54# Inline math,  $...$
55#
56sub do_env_tex2html_wrap_inline {
57    local($_) = @_;
58    local($math_mode, $failed, $labels, $comment) = ("inline",'','');
59    $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
60    local($attribs, $border, $web_failed, $alt_math);
61    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
62    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
63    local($saved) = $_;
64    s/(^\s*(\$|\\\()\s*|\s*(\$|\\\))\s*$)//g; # remove the \$ signs or \(..\)
65
66    ($labels, $comment, $alt_math) = &process_math_env($math_mode,$_);
67    $comment =~ s/^\n//; # remove the leading \n
68    ($web_failed, $_) = &convert_to_webtex('inline',$saved,$alt_math);
69    if ($failed) {
70	$_ = join ('', $labels, $comment
71            , &process_undefined_environment("tex2html_wrap_inline", $id, $saved));
72    } else { $_ = join('', $labels, $comment, $_); }
73    if ($border||($attribs)) {
74        &make_table( $border, $attribs, '', '', '', $_ )
75    } else { $_ }
76}
77
78
79
80sub do_env_displaymath {
81    local($_) = @_;
82    local($math_mode, $failed, $labels, $comment) = ("display",'','');
83    $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
84    local($attribs, $border);
85    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
86    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
87    local($saved) = $_;
88    local($halign) = $math_class unless $FLUSH_EQN;
89    local($sbig,$ebig,$web_failed);
90    ($sbig,$ebig) = ('<BIG>','</BIG>')
91	if (($DISP_SCALE_FACTOR)&&($DISP_SCALE_FACTOR >= 1.2 ));
92
93    ($labels, $comment, $alt_math) = &process_math_env($math_mode,$_);
94    ($web_failed, $_) = &convert_to_webtex('display',$saved,$alt_math);
95
96    if ($failed) {
97	$_ = &process_undefined_environment("displaymath", $id, $saved);
98	s/^[ \t]*\n?/\n/; s/\n?[ \t]*$/\n/;
99	$_ = (($comment.$labels)? "$comment$labels\n":''). $_;
100    } else {
101	s/^[ \t]*\n?/\n/; s/\n?[ \t]*$/\n/;
102	$_ = (($comment.$labels)? "$comment$labels\n":'').$sbig.$_.$ebig;
103    }
104    if ($border||($attribs)) {
105	join('',"<BR>\n<DIV$math_class>\n"
106            , &make_table( $border, $attribs, '', '', '', $_ )
107	    , "</DIV>\n<BR CLEAR=\"ALL\">");
108    } else {
109        join('',"<BR><P></P>\n<DIV$math_class>",$_
110            ,"</DIV><BR CLEAR=\"ALL\">\n<P></P>");
111    }
112}
113
114
115sub convert_to_webtex {
116    local($mode,$orig,$no_applet) = @_;
117
118    print "\nWebTeX:$mode:". ($WEBEQ_NOIMG ? 'no' : 'with')
119	. ' images' . ($WEBEQ_IMG_ONLY ? ' only' : '') . "\n$_\n"
120	    if ($VERBOSITY > 1);
121    if($WEBEQ_IMG_ONLY) { return (1,$no_applet) };
122
123    local($savedRS, $failed, $env_id, $_) = ($/,'','',$orig);
124    $/='';
125    if ($mode =~ /inline/) {
126	if (/^\s*\\\(/) { $failed = 1 }
127	else {
128	    $_ = &revert_to_raw_tex($_);
129	    $_ =~ s/^\s*\$?/\$/sm;
130	    $_ =~ s/\$?$/\$/sm;
131	    $env_id .= $WEBEQ_INL if $USING_STYLES;
132	}
133    } elsif ($mode =~ /display/) {
134	if (/^\s*\$\$/) { $failed = 1 }
135	else {
136	    $_ = &revert_to_raw_tex($_);
137	    $_ =~ s/^\s*(\\\[|\$\$)?/\\\[/sm;
138	    $_ =~ s/(\$\$|\\\])?\s*$/\\\]/sm;
139	    $env_id .= $WEBEQ_DIS if $USING_STYLES;
140	}
141    } else {
142	print " *** Unknown WebTeX mode, no applet ***";
143	$/ = $savedRS;
144	return (0,$no_applet)
145    }
146    $/ = $savedRS;
147    return (0,$no_applet) if $failed;
148
149    ($failed,$_) = &check_only_webtex($_);
150    return (0,$no_applet) if $failed;
151
152    local($webeq_abbrev);
153    SWITCH: {
154	if ($WEBEQ_IMG_ONLY) { $webeq_abbrev = ''; last SWITCH; };
155	if ($WEBEQ_MML_ONLY) { $webeq_abbrev = 'MML'; last SWITCH; };
156	if ($WEBEQ_APP_ONLY) { $webeq_abbrev = 'APP'; last SWITCH; };
157	if ($WEBEQ_APPMML) { $webeq_abbrev = 'APPMML'; last SWITCH; }
158	else { $webeq_abbrev = 'MMLAPP'; last SWITCH; }
159    };
160    $webeq_abbrev .= (($WEBEQ_NOIMG || $WEBEQ_MML_ONLY) ? ':' : 'IMG:' );
161
162    local($uucontents) = &encode(&addto_encoding('webeq'.$mode.$webeq_abbrev,$_));
163#    local($cached) = $WEBEQ_CACHE{$uucontents};
164    local($cached) = $cached_env_image{$uucontents};
165    if ($cached) {
166	$_ = $cached;
167    } else {
168	$verbatim{++$global{'verbatim_counter'}} = $_;
169	local($verb_math) = join("",$verbatim_mark
170		, 'verbatim',$global{'verbatim_counter'},'#');
171
172	# don't bother making an image, use LaTeX2HTML's one
173	$WEBEQ_IMG = $WEBEQ_NONE;
174
175	++$WEBEQ_CTR;
176	local($WEBEQ_CMD);
177	local($WEBEQ_PRE) = "wbq${WEBEQ_CTR}"
178		. (($WEBEQ_OLD &&(!$WEBEQ_IMG eq $WEBEQ_NONE))? 'a':'');
179	local($wbq_src) = $WEBEQ_PRE.'.src';
180	local($out_app) = $WEBEQ_PRE.'.app';
181	local($out_tag) = $WEBEQ_PRE.'.tag';
182	local($out_jpg) = $WEBEQ_PRE.'1.jpg';
183	local($out_png) = $WEBEQ_PRE.'1.png';
184	local($out_mml) = $WEBEQ_PRE.'.mml';
185	local($out_err) = $WEBEQ_PRE.'.err';
186	local($mml_tag, $app_tag, $ewebeq) = ('','','</NOEMBED>');
187
188#	local($WEBEQ_IMG) = (($IMAGE_TYPE =~ /png/) ? $WEBEQ_PNG : $WEBEQ_JPG);
189#	local($out_img) = (($IMAGE_TYPE =~ /png/) ? $out_png : $out_jpg);
190
191
192	open (SRC , ">$wbq_src");
193	print SRC $_;
194	close SRC;
195
196	local($eapplet) = '</applet>';
197	local($snoembed) = "<NOEMBED>\n";
198	local($enoembed) = '</NOEMBED>';
199	local($width,$height,$align);
200
201    if (!$WEBEQ_APP_ONLY) {
202	$WEBEQ_CMD = $WEBEQ.$WEBEQ_OPTS.$WEBEQ_MML.$WEBEQ_PARSER.$WEBEQ_IMG
203	   ." -errors $out_err -o $out_mml $wbq_src\n";
204	print "\n$WEBEQ_CMD" if $DEBUG;
205	if (system $WEBEQ_CMD) {
206	    &webeq_failed($out_mml); $out_mml = '';
207	} else {
208	    ($width,$height,$align) =
209		&cleanup_mml_attribs($out_mml,$mode,$no_applet);
210	    $mml_tag = join('', '<EMBED SRC="', $out_mml, '"'
211			, $WEBEQ_MIME , "\n "
212			, ($height ? " HEIGHT=\"$height\"" : '')
213			, ($width ? " WIDTH=\"$width\"" : '')
214			, ' ALIGN="'.($align ? $align : 'MIDDLE').'"'
215			, ">\n</EMBED>\n");
216	}
217	print "\nMATHML:\n$mml_tag\n" if ($DEBUG ||($VERBOSITY>1));
218    };
219
220
221    if (!$WEBEQ_MML_ONLY) {
222	$WEBEQ_CMD = $WEBEQ.$WEBEQ_OPTS.$WEBEQ_APP.$WEBEQ_IMG.$WEBEQ_PARSER
223	    ." -imgtype none -errors $out_err -o $out_tag $wbq_src\n";
224	print "\n$WEBEQ_CMD" if $DEBUG;
225	if (system $WEBEQ_CMD) {
226	    $_ = $no_applet;
227	    &webeq_failed($out_tag); $out_tag = '';
228	} else {
229	    open(TAG, "<$out_tag");
230	    $app_tag = join('',<TAG>);
231	    close(TAG);
232	    # replace webeq fall-back image by LaTeX2HTML's own, or none at all
233#	    $app_tag =~ s/<img[^>]*>/($WEBEQ_NOIMG ? '' : $no_applet)/e;
234#	    $app_tag =~ s|(\n?</applet>)\s*|($WEBEQ_NOIMG ? '' : $no_applet).$1|e;
235	    if ($mode =~ /display/) {
236		# remove initial space, line-ends and HTML tags
237		$app_tag =~ s/^\s*(<P><CENTER>)?//s;
238		$app_tag =~ s|(</CENTER><P>)?\s*$||s;
239	    }
240
241	    # cleanup blank lines
242	    $app_tag =~ s/\n[ \t]*\n/\n/sg;
243
244	    local($code);
245	    $app_tag =~ s/(<param[^"\n]*name=eq value=")([^"]*)(">)/
246		$code = $2;
247		$code =~ s|[<>"&]|'&'.$html_special_entities{$&}.';'|eg;
248		$verbatim{++$global{'verbatim_counter'}} = $code;
249		join("", $1, $verbatim_mark
250		    , 'rawhtml', $global{'verbatim_counter'},'#',$3)/e;
251	}
252    }
253
254    SWITCH: {
255	if ($WEBEQ_MML_ONLY) {
256	    return (0,$no_applet) unless $mml_tag;
257	    $_ = $mml_tag . $snoembed . $enoembed;
258	    last SWITCH }
259
260	if ($WEBEQ_APP_ONLY) {
261	    return (0,$no_applet) unless $app_tag;
262	    $_ = $app_tag;
263	    last SWITCH }
264
265	if ($WEBEQ_APPMML) {
266	    $_ = $app_tag;
267	    $_ =~ s/(\Q$eapplet\E)\s*$/$mml_tag$snoembed$enoembed$1/;
268	    last SWITCH;
269	} else {
270	    $_ = join('', $mml_tag
271		, $snoembed, $app_tag , $enoembed );
272	    last SWITCH;
273	}
274    }
275
276	if (($WEBEQ_IMG eq $WEBEQ_NONE)&&(!$WEBEQ_NOIMG)) {
277	    # insert the fall-back material
278	    $_ =~ s/((\s*($eapplet|$enoembed))+)\s*$/$no_applet$1/;
279	} elsif ($WEBEQ_NOIMG) {
280	    $_ =~ s/$snoembed\s*$enoembed//g;
281	}
282
283	if ($HTML_VERSION >= 4.0) {
284	    # use <OBJECT> tag, not the deprecated <APPLET> tag
285	    $_ =~ s/^\s*<(APPLET|EMBED)/<OBJECT$env_id/igs;
286#	    $_ =~ s/<(APPLET|EMBED)/<OBJECT$env_id/igs;
287	    $_ =~ s/<\/(APPLET|(NO)?EMBED)>\s*$/<\/OBJECT>/igs;
288	    $_ =~ s/<\/(OBJECT|EMBED)>\s*<NOEMBED>//g;
289	    $_ =~ s/ SRC=/ DATA=/gi;
290	    $_ =~ s/ NAME=/ ID=/gi;
291	    $_ =~ s/ PLUGINURL=/ CLASSID=/gi;
292	    $_ =~ s/ PLUGINSPAGE=/ CODEBASE=/gi;
293	    print "\nOBJECT:$_\n" if ($DEBUG||($VERBOSITY > 1));
294	}
295
296
297#	$WEBEQ_CACHE{$uucontents} = $_;
298	$cached_env_image{$uucontents} = $_ unless $WEBEQ_IMG_ONLY;
299
300    } # end of  if($cached) { ... } else {
301
302    ($failed,$_);
303}
304
305# check that the only macro-names are those known to WebTeX
306sub check_only_webtex {
307    local($webtex) = @_;
308#    $webtex =~ s/\'/\\prime /g;		# coerce ' --> \prime
309    (0,$webtex);
310}
311
312sub webeq_failed {
313    local($err_str) = "\n*** WebEQ failed to make image @_[0] ***";
314    print $err_str."\n" if ($DEBUG || ($VERBOSITY > 1));
315    &write_warnings($err_str);
316}
317
318# early versions of  webeq  started with <P><CENTER> tags and their ends
319# remove these, if they exist.
320sub cleanup_mml_attribs {
321    local($mml_file,$mode,$_) = @_;
322    local($width,$height,$align);
323    open (MML, "<$mml_file");
324    local($mml_code) = join('',<MML>);
325    close MML;
326
327    local($savedRS) = $/; $/='';
328    $mml_code =~ s/^\s*<P><CENTER>\n?//s;
329    $mml_code =~ s/\s*<applet code="[^"]*" width=(\d+) height=(\d+) align=(\w+)>\s*/
330	$width=$1;$height=$2;$align=$3;''/e;
331    $mml_code =~ s/<param[^>\n]*>?\n//g;
332    $mml_code =~ s|(\n\">\s*</applet>\s*)?\s*</CENTER><P>\s*||s;
333    $mml_code =~ s|\n\">\s*</applet>\s*||s;
334    $mml_code =~ s/\&($WEBEQ_mml_name_rx);/$WEBEQ_mml_name{$1}/eg;
335    $mml_code =~ s/\&($WEBEQ_mml_punct_rx);/$WEBEQ_mml_punct{$1}/eg;
336    # catch superscripted primes --- put them into the preceding tag
337    $mml_code =~ s|<(msup>)\s*<([^>]*>)([^<>]*)</\2\s*<mo>\&prime;</mo>\s*</\1|<$2$3\'</$2|sg;
338    open (MML, ">$mml_file");
339    print MML $mml_code;
340    close MML;
341
342    if ($mode =~/display/) {
343	# webweq has already used a scaling for \displaystyle
344	if ($width) { $width *= $WEBEQ_TCX_REL_SCALE; $width = int($width + 0.5) }
345	if ($height) { $height *= $WEBEQ_TCX_REL_SCALE; $height = int($height + 0.5) }
346    } elsif ($no_applet) {
347	local($find_width,$find_height,$val) = ($width,$height);
348	&replace_image_marks;
349	if (s/(WIDTH|HEIGHT)\s*=\s*"?(\d+)"?/$val=$2;
350		if ($1 eq 'WIDTH') { $find_width = $val if ($val > $find_width) }
351		else { $find_height = $val if ($val > $find_height) };''/esg ) {
352	    if (/ALIGN="MIDDLE"/) { $height *= 2; }
353	    else { $height *= $WEBEQ_TCX_INL_SCALE; }
354	    $width *= $WEBEQ_TCX_INL_SCALE;
355	    if ($find_width > $width) { $width = $find_width };
356	    if ($find_height > $height) { $height = $find_height };
357	} else {
358	    print "\nNo HEIGHT/WIDTH info within: $_ ***";
359	    if ($width) { $width *= $WEBEQ_TCX_INL_SCALE }
360	    if ($height) { $height *= $WEBEQ_TCX_INL_SCALE }
361	}
362    } else {
363	# tech-explorer uses a scaling of roughly 1.5
364	if ($width) { $width *= $WEBEQ_TCX_INL_SCALE }
365	if ($height) { $height *= $WEBEQ_TCX_INL_SCALE }
366    }
367    $width = 10 + int($width + 0.5) if $width;
368    $height = 5 + int($height + 0.5) if $height;
369    ($width,$height,$align);
370}
371
372# Fix entity-name errors in webeq output
373%WEBEQ_mml_name = (
374	 'in'	, '&isin;'			#
375	, 'setminus' , "\\"			# &setminus;
376	, 'mapsto' , '&nbsp;- > '		# &setminus;
377	, 'times' , '&nbsp;x '			# &times;
378	, 'rightarrow' , '&nbsp;-- > '		# &rarrow;
379	, 'longrightarrow' , '&nbsp;--- > '	# &rrarrow;
380	);
381$WEBEQ_mml_name_rx = join('|', keys %WEBEQ_mml_name);
382
383
384%WEBEQ_mml_punct = (
385	 ','	, ' '		# '&thinsp;'
386#	 '.'	, '&dot;'	# dot accent
387	, ':'	, '&nbsp;'	# '&medsp;'
388	, ';'	, ' &nbsp;'	# '&thicksp;'
389	, '!'	, '&negsp;'
390	, '~'	, '&nbsp;'
391#	, '`'	, '`'		# acute accent
392#	, '''	, '''		# grave -- accent;
393#	, '"'	, '"'		# umlaut -- accent;
394	, '@'	, '@'
395	, '#'	, '#'
396	, '$'	, '$'
397	, '%'	, '%'
398#	, '^'	, '^'		# caret -- accent;
399	, '&'	, '&amp;'
400	, '*'	, '&star;'
401	, '('	, ''
402	, ')'	, ''
403	, '-'	, ''
404	, '_'	, '_'
405	, '+'	, ''
406	, '='	, ''
407	, '='	, ''
408	, '['	, '['
409	, ']'	, ']'
410	, '|'	, '||'		# &Vert;  or  &Verbar;
411	, '<'	, '&langle;'
412	, '>'	, '&rangle;'
413	, '{'	, '{'		# &lbrace;
414	, '}'	, '}'		# &rbrace;
415	);
416$WEBEQ_mml_punct_rx = "\\W";
417
418
419$WEBEQ_CLASSES = $ENV{'CLASSPATH'};
420print " *** no JAVA classes*** \n
421 please set the CLASSPATH variable\n" unless $WEBEQ_CLASSES;
422
423$WEBEQ_CTR = '';
424$WEBEQ = 'java webeq.wizard.clwizard ';
425$WEBEQ_OPTS = ' -colorspace colors -quality excellent -linewrap true -allow_selection true ';
426$WEBEQ_PARSER = ' -parser WebTeX -delims WebTeX ';
427$WEBEQ_PMML = ' -parser MathML -delims MathML ';
428$WEBEQ_APP = ' -outtype Applets';
429$WEBEQ_IMG = ' -outtype Images_Only';
430#$WEBEQ_MML = ' -outtype MathML_Only';
431$WEBEQ_MML = ' -outtype MathML_Applets';
432$WEBEQ_JPG = ' -imgtype jpeg';
433$WEBEQ_PNG = ' -imgtype png';
434$WEBEQ_NONE = ' -imgtype none';
435$WEBEQ_ERR = ' -errors ';
436$WEBEQ_OUT = ' -o ';
437#$WEBEQ_MIME = ' TYPE="application/mathml"';
438$WEBEQ_MIME = ' TYPE="text/mathml"';
439$WEBEQ_JAVA = ' TYPE="application/java"';
440$WEBEQ_INL = ' CLASS="INLINE"';
441$WEBEQ_DIS = ' CLASS="DISPLAY"';
442$WEBEQ_BKG = ' color=#ffffff';
443$WEBEQ_TCX_REL_SCALE = 1.2;
444$WEBEQ_TCX_INL_SCALE = 1.6;
445
446%WEBEQ_CACHE = ();
447
448&ignore_commands( <<_IGNORED_CMDS_);
449_IGNORED_CMDS_
450
451
452&process_commands_wrap_deferred (<<_RAW_ARG_DEFERRED_CMDS_);
453_RAW_ARG_DEFERRED_CMDS_
454
4551;
456
457