EMMA Coverage Report (generated Fri Feb 14 08:28:31 UTC 2014)
[all classes][org.qedeq.kernel.bo.service.unicode]

COVERAGE SUMMARY FOR SOURCE FILE [Latex2UnicodeParser.java]

nameclass, %method, %block, %line, %
Latex2UnicodeParser.java100% (2/2)94%  (29/31)83%  (2256/2717)87%  (549.4/635)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Latex2UnicodeParser$1100% (1/1)33%  (1/3)33%  (6/18)33%  (1/3)
addWarning (int, String, SourcePosition, SourcePosition): void 0%   (0/1)0%   (0/1)0%   (0/1)
getReferenceLink (String, SourcePosition, SourcePosition): String 0%   (0/1)0%   (0/11)0%   (0/1)
Latex2UnicodeParser$1 (Latex2UnicodeParser): void 100% (1/1)100% (6/6)100% (1/1)
     
class Latex2UnicodeParser100% (1/1)100% (28/28)83%  (2250/2699)87%  (549.4/633)
mathbb (String): void 100% (1/1)26%  (20/76)29%  (6/21)
readTilToken (String): SubTextInput 100% (1/1)52%  (35/67)85%  (11/13)
readSection (String): SubTextInput 100% (1/1)58%  (49/85)88%  (15/17)
mathfrak (String): void 100% (1/1)62%  (10/16)75%  (3/4)
print (String): void 100% (1/1)78%  (810/1035)80%  (184/229)
readCurlyBraceContents (): SubTextInput 100% (1/1)79%  (84/106)92%  (24/26)
readBackslashToken (): String 100% (1/1)83%  (82/99)79%  (15/19)
readToken (): String 100% (1/1)84%  (158/187)84%  (39.6/47)
parseQref (): void 100% (1/1)89%  (74/83)89%  (17/19)
<static initializer> 100% (1/1)90%  (9/10)90%  (0.9/1)
parseAndPrint (SubTextInput): void 100% (1/1)97%  (522/538)98%  (125.9/129)
Latex2UnicodeParser (ReferenceFinder): void 100% (1/1)100% (70/70)100% (18/18)
addWarning (int, String, int, int): void 100% (1/1)100% (12/12)100% (2/2)
bold (String): void 100% (1/1)100% (16/16)100% (4/4)
emph (String): void 100% (1/1)100% (16/16)100% (4/4)
eof (): boolean 100% (1/1)100% (4/4)100% (1/1)
getAbsoluteSourcePosition (int): SourcePosition 100% (1/1)100% (8/8)100% (1/1)
getChar (): int 100% (1/1)100% (4/4)100% (1/1)
getUtf8 (String): String 100% (1/1)100% (17/17)100% (4/4)
isWs (String): boolean 100% (1/1)100% (10/10)100% (1/1)
parseBegin (): void 100% (1/1)100% (120/120)100% (34/34)
parseFootnote (): void 100% (1/1)100% (64/64)100% (22/22)
printSubscript (String): void 100% (1/1)100% (6/6)100% (2/2)
printSuperscript (String): void 100% (1/1)100% (6/6)100% (2/2)
println (): void 100% (1/1)100% (4/4)100% (2/2)
read (): int 100% (1/1)100% (4/4)100% (1/1)
readln (): String 100% (1/1)100% (23/23)100% (6/6)
transform (ReferenceFinder, String, int): String 100% (1/1)100% (13/13)100% (3/3)

