1 /*
2 blahtex: a TeX to MathML converter designed with MediaWiki in mind
3 blahtexml: an extension of blahtex with XML processing in mind
4 http://gva.noekeon.org/blahtexml
5
6 Copyright (c) 2006, David Harvey
7 Copyright (c) 2010, Gilles Van Assche
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
11
12 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
14 * Neither the names of the authors nor the names of their affiliation may be used to endorse or promote products derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 */
18
19 #include "BlahtexCore/Interface.h"
20 #include "UnicodeConverter.h"
21 #include "mainPng.h"
22 #include <iostream>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sstream>
26 #include <stdexcept>
27 #include <iostream>
28 #include <fstream>
29
30 #include <unistd.h>
31
32 using namespace std;
33 using namespace blahtex;
34
35 #ifdef BLAHTEXML_USING_XERCES
36 #include <string.h>
37 #include <xercesc/framework/StdInInputSource.hpp>
38 #include <xercesc/framework/XMLFormatter.hpp>
39 #include <xercesc/parsers/SAX2XMLFilterImpl.hpp>
40 #include <xercesc/sax2/Attributes.hpp>
41 #include <xercesc/sax2/SAX2XMLReader.hpp>
42 #include <xercesc/sax2/XMLReaderFactory.hpp>
43 #include <xercesc/util/OutOfMemoryException.hpp>
44 #include <xercesc/util/PlatformUtils.hpp>
45 #include <xercesc/util/TransService.hpp>
46 #include <xercesc/util/XMLString.hpp>
47 #include <xercesc/util/XMLUniDefs.hpp>
48 #include "BlahtexXMLin/BlahtexFilter.h"
49 #include "BlahtexXMLin/SAX2Output.h"
50 #endif
51
52 string gBlahtexVersion = "0.9";
53
54 // A single global instance of UnicodeConverter.
55 UnicodeConverter gUnicodeConverter;
56
57 // Imported from Messages.cpp:
58 extern wstring GetErrorMessage(const blahtex::Exception& e);
59 extern wstring GetErrorMessages();
60
61 // FormatError() converts a blahtex Exception object into a string like
62 // "<error><id>...</id><arg>...</arg><arg>...</arg> ...
63 // <message>...</message></error".
FormatError(const blahtex::Exception & e,const EncodingOptions & options)64 wstring FormatError(
65 const blahtex::Exception& e,
66 const EncodingOptions& options
67 )
68 {
69 wstring output = L"<error><id>" + e.GetCode() + L"</id>";
70 for (vector<wstring>::const_iterator
71 arg = e.GetArgs().begin(); arg != e.GetArgs().end(); arg++
72 )
73 output += L"<arg>" + XmlEncode(*arg, options) + L"</arg>";
74
75 output += L"<message>";
76 output += XmlEncode(GetErrorMessage(e), options);
77 output += L"</message>";
78
79 output += L"</error>";
80 return output;
81 }
82
ULLToWstring(unsigned long long number)83 wstring ULLToWstring(unsigned long long number)
84 {
85 wstring wstr;
86
87 stringstream ss;
88 ss << number;
89
90 string str = ss.str();
91
92 return wstr.assign(str.begin(), str.end());
93 }
94
FormatTokenError(const blahtex::TokenException & e,const EncodingOptions & options)95 wstring FormatTokenError(const blahtex::TokenException & e, const EncodingOptions & options)
96 {
97 wstring output = L"<error><id>" + e.GetCode() + L"</id>";
98
99 for (vector<wstring>::const_iterator arg = e.GetArgs().begin(); arg != e.GetArgs().end(); arg++)
100 output += L"<arg>" + XmlEncode(*arg, options) + L"</arg>";
101
102 output += L"<message>";
103 output += XmlEncode(GetErrorMessage(e), options);
104 output += L"</message>";
105
106 output += L"<startPos>";
107 output += ULLToWstring(e.getToken().getStartPos());
108 output += L"</startPos>";
109
110 output += L"<length>";
111 output += ULLToWstring(e.getToken().getLength());
112 output += L"</length>";
113
114 output += L"</error>";
115
116 return output;
117 }
118
119 // ShowUsage() prints a help screen.
ShowUsage()120 void ShowUsage()
121 {
122 cout << "\n"
123 #ifdef BLAHTEXML_USING_XERCES
124 "Blahtexml version " << gBlahtexVersion << "\n"
125 #else
126 "Blahtex version " << gBlahtexVersion << "\n"
127 #endif
128 "Copyright (C) 2006, David Harvey\n"
129 "Copyright (C) 2007-2010, Gilles Van Assche\n"
130 "\n"
131 "This is free software; see the source "
132 "for copying conditions. There is NO\n"
133 "warranty; not even for MERCHANTABILITY "
134 "or FITNESS FOR A PARTICULAR PURPOSE.\n"
135 "\n"
136 #ifdef BLAHTEXML_USING_XERCES
137 "Normal mode: blahtexml [ options ] < inputfile > outputfile\n"
138 "XML input mode: blahtexml --xmlin [ options ] < inputfile > outputfile\n"
139 #else
140 "Usage: blahtex [ options ] < inputfile > outputfile\n"
141 #endif
142 "\n"
143 "SUMMARY OF OPTIONS (see manual for details)\n"
144 "\n"
145 " --texvc-compatible-commands\n"
146 "\n"
147 " --mathml\n"
148 " --displaymath\n"
149 " --indented\n"
150 " --spacing { strict | moderate | relaxed }\n"
151 " --mathml-version-1-fonts\n"
152 " --disallow-plane-1\n"
153 " --mathml-encoding { raw | numeric | short | long }\n"
154 " --other-encoding { raw | numeric }\n"
155 "\n"
156 " --png\n"
157 " --displaymath\n"
158 " --use-ucs-package\n"
159 " --use-cjk-package\n"
160 " --use-preview-package\n"
161 " --japanese-font fontname\n"
162 " --shell-latex command\n"
163 " --shell-dvipng command\n"
164 " --temp-directory directory\n"
165 " --png-directory directory\n"
166 " --png-latex-preamble content\n"
167 " --png-latex-before-math content\n"
168 "\n"
169 " --debug { parse | layout | purified }\n"
170 " --keep-temp-files\n"
171 " --throw-logic-error\n"
172 " --print-error-messages\n"
173 "\n"
174 #ifdef BLAHTEXML_USING_XERCES
175 " --doctype-system DTD\n"
176 " --doctype-public PublicID DTD\n"
177 " --doctype-xhtml+mathml\n"
178 " --mathml-nsprefix-auto\n"
179 " --mathml-nsprefix-none\n"
180 " --mathml-nsprefix prefix\n"
181 " --annotate-PNG\n"
182 " --annotate-TeX\n"
183 "\n"
184 "\n"
185 #endif
186 "More information available at http://gva.noekeon.org/blahtexml/\n"
187 "\n";
188
189 // FIX: need command line option to select output DPI
190
191 exit(0);
192 }
193
194 // CommandLineException is used for reporting incorrect command line
195 // syntax.
196 struct CommandLineException
197 {
198 string mMessage;
199
CommandLineExceptionCommandLineException200 CommandLineException(
201 const string& message
202 ) :
203 mMessage(message)
204 { }
205 };
206
207 // Adds a trailing slash to the string, if it's not already there.
AddTrailingSlash(string & s)208 void AddTrailingSlash(string& s)
209 {
210 if (!s.empty() && s[s.size() - 1] != '/')
211 s += '/';
212 }
213
214 PngParams pngParams;
215 #ifdef BLAHTEXML_USING_XERCES
216 SAX2Output::Doctype outputDoctype = SAX2Output::DoctypeNone;
217 string outputPublicID;
218 string outputDTD;
219 BlahtexFilter::PrefixType MathMLPrefixType = BlahtexFilter::PrefixAuto;
220 string MathMLPrefix;
221 bool annotatePNG, annotateTeX;
batchXMLConversion(blahtex::Interface & interface)222 int batchXMLConversion(blahtex::Interface& interface)
223 {
224 cerr << "\n"
225 "Blahtexml version " << gBlahtexVersion << "\n"
226 "Copyright (C) 2006, David Harvey\n"
227 "Copyright (C) 2007-2010, Gilles Van Assche\n"
228 "\n"
229 "This is free software; see the source "
230 "for copying conditions. There is NO\n"
231 "warranty; not even for MERCHANTABILITY "
232 "or FITNESS FOR A PARTICULAR PURPOSE.\n";
233 cerr << endl;
234 try {
235 XMLPlatformUtils::Initialize();
236 }
237 catch (const XMLException& toCatch) {
238 XERCES_STD_QUALIFIER cerr << "Error during initialization! :\n" << XMLString::transcode(toCatch.getMessage()) << endl;
239 return 1;
240 }
241 SAX2XMLReader* reader = XMLReaderFactory::createXMLReader();
242 BlahtexFilter* parser = new BlahtexFilter(reader, interface);
243
244 parser->setFeature(XMLUni::fgSAX2CoreValidation, false);
245 parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
246 parser->setFeature(XMLUni::fgXercesSchema, false);
247 parser->setFeature(XMLUni::fgXercesSchemaFullChecking, false);
248 parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, false);
249
250 XercesString _MathMLPrefix(MathMLPrefix.c_str());
251 wstring __MathMLPrefix = _MathMLPrefix.convertTowstring();
252 parser->setDesiredMathMLPrefixType(MathMLPrefixType, __MathMLPrefix);
253 parser->setAnnotatePNG(annotatePNG);
254 parser->setAnnotateTeX(annotateTeX);
255 parser->setPngParams(pngParams);
256
257 int parserErrors = 0;
258 int result = 0;
259 {
260 StdInInputSource stdIn;
261 try {
262 XercesString publicID(outputPublicID.c_str());
263 XercesString DTD(outputDTD.c_str());
264 SAX2Output output(cout, "UTF-8", XMLFormatter::UnRep_CharRef, outputDoctype, publicID, DTD);
265 parser->setContentHandler(&output);
266 parser->setErrorHandler(&output);
267 parser->parse(stdIn);
268 parserErrors = parser->getErrorCount();
269 }
270 catch (const OutOfMemoryException&) {
271 cerr << endl;
272 cerr << "Out of memory exception" << endl;
273 result = 1;
274 }
275 catch (const XMLException& e) {
276 char *errorString = XMLString::transcode(e.getMessage());
277 cerr << endl;
278 cerr << "Error: " << errorString << endl;
279 XMLString::release(&errorString);
280 result = 1;
281 }
282 }
283 if (parserErrors > 0) {
284 cerr << "During the XML input parsing, ";
285 if (parserErrors == 1) cerr << "an error";
286 else cerr << parserErrors << " errors";
287 cerr << " occurred." << endl;
288 }
289 int blahtexErrors = parser->getNumberOfErrors();
290 if (blahtexErrors > 0) {
291 cerr << "During the blahtex conversion, ";
292 if (blahtexErrors == 1) cerr << "an error";
293 else cerr << blahtexErrors << " errors";
294 cerr << " occurred.\nSee the output file for more information." << endl;
295 result = 1;
296 }
297 delete parser;
298 delete reader;
299 XMLPlatformUtils::Terminate();
300 return result;
301 }
302 #endif
303
main(int argc,char * const argv[])304 int main (int argc, char* const argv[]) {
305 // This outermost try block catches std::runtime_error
306 // and CommandLineException.
307 try
308 {
309 gUnicodeConverter.Open();
310
311 blahtex::Interface interface;
312
313 bool doPng = false;
314 bool doMathml = false;
315 #ifdef BLAHTEXML_USING_XERCES
316 bool doXMLinput = false;
317 annotatePNG = false;
318 annotateTeX = false;
319 #endif
320
321 bool debugLayoutTree = false;
322 bool debugParseTree = false;
323 bool debugPurifiedTex = false;
324
325 pngParams.deleteTempFiles = true;
326 pngParams.shellLatex = "latex";
327 pngParams.shellDvipng = "dvipng";
328 pngParams.tempDirectory = "./";
329 pngParams.pngDirectory = "./";
330
331 bool displayStyle = false;
332
333 const char *inputFilePath = NULL;
334
335
336 // Process command line arguments
337 for (int i = 1; i < argc; i++)
338 {
339 string arg(argv[i]);
340
341 if (arg == "--help")
342 ShowUsage();
343
344 else if (arg == "--input-file")
345 {
346 if (++i == argc)
347 throw CommandLineException("Missing file path after \"--input-file\"");
348
349 inputFilePath = argv[i];
350 }
351
352 else if (arg == "--print-error-messages")
353 {
354 cout << gUnicodeConverter.ConvertOut(GetErrorMessages())
355 << endl;
356 return 0;
357 }
358
359 else if (arg == "--throw-logic-error")
360 throw logic_error("Aaarrrgggghhhh!");
361
362 else if (arg == "--shell-latex")
363 {
364 if (++i == argc)
365 throw CommandLineException(
366 "Missing string after \"--shell-latex\""
367 );
368 pngParams.shellLatex = string(argv[i]);
369 }
370
371 else if (arg == "--shell-dvipng")
372 {
373 if (++i == argc)
374 throw CommandLineException(
375 "Missing string after \"--shell-dvipng\""
376 );
377 pngParams.shellDvipng = string(argv[i]);
378 }
379
380 else if (arg == "--temp-directory")
381 {
382 if (++i == argc)
383 throw CommandLineException(
384 "Missing string after \"--temp-directory\""
385 );
386 pngParams.tempDirectory = string(argv[i]);
387 AddTrailingSlash(pngParams.tempDirectory);
388 }
389
390 else if (arg == "--png-directory")
391 {
392 if (++i == argc)
393 throw CommandLineException(
394 "Missing string after \"--png-directory\""
395 );
396 pngParams.pngDirectory = string(argv[i]);
397 AddTrailingSlash(pngParams.pngDirectory);
398 }
399
400 else if (arg == "--displaymath") {
401 interface.mPurifiedTexOptions.mDisplayMath = true;
402 displayStyle = true;
403 }
404
405 else if (arg == "--use-ucs-package")
406 interface.mPurifiedTexOptions.mAllowUcs = true;
407
408 else if (arg == "--use-cjk-package")
409 interface.mPurifiedTexOptions.mAllowCJK = true;
410
411 else if (arg == "--use-preview-package")
412 interface.mPurifiedTexOptions.mAllowPreview = true;
413
414 else if (arg == "--japanese-font")
415 {
416 if (++i == argc)
417 throw CommandLineException(
418 "Missing string after \"--japanese-font\""
419 );
420 interface.mPurifiedTexOptions.mJapaneseFont =
421 gUnicodeConverter.ConvertIn(string(argv[i]));
422 }
423
424 else if (arg == "--indented")
425 interface.mIndented = true;
426
427 else if (arg == "--spacing")
428 {
429 if (++i == argc)
430 throw CommandLineException(
431 "Missing string after \"--spacing\""
432 );
433 arg = string(argv[i]);
434
435 if (arg == "strict")
436 interface.mMathmlOptions.mSpacingControl
437 = MathmlOptions::cSpacingControlStrict;
438
439 else if (arg == "moderate")
440 interface.mMathmlOptions.mSpacingControl
441 = MathmlOptions::cSpacingControlModerate;
442
443 else if (arg == "relaxed")
444 interface.mMathmlOptions.mSpacingControl
445 = MathmlOptions::cSpacingControlRelaxed;
446
447 else
448 throw CommandLineException(
449 "Illegal string after \"--spacing\""
450 );
451 }
452
453 else if (arg == "--mathml-version-1-fonts")
454 interface.mMathmlOptions.mUseVersion1FontAttributes = true;
455
456 else if (arg == "--texvc-compatible-commands")
457 interface.mTexvcCompatibility = true;
458
459 else if (arg == "--png")
460 doPng = true;
461
462 else if (arg == "--mathml")
463 doMathml = true;
464
465 else if (arg == "--mathml-encoding")
466 {
467 if (++i == argc)
468 throw CommandLineException(
469 "Missing string after \"--mathml-encoding\""
470 );
471 arg = string(argv[i]);
472
473 if (arg == "raw")
474 interface.mEncodingOptions.mMathmlEncoding
475 = EncodingOptions::cMathmlEncodingRaw;
476
477 else if (arg == "numeric")
478 interface.mEncodingOptions.mMathmlEncoding
479 = EncodingOptions::cMathmlEncodingNumeric;
480
481 else if (arg == "short")
482 interface.mEncodingOptions.mMathmlEncoding
483 = EncodingOptions::cMathmlEncodingShort;
484
485 else if (arg == "long")
486 interface.mEncodingOptions.mMathmlEncoding
487 = EncodingOptions::cMathmlEncodingLong;
488
489 else
490 throw CommandLineException(
491 "Illegal string after \"--mathml-encoding\""
492 );
493 }
494
495 else if (arg == "--disallow-plane-1")
496 {
497 interface.mMathmlOptions .mAllowPlane1 = false;
498 interface.mEncodingOptions.mAllowPlane1 = false;
499 }
500
501 else if (arg == "--other-encoding")
502 {
503 if (++i == argc)
504 throw CommandLineException(
505 "Missing string after \"--other-encoding\""
506 );
507 arg = string(argv[i]);
508 if (arg == "raw")
509 interface.mEncodingOptions.mOtherEncodingRaw = true;
510 else if (arg == "numeric")
511 interface.mEncodingOptions.mOtherEncodingRaw = false;
512 else
513 throw CommandLineException(
514 "Illegal string after \"--other-encoding\""
515 );
516 }
517
518 else if (arg == "--debug")
519 {
520 if (++i == argc)
521 throw CommandLineException(
522 "Missing string after \"--debug\""
523 );
524 arg = string(argv[i]);
525 if (arg == "layout")
526 debugLayoutTree = true;
527 else if (arg == "parse")
528 debugParseTree = true;
529 else if (arg == "purified")
530 debugPurifiedTex = true;
531 else
532 throw CommandLineException(
533 "Illegal string after \"--debug\""
534 );
535 }
536
537 else if (arg == "--keep-temp-files")
538 pngParams.deleteTempFiles = false;
539 #ifdef BLAHTEXML_USING_XERCES
540 else if (arg == "--xmlin")
541 doXMLinput = true;
542 else if (arg == "--doctype-system") {
543 outputDoctype = SAX2Output::DoctypeSystem;
544 if (++i == argc) throw CommandLineException("Missing string after \"--doctype-system\"");
545 outputDTD = argv[i];
546 }
547 else if (arg == "--doctype-public") {
548 outputDoctype = SAX2Output::DoctypePublic;
549 if (++i == argc) throw CommandLineException("Missing two strings after \"--doctype-public\"");
550 outputPublicID = argv[i];
551 if (++i == argc) throw CommandLineException("Missing one string after \"--doctype-public\"");
552 outputDTD = argv[i];
553 }
554 else if (arg == "--doctype-xhtml+mathml") {
555 outputDoctype = SAX2Output::DoctypePublic;
556 outputPublicID = "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN";
557 outputDTD = "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd";
558 MathMLPrefixType = BlahtexFilter::PrefixNone;
559 }
560 else if (arg == "--mathml-nsprefix-auto")
561 MathMLPrefixType = BlahtexFilter::PrefixAuto;
562 else if (arg == "--mathml-nsprefix-none")
563 MathMLPrefixType = BlahtexFilter::PrefixNone;
564 else if (arg == "--mathml-nsprefix") {
565 MathMLPrefixType = BlahtexFilter::PrefixAdd;
566 if (++i == argc) throw CommandLineException("Missing string after \"--mathml-nsprefix\"");
567 MathMLPrefix = argv[i];
568 }
569 else if (arg == "--annotate-PNG")
570 annotatePNG = true;
571 else if (arg == "--annotate-TeX")
572 annotateTeX = true;
573 #endif
574 else if (arg == "--png-latex-preamble") {
575 if (++i == argc) {
576 throw CommandLineException(
577 "Missing string after \"--png-latex-preamble\""
578 );
579 }
580 interface.mPurifiedTexOptions.mLaTeXPreamble = gUnicodeConverter.ConvertIn(string(argv[i]));
581 }
582 else if (arg == "--png-latex-before-math") {
583 if (++i == argc) {
584 throw CommandLineException(
585 "Missing string after \"--png-latex-before-math\""
586 );
587 }
588 interface.mPurifiedTexOptions.mLaTeXBeforeMath = gUnicodeConverter.ConvertIn(string(argv[i]));
589 }
590 else
591 throw CommandLineException(
592 "Unrecognised command line option \"" + arg + "\""
593 );
594 }
595
596 // Finished processing command line, now process the input
597
598 #ifdef BLAHTEXML_USING_XERCES
599 if (doXMLinput)
600 return batchXMLConversion(interface);
601 #endif
602 if (isatty(0) && !inputFilePath)
603 ShowUsage();
604
605 wostringstream mainOutput;
606
607 try
608 {
609 wstring input;
610
611 // Read input file
612 string inputUtf8;
613 {
614 if (inputFilePath)
615 {
616 ifstream inputFile (inputFilePath, ifstream::in);
617
618 if (inputFile.is_open())
619 {
620 char c;
621 while (inputFile.get(c))
622 inputUtf8 += c;
623 inputFile.close();
624 }
625
626 else
627 {
628 throw CommandLineException("Could not open the input file!");
629 }
630 }
631
632 else
633 {
634 char c;
635 while (cin.get(c))
636 inputUtf8 += c;
637
638 }
639 }
640
641 // This try block converts UnicodeConverter::Exception into an
642 // input syntax error, i.e. if the user supplies invalid UTF-8.
643 // (Later we treat such exceptions as debug assertions.)
644 try
645 {
646 input = gUnicodeConverter.ConvertIn(inputUtf8);
647 }
648 catch (UnicodeConverter::Exception& e)
649 {
650 throw blahtex::Exception(L"InvalidUtf8Input");
651 }
652
653 // Build the parse and layout trees.
654 interface.ProcessInput(input, displayStyle);
655
656 if (debugParseTree)
657 {
658 mainOutput << L"\n=== BEGIN PARSE TREE ===\n\n";
659 interface.GetManager()->GetParseTree()->Print(mainOutput);
660 mainOutput << L"\n=== END PARSE TREE ===\n\n";
661 }
662
663 if (debugLayoutTree)
664 {
665 mainOutput << L"\n=== BEGIN LAYOUT TREE ===\n\n";
666 wostringstream temp;
667 interface.GetManager()->GetLayoutTree()->Print(temp);
668 mainOutput << XmlEncode(temp.str(), EncodingOptions());
669 mainOutput << L"\n=== END LAYOUT TREE ===\n\n";
670 }
671
672 // Generate purified TeX if required.
673 if (doPng || debugPurifiedTex)
674 {
675 // This stream is where we build the PNG output block:
676 wostringstream pngOutput;
677
678 try
679 {
680 wstring purifiedTex = interface.GetPurifiedTex();
681
682 if (debugPurifiedTex)
683 {
684 pngOutput << L"\n=== BEGIN PURIFIED TEX ===\n\n";
685 pngOutput << purifiedTex;
686 pngOutput << L"\n=== END PURIFIED TEX ===\n\n";
687 }
688
689 // Make the system calls to generate the PNG image
690 // if requested.
691 if (doPng)
692 {
693 PngInfo info = MakePngFile(purifiedTex, "", pngParams);
694
695 // The height and depth measurements are only
696 // valid if the "preview" package is used:
697 if (interface.mPurifiedTexOptions.mAllowPreview
698 && info.mDimensionsValid
699 )
700 {
701 pngOutput << L"<height>"
702 << info.mHeight << L"</height>\n";
703 pngOutput << L"<depth>"
704 << info.mDepth << L"</depth>\n";
705 }
706
707 pngOutput << L"<md5>"
708 << gUnicodeConverter.ConvertIn(info.mMd5)
709 << L"</md5>\n";
710 }
711 }
712
713 // Catching errors that occurred during PNG generation:
714 catch (blahtex::Exception& e)
715 {
716 pngOutput.str(L"");
717 pngOutput << FormatError(e, interface.mEncodingOptions)
718 << endl;
719 }
720
721 mainOutput << L"<png>\n" << pngOutput.str() << L"</png>\n";
722 }
723
724 // This block generates MathML output if requested.
725 if (doMathml)
726 {
727 // This stream is where we build the MathML output block:
728 wostringstream mathmlOutput;
729
730 try
731 {
732 mathmlOutput << L"<markup>\n";
733 mathmlOutput << interface.GetMathml();
734 if (!interface.mIndented)
735 mathmlOutput << L"\n";
736 mathmlOutput << L"</markup>\n";
737 }
738
739 // Catch errors in generating the MathML:
740 catch (blahtex::Exception& e)
741 {
742 mathmlOutput.str(L"");
743 mathmlOutput
744 << FormatError(e, interface.mEncodingOptions)
745 << endl;
746 }
747
748 mainOutput << L"<mathml>\n" << mathmlOutput.str()
749 << L"</mathml>\n";
750 }
751 }
752
753 catch (blahtex::TokenException& e)
754 {
755 mainOutput.str(L"");
756 mainOutput << FormatTokenError(e, interface.mEncodingOptions) << endl;
757 }
758
759 // This catches input syntax errors.
760 catch (blahtex::Exception& e)
761 {
762 mainOutput.str(L"");
763 mainOutput << FormatError(e, interface.mEncodingOptions) << endl;
764 }
765
766 cout << "<blahtex>\n"
767 << gUnicodeConverter.ConvertOut(mainOutput.str())
768 << "</blahtex>\n";
769 }
770
771 // The following errors might occur if there's a bug in blahtex that
772 // some assertion condition picked up. We still want to report these
773 // nicely to the user so that they can notify the developers.
774 catch (std::logic_error& e)
775 {
776 // WARNING: this doesn't XML-encode the message
777 // (We don't expect to the message to contain the characters &<>)
778 cout << "<blahtex>\n<logicError>" << e.what()
779 << "</logicError>\n</blahtex>\n";
780 }
781
782 // These indicate incorrect command line syntax:
783 catch (CommandLineException& e)
784 {
785 cerr << "blahtex: " << e.mMessage
786 #ifdef BLAHTEXML_USING_XERCES
787 << " (try \"blahtexml --help\")\n";
788 #else
789 << " (try \"blahtex --help\")\n";
790 #endif
791 }
792
793 // These kind of errors should only occur if the program has been
794 // installed incorrectly.
795 catch (std::runtime_error& e)
796 {
797 cerr << "blahtex runtime error: " << e.what() << endl;
798 }
799
800 return 0;
801 }
802
803 // end of file @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
804