1/* This file is part of the project "Hilbert II" - http://www.qedeq.org
2 *
3 * Copyright 2000-2014,  Michael Meyling <mime@qedeq.org>.
4 *
5 * "Hilbert II" is free software; you can redistribute
6 * it and/or modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15 
16package org.qedeq.kernel.bo.service.unicode;
17 
18import java.util.Stack;
19 
20import org.qedeq.base.io.AbstractOutput;
21import org.qedeq.base.io.SourcePosition;
22import org.qedeq.base.io.StringOutput;
23import org.qedeq.base.io.SubTextInput;
24import org.qedeq.base.io.TextInput;
25import org.qedeq.base.trace.Trace;
26import org.qedeq.kernel.bo.service.latex.LatexErrorCodes;
27 
28/**
29 * Transform LaTeX into Unicode format.
30 *
31 * @author  Michael Meyling
32 */
33public final class Latex2UnicodeParser {
34 
35    /** This class. */
36    private static final Class CLASS = Latex2UnicodeParser.class;
37 
38    /** These characters get a special treatment in LaTeX. */
39    private static final String SPECIALCHARACTERS = "(),{}\\~%$&\'`^_-";
40 
41    /** Herein goes our output. */
42    private final AbstractOutput output;
43 
44    /** Resolver for references. */
45    private final ReferenceFinder finder;
46 
47    /** This is our current input stream .*/
48    private SubTextInput input;
49 
50    /** Math mode on? */
51    private boolean mathMode = false;
52 
53    /** Mathfrak mode on? */
54    private boolean mathfrak = false;
55 
56    /** Emphasize on? */
57    private boolean emph = false;
58 
59    /** Bold on? */
60    private boolean bold = false;
61 
62    /** Mathbb on? */
63    private boolean mathbb = false;
64 
65    /** Stack for input parser. */
66    private Stack inputStack = new Stack();
67 
68    /** Stack for math mode. */
69    private Stack mathModeStack = new Stack();
70 
71    /** Stack for mathfrak mode. */
72    private Stack mathfrakStack = new Stack();
73 
74    /** Stack for emphasize mode. */
75    private Stack emphStack = new Stack();
76 
77    /** Stack for bold mode. */
78    private Stack boldStack = new Stack();
79 
80    /** Stack for mathbb mode. */
81    private Stack mathbbStack = new Stack();
82 
83    /** Stack for skipWhitspace mode. */
84    private Stack skipWhitespaceStack = new Stack();
85 
86    /** Should I skip whitespace before printing the next token. */
87    private boolean skipWhitespace;
88 
89    /** Here the last read token begins. This is an absolute position. */
90    private int tokenBegin;
91 
92    /** Here the last read token ends. This is an absolute position. */
93    private int tokenEnd;
94 
95    /** Current item number. */
96    private int itemNumber;
97 
98    /**
99     * Parse LaTeX text into QEDEQ module string.
100     *
101     * @param   finder  Finder for references.
102     * @param   input   Parse this input.
103     * @param   columns Maximum column number. Break (if possible) before.
104     * @return  QEDEQ module string.
105     */
106    public static final String transform(final ReferenceFinder finder, final String input,
107            final int columns) {
108        final Latex2UnicodeParser parser = new Latex2UnicodeParser(finder);
109        parser.output.setColumns(columns);
110        return parser.getUtf8(input);
111    }
112 
113    /**
114     * Constructor.
115     *
116     * @param   finder  Finder for references.
117     */
118    private Latex2UnicodeParser(final ReferenceFinder finder) {
119        // use dummy implementation if finder is null
120        if (finder == null) {
121            this.finder = new ReferenceFinder() {
122                public String getReferenceLink(final String reference,
123                        final SourcePosition startDelta, final SourcePosition endDelta) {
124                    return "[" + reference + "]";
125                }
126 
127                public void addWarning(final int code, final String msg,
128                        final SourcePosition startDelta, final SourcePosition endDelta) {
129                    // nothing to do
130                }
131            };
132        } else {
133            this.finder = finder;
134        }
135        this.output = new StringOutput();
136    }
137 
138    /**
139     * Get UTF-8 String out of LaTeX text.
140     *
141     * @param   text    LaTeX.
142     * @return  UTF-8.
143     */
144    private String getUtf8(final String text) {
145        skipWhitespace = true;
146        this.input = new SubTextInput(text);
147        parseAndPrint(this.input);
148        return output.toString();
149    }
150 
151    /**
152     * Do parsing and print result.
153     *
154     * @param   input   Parse this LaTeX text and print UTF-8 into output.
155     */
156    private void parseAndPrint(final SubTextInput input) {
157        // remember old:
158        inputStack.push(this.input);
159        mathModeStack.push(Boolean.valueOf(mathMode));
160        mathfrakStack.push(Boolean.valueOf(mathfrak));
161        emphStack.push(Boolean.valueOf(emph));
162        boldStack.push(Boolean.valueOf(bold));
163        mathbbStack.push(Boolean.valueOf(mathbb));
164        skipWhitespaceStack.push(Boolean.valueOf(skipWhitespace));
165        try {
166            this.input = input;
167            boolean whitespace = false;
168            while (!eof()) {
169                String token = readToken();
170                if (!token.startsWith("\\")) {
171                    token = token.trim();
172                }
173                if (token.length() == 0) {
174                    whitespace = true;
175                    continue;
176                }
177                if (whitespace && !"\\par".equals(token)) {
178                    print(" ");
179                    whitespace = false;
180                }
181                if ("\\begin".equals(token)) {
182                    parseBegin();
183                } else if ("\\footnote".equals(token)) {
184                    parseFootnote();
185                } else if ("\\qref".equals(token)) {
186                    parseQref();
187                } else if ("$$".equals(token)) {
188                    mathMode = true;
189                    final SubTextInput content = readTilToken(token);
190                    println();
191                    parseAndPrint(content);
192                    println();
193                    mathMode = false;
194                } else if ("$".equals(token)) {
195                    mathMode = true;
196                    final SubTextInput content = readTilToken(token);
197                    parseAndPrint(content);
198                    mathMode = false;
199                } else if ("\\mathfrak".equals(token)) {
200                    if ('{' == getChar()) {
201                        mathfrak = true;
202                        final SubTextInput content = readCurlyBraceContents();
203                        parseAndPrint(content);
204                        mathfrak = false;
205                    } else {
206                        mathfrak = true;
207                    }
208                } else if ("\\mathbb".equals(token)) {
209                    if ('{' == getChar()) {
210                        mathbb = true;
211                        final SubTextInput content = readCurlyBraceContents();
212                        parseAndPrint(content);
213                        mathbb = false;
214                    } else {
215                        mathbb = true;
216                    }
217                } else if ("\\emph".equals(token)) {
218                    if ('{' == getChar()) {
219                        emph = true;
220                        final SubTextInput content = readCurlyBraceContents();
221                        parseAndPrint(content);
222//                        output.addWs("\u2006");
223                        output.addWs(" ");
224                        emph = false;
225                    } else {
226                        emph = true;
227                    }
228                } else if ("\\textbf".equals(token)) {
229                    if ('{' == getChar()) {
230                        bold = true;
231                        final SubTextInput content = readCurlyBraceContents();
232                        parseAndPrint(content);
233                        bold = false;
234                    } else {
235                        bold = true;
236                    }
237                } else if ("\\cite".equals(token)) {
238                    if ('{' == getChar()) {
239                        final SubTextInput content = readCurlyBraceContents();
240                        output.addToken("[" + content.asString() + "]");
241                    }
242                } else if ("\\tag".equals(token)) {
243                    if ('{' == getChar()) {
244                        final SubTextInput content = readCurlyBraceContents();
245                        output.addToken("(" + content.asString() + ")");
246                    }
247                } else if ("\\mbox".equals(token)) {
248                    if ('{' == getChar()) {
249                        final SubTextInput content = readCurlyBraceContents();
250                        parseAndPrint(content);
251                    }
252                } else if ("\\cline".equals(token)) {
253                    if ('{' == getChar()) {
254                        readCurlyBraceContents();
255                        // ignore
256                    }
257                    output.addToken("_______________________________________");
258                    println();
259                } else if ("\\item".equals(token)) {
260                    output.popLevel(3);
261                    itemNumber++;
262                    output.println();
263                    output.addToken(itemNumber + ".");
264                    output.addWs("");
265                    output.pushLevel("   ");
266                    output.setTabLevel();
267                } else if ("{".equals(token)) {
268                    input.readInverse();
269                    final SubTextInput content = readCurlyBraceContents();
270                    parseAndPrint(content);
271                } else if ("\\url".equals(token)) {
272                    final SubTextInput content = readCurlyBraceContents();
273                    output.addToken(" " + content.asString() + " ");
274                } else if ('{' == getChar() && ("\\index".equals(token) || "\\label".equals(token)
275                        || token.equals("\\vspace") || token.equals("\\hspace")
276                        || token.equals("\\vspace*") || token.equals("\\hspace*"))) {
277                    // ignore content
278                    readCurlyBraceContents();
279                } else if ("_".equals(token) || "^".equals(token)) {
280                    if (mathMode) {
281                        String content;
282                        if ('{' == getChar()) {
283                            content = readCurlyBraceContents().asString();
284                        } else {
285                            content = readToken();
286                        }
287                        if ("_".equals(token)) {
288                            printSubscript(content);
289                        } else {
290                            printSuperscript(content);
291                        }
292                    } else {
293                        print(token);
294                    }
295                } else {
296                    print(token);
297                }
298            }
299        } finally {
300            this.input = (SubTextInput) inputStack.pop();
301            mathMode = ((Boolean) mathModeStack.pop()).booleanValue();
302            mathfrak = ((Boolean) mathfrakStack.pop()).booleanValue();
303            emph = ((Boolean) emphStack.pop()).booleanValue();
304            bold = ((Boolean) boldStack.pop()).booleanValue();
305            skipWhitespace = ((Boolean) skipWhitespaceStack.pop()).booleanValue();
306            output.flush();
307        }
308    }
309 
310    /**
311     * Parse after \footnote.
312     */
313    private void parseFootnote() {
314        if ('{' == getChar()) {
315            final SubTextInput content = readCurlyBraceContents();
316            println();
317            output.printWithoutSplit("          \u250C");
318            output.pushLevel();
319            output.pushLevel();
320            output.pushLevel();
321            output.pushLevel();
322            output.pushLevel();
323            output.pushLevel("\u2502 ");
324            println();
325            parseAndPrint(content);
326            output.popLevel();
327            output.popLevel();
328            output.popLevel();
329            output.popLevel();
330            output.popLevel();
331            output.popLevel();
332            println();
333            output.printWithoutSplit("          \u2514");
334            println();
335        }
336    }
337 
338    /**
339     * Transform <code>\qref{key}</code> entries into common LaTeX code.
340     *
341     * @param   text    Work on this text.
342     * @return  Result of transforming \qref into text.
343     */
344    /**
345     * Parse after \footnote.
346     */
347    private void parseQref() {
348        final String method = "parseQref()";
349        final int localStart1 = input.getAbsolutePosition();
350        if ('{' == getChar()) {
351            final SubTextInput content = readCurlyBraceContents();
352            String ref = content.asString().trim();
353            Trace.param(CLASS, this, method, "ref", ref);
354            if (ref.length() == 0) {
355                addWarning(LatexErrorCodes.QREF_EMPTY_CODE, LatexErrorCodes.QREF_EMPTY_TEXT,
356                    localStart1, input.getAbsolutePosition());
357                return;
358            }
359            if (ref.length() > 1024) {
360                addWarning(LatexErrorCodes.QREF_END_NOT_FOUND_CODE,
361                    LatexErrorCodes.QREF_END_NOT_FOUND_TEXT,
362                    localStart1, input.getAbsolutePosition());
363                return;
364            }
365            if (ref.indexOf("{") >= 0) {
366                addWarning(LatexErrorCodes.QREF_END_NOT_FOUND_CODE,
367                    LatexErrorCodes.QREF_END_NOT_FOUND_TEXT,
368                    localStart1, input.getAbsolutePosition());
369                input.setAbsolutePosition(localStart1);
370                return;
371            }
372 
373            String display = finder.getReferenceLink(ref, getAbsoluteSourcePosition(localStart1),
374                getAbsoluteSourcePosition(input.getAbsolutePosition()));
375            output.addToken(display);
376        }
377    }
378 
379 
380    /**
381     * Parse after \begin.
382     */
383    private void parseBegin() {
384        final String kind = readCurlyBraceContents().asString();   // ignore
385        final SubTextInput content = readSection(kind);
386        if ("eqnarray".equals(kind)
387            || "eqnarray*".equals(kind)
388            || "equation*".equals(kind)) {
389            mathMode = true;
390            skipWhitespace = false;
391            parseAndPrint(content);
392            println();
393            mathMode = false;
394        } else if ("quote".equals(kind)) {
395            output.pushLevel();
396            output.pushLevel();
397            output.pushLevel();
398            println();
399            parseAndPrint(content);
400            println();
401            output.popLevel();
402            output.popLevel();
403            output.popLevel();
404        } else if ("tabularx".equals(kind)) {
405            skipWhitespace = false;
406            parseAndPrint(content);
407        } else if ("enumerate".equals(kind)) {
408            itemNumber = 0;
409            output.pushLevel("   ");
410            parseAndPrint(content);
411            output.popLevel(3);
412        } else if ("verbatim".equals(kind)) {
413            final String level = output.getLevel();
414            output.setLevel("");
415            print(content.asString());
416            output.setLevel(level);
417        } else {
418            parseAndPrint(content);
419        }
420    }
421 
422    private void printSubscript(final String content) {
423        output.addToken(Latex2UnicodeSpecials.transform2Subscript(content));
424    }
425 
426    private void printSuperscript(final String content) {
427        output.addToken(Latex2UnicodeSpecials.transform2Superscript(content));
428    }
429 
430    /**
431     * Read until section ends with \{kind}.
432     *
433     * @param   kind    Look for the end of this.
434     * @return  Read text.
435     */
436    private SubTextInput readSection(final String kind) {
437        if ('{' == getChar()) { // skip content
438            readCurlyBraceContents();
439        }
440        if ('{' == getChar()) { // skip content
441            readCurlyBraceContents();
442        }
443        final int localStart = input.getAbsolutePosition();
444        int current = localStart;
445        do {
446            current = input.getAbsolutePosition();
447            final String item = readToken();
448            if (item == null) {
449                Trace.fatal(CLASS, this, "readSection", "not found: " + "\\end{" + kind + "}",
450                    new IllegalArgumentException("from " + localStart + " to " + input.getAbsolutePosition()
451                    + input.getPosition()));
452                break;
453            }
454            if ("\\end".equals(item)) {
455                final String curly2 = readCurlyBraceContents().asString();
456                if (kind.equals(curly2)) {
457                    break;
458                }
459            }
460        } while (true);
461        return input.getSubTextInput(localStart, current);
462    }
463 
464    /**
465     * Get text till <code>token</code> occurs.
466     *
467     * @param   token   Terminator token.
468     * @return  Read text before token.
469     */
470    private SubTextInput readTilToken(final String token) {
471        final int localStart = input.getAbsolutePosition();
472        final StringBuffer buffer = new StringBuffer();
473        int current = localStart;
474        do {
475            current = input.getAbsolutePosition();
476            final String item = readToken();
477            if (item == null) {
478                Trace.fatal(CLASS, this, "readSection", "not found: " + token,
479                    new IllegalArgumentException("from " + localStart + " to " + current
480                    + input.getAbsolutePosition()));
481                break;
482            }
483            if (token.equals(item)) {
484                break;
485            }
486            buffer.append(item);
487        } while (true);
488        return input.getSubTextInput(localStart, current);
489    }
490 
491    /**
492     * Read next token from input stream.
493     *
494     * @return  Read token.
495     */
496    protected final String readToken() {
497        final String method = "readToken()";
498        Trace.begin(CLASS, this, method);
499        tokenBegin = input.getAbsolutePosition();
500        StringBuffer token = new StringBuffer();
501        try {
502            do {
503                if (eof()) {
504                    if (token.length() <= 0) {
505                        token = null;
506                    }
507                    break;
508                }
509                final char c = (char) getChar();
510                if (Character.isDigit(c)) {
511                    token.append((char) read());
512                    if (Character.isDigit((char) getChar())) {
513                        continue;
514                    }
515                    break;
516                }
517                if (Character.isLetter(c)) {
518                    token.append((char) read());
519                    if (Character.isLetter((char) getChar())) {
520                        continue;
521                    }
522                    break;
523                }
524                if (SPECIALCHARACTERS.indexOf(c) >= 0) {
525                    switch (c) {
526                    case '&':
527                    case '{':
528                    case '}':
529                    case '~':
530                    case '_':
531                    case '^':
532                        token.append((char) read());
533                        break;
534                    case '$':
535                    case '\'':
536                    case '`':
537                    case '-':
538                        token.append((char) read());
539                        if (c == getChar()) {
540                            continue;
541                        }
542                        break;
543                    case '%':
544                        token.append((char) read());
545                        if (c == getChar()) {
546                            // we must skip till end of line
547                            token.append(readln());
548//                            System.out.println("skipping comment:");
549//                            System.out.println(token);
550                            token.setLength(0);
551                            continue;
552                        }
553                        break;
554                    case '\\':
555                        if (' ' == getChar()) {
556                            token.append("\\");
557                            token.append((char) read());
558                            break;
559                        }
560                        final String t = readBackslashToken();
561                        token.append(t);
562                        break;
563                    default:
564                        read();
565                        token.append(c);
566                    }
567                    break;
568                }
569                token.append((char) read());
570                if ('_' == getChar() || '^' == getChar()) {
571                    token.append((char) read());
572                    continue;
573                }
574                break;
575            } while (!eof());
576            Trace.param(CLASS, this, method, "Read token", token);
577//            System.out.println("< " + token);
578            tokenEnd = input.getAbsolutePosition();
579            return (token != null ? token.toString() : null);
580        } finally {
581            Trace.end(CLASS, this, method);
582        }
583    }
584 
585    /**
586     * Get token that starts with a backlash.
587     *
588     * @return  Token with backslash.
589     */
590    private String readBackslashToken() {
591        final String method = "readBackslashToken()";
592        Trace.begin(CLASS, this, method);
593        if (getChar() != '\\') {
594            throw new IllegalArgumentException("\\ expected");
595        }
596        read(); // read \
597        if (eof()) {
598            Trace.param(CLASS, this, method, "return", null);
599            Trace.end(CLASS, this, method);
600            return null;
601        }
602        if (!Character.isLetter((char) getChar())) {
603            Trace.param(CLASS, this, method, "return", (char) getChar());
604            Trace.end(CLASS, this, method);
605            return "\\" + ((char) read());
606        }
607        final StringBuffer buffer = new StringBuffer("\\");
608        do {
609            buffer.append((char) read());
610        } while (!eof() && (Character.isLetter((char) getChar()) || '*' == (char) getChar()));
611        Trace.param(CLASS, this, method, "return", buffer.toString());
612        Trace.end(CLASS, this, method);
613        return buffer.toString();
614    }
615 
616    /**
617     * Read contents that is within { .. }.
618     *
619     * @return  Contents.
620     */
621    private SubTextInput readCurlyBraceContents() {
622        final int localStart = input.getAbsolutePosition();
623        final String first = readToken();
624        if (!"{".equals(first)) {
625            addWarning(LatexErrorCodes.BRACKET_START_NOT_FOUND_CODE,
626                    LatexErrorCodes.BRACKET_START_NOT_FOUND_TEXT,
627                    localStart, input.getAbsolutePosition());
628            throw new IllegalArgumentException("\"{\" expected, but was: \"" + first + "\"");
629        }
630        final int curlyStart = input.getAbsolutePosition();
631        int curlyEnd = curlyStart;
632        final StringBuffer buffer = new StringBuffer();
633        String next = "";
634        int level = 1;
635        while (level > 0 && getChar() != TextInput.EOF) {
636            next = readToken();
637            if ("{".equals(next)) {
638                level++;
639            } else if ("}".equals(next)) {
640                level--;
641            }
642            if (level <= 0) {
643                break;
644            }
645            buffer.append(next);
646            curlyEnd = input.getAbsolutePosition();
647        }
648        if (!"}".equals(next)) {
649            addWarning(LatexErrorCodes.BRACKET_END_NOT_FOUND_CODE,
650                LatexErrorCodes.BRACKET_END_NOT_FOUND_TEXT,
651                localStart, input.getAbsolutePosition());
652            buffer.setLength(0);
653            input.setAbsolutePosition(curlyStart);
654            curlyEnd = curlyStart;
655        }
656        return input.getSubTextInput(curlyStart, curlyEnd);
657    }
658 
659    /**
660     * Print <code>token</code> to output stream.
661     *
662     * @param   token    Print this for UTF-8.
663     */
664    private final void print(final String token) {
665//        System.out.println("> " + token);
666        if (token.trim().length() == 0) {
667            if (skipWhitespace) {
668                return;
669            }
670        }
671        skipWhitespace = false;
672        if (token.equals("\\par")) {
673            println();
674            println();
675            skipWhitespace = true;
676        } else if (token.equals("\\\\")) {
677            println();
678        } else if (token.equals("&")) {
679            output.addWs(" ");
680        } else if (token.equals("\\-")) {
681            // ignore
682        } else if (token.equals("--")) {
683            output.addToken("\u2012");
684        } else if (token.equals("`")) {
685            output.addWs("\u2018");
686        } else if (token.equals("'")) {
687            output.addToken("\u2019");
688        } else if (token.equals("\\neq")) {
689            output.addToken("\u2260");
690        } else if (token.equals("\\in")) {
691            output.addToken("\u2208");
692        } else if (token.equals("\\forall")) {
693            output.addToken("\u2200");
694        } else if (token.equals("\\exists")) {
695            output.addToken("\u2203");
696        } else if (token.equals("\\emptyset")) {
697            output.addToken("\u2205");
698        } else if (token.equals("\\rightarrow")) {
699            output.addToken("\u2192");
700        } else if (token.equals("\\Rightarrow")) {
701            output.addToken("\u21D2");
702        } else if (token.equals("\\leftrightarrow")) {
703            output.addToken("\u2194");
704        } else if (token.equals("\\Leftarrow")) {
705            output.addToken("\u21D0");
706        } else if (token.equals("\\Leftrightarrow")) {
707            output.addToken("\u21D4");
708        } else if (token.equals("\\langle")) {
709            output.addToken("\u2329");
710        } else if (token.equals("\\rangle")) {
711            output.addToken("\u232A");
712        } else if (token.equals("\\land") || token.equals("\\vee")) {
713            output.addToken("\u2227");
714        } else if (token.equals("\\lor") || token.equals("\\wedge")) {
715            output.addToken("\u2228");
716        } else if (token.equals("\\bar")) {
717            output.addToken("\u203E");
718        } else if (token.equals("\\bigcap")) {
719            output.addToken("\u22C2");
720        } else if (token.equals("\\cap")) {
721            output.addToken("\u2229");
722        } else if (token.equals("\\bigcup")) {
723            output.addToken("\u22C3");
724        } else if (token.equals("\\cup")) {
725            output.addToken("\u222A");
726        } else if (token.equals("\\in")) {
727            output.addToken("\u2208");
728        } else if (token.equals("\\notin")) {
729            output.addToken("\u2209");
730        } else if (token.equals("\\Alpha")) {
731            output.addToken("\u0391");
732        } else if (token.equals("\\alpha")) {
733            output.addToken("\u03B1");
734        } else if (token.equals("\\Beta")) {
735            output.addToken("\u0392");
736        } else if (token.equals("\\beta")) {
737            output.addToken("\u03B2");
738        } else if (token.equals("\\Gamma")) {
739            output.addToken("\u0393");
740        } else if (token.equals("\\gamma")) {
741            output.addToken("\u03B3");
742        } else if (token.equals("\\Delta")) {
743            output.addToken("\u0394");
744        } else if (token.equals("\\delta")) {
745            output.addToken("\u03B4");
746        } else if (token.equals("\\Epslilon")) {
747            output.addToken("\u0395");
748        } else if (token.equals("\\epsilon")) {
749            output.addToken("\u03B5");
750        } else if (token.equals("\\Zeta")) {
751            output.addToken("\u0396");
752        } else if (token.equals("\\zeta")) {
753            output.addToken("\u03B6");
754        } else if (token.equals("\\Eta")) {
755            output.addToken("\u0397");
756        } else if (token.equals("\\eta")) {
757            output.addToken("\u03B7");
758        } else if (token.equals("\\Theta")) {
759            output.addToken("\u0398");
760        } else if (token.equals("\\theta")) {
761            output.addToken("\u03B8");
762        } else if (token.equals("\\Iota")) {
763            output.addToken("\u0399");
764        } else if (token.equals("\\iota")) {
765            output.addToken("\u03B9");
766        } else if (token.equals("\\Kappa")) {
767            output.addToken("\u039A");
768        } else if (token.equals("\\kappa")) {
769            output.addToken("\u03BA");
770        } else if (token.equals("\\Lamda")) {
771            output.addToken("\u039B");
772        } else if (token.equals("\\lamda")) {
773            output.addToken("\u03BB");
774        } else if (token.equals("\\Mu")) {
775            output.addToken("\u039C");
776        } else if (token.equals("\\mu")) {
777            output.addToken("\u03BC");
778        } else if (token.equals("\\Nu")) {
779            output.addToken("\u039D");
780        } else if (token.equals("\\nu")) {
781            output.addToken("\u03BD");
782        } else if (token.equals("\\Xi")) {
783            output.addToken("\u039E");
784        } else if (token.equals("\\xi")) {
785            output.addToken("\u03BE");
786        } else if (token.equals("\\Omikron")) {
787            output.addToken("\u039F");
788        } else if (token.equals("\\omikron")) {
789            output.addToken("\u03BF");
790        } else if (token.equals("\\Pi")) {
791            output.addToken("\u03A0");
792        } else if (token.equals("\\pi")) {
793            output.addToken("\u03C0");
794        } else if (token.equals("\\Rho")) {
795            output.addToken("\u03A1");
796        } else if (token.equals("\\rho")) {
797            output.addToken("\u03C1");
798        } else if (token.equals("\\Sigma")) {
799            output.addToken("\u03A3");
800        } else if (token.equals("\\sigma")) {
801            output.addToken("\u03C3");
802        } else if (token.equals("\\Tau")) {
803            output.addToken("\u03A4");
804        } else if (token.equals("\\tau")) {
805            output.addToken("\u03C4");
806        } else if (token.equals("\\Upsilon")) {
807            output.addToken("\u03A5");
808        } else if (token.equals("\\upsilon")) {
809            output.addToken("\u03C5");
810        } else if (token.equals("\\Phi")) {
811            output.addToken("\u03A6");
812        } else if (token.equals("\\phi")) {
813            output.addToken("\u03C6");
814        } else if (token.equals("\\Chi")) {
815            output.addToken("\u03A6");
816        } else if (token.equals("\\chi")) {
817            output.addToken("\u03C7");
818        } else if (token.equals("\\Psi")) {
819            output.addToken("\u03A8");
820        } else if (token.equals("\\psi")) {
821            output.addToken("\u03C8");
822        } else if (token.equals("\\Omega")) {
823            output.addToken("\u03A9");
824        } else if (token.equals("\\omega")) {
825            output.addToken("\u03C9");
826        } else if (token.equals("\\subset")) {
827            output.addToken("\u2282");
828        } else if (token.equals("\\supset")) {
829            output.addToken("\u2283");
830        } else if (token.equals("\\subseteq")) {
831            output.addToken("\u2286");
832        } else if (token.equals("\\supseteq")) {
833            output.addToken("\u2287");
834        } else if (token.equals("\\{")) {
835            output.addToken("{");
836        } else if (token.equals("\\}")) {
837            output.addToken("}");
838        } else if (token.equals("\\&")) {
839            output.addToken("&");
840        } else if (token.equals("\\ ")) {
841            output.addWs(" ");
842        } else if (token.equals("\\S")) {
843            output.addToken("\u00A7");
844        } else if (token.equals("\\tt")) {
845            // ignore
846        } else if (token.equals("\\tiny")) {
847            // ignore
848        } else if (token.equals("\\nonumber")) {
849            // ignore
850        } else if (token.equals("\\LaTeX")) {
851            output.addToken("LaTeX");
852        } else if (token.equals("\\vdash")) {
853            output.addToken("\u22A2");
854        } else if (token.equals("\\dashv")) {
855            output.addToken("\u22A3");
856        } else if (token.equals("\\times")) {
857            output.addToken("\u00D7");
858        } else if (token.equals("~")) {
859            output.addToken("\u00A0");
860        } else if (token.equals("\\quad")) {
861//            output.addWs("\u2000");
862            output.addWs(" ");
863        } else if (token.equals("\\qquad")) {
864//            output.addWs("\u2000\u2000");
865            output.addWs("  ");
866        } else if (token.equals("\\,")) {
867//            output.addWs("\u2009");
868            output.addWs(" ");
869        } else if (token.equals("\\neg") || token.equals("\\not")) {
870            output.addToken("\u00AC");
871        } else if (token.equals("\\bot")) {
872            output.addToken("\u22A5");
873        } else if (token.equals("\\top")) {
874            output.addToken("\u22A4");
875        } else if (token.equals("''") || token.equals("\\grqq")) {
876            output.addToken("\u201D");
877        } else if (token.equals("``") || token.equals("\\glqq")) {
878            skipWhitespace = true;
879            output.addToken("\u201E");
880        } else if (token.equals("\\ldots")) {
881            output.addToken("...");
882        } else if (token.equals("\\cdots")) {
883            output.addToken("\u00B7\u00B7\u00B7");
884        } else if (token.equals("\\hdots")) {
885            output.addToken("\u00B7\u00B7\u00B7");
886        } else if (token.equals("\\vdots")) {
887            output.addToken("\u2807");
888        } else if (token.equals("\\overline")) {    // TODO 20101018 m31: we assume set complement
889            output.addToken("\u2201");
890        } else if (token.startsWith("\\")) {
891            addWarning(LatexErrorCodes.COMMAND_NOT_SUPPORTED_CODE,
892                LatexErrorCodes.COMMAND_NOT_SUPPORTED_TEXT + token, tokenBegin, tokenEnd);
893        } else {
894            if (mathfrak) {
895                mathfrak(token);
896            } else if (mathbb) {
897                mathbb(token);
898            } else if (emph) {
899                emph(token);
900            } else if (bold) {
901                bold(token);
902            } else {
903                if (isWs(token)) {
904                    output.addWs(token);
905                } else {
906                    output.addToken(token);
907                }
908            }
909        }
910    }
911 
912    /**
913     * Write token chars in mathbb mode.
914     *
915     * @param   token   Chars to write.
916     */
917    private void emph(final String token) {
918        if (isWs(token)) {
919            output.addWs(Latex2UnicodeSpecials.transform2Emph(token));
920        } else {
921            output.addToken(Latex2UnicodeSpecials.transform2Emph(token));
922        }
923    }
924 
925    /**
926     * Write token chars in mathbb mode.
927     *
928     * @param   token   Chars to write.
929     */
930    private void mathbb(final String token) {
931        for (int i = 0; i < token.length(); i++) {
932            final char c = token.charAt(i);
933            switch (c) {
934            case 'C': output.addToken("\u2102");
935                break;
936            case 'H': output.addToken("\u210D");
937                break;
938            case 'N': output.addToken("\u2115");
939                break;
940            case 'P': output.addToken("\u2119");
941                break;
942            case 'Q': output.addToken("\u211A");
943                break;
944            case 'R': output.addToken("\u211D");
945                break;
946            case 'Z': output.addToken("\u2124");
947                break;
948            default:
949                if (Character.isWhitespace(c)) {
950                    output.addWs("" + c);
951                } else {
952                    output.addToken("" + c);
953                }
954            }
955        }
956    }
957 
958    private boolean isWs(final String token) {
959        return token == null || token.trim().length() == 0;
960    }
961 
962    /**
963     * Write token chars in mathfrak mode.
964     *
965     * @param   token   Chars to write.
966     */
967    private void mathfrak(final String token) {
968        if (isWs(token)) {
969            output.addWs(Latex2UnicodeSpecials.transform2Mathfrak(token));
970        } else {
971            output.addToken(Latex2UnicodeSpecials.transform2Mathfrak(token));
972        }
973    }
974 
975    /**
976     * Write token in bold mode.
977     *
978     * @param   token   Chars to write.
979     */
980    private void bold(final String token) {
981        if (isWs(token)) {
982            output.addWs(Latex2UnicodeSpecials.transform2Bold(token));
983        } else {
984            output.addToken(Latex2UnicodeSpecials.transform2Bold(token));
985        }
986    }
987 
988    /**
989     * Print end of line.
990     */
991    private final void println() {
992        output.println();
993    }
994 
995    /**
996     * Reads a single character and does not change the reading
997     * position.
998     *
999     * @return  character read, if there are no more chars
1000     *          <code>-1</code> is returned
1001     */
1002    protected final int getChar() {
1003        return input.getChar();
1004    }
1005 
1006    /**
1007     * Reads a single character and increments the reading position
1008     * by one.
1009     *
1010     * @return  character read, if there are no more chars
1011     *          <code>-1</code> is returned
1012     */
1013    protected final int read() {
1014        return input.read();
1015    }
1016 
1017    /**
1018     * Read until end of line.
1019     *
1020     * @return  Characters read.
1021     */
1022    protected final String readln() {
1023        StringBuffer result = new StringBuffer();
1024        int c;
1025        while (TextInput.EOF != (c = read())) {
1026            if (c == '\n') {
1027                break;
1028            }
1029            result.append((char) c);
1030        }
1031        return result.toString();
1032    }
1033 
1034    /**
1035     * Are there still any characters to read?
1036     *
1037     * @return  Anything left for reading further?
1038     */
1039    public final boolean eof() {
1040        return input.isEmpty();
1041    }
1042 
1043    /**
1044     * Convert character position into row and column information.
1045     *
1046     * @param   absolutePosition    Find this character position.
1047     * @return  Row and column information.
1048     */
1049    public SourcePosition getAbsoluteSourcePosition(final int absolutePosition) {
1050        return ((SubTextInput) inputStack.get(0)).getPosition(absolutePosition);
1051    }
1052 
1053    /**
1054     * Add warning message.
1055     *
1056     * @param   code    Message code.
1057     * @param   message Message.
1058     * @param   from    Absolute character position of problem start.
1059     * @param   to      Absolute character position of problem end.
1060     */
1061    private void addWarning(final int code, final String message, final int from, final int to) {
1062        finder.addWarning(code, message, getAbsoluteSourcePosition(from),
1063            getAbsoluteSourcePosition(to));
1064    }
1065 
1066 
1067 
1068}

[all classes][org.qedeq.kernel.bo.service.unicode]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov