initial repo - webdump - HTML to plain-text converter for webpages
 (HTM) git clone git://git.codemadness.org/webdump
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit ce2a730d81823f9fc5f1d607296bb4529e9aeef0
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Thu,  7 Sep 2023 18:25:16 +0200
       
       initial repo
       
       Reset development/chaotic hacking history.
       
       Diffstat:
         A LICENSE                             |      15 +++++++++++++++
         A Makefile                            |     100 +++++++++++++++++++++++++++++++
         A README                              |      98 +++++++++++++++++++++++++++++++
         A arg.h                               |      42 +++++++++++++++++++++++++++++++
         A namedentities.all.h                 |    2031 +++++++++++++++++++++++++++++++
         A namedentities.h                     |      62 +++++++++++++++++++++++++++++++
         A strlcat.c                           |      55 +++++++++++++++++++++++++++++++
         A strlcpy.c                           |      50 +++++++++++++++++++++++++++++++
         A webdump.1                           |      66 +++++++++++++++++++++++++++++++
         A webdump.c                           |    2072 +++++++++++++++++++++++++++++++
         A xml.c                               |     489 +++++++++++++++++++++++++++++++
         A xml.h                               |      49 +++++++++++++++++++++++++++++++
       
       12 files changed, 5129 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/LICENSE b/LICENSE
       @@ -0,0 +1,15 @@
       +ISC License
       +
       +Copyright (c) 2017-2023 Hiltjo Posthuma <hiltjo@codemadness.org>
       +
       +Permission to use, copy, modify, and/or distribute this software for any
       +purpose with or without fee is hereby granted, provided that the above
       +copyright notice and this permission notice appear in all copies.
       +
       +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 (DIR) diff --git a/Makefile b/Makefile
       @@ -0,0 +1,100 @@
       +.POSIX:
       +
       +NAME = webdump
       +VERSION = 0.1
       +
       +# paths
       +PREFIX = /usr/local
       +MANPREFIX = ${PREFIX}/man
       +DOCPREFIX = ${PREFIX}/share/doc/${NAME}
       +
       +RANLIB = ranlib
       +
       +# use system flags.
       +WEBDUMP_CFLAGS = ${CFLAGS}
       +WEBDUMP_LDFLAGS = ${LDFLAGS}
       +WEBDUMP_CPPFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -D_BSD_SOURCE
       +
       +BIN = ${NAME}
       +SCRIPTS =
       +
       +SRC = ${BIN:=.c}
       +HDR = arg.h namedentities.h namedentities.all.h xml.h
       +
       +LIBXML = libxml.a
       +LIBXMLSRC = \
       +        xml.c
       +LIBXMLOBJ = ${LIBXMLSRC:.c=.o}
       +
       +COMPATSRC = \
       +        strlcat.c\
       +        strlcpy.c
       +COMPATOBJ =\
       +        strlcat.o\
       +        strlcpy.o
       +
       +LIB = ${LIBXML} ${COMPATOBJ}
       +
       +MAN1 = ${BIN:=.1}\
       +        ${SCRIPTS:=.1}
       +
       +DOC = \
       +        LICENSE\
       +        README
       +
       +all: ${BIN}
       +
       +${BIN}: ${LIB} ${@:=.o}
       +
       +OBJ = ${SRC:.c=.o} ${LIBXMLOBJ} ${COMPATOBJ}
       +
       +${OBJ}: ${HDR}
       +
       +.o:
       +        ${CC} ${WEBDUMP_LDFLAGS} -o $@ $< ${LIB}
       +
       +.c.o:
       +        ${CC} ${WEBDUMP_CFLAGS} ${WEBDUMP_CPPFLAGS} -o $@ -c $<
       +
       +${LIBXML}: ${LIBXMLOBJ}
       +        ${AR} rc $@ $?
       +        ${RANLIB} $@
       +
       +dist:
       +        rm -rf "${NAME}-${VERSION}"
       +        mkdir -p "${NAME}-${VERSION}"
       +        cp -f ${MAN1} ${DOC} ${HDR} \
       +                ${SRC} ${LIBXMLSRC} ${COMPATSRC} ${SCRIPTS} \
       +                Makefile \
       +                "${NAME}-${VERSION}"
       +        # make tarball
       +        tar -cf - "${NAME}-${VERSION}" | \
       +                gzip -c > "${NAME}-${VERSION}.tar.gz"
       +        rm -rf "${NAME}-${VERSION}"
       +
       +clean:
       +        rm -f ${BIN} ${OBJ} ${LIB}
       +
       +install: all
       +        # installing executable files and scripts.
       +        mkdir -p "${DESTDIR}${PREFIX}/bin"
       +        cp -f ${BIN} ${SCRIPTS} "${DESTDIR}${PREFIX}/bin"
       +        for f in ${BIN} ${SCRIPTS}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done
       +        # installing example files.
       +        mkdir -p "${DESTDIR}${DOCPREFIX}"
       +        cp -f README "${DESTDIR}${DOCPREFIX}"
       +        # installing manual pages for general commands: section 1.
       +        mkdir -p "${DESTDIR}${MANPREFIX}/man1"
       +        cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1"
       +        for m in ${MAN1}; do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done
       +
       +uninstall:
       +        # removing executable files and scripts.
       +        for f in ${BIN} ${SCRIPTS}; do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done
       +        # removing example files.
       +        rm -f "${DESTDIR}${DOCPREFIX}/README"
       +        -rmdir "${DESTDIR}${DOCPREFIX}"
       +        # removing manual pages.
       +        for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done
       +
       +.PHONY: all clean dist install uninstall
 (DIR) diff --git a/README b/README
       @@ -0,0 +1,98 @@
       +!!!
       +
       +NOTE! work-in-progress (very slowly) and experimental.
       +
       +This code has many dirty hacks and ugliness. Intended for my personal use only.
       +Knowing this: of course feel free to use it in any way you like, see the
       +LICENSE.
       +
       +!!!
       +
       +
       +webdump
       +-------
       +
       +HTML to plain-text converter tool.
       +
       +It reads HTML in UTF-8 from stdin and writes plain-text to stdout.
       +
       +
       +Build and install
       +-----------------
       +
       +$ make
       +# make install
       +
       +
       +Dependencies
       +------------
       +
       +- C compiler.
       +- libc + some BSDisms.
       +
       +
       +Usage
       +-----
       +
       +webdump < file.html | less -R
       +
       +hurl 'https://codemadness.org/' | webdump | less -R
       +
       +webdump -a -i -l -r -w $(tput cols) < file.html | less -R
       +
       +
       +Goals / scope
       +-------------
       +
       +The tool will only render HTML to stdout, similarly to links -dump or
       +lynx -dump but simpler and more secure.
       +
       +- HTML and XHTML will be supported.
       +- There will be some workarounds and quirks for broken and legacy HTML code.
       +- It will be usable and secure for reading HTML from mails and RSS/Atom feeds.
       +- No remote resources which are part of the HTML will be downloaded:
       +  images, video, audio, etc. But these may be visible as a link reference.
       +- Data will be written to stdout. Intended for plain-text or a text terminal.
       +- No support for Javascript, CSS, frame rendering or forms.
       +- No HTTP or network protocol handling: HTML data is read from stdin.
       +
       +
       +Features
       +--------
       +
       +- Support for word-wrapping.
       +- A mode to enable basic markup: bold, underline, italic and blink ;)
       +- Indentation of headers, paragraphs, pre and list items.
       +- Basic support to query an element or hide them.
       +- Show link references.
       +- Show link references and resources such as img, video, audio, subtitles.
       +- Export link references and resources to a TAB-separated format.
       +
       +
       +Examples
       +--------
       +
       +To use webdump as a HTML filter for example in mutt, change in ~/.mailcap:
       +
       +        text/html;      /home/user/.config/scripts/mutt/viewhtml.sh %s; copiousoutput; nametemplate=%s.html
       +
       +The viewhtml.sh could be something like:
       +
       +        #!/bin/sh
       +        webdump -r -l < "$1"
       +
       +In mutt you should then add:
       +
       +        auto_view text/html
       +
       +
       +License
       +-------
       +
       +ISC, see LICENSE file.
       +
       +
       +Author
       +------
       +
       +Hiltjo Posthuma <hiltjo@codemadness.org>
 (DIR) diff --git a/arg.h b/arg.h
       @@ -0,0 +1,42 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#ifndef ARG_H__
       +#define ARG_H__
       +
       +extern char *argv0;
       +
       +/* use main(int argc, char *argv[]) */
       +#define ARGBEGIN        for (argv0 = *argv, argv++, argc--;\
       +                                        argv[0] && argv[0][0] == '-'\
       +                                        && argv[0][1];\
       +                                        argc--, argv++) {\
       +                                char argc_;\
       +                                char **argv_;\
       +                                int brk_;\
       +                                if (argv[0][1] == '-' && argv[0][2] == '\0') {\
       +                                        argv++;\
       +                                        argc--;\
       +                                        break;\
       +                                }\
       +                                int i_;\
       +                                for (i_ = 1, brk_ = 0, argv_ = argv;\
       +                                                argv[0][i_] && !brk_;\
       +                                                i_++) {\
       +                                        if (argv_ != argv)\
       +                                                break;\
       +                                        argc_ = argv[0][i_];\
       +                                        switch (argc_)
       +
       +#define ARGEND                        }\
       +                        }
       +
       +#define EARGF(x)        ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
       +                                ((x), abort(), (char *)0) :\
       +                                (brk_ = 1, (argv[0][i_+1] != '\0')?\
       +                                        (&argv[0][i_+1]) :\
       +                                        (argc--, argv++, argv[0])))
       +
       +#endif
 (DIR) diff --git a/namedentities.all.h b/namedentities.all.h
       @@ -0,0 +1,2031 @@
       +{ "AElig;", 0x000C6 }, /* LATIN CAPITAL LETTER AE */
       +{ "AMP;", 0x00026 }, /* AMPERSAND */
       +{ "Aacute;", 0x000C1 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
       +{ "Abreve;", 0x00102 }, /* LATIN CAPITAL LETTER A WITH BREVE */
       +{ "Acirc;", 0x000C2 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
       +{ "Acy;", 0x00410 }, /* CYRILLIC CAPITAL LETTER A */
       +{ "Afr;", 0x1D504 }, /* MATHEMATICAL FRAKTUR CAPITAL A */
       +{ "Agrave;", 0x000C0 }, /* LATIN CAPITAL LETTER A WITH GRAVE */
       +{ "Alpha;", 0x00391 }, /* GREEK CAPITAL LETTER ALPHA */
       +{ "Amacr;", 0x00100 }, /* LATIN CAPITAL LETTER A WITH MACRON */
       +{ "And;", 0x02A53 }, /* DOUBLE LOGICAL AND */
       +{ "Aogon;", 0x00104 }, /* LATIN CAPITAL LETTER A WITH OGONEK */
       +{ "Aopf;", 0x1D538 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL A */
       +{ "ApplyFunction;", 0x02061 }, /* FUNCTION APPLICATION */
       +{ "Aring;", 0x000C5 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
       +{ "Ascr;", 0x1D49C }, /* MATHEMATICAL SCRIPT CAPITAL A */
       +{ "Assign;", 0x02254 }, /* COLON EQUALS */
       +{ "Atilde;", 0x000C3 }, /* LATIN CAPITAL LETTER A WITH TILDE */
       +{ "Auml;", 0x000C4 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
       +{ "Backslash;", 0x02216 }, /* SET MINUS */
       +{ "Barv;", 0x02AE7 }, /* SHORT DOWN TACK WITH OVERBAR */
       +{ "Barwed;", 0x02306 }, /* PERSPECTIVE */
       +{ "Bcy;", 0x00411 }, /* CYRILLIC CAPITAL LETTER BE */
       +{ "Because;", 0x02235 }, /* BECAUSE */
       +{ "Bernoullis;", 0x0212C }, /* SCRIPT CAPITAL B */
       +{ "Beta;", 0x00392 }, /* GREEK CAPITAL LETTER BETA */
       +{ "Bfr;", 0x1D505 }, /* MATHEMATICAL FRAKTUR CAPITAL B */
       +{ "Bopf;", 0x1D539 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL B */
       +{ "Breve;", 0x002D8 }, /* BREVE */
       +{ "Bscr;", 0x0212C }, /* SCRIPT CAPITAL B */
       +{ "Bumpeq;", 0x0224E }, /* GEOMETRICALLY EQUIVALENT TO */
       +{ "CHcy;", 0x00427 }, /* CYRILLIC CAPITAL LETTER CHE */
       +{ "COPY;", 0x000A9 }, /* COPYRIGHT SIGN */
       +{ "Cacute;", 0x00106 }, /* LATIN CAPITAL LETTER C WITH ACUTE */
       +{ "Cap;", 0x022D2 }, /* DOUBLE INTERSECTION */
       +{ "CapitalDifferentialD;", 0x02145 }, /* DOUBLE-STRUCK ITALIC CAPITAL D */
       +{ "Cayleys;", 0x0212D }, /* BLACK-LETTER CAPITAL C */
       +{ "Ccaron;", 0x0010C }, /* LATIN CAPITAL LETTER C WITH CARON */
       +{ "Ccedil;", 0x000C7 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
       +{ "Ccirc;", 0x00108 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
       +{ "Cconint;", 0x02230 }, /* VOLUME INTEGRAL */
       +{ "Cdot;", 0x0010A }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */
       +{ "Cedilla;", 0x000B8 }, /* CEDILLA */
       +{ "CenterDot;", 0x000B7 }, /* MIDDLE DOT */
       +{ "Cfr;", 0x0212D }, /* BLACK-LETTER CAPITAL C */
       +{ "Chi;", 0x003A7 }, /* GREEK CAPITAL LETTER CHI */
       +{ "CircleDot;", 0x02299 }, /* CIRCLED DOT OPERATOR */
       +{ "CircleMinus;", 0x02296 }, /* CIRCLED MINUS */
       +{ "CirclePlus;", 0x02295 }, /* CIRCLED PLUS */
       +{ "CircleTimes;", 0x02297 }, /* CIRCLED TIMES */
       +{ "ClockwiseContourIntegral;", 0x02232 }, /* CLOCKWISE CONTOUR INTEGRAL */
       +{ "CloseCurlyDoubleQuote;", 0x0201D }, /* RIGHT DOUBLE QUOTATION MARK */
       +{ "CloseCurlyQuote;", 0x02019 }, /* RIGHT SINGLE QUOTATION MARK */
       +{ "Colon;", 0x02237 }, /* PROPORTION */
       +{ "Colone;", 0x02A74 }, /* DOUBLE COLON EQUAL */
       +{ "Congruent;", 0x02261 }, /* IDENTICAL TO */
       +{ "Conint;", 0x0222F }, /* SURFACE INTEGRAL */
       +{ "ContourIntegral;", 0x0222E }, /* CONTOUR INTEGRAL */
       +{ "Copf;", 0x02102 }, /* DOUBLE-STRUCK CAPITAL C */
       +{ "Coproduct;", 0x02210 }, /* N-ARY COPRODUCT */
       +{ "CounterClockwiseContourIntegral;", 0x02233 }, /* ANTICLOCKWISE CONTOUR INTEGRAL */
       +{ "Cross;", 0x02A2F }, /* VECTOR OR CROSS PRODUCT */
       +{ "Cscr;", 0x1D49E }, /* MATHEMATICAL SCRIPT CAPITAL C */
       +{ "Cup;", 0x022D3 }, /* DOUBLE UNION */
       +{ "CupCap;", 0x0224D }, /* EQUIVALENT TO */
       +{ "DD;", 0x02145 }, /* DOUBLE-STRUCK ITALIC CAPITAL D */
       +{ "DDotrahd;", 0x02911 }, /* RIGHTWARDS ARROW WITH DOTTED STEM */
       +{ "DJcy;", 0x00402 }, /* CYRILLIC CAPITAL LETTER DJE */
       +{ "DScy;", 0x00405 }, /* CYRILLIC CAPITAL LETTER DZE */
       +{ "DZcy;", 0x0040F }, /* CYRILLIC CAPITAL LETTER DZHE */
       +{ "Dagger;", 0x02021 }, /* DOUBLE DAGGER */
       +{ "Darr;", 0x021A1 }, /* DOWNWARDS TWO HEADED ARROW */
       +{ "Dashv;", 0x02AE4 }, /* VERTICAL BAR DOUBLE LEFT TURNSTILE */
       +{ "Dcaron;", 0x0010E }, /* LATIN CAPITAL LETTER D WITH CARON */
       +{ "Dcy;", 0x00414 }, /* CYRILLIC CAPITAL LETTER DE */
       +{ "Del;", 0x02207 }, /* NABLA */
       +{ "Delta;", 0x00394 }, /* GREEK CAPITAL LETTER DELTA */
       +{ "Dfr;", 0x1D507 }, /* MATHEMATICAL FRAKTUR CAPITAL D */
       +{ "DiacriticalAcute;", 0x000B4 }, /* ACUTE ACCENT */
       +{ "DiacriticalDot;", 0x002D9 }, /* DOT ABOVE */
       +{ "DiacriticalDoubleAcute;", 0x002DD }, /* DOUBLE ACUTE ACCENT */
       +{ "DiacriticalGrave;", 0x00060 }, /* GRAVE ACCENT */
       +{ "DiacriticalTilde;", 0x002DC }, /* SMALL TILDE */
       +{ "Diamond;", 0x022C4 }, /* DIAMOND OPERATOR */
       +{ "DifferentialD;", 0x02146 }, /* DOUBLE-STRUCK ITALIC SMALL D */
       +{ "Dopf;", 0x1D53B }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL D */
       +{ "Dot;", 0x000A8 }, /* DIAERESIS */
       +{ "DotDot;", 0x020DC }, /* COMBINING FOUR DOTS ABOVE */
       +{ "DotEqual;", 0x02250 }, /* APPROACHES THE LIMIT */
       +{ "DoubleContourIntegral;", 0x0222F }, /* SURFACE INTEGRAL */
       +{ "DoubleDot;", 0x000A8 }, /* DIAERESIS */
       +{ "DoubleDownArrow;", 0x021D3 }, /* DOWNWARDS DOUBLE ARROW */
       +{ "DoubleLeftArrow;", 0x021D0 }, /* LEFTWARDS DOUBLE ARROW */
       +{ "DoubleLeftRightArrow;", 0x021D4 }, /* LEFT RIGHT DOUBLE ARROW */
       +{ "DoubleLeftTee;", 0x02AE4 }, /* VERTICAL BAR DOUBLE LEFT TURNSTILE */
       +{ "DoubleLongLeftArrow;", 0x027F8 }, /* LONG LEFTWARDS DOUBLE ARROW */
       +{ "DoubleLongLeftRightArrow;", 0x027FA }, /* LONG LEFT RIGHT DOUBLE ARROW */
       +{ "DoubleLongRightArrow;", 0x027F9 }, /* LONG RIGHTWARDS DOUBLE ARROW */
       +{ "DoubleRightArrow;", 0x021D2 }, /* RIGHTWARDS DOUBLE ARROW */
       +{ "DoubleRightTee;", 0x022A8 }, /* TRUE */
       +{ "DoubleUpArrow;", 0x021D1 }, /* UPWARDS DOUBLE ARROW */
       +{ "DoubleUpDownArrow;", 0x021D5 }, /* UP DOWN DOUBLE ARROW */
       +{ "DoubleVerticalBar;", 0x02225 }, /* PARALLEL TO */
       +{ "DownArrow;", 0x02193 }, /* DOWNWARDS ARROW */
       +{ "DownArrowBar;", 0x02913 }, /* DOWNWARDS ARROW TO BAR */
       +{ "DownArrowUpArrow;", 0x021F5 }, /* DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW */
       +{ "DownBreve;", 0x00311 }, /* COMBINING INVERTED BREVE */
       +{ "DownLeftRightVector;", 0x02950 }, /* LEFT BARB DOWN RIGHT BARB DOWN HARPOON */
       +{ "DownLeftTeeVector;", 0x0295E }, /* LEFTWARDS HARPOON WITH BARB DOWN FROM BAR */
       +{ "DownLeftVector;", 0x021BD }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS */
       +{ "DownLeftVectorBar;", 0x02956 }, /* LEFTWARDS HARPOON WITH BARB DOWN TO BAR */
       +{ "DownRightTeeVector;", 0x0295F }, /* RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR */
       +{ "DownRightVector;", 0x021C1 }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS */
       +{ "DownRightVectorBar;", 0x02957 }, /* RIGHTWARDS HARPOON WITH BARB DOWN TO BAR */
       +{ "DownTee;", 0x022A4 }, /* DOWN TACK */
       +{ "DownTeeArrow;", 0x021A7 }, /* DOWNWARDS ARROW FROM BAR */
       +{ "Downarrow;", 0x021D3 }, /* DOWNWARDS DOUBLE ARROW */
       +{ "Dscr;", 0x1D49F }, /* MATHEMATICAL SCRIPT CAPITAL D */
       +{ "Dstrok;", 0x00110 }, /* LATIN CAPITAL LETTER D WITH STROKE */
       +{ "ENG;", 0x0014A }, /* LATIN CAPITAL LETTER ENG */
       +{ "ETH;", 0x000D0 }, /* LATIN CAPITAL LETTER ETH */
       +{ "Eacute;", 0x000C9 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
       +{ "Ecaron;", 0x0011A }, /* LATIN CAPITAL LETTER E WITH CARON */
       +{ "Ecirc;", 0x000CA }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
       +{ "Ecy;", 0x0042D }, /* CYRILLIC CAPITAL LETTER E */
       +{ "Edot;", 0x00116 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */
       +{ "Efr;", 0x1D508 }, /* MATHEMATICAL FRAKTUR CAPITAL E */
       +{ "Egrave;", 0x000C8 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
       +{ "Element;", 0x02208 }, /* ELEMENT OF */
       +{ "Emacr;", 0x00112 }, /* LATIN CAPITAL LETTER E WITH MACRON */
       +{ "EmptySmallSquare;", 0x025FB }, /* WHITE MEDIUM SQUARE */
       +{ "EmptyVerySmallSquare;", 0x025AB }, /* WHITE SMALL SQUARE */
       +{ "Eogon;", 0x00118 }, /* LATIN CAPITAL LETTER E WITH OGONEK */
       +{ "Eopf;", 0x1D53C }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL E */
       +{ "Epsilon;", 0x00395 }, /* GREEK CAPITAL LETTER EPSILON */
       +{ "Equal;", 0x02A75 }, /* TWO CONSECUTIVE EQUALS SIGNS */
       +{ "EqualTilde;", 0x02242 }, /* MINUS TILDE */
       +{ "Equilibrium;", 0x021CC }, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON */
       +{ "Escr;", 0x02130 }, /* SCRIPT CAPITAL E */
       +{ "Esim;", 0x02A73 }, /* EQUALS SIGN ABOVE TILDE OPERATOR */
       +{ "Eta;", 0x00397 }, /* GREEK CAPITAL LETTER ETA */
       +{ "Euml;", 0x000CB }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
       +{ "Exists;", 0x02203 }, /* THERE EXISTS */
       +{ "ExponentialE;", 0x02147 }, /* DOUBLE-STRUCK ITALIC SMALL E */
       +{ "Fcy;", 0x00424 }, /* CYRILLIC CAPITAL LETTER EF */
       +{ "Ffr;", 0x1D509 }, /* MATHEMATICAL FRAKTUR CAPITAL F */
       +{ "FilledSmallSquare;", 0x025FC }, /* BLACK MEDIUM SQUARE */
       +{ "FilledVerySmallSquare;", 0x025AA }, /* BLACK SMALL SQUARE */
       +{ "Fopf;", 0x1D53D }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL F */
       +{ "ForAll;", 0x02200 }, /* FOR ALL */
       +{ "Fouriertrf;", 0x02131 }, /* SCRIPT CAPITAL F */
       +{ "Fscr;", 0x02131 }, /* SCRIPT CAPITAL F */
       +{ "GJcy;", 0x00403 }, /* CYRILLIC CAPITAL LETTER GJE */
       +{ "GT;", 0x0003E }, /* GREATER-THAN SIGN */
       +{ "Gamma;", 0x00393 }, /* GREEK CAPITAL LETTER GAMMA */
       +{ "Gammad;", 0x003DC }, /* GREEK LETTER DIGAMMA */
       +{ "Gbreve;", 0x0011E }, /* LATIN CAPITAL LETTER G WITH BREVE */
       +{ "Gcedil;", 0x00122 }, /* LATIN CAPITAL LETTER G WITH CEDILLA */
       +{ "Gcirc;", 0x0011C }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
       +{ "Gcy;", 0x00413 }, /* CYRILLIC CAPITAL LETTER GHE */
       +{ "Gdot;", 0x00120 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */
       +{ "Gfr;", 0x1D50A }, /* MATHEMATICAL FRAKTUR CAPITAL G */
       +{ "Gg;", 0x022D9 }, /* VERY MUCH GREATER-THAN */
       +{ "Gopf;", 0x1D53E }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL G */
       +{ "GreaterEqual;", 0x02265 }, /* GREATER-THAN OR EQUAL TO */
       +{ "GreaterEqualLess;", 0x022DB }, /* GREATER-THAN EQUAL TO OR LESS-THAN */
       +{ "GreaterFullEqual;", 0x02267 }, /* GREATER-THAN OVER EQUAL TO */
       +{ "GreaterGreater;", 0x02AA2 }, /* DOUBLE NESTED GREATER-THAN */
       +{ "GreaterLess;", 0x02277 }, /* GREATER-THAN OR LESS-THAN */
       +{ "GreaterSlantEqual;", 0x02A7E }, /* GREATER-THAN OR SLANTED EQUAL TO */
       +{ "GreaterTilde;", 0x02273 }, /* GREATER-THAN OR EQUIVALENT TO */
       +{ "Gscr;", 0x1D4A2 }, /* MATHEMATICAL SCRIPT CAPITAL G */
       +{ "Gt;", 0x0226B }, /* MUCH GREATER-THAN */
       +{ "HARDcy;", 0x0042A }, /* CYRILLIC CAPITAL LETTER HARD SIGN */
       +{ "Hacek;", 0x002C7 }, /* CARON */
       +{ "Hat;", 0x0005E }, /* CIRCUMFLEX ACCENT */
       +{ "Hcirc;", 0x00124 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
       +{ "Hfr;", 0x0210C }, /* BLACK-LETTER CAPITAL H */
       +{ "HilbertSpace;", 0x0210B }, /* SCRIPT CAPITAL H */
       +{ "Hopf;", 0x0210D }, /* DOUBLE-STRUCK CAPITAL H */
       +{ "HorizontalLine;", 0x02500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */
       +{ "Hscr;", 0x0210B }, /* SCRIPT CAPITAL H */
       +{ "Hstrok;", 0x00126 }, /* LATIN CAPITAL LETTER H WITH STROKE */
       +{ "HumpDownHump;", 0x0224E }, /* GEOMETRICALLY EQUIVALENT TO */
       +{ "HumpEqual;", 0x0224F }, /* DIFFERENCE BETWEEN */
       +{ "IEcy;", 0x00415 }, /* CYRILLIC CAPITAL LETTER IE */
       +{ "IJlig;", 0x00132 }, /* LATIN CAPITAL LIGATURE IJ */
       +{ "IOcy;", 0x00401 }, /* CYRILLIC CAPITAL LETTER IO */
       +{ "Iacute;", 0x000CD }, /* LATIN CAPITAL LETTER I WITH ACUTE */
       +{ "Icirc;", 0x000CE }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
       +{ "Icy;", 0x00418 }, /* CYRILLIC CAPITAL LETTER I */
       +{ "Idot;", 0x00130 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
       +{ "Ifr;", 0x02111 }, /* BLACK-LETTER CAPITAL I */
       +{ "Igrave;", 0x000CC }, /* LATIN CAPITAL LETTER I WITH GRAVE */
       +{ "Im;", 0x02111 }, /* BLACK-LETTER CAPITAL I */
       +{ "Imacr;", 0x0012A }, /* LATIN CAPITAL LETTER I WITH MACRON */
       +{ "ImaginaryI;", 0x02148 }, /* DOUBLE-STRUCK ITALIC SMALL I */
       +{ "Implies;", 0x021D2 }, /* RIGHTWARDS DOUBLE ARROW */
       +{ "Int;", 0x0222C }, /* DOUBLE INTEGRAL */
       +{ "Integral;", 0x0222B }, /* INTEGRAL */
       +{ "Intersection;", 0x022C2 }, /* N-ARY INTERSECTION */
       +{ "InvisibleComma;", 0x02063 }, /* INVISIBLE SEPARATOR */
       +{ "InvisibleTimes;", 0x02062 }, /* INVISIBLE TIMES */
       +{ "Iogon;", 0x0012E }, /* LATIN CAPITAL LETTER I WITH OGONEK */
       +{ "Iopf;", 0x1D540 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL I */
       +{ "Iota;", 0x00399 }, /* GREEK CAPITAL LETTER IOTA */
       +{ "Iscr;", 0x02110 }, /* SCRIPT CAPITAL I */
       +{ "Itilde;", 0x00128 }, /* LATIN CAPITAL LETTER I WITH TILDE */
       +{ "Iukcy;", 0x00406 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
       +{ "Iuml;", 0x000CF }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
       +{ "Jcirc;", 0x00134 }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
       +{ "Jcy;", 0x00419 }, /* CYRILLIC CAPITAL LETTER SHORT I */
       +{ "Jfr;", 0x1D50D }, /* MATHEMATICAL FRAKTUR CAPITAL J */
       +{ "Jopf;", 0x1D541 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL J */
       +{ "Jscr;", 0x1D4A5 }, /* MATHEMATICAL SCRIPT CAPITAL J */
       +{ "Jsercy;", 0x00408 }, /* CYRILLIC CAPITAL LETTER JE */
       +{ "Jukcy;", 0x00404 }, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */
       +{ "KHcy;", 0x00425 }, /* CYRILLIC CAPITAL LETTER HA */
       +{ "KJcy;", 0x0040C }, /* CYRILLIC CAPITAL LETTER KJE */
       +{ "Kappa;", 0x0039A }, /* GREEK CAPITAL LETTER KAPPA */
       +{ "Kcedil;", 0x00136 }, /* LATIN CAPITAL LETTER K WITH CEDILLA */
       +{ "Kcy;", 0x0041A }, /* CYRILLIC CAPITAL LETTER KA */
       +{ "Kfr;", 0x1D50E }, /* MATHEMATICAL FRAKTUR CAPITAL K */
       +{ "Kopf;", 0x1D542 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL K */
       +{ "Kscr;", 0x1D4A6 }, /* MATHEMATICAL SCRIPT CAPITAL K */
       +{ "LJcy;", 0x00409 }, /* CYRILLIC CAPITAL LETTER LJE */
       +{ "LT;", 0x0003C }, /* LESS-THAN SIGN */
       +{ "Lacute;", 0x00139 }, /* LATIN CAPITAL LETTER L WITH ACUTE */
       +{ "Lambda;", 0x0039B }, /* GREEK CAPITAL LETTER LAMDA */
       +{ "Lang;", 0x027EA }, /* MATHEMATICAL LEFT DOUBLE ANGLE BRACKET */
       +{ "Laplacetrf;", 0x02112 }, /* SCRIPT CAPITAL L */
       +{ "Larr;", 0x0219E }, /* LEFTWARDS TWO HEADED ARROW */
       +{ "Lcaron;", 0x0013D }, /* LATIN CAPITAL LETTER L WITH CARON */
       +{ "Lcedil;", 0x0013B }, /* LATIN CAPITAL LETTER L WITH CEDILLA */
       +{ "Lcy;", 0x0041B }, /* CYRILLIC CAPITAL LETTER EL */
       +{ "LeftAngleBracket;", 0x027E8 }, /* MATHEMATICAL LEFT ANGLE BRACKET */
       +{ "LeftArrow;", 0x02190 }, /* LEFTWARDS ARROW */
       +{ "LeftArrowBar;", 0x021E4 }, /* LEFTWARDS ARROW TO BAR */
       +{ "LeftArrowRightArrow;", 0x021C6 }, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW */
       +{ "LeftCeiling;", 0x02308 }, /* LEFT CEILING */
       +{ "LeftDoubleBracket;", 0x027E6 }, /* MATHEMATICAL LEFT WHITE SQUARE BRACKET */
       +{ "LeftDownTeeVector;", 0x02961 }, /* DOWNWARDS HARPOON WITH BARB LEFT FROM BAR */
       +{ "LeftDownVector;", 0x021C3 }, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS */
       +{ "LeftDownVectorBar;", 0x02959 }, /* DOWNWARDS HARPOON WITH BARB LEFT TO BAR */
       +{ "LeftFloor;", 0x0230A }, /* LEFT FLOOR */
       +{ "LeftRightArrow;", 0x02194 }, /* LEFT RIGHT ARROW */
       +{ "LeftRightVector;", 0x0294E }, /* LEFT BARB UP RIGHT BARB UP HARPOON */
       +{ "LeftTee;", 0x022A3 }, /* LEFT TACK */
       +{ "LeftTeeArrow;", 0x021A4 }, /* LEFTWARDS ARROW FROM BAR */
       +{ "LeftTeeVector;", 0x0295A }, /* LEFTWARDS HARPOON WITH BARB UP FROM BAR */
       +{ "LeftTriangle;", 0x022B2 }, /* NORMAL SUBGROUP OF */
       +{ "LeftTriangleBar;", 0x029CF }, /* LEFT TRIANGLE BESIDE VERTICAL BAR */
       +{ "LeftTriangleEqual;", 0x022B4 }, /* NORMAL SUBGROUP OF OR EQUAL TO */
       +{ "LeftUpDownVector;", 0x02951 }, /* UP BARB LEFT DOWN BARB LEFT HARPOON */
       +{ "LeftUpTeeVector;", 0x02960 }, /* UPWARDS HARPOON WITH BARB LEFT FROM BAR */
       +{ "LeftUpVector;", 0x021BF }, /* UPWARDS HARPOON WITH BARB LEFTWARDS */
       +{ "LeftUpVectorBar;", 0x02958 }, /* UPWARDS HARPOON WITH BARB LEFT TO BAR */
       +{ "LeftVector;", 0x021BC }, /* LEFTWARDS HARPOON WITH BARB UPWARDS */
       +{ "LeftVectorBar;", 0x02952 }, /* LEFTWARDS HARPOON WITH BARB UP TO BAR */
       +{ "Leftarrow;", 0x021D0 }, /* LEFTWARDS DOUBLE ARROW */
       +{ "Leftrightarrow;", 0x021D4 }, /* LEFT RIGHT DOUBLE ARROW */
       +{ "LessEqualGreater;", 0x022DA }, /* LESS-THAN EQUAL TO OR GREATER-THAN */
       +{ "LessFullEqual;", 0x02266 }, /* LESS-THAN OVER EQUAL TO */
       +{ "LessGreater;", 0x02276 }, /* LESS-THAN OR GREATER-THAN */
       +{ "LessLess;", 0x02AA1 }, /* DOUBLE NESTED LESS-THAN */
       +{ "LessSlantEqual;", 0x02A7D }, /* LESS-THAN OR SLANTED EQUAL TO */
       +{ "LessTilde;", 0x02272 }, /* LESS-THAN OR EQUIVALENT TO */
       +{ "Lfr;", 0x1D50F }, /* MATHEMATICAL FRAKTUR CAPITAL L */
       +{ "Ll;", 0x022D8 }, /* VERY MUCH LESS-THAN */
       +{ "Lleftarrow;", 0x021DA }, /* LEFTWARDS TRIPLE ARROW */
       +{ "Lmidot;", 0x0013F }, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */
       +{ "LongLeftArrow;", 0x027F5 }, /* LONG LEFTWARDS ARROW */
       +{ "LongLeftRightArrow;", 0x027F7 }, /* LONG LEFT RIGHT ARROW */
       +{ "LongRightArrow;", 0x027F6 }, /* LONG RIGHTWARDS ARROW */
       +{ "Longleftarrow;", 0x027F8 }, /* LONG LEFTWARDS DOUBLE ARROW */
       +{ "Longleftrightarrow;", 0x027FA }, /* LONG LEFT RIGHT DOUBLE ARROW */
       +{ "Longrightarrow;", 0x027F9 }, /* LONG RIGHTWARDS DOUBLE ARROW */
       +{ "Lopf;", 0x1D543 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL L */
       +{ "LowerLeftArrow;", 0x02199 }, /* SOUTH WEST ARROW */
       +{ "LowerRightArrow;", 0x02198 }, /* SOUTH EAST ARROW */
       +{ "Lscr;", 0x02112 }, /* SCRIPT CAPITAL L */
       +{ "Lsh;", 0x021B0 }, /* UPWARDS ARROW WITH TIP LEFTWARDS */
       +{ "Lstrok;", 0x00141 }, /* LATIN CAPITAL LETTER L WITH STROKE */
       +{ "Lt;", 0x0226A }, /* MUCH LESS-THAN */
       +{ "Map;", 0x02905 }, /* RIGHTWARDS TWO-HEADED ARROW FROM BAR */
       +{ "Mcy;", 0x0041C }, /* CYRILLIC CAPITAL LETTER EM */
       +{ "MediumSpace;", 0x0205F }, /* MEDIUM MATHEMATICAL SPACE */
       +{ "Mellintrf;", 0x02133 }, /* SCRIPT CAPITAL M */
       +{ "Mfr;", 0x1D510 }, /* MATHEMATICAL FRAKTUR CAPITAL M */
       +{ "MinusPlus;", 0x02213 }, /* MINUS-OR-PLUS SIGN */
       +{ "Mopf;", 0x1D544 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL M */
       +{ "Mscr;", 0x02133 }, /* SCRIPT CAPITAL M */
       +{ "Mu;", 0x0039C }, /* GREEK CAPITAL LETTER MU */
       +{ "NJcy;", 0x0040A }, /* CYRILLIC CAPITAL LETTER NJE */
       +{ "Nacute;", 0x00143 }, /* LATIN CAPITAL LETTER N WITH ACUTE */
       +{ "Ncaron;", 0x00147 }, /* LATIN CAPITAL LETTER N WITH CARON */
       +{ "Ncedil;", 0x00145 }, /* LATIN CAPITAL LETTER N WITH CEDILLA */
       +{ "Ncy;", 0x0041D }, /* CYRILLIC CAPITAL LETTER EN */
       +{ "NegativeMediumSpace;", 0x0200B }, /* ZERO WIDTH SPACE */
       +{ "NegativeThickSpace;", 0x0200B }, /* ZERO WIDTH SPACE */
       +{ "NegativeThinSpace;", 0x0200B }, /* ZERO WIDTH SPACE */
       +{ "NegativeVeryThinSpace;", 0x0200B }, /* ZERO WIDTH SPACE */
       +{ "NestedGreaterGreater;", 0x0226B }, /* MUCH GREATER-THAN */
       +{ "NestedLessLess;", 0x0226A }, /* MUCH LESS-THAN */
       +{ "NewLine;", 0x0000A }, /* LINE FEED (LF) */
       +{ "Nfr;", 0x1D511 }, /* MATHEMATICAL FRAKTUR CAPITAL N */
       +{ "NoBreak;", 0x02060 }, /* WORD JOINER */
       +{ "NonBreakingSpace;", 0x000A0 }, /* NO-BREAK SPACE */
       +{ "Nopf;", 0x02115 }, /* DOUBLE-STRUCK CAPITAL N */
       +{ "Not;", 0x02AEC }, /* DOUBLE STROKE NOT SIGN */
       +{ "NotCongruent;", 0x02262 }, /* NOT IDENTICAL TO */
       +{ "NotCupCap;", 0x0226D }, /* NOT EQUIVALENT TO */
       +{ "NotDoubleVerticalBar;", 0x02226 }, /* NOT PARALLEL TO */
       +{ "NotElement;", 0x02209 }, /* NOT AN ELEMENT OF */
       +{ "NotEqual;", 0x02260 }, /* NOT EQUAL TO */
       +{ "NotExists;", 0x02204 }, /* THERE DOES NOT EXIST */
       +{ "NotGreater;", 0x0226F }, /* NOT GREATER-THAN */
       +{ "NotGreaterEqual;", 0x02271 }, /* NEITHER GREATER-THAN NOR EQUAL TO */
       +{ "NotGreaterLess;", 0x02279 }, /* NEITHER GREATER-THAN NOR LESS-THAN */
       +{ "NotGreaterTilde;", 0x02275 }, /* NEITHER GREATER-THAN NOR EQUIVALENT TO */
       +{ "NotLeftTriangle;", 0x022EA }, /* NOT NORMAL SUBGROUP OF */
       +{ "NotLeftTriangleEqual;", 0x022EC }, /* NOT NORMAL SUBGROUP OF OR EQUAL TO */
       +{ "NotLess;", 0x0226E }, /* NOT LESS-THAN */
       +{ "NotLessEqual;", 0x02270 }, /* NEITHER LESS-THAN NOR EQUAL TO */
       +{ "NotLessGreater;", 0x02278 }, /* NEITHER LESS-THAN NOR GREATER-THAN */
       +{ "NotLessTilde;", 0x02274 }, /* NEITHER LESS-THAN NOR EQUIVALENT TO */
       +{ "NotPrecedes;", 0x02280 }, /* DOES NOT PRECEDE */
       +{ "NotPrecedesSlantEqual;", 0x022E0 }, /* DOES NOT PRECEDE OR EQUAL */
       +{ "NotReverseElement;", 0x0220C }, /* DOES NOT CONTAIN AS MEMBER */
       +{ "NotRightTriangle;", 0x022EB }, /* DOES NOT CONTAIN AS NORMAL SUBGROUP */
       +{ "NotRightTriangleEqual;", 0x022ED }, /* DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL */
       +{ "NotSquareSubsetEqual;", 0x022E2 }, /* NOT SQUARE IMAGE OF OR EQUAL TO */
       +{ "NotSquareSupersetEqual;", 0x022E3 }, /* NOT SQUARE ORIGINAL OF OR EQUAL TO */
       +{ "NotSubsetEqual;", 0x02288 }, /* NEITHER A SUBSET OF NOR EQUAL TO */
       +{ "NotSucceeds;", 0x02281 }, /* DOES NOT SUCCEED */
       +{ "NotSucceedsSlantEqual;", 0x022E1 }, /* DOES NOT SUCCEED OR EQUAL */
       +{ "NotSupersetEqual;", 0x02289 }, /* NEITHER A SUPERSET OF NOR EQUAL TO */
       +{ "NotTilde;", 0x02241 }, /* NOT TILDE */
       +{ "NotTildeEqual;", 0x02244 }, /* NOT ASYMPTOTICALLY EQUAL TO */
       +{ "NotTildeFullEqual;", 0x02247 }, /* NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO */
       +{ "NotTildeTilde;", 0x02249 }, /* NOT ALMOST EQUAL TO */
       +{ "NotVerticalBar;", 0x02224 }, /* DOES NOT DIVIDE */
       +{ "Nscr;", 0x1D4A9 }, /* MATHEMATICAL SCRIPT CAPITAL N */
       +{ "Ntilde;", 0x000D1 }, /* LATIN CAPITAL LETTER N WITH TILDE */
       +{ "Nu;", 0x0039D }, /* GREEK CAPITAL LETTER NU */
       +{ "OElig;", 0x00152 }, /* LATIN CAPITAL LIGATURE OE */
       +{ "Oacute;", 0x000D3 }, /* LATIN CAPITAL LETTER O WITH ACUTE */
       +{ "Ocirc;", 0x000D4 }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
       +{ "Ocy;", 0x0041E }, /* CYRILLIC CAPITAL LETTER O */
       +{ "Odblac;", 0x00150 }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
       +{ "Ofr;", 0x1D512 }, /* MATHEMATICAL FRAKTUR CAPITAL O */
       +{ "Ograve;", 0x000D2 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
       +{ "Omacr;", 0x0014C }, /* LATIN CAPITAL LETTER O WITH MACRON */
       +{ "Omega;", 0x003A9 }, /* GREEK CAPITAL LETTER OMEGA */
       +{ "Omicron;", 0x0039F }, /* GREEK CAPITAL LETTER OMICRON */
       +{ "Oopf;", 0x1D546 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL O */
       +{ "OpenCurlyDoubleQuote;", 0x0201C }, /* LEFT DOUBLE QUOTATION MARK */
       +{ "OpenCurlyQuote;", 0x02018 }, /* LEFT SINGLE QUOTATION MARK */
       +{ "Or;", 0x02A54 }, /* DOUBLE LOGICAL OR */
       +{ "Oscr;", 0x1D4AA }, /* MATHEMATICAL SCRIPT CAPITAL O */
       +{ "Oslash;", 0x000D8 }, /* LATIN CAPITAL LETTER O WITH STROKE */
       +{ "Otilde;", 0x000D5 }, /* LATIN CAPITAL LETTER O WITH TILDE */
       +{ "Otimes;", 0x02A37 }, /* MULTIPLICATION SIGN IN DOUBLE CIRCLE */
       +{ "Ouml;", 0x000D6 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
       +{ "OverBar;", 0x000AF }, /* MACRON */
       +{ "OverBrace;", 0x023DE }, /* TOP CURLY BRACKET */
       +{ "OverBracket;", 0x023B4 }, /* TOP SQUARE BRACKET */
       +{ "OverParenthesis;", 0x023DC }, /* TOP PARENTHESIS */
       +{ "PartialD;", 0x02202 }, /* PARTIAL DIFFERENTIAL */
       +{ "Pcy;", 0x0041F }, /* CYRILLIC CAPITAL LETTER PE */
       +{ "Pfr;", 0x1D513 }, /* MATHEMATICAL FRAKTUR CAPITAL P */
       +{ "Phi;", 0x003A6 }, /* GREEK CAPITAL LETTER PHI */
       +{ "Pi;", 0x003A0 }, /* GREEK CAPITAL LETTER PI */
       +{ "PlusMinus;", 0x000B1 }, /* PLUS-MINUS SIGN */
       +{ "Poincareplane;", 0x0210C }, /* BLACK-LETTER CAPITAL H */
       +{ "Popf;", 0x02119 }, /* DOUBLE-STRUCK CAPITAL P */
       +{ "Pr;", 0x02ABB }, /* DOUBLE PRECEDES */
       +{ "Precedes;", 0x0227A }, /* PRECEDES */
       +{ "PrecedesEqual;", 0x02AAF }, /* PRECEDES ABOVE SINGLE-LINE EQUALS SIGN */
       +{ "PrecedesSlantEqual;", 0x0227C }, /* PRECEDES OR EQUAL TO */
       +{ "PrecedesTilde;", 0x0227E }, /* PRECEDES OR EQUIVALENT TO */
       +{ "Prime;", 0x02033 }, /* DOUBLE PRIME */
       +{ "Product;", 0x0220F }, /* N-ARY PRODUCT */
       +{ "Proportion;", 0x02237 }, /* PROPORTION */
       +{ "Proportional;", 0x0221D }, /* PROPORTIONAL TO */
       +{ "Pscr;", 0x1D4AB }, /* MATHEMATICAL SCRIPT CAPITAL P */
       +{ "Psi;", 0x003A8 }, /* GREEK CAPITAL LETTER PSI */
       +{ "QUOT;", 0x00022 }, /* QUOTATION MARK */
       +{ "Qfr;", 0x1D514 }, /* MATHEMATICAL FRAKTUR CAPITAL Q */
       +{ "Qopf;", 0x0211A }, /* DOUBLE-STRUCK CAPITAL Q */
       +{ "Qscr;", 0x1D4AC }, /* MATHEMATICAL SCRIPT CAPITAL Q */
       +{ "RBarr;", 0x02910 }, /* RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW */
       +{ "REG;", 0x000AE }, /* REGISTERED SIGN */
       +{ "Racute;", 0x00154 }, /* LATIN CAPITAL LETTER R WITH ACUTE */
       +{ "Rang;", 0x027EB }, /* MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET */
       +{ "Rarr;", 0x021A0 }, /* RIGHTWARDS TWO HEADED ARROW */
       +{ "Rarrtl;", 0x02916 }, /* RIGHTWARDS TWO-HEADED ARROW WITH TAIL */
       +{ "Rcaron;", 0x00158 }, /* LATIN CAPITAL LETTER R WITH CARON */
       +{ "Rcedil;", 0x00156 }, /* LATIN CAPITAL LETTER R WITH CEDILLA */
       +{ "Rcy;", 0x00420 }, /* CYRILLIC CAPITAL LETTER ER */
       +{ "Re;", 0x0211C }, /* BLACK-LETTER CAPITAL R */
       +{ "ReverseElement;", 0x0220B }, /* CONTAINS AS MEMBER */
       +{ "ReverseEquilibrium;", 0x021CB }, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON */
       +{ "ReverseUpEquilibrium;", 0x0296F }, /* DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT */
       +{ "Rfr;", 0x0211C }, /* BLACK-LETTER CAPITAL R */
       +{ "Rho;", 0x003A1 }, /* GREEK CAPITAL LETTER RHO */
       +{ "RightAngleBracket;", 0x027E9 }, /* MATHEMATICAL RIGHT ANGLE BRACKET */
       +{ "RightArrow;", 0x02192 }, /* RIGHTWARDS ARROW */
       +{ "RightArrowBar;", 0x021E5 }, /* RIGHTWARDS ARROW TO BAR */
       +{ "RightArrowLeftArrow;", 0x021C4 }, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW */
       +{ "RightCeiling;", 0x02309 }, /* RIGHT CEILING */
       +{ "RightDoubleBracket;", 0x027E7 }, /* MATHEMATICAL RIGHT WHITE SQUARE BRACKET */
       +{ "RightDownTeeVector;", 0x0295D }, /* DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR */
       +{ "RightDownVector;", 0x021C2 }, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS */
       +{ "RightDownVectorBar;", 0x02955 }, /* DOWNWARDS HARPOON WITH BARB RIGHT TO BAR */
       +{ "RightFloor;", 0x0230B }, /* RIGHT FLOOR */
       +{ "RightTee;", 0x022A2 }, /* RIGHT TACK */
       +{ "RightTeeArrow;", 0x021A6 }, /* RIGHTWARDS ARROW FROM BAR */
       +{ "RightTeeVector;", 0x0295B }, /* RIGHTWARDS HARPOON WITH BARB UP FROM BAR */
       +{ "RightTriangle;", 0x022B3 }, /* CONTAINS AS NORMAL SUBGROUP */
       +{ "RightTriangleBar;", 0x029D0 }, /* VERTICAL BAR BESIDE RIGHT TRIANGLE */
       +{ "RightTriangleEqual;", 0x022B5 }, /* CONTAINS AS NORMAL SUBGROUP OR EQUAL TO */
       +{ "RightUpDownVector;", 0x0294F }, /* UP BARB RIGHT DOWN BARB RIGHT HARPOON */
       +{ "RightUpTeeVector;", 0x0295C }, /* UPWARDS HARPOON WITH BARB RIGHT FROM BAR */
       +{ "RightUpVector;", 0x021BE }, /* UPWARDS HARPOON WITH BARB RIGHTWARDS */
       +{ "RightUpVectorBar;", 0x02954 }, /* UPWARDS HARPOON WITH BARB RIGHT TO BAR */
       +{ "RightVector;", 0x021C0 }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS */
       +{ "RightVectorBar;", 0x02953 }, /* RIGHTWARDS HARPOON WITH BARB UP TO BAR */
       +{ "Rightarrow;", 0x021D2 }, /* RIGHTWARDS DOUBLE ARROW */
       +{ "Ropf;", 0x0211D }, /* DOUBLE-STRUCK CAPITAL R */
       +{ "RoundImplies;", 0x02970 }, /* RIGHT DOUBLE ARROW WITH ROUNDED HEAD */
       +{ "Rrightarrow;", 0x021DB }, /* RIGHTWARDS TRIPLE ARROW */
       +{ "Rscr;", 0x0211B }, /* SCRIPT CAPITAL R */
       +{ "Rsh;", 0x021B1 }, /* UPWARDS ARROW WITH TIP RIGHTWARDS */
       +{ "RuleDelayed;", 0x029F4 }, /* RULE-DELAYED */
       +{ "SHCHcy;", 0x00429 }, /* CYRILLIC CAPITAL LETTER SHCHA */
       +{ "SHcy;", 0x00428 }, /* CYRILLIC CAPITAL LETTER SHA */
       +{ "SOFTcy;", 0x0042C }, /* CYRILLIC CAPITAL LETTER SOFT SIGN */
       +{ "Sacute;", 0x0015A }, /* LATIN CAPITAL LETTER S WITH ACUTE */
       +{ "Sc;", 0x02ABC }, /* DOUBLE SUCCEEDS */
       +{ "Scaron;", 0x00160 }, /* LATIN CAPITAL LETTER S WITH CARON */
       +{ "Scedil;", 0x0015E }, /* LATIN CAPITAL LETTER S WITH CEDILLA */
       +{ "Scirc;", 0x0015C }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
       +{ "Scy;", 0x00421 }, /* CYRILLIC CAPITAL LETTER ES */
       +{ "Sfr;", 0x1D516 }, /* MATHEMATICAL FRAKTUR CAPITAL S */
       +{ "ShortDownArrow;", 0x02193 }, /* DOWNWARDS ARROW */
       +{ "ShortLeftArrow;", 0x02190 }, /* LEFTWARDS ARROW */
       +{ "ShortRightArrow;", 0x02192 }, /* RIGHTWARDS ARROW */
       +{ "ShortUpArrow;", 0x02191 }, /* UPWARDS ARROW */
       +{ "Sigma;", 0x003A3 }, /* GREEK CAPITAL LETTER SIGMA */
       +{ "SmallCircle;", 0x02218 }, /* RING OPERATOR */
       +{ "Sopf;", 0x1D54A }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL S */
       +{ "Sqrt;", 0x0221A }, /* SQUARE ROOT */
       +{ "Square;", 0x025A1 }, /* WHITE SQUARE */
       +{ "SquareIntersection;", 0x02293 }, /* SQUARE CAP */
       +{ "SquareSubset;", 0x0228F }, /* SQUARE IMAGE OF */
       +{ "SquareSubsetEqual;", 0x02291 }, /* SQUARE IMAGE OF OR EQUAL TO */
       +{ "SquareSuperset;", 0x02290 }, /* SQUARE ORIGINAL OF */
       +{ "SquareSupersetEqual;", 0x02292 }, /* SQUARE ORIGINAL OF OR EQUAL TO */
       +{ "SquareUnion;", 0x02294 }, /* SQUARE CUP */
       +{ "Sscr;", 0x1D4AE }, /* MATHEMATICAL SCRIPT CAPITAL S */
       +{ "Star;", 0x022C6 }, /* STAR OPERATOR */
       +{ "Sub;", 0x022D0 }, /* DOUBLE SUBSET */
       +{ "Subset;", 0x022D0 }, /* DOUBLE SUBSET */
       +{ "SubsetEqual;", 0x02286 }, /* SUBSET OF OR EQUAL TO */
       +{ "Succeeds;", 0x0227B }, /* SUCCEEDS */
       +{ "SucceedsEqual;", 0x02AB0 }, /* SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN */
       +{ "SucceedsSlantEqual;", 0x0227D }, /* SUCCEEDS OR EQUAL TO */
       +{ "SucceedsTilde;", 0x0227F }, /* SUCCEEDS OR EQUIVALENT TO */
       +{ "SuchThat;", 0x0220B }, /* CONTAINS AS MEMBER */
       +{ "Sum;", 0x02211 }, /* N-ARY SUMMATION */
       +{ "Sup;", 0x022D1 }, /* DOUBLE SUPERSET */
       +{ "Superset;", 0x02283 }, /* SUPERSET OF */
       +{ "SupersetEqual;", 0x02287 }, /* SUPERSET OF OR EQUAL TO */
       +{ "Supset;", 0x022D1 }, /* DOUBLE SUPERSET */
       +{ "THORN;", 0x000DE }, /* LATIN CAPITAL LETTER THORN */
       +{ "TRADE;", 0x02122 }, /* TRADE MARK SIGN */
       +{ "TSHcy;", 0x0040B }, /* CYRILLIC CAPITAL LETTER TSHE */
       +{ "TScy;", 0x00426 }, /* CYRILLIC CAPITAL LETTER TSE */
       +{ "Tab;", 0x00009 }, /* CHARACTER TABULATION */
       +{ "Tau;", 0x003A4 }, /* GREEK CAPITAL LETTER TAU */
       +{ "Tcaron;", 0x00164 }, /* LATIN CAPITAL LETTER T WITH CARON */
       +{ "Tcedil;", 0x00162 }, /* LATIN CAPITAL LETTER T WITH CEDILLA */
       +{ "Tcy;", 0x00422 }, /* CYRILLIC CAPITAL LETTER TE */
       +{ "Tfr;", 0x1D517 }, /* MATHEMATICAL FRAKTUR CAPITAL T */
       +{ "Therefore;", 0x02234 }, /* THEREFORE */
       +{ "Theta;", 0x00398 }, /* GREEK CAPITAL LETTER THETA */
       +{ "ThinSpace;", 0x02009 }, /* THIN SPACE */
       +{ "Tilde;", 0x0223C }, /* TILDE OPERATOR */
       +{ "TildeEqual;", 0x02243 }, /* ASYMPTOTICALLY EQUAL TO */
       +{ "TildeFullEqual;", 0x02245 }, /* APPROXIMATELY EQUAL TO */
       +{ "TildeTilde;", 0x02248 }, /* ALMOST EQUAL TO */
       +{ "Topf;", 0x1D54B }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL T */
       +{ "TripleDot;", 0x020DB }, /* COMBINING THREE DOTS ABOVE */
       +{ "Tscr;", 0x1D4AF }, /* MATHEMATICAL SCRIPT CAPITAL T */
       +{ "Tstrok;", 0x00166 }, /* LATIN CAPITAL LETTER T WITH STROKE */
       +{ "Uacute;", 0x000DA }, /* LATIN CAPITAL LETTER U WITH ACUTE */
       +{ "Uarr;", 0x0219F }, /* UPWARDS TWO HEADED ARROW */
       +{ "Uarrocir;", 0x02949 }, /* UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE */
       +{ "Ubrcy;", 0x0040E }, /* CYRILLIC CAPITAL LETTER SHORT U */
       +{ "Ubreve;", 0x0016C }, /* LATIN CAPITAL LETTER U WITH BREVE */
       +{ "Ucirc;", 0x000DB }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
       +{ "Ucy;", 0x00423 }, /* CYRILLIC CAPITAL LETTER U */
       +{ "Udblac;", 0x00170 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
       +{ "Ufr;", 0x1D518 }, /* MATHEMATICAL FRAKTUR CAPITAL U */
       +{ "Ugrave;", 0x000D9 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
       +{ "Umacr;", 0x0016A }, /* LATIN CAPITAL LETTER U WITH MACRON */
       +{ "UnderBar;", 0x00332 }, /* COMBINING LOW LINE */
       +{ "UnderBrace;", 0x023DF }, /* BOTTOM CURLY BRACKET */
       +{ "UnderBracket;", 0x023B5 }, /* BOTTOM SQUARE BRACKET */
       +{ "UnderParenthesis;", 0x023DD }, /* BOTTOM PARENTHESIS */
       +{ "Union;", 0x022C3 }, /* N-ARY UNION */
       +{ "UnionPlus;", 0x0228E }, /* MULTISET UNION */
       +{ "Uogon;", 0x00172 }, /* LATIN CAPITAL LETTER U WITH OGONEK */
       +{ "Uopf;", 0x1D54C }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL U */
       +{ "UpArrow;", 0x02191 }, /* UPWARDS ARROW */
       +{ "UpArrowBar;", 0x02912 }, /* UPWARDS ARROW TO BAR */
       +{ "UpArrowDownArrow;", 0x021C5 }, /* UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW */
       +{ "UpDownArrow;", 0x02195 }, /* UP DOWN ARROW */
       +{ "UpEquilibrium;", 0x0296E }, /* UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT */
       +{ "UpTee;", 0x022A5 }, /* UP TACK */
       +{ "UpTeeArrow;", 0x021A5 }, /* UPWARDS ARROW FROM BAR */
       +{ "Uparrow;", 0x021D1 }, /* UPWARDS DOUBLE ARROW */
       +{ "Updownarrow;", 0x021D5 }, /* UP DOWN DOUBLE ARROW */
       +{ "UpperLeftArrow;", 0x02196 }, /* NORTH WEST ARROW */
       +{ "UpperRightArrow;", 0x02197 }, /* NORTH EAST ARROW */
       +{ "Upsi;", 0x003D2 }, /* GREEK UPSILON WITH HOOK SYMBOL */
       +{ "Upsilon;", 0x003A5 }, /* GREEK CAPITAL LETTER UPSILON */
       +{ "Uring;", 0x0016E }, /* LATIN CAPITAL LETTER U WITH RING ABOVE */
       +{ "Uscr;", 0x1D4B0 }, /* MATHEMATICAL SCRIPT CAPITAL U */
       +{ "Utilde;", 0x00168 }, /* LATIN CAPITAL LETTER U WITH TILDE */
       +{ "Uuml;", 0x000DC }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
       +{ "VDash;", 0x022AB }, /* DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE */
       +{ "Vbar;", 0x02AEB }, /* DOUBLE UP TACK */
       +{ "Vcy;", 0x00412 }, /* CYRILLIC CAPITAL LETTER VE */
       +{ "Vdash;", 0x022A9 }, /* FORCES */
       +{ "Vdashl;", 0x02AE6 }, /* LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL */
       +{ "Vee;", 0x022C1 }, /* N-ARY LOGICAL OR */
       +{ "Verbar;", 0x02016 }, /* DOUBLE VERTICAL LINE */
       +{ "Vert;", 0x02016 }, /* DOUBLE VERTICAL LINE */
       +{ "VerticalBar;", 0x02223 }, /* DIVIDES */
       +{ "VerticalLine;", 0x0007C }, /* VERTICAL LINE */
       +{ "VerticalSeparator;", 0x02758 }, /* LIGHT VERTICAL BAR */
       +{ "VerticalTilde;", 0x02240 }, /* WREATH PRODUCT */
       +{ "VeryThinSpace;", 0x0200A }, /* HAIR SPACE */
       +{ "Vfr;", 0x1D519 }, /* MATHEMATICAL FRAKTUR CAPITAL V */
       +{ "Vopf;", 0x1D54D }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL V */
       +{ "Vscr;", 0x1D4B1 }, /* MATHEMATICAL SCRIPT CAPITAL V */
       +{ "Vvdash;", 0x022AA }, /* TRIPLE VERTICAL BAR RIGHT TURNSTILE */
       +{ "Wcirc;", 0x00174 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
       +{ "Wedge;", 0x022C0 }, /* N-ARY LOGICAL AND */
       +{ "Wfr;", 0x1D51A }, /* MATHEMATICAL FRAKTUR CAPITAL W */
       +{ "Wopf;", 0x1D54E }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL W */
       +{ "Wscr;", 0x1D4B2 }, /* MATHEMATICAL SCRIPT CAPITAL W */
       +{ "Xfr;", 0x1D51B }, /* MATHEMATICAL FRAKTUR CAPITAL X */
       +{ "Xi;", 0x0039E }, /* GREEK CAPITAL LETTER XI */
       +{ "Xopf;", 0x1D54F }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL X */
       +{ "Xscr;", 0x1D4B3 }, /* MATHEMATICAL SCRIPT CAPITAL X */
       +{ "YAcy;", 0x0042F }, /* CYRILLIC CAPITAL LETTER YA */
       +{ "YIcy;", 0x00407 }, /* CYRILLIC CAPITAL LETTER YI */
       +{ "YUcy;", 0x0042E }, /* CYRILLIC CAPITAL LETTER YU */
       +{ "Yacute;", 0x000DD }, /* LATIN CAPITAL LETTER Y WITH ACUTE */
       +{ "Ycirc;", 0x00176 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
       +{ "Ycy;", 0x0042B }, /* CYRILLIC CAPITAL LETTER YERU */
       +{ "Yfr;", 0x1D51C }, /* MATHEMATICAL FRAKTUR CAPITAL Y */
       +{ "Yopf;", 0x1D550 }, /* MATHEMATICAL DOUBLE-STRUCK CAPITAL Y */
       +{ "Yscr;", 0x1D4B4 }, /* MATHEMATICAL SCRIPT CAPITAL Y */
       +{ "Yuml;", 0x00178 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
       +{ "ZHcy;", 0x00416 }, /* CYRILLIC CAPITAL LETTER ZHE */
       +{ "Zacute;", 0x00179 }, /* LATIN CAPITAL LETTER Z WITH ACUTE */
       +{ "Zcaron;", 0x0017D }, /* LATIN CAPITAL LETTER Z WITH CARON */
       +{ "Zcy;", 0x00417 }, /* CYRILLIC CAPITAL LETTER ZE */
       +{ "Zdot;", 0x0017B }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */
       +{ "ZeroWidthSpace;", 0x0200B }, /* ZERO WIDTH SPACE */
       +{ "Zeta;", 0x00396 }, /* GREEK CAPITAL LETTER ZETA */
       +{ "Zfr;", 0x02128 }, /* BLACK-LETTER CAPITAL Z */
       +{ "Zopf;", 0x02124 }, /* DOUBLE-STRUCK CAPITAL Z */
       +{ "Zscr;", 0x1D4B5 }, /* MATHEMATICAL SCRIPT CAPITAL Z */
       +{ "aacute;", 0x000E1 }, /* LATIN SMALL LETTER A WITH ACUTE */
       +{ "abreve;", 0x00103 }, /* LATIN SMALL LETTER A WITH BREVE */
       +{ "ac;", 0x0223E }, /* INVERTED LAZY S */
       +{ "acd;", 0x0223F }, /* SINE WAVE */
       +{ "acirc;", 0x000E2 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
       +{ "acute;", 0x000B4 }, /* ACUTE ACCENT */
       +{ "acy;", 0x00430 }, /* CYRILLIC SMALL LETTER A */
       +{ "aelig;", 0x000E6 }, /* LATIN SMALL LETTER AE */
       +{ "af;", 0x02061 }, /* FUNCTION APPLICATION */
       +{ "afr;", 0x1D51E }, /* MATHEMATICAL FRAKTUR SMALL A */
       +{ "agrave;", 0x000E0 }, /* LATIN SMALL LETTER A WITH GRAVE */
       +{ "alefsym;", 0x02135 }, /* ALEF SYMBOL */
       +{ "aleph;", 0x02135 }, /* ALEF SYMBOL */
       +{ "alpha;", 0x003B1 }, /* GREEK SMALL LETTER ALPHA */
       +{ "amacr;", 0x00101 }, /* LATIN SMALL LETTER A WITH MACRON */
       +{ "amalg;", 0x02A3F }, /* AMALGAMATION OR COPRODUCT */
       +{ "amp;", 0x00026 }, /* AMPERSAND */
       +{ "and;", 0x02227 }, /* LOGICAL AND */
       +{ "andand;", 0x02A55 }, /* TWO INTERSECTING LOGICAL AND */
       +{ "andd;", 0x02A5C }, /* LOGICAL AND WITH HORIZONTAL DASH */
       +{ "andslope;", 0x02A58 }, /* SLOPING LARGE AND */
       +{ "andv;", 0x02A5A }, /* LOGICAL AND WITH MIDDLE STEM */
       +{ "ang;", 0x02220 }, /* ANGLE */
       +{ "ange;", 0x029A4 }, /* ANGLE WITH UNDERBAR */
       +{ "angle;", 0x02220 }, /* ANGLE */
       +{ "angmsd;", 0x02221 }, /* MEASURED ANGLE */
       +{ "angmsdaa;", 0x029A8 }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT */
       +{ "angmsdab;", 0x029A9 }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT */
       +{ "angmsdac;", 0x029AA }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT */
       +{ "angmsdad;", 0x029AB }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT */
       +{ "angmsdae;", 0x029AC }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP */
       +{ "angmsdaf;", 0x029AD }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP */
       +{ "angmsdag;", 0x029AE }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN */
       +{ "angmsdah;", 0x029AF }, /* MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN */
       +{ "angrt;", 0x0221F }, /* RIGHT ANGLE */
       +{ "angrtvb;", 0x022BE }, /* RIGHT ANGLE WITH ARC */
       +{ "angrtvbd;", 0x0299D }, /* MEASURED RIGHT ANGLE WITH DOT */
       +{ "angsph;", 0x02222 }, /* SPHERICAL ANGLE */
       +{ "angst;", 0x0212B }, /* ANGSTROM SIGN */
       +{ "angzarr;", 0x0237C }, /* RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW */
       +{ "aogon;", 0x00105 }, /* LATIN SMALL LETTER A WITH OGONEK */
       +{ "aopf;", 0x1D552 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL A */
       +{ "ap;", 0x02248 }, /* ALMOST EQUAL TO */
       +{ "apE;", 0x02A70 }, /* APPROXIMATELY EQUAL OR EQUAL TO */
       +{ "apacir;", 0x02A6F }, /* ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT */
       +{ "ape;", 0x0224A }, /* ALMOST EQUAL OR EQUAL TO */
       +{ "apid;", 0x0224B }, /* TRIPLE TILDE */
       +{ "apos;", 0x00027 }, /* APOSTROPHE */
       +{ "approx;", 0x02248 }, /* ALMOST EQUAL TO */
       +{ "approxeq;", 0x0224A }, /* ALMOST EQUAL OR EQUAL TO */
       +{ "aring;", 0x000E5 }, /* LATIN SMALL LETTER A WITH RING ABOVE */
       +{ "ascr;", 0x1D4B6 }, /* MATHEMATICAL SCRIPT SMALL A */
       +{ "ast;", 0x0002A }, /* ASTERISK */
       +{ "asymp;", 0x02248 }, /* ALMOST EQUAL TO */
       +{ "asympeq;", 0x0224D }, /* EQUIVALENT TO */
       +{ "atilde;", 0x000E3 }, /* LATIN SMALL LETTER A WITH TILDE */
       +{ "auml;", 0x000E4 }, /* LATIN SMALL LETTER A WITH DIAERESIS */
       +{ "awconint;", 0x02233 }, /* ANTICLOCKWISE CONTOUR INTEGRAL */
       +{ "awint;", 0x02A11 }, /* ANTICLOCKWISE INTEGRATION */
       +{ "bNot;", 0x02AED }, /* REVERSED DOUBLE STROKE NOT SIGN */
       +{ "backcong;", 0x0224C }, /* ALL EQUAL TO */
       +{ "backepsilon;", 0x003F6 }, /* GREEK REVERSED LUNATE EPSILON SYMBOL */
       +{ "backprime;", 0x02035 }, /* REVERSED PRIME */
       +{ "backsim;", 0x0223D }, /* REVERSED TILDE */
       +{ "backsimeq;", 0x022CD }, /* REVERSED TILDE EQUALS */
       +{ "barvee;", 0x022BD }, /* NOR */
       +{ "barwed;", 0x02305 }, /* PROJECTIVE */
       +{ "barwedge;", 0x02305 }, /* PROJECTIVE */
       +{ "bbrk;", 0x023B5 }, /* BOTTOM SQUARE BRACKET */
       +{ "bbrktbrk;", 0x023B6 }, /* BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET */
       +{ "bcong;", 0x0224C }, /* ALL EQUAL TO */
       +{ "bcy;", 0x00431 }, /* CYRILLIC SMALL LETTER BE */
       +{ "bdquo;", 0x0201E }, /* DOUBLE LOW-9 QUOTATION MARK */
       +{ "becaus;", 0x02235 }, /* BECAUSE */
       +{ "because;", 0x02235 }, /* BECAUSE */
       +{ "bemptyv;", 0x029B0 }, /* REVERSED EMPTY SET */
       +{ "bepsi;", 0x003F6 }, /* GREEK REVERSED LUNATE EPSILON SYMBOL */
       +{ "bernou;", 0x0212C }, /* SCRIPT CAPITAL B */
       +{ "beta;", 0x003B2 }, /* GREEK SMALL LETTER BETA */
       +{ "beth;", 0x02136 }, /* BET SYMBOL */
       +{ "between;", 0x0226C }, /* BETWEEN */
       +{ "bfr;", 0x1D51F }, /* MATHEMATICAL FRAKTUR SMALL B */
       +{ "bigcap;", 0x022C2 }, /* N-ARY INTERSECTION */
       +{ "bigcirc;", 0x025EF }, /* LARGE CIRCLE */
       +{ "bigcup;", 0x022C3 }, /* N-ARY UNION */
       +{ "bigodot;", 0x02A00 }, /* N-ARY CIRCLED DOT OPERATOR */
       +{ "bigoplus;", 0x02A01 }, /* N-ARY CIRCLED PLUS OPERATOR */
       +{ "bigotimes;", 0x02A02 }, /* N-ARY CIRCLED TIMES OPERATOR */
       +{ "bigsqcup;", 0x02A06 }, /* N-ARY SQUARE UNION OPERATOR */
       +{ "bigstar;", 0x02605 }, /* BLACK STAR */
       +{ "bigtriangledown;", 0x025BD }, /* WHITE DOWN-POINTING TRIANGLE */
       +{ "bigtriangleup;", 0x025B3 }, /* WHITE UP-POINTING TRIANGLE */
       +{ "biguplus;", 0x02A04 }, /* N-ARY UNION OPERATOR WITH PLUS */
       +{ "bigvee;", 0x022C1 }, /* N-ARY LOGICAL OR */
       +{ "bigwedge;", 0x022C0 }, /* N-ARY LOGICAL AND */
       +{ "bkarow;", 0x0290D }, /* RIGHTWARDS DOUBLE DASH ARROW */
       +{ "blacklozenge;", 0x029EB }, /* BLACK LOZENGE */
       +{ "blacksquare;", 0x025AA }, /* BLACK SMALL SQUARE */
       +{ "blacktriangle;", 0x025B4 }, /* BLACK UP-POINTING SMALL TRIANGLE */
       +{ "blacktriangledown;", 0x025BE }, /* BLACK DOWN-POINTING SMALL TRIANGLE */
       +{ "blacktriangleleft;", 0x025C2 }, /* BLACK LEFT-POINTING SMALL TRIANGLE */
       +{ "blacktriangleright;", 0x025B8 }, /* BLACK RIGHT-POINTING SMALL TRIANGLE */
       +{ "blank;", 0x02423 }, /* OPEN BOX */
       +{ "blk12;", 0x02592 }, /* MEDIUM SHADE */
       +{ "blk14;", 0x02591 }, /* LIGHT SHADE */
       +{ "blk34;", 0x02593 }, /* DARK SHADE */
       +{ "block;", 0x02588 }, /* FULL BLOCK */
       +{ "bnot;", 0x02310 }, /* REVERSED NOT SIGN */
       +{ "bopf;", 0x1D553 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL B */
       +{ "bot;", 0x022A5 }, /* UP TACK */
       +{ "bottom;", 0x022A5 }, /* UP TACK */
       +{ "bowtie;", 0x022C8 }, /* BOWTIE */
       +{ "boxDL;", 0x02557 }, /* BOX DRAWINGS DOUBLE DOWN AND LEFT */
       +{ "boxDR;", 0x02554 }, /* BOX DRAWINGS DOUBLE DOWN AND RIGHT */
       +{ "boxDl;", 0x02556 }, /* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */
       +{ "boxDr;", 0x02553 }, /* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */
       +{ "boxH;", 0x02550 }, /* BOX DRAWINGS DOUBLE HORIZONTAL */
       +{ "boxHD;", 0x02566 }, /* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */
       +{ "boxHU;", 0x02569 }, /* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */
       +{ "boxHd;", 0x02564 }, /* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */
       +{ "boxHu;", 0x02567 }, /* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */
       +{ "boxUL;", 0x0255D }, /* BOX DRAWINGS DOUBLE UP AND LEFT */
       +{ "boxUR;", 0x0255A }, /* BOX DRAWINGS DOUBLE UP AND RIGHT */
       +{ "boxUl;", 0x0255C }, /* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */
       +{ "boxUr;", 0x02559 }, /* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */
       +{ "boxV;", 0x02551 }, /* BOX DRAWINGS DOUBLE VERTICAL */
       +{ "boxVH;", 0x0256C }, /* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */
       +{ "boxVL;", 0x02563 }, /* BOX DRAWINGS DOUBLE VERTICAL AND LEFT */
       +{ "boxVR;", 0x02560 }, /* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */
       +{ "boxVh;", 0x0256B }, /* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */
       +{ "boxVl;", 0x02562 }, /* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */
       +{ "boxVr;", 0x0255F }, /* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */
       +{ "boxbox;", 0x029C9 }, /* TWO JOINED SQUARES */
       +{ "boxdL;", 0x02555 }, /* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */
       +{ "boxdR;", 0x02552 }, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */
       +{ "boxdl;", 0x02510 }, /* BOX DRAWINGS LIGHT DOWN AND LEFT */
       +{ "boxdr;", 0x0250C }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */
       +{ "boxh;", 0x02500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */
       +{ "boxhD;", 0x02565 }, /* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */
       +{ "boxhU;", 0x02568 }, /* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */
       +{ "boxhd;", 0x0252C }, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
       +{ "boxhu;", 0x02534 }, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
       +{ "boxminus;", 0x0229F }, /* SQUARED MINUS */
       +{ "boxplus;", 0x0229E }, /* SQUARED PLUS */
       +{ "boxtimes;", 0x022A0 }, /* SQUARED TIMES */
       +{ "boxuL;", 0x0255B }, /* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */
       +{ "boxuR;", 0x02558 }, /* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */
       +{ "boxul;", 0x02518 }, /* BOX DRAWINGS LIGHT UP AND LEFT */
       +{ "boxur;", 0x02514 }, /* BOX DRAWINGS LIGHT UP AND RIGHT */
       +{ "boxv;", 0x02502 }, /* BOX DRAWINGS LIGHT VERTICAL */
       +{ "boxvH;", 0x0256A }, /* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */
       +{ "boxvL;", 0x02561 }, /* BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE */
       +{ "boxvR;", 0x0255E }, /* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */
       +{ "boxvh;", 0x0253C }, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
       +{ "boxvl;", 0x02524 }, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
       +{ "boxvr;", 0x0251C }, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
       +{ "bprime;", 0x02035 }, /* REVERSED PRIME */
       +{ "breve;", 0x002D8 }, /* BREVE */
       +{ "brvbar;", 0x000A6 }, /* BROKEN BAR */
       +{ "bscr;", 0x1D4B7 }, /* MATHEMATICAL SCRIPT SMALL B */
       +{ "bsemi;", 0x0204F }, /* REVERSED SEMICOLON */
       +{ "bsim;", 0x0223D }, /* REVERSED TILDE */
       +{ "bsime;", 0x022CD }, /* REVERSED TILDE EQUALS */
       +{ "bsol;", 0x0005C }, /* REVERSE SOLIDUS */
       +{ "bsolb;", 0x029C5 }, /* SQUARED FALLING DIAGONAL SLASH */
       +{ "bull;", 0x02022 }, /* BULLET */
       +{ "bullet;", 0x02022 }, /* BULLET */
       +{ "bump;", 0x0224E }, /* GEOMETRICALLY EQUIVALENT TO */
       +{ "bumpE;", 0x02AAE }, /* EQUALS SIGN WITH BUMPY ABOVE */
       +{ "bumpe;", 0x0224F }, /* DIFFERENCE BETWEEN */
       +{ "bumpeq;", 0x0224F }, /* DIFFERENCE BETWEEN */
       +{ "cacute;", 0x00107 }, /* LATIN SMALL LETTER C WITH ACUTE */
       +{ "cap;", 0x02229 }, /* INTERSECTION */
       +{ "capand;", 0x02A44 }, /* INTERSECTION WITH LOGICAL AND */
       +{ "capbrcup;", 0x02A49 }, /* INTERSECTION ABOVE BAR ABOVE UNION */
       +{ "capcap;", 0x02A4B }, /* INTERSECTION BESIDE AND JOINED WITH INTERSECTION */
       +{ "capcup;", 0x02A47 }, /* INTERSECTION ABOVE UNION */
       +{ "capdot;", 0x02A40 }, /* INTERSECTION WITH DOT */
       +{ "caret;", 0x02041 }, /* CARET INSERTION POINT */
       +{ "caron;", 0x002C7 }, /* CARON */
       +{ "ccaps;", 0x02A4D }, /* CLOSED INTERSECTION WITH SERIFS */
       +{ "ccaron;", 0x0010D }, /* LATIN SMALL LETTER C WITH CARON */
       +{ "ccedil;", 0x000E7 }, /* LATIN SMALL LETTER C WITH CEDILLA */
       +{ "ccirc;", 0x00109 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */
       +{ "ccups;", 0x02A4C }, /* CLOSED UNION WITH SERIFS */
       +{ "ccupssm;", 0x02A50 }, /* CLOSED UNION WITH SERIFS AND SMASH PRODUCT */
       +{ "cdot;", 0x0010B }, /* LATIN SMALL LETTER C WITH DOT ABOVE */
       +{ "cedil;", 0x000B8 }, /* CEDILLA */
       +{ "cemptyv;", 0x029B2 }, /* EMPTY SET WITH SMALL CIRCLE ABOVE */
       +{ "cent;", 0x000A2 }, /* CENT SIGN */
       +{ "centerdot;", 0x000B7 }, /* MIDDLE DOT */
       +{ "cfr;", 0x1D520 }, /* MATHEMATICAL FRAKTUR SMALL C */
       +{ "chcy;", 0x00447 }, /* CYRILLIC SMALL LETTER CHE */
       +{ "check;", 0x02713 }, /* CHECK MARK */
       +{ "checkmark;", 0x02713 }, /* CHECK MARK */
       +{ "chi;", 0x003C7 }, /* GREEK SMALL LETTER CHI */
       +{ "cir;", 0x025CB }, /* WHITE CIRCLE */
       +{ "cirE;", 0x029C3 }, /* CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT */
       +{ "circ;", 0x002C6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
       +{ "circeq;", 0x02257 }, /* RING EQUAL TO */
       +{ "circlearrowleft;", 0x021BA }, /* ANTICLOCKWISE OPEN CIRCLE ARROW */
       +{ "circlearrowright;", 0x021BB }, /* CLOCKWISE OPEN CIRCLE ARROW */
       +{ "circledR;", 0x000AE }, /* REGISTERED SIGN */
       +{ "circledS;", 0x024C8 }, /* CIRCLED LATIN CAPITAL LETTER S */
       +{ "circledast;", 0x0229B }, /* CIRCLED ASTERISK OPERATOR */
       +{ "circledcirc;", 0x0229A }, /* CIRCLED RING OPERATOR */
       +{ "circleddash;", 0x0229D }, /* CIRCLED DASH */
       +{ "cire;", 0x02257 }, /* RING EQUAL TO */
       +{ "cirfnint;", 0x02A10 }, /* CIRCULATION FUNCTION */
       +{ "cirmid;", 0x02AEF }, /* VERTICAL LINE WITH CIRCLE ABOVE */
       +{ "cirscir;", 0x029C2 }, /* CIRCLE WITH SMALL CIRCLE TO THE RIGHT */
       +{ "clubs;", 0x02663 }, /* BLACK CLUB SUIT */
       +{ "clubsuit;", 0x02663 }, /* BLACK CLUB SUIT */
       +{ "colon;", 0x0003A }, /* COLON */
       +{ "colone;", 0x02254 }, /* COLON EQUALS */
       +{ "coloneq;", 0x02254 }, /* COLON EQUALS */
       +{ "comma;", 0x0002C }, /* COMMA */
       +{ "commat;", 0x00040 }, /* COMMERCIAL AT */
       +{ "comp;", 0x02201 }, /* COMPLEMENT */
       +{ "compfn;", 0x02218 }, /* RING OPERATOR */
       +{ "complement;", 0x02201 }, /* COMPLEMENT */
       +{ "complexes;", 0x02102 }, /* DOUBLE-STRUCK CAPITAL C */
       +{ "cong;", 0x02245 }, /* APPROXIMATELY EQUAL TO */
       +{ "congdot;", 0x02A6D }, /* CONGRUENT WITH DOT ABOVE */
       +{ "conint;", 0x0222E }, /* CONTOUR INTEGRAL */
       +{ "copf;", 0x1D554 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL C */
       +{ "coprod;", 0x02210 }, /* N-ARY COPRODUCT */
       +{ "copy;", 0x000A9 }, /* COPYRIGHT SIGN */
       +{ "copysr;", 0x02117 }, /* SOUND RECORDING COPYRIGHT */
       +{ "crarr;", 0x021B5 }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS */
       +{ "cross;", 0x02717 }, /* BALLOT X */
       +{ "cscr;", 0x1D4B8 }, /* MATHEMATICAL SCRIPT SMALL C */
       +{ "csub;", 0x02ACF }, /* CLOSED SUBSET */
       +{ "csube;", 0x02AD1 }, /* CLOSED SUBSET OR EQUAL TO */
       +{ "csup;", 0x02AD0 }, /* CLOSED SUPERSET */
       +{ "csupe;", 0x02AD2 }, /* CLOSED SUPERSET OR EQUAL TO */
       +{ "ctdot;", 0x022EF }, /* MIDLINE HORIZONTAL ELLIPSIS */
       +{ "cudarrl;", 0x02938 }, /* RIGHT-SIDE ARC CLOCKWISE ARROW */
       +{ "cudarrr;", 0x02935 }, /* ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS */
       +{ "cuepr;", 0x022DE }, /* EQUAL TO OR PRECEDES */
       +{ "cuesc;", 0x022DF }, /* EQUAL TO OR SUCCEEDS */
       +{ "cularr;", 0x021B6 }, /* ANTICLOCKWISE TOP SEMICIRCLE ARROW */
       +{ "cularrp;", 0x0293D }, /* TOP ARC ANTICLOCKWISE ARROW WITH PLUS */
       +{ "cup;", 0x0222A }, /* UNION */
       +{ "cupbrcap;", 0x02A48 }, /* UNION ABOVE BAR ABOVE INTERSECTION */
       +{ "cupcap;", 0x02A46 }, /* UNION ABOVE INTERSECTION */
       +{ "cupcup;", 0x02A4A }, /* UNION BESIDE AND JOINED WITH UNION */
       +{ "cupdot;", 0x0228D }, /* MULTISET MULTIPLICATION */
       +{ "cupor;", 0x02A45 }, /* UNION WITH LOGICAL OR */
       +{ "curarr;", 0x021B7 }, /* CLOCKWISE TOP SEMICIRCLE ARROW */
       +{ "curarrm;", 0x0293C }, /* TOP ARC CLOCKWISE ARROW WITH MINUS */
       +{ "curlyeqprec;", 0x022DE }, /* EQUAL TO OR PRECEDES */
       +{ "curlyeqsucc;", 0x022DF }, /* EQUAL TO OR SUCCEEDS */
       +{ "curlyvee;", 0x022CE }, /* CURLY LOGICAL OR */
       +{ "curlywedge;", 0x022CF }, /* CURLY LOGICAL AND */
       +{ "curren;", 0x000A4 }, /* CURRENCY SIGN */
       +{ "curvearrowleft;", 0x021B6 }, /* ANTICLOCKWISE TOP SEMICIRCLE ARROW */
       +{ "curvearrowright;", 0x021B7 }, /* CLOCKWISE TOP SEMICIRCLE ARROW */
       +{ "cuvee;", 0x022CE }, /* CURLY LOGICAL OR */
       +{ "cuwed;", 0x022CF }, /* CURLY LOGICAL AND */
       +{ "cwconint;", 0x02232 }, /* CLOCKWISE CONTOUR INTEGRAL */
       +{ "cwint;", 0x02231 }, /* CLOCKWISE INTEGRAL */
       +{ "cylcty;", 0x0232D }, /* CYLINDRICITY */
       +{ "dArr;", 0x021D3 }, /* DOWNWARDS DOUBLE ARROW */
       +{ "dHar;", 0x02965 }, /* DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT */
       +{ "dagger;", 0x02020 }, /* DAGGER */
       +{ "daleth;", 0x02138 }, /* DALET SYMBOL */
       +{ "darr;", 0x02193 }, /* DOWNWARDS ARROW */
       +{ "dash;", 0x02010 }, /* HYPHEN */
       +{ "dashv;", 0x022A3 }, /* LEFT TACK */
       +{ "dbkarow;", 0x0290F }, /* RIGHTWARDS TRIPLE DASH ARROW */
       +{ "dblac;", 0x002DD }, /* DOUBLE ACUTE ACCENT */
       +{ "dcaron;", 0x0010F }, /* LATIN SMALL LETTER D WITH CARON */
       +{ "dcy;", 0x00434 }, /* CYRILLIC SMALL LETTER DE */
       +{ "dd;", 0x02146 }, /* DOUBLE-STRUCK ITALIC SMALL D */
       +{ "ddagger;", 0x02021 }, /* DOUBLE DAGGER */
       +{ "ddarr;", 0x021CA }, /* DOWNWARDS PAIRED ARROWS */
       +{ "ddotseq;", 0x02A77 }, /* EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW */
       +{ "deg;", 0x000B0 }, /* DEGREE SIGN */
       +{ "delta;", 0x003B4 }, /* GREEK SMALL LETTER DELTA */
       +{ "demptyv;", 0x029B1 }, /* EMPTY SET WITH OVERBAR */
       +{ "dfisht;", 0x0297F }, /* DOWN FISH TAIL */
       +{ "dfr;", 0x1D521 }, /* MATHEMATICAL FRAKTUR SMALL D */
       +{ "dharl;", 0x021C3 }, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS */
       +{ "dharr;", 0x021C2 }, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS */
       +{ "diam;", 0x022C4 }, /* DIAMOND OPERATOR */
       +{ "diamond;", 0x022C4 }, /* DIAMOND OPERATOR */
       +{ "diamondsuit;", 0x02666 }, /* BLACK DIAMOND SUIT */
       +{ "diams;", 0x02666 }, /* BLACK DIAMOND SUIT */
       +{ "die;", 0x000A8 }, /* DIAERESIS */
       +{ "digamma;", 0x003DD }, /* GREEK SMALL LETTER DIGAMMA */
       +{ "disin;", 0x022F2 }, /* ELEMENT OF WITH LONG HORIZONTAL STROKE */
       +{ "div;", 0x000F7 }, /* DIVISION SIGN */
       +{ "divide;", 0x000F7 }, /* DIVISION SIGN */
       +{ "divideontimes;", 0x022C7 }, /* DIVISION TIMES */
       +{ "divonx;", 0x022C7 }, /* DIVISION TIMES */
       +{ "djcy;", 0x00452 }, /* CYRILLIC SMALL LETTER DJE */
       +{ "dlcorn;", 0x0231E }, /* BOTTOM LEFT CORNER */
       +{ "dlcrop;", 0x0230D }, /* BOTTOM LEFT CROP */
       +{ "dollar;", 0x00024 }, /* DOLLAR SIGN */
       +{ "dopf;", 0x1D555 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL D */
       +{ "dot;", 0x002D9 }, /* DOT ABOVE */
       +{ "doteq;", 0x02250 }, /* APPROACHES THE LIMIT */
       +{ "doteqdot;", 0x02251 }, /* GEOMETRICALLY EQUAL TO */
       +{ "dotminus;", 0x02238 }, /* DOT MINUS */
       +{ "dotplus;", 0x02214 }, /* DOT PLUS */
       +{ "dotsquare;", 0x022A1 }, /* SQUARED DOT OPERATOR */
       +{ "doublebarwedge;", 0x02306 }, /* PERSPECTIVE */
       +{ "downarrow;", 0x02193 }, /* DOWNWARDS ARROW */
       +{ "downdownarrows;", 0x021CA }, /* DOWNWARDS PAIRED ARROWS */
       +{ "downharpoonleft;", 0x021C3 }, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS */
       +{ "downharpoonright;", 0x021C2 }, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS */
       +{ "drbkarow;", 0x02910 }, /* RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW */
       +{ "drcorn;", 0x0231F }, /* BOTTOM RIGHT CORNER */
       +{ "drcrop;", 0x0230C }, /* BOTTOM RIGHT CROP */
       +{ "dscr;", 0x1D4B9 }, /* MATHEMATICAL SCRIPT SMALL D */
       +{ "dscy;", 0x00455 }, /* CYRILLIC SMALL LETTER DZE */
       +{ "dsol;", 0x029F6 }, /* SOLIDUS WITH OVERBAR */
       +{ "dstrok;", 0x00111 }, /* LATIN SMALL LETTER D WITH STROKE */
       +{ "dtdot;", 0x022F1 }, /* DOWN RIGHT DIAGONAL ELLIPSIS */
       +{ "dtri;", 0x025BF }, /* WHITE DOWN-POINTING SMALL TRIANGLE */
       +{ "dtrif;", 0x025BE }, /* BLACK DOWN-POINTING SMALL TRIANGLE */
       +{ "duarr;", 0x021F5 }, /* DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW */
       +{ "duhar;", 0x0296F }, /* DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT */
       +{ "dwangle;", 0x029A6 }, /* OBLIQUE ANGLE OPENING UP */
       +{ "dzcy;", 0x0045F }, /* CYRILLIC SMALL LETTER DZHE */
       +{ "dzigrarr;", 0x027FF }, /* LONG RIGHTWARDS SQUIGGLE ARROW */
       +{ "eDDot;", 0x02A77 }, /* EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW */
       +{ "eDot;", 0x02251 }, /* GEOMETRICALLY EQUAL TO */
       +{ "eacute;", 0x000E9 }, /* LATIN SMALL LETTER E WITH ACUTE */
       +{ "easter;", 0x02A6E }, /* EQUALS WITH ASTERISK */
       +{ "ecaron;", 0x0011B }, /* LATIN SMALL LETTER E WITH CARON */
       +{ "ecir;", 0x02256 }, /* RING IN EQUAL TO */
       +{ "ecirc;", 0x000EA }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
       +{ "ecolon;", 0x02255 }, /* EQUALS COLON */
       +{ "ecy;", 0x0044D }, /* CYRILLIC SMALL LETTER E */
       +{ "edot;", 0x00117 }, /* LATIN SMALL LETTER E WITH DOT ABOVE */
       +{ "ee;", 0x02147 }, /* DOUBLE-STRUCK ITALIC SMALL E */
       +{ "efDot;", 0x02252 }, /* APPROXIMATELY EQUAL TO OR THE IMAGE OF */
       +{ "efr;", 0x1D522 }, /* MATHEMATICAL FRAKTUR SMALL E */
       +{ "eg;", 0x02A9A }, /* DOUBLE-LINE EQUAL TO OR GREATER-THAN */
       +{ "egrave;", 0x000E8 }, /* LATIN SMALL LETTER E WITH GRAVE */
       +{ "egs;", 0x02A96 }, /* SLANTED EQUAL TO OR GREATER-THAN */
       +{ "egsdot;", 0x02A98 }, /* SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE */
       +{ "el;", 0x02A99 }, /* DOUBLE-LINE EQUAL TO OR LESS-THAN */
       +{ "elinters;", 0x023E7 }, /* ELECTRICAL INTERSECTION */
       +{ "ell;", 0x02113 }, /* SCRIPT SMALL L */
       +{ "els;", 0x02A95 }, /* SLANTED EQUAL TO OR LESS-THAN */
       +{ "elsdot;", 0x02A97 }, /* SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE */
       +{ "emacr;", 0x00113 }, /* LATIN SMALL LETTER E WITH MACRON */
       +{ "empty;", 0x02205 }, /* EMPTY SET */
       +{ "emptyset;", 0x02205 }, /* EMPTY SET */
       +{ "emptyv;", 0x02205 }, /* EMPTY SET */
       +{ "emsp13;", 0x02004 }, /* THREE-PER-EM SPACE */
       +{ "emsp14;", 0x02005 }, /* FOUR-PER-EM SPACE */
       +{ "emsp;", 0x02003 }, /* EM SPACE */
       +{ "eng;", 0x0014B }, /* LATIN SMALL LETTER ENG */
       +{ "ensp;", 0x02002 }, /* EN SPACE */
       +{ "eogon;", 0x00119 }, /* LATIN SMALL LETTER E WITH OGONEK */
       +{ "eopf;", 0x1D556 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL E */
       +{ "epar;", 0x022D5 }, /* EQUAL AND PARALLEL TO */
       +{ "eparsl;", 0x029E3 }, /* EQUALS SIGN AND SLANTED PARALLEL */
       +{ "eplus;", 0x02A71 }, /* EQUALS SIGN ABOVE PLUS SIGN */
       +{ "epsi;", 0x003F5 }, /* GREEK LUNATE EPSILON SYMBOL */
       +{ "epsilon;", 0x003B5 }, /* GREEK SMALL LETTER EPSILON */
       +{ "epsiv;", 0x003B5 }, /* GREEK SMALL LETTER EPSILON */
       +{ "eqcirc;", 0x02256 }, /* RING IN EQUAL TO */
       +{ "eqcolon;", 0x02255 }, /* EQUALS COLON */
       +{ "eqsim;", 0x02242 }, /* MINUS TILDE */
       +{ "eqslantgtr;", 0x02A96 }, /* SLANTED EQUAL TO OR GREATER-THAN */
       +{ "eqslantless;", 0x02A95 }, /* SLANTED EQUAL TO OR LESS-THAN */
       +{ "equals;", 0x0003D }, /* EQUALS SIGN */
       +{ "equest;", 0x0225F }, /* QUESTIONED EQUAL TO */
       +{ "equiv;", 0x02261 }, /* IDENTICAL TO */
       +{ "equivDD;", 0x02A78 }, /* EQUIVALENT WITH FOUR DOTS ABOVE */
       +{ "eqvparsl;", 0x029E5 }, /* IDENTICAL TO AND SLANTED PARALLEL */
       +{ "erDot;", 0x02253 }, /* IMAGE OF OR APPROXIMATELY EQUAL TO */
       +{ "erarr;", 0x02971 }, /* EQUALS SIGN ABOVE RIGHTWARDS ARROW */
       +{ "escr;", 0x0212F }, /* SCRIPT SMALL E */
       +{ "esdot;", 0x02250 }, /* APPROACHES THE LIMIT */
       +{ "esim;", 0x02242 }, /* MINUS TILDE */
       +{ "eta;", 0x003B7 }, /* GREEK SMALL LETTER ETA */
       +{ "eth;", 0x000F0 }, /* LATIN SMALL LETTER ETH */
       +{ "euml;", 0x000EB }, /* LATIN SMALL LETTER E WITH DIAERESIS */
       +{ "euro;", 0x020AC }, /* EURO SIGN */
       +{ "excl;", 0x00021 }, /* EXCLAMATION MARK */
       +{ "exist;", 0x02203 }, /* THERE EXISTS */
       +{ "expectation;", 0x02130 }, /* SCRIPT CAPITAL E */
       +{ "exponentiale;", 0x02147 }, /* DOUBLE-STRUCK ITALIC SMALL E */
       +{ "fallingdotseq;", 0x02252 }, /* APPROXIMATELY EQUAL TO OR THE IMAGE OF */
       +{ "fcy;", 0x00444 }, /* CYRILLIC SMALL LETTER EF */
       +{ "female;", 0x02640 }, /* FEMALE SIGN */
       +{ "ffilig;", 0x0FB03 }, /* LATIN SMALL LIGATURE FFI */
       +{ "fflig;", 0x0FB00 }, /* LATIN SMALL LIGATURE FF */
       +{ "ffllig;", 0x0FB04 }, /* LATIN SMALL LIGATURE FFL */
       +{ "ffr;", 0x1D523 }, /* MATHEMATICAL FRAKTUR SMALL F */
       +{ "filig;", 0x0FB01 }, /* LATIN SMALL LIGATURE FI */
       +{ "flat;", 0x0266D }, /* MUSIC FLAT SIGN */
       +{ "fllig;", 0x0FB02 }, /* LATIN SMALL LIGATURE FL */
       +{ "fltns;", 0x025B1 }, /* WHITE PARALLELOGRAM */
       +{ "fnof;", 0x00192 }, /* LATIN SMALL LETTER F WITH HOOK */
       +{ "fopf;", 0x1D557 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL F */
       +{ "forall;", 0x02200 }, /* FOR ALL */
       +{ "fork;", 0x022D4 }, /* PITCHFORK */
       +{ "forkv;", 0x02AD9 }, /* ELEMENT OF OPENING DOWNWARDS */
       +{ "fpartint;", 0x02A0D }, /* FINITE PART INTEGRAL */
       +{ "frac12;", 0x000BD }, /* VULGAR FRACTION ONE HALF */
       +{ "frac13;", 0x02153 }, /* VULGAR FRACTION ONE THIRD */
       +{ "frac14;", 0x000BC }, /* VULGAR FRACTION ONE QUARTER */
       +{ "frac15;", 0x02155 }, /* VULGAR FRACTION ONE FIFTH */
       +{ "frac16;", 0x02159 }, /* VULGAR FRACTION ONE SIXTH */
       +{ "frac18;", 0x0215B }, /* VULGAR FRACTION ONE EIGHTH */
       +{ "frac23;", 0x02154 }, /* VULGAR FRACTION TWO THIRDS */
       +{ "frac25;", 0x02156 }, /* VULGAR FRACTION TWO FIFTHS */
       +{ "frac34;", 0x000BE }, /* VULGAR FRACTION THREE QUARTERS */
       +{ "frac35;", 0x02157 }, /* VULGAR FRACTION THREE FIFTHS */
       +{ "frac38;", 0x0215C }, /* VULGAR FRACTION THREE EIGHTHS */
       +{ "frac45;", 0x02158 }, /* VULGAR FRACTION FOUR FIFTHS */
       +{ "frac56;", 0x0215A }, /* VULGAR FRACTION FIVE SIXTHS */
       +{ "frac58;", 0x0215D }, /* VULGAR FRACTION FIVE EIGHTHS */
       +{ "frac78;", 0x0215E }, /* VULGAR FRACTION SEVEN EIGHTHS */
       +{ "frasl;", 0x02044 }, /* FRACTION SLASH */
       +{ "frown;", 0x02322 }, /* FROWN */
       +{ "fscr;", 0x1D4BB }, /* MATHEMATICAL SCRIPT SMALL F */
       +{ "gE;", 0x02267 }, /* GREATER-THAN OVER EQUAL TO */
       +{ "gEl;", 0x02A8C }, /* GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN */
       +{ "gacute;", 0x001F5 }, /* LATIN SMALL LETTER G WITH ACUTE */
       +{ "gamma;", 0x003B3 }, /* GREEK SMALL LETTER GAMMA */
       +{ "gammad;", 0x003DD }, /* GREEK SMALL LETTER DIGAMMA */
       +{ "gap;", 0x02A86 }, /* GREATER-THAN OR APPROXIMATE */
       +{ "gbreve;", 0x0011F }, /* LATIN SMALL LETTER G WITH BREVE */
       +{ "gcirc;", 0x0011D }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */
       +{ "gcy;", 0x00433 }, /* CYRILLIC SMALL LETTER GHE */
       +{ "gdot;", 0x00121 }, /* LATIN SMALL LETTER G WITH DOT ABOVE */
       +{ "ge;", 0x02265 }, /* GREATER-THAN OR EQUAL TO */
       +{ "gel;", 0x022DB }, /* GREATER-THAN EQUAL TO OR LESS-THAN */
       +{ "geq;", 0x02265 }, /* GREATER-THAN OR EQUAL TO */
       +{ "geqq;", 0x02267 }, /* GREATER-THAN OVER EQUAL TO */
       +{ "geqslant;", 0x02A7E }, /* GREATER-THAN OR SLANTED EQUAL TO */
       +{ "ges;", 0x02A7E }, /* GREATER-THAN OR SLANTED EQUAL TO */
       +{ "gescc;", 0x02AA9 }, /* GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL */
       +{ "gesdot;", 0x02A80 }, /* GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE */
       +{ "gesdoto;", 0x02A82 }, /* GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE */
       +{ "gesdotol;", 0x02A84 }, /* GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT */
       +{ "gesles;", 0x02A94 }, /* GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL */
       +{ "gfr;", 0x1D524 }, /* MATHEMATICAL FRAKTUR SMALL G */
       +{ "gg;", 0x0226B }, /* MUCH GREATER-THAN */
       +{ "ggg;", 0x022D9 }, /* VERY MUCH GREATER-THAN */
       +{ "gimel;", 0x02137 }, /* GIMEL SYMBOL */
       +{ "gjcy;", 0x00453 }, /* CYRILLIC SMALL LETTER GJE */
       +{ "gl;", 0x02277 }, /* GREATER-THAN OR LESS-THAN */
       +{ "glE;", 0x02A92 }, /* GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL */
       +{ "gla;", 0x02AA5 }, /* GREATER-THAN BESIDE LESS-THAN */
       +{ "glj;", 0x02AA4 }, /* GREATER-THAN OVERLAPPING LESS-THAN */
       +{ "gnE;", 0x02269 }, /* GREATER-THAN BUT NOT EQUAL TO */
       +{ "gnap;", 0x02A8A }, /* GREATER-THAN AND NOT APPROXIMATE */
       +{ "gnapprox;", 0x02A8A }, /* GREATER-THAN AND NOT APPROXIMATE */
       +{ "gne;", 0x02A88 }, /* GREATER-THAN AND SINGLE-LINE NOT EQUAL TO */
       +{ "gneq;", 0x02A88 }, /* GREATER-THAN AND SINGLE-LINE NOT EQUAL TO */
       +{ "gneqq;", 0x02269 }, /* GREATER-THAN BUT NOT EQUAL TO */
       +{ "gnsim;", 0x022E7 }, /* GREATER-THAN BUT NOT EQUIVALENT TO */
       +{ "gopf;", 0x1D558 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL G */
       +{ "grave;", 0x00060 }, /* GRAVE ACCENT */
       +{ "gscr;", 0x0210A }, /* SCRIPT SMALL G */
       +{ "gsim;", 0x02273 }, /* GREATER-THAN OR EQUIVALENT TO */
       +{ "gsime;", 0x02A8E }, /* GREATER-THAN ABOVE SIMILAR OR EQUAL */
       +{ "gsiml;", 0x02A90 }, /* GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN */
       +{ "gt;", 0x0003E }, /* GREATER-THAN SIGN */
       +{ "gtcc;", 0x02AA7 }, /* GREATER-THAN CLOSED BY CURVE */
       +{ "gtcir;", 0x02A7A }, /* GREATER-THAN WITH CIRCLE INSIDE */
       +{ "gtdot;", 0x022D7 }, /* GREATER-THAN WITH DOT */
       +{ "gtlPar;", 0x02995 }, /* DOUBLE LEFT ARC GREATER-THAN BRACKET */
       +{ "gtquest;", 0x02A7C }, /* GREATER-THAN WITH QUESTION MARK ABOVE */
       +{ "gtrapprox;", 0x02A86 }, /* GREATER-THAN OR APPROXIMATE */
       +{ "gtrarr;", 0x02978 }, /* GREATER-THAN ABOVE RIGHTWARDS ARROW */
       +{ "gtrdot;", 0x022D7 }, /* GREATER-THAN WITH DOT */
       +{ "gtreqless;", 0x022DB }, /* GREATER-THAN EQUAL TO OR LESS-THAN */
       +{ "gtreqqless;", 0x02A8C }, /* GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN */
       +{ "gtrless;", 0x02277 }, /* GREATER-THAN OR LESS-THAN */
       +{ "gtrsim;", 0x02273 }, /* GREATER-THAN OR EQUIVALENT TO */
       +{ "hArr;", 0x021D4 }, /* LEFT RIGHT DOUBLE ARROW */
       +{ "hairsp;", 0x0200A }, /* HAIR SPACE */
       +{ "half;", 0x000BD }, /* VULGAR FRACTION ONE HALF */
       +{ "hamilt;", 0x0210B }, /* SCRIPT CAPITAL H */
       +{ "hardcy;", 0x0044A }, /* CYRILLIC SMALL LETTER HARD SIGN */
       +{ "harr;", 0x02194 }, /* LEFT RIGHT ARROW */
       +{ "harrcir;", 0x02948 }, /* LEFT RIGHT ARROW THROUGH SMALL CIRCLE */
       +{ "harrw;", 0x021AD }, /* LEFT RIGHT WAVE ARROW */
       +{ "hbar;", 0x0210F }, /* PLANCK CONSTANT OVER TWO PI */
       +{ "hcirc;", 0x00125 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */
       +{ "hearts;", 0x02665 }, /* BLACK HEART SUIT */
       +{ "heartsuit;", 0x02665 }, /* BLACK HEART SUIT */
       +{ "hellip;", 0x02026 }, /* HORIZONTAL ELLIPSIS */
       +{ "hercon;", 0x022B9 }, /* HERMITIAN CONJUGATE MATRIX */
       +{ "hfr;", 0x1D525 }, /* MATHEMATICAL FRAKTUR SMALL H */
       +{ "hksearow;", 0x02925 }, /* SOUTH EAST ARROW WITH HOOK */
       +{ "hkswarow;", 0x02926 }, /* SOUTH WEST ARROW WITH HOOK */
       +{ "hoarr;", 0x021FF }, /* LEFT RIGHT OPEN-HEADED ARROW */
       +{ "homtht;", 0x0223B }, /* HOMOTHETIC */
       +{ "hookleftarrow;", 0x021A9 }, /* LEFTWARDS ARROW WITH HOOK */
       +{ "hookrightarrow;", 0x021AA }, /* RIGHTWARDS ARROW WITH HOOK */
       +{ "hopf;", 0x1D559 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL H */
       +{ "horbar;", 0x02015 }, /* HORIZONTAL BAR */
       +{ "hscr;", 0x1D4BD }, /* MATHEMATICAL SCRIPT SMALL H */
       +{ "hslash;", 0x0210F }, /* PLANCK CONSTANT OVER TWO PI */
       +{ "hstrok;", 0x00127 }, /* LATIN SMALL LETTER H WITH STROKE */
       +{ "hybull;", 0x02043 }, /* HYPHEN BULLET */
       +{ "hyphen;", 0x02010 }, /* HYPHEN */
       +{ "iacute;", 0x000ED }, /* LATIN SMALL LETTER I WITH ACUTE */
       +{ "ic;", 0x02063 }, /* INVISIBLE SEPARATOR */
       +{ "icirc;", 0x000EE }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
       +{ "icy;", 0x00438 }, /* CYRILLIC SMALL LETTER I */
       +{ "iecy;", 0x00435 }, /* CYRILLIC SMALL LETTER IE */
       +{ "iexcl;", 0x000A1 }, /* INVERTED EXCLAMATION MARK */
       +{ "iff;", 0x021D4 }, /* LEFT RIGHT DOUBLE ARROW */
       +{ "ifr;", 0x1D526 }, /* MATHEMATICAL FRAKTUR SMALL I */
       +{ "igrave;", 0x000EC }, /* LATIN SMALL LETTER I WITH GRAVE */
       +{ "ii;", 0x02148 }, /* DOUBLE-STRUCK ITALIC SMALL I */
       +{ "iiiint;", 0x02A0C }, /* QUADRUPLE INTEGRAL OPERATOR */
       +{ "iiint;", 0x0222D }, /* TRIPLE INTEGRAL */
       +{ "iinfin;", 0x029DC }, /* INCOMPLETE INFINITY */
       +{ "iiota;", 0x02129 }, /* TURNED GREEK SMALL LETTER IOTA */
       +{ "ijlig;", 0x00133 }, /* LATIN SMALL LIGATURE IJ */
       +{ "imacr;", 0x0012B }, /* LATIN SMALL LETTER I WITH MACRON */
       +{ "image;", 0x02111 }, /* BLACK-LETTER CAPITAL I */
       +{ "imagline;", 0x02110 }, /* SCRIPT CAPITAL I */
       +{ "imagpart;", 0x02111 }, /* BLACK-LETTER CAPITAL I */
       +{ "imath;", 0x00131 }, /* LATIN SMALL LETTER DOTLESS I */
       +{ "imof;", 0x022B7 }, /* IMAGE OF */
       +{ "imped;", 0x001B5 }, /* LATIN CAPITAL LETTER Z WITH STROKE */
       +{ "in;", 0x02208 }, /* ELEMENT OF */
       +{ "incare;", 0x02105 }, /* CARE OF */
       +{ "infin;", 0x0221E }, /* INFINITY */
       +{ "infintie;", 0x029DD }, /* TIE OVER INFINITY */
       +{ "inodot;", 0x00131 }, /* LATIN SMALL LETTER DOTLESS I */
       +{ "int;", 0x0222B }, /* INTEGRAL */
       +{ "intcal;", 0x022BA }, /* INTERCALATE */
       +{ "integers;", 0x02124 }, /* DOUBLE-STRUCK CAPITAL Z */
       +{ "intercal;", 0x022BA }, /* INTERCALATE */
       +{ "intlarhk;", 0x02A17 }, /* INTEGRAL WITH LEFTWARDS ARROW WITH HOOK */
       +{ "intprod;", 0x02A3C }, /* INTERIOR PRODUCT */
       +{ "iocy;", 0x00451 }, /* CYRILLIC SMALL LETTER IO */
       +{ "iogon;", 0x0012F }, /* LATIN SMALL LETTER I WITH OGONEK */
       +{ "iopf;", 0x1D55A }, /* MATHEMATICAL DOUBLE-STRUCK SMALL I */
       +{ "iota;", 0x003B9 }, /* GREEK SMALL LETTER IOTA */
       +{ "iprod;", 0x02A3C }, /* INTERIOR PRODUCT */
       +{ "iquest;", 0x000BF }, /* INVERTED QUESTION MARK */
       +{ "iscr;", 0x1D4BE }, /* MATHEMATICAL SCRIPT SMALL I */
       +{ "isin;", 0x02208 }, /* ELEMENT OF */
       +{ "isinE;", 0x022F9 }, /* ELEMENT OF WITH TWO HORIZONTAL STROKES */
       +{ "isindot;", 0x022F5 }, /* ELEMENT OF WITH DOT ABOVE */
       +{ "isins;", 0x022F4 }, /* SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE */
       +{ "isinsv;", 0x022F3 }, /* ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE */
       +{ "isinv;", 0x02208 }, /* ELEMENT OF */
       +{ "it;", 0x02062 }, /* INVISIBLE TIMES */
       +{ "itilde;", 0x00129 }, /* LATIN SMALL LETTER I WITH TILDE */
       +{ "iukcy;", 0x00456 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
       +{ "iuml;", 0x000EF }, /* LATIN SMALL LETTER I WITH DIAERESIS */
       +{ "jcirc;", 0x00135 }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */
       +{ "jcy;", 0x00439 }, /* CYRILLIC SMALL LETTER SHORT I */
       +{ "jfr;", 0x1D527 }, /* MATHEMATICAL FRAKTUR SMALL J */
       +{ "jmath;", 0x00237 }, /* LATIN SMALL LETTER DOTLESS J */
       +{ "jopf;", 0x1D55B }, /* MATHEMATICAL DOUBLE-STRUCK SMALL J */
       +{ "jscr;", 0x1D4BF }, /* MATHEMATICAL SCRIPT SMALL J */
       +{ "jsercy;", 0x00458 }, /* CYRILLIC SMALL LETTER JE */
       +{ "jukcy;", 0x00454 }, /* CYRILLIC SMALL LETTER UKRAINIAN IE */
       +{ "kappa;", 0x003BA }, /* GREEK SMALL LETTER KAPPA */
       +{ "kappav;", 0x003F0 }, /* GREEK KAPPA SYMBOL */
       +{ "kcedil;", 0x00137 }, /* LATIN SMALL LETTER K WITH CEDILLA */
       +{ "kcy;", 0x0043A }, /* CYRILLIC SMALL LETTER KA */
       +{ "kfr;", 0x1D528 }, /* MATHEMATICAL FRAKTUR SMALL K */
       +{ "kgreen;", 0x00138 }, /* LATIN SMALL LETTER KRA */
       +{ "khcy;", 0x00445 }, /* CYRILLIC SMALL LETTER HA */
       +{ "kjcy;", 0x0045C }, /* CYRILLIC SMALL LETTER KJE */
       +{ "kopf;", 0x1D55C }, /* MATHEMATICAL DOUBLE-STRUCK SMALL K */
       +{ "kscr;", 0x1D4C0 }, /* MATHEMATICAL SCRIPT SMALL K */
       +{ "lAarr;", 0x021DA }, /* LEFTWARDS TRIPLE ARROW */
       +{ "lArr;", 0x021D0 }, /* LEFTWARDS DOUBLE ARROW */
       +{ "lAtail;", 0x0291B }, /* LEFTWARDS DOUBLE ARROW-TAIL */
       +{ "lBarr;", 0x0290E }, /* LEFTWARDS TRIPLE DASH ARROW */
       +{ "lE;", 0x02266 }, /* LESS-THAN OVER EQUAL TO */
       +{ "lEg;", 0x02A8B }, /* LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN */
       +{ "lHar;", 0x02962 }, /* LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN */
       +{ "lacute;", 0x0013A }, /* LATIN SMALL LETTER L WITH ACUTE */
       +{ "laemptyv;", 0x029B4 }, /* EMPTY SET WITH LEFT ARROW ABOVE */
       +{ "lagran;", 0x02112 }, /* SCRIPT CAPITAL L */
       +{ "lambda;", 0x003BB }, /* GREEK SMALL LETTER LAMDA */
       +{ "lang;", 0x027E8 }, /* MATHEMATICAL LEFT ANGLE BRACKET */
       +{ "langd;", 0x02991 }, /* LEFT ANGLE BRACKET WITH DOT */
       +{ "langle;", 0x027E8 }, /* MATHEMATICAL LEFT ANGLE BRACKET */
       +{ "lap;", 0x02A85 }, /* LESS-THAN OR APPROXIMATE */
       +{ "laquo;", 0x000AB }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
       +{ "larr;", 0x02190 }, /* LEFTWARDS ARROW */
       +{ "larrb;", 0x021E4 }, /* LEFTWARDS ARROW TO BAR */
       +{ "larrbfs;", 0x0291F }, /* LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND */
       +{ "larrfs;", 0x0291D }, /* LEFTWARDS ARROW TO BLACK DIAMOND */
       +{ "larrhk;", 0x021A9 }, /* LEFTWARDS ARROW WITH HOOK */
       +{ "larrlp;", 0x021AB }, /* LEFTWARDS ARROW WITH LOOP */
       +{ "larrpl;", 0x02939 }, /* LEFT-SIDE ARC ANTICLOCKWISE ARROW */
       +{ "larrsim;", 0x02973 }, /* LEFTWARDS ARROW ABOVE TILDE OPERATOR */
       +{ "larrtl;", 0x021A2 }, /* LEFTWARDS ARROW WITH TAIL */
       +{ "lat;", 0x02AAB }, /* LARGER THAN */
       +{ "latail;", 0x02919 }, /* LEFTWARDS ARROW-TAIL */
       +{ "late;", 0x02AAD }, /* LARGER THAN OR EQUAL TO */
       +{ "lbarr;", 0x0290C }, /* LEFTWARDS DOUBLE DASH ARROW */
       +{ "lbbrk;", 0x02772 }, /* LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT */
       +{ "lbrace;", 0x0007B }, /* LEFT CURLY BRACKET */
       +{ "lbrack;", 0x0005B }, /* LEFT SQUARE BRACKET */
       +{ "lbrke;", 0x0298B }, /* LEFT SQUARE BRACKET WITH UNDERBAR */
       +{ "lbrksld;", 0x0298F }, /* LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER */
       +{ "lbrkslu;", 0x0298D }, /* LEFT SQUARE BRACKET WITH TICK IN TOP CORNER */
       +{ "lcaron;", 0x0013E }, /* LATIN SMALL LETTER L WITH CARON */
       +{ "lcedil;", 0x0013C }, /* LATIN SMALL LETTER L WITH CEDILLA */
       +{ "lceil;", 0x02308 }, /* LEFT CEILING */
       +{ "lcub;", 0x0007B }, /* LEFT CURLY BRACKET */
       +{ "lcy;", 0x0043B }, /* CYRILLIC SMALL LETTER EL */
       +{ "ldca;", 0x02936 }, /* ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS */
       +{ "ldquo;", 0x0201C }, /* LEFT DOUBLE QUOTATION MARK */
       +{ "ldquor;", 0x0201E }, /* DOUBLE LOW-9 QUOTATION MARK */
       +{ "ldrdhar;", 0x02967 }, /* LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN */
       +{ "ldrushar;", 0x0294B }, /* LEFT BARB DOWN RIGHT BARB UP HARPOON */
       +{ "ldsh;", 0x021B2 }, /* DOWNWARDS ARROW WITH TIP LEFTWARDS */
       +{ "le;", 0x02264 }, /* LESS-THAN OR EQUAL TO */
       +{ "leftarrow;", 0x02190 }, /* LEFTWARDS ARROW */
       +{ "leftarrowtail;", 0x021A2 }, /* LEFTWARDS ARROW WITH TAIL */
       +{ "leftharpoondown;", 0x021BD }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS */
       +{ "leftharpoonup;", 0x021BC }, /* LEFTWARDS HARPOON WITH BARB UPWARDS */
       +{ "leftleftarrows;", 0x021C7 }, /* LEFTWARDS PAIRED ARROWS */
       +{ "leftrightarrow;", 0x02194 }, /* LEFT RIGHT ARROW */
       +{ "leftrightarrows;", 0x021C6 }, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW */
       +{ "leftrightharpoons;", 0x021CB }, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON */
       +{ "leftrightsquigarrow;", 0x021AD }, /* LEFT RIGHT WAVE ARROW */
       +{ "leftthreetimes;", 0x022CB }, /* LEFT SEMIDIRECT PRODUCT */
       +{ "leg;", 0x022DA }, /* LESS-THAN EQUAL TO OR GREATER-THAN */
       +{ "leq;", 0x02264 }, /* LESS-THAN OR EQUAL TO */
       +{ "leqq;", 0x02266 }, /* LESS-THAN OVER EQUAL TO */
       +{ "leqslant;", 0x02A7D }, /* LESS-THAN OR SLANTED EQUAL TO */
       +{ "les;", 0x02A7D }, /* LESS-THAN OR SLANTED EQUAL TO */
       +{ "lescc;", 0x02AA8 }, /* LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL */
       +{ "lesdot;", 0x02A7F }, /* LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE */
       +{ "lesdoto;", 0x02A81 }, /* LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE */
       +{ "lesdotor;", 0x02A83 }, /* LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT */
       +{ "lesges;", 0x02A93 }, /* LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL */
       +{ "lessapprox;", 0x02A85 }, /* LESS-THAN OR APPROXIMATE */
       +{ "lessdot;", 0x022D6 }, /* LESS-THAN WITH DOT */
       +{ "lesseqgtr;", 0x022DA }, /* LESS-THAN EQUAL TO OR GREATER-THAN */
       +{ "lesseqqgtr;", 0x02A8B }, /* LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN */
       +{ "lessgtr;", 0x02276 }, /* LESS-THAN OR GREATER-THAN */
       +{ "lesssim;", 0x02272 }, /* LESS-THAN OR EQUIVALENT TO */
       +{ "lfisht;", 0x0297C }, /* LEFT FISH TAIL */
       +{ "lfloor;", 0x0230A }, /* LEFT FLOOR */
       +{ "lfr;", 0x1D529 }, /* MATHEMATICAL FRAKTUR SMALL L */
       +{ "lg;", 0x02276 }, /* LESS-THAN OR GREATER-THAN */
       +{ "lgE;", 0x02A91 }, /* LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL */
       +{ "lhard;", 0x021BD }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS */
       +{ "lharu;", 0x021BC }, /* LEFTWARDS HARPOON WITH BARB UPWARDS */
       +{ "lharul;", 0x0296A }, /* LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH */
       +{ "lhblk;", 0x02584 }, /* LOWER HALF BLOCK */
       +{ "ljcy;", 0x00459 }, /* CYRILLIC SMALL LETTER LJE */
       +{ "ll;", 0x0226A }, /* MUCH LESS-THAN */
       +{ "llarr;", 0x021C7 }, /* LEFTWARDS PAIRED ARROWS */
       +{ "llcorner;", 0x0231E }, /* BOTTOM LEFT CORNER */
       +{ "llhard;", 0x0296B }, /* LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH */
       +{ "lltri;", 0x025FA }, /* LOWER LEFT TRIANGLE */
       +{ "lmidot;", 0x00140 }, /* LATIN SMALL LETTER L WITH MIDDLE DOT */
       +{ "lmoust;", 0x023B0 }, /* UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION */
       +{ "lmoustache;", 0x023B0 }, /* UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION */
       +{ "lnE;", 0x02268 }, /* LESS-THAN BUT NOT EQUAL TO */
       +{ "lnap;", 0x02A89 }, /* LESS-THAN AND NOT APPROXIMATE */
       +{ "lnapprox;", 0x02A89 }, /* LESS-THAN AND NOT APPROXIMATE */
       +{ "lne;", 0x02A87 }, /* LESS-THAN AND SINGLE-LINE NOT EQUAL TO */
       +{ "lneq;", 0x02A87 }, /* LESS-THAN AND SINGLE-LINE NOT EQUAL TO */
       +{ "lneqq;", 0x02268 }, /* LESS-THAN BUT NOT EQUAL TO */
       +{ "lnsim;", 0x022E6 }, /* LESS-THAN BUT NOT EQUIVALENT TO */
       +{ "loang;", 0x027EC }, /* MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET */
       +{ "loarr;", 0x021FD }, /* LEFTWARDS OPEN-HEADED ARROW */
       +{ "lobrk;", 0x027E6 }, /* MATHEMATICAL LEFT WHITE SQUARE BRACKET */
       +{ "longleftarrow;", 0x027F5 }, /* LONG LEFTWARDS ARROW */
       +{ "longleftrightarrow;", 0x027F7 }, /* LONG LEFT RIGHT ARROW */
       +{ "longmapsto;", 0x027FC }, /* LONG RIGHTWARDS ARROW FROM BAR */
       +{ "longrightarrow;", 0x027F6 }, /* LONG RIGHTWARDS ARROW */
       +{ "looparrowleft;", 0x021AB }, /* LEFTWARDS ARROW WITH LOOP */
       +{ "looparrowright;", 0x021AC }, /* RIGHTWARDS ARROW WITH LOOP */
       +{ "lopar;", 0x02985 }, /* LEFT WHITE PARENTHESIS */
       +{ "lopf;", 0x1D55D }, /* MATHEMATICAL DOUBLE-STRUCK SMALL L */
       +{ "loplus;", 0x02A2D }, /* PLUS SIGN IN LEFT HALF CIRCLE */
       +{ "lotimes;", 0x02A34 }, /* MULTIPLICATION SIGN IN LEFT HALF CIRCLE */
       +{ "lowast;", 0x02217 }, /* ASTERISK OPERATOR */
       +{ "lowbar;", 0x0005F }, /* LOW LINE */
       +{ "loz;", 0x025CA }, /* LOZENGE */
       +{ "lozenge;", 0x025CA }, /* LOZENGE */
       +{ "lozf;", 0x029EB }, /* BLACK LOZENGE */
       +{ "lpar;", 0x00028 }, /* LEFT PARENTHESIS */
       +{ "lparlt;", 0x02993 }, /* LEFT ARC LESS-THAN BRACKET */
       +{ "lrarr;", 0x021C6 }, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW */
       +{ "lrcorner;", 0x0231F }, /* BOTTOM RIGHT CORNER */
       +{ "lrhar;", 0x021CB }, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON */
       +{ "lrhard;", 0x0296D }, /* RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH */
       +{ "lrm;", 0x0200E }, /* LEFT-TO-RIGHT MARK */
       +{ "lrtri;", 0x022BF }, /* RIGHT TRIANGLE */
       +{ "lsaquo;", 0x02039 }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
       +{ "lscr;", 0x1D4C1 }, /* MATHEMATICAL SCRIPT SMALL L */
       +{ "lsh;", 0x021B0 }, /* UPWARDS ARROW WITH TIP LEFTWARDS */
       +{ "lsim;", 0x02272 }, /* LESS-THAN OR EQUIVALENT TO */
       +{ "lsime;", 0x02A8D }, /* LESS-THAN ABOVE SIMILAR OR EQUAL */
       +{ "lsimg;", 0x02A8F }, /* LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN */
       +{ "lsqb;", 0x0005B }, /* LEFT SQUARE BRACKET */
       +{ "lsquo;", 0x02018 }, /* LEFT SINGLE QUOTATION MARK */
       +{ "lsquor;", 0x0201A }, /* SINGLE LOW-9 QUOTATION MARK */
       +{ "lstrok;", 0x00142 }, /* LATIN SMALL LETTER L WITH STROKE */
       +{ "lt;", 0x0003C }, /* LESS-THAN SIGN */
       +{ "ltcc;", 0x02AA6 }, /* LESS-THAN CLOSED BY CURVE */
       +{ "ltcir;", 0x02A79 }, /* LESS-THAN WITH CIRCLE INSIDE */
       +{ "ltdot;", 0x022D6 }, /* LESS-THAN WITH DOT */
       +{ "lthree;", 0x022CB }, /* LEFT SEMIDIRECT PRODUCT */
       +{ "ltimes;", 0x022C9 }, /* LEFT NORMAL FACTOR SEMIDIRECT PRODUCT */
       +{ "ltlarr;", 0x02976 }, /* LESS-THAN ABOVE LEFTWARDS ARROW */
       +{ "ltquest;", 0x02A7B }, /* LESS-THAN WITH QUESTION MARK ABOVE */
       +{ "ltrPar;", 0x02996 }, /* DOUBLE RIGHT ARC LESS-THAN BRACKET */
       +{ "ltri;", 0x025C3 }, /* WHITE LEFT-POINTING SMALL TRIANGLE */
       +{ "ltrie;", 0x022B4 }, /* NORMAL SUBGROUP OF OR EQUAL TO */
       +{ "ltrif;", 0x025C2 }, /* BLACK LEFT-POINTING SMALL TRIANGLE */
       +{ "lurdshar;", 0x0294A }, /* LEFT BARB UP RIGHT BARB DOWN HARPOON */
       +{ "luruhar;", 0x02966 }, /* LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP */
       +{ "mDDot;", 0x0223A }, /* GEOMETRIC PROPORTION */
       +{ "macr;", 0x000AF }, /* MACRON */
       +{ "male;", 0x02642 }, /* MALE SIGN */
       +{ "malt;", 0x02720 }, /* MALTESE CROSS */
       +{ "maltese;", 0x02720 }, /* MALTESE CROSS */
       +{ "map;", 0x021A6 }, /* RIGHTWARDS ARROW FROM BAR */
       +{ "mapsto;", 0x021A6 }, /* RIGHTWARDS ARROW FROM BAR */
       +{ "mapstodown;", 0x021A7 }, /* DOWNWARDS ARROW FROM BAR */
       +{ "mapstoleft;", 0x021A4 }, /* LEFTWARDS ARROW FROM BAR */
       +{ "mapstoup;", 0x021A5 }, /* UPWARDS ARROW FROM BAR */
       +{ "marker;", 0x025AE }, /* BLACK VERTICAL RECTANGLE */
       +{ "mcomma;", 0x02A29 }, /* MINUS SIGN WITH COMMA ABOVE */
       +{ "mcy;", 0x0043C }, /* CYRILLIC SMALL LETTER EM */
       +{ "mdash;", 0x02014 }, /* EM DASH */
       +{ "measuredangle;", 0x02221 }, /* MEASURED ANGLE */
       +{ "mfr;", 0x1D52A }, /* MATHEMATICAL FRAKTUR SMALL M */
       +{ "mho;", 0x02127 }, /* INVERTED OHM SIGN */
       +{ "micro;", 0x000B5 }, /* MICRO SIGN */
       +{ "mid;", 0x02223 }, /* DIVIDES */
       +{ "midast;", 0x0002A }, /* ASTERISK */
       +{ "midcir;", 0x02AF0 }, /* VERTICAL LINE WITH CIRCLE BELOW */
       +{ "middot;", 0x000B7 }, /* MIDDLE DOT */
       +{ "minus;", 0x02212 }, /* MINUS SIGN */
       +{ "minusb;", 0x0229F }, /* SQUARED MINUS */
       +{ "minusd;", 0x02238 }, /* DOT MINUS */
       +{ "minusdu;", 0x02A2A }, /* MINUS SIGN WITH DOT BELOW */
       +{ "mlcp;", 0x02ADB }, /* TRANSVERSAL INTERSECTION */
       +{ "mldr;", 0x02026 }, /* HORIZONTAL ELLIPSIS */
       +{ "mnplus;", 0x02213 }, /* MINUS-OR-PLUS SIGN */
       +{ "models;", 0x022A7 }, /* MODELS */
       +{ "mopf;", 0x1D55E }, /* MATHEMATICAL DOUBLE-STRUCK SMALL M */
       +{ "mp;", 0x02213 }, /* MINUS-OR-PLUS SIGN */
       +{ "mscr;", 0x1D4C2 }, /* MATHEMATICAL SCRIPT SMALL M */
       +{ "mstpos;", 0x0223E }, /* INVERTED LAZY S */
       +{ "mu;", 0x003BC }, /* GREEK SMALL LETTER MU */
       +{ "multimap;", 0x022B8 }, /* MULTIMAP */
       +{ "mumap;", 0x022B8 }, /* MULTIMAP */
       +{ "nLeftarrow;", 0x021CD }, /* LEFTWARDS DOUBLE ARROW WITH STROKE */
       +{ "nLeftrightarrow;", 0x021CE }, /* LEFT RIGHT DOUBLE ARROW WITH STROKE */
       +{ "nRightarrow;", 0x021CF }, /* RIGHTWARDS DOUBLE ARROW WITH STROKE */
       +{ "nVDash;", 0x022AF }, /* NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE */
       +{ "nVdash;", 0x022AE }, /* DOES NOT FORCE */
       +{ "nabla;", 0x02207 }, /* NABLA */
       +{ "nacute;", 0x00144 }, /* LATIN SMALL LETTER N WITH ACUTE */
       +{ "nap;", 0x02249 }, /* NOT ALMOST EQUAL TO */
       +{ "napos;", 0x00149 }, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
       +{ "napprox;", 0x02249 }, /* NOT ALMOST EQUAL TO */
       +{ "natur;", 0x0266E }, /* MUSIC NATURAL SIGN */
       +{ "natural;", 0x0266E }, /* MUSIC NATURAL SIGN */
       +{ "naturals;", 0x02115 }, /* DOUBLE-STRUCK CAPITAL N */
       +{ "nbsp;", 0x000A0 }, /* NO-BREAK SPACE */
       +{ "ncap;", 0x02A43 }, /* INTERSECTION WITH OVERBAR */
       +{ "ncaron;", 0x00148 }, /* LATIN SMALL LETTER N WITH CARON */
       +{ "ncedil;", 0x00146 }, /* LATIN SMALL LETTER N WITH CEDILLA */
       +{ "ncong;", 0x02247 }, /* NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO */
       +{ "ncup;", 0x02A42 }, /* UNION WITH OVERBAR */
       +{ "ncy;", 0x0043D }, /* CYRILLIC SMALL LETTER EN */
       +{ "ndash;", 0x02013 }, /* EN DASH */
       +{ "ne;", 0x02260 }, /* NOT EQUAL TO */
       +{ "neArr;", 0x021D7 }, /* NORTH EAST DOUBLE ARROW */
       +{ "nearhk;", 0x02924 }, /* NORTH EAST ARROW WITH HOOK */
       +{ "nearr;", 0x02197 }, /* NORTH EAST ARROW */
       +{ "nearrow;", 0x02197 }, /* NORTH EAST ARROW */
       +{ "nequiv;", 0x02262 }, /* NOT IDENTICAL TO */
       +{ "nesear;", 0x02928 }, /* NORTH EAST ARROW AND SOUTH EAST ARROW */
       +{ "nexist;", 0x02204 }, /* THERE DOES NOT EXIST */
       +{ "nexists;", 0x02204 }, /* THERE DOES NOT EXIST */
       +{ "nfr;", 0x1D52B }, /* MATHEMATICAL FRAKTUR SMALL N */
       +{ "nge;", 0x02271 }, /* NEITHER GREATER-THAN NOR EQUAL TO */
       +{ "ngeq;", 0x02271 }, /* NEITHER GREATER-THAN NOR EQUAL TO */
       +{ "ngsim;", 0x02275 }, /* NEITHER GREATER-THAN NOR EQUIVALENT TO */
       +{ "ngt;", 0x0226F }, /* NOT GREATER-THAN */
       +{ "ngtr;", 0x0226F }, /* NOT GREATER-THAN */
       +{ "nhArr;", 0x021CE }, /* LEFT RIGHT DOUBLE ARROW WITH STROKE */
       +{ "nharr;", 0x021AE }, /* LEFT RIGHT ARROW WITH STROKE */
       +{ "nhpar;", 0x02AF2 }, /* PARALLEL WITH HORIZONTAL STROKE */
       +{ "ni;", 0x0220B }, /* CONTAINS AS MEMBER */
       +{ "nis;", 0x022FC }, /* SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE */
       +{ "nisd;", 0x022FA }, /* CONTAINS WITH LONG HORIZONTAL STROKE */
       +{ "niv;", 0x0220B }, /* CONTAINS AS MEMBER */
       +{ "njcy;", 0x0045A }, /* CYRILLIC SMALL LETTER NJE */
       +{ "nlArr;", 0x021CD }, /* LEFTWARDS DOUBLE ARROW WITH STROKE */
       +{ "nlarr;", 0x0219A }, /* LEFTWARDS ARROW WITH STROKE */
       +{ "nldr;", 0x02025 }, /* TWO DOT LEADER */
       +{ "nle;", 0x02270 }, /* NEITHER LESS-THAN NOR EQUAL TO */
       +{ "nleftarrow;", 0x0219A }, /* LEFTWARDS ARROW WITH STROKE */
       +{ "nleftrightarrow;", 0x021AE }, /* LEFT RIGHT ARROW WITH STROKE */
       +{ "nleq;", 0x02270 }, /* NEITHER LESS-THAN NOR EQUAL TO */
       +{ "nless;", 0x0226E }, /* NOT LESS-THAN */
       +{ "nlsim;", 0x02274 }, /* NEITHER LESS-THAN NOR EQUIVALENT TO */
       +{ "nlt;", 0x0226E }, /* NOT LESS-THAN */
       +{ "nltri;", 0x022EA }, /* NOT NORMAL SUBGROUP OF */
       +{ "nltrie;", 0x022EC }, /* NOT NORMAL SUBGROUP OF OR EQUAL TO */
       +{ "nmid;", 0x02224 }, /* DOES NOT DIVIDE */
       +{ "nopf;", 0x1D55F }, /* MATHEMATICAL DOUBLE-STRUCK SMALL N */
       +{ "not;", 0x000AC }, /* NOT SIGN */
       +{ "notin;", 0x02209 }, /* NOT AN ELEMENT OF */
       +{ "notinva;", 0x02209 }, /* NOT AN ELEMENT OF */
       +{ "notinvb;", 0x022F7 }, /* SMALL ELEMENT OF WITH OVERBAR */
       +{ "notinvc;", 0x022F6 }, /* ELEMENT OF WITH OVERBAR */
       +{ "notni;", 0x0220C }, /* DOES NOT CONTAIN AS MEMBER */
       +{ "notniva;", 0x0220C }, /* DOES NOT CONTAIN AS MEMBER */
       +{ "notnivb;", 0x022FE }, /* SMALL CONTAINS WITH OVERBAR */
       +{ "notnivc;", 0x022FD }, /* CONTAINS WITH OVERBAR */
       +{ "npar;", 0x02226 }, /* NOT PARALLEL TO */
       +{ "nparallel;", 0x02226 }, /* NOT PARALLEL TO */
       +{ "npolint;", 0x02A14 }, /* LINE INTEGRATION NOT INCLUDING THE POLE */
       +{ "npr;", 0x02280 }, /* DOES NOT PRECEDE */
       +{ "nprcue;", 0x022E0 }, /* DOES NOT PRECEDE OR EQUAL */
       +{ "nprec;", 0x02280 }, /* DOES NOT PRECEDE */
       +{ "nrArr;", 0x021CF }, /* RIGHTWARDS DOUBLE ARROW WITH STROKE */
       +{ "nrarr;", 0x0219B }, /* RIGHTWARDS ARROW WITH STROKE */
       +{ "nrightarrow;", 0x0219B }, /* RIGHTWARDS ARROW WITH STROKE */
       +{ "nrtri;", 0x022EB }, /* DOES NOT CONTAIN AS NORMAL SUBGROUP */
       +{ "nrtrie;", 0x022ED }, /* DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL */
       +{ "nsc;", 0x02281 }, /* DOES NOT SUCCEED */
       +{ "nsccue;", 0x022E1 }, /* DOES NOT SUCCEED OR EQUAL */
       +{ "nscr;", 0x1D4C3 }, /* MATHEMATICAL SCRIPT SMALL N */
       +{ "nshortmid;", 0x02224 }, /* DOES NOT DIVIDE */
       +{ "nshortparallel;", 0x02226 }, /* NOT PARALLEL TO */
       +{ "nsim;", 0x02241 }, /* NOT TILDE */
       +{ "nsime;", 0x02244 }, /* NOT ASYMPTOTICALLY EQUAL TO */
       +{ "nsimeq;", 0x02244 }, /* NOT ASYMPTOTICALLY EQUAL TO */
       +{ "nsmid;", 0x02224 }, /* DOES NOT DIVIDE */
       +{ "nspar;", 0x02226 }, /* NOT PARALLEL TO */
       +{ "nsqsube;", 0x022E2 }, /* NOT SQUARE IMAGE OF OR EQUAL TO */
       +{ "nsqsupe;", 0x022E3 }, /* NOT SQUARE ORIGINAL OF OR EQUAL TO */
       +{ "nsub;", 0x02284 }, /* NOT A SUBSET OF */
       +{ "nsube;", 0x02288 }, /* NEITHER A SUBSET OF NOR EQUAL TO */
       +{ "nsubseteq;", 0x02288 }, /* NEITHER A SUBSET OF NOR EQUAL TO */
       +{ "nsucc;", 0x02281 }, /* DOES NOT SUCCEED */
       +{ "nsup;", 0x02285 }, /* NOT A SUPERSET OF */
       +{ "nsupe;", 0x02289 }, /* NEITHER A SUPERSET OF NOR EQUAL TO */
       +{ "nsupseteq;", 0x02289 }, /* NEITHER A SUPERSET OF NOR EQUAL TO */
       +{ "ntgl;", 0x02279 }, /* NEITHER GREATER-THAN NOR LESS-THAN */
       +{ "ntilde;", 0x000F1 }, /* LATIN SMALL LETTER N WITH TILDE */
       +{ "ntlg;", 0x02278 }, /* NEITHER LESS-THAN NOR GREATER-THAN */
       +{ "ntriangleleft;", 0x022EA }, /* NOT NORMAL SUBGROUP OF */
       +{ "ntrianglelefteq;", 0x022EC }, /* NOT NORMAL SUBGROUP OF OR EQUAL TO */
       +{ "ntriangleright;", 0x022EB }, /* DOES NOT CONTAIN AS NORMAL SUBGROUP */
       +{ "ntrianglerighteq;", 0x022ED }, /* DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL */
       +{ "nu;", 0x003BD }, /* GREEK SMALL LETTER NU */
       +{ "num;", 0x00023 }, /* NUMBER SIGN */
       +{ "numero;", 0x02116 }, /* NUMERO SIGN */
       +{ "numsp;", 0x02007 }, /* FIGURE SPACE */
       +{ "nvDash;", 0x022AD }, /* NOT TRUE */
       +{ "nvHarr;", 0x02904 }, /* LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE */
       +{ "nvdash;", 0x022AC }, /* DOES NOT PROVE */
       +{ "nvinfin;", 0x029DE }, /* INFINITY NEGATED WITH VERTICAL BAR */
       +{ "nvlArr;", 0x02902 }, /* LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE */
       +{ "nvrArr;", 0x02903 }, /* RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE */
       +{ "nwArr;", 0x021D6 }, /* NORTH WEST DOUBLE ARROW */
       +{ "nwarhk;", 0x02923 }, /* NORTH WEST ARROW WITH HOOK */
       +{ "nwarr;", 0x02196 }, /* NORTH WEST ARROW */
       +{ "nwarrow;", 0x02196 }, /* NORTH WEST ARROW */
       +{ "nwnear;", 0x02927 }, /* NORTH WEST ARROW AND NORTH EAST ARROW */
       +{ "oS;", 0x024C8 }, /* CIRCLED LATIN CAPITAL LETTER S */
       +{ "oacute;", 0x000F3 }, /* LATIN SMALL LETTER O WITH ACUTE */
       +{ "oast;", 0x0229B }, /* CIRCLED ASTERISK OPERATOR */
       +{ "ocir;", 0x0229A }, /* CIRCLED RING OPERATOR */
       +{ "ocirc;", 0x000F4 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
       +{ "ocy;", 0x0043E }, /* CYRILLIC SMALL LETTER O */
       +{ "odash;", 0x0229D }, /* CIRCLED DASH */
       +{ "odblac;", 0x00151 }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */
       +{ "odiv;", 0x02A38 }, /* CIRCLED DIVISION SIGN */
       +{ "odot;", 0x02299 }, /* CIRCLED DOT OPERATOR */
       +{ "odsold;", 0x029BC }, /* CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN */
       +{ "oelig;", 0x00153 }, /* LATIN SMALL LIGATURE OE */
       +{ "ofcir;", 0x029BF }, /* CIRCLED BULLET */
       +{ "ofr;", 0x1D52C }, /* MATHEMATICAL FRAKTUR SMALL O */
       +{ "ogon;", 0x002DB }, /* OGONEK */
       +{ "ograve;", 0x000F2 }, /* LATIN SMALL LETTER O WITH GRAVE */
       +{ "ogt;", 0x029C1 }, /* CIRCLED GREATER-THAN */
       +{ "ohbar;", 0x029B5 }, /* CIRCLE WITH HORIZONTAL BAR */
       +{ "ohm;", 0x02126 }, /* OHM SIGN */
       +{ "oint;", 0x0222E }, /* CONTOUR INTEGRAL */
       +{ "olarr;", 0x021BA }, /* ANTICLOCKWISE OPEN CIRCLE ARROW */
       +{ "olcir;", 0x029BE }, /* CIRCLED WHITE BULLET */
       +{ "olcross;", 0x029BB }, /* CIRCLE WITH SUPERIMPOSED X */
       +{ "oline;", 0x0203E }, /* OVERLINE */
       +{ "olt;", 0x029C0 }, /* CIRCLED LESS-THAN */
       +{ "omacr;", 0x0014D }, /* LATIN SMALL LETTER O WITH MACRON */
       +{ "omega;", 0x003C9 }, /* GREEK SMALL LETTER OMEGA */
       +{ "omicron;", 0x003BF }, /* GREEK SMALL LETTER OMICRON */
       +{ "omid;", 0x029B6 }, /* CIRCLED VERTICAL BAR */
       +{ "ominus;", 0x02296 }, /* CIRCLED MINUS */
       +{ "oopf;", 0x1D560 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL O */
       +{ "opar;", 0x029B7 }, /* CIRCLED PARALLEL */
       +{ "operp;", 0x029B9 }, /* CIRCLED PERPENDICULAR */
       +{ "oplus;", 0x02295 }, /* CIRCLED PLUS */
       +{ "or;", 0x02228 }, /* LOGICAL OR */
       +{ "orarr;", 0x021BB }, /* CLOCKWISE OPEN CIRCLE ARROW */
       +{ "ord;", 0x02A5D }, /* LOGICAL OR WITH HORIZONTAL DASH */
       +{ "order;", 0x02134 }, /* SCRIPT SMALL O */
       +{ "orderof;", 0x02134 }, /* SCRIPT SMALL O */
       +{ "ordf;", 0x000AA }, /* FEMININE ORDINAL INDICATOR */
       +{ "ordm;", 0x000BA }, /* MASCULINE ORDINAL INDICATOR */
       +{ "origof;", 0x022B6 }, /* ORIGINAL OF */
       +{ "oror;", 0x02A56 }, /* TWO INTERSECTING LOGICAL OR */
       +{ "orslope;", 0x02A57 }, /* SLOPING LARGE OR */
       +{ "orv;", 0x02A5B }, /* LOGICAL OR WITH MIDDLE STEM */
       +{ "oscr;", 0x02134 }, /* SCRIPT SMALL O */
       +{ "oslash;", 0x000F8 }, /* LATIN SMALL LETTER O WITH STROKE */
       +{ "osol;", 0x02298 }, /* CIRCLED DIVISION SLASH */
       +{ "otilde;", 0x000F5 }, /* LATIN SMALL LETTER O WITH TILDE */
       +{ "otimes;", 0x02297 }, /* CIRCLED TIMES */
       +{ "otimesas;", 0x02A36 }, /* CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT */
       +{ "ouml;", 0x000F6 }, /* LATIN SMALL LETTER O WITH DIAERESIS */
       +{ "ovbar;", 0x0233D }, /* APL FUNCTIONAL SYMBOL CIRCLE STILE */
       +{ "par;", 0x02225 }, /* PARALLEL TO */
       +{ "para;", 0x000B6 }, /* PILCROW SIGN */
       +{ "parallel;", 0x02225 }, /* PARALLEL TO */
       +{ "parsim;", 0x02AF3 }, /* PARALLEL WITH TILDE OPERATOR */
       +{ "parsl;", 0x02AFD }, /* DOUBLE SOLIDUS OPERATOR */
       +{ "part;", 0x02202 }, /* PARTIAL DIFFERENTIAL */
       +{ "pcy;", 0x0043F }, /* CYRILLIC SMALL LETTER PE */
       +{ "percnt;", 0x00025 }, /* PERCENT SIGN */
       +{ "period;", 0x0002E }, /* FULL STOP */
       +{ "permil;", 0x02030 }, /* PER MILLE SIGN */
       +{ "perp;", 0x022A5 }, /* UP TACK */
       +{ "pertenk;", 0x02031 }, /* PER TEN THOUSAND SIGN */
       +{ "pfr;", 0x1D52D }, /* MATHEMATICAL FRAKTUR SMALL P */
       +{ "phi;", 0x003C6 }, /* GREEK SMALL LETTER PHI */
       +{ "phiv;", 0x003C6 }, /* GREEK SMALL LETTER PHI */
       +{ "phmmat;", 0x02133 }, /* SCRIPT CAPITAL M */
       +{ "phone;", 0x0260E }, /* BLACK TELEPHONE */
       +{ "pi;", 0x003C0 }, /* GREEK SMALL LETTER PI */
       +{ "pitchfork;", 0x022D4 }, /* PITCHFORK */
       +{ "piv;", 0x003D6 }, /* GREEK PI SYMBOL */
       +{ "planck;", 0x0210F }, /* PLANCK CONSTANT OVER TWO PI */
       +{ "planckh;", 0x0210E }, /* PLANCK CONSTANT */
       +{ "plankv;", 0x0210F }, /* PLANCK CONSTANT OVER TWO PI */
       +{ "plus;", 0x0002B }, /* PLUS SIGN */
       +{ "plusacir;", 0x02A23 }, /* PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE */
       +{ "plusb;", 0x0229E }, /* SQUARED PLUS */
       +{ "pluscir;", 0x02A22 }, /* PLUS SIGN WITH SMALL CIRCLE ABOVE */
       +{ "plusdo;", 0x02214 }, /* DOT PLUS */
       +{ "plusdu;", 0x02A25 }, /* PLUS SIGN WITH DOT BELOW */
       +{ "pluse;", 0x02A72 }, /* PLUS SIGN ABOVE EQUALS SIGN */
       +{ "plusmn;", 0x000B1 }, /* PLUS-MINUS SIGN */
       +{ "plussim;", 0x02A26 }, /* PLUS SIGN WITH TILDE BELOW */
       +{ "plustwo;", 0x02A27 }, /* PLUS SIGN WITH SUBSCRIPT TWO */
       +{ "pm;", 0x000B1 }, /* PLUS-MINUS SIGN */
       +{ "pointint;", 0x02A15 }, /* INTEGRAL AROUND A POINT OPERATOR */
       +{ "popf;", 0x1D561 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL P */
       +{ "pound;", 0x000A3 }, /* POUND SIGN */
       +{ "pr;", 0x0227A }, /* PRECEDES */
       +{ "prE;", 0x02AB3 }, /* PRECEDES ABOVE EQUALS SIGN */
       +{ "prap;", 0x02AB7 }, /* PRECEDES ABOVE ALMOST EQUAL TO */
       +{ "prcue;", 0x0227C }, /* PRECEDES OR EQUAL TO */
       +{ "pre;", 0x02AAF }, /* PRECEDES ABOVE SINGLE-LINE EQUALS SIGN */
       +{ "prec;", 0x0227A }, /* PRECEDES */
       +{ "precapprox;", 0x02AB7 }, /* PRECEDES ABOVE ALMOST EQUAL TO */
       +{ "preccurlyeq;", 0x0227C }, /* PRECEDES OR EQUAL TO */
       +{ "preceq;", 0x02AAF }, /* PRECEDES ABOVE SINGLE-LINE EQUALS SIGN */
       +{ "precnapprox;", 0x02AB9 }, /* PRECEDES ABOVE NOT ALMOST EQUAL TO */
       +{ "precneqq;", 0x02AB5 }, /* PRECEDES ABOVE NOT EQUAL TO */
       +{ "precnsim;", 0x022E8 }, /* PRECEDES BUT NOT EQUIVALENT TO */
       +{ "precsim;", 0x0227E }, /* PRECEDES OR EQUIVALENT TO */
       +{ "prime;", 0x02032 }, /* PRIME */
       +{ "primes;", 0x02119 }, /* DOUBLE-STRUCK CAPITAL P */
       +{ "prnE;", 0x02AB5 }, /* PRECEDES ABOVE NOT EQUAL TO */
       +{ "prnap;", 0x02AB9 }, /* PRECEDES ABOVE NOT ALMOST EQUAL TO */
       +{ "prnsim;", 0x022E8 }, /* PRECEDES BUT NOT EQUIVALENT TO */
       +{ "prod;", 0x0220F }, /* N-ARY PRODUCT */
       +{ "profalar;", 0x0232E }, /* ALL AROUND-PROFILE */
       +{ "profline;", 0x02312 }, /* ARC */
       +{ "profsurf;", 0x02313 }, /* SEGMENT */
       +{ "prop;", 0x0221D }, /* PROPORTIONAL TO */
       +{ "propto;", 0x0221D }, /* PROPORTIONAL TO */
       +{ "prsim;", 0x0227E }, /* PRECEDES OR EQUIVALENT TO */
       +{ "prurel;", 0x022B0 }, /* PRECEDES UNDER RELATION */
       +{ "pscr;", 0x1D4C5 }, /* MATHEMATICAL SCRIPT SMALL P */
       +{ "psi;", 0x003C8 }, /* GREEK SMALL LETTER PSI */
       +{ "puncsp;", 0x02008 }, /* PUNCTUATION SPACE */
       +{ "qfr;", 0x1D52E }, /* MATHEMATICAL FRAKTUR SMALL Q */
       +{ "qint;", 0x02A0C }, /* QUADRUPLE INTEGRAL OPERATOR */
       +{ "qopf;", 0x1D562 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL Q */
       +{ "qprime;", 0x02057 }, /* QUADRUPLE PRIME */
       +{ "qscr;", 0x1D4C6 }, /* MATHEMATICAL SCRIPT SMALL Q */
       +{ "quaternions;", 0x0210D }, /* DOUBLE-STRUCK CAPITAL H */
       +{ "quatint;", 0x02A16 }, /* QUATERNION INTEGRAL OPERATOR */
       +{ "quest;", 0x0003F }, /* QUESTION MARK */
       +{ "questeq;", 0x0225F }, /* QUESTIONED EQUAL TO */
       +{ "quot;", 0x00022 }, /* QUOTATION MARK */
       +{ "rAarr;", 0x021DB }, /* RIGHTWARDS TRIPLE ARROW */
       +{ "rArr;", 0x021D2 }, /* RIGHTWARDS DOUBLE ARROW */
       +{ "rAtail;", 0x0291C }, /* RIGHTWARDS DOUBLE ARROW-TAIL */
       +{ "rBarr;", 0x0290F }, /* RIGHTWARDS TRIPLE DASH ARROW */
       +{ "rHar;", 0x02964 }, /* RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN */
       +{ "race;", 0x029DA }, /* LEFT DOUBLE WIGGLY FENCE */
       +{ "racute;", 0x00155 }, /* LATIN SMALL LETTER R WITH ACUTE */
       +{ "radic;", 0x0221A }, /* SQUARE ROOT */
       +{ "raemptyv;", 0x029B3 }, /* EMPTY SET WITH RIGHT ARROW ABOVE */
       +{ "rang;", 0x027E9 }, /* MATHEMATICAL RIGHT ANGLE BRACKET */
       +{ "rangd;", 0x02992 }, /* RIGHT ANGLE BRACKET WITH DOT */
       +{ "range;", 0x029A5 }, /* REVERSED ANGLE WITH UNDERBAR */
       +{ "rangle;", 0x027E9 }, /* MATHEMATICAL RIGHT ANGLE BRACKET */
       +{ "raquo;", 0x000BB }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
       +{ "rarr;", 0x02192 }, /* RIGHTWARDS ARROW */
       +{ "rarrap;", 0x02975 }, /* RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO */
       +{ "rarrb;", 0x021E5 }, /* RIGHTWARDS ARROW TO BAR */
       +{ "rarrbfs;", 0x02920 }, /* RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND */
       +{ "rarrc;", 0x02933 }, /* WAVE ARROW POINTING DIRECTLY RIGHT */
       +{ "rarrfs;", 0x0291E }, /* RIGHTWARDS ARROW TO BLACK DIAMOND */
       +{ "rarrhk;", 0x021AA }, /* RIGHTWARDS ARROW WITH HOOK */
       +{ "rarrlp;", 0x021AC }, /* RIGHTWARDS ARROW WITH LOOP */
       +{ "rarrpl;", 0x02945 }, /* RIGHTWARDS ARROW WITH PLUS BELOW */
       +{ "rarrsim;", 0x02974 }, /* RIGHTWARDS ARROW ABOVE TILDE OPERATOR */
       +{ "rarrtl;", 0x021A3 }, /* RIGHTWARDS ARROW WITH TAIL */
       +{ "rarrw;", 0x0219D }, /* RIGHTWARDS WAVE ARROW */
       +{ "ratail;", 0x0291A }, /* RIGHTWARDS ARROW-TAIL */
       +{ "ratio;", 0x02236 }, /* RATIO */
       +{ "rationals;", 0x0211A }, /* DOUBLE-STRUCK CAPITAL Q */
       +{ "rbarr;", 0x0290D }, /* RIGHTWARDS DOUBLE DASH ARROW */
       +{ "rbbrk;", 0x02773 }, /* LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT */
       +{ "rbrace;", 0x0007D }, /* RIGHT CURLY BRACKET */
       +{ "rbrack;", 0x0005D }, /* RIGHT SQUARE BRACKET */
       +{ "rbrke;", 0x0298C }, /* RIGHT SQUARE BRACKET WITH UNDERBAR */
       +{ "rbrksld;", 0x0298E }, /* RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER */
       +{ "rbrkslu;", 0x02990 }, /* RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER */
       +{ "rcaron;", 0x00159 }, /* LATIN SMALL LETTER R WITH CARON */
       +{ "rcedil;", 0x00157 }, /* LATIN SMALL LETTER R WITH CEDILLA */
       +{ "rceil;", 0x02309 }, /* RIGHT CEILING */
       +{ "rcub;", 0x0007D }, /* RIGHT CURLY BRACKET */
       +{ "rcy;", 0x00440 }, /* CYRILLIC SMALL LETTER ER */
       +{ "rdca;", 0x02937 }, /* ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS */
       +{ "rdldhar;", 0x02969 }, /* RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN */
       +{ "rdquo;", 0x0201D }, /* RIGHT DOUBLE QUOTATION MARK */
       +{ "rdquor;", 0x0201D }, /* RIGHT DOUBLE QUOTATION MARK */
       +{ "rdsh;", 0x021B3 }, /* DOWNWARDS ARROW WITH TIP RIGHTWARDS */
       +{ "real;", 0x0211C }, /* BLACK-LETTER CAPITAL R */
       +{ "realine;", 0x0211B }, /* SCRIPT CAPITAL R */
       +{ "realpart;", 0x0211C }, /* BLACK-LETTER CAPITAL R */
       +{ "reals;", 0x0211D }, /* DOUBLE-STRUCK CAPITAL R */
       +{ "rect;", 0x025AD }, /* WHITE RECTANGLE */
       +{ "reg;", 0x000AE }, /* REGISTERED SIGN */
       +{ "rfisht;", 0x0297D }, /* RIGHT FISH TAIL */
       +{ "rfloor;", 0x0230B }, /* RIGHT FLOOR */
       +{ "rfr;", 0x1D52F }, /* MATHEMATICAL FRAKTUR SMALL R */
       +{ "rhard;", 0x021C1 }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS */
       +{ "rharu;", 0x021C0 }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS */
       +{ "rharul;", 0x0296C }, /* RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH */
       +{ "rho;", 0x003C1 }, /* GREEK SMALL LETTER RHO */
       +{ "rhov;", 0x003F1 }, /* GREEK RHO SYMBOL */
       +{ "rightarrow;", 0x02192 }, /* RIGHTWARDS ARROW */
       +{ "rightarrowtail;", 0x021A3 }, /* RIGHTWARDS ARROW WITH TAIL */
       +{ "rightharpoondown;", 0x021C1 }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS */
       +{ "rightharpoonup;", 0x021C0 }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS */
       +{ "rightleftarrows;", 0x021C4 }, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW */
       +{ "rightleftharpoons;", 0x021CC }, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON */
       +{ "rightrightarrows;", 0x021C9 }, /* RIGHTWARDS PAIRED ARROWS */
       +{ "rightsquigarrow;", 0x0219D }, /* RIGHTWARDS WAVE ARROW */
       +{ "rightthreetimes;", 0x022CC }, /* RIGHT SEMIDIRECT PRODUCT */
       +{ "ring;", 0x002DA }, /* RING ABOVE */
       +{ "risingdotseq;", 0x02253 }, /* IMAGE OF OR APPROXIMATELY EQUAL TO */
       +{ "rlarr;", 0x021C4 }, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW */
       +{ "rlhar;", 0x021CC }, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON */
       +{ "rlm;", 0x0200F }, /* RIGHT-TO-LEFT MARK */
       +{ "rmoust;", 0x023B1 }, /* UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION */
       +{ "rmoustache;", 0x023B1 }, /* UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION */
       +{ "rnmid;", 0x02AEE }, /* DOES NOT DIVIDE WITH REVERSED NEGATION SLASH */
       +{ "roang;", 0x027ED }, /* MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET */
       +{ "roarr;", 0x021FE }, /* RIGHTWARDS OPEN-HEADED ARROW */
       +{ "robrk;", 0x027E7 }, /* MATHEMATICAL RIGHT WHITE SQUARE BRACKET */
       +{ "ropar;", 0x02986 }, /* RIGHT WHITE PARENTHESIS */
       +{ "ropf;", 0x1D563 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL R */
       +{ "roplus;", 0x02A2E }, /* PLUS SIGN IN RIGHT HALF CIRCLE */
       +{ "rotimes;", 0x02A35 }, /* MULTIPLICATION SIGN IN RIGHT HALF CIRCLE */
       +{ "rpar;", 0x00029 }, /* RIGHT PARENTHESIS */
       +{ "rpargt;", 0x02994 }, /* RIGHT ARC GREATER-THAN BRACKET */
       +{ "rppolint;", 0x02A12 }, /* LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE */
       +{ "rrarr;", 0x021C9 }, /* RIGHTWARDS PAIRED ARROWS */
       +{ "rsaquo;", 0x0203A }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
       +{ "rscr;", 0x1D4C7 }, /* MATHEMATICAL SCRIPT SMALL R */
       +{ "rsh;", 0x021B1 }, /* UPWARDS ARROW WITH TIP RIGHTWARDS */
       +{ "rsqb;", 0x0005D }, /* RIGHT SQUARE BRACKET */
       +{ "rsquo;", 0x02019 }, /* RIGHT SINGLE QUOTATION MARK */
       +{ "rsquor;", 0x02019 }, /* RIGHT SINGLE QUOTATION MARK */
       +{ "rthree;", 0x022CC }, /* RIGHT SEMIDIRECT PRODUCT */
       +{ "rtimes;", 0x022CA }, /* RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT */
       +{ "rtri;", 0x025B9 }, /* WHITE RIGHT-POINTING SMALL TRIANGLE */
       +{ "rtrie;", 0x022B5 }, /* CONTAINS AS NORMAL SUBGROUP OR EQUAL TO */
       +{ "rtrif;", 0x025B8 }, /* BLACK RIGHT-POINTING SMALL TRIANGLE */
       +{ "rtriltri;", 0x029CE }, /* RIGHT TRIANGLE ABOVE LEFT TRIANGLE */
       +{ "ruluhar;", 0x02968 }, /* RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP */
       +{ "rx;", 0x0211E }, /* PRESCRIPTION TAKE */
       +{ "sacute;", 0x0015B }, /* LATIN SMALL LETTER S WITH ACUTE */
       +{ "sbquo;", 0x0201A }, /* SINGLE LOW-9 QUOTATION MARK */
       +{ "sc;", 0x0227B }, /* SUCCEEDS */
       +{ "scE;", 0x02AB4 }, /* SUCCEEDS ABOVE EQUALS SIGN */
       +{ "scap;", 0x02AB8 }, /* SUCCEEDS ABOVE ALMOST EQUAL TO */
       +{ "scaron;", 0x00161 }, /* LATIN SMALL LETTER S WITH CARON */
       +{ "sccue;", 0x0227D }, /* SUCCEEDS OR EQUAL TO */
       +{ "sce;", 0x02AB0 }, /* SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN */
       +{ "scedil;", 0x0015F }, /* LATIN SMALL LETTER S WITH CEDILLA */
       +{ "scirc;", 0x0015D }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */
       +{ "scnE;", 0x02AB6 }, /* SUCCEEDS ABOVE NOT EQUAL TO */
       +{ "scnap;", 0x02ABA }, /* SUCCEEDS ABOVE NOT ALMOST EQUAL TO */
       +{ "scnsim;", 0x022E9 }, /* SUCCEEDS BUT NOT EQUIVALENT TO */
       +{ "scpolint;", 0x02A13 }, /* LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE */
       +{ "scsim;", 0x0227F }, /* SUCCEEDS OR EQUIVALENT TO */
       +{ "scy;", 0x00441 }, /* CYRILLIC SMALL LETTER ES */
       +{ "sdot;", 0x022C5 }, /* DOT OPERATOR */
       +{ "sdotb;", 0x022A1 }, /* SQUARED DOT OPERATOR */
       +{ "sdote;", 0x02A66 }, /* EQUALS SIGN WITH DOT BELOW */
       +{ "seArr;", 0x021D8 }, /* SOUTH EAST DOUBLE ARROW */
       +{ "searhk;", 0x02925 }, /* SOUTH EAST ARROW WITH HOOK */
       +{ "searr;", 0x02198 }, /* SOUTH EAST ARROW */
       +{ "searrow;", 0x02198 }, /* SOUTH EAST ARROW */
       +{ "sect;", 0x000A7 }, /* SECTION SIGN */
       +{ "semi;", 0x0003B }, /* SEMICOLON */
       +{ "seswar;", 0x02929 }, /* SOUTH EAST ARROW AND SOUTH WEST ARROW */
       +{ "setminus;", 0x02216 }, /* SET MINUS */
       +{ "setmn;", 0x02216 }, /* SET MINUS */
       +{ "sext;", 0x02736 }, /* SIX POINTED BLACK STAR */
       +{ "sfr;", 0x1D530 }, /* MATHEMATICAL FRAKTUR SMALL S */
       +{ "sfrown;", 0x02322 }, /* FROWN */
       +{ "sharp;", 0x0266F }, /* MUSIC SHARP SIGN */
       +{ "shchcy;", 0x00449 }, /* CYRILLIC SMALL LETTER SHCHA */
       +{ "shcy;", 0x00448 }, /* CYRILLIC SMALL LETTER SHA */
       +{ "shortmid;", 0x02223 }, /* DIVIDES */
       +{ "shortparallel;", 0x02225 }, /* PARALLEL TO */
       +{ "shy;", 0x000AD }, /* SOFT HYPHEN */
       +{ "sigma;", 0x003C3 }, /* GREEK SMALL LETTER SIGMA */
       +{ "sigmaf;", 0x003C2 }, /* GREEK SMALL LETTER FINAL SIGMA */
       +{ "sigmav;", 0x003C2 }, /* GREEK SMALL LETTER FINAL SIGMA */
       +{ "sim;", 0x0223C }, /* TILDE OPERATOR */
       +{ "simdot;", 0x02A6A }, /* TILDE OPERATOR WITH DOT ABOVE */
       +{ "sime;", 0x02243 }, /* ASYMPTOTICALLY EQUAL TO */
       +{ "simeq;", 0x02243 }, /* ASYMPTOTICALLY EQUAL TO */
       +{ "simg;", 0x02A9E }, /* SIMILAR OR GREATER-THAN */
       +{ "simgE;", 0x02AA0 }, /* SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN */
       +{ "siml;", 0x02A9D }, /* SIMILAR OR LESS-THAN */
       +{ "simlE;", 0x02A9F }, /* SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN */
       +{ "simne;", 0x02246 }, /* APPROXIMATELY BUT NOT ACTUALLY EQUAL TO */
       +{ "simplus;", 0x02A24 }, /* PLUS SIGN WITH TILDE ABOVE */
       +{ "simrarr;", 0x02972 }, /* TILDE OPERATOR ABOVE RIGHTWARDS ARROW */
       +{ "slarr;", 0x02190 }, /* LEFTWARDS ARROW */
       +{ "smallsetminus;", 0x02216 }, /* SET MINUS */
       +{ "smashp;", 0x02A33 }, /* SMASH PRODUCT */
       +{ "smeparsl;", 0x029E4 }, /* EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE */
       +{ "smid;", 0x02223 }, /* DIVIDES */
       +{ "smile;", 0x02323 }, /* SMILE */
       +{ "smt;", 0x02AAA }, /* SMALLER THAN */
       +{ "smte;", 0x02AAC }, /* SMALLER THAN OR EQUAL TO */
       +{ "softcy;", 0x0044C }, /* CYRILLIC SMALL LETTER SOFT SIGN */
       +{ "sol;", 0x0002F }, /* SOLIDUS */
       +{ "solb;", 0x029C4 }, /* SQUARED RISING DIAGONAL SLASH */
       +{ "solbar;", 0x0233F }, /* APL FUNCTIONAL SYMBOL SLASH BAR */
       +{ "sopf;", 0x1D564 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL S */
       +{ "spades;", 0x02660 }, /* BLACK SPADE SUIT */
       +{ "spadesuit;", 0x02660 }, /* BLACK SPADE SUIT */
       +{ "spar;", 0x02225 }, /* PARALLEL TO */
       +{ "sqcap;", 0x02293 }, /* SQUARE CAP */
       +{ "sqcup;", 0x02294 }, /* SQUARE CUP */
       +{ "sqsub;", 0x0228F }, /* SQUARE IMAGE OF */
       +{ "sqsube;", 0x02291 }, /* SQUARE IMAGE OF OR EQUAL TO */
       +{ "sqsubset;", 0x0228F }, /* SQUARE IMAGE OF */
       +{ "sqsubseteq;", 0x02291 }, /* SQUARE IMAGE OF OR EQUAL TO */
       +{ "sqsup;", 0x02290 }, /* SQUARE ORIGINAL OF */
       +{ "sqsupe;", 0x02292 }, /* SQUARE ORIGINAL OF OR EQUAL TO */
       +{ "sqsupset;", 0x02290 }, /* SQUARE ORIGINAL OF */
       +{ "sqsupseteq;", 0x02292 }, /* SQUARE ORIGINAL OF OR EQUAL TO */
       +{ "squ;", 0x025A1 }, /* WHITE SQUARE */
       +{ "square;", 0x025A1 }, /* WHITE SQUARE */
       +{ "squarf;", 0x025AA }, /* BLACK SMALL SQUARE */
       +{ "squf;", 0x025AA }, /* BLACK SMALL SQUARE */
       +{ "srarr;", 0x02192 }, /* RIGHTWARDS ARROW */
       +{ "sscr;", 0x1D4C8 }, /* MATHEMATICAL SCRIPT SMALL S */
       +{ "ssetmn;", 0x02216 }, /* SET MINUS */
       +{ "ssmile;", 0x02323 }, /* SMILE */
       +{ "sstarf;", 0x022C6 }, /* STAR OPERATOR */
       +{ "star;", 0x02606 }, /* WHITE STAR */
       +{ "starf;", 0x02605 }, /* BLACK STAR */
       +{ "straightepsilon;", 0x003F5 }, /* GREEK LUNATE EPSILON SYMBOL */
       +{ "straightphi;", 0x003D5 }, /* GREEK PHI SYMBOL */
       +{ "strns;", 0x000AF }, /* MACRON */
       +{ "sub;", 0x02282 }, /* SUBSET OF */
       +{ "subE;", 0x02AC5 }, /* SUBSET OF ABOVE EQUALS SIGN */
       +{ "subdot;", 0x02ABD }, /* SUBSET WITH DOT */
       +{ "sube;", 0x02286 }, /* SUBSET OF OR EQUAL TO */
       +{ "subedot;", 0x02AC3 }, /* SUBSET OF OR EQUAL TO WITH DOT ABOVE */
       +{ "submult;", 0x02AC1 }, /* SUBSET WITH MULTIPLICATION SIGN BELOW */
       +{ "subnE;", 0x02ACB }, /* SUBSET OF ABOVE NOT EQUAL TO */
       +{ "subne;", 0x0228A }, /* SUBSET OF WITH NOT EQUAL TO */
       +{ "subplus;", 0x02ABF }, /* SUBSET WITH PLUS SIGN BELOW */
       +{ "subrarr;", 0x02979 }, /* SUBSET ABOVE RIGHTWARDS ARROW */
       +{ "subset;", 0x02282 }, /* SUBSET OF */
       +{ "subseteq;", 0x02286 }, /* SUBSET OF OR EQUAL TO */
       +{ "subseteqq;", 0x02AC5 }, /* SUBSET OF ABOVE EQUALS SIGN */
       +{ "subsetneq;", 0x0228A }, /* SUBSET OF WITH NOT EQUAL TO */
       +{ "subsetneqq;", 0x02ACB }, /* SUBSET OF ABOVE NOT EQUAL TO */
       +{ "subsim;", 0x02AC7 }, /* SUBSET OF ABOVE TILDE OPERATOR */
       +{ "subsub;", 0x02AD5 }, /* SUBSET ABOVE SUBSET */
       +{ "subsup;", 0x02AD3 }, /* SUBSET ABOVE SUPERSET */
       +{ "succ;", 0x0227B }, /* SUCCEEDS */
       +{ "succapprox;", 0x02AB8 }, /* SUCCEEDS ABOVE ALMOST EQUAL TO */
       +{ "succcurlyeq;", 0x0227D }, /* SUCCEEDS OR EQUAL TO */
       +{ "succeq;", 0x02AB0 }, /* SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN */
       +{ "succnapprox;", 0x02ABA }, /* SUCCEEDS ABOVE NOT ALMOST EQUAL TO */
       +{ "succneqq;", 0x02AB6 }, /* SUCCEEDS ABOVE NOT EQUAL TO */
       +{ "succnsim;", 0x022E9 }, /* SUCCEEDS BUT NOT EQUIVALENT TO */
       +{ "succsim;", 0x0227F }, /* SUCCEEDS OR EQUIVALENT TO */
       +{ "sum;", 0x02211 }, /* N-ARY SUMMATION */
       +{ "sung;", 0x0266A }, /* EIGHTH NOTE */
       +{ "sup1;", 0x000B9 }, /* SUPERSCRIPT ONE */
       +{ "sup2;", 0x000B2 }, /* SUPERSCRIPT TWO */
       +{ "sup3;", 0x000B3 }, /* SUPERSCRIPT THREE */
       +{ "sup;", 0x02283 }, /* SUPERSET OF */
       +{ "supE;", 0x02AC6 }, /* SUPERSET OF ABOVE EQUALS SIGN */
       +{ "supdot;", 0x02ABE }, /* SUPERSET WITH DOT */
       +{ "supdsub;", 0x02AD8 }, /* SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET */
       +{ "supe;", 0x02287 }, /* SUPERSET OF OR EQUAL TO */
       +{ "supedot;", 0x02AC4 }, /* SUPERSET OF OR EQUAL TO WITH DOT ABOVE */
       +{ "suphsub;", 0x02AD7 }, /* SUPERSET BESIDE SUBSET */
       +{ "suplarr;", 0x0297B }, /* SUPERSET ABOVE LEFTWARDS ARROW */
       +{ "supmult;", 0x02AC2 }, /* SUPERSET WITH MULTIPLICATION SIGN BELOW */
       +{ "supnE;", 0x02ACC }, /* SUPERSET OF ABOVE NOT EQUAL TO */
       +{ "supne;", 0x0228B }, /* SUPERSET OF WITH NOT EQUAL TO */
       +{ "supplus;", 0x02AC0 }, /* SUPERSET WITH PLUS SIGN BELOW */
       +{ "supset;", 0x02283 }, /* SUPERSET OF */
       +{ "supseteq;", 0x02287 }, /* SUPERSET OF OR EQUAL TO */
       +{ "supseteqq;", 0x02AC6 }, /* SUPERSET OF ABOVE EQUALS SIGN */
       +{ "supsetneq;", 0x0228B }, /* SUPERSET OF WITH NOT EQUAL TO */
       +{ "supsetneqq;", 0x02ACC }, /* SUPERSET OF ABOVE NOT EQUAL TO */
       +{ "supsim;", 0x02AC8 }, /* SUPERSET OF ABOVE TILDE OPERATOR */
       +{ "supsub;", 0x02AD4 }, /* SUPERSET ABOVE SUBSET */
       +{ "supsup;", 0x02AD6 }, /* SUPERSET ABOVE SUPERSET */
       +{ "swArr;", 0x021D9 }, /* SOUTH WEST DOUBLE ARROW */
       +{ "swarhk;", 0x02926 }, /* SOUTH WEST ARROW WITH HOOK */
       +{ "swarr;", 0x02199 }, /* SOUTH WEST ARROW */
       +{ "swarrow;", 0x02199 }, /* SOUTH WEST ARROW */
       +{ "swnwar;", 0x0292A }, /* SOUTH WEST ARROW AND NORTH WEST ARROW */
       +{ "szlig;", 0x000DF }, /* LATIN SMALL LETTER SHARP S */
       +{ "target;", 0x02316 }, /* POSITION INDICATOR */
       +{ "tau;", 0x003C4 }, /* GREEK SMALL LETTER TAU */
       +{ "tbrk;", 0x023B4 }, /* TOP SQUARE BRACKET */
       +{ "tcaron;", 0x00165 }, /* LATIN SMALL LETTER T WITH CARON */
       +{ "tcedil;", 0x00163 }, /* LATIN SMALL LETTER T WITH CEDILLA */
       +{ "tcy;", 0x00442 }, /* CYRILLIC SMALL LETTER TE */
       +{ "tdot;", 0x020DB }, /* COMBINING THREE DOTS ABOVE */
       +{ "telrec;", 0x02315 }, /* TELEPHONE RECORDER */
       +{ "tfr;", 0x1D531 }, /* MATHEMATICAL FRAKTUR SMALL T */
       +{ "there4;", 0x02234 }, /* THEREFORE */
       +{ "therefore;", 0x02234 }, /* THEREFORE */
       +{ "theta;", 0x003B8 }, /* GREEK SMALL LETTER THETA */
       +{ "thetasym;", 0x003D1 }, /* GREEK THETA SYMBOL */
       +{ "thetav;", 0x003D1 }, /* GREEK THETA SYMBOL */
       +{ "thickapprox;", 0x02248 }, /* ALMOST EQUAL TO */
       +{ "thicksim;", 0x0223C }, /* TILDE OPERATOR */
       +{ "thinsp;", 0x02009 }, /* THIN SPACE */
       +{ "thkap;", 0x02248 }, /* ALMOST EQUAL TO */
       +{ "thksim;", 0x0223C }, /* TILDE OPERATOR */
       +{ "thorn;", 0x000FE }, /* LATIN SMALL LETTER THORN */
       +{ "tilde;", 0x002DC }, /* SMALL TILDE */
       +{ "times;", 0x000D7 }, /* MULTIPLICATION SIGN */
       +{ "timesb;", 0x022A0 }, /* SQUARED TIMES */
       +{ "timesbar;", 0x02A31 }, /* MULTIPLICATION SIGN WITH UNDERBAR */
       +{ "timesd;", 0x02A30 }, /* MULTIPLICATION SIGN WITH DOT ABOVE */
       +{ "tint;", 0x0222D }, /* TRIPLE INTEGRAL */
       +{ "toea;", 0x02928 }, /* NORTH EAST ARROW AND SOUTH EAST ARROW */
       +{ "top;", 0x022A4 }, /* DOWN TACK */
       +{ "topbot;", 0x02336 }, /* APL FUNCTIONAL SYMBOL I-BEAM */
       +{ "topcir;", 0x02AF1 }, /* DOWN TACK WITH CIRCLE BELOW */
       +{ "topf;", 0x1D565 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL T */
       +{ "topfork;", 0x02ADA }, /* PITCHFORK WITH TEE TOP */
       +{ "tosa;", 0x02929 }, /* SOUTH EAST ARROW AND SOUTH WEST ARROW */
       +{ "tprime;", 0x02034 }, /* TRIPLE PRIME */
       +{ "trade;", 0x02122 }, /* TRADE MARK SIGN */
       +{ "triangle;", 0x025B5 }, /* WHITE UP-POINTING SMALL TRIANGLE */
       +{ "triangledown;", 0x025BF }, /* WHITE DOWN-POINTING SMALL TRIANGLE */
       +{ "triangleleft;", 0x025C3 }, /* WHITE LEFT-POINTING SMALL TRIANGLE */
       +{ "trianglelefteq;", 0x022B4 }, /* NORMAL SUBGROUP OF OR EQUAL TO */
       +{ "triangleq;", 0x0225C }, /* DELTA EQUAL TO */
       +{ "triangleright;", 0x025B9 }, /* WHITE RIGHT-POINTING SMALL TRIANGLE */
       +{ "trianglerighteq;", 0x022B5 }, /* CONTAINS AS NORMAL SUBGROUP OR EQUAL TO */
       +{ "tridot;", 0x025EC }, /* WHITE UP-POINTING TRIANGLE WITH DOT */
       +{ "trie;", 0x0225C }, /* DELTA EQUAL TO */
       +{ "triminus;", 0x02A3A }, /* MINUS SIGN IN TRIANGLE */
       +{ "triplus;", 0x02A39 }, /* PLUS SIGN IN TRIANGLE */
       +{ "trisb;", 0x029CD }, /* TRIANGLE WITH SERIFS AT BOTTOM */
       +{ "tritime;", 0x02A3B }, /* MULTIPLICATION SIGN IN TRIANGLE */
       +{ "trpezium;", 0x023E2 }, /* WHITE TRAPEZIUM */
       +{ "tscr;", 0x1D4C9 }, /* MATHEMATICAL SCRIPT SMALL T */
       +{ "tscy;", 0x00446 }, /* CYRILLIC SMALL LETTER TSE */
       +{ "tshcy;", 0x0045B }, /* CYRILLIC SMALL LETTER TSHE */
       +{ "tstrok;", 0x00167 }, /* LATIN SMALL LETTER T WITH STROKE */
       +{ "twixt;", 0x0226C }, /* BETWEEN */
       +{ "twoheadleftarrow;", 0x0219E }, /* LEFTWARDS TWO HEADED ARROW */
       +{ "twoheadrightarrow;", 0x021A0 }, /* RIGHTWARDS TWO HEADED ARROW */
       +{ "uArr;", 0x021D1 }, /* UPWARDS DOUBLE ARROW */
       +{ "uHar;", 0x02963 }, /* UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT */
       +{ "uacute;", 0x000FA }, /* LATIN SMALL LETTER U WITH ACUTE */
       +{ "uarr;", 0x02191 }, /* UPWARDS ARROW */
       +{ "ubrcy;", 0x0045E }, /* CYRILLIC SMALL LETTER SHORT U */
       +{ "ubreve;", 0x0016D }, /* LATIN SMALL LETTER U WITH BREVE */
       +{ "ucirc;", 0x000FB }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
       +{ "ucy;", 0x00443 }, /* CYRILLIC SMALL LETTER U */
       +{ "udarr;", 0x021C5 }, /* UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW */
       +{ "udblac;", 0x00171 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */
       +{ "udhar;", 0x0296E }, /* UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT */
       +{ "ufisht;", 0x0297E }, /* UP FISH TAIL */
       +{ "ufr;", 0x1D532 }, /* MATHEMATICAL FRAKTUR SMALL U */
       +{ "ugrave;", 0x000F9 }, /* LATIN SMALL LETTER U WITH GRAVE */
       +{ "uharl;", 0x021BF }, /* UPWARDS HARPOON WITH BARB LEFTWARDS */
       +{ "uharr;", 0x021BE }, /* UPWARDS HARPOON WITH BARB RIGHTWARDS */
       +{ "uhblk;", 0x02580 }, /* UPPER HALF BLOCK */
       +{ "ulcorn;", 0x0231C }, /* TOP LEFT CORNER */
       +{ "ulcorner;", 0x0231C }, /* TOP LEFT CORNER */
       +{ "ulcrop;", 0x0230F }, /* TOP LEFT CROP */
       +{ "ultri;", 0x025F8 }, /* UPPER LEFT TRIANGLE */
       +{ "umacr;", 0x0016B }, /* LATIN SMALL LETTER U WITH MACRON */
       +{ "uml;", 0x000A8 }, /* DIAERESIS */
       +{ "uogon;", 0x00173 }, /* LATIN SMALL LETTER U WITH OGONEK */
       +{ "uopf;", 0x1D566 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL U */
       +{ "uparrow;", 0x02191 }, /* UPWARDS ARROW */
       +{ "updownarrow;", 0x02195 }, /* UP DOWN ARROW */
       +{ "upharpoonleft;", 0x021BF }, /* UPWARDS HARPOON WITH BARB LEFTWARDS */
       +{ "upharpoonright;", 0x021BE }, /* UPWARDS HARPOON WITH BARB RIGHTWARDS */
       +{ "uplus;", 0x0228E }, /* MULTISET UNION */
       +{ "upsi;", 0x003C5 }, /* GREEK SMALL LETTER UPSILON */
       +{ "upsih;", 0x003D2 }, /* GREEK UPSILON WITH HOOK SYMBOL */
       +{ "upsilon;", 0x003C5 }, /* GREEK SMALL LETTER UPSILON */
       +{ "upuparrows;", 0x021C8 }, /* UPWARDS PAIRED ARROWS */
       +{ "urcorn;", 0x0231D }, /* TOP RIGHT CORNER */
       +{ "urcorner;", 0x0231D }, /* TOP RIGHT CORNER */
       +{ "urcrop;", 0x0230E }, /* TOP RIGHT CROP */
       +{ "uring;", 0x0016F }, /* LATIN SMALL LETTER U WITH RING ABOVE */
       +{ "urtri;", 0x025F9 }, /* UPPER RIGHT TRIANGLE */
       +{ "uscr;", 0x1D4CA }, /* MATHEMATICAL SCRIPT SMALL U */
       +{ "utdot;", 0x022F0 }, /* UP RIGHT DIAGONAL ELLIPSIS */
       +{ "utilde;", 0x00169 }, /* LATIN SMALL LETTER U WITH TILDE */
       +{ "utri;", 0x025B5 }, /* WHITE UP-POINTING SMALL TRIANGLE */
       +{ "utrif;", 0x025B4 }, /* BLACK UP-POINTING SMALL TRIANGLE */
       +{ "uuarr;", 0x021C8 }, /* UPWARDS PAIRED ARROWS */
       +{ "uuml;", 0x000FC }, /* LATIN SMALL LETTER U WITH DIAERESIS */
       +{ "uwangle;", 0x029A7 }, /* OBLIQUE ANGLE OPENING DOWN */
       +{ "vArr;", 0x021D5 }, /* UP DOWN DOUBLE ARROW */
       +{ "vBar;", 0x02AE8 }, /* SHORT UP TACK WITH UNDERBAR */
       +{ "vBarv;", 0x02AE9 }, /* SHORT UP TACK ABOVE SHORT DOWN TACK */
       +{ "vDash;", 0x022A8 }, /* TRUE */
       +{ "vangrt;", 0x0299C }, /* RIGHT ANGLE VARIANT WITH SQUARE */
       +{ "varepsilon;", 0x003B5 }, /* GREEK SMALL LETTER EPSILON */
       +{ "varkappa;", 0x003F0 }, /* GREEK KAPPA SYMBOL */
       +{ "varnothing;", 0x02205 }, /* EMPTY SET */
       +{ "varphi;", 0x003C6 }, /* GREEK SMALL LETTER PHI */
       +{ "varpi;", 0x003D6 }, /* GREEK PI SYMBOL */
       +{ "varpropto;", 0x0221D }, /* PROPORTIONAL TO */
       +{ "varr;", 0x02195 }, /* UP DOWN ARROW */
       +{ "varrho;", 0x003F1 }, /* GREEK RHO SYMBOL */
       +{ "varsigma;", 0x003C2 }, /* GREEK SMALL LETTER FINAL SIGMA */
       +{ "vartheta;", 0x003D1 }, /* GREEK THETA SYMBOL */
       +{ "vartriangleleft;", 0x022B2 }, /* NORMAL SUBGROUP OF */
       +{ "vartriangleright;", 0x022B3 }, /* CONTAINS AS NORMAL SUBGROUP */
       +{ "vcy;", 0x00432 }, /* CYRILLIC SMALL LETTER VE */
       +{ "vdash;", 0x022A2 }, /* RIGHT TACK */
       +{ "vee;", 0x02228 }, /* LOGICAL OR */
       +{ "veebar;", 0x022BB }, /* XOR */
       +{ "veeeq;", 0x0225A }, /* EQUIANGULAR TO */
       +{ "vellip;", 0x022EE }, /* VERTICAL ELLIPSIS */
       +{ "verbar;", 0x0007C }, /* VERTICAL LINE */
       +{ "vert;", 0x0007C }, /* VERTICAL LINE */
       +{ "vfr;", 0x1D533 }, /* MATHEMATICAL FRAKTUR SMALL V */
       +{ "vltri;", 0x022B2 }, /* NORMAL SUBGROUP OF */
       +{ "vopf;", 0x1D567 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL V */
       +{ "vprop;", 0x0221D }, /* PROPORTIONAL TO */
       +{ "vrtri;", 0x022B3 }, /* CONTAINS AS NORMAL SUBGROUP */
       +{ "vscr;", 0x1D4CB }, /* MATHEMATICAL SCRIPT SMALL V */
       +{ "vzigzag;", 0x0299A }, /* VERTICAL ZIGZAG LINE */
       +{ "wcirc;", 0x00175 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */
       +{ "wedbar;", 0x02A5F }, /* LOGICAL AND WITH UNDERBAR */
       +{ "wedge;", 0x02227 }, /* LOGICAL AND */
       +{ "wedgeq;", 0x02259 }, /* ESTIMATES */
       +{ "weierp;", 0x02118 }, /* SCRIPT CAPITAL P */
       +{ "wfr;", 0x1D534 }, /* MATHEMATICAL FRAKTUR SMALL W */
       +{ "wopf;", 0x1D568 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL W */
       +{ "wp;", 0x02118 }, /* SCRIPT CAPITAL P */
       +{ "wr;", 0x02240 }, /* WREATH PRODUCT */
       +{ "wreath;", 0x02240 }, /* WREATH PRODUCT */
       +{ "wscr;", 0x1D4CC }, /* MATHEMATICAL SCRIPT SMALL W */
       +{ "xcap;", 0x022C2 }, /* N-ARY INTERSECTION */
       +{ "xcirc;", 0x025EF }, /* LARGE CIRCLE */
       +{ "xcup;", 0x022C3 }, /* N-ARY UNION */
       +{ "xdtri;", 0x025BD }, /* WHITE DOWN-POINTING TRIANGLE */
       +{ "xfr;", 0x1D535 }, /* MATHEMATICAL FRAKTUR SMALL X */
       +{ "xhArr;", 0x027FA }, /* LONG LEFT RIGHT DOUBLE ARROW */
       +{ "xharr;", 0x027F7 }, /* LONG LEFT RIGHT ARROW */
       +{ "xi;", 0x003BE }, /* GREEK SMALL LETTER XI */
       +{ "xlArr;", 0x027F8 }, /* LONG LEFTWARDS DOUBLE ARROW */
       +{ "xlarr;", 0x027F5 }, /* LONG LEFTWARDS ARROW */
       +{ "xmap;", 0x027FC }, /* LONG RIGHTWARDS ARROW FROM BAR */
       +{ "xnis;", 0x022FB }, /* CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE */
       +{ "xodot;", 0x02A00 }, /* N-ARY CIRCLED DOT OPERATOR */
       +{ "xopf;", 0x1D569 }, /* MATHEMATICAL DOUBLE-STRUCK SMALL X */
       +{ "xoplus;", 0x02A01 }, /* N-ARY CIRCLED PLUS OPERATOR */
       +{ "xotime;", 0x02A02 }, /* N-ARY CIRCLED TIMES OPERATOR */
       +{ "xrArr;", 0x027F9 }, /* LONG RIGHTWARDS DOUBLE ARROW */
       +{ "xrarr;", 0x027F6 }, /* LONG RIGHTWARDS ARROW */
       +{ "xscr;", 0x1D4CD }, /* MATHEMATICAL SCRIPT SMALL X */
       +{ "xsqcup;", 0x02A06 }, /* N-ARY SQUARE UNION OPERATOR */
       +{ "xuplus;", 0x02A04 }, /* N-ARY UNION OPERATOR WITH PLUS */
       +{ "xutri;", 0x025B3 }, /* WHITE UP-POINTING TRIANGLE */
       +{ "xvee;", 0x022C1 }, /* N-ARY LOGICAL OR */
       +{ "xwedge;", 0x022C0 }, /* N-ARY LOGICAL AND */
       +{ "yacute;", 0x000FD }, /* LATIN SMALL LETTER Y WITH ACUTE */
       +{ "yacy;", 0x0044F }, /* CYRILLIC SMALL LETTER YA */
       +{ "ycirc;", 0x00177 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */
       +{ "ycy;", 0x0044B }, /* CYRILLIC SMALL LETTER YERU */
       +{ "yen;", 0x000A5 }, /* YEN SIGN */
       +{ "yfr;", 0x1D536 }, /* MATHEMATICAL FRAKTUR SMALL Y */
       +{ "yicy;", 0x00457 }, /* CYRILLIC SMALL LETTER YI */
       +{ "yopf;", 0x1D56A }, /* MATHEMATICAL DOUBLE-STRUCK SMALL Y */
       +{ "yscr;", 0x1D4CE }, /* MATHEMATICAL SCRIPT SMALL Y */
       +{ "yucy;", 0x0044E }, /* CYRILLIC SMALL LETTER YU */
       +{ "yuml;", 0x000FF }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
       +{ "zacute;", 0x0017A }, /* LATIN SMALL LETTER Z WITH ACUTE */
       +{ "zcaron;", 0x0017E }, /* LATIN SMALL LETTER Z WITH CARON */
       +{ "zcy;", 0x00437 }, /* CYRILLIC SMALL LETTER ZE */
       +{ "zdot;", 0x0017C }, /* LATIN SMALL LETTER Z WITH DOT ABOVE */
       +{ "zeetrf;", 0x02128 }, /* BLACK-LETTER CAPITAL Z */
       +{ "zeta;", 0x003B6 }, /* GREEK SMALL LETTER ZETA */
       +{ "zfr;", 0x1D537 }, /* MATHEMATICAL FRAKTUR SMALL Z */
       +{ "zhcy;", 0x00436 }, /* CYRILLIC SMALL LETTER ZHE */
       +{ "zigrarr;", 0x021DD }, /* RIGHTWARDS SQUIGGLE ARROW */
       +{ "zopf;", 0x1D56B }, /* MATHEMATICAL DOUBLE-STRUCK SMALL Z */
       +{ "zscr;", 0x1D4CF }, /* MATHEMATICAL SCRIPT SMALL Z */
       +{ "zwj;", 0x0200D }, /* ZERO WIDTH JOINER */
       +{ "zwnj;", 0x0200C }, /* ZERO WIDTH NON-JOINER */
 (DIR) diff --git a/namedentities.h b/namedentities.h
       @@ -0,0 +1,62 @@
       +/* from https://dev.w3.org/html5/html-author/charref and
       +   https://www.w3.org/TR/html4/sgml/entities.html */
       +
       +{ "AMP;", 0x00026 }, /* AMPERSAND */
       +{ "COPY;", 0x000A9 }, /* COPYRIGHT SIGN */
       +{ "GT;", 0x0003E }, /* GREATER-THAN SIGN */
       +{ "LT;", 0x0003C }, /* LESS-THAN SIGN */
       +{ "QUOT;", 0x00022 }, /* QUOTATION MARK */
       +{ "REG;", 0x000AE }, /* REGISTERED SIGN */
       +{ "TRADE;", 0x02122 }, /* TRADE MARK SIGN */
       +{ "aacute;", 0x000E1 }, /* LATIN SMALL LETTER A WITH ACUTE */
       +{ "acute;", 0x000B4 }, /* ACUTE ACCENT */
       +{ "agrave;", 0x000E0 }, /* LATIN SMALL LETTER A WITH GRAVE */
       +{ "amp;", 0x00026 }, /* AMPERSAND */
       +{ "apos;", 0x00027 }, /* APOSTROPHE */
       +{ "bull;", 0x02022 }, /* BULLET */
       +{ "bullet;", 0x02022 }, /* BULLET */
       +{ "cent;", 0x000A2 }, /* CENT SIGN */
       +{ "copy;", 0x000A9 }, /* COPYRIGHT SIGN */
       +{ "dagger;", 0x02020 }, /* DAGGER */
       +{ "dash;", 0x02010 }, /* HYPHEN */
       +{ "deg;", 0x000B0 }, /* DEGREE SIGN */
       +{ "delta;", 0x003B4 }, /* GREEK SMALL LETTER DELTA */
       +{ "dollar;", 0x00024 }, /* DOLLAR SIGN */
       +{ "eacute;", 0x000E9 }, /* LATIN SMALL LETTER E WITH ACUTE */
       +{ "egrave;", 0x000E8 }, /* LATIN SMALL LETTER E WITH GRAVE */
       +{ "emsp;", 0x02003 }, /* EM SPACE */
       +{ "ensp;", 0x02002 }, /* EN SPACE */
       +{ "equals;", 0x0003D }, /* EQUALS SIGN */
       +{ "euml;", 0x000EB }, /* LATIN SMALL LETTER E WITH DIAERESIS */
       +{ "euro;", 0x020AC }, /* EURO SIGN */
       +{ "gbreve;", 0x0011F }, /* LATIN SMALL LETTER G WITH BREVE */
       +{ "grave;", 0x00060 }, /* GRAVE ACCENT */
       +{ "gt;", 0x0003E }, /* GREATER-THAN SIGN */
       +{ "hellip;", 0x02026 }, /* HORIZONTAL ELLIPSIS */
       +{ "hyphen;", 0x02010 }, /* HYPHEN */
       +{ "laquo;", 0x000AB }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
       +{ "ldquo;", 0x0201C }, /* LEFT DOUBLE QUOTATION MARK */
       +{ "lpar;", 0x00028 }, /* LEFT PARENTHESIS */
       +{ "lrm;", 0x0200E }, /* LEFT-TO-RIGHT MARK */
       +{ "lsquo;", 0x02018 }, /* LEFT SINGLE QUOTATION MARK */
       +{ "lt;", 0x0003C }, /* LESS-THAN SIGN */
       +{ "mdash;", 0x02014 }, /* EM DASH */
       +{ "micro;", 0x000B5 }, /* MICRO SIGN */
       +{ "middot;", 0x000B7 }, /* MIDDLE DOT */
       +{ "nbsp;", 0x000A0 }, /* NO-BREAK SPACE */
       +{ "ndash;", 0x02013 }, /* EN DASH */
       +{ "percnt;", 0x00025 }, /* PERCENT SIGN */
       +{ "pi;", 0x003C0 }, /* GREEK SMALL LETTER PI */
       +{ "pound;", 0x000A3 }, /* POUND SIGN */
       +{ "quot;", 0x00022 }, /* QUOTATION MARK */
       +{ "raquo;", 0x000BB }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
       +{ "rdquo;", 0x0201D }, /* RIGHT DOUBLE QUOTATION MARK */
       +{ "reg;", 0x000AE }, /* REGISTERED SIGN */
       +{ "rpar;", 0x00029 }, /* RIGHT PARENTHESIS */
       +{ "rsquo;", 0x02019 }, /* RIGHT SINGLE QUOTATION MARK */
       +{ "shy;", 0x000AD }, /* SOFT HYPHEN */
       +{ "sigma;", 0x003C3 }, /* GREEK SMALL LETTER SIGMA */
       +{ "thinsp;", 0x02009 }, /* THIN SPACE */
       +{ "times;", 0x000D7 }, /* MULTIPLICATION SIGN */
       +{ "trade;", 0x02122 }, /* TRADE MARK SIGN */
       +{ "yen;", 0x000A5 }, /* YEN SIGN */
 (DIR) diff --git a/strlcat.c b/strlcat.c
       @@ -0,0 +1,55 @@
       +/*        $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $        */
       +
       +/*
       + * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
       + *
       + * Permission to use, copy, modify, and distribute this software for any
       + * purpose with or without fee is hereby granted, provided that the above
       + * copyright notice and this permission notice appear in all copies.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       + */
       +
       +#include <sys/types.h>
       +#include <string.h>
       +
       +/*
       + * Appends src to string dst of size dsize (unlike strncat, dsize is the
       + * full size of dst, not space left).  At most dsize-1 characters
       + * will be copied.  Always NUL terminates (unless dsize <= strlen(dst)).
       + * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
       + * If retval >= dsize, truncation occurred.
       + */
       +size_t
       +strlcat(char *dst, const char *src, size_t dsize)
       +{
       +        const char *odst = dst;
       +        const char *osrc = src;
       +        size_t n = dsize;
       +        size_t dlen;
       +
       +        /* Find the end of dst and adjust bytes left but don't go past end. */
       +        while (n-- != 0 && *dst != '\0')
       +                dst++;
       +        dlen = dst - odst;
       +        n = dsize - dlen;
       +
       +        if (n-- == 0)
       +                return(dlen + strlen(src));
       +        while (*src != '\0') {
       +                if (n != 0) {
       +                        *dst++ = *src;
       +                        n--;
       +                }
       +                src++;
       +        }
       +        *dst = '\0';
       +
       +        return(dlen + (src - osrc));        /* count does not include NUL */
       +}
 (DIR) diff --git a/strlcpy.c b/strlcpy.c
       @@ -0,0 +1,50 @@
       +/*        $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $        */
       +
       +/*
       + * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
       + *
       + * Permission to use, copy, modify, and distribute this software for any
       + * purpose with or without fee is hereby granted, provided that the above
       + * copyright notice and this permission notice appear in all copies.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       + */
       +
       +#include <sys/types.h>
       +#include <string.h>
       +
       +/*
       + * Copy string src to buffer dst of size dsize.  At most dsize-1
       + * chars will be copied.  Always NUL terminates (unless dsize == 0).
       + * Returns strlen(src); if retval >= dsize, truncation occurred.
       + */
       +size_t
       +strlcpy(char *dst, const char *src, size_t dsize)
       +{
       +        const char *osrc = src;
       +        size_t nleft = dsize;
       +
       +        /* Copy as many bytes as will fit. */
       +        if (nleft != 0) {
       +                while (--nleft != 0) {
       +                        if ((*dst++ = *src++) == '\0')
       +                                break;
       +                }
       +        }
       +
       +        /* Not enough room in dst, add NUL and traverse rest of src. */
       +        if (nleft == 0) {
       +                if (dsize != 0)
       +                        *dst = '\0';                /* NUL-terminate dst */
       +                while (*src++)
       +                        ;
       +        }
       +
       +        return(src - osrc - 1);        /* count does not include NUL */
       +}
 (DIR) diff --git a/webdump.1 b/webdump.1
       @@ -0,0 +1,66 @@
       +.Dd September 7, 2023
       +.Dt WEBDUMP 1
       +.Os
       +.Sh NAME
       +.Nm webdump
       +.Nd convert HTML to plain-text
       +.Sh SYNOPSIS
       +.Nm
       +.Op Fl 8ailrx
       +.Op Fl b Ar baseurl
       +.Op Fl s Ar selector
       +.Op Fl u Ar selector
       +.Op Fl w Ar termwidth
       +.Sh DESCRIPTION
       +.Nm
       +reads UTF-8 HTML data from stdin.
       +It converts and writes the output as plain-text to stdout.
       +A
       +.Ar baseurl
       +can be specified if the links in the feed are relative URLs.
       +.Bl -tag -width Ds
       +.It Fl 8
       +Use UTF-8 symbols for certain items like bullet items and rulers to make the
       +output fancier.
       +.It Fl a
       +Toggle ANSI escape codes usage, by default it is not enabled.
       +.It Fl b Ar baseurl
       +Base URL of links.
       +This is used to make links absolute.
       +.It Fl i
       +Toggle if link reference numbers are displayed inline or not, by default it is
       +not enabled.
       +.It Fl l
       +Toggle if link references are displayed at the bottom or not, by default it is
       +not enabled.
       +.It Fl r
       +Toggle if line-wrapping mode is enabled, by default it is not enabled.
       +.It Fl s
       +CSS-like selectors, this sets a reader mode to hide content
       +matching the selector, for example: "main" or "main#id" or "main.class".
       +Multiple selectors can be specified by separating them with a comma.
       +.It Fl u
       +CSS-like selectors, this sets a reader mode to hide content
       +matching the selector, for example: "main" or "main#id" or "main.class".
       +Multiple selectors can be specified by separating them with a comma.
       +.It Fl w Ar termwidth
       +The terminal width.
       +The default is 77 characters.
       +.It Fl x
       +Write resources as TAB-separated lines to file descriptor 3.
       +.El
       +.Sh EXIT STATUS
       +.Ex -std
       +.Sh EXAMPLES
       +.Bd -literal
       +curl -s 'https://codemadness.org/' | \\
       +        webdump -b 'https://codemadness.org' -l -r | \\
       +        less
       +.Ed
       +.Sh SEE ALSO
       +.Xr curl 1 ,
       +.Xr xmllint 1 ,
       +.Xr xmlstarlet 1 ,
       +.Xr ftp 1
       +.Sh AUTHORS
       +.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org
 (DIR) diff --git a/webdump.c b/webdump.c
       @@ -0,0 +1,2072 @@
       +#include <errno.h>
       +#include <limits.h>
       +#include <stdio.h>
       +#include <stdarg.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <strings.h>
       +#include <unistd.h>
       +
       +#include "arg.h"
       +char *argv0;
       +
       +#include "xml.h"
       +
       +static XMLParser parser;
       +
       +#ifndef __OpenBSD__
       +#define pledge(p1,p2) 0
       +#endif
       +
       +#undef strlcat
       +size_t strlcat(char *, const char *, size_t);
       +#undef strlcpy
       +size_t strlcpy(char *, const char *, size_t);
       +
       +/* ctype-like macros, but always compatible with ASCII / UTF-8 */
       +#define ISALPHA(c) ((((unsigned)c) | 32) - 'a' < 26)
       +#define ISCNTRL(c) ((c) < ' ' || (c) == 0x7f)
       +#define ISDIGIT(c) (((unsigned)c) - '0' < 10)
       +#define ISSPACE(c) ((c) == ' ' || ((((unsigned)c) - '\t') < 5))
       +#define TOLOWER(c) ((((unsigned)c) - 'A' < 26) ? ((c) | 32) : (c))
       +
       +#define LEN(x) (sizeof(x) / sizeof(x[0]))
       +
       +/* URI */
       +struct uri {
       +        char proto[48];     /* scheme including ":" or "://" */
       +        char userinfo[256]; /* username [:password] */
       +        char host[256];
       +        char port[6];       /* numeric port */
       +        char path[1024];
       +        char query[1024];
       +        char fragment[1024];
       +};
       +
       +/* options */
       +static int allowansi     = 0;  /* allow ANSI escape codes */
       +static int showrefbottom = 0;  /* show link references at the bottom */
       +static int showrefinline = 0;  /* show link reference number inline */
       +static int linewrap      = 0;  /* line-wrapping */
       +static int termwidth     = 77; /* terminal width */
       +static int resources     = 0;  /* write resources line-by-line to fd 3? */
       +
       +/* linked-list of link references */
       +struct linkref {
       +        char *type;
       +        char *url;
       +        int ishidden;
       +        struct linkref *next;
       +};
       +
       +static struct linkref *links_head;
       +static struct linkref *links_cur;
       +static int linkcount; /* visible link count */
       +
       +enum DisplayType {
       +        DisplayUnknown     = 0,
       +        DisplayInline      = 1 << 0,
       +        DisplayInlineBlock = 1 << 1, /* unused for now */
       +        DisplayBlock       = 1 << 2,
       +        DisplayNone        = 1 << 3,
       +        DisplayPre         = 1 << 4,
       +        DisplayList        = 1 << 5,
       +        DisplayListOrdered = 1 << 6,
       +        DisplayListItem    = 1 << 7,
       +        DisplayTable       = 1 << 8,
       +        DisplayTableRow    = 1 << 9,
       +        DisplayTableCell   = 1 << 10,
       +        DisplayHeader      = 1 << 11
       +};
       +
       +/* ANSI markup */
       +enum MarkupType {
       +        MarkupNone        = 0,
       +        MarkupBold        = 1 << 0,
       +        MarkupItalic      = 1 << 1,
       +        MarkupUnderline   = 1 << 2,
       +        MarkupBlink       = 1 << 3, /* lol */
       +        MarkupReverse     = 1 << 4,
       +        MarkupStrike      = 1 << 5
       +};
       +
       +/* String data / memory pool */
       +typedef struct string {
       +        char   *data;   /* data */
       +        size_t  len;    /* string length */
       +        size_t  bufsiz; /* allocated size */
       +} String;
       +
       +struct tag {
       +        const char *name;
       +        enum DisplayType displaytype;
       +        enum MarkupType markuptype; /* ANSI markup */
       +        enum DisplayType parenttype; /* display type belonging to element */
       +        int isvoid; /* "void" element */
       +        int isoptional; /* optional to close tag */
       +        int margintop; /* newlines when the tag starts */
       +        int marginbottom; /* newlines after the tag ends */
       +        int indent; /* indent in cells */
       +};
       +
       +struct node {
       +        char tagname[256];
       +        struct tag tag;
       +        size_t nchildren; /* child node count */
       +        size_t visnchildren; /* child node count which are visible */
       +        /* attributes */
       +        char id[256];
       +        char classnames[1024];
       +        int indent; /* indent per node, for formatting */
       +        int hasdata; /* tag contains some data, for formatting */
       +};
       +
       +struct selectornode {
       +        char tagname[256];
       +        /* attributes */
       +        char id[256];
       +        char classnames[1024];
       +};
       +
       +struct selector {
       +        const char *text;
       +        struct selectornode nodes[32];
       +        int depth;
       +};
       +
       +/* list of selectors */
       +struct selectors {
       +        struct selector **selectors;
       +        size_t count;
       +};
       +
       +static const char *str_bullet_item = "* ";
       +static const char *str_ruler = "-";
       +
       +/* base href, to make URLs absolute */
       +static char *basehref = "";
       +static char basehrefdoc[4096]; /* base href in document, if any */
       +
       +/* buffers for some attributes of the current tag */
       +String attr_alt; /* alt attribute */
       +String attr_class; /* class attribute */
       +String attr_href; /* href attribute */
       +String attr_id; /* id attribute */
       +String attr_src; /* src attribute */
       +String attr_type; /* type attribute */
       +String attr_value; /* value attribute */
       +
       +static String htmldata;
       +
       +/* for white-space output handling:
       +   1 = whitespace emitted (suppress repeated), 2 = other characters on this line
       +   Behaviour:
       +   * White-space data before non-whitespace data in tags are ignored on a line.
       +   * Repeated white-space are ignored: a single space (' ') is emitted.
       +*/
       +static int whitespace_mode = 0;
       +static int nbytesline = 0;
       +static int ncells = 0; /* current cell count */
       +static int hadnewline = 0; /* count for repeated newlines */
       +/* flag for skipping initial white-space in tag: for HTML white-space handling */
       +static int skipinitialws = 1;
       +static const int defaultindent = 2;
       +static int indent;
       +/* previous output sequential newlines, used for calculating margins between
       +   elements and reducing excessive newlines */
       +static int currentnewlines;
       +
       +/* buffers for line-wrapping (buffer per word boundary) */
       +static char rbuf[1024];
       +static int rbuflen;
       +static int rnbufcells = 0; /* pending cell count to add */
       +
       +#define MAX_DEPTH 256
       +static struct node nodes[MAX_DEPTH];
       +static String nodes_links[MAX_DEPTH]; /* keep track of links per node */
       +static int curnode;
       +
       +/* reader / selector mode */
       +static int reader_mode = 0;
       +static int reader_ignore = 0;
       +
       +static enum MarkupType curmarkup;
       +
       +/* selector to match */
       +static struct selectors *sel_hide, *sel_show;
       +
       +/* tag          displaytype                       markup           parent           v  o  b  a  i */
       +static struct tag tags[] = {
       +{ "a",          DisplayInline,                    MarkupUnderline, 0,               0, 0, 0, 0, 0 },
       +{ "area",       DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "article",    DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "audio",      DisplayInline,                    MarkupUnderline, 0,               0, 0, 0, 0, 0 },
       +{ "b",          DisplayInline,                    MarkupBold,      0,               0, 0, 0, 0, 0 },
       +{ "base",       DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "blink",      DisplayInline,                    MarkupBlink,     0,               0, 0, 0, 0, 0 },
       +{ "blockquote", DisplayBlock,                     0,               0,               0, 0, 0, 0, 2 },
       +{ "body",       DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "br",         0,                                0,               0,               1, 0, 0, 0, 0 },
       +{ "code",       DisplayInline,                    0,               0,               0, 0, 0, 0, 0 },
       +{ "col",        DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "colgroup",   DisplayInline,                    0,               0,               0, 1, 0, 0, 0 },
       +{ "dd",         DisplayBlock,                     0,               0,               0, 1, 0, 0, 4 },
       +{ "del",        DisplayInline,                    MarkupStrike,    0,               0, 0, 0, 0, 0 },
       +{ "div",        DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "dl",         DisplayInline,                    0,               0,               0, 0, 0, 0, 0 },
       +{ "dt",         DisplayBlock,                     MarkupBold,      0,               0, 1, 0, 0, 0 },
       +{ "em",         DisplayInline,                    MarkupItalic,    0,               0, 0, 0, 0, 0 },
       +{ "embed",      DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "footer",     DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "h1",         DisplayHeader,                    MarkupBold,      0,               0, 0, 1, 1, -defaultindent },
       +{ "h2",         DisplayHeader,                    MarkupBold,      0,               0, 0, 1, 1, -defaultindent },
       +{ "h3",         DisplayHeader,                    MarkupBold,      0,               0, 0, 1, 1, -defaultindent },
       +{ "h4",         DisplayHeader,                    MarkupBold,      0,               0, 0, 1, 1, -defaultindent },
       +{ "h5",         DisplayHeader,                    MarkupBold,      0,               0, 0, 1, 1, -defaultindent },
       +{ "h6",         DisplayHeader,                    MarkupBold,      0,               0, 0, 1, 1, -defaultindent },
       +{ "head",       DisplayBlock,                     0,               0,               0, 1, 0, 0, 0 },
       +{ "header",     DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "hr",         DisplayBlock,                     0,               0,               1, 0, 0, 0, 0 },
       +{ "html",       DisplayBlock,                     0,               0,               0, 1, 0, 0, 0 },
       +{ "i",          DisplayInline,                    MarkupItalic,    0,               0, 0, 0, 0, 0 },
       +{ "img",        DisplayInline,                    MarkupUnderline, 0,               1, 0, 0, 0, 0 },
       +{ "input",      DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "label",      DisplayInline,                    MarkupBold,      0,               0, 0, 0, 0, 0 },
       +{ "li",         DisplayListItem,                  0,               DisplayList,     0, 1, 0, 0, 0 },
       +{ "link",       DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "main",       DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "meta",       DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "nav",        DisplayBlock,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "ol",         DisplayList | DisplayListOrdered, 0,               0,               0, 0, 1, 1, 0 },
       +{ "option",     DisplayNone,                      0,               0,               0, 1, 0, 0, 0 }, /* prevent clutter and hide all options for now */
       +{ "p",          DisplayBlock,                     0,               0,               0, 1, 1, 1, 0 },
       +{ "param",      DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "pre",        DisplayPre,                       0,               0,               0, 0, 1, 1, 4 },
       +{ "s",          DisplayInline,                    MarkupStrike,    0,               0, 0, 0, 0, 0 },
       +{ "script",     DisplayNone,                      0,               0,               0, 0, 0, 0, 0 },
       +{ "source",     DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "strike",     DisplayInline,                    MarkupStrike,    0,               0, 0, 0, 0, 0 },
       +{ "strong",     DisplayInline,                    MarkupBold,      0,               0, 0, 0, 0, 0 },
       +{ "style",      DisplayNone,                      0,               0,               0, 0, 0, 0, 0 },
       +{ "table",      DisplayTable,                     0,               0,               0, 0, 0, 0, 0 },
       +{ "tbody",      DisplayInline,                    0,               DisplayTable,    0, 1, 0, 0, 0 },
       +{ "td",         DisplayTableCell,                 0,               DisplayTableRow, 0, 1, 0, 0, 0 },
       +{ "template",   DisplayNone,                      0,               0,               0, 0, 0, 0, 0 },
       +{ "textarea",   DisplayInline,                    0,               0,               0, 0, 0, 0, 0 },
       +{ "tfoot",      DisplayInline,                    0,               DisplayTable,    0, 1, 0, 0, 0 },
       +{ "th",         DisplayTableCell,                 MarkupBold,      DisplayTableRow, 0, 1, 0, 0, 0 },
       +{ "thead",      DisplayInline,                    0,               DisplayTable,    0, 1, 0, 0, 0 },
       +{ "time",       DisplayInline,                    0,               0,               0, 0, 0, 0, 0 },
       +{ "title",      DisplayBlock,                     0,               0,               0, 0, 0, 1, -defaultindent },
       +{ "tr",         DisplayTableRow,                  0,               DisplayTable,    0, 1, 0, 0, 0 },
       +{ "track",      DisplayInline,                    0,               0,               1, 0, 0, 0, 0 },
       +{ "u",          DisplayInline,                    MarkupUnderline, 0,               0, 0, 0, 0, 0 },
       +{ "ul",         DisplayList,                      0,               0,               0, 0, 1, 1, 2 },
       +{ "video",      DisplayInline,                    MarkupUnderline, 0,               0, 0, 0, 0, 0 },
       +{ "wbr",        DisplayInline,                    0,               0,               1, 0, 0, 0, 0 }
       +};
       +
       +/* hint for compilers and static analyzers that a function exits */
       +#ifndef __dead
       +#define __dead
       +#endif
       +
       +/* print to stderr, print error message of errno and exit(). */
       +__dead void
       +err(int exitstatus, const char *fmt, ...)
       +{
       +        va_list ap;
       +        int saved_errno;
       +
       +        saved_errno = errno;
       +
       +        fputs("webdump: ", stderr);
       +        if (fmt) {
       +                va_start(ap, fmt);
       +                vfprintf(stderr, fmt, ap);
       +                va_end(ap);
       +                fputs(": ", stderr);
       +        }
       +        fprintf(stderr, "%s\n", strerror(saved_errno));
       +
       +        exit(exitstatus);
       +}
       +
       +/* print to stderr and exit(). */
       +__dead void
       +errx(int exitstatus, const char *fmt, ...)
       +{
       +        va_list ap;
       +
       +        fputs("webdump: ", stderr);
       +        if (fmt) {
       +                va_start(ap, fmt);
       +                vfprintf(stderr, fmt, ap);
       +                va_end(ap);
       +        }
       +        fputs("\n", stderr);
       +
       +        exit(exitstatus);
       +}
       +
       +static const char *ignorestate, *endtag;
       +static int (*getnext)(void);
       +
       +/* return a space for all data until some case-insensitive string occurs. This
       +   is used to parse incorrect HTML/XML that contains unescaped HTML in script
       +   or style tags. If you see some </script> tag in a CDATA or comment
       +   section then e-mail W3C and tell them the web is too complex. */
       +static inline int
       +getnext_ignore(void)
       +{
       +        int c;
       +
       +        if ((c = getnext()) == EOF)
       +                return EOF;
       +
       +        if (TOLOWER((unsigned char)c) == TOLOWER((unsigned char)*ignorestate)) {
       +                ignorestate++;
       +                if (*ignorestate == '\0') {
       +                        parser.getnext = getnext; /* restore */
       +                        return ' ';
       +                }
       +        } else {
       +                ignorestate = endtag; /* no full match: reset to beginning */
       +        }
       +
       +        return ' '; /* pretend there is just SPACEs */
       +}
       +
       +/* Clear string only; don't free, prevents unnecessary reallocation. */
       +static void
       +string_clear(String *s)
       +{
       +        if (s->data)
       +                s->data[0] = '\0';
       +        s->len = 0;
       +}
       +
       +static void
       +string_buffer_realloc(String *s, size_t newlen)
       +{
       +        size_t alloclen;
       +
       +        for (alloclen = 64; alloclen <= newlen; alloclen *= 2)
       +                ;
       +        if (!(s->data = realloc(s->data, alloclen)))
       +                err(1, "realloc");
       +        s->bufsiz = alloclen;
       +}
       +
       +static void
       +string_append(String *s, const char *data, size_t len)
       +{
       +        if (!len)
       +                return;
       +        /* check if allocation is necesary, don't shrink buffer,
       +         * should be more than bufsiz ofcourse. */
       +        if (s->len + len >= s->bufsiz)
       +                string_buffer_realloc(s, s->len + len + 1);
       +        memcpy(s->data + s->len, data, len);
       +        s->len += len;
       +        s->data[s->len] = '\0';
       +}
       +
       +char *
       +estrdup(const char *s)
       +{
       +        char *p;
       +
       +        if (!(p = strdup(s)))
       +                err(1, "strdup");
       +        return p;
       +}
       +
       +char *
       +estrndup(const char *s, size_t n)
       +{
       +        char *p;
       +
       +        if (!(p = strndup(s, n)))
       +                err(1, "strndup");
       +        return p;
       +}
       +
       +void *
       +erealloc(void *p, size_t siz)
       +{
       +        if (!(p = realloc(p, siz)))
       +                err(1, "realloc");
       +
       +        return p;
       +}
       +
       +void *
       +ecalloc(size_t nmemb, size_t size)
       +{
       +        void *p;
       +
       +        if (!(p = calloc(nmemb, size)))
       +                err(1, "calloc");
       +        return p;
       +}
       +
       +/* check if string has a non-empty scheme / protocol part */
       +int
       +uri_hasscheme(const char *s)
       +{
       +        const char *p = s;
       +
       +        for (; ISALPHA((unsigned char)*p) || ISDIGIT((unsigned char)*p) ||
       +                       *p == '+' || *p == '-' || *p == '.'; p++)
       +                ;
       +        /* scheme, except if empty and starts with ":" then it is a path */
       +        return (*p == ':' && p != s);
       +}
       +
       +int
       +uri_parse(const char *s, struct uri *u)
       +{
       +        const char *p = s;
       +        char *endptr;
       +        size_t i;
       +        long l;
       +
       +        u->proto[0] = u->userinfo[0] = u->host[0] = u->port[0] = '\0';
       +        u->path[0] = u->query[0] = u->fragment[0] = '\0';
       +
       +        /* protocol-relative */
       +        if (*p == '/' && *(p + 1) == '/') {
       +                p += 2; /* skip "//" */
       +                goto parseauth;
       +        }
       +
       +        /* scheme / protocol part */
       +        for (; ISALPHA((unsigned char)*p) || ISDIGIT((unsigned char)*p) ||
       +                       *p == '+' || *p == '-' || *p == '.'; p++)
       +                ;
       +        /* scheme, except if empty and starts with ":" then it is a path */
       +        if (*p == ':' && p != s) {
       +                if (*(p + 1) == '/' && *(p + 2) == '/')
       +                        p += 3; /* skip "://" */
       +                else
       +                        p++; /* skip ":" */
       +
       +                if ((size_t)(p - s) >= sizeof(u->proto))
       +                        return -1; /* protocol too long */
       +                memcpy(u->proto, s, p - s);
       +                u->proto[p - s] = '\0';
       +
       +                if (*(p - 1) != '/')
       +                        goto parsepath;
       +        } else {
       +                p = s; /* no scheme format, reset to start */
       +                goto parsepath;
       +        }
       +
       +parseauth:
       +        /* userinfo (username:password) */
       +        i = strcspn(p, "@/?#");
       +        if (p[i] == '@') {
       +                if (i >= sizeof(u->userinfo))
       +                        return -1; /* userinfo too long */
       +                memcpy(u->userinfo, p, i);
       +                u->userinfo[i] = '\0';
       +                p += i + 1;
       +        }
       +
       +        /* IPv6 address */
       +        if (*p == '[') {
       +                /* bracket not found, host too short or too long */
       +                i = strcspn(p, "]");
       +                if (p[i] != ']' || i < 3)
       +                        return -1;
       +                i++; /* including "]" */
       +        } else {
       +                /* domain / host part, skip until port, path or end. */
       +                i = strcspn(p, ":/?#");
       +        }
       +        if (i >= sizeof(u->host))
       +                return -1; /* host too long */
       +        memcpy(u->host, p, i);
       +        u->host[i] = '\0';
       +        p += i;
       +
       +        /* port */
       +        if (*p == ':') {
       +                p++;
       +                if ((i = strcspn(p, "/?#")) >= sizeof(u->port))
       +                        return -1; /* port too long */
       +                memcpy(u->port, p, i);
       +                u->port[i] = '\0';
       +                /* check for valid port: range 1 - 65535, may be empty */
       +                errno = 0;
       +                l = strtol(u->port, &endptr, 10);
       +                if (i && (errno || *endptr || l <= 0 || l > 65535))
       +                        return -1;
       +                p += i;
       +        }
       +
       +parsepath:
       +        /* path */
       +        if ((i = strcspn(p, "?#")) >= sizeof(u->path))
       +                return -1; /* path too long */
       +        memcpy(u->path, p, i);
       +        u->path[i] = '\0';
       +        p += i;
       +
       +        /* query */
       +        if (*p == '?') {
       +                p++;
       +                if ((i = strcspn(p, "#")) >= sizeof(u->query))
       +                        return -1; /* query too long */
       +                memcpy(u->query, p, i);
       +                u->query[i] = '\0';
       +                p += i;
       +        }
       +
       +        /* fragment */
       +        if (*p == '#') {
       +                p++;
       +                if ((i = strlen(p)) >= sizeof(u->fragment))
       +                        return -1; /* fragment too long */
       +                memcpy(u->fragment, p, i);
       +                u->fragment[i] = '\0';
       +        }
       +
       +        return 0;
       +}
       +
       +/* Transform and try to make the URI `u` absolute using base URI `b` into `a`.
       +   Follows some of the logic from "RFC 3986 - 5.2.2. Transform References".
       +   Returns 0 on success, -1 on error or truncation. */
       +int
       +uri_makeabs(struct uri *a, struct uri *u, struct uri *b)
       +{
       +        char *p;
       +        int c;
       +
       +        strlcpy(a->fragment, u->fragment, sizeof(a->fragment));
       +
       +        if (u->proto[0] || u->host[0]) {
       +                strlcpy(a->proto, u->proto[0] ? u->proto : b->proto, sizeof(a->proto));
       +                strlcpy(a->host, u->host, sizeof(a->host));
       +                strlcpy(a->userinfo, u->userinfo, sizeof(a->userinfo));
       +                strlcpy(a->host, u->host, sizeof(a->host));
       +                strlcpy(a->port, u->port, sizeof(a->port));
       +                strlcpy(a->path, u->path, sizeof(a->path));
       +                strlcpy(a->query, u->query, sizeof(a->query));
       +                return 0;
       +        }
       +
       +        strlcpy(a->proto, b->proto, sizeof(a->proto));
       +        strlcpy(a->host, b->host, sizeof(a->host));
       +        strlcpy(a->userinfo, b->userinfo, sizeof(a->userinfo));
       +        strlcpy(a->host, b->host, sizeof(a->host));
       +        strlcpy(a->port, b->port, sizeof(a->port));
       +
       +        if (!u->path[0]) {
       +                strlcpy(a->path, b->path, sizeof(a->path));
       +        } else if (u->path[0] == '/') {
       +                strlcpy(a->path, u->path, sizeof(a->path));
       +        } else {
       +                a->path[0] = (b->host[0] && b->path[0] != '/') ? '/' : '\0';
       +                a->path[1] = '\0';
       +
       +                if ((p = strrchr(b->path, '/'))) {
       +                        c = *(++p);
       +                        *p = '\0'; /* temporary NUL-terminate */
       +                        if (strlcat(a->path, b->path, sizeof(a->path)) >= sizeof(a->path))
       +                                return -1;
       +                        *p = c; /* restore */
       +                }
       +                if (strlcat(a->path, u->path, sizeof(a->path)) >= sizeof(a->path))
       +                        return -1;
       +        }
       +
       +        if (u->path[0] || u->query[0])
       +                strlcpy(a->query, u->query, sizeof(a->query));
       +        else
       +                strlcpy(a->query, b->query, sizeof(a->query));
       +
       +        return 0;
       +}
       +
       +int
       +uri_format(char *buf, size_t bufsiz, struct uri *u)
       +{
       +        return snprintf(buf, bufsiz, "%s%s%s%s%s%s%s%s%s%s%s%s",
       +                u->proto,
       +                u->userinfo[0] ? u->userinfo : "",
       +                u->userinfo[0] ? "@" : "",
       +                u->host,
       +                u->port[0] ? ":" : "",
       +                u->port,
       +                u->host[0] && u->path[0] && u->path[0] != '/' ? "/" : "",
       +                u->path,
       +                u->query[0] ? "?" : "",
       +                u->query,
       +                u->fragment[0] ? "#" : "",
       +                u->fragment);
       +}
       +
       +static void
       +rindent(void)
       +{
       +        int i;
       +
       +        for (i = 0; i < indent + defaultindent; i++) {
       +                putchar(' ');
       +                nbytesline++;
       +                ncells++;
       +        }
       +}
       +
       +static void
       +emitmarkup(int markuptype)
       +{
       +        if (!allowansi)
       +                return;
       +
       +        if (!markuptype)
       +                fputs("\033[0m", stdout); /* reset all attributes */
       +
       +        /* set */
       +        if (markuptype & MarkupBold)
       +                fputs("\033[1m", stdout);
       +        if (markuptype & MarkupItalic)
       +                fputs("\033[3m", stdout);
       +        if (markuptype & MarkupUnderline)
       +                fputs("\033[4m", stdout);
       +        if (markuptype & MarkupBlink)
       +                fputs("\033[5m", stdout);
       +        if (markuptype & MarkupReverse)
       +                fputs("\033[7m", stdout);
       +        if (markuptype & MarkupStrike)
       +                fputs("\033[9m", stdout);
       +}
       +
       +/* flush remaining buffer (containing a word): used for word-wrap handling */
       +static void
       +hflush(void)
       +{
       +        int i;
       +
       +        if (!rbuflen)
       +                return;
       +
       +        if (!nbytesline) {
       +                emitmarkup(0);
       +                rindent();
       +                /* emit code again per line, needed for GNU/less -R */
       +                emitmarkup(curmarkup);
       +        }
       +
       +        for (i = 0; i < rbuflen; i++)
       +                putchar(rbuf[i]);
       +
       +        nbytesline += rbuflen;
       +        ncells += rnbufcells;
       +        rbuflen = 0;
       +        rnbufcells = 0;
       +}
       +
       +static void
       +printansi(const char *s)
       +{
       +        size_t len;
       +
       +        if (!allowansi)
       +                return;
       +
       +        if (linewrap) {
       +                len = strlen(s);
       +                if (rbuflen + len + 1 >= sizeof(rbuf))
       +                        hflush();
       +                if (rbuflen + len + 1 < sizeof(rbuf)) {
       +                        memcpy(rbuf + rbuflen, s, len);
       +                        rbuflen += len;
       +                }
       +        } else {
       +                fputs(s, stdout);
       +        }
       +}
       +
       +static void
       +setmarkup(int markuptype)
       +{
       +        if (!allowansi)
       +                return;
       +
       +        /* need change? */
       +        if (curmarkup == markuptype)
       +                return;
       +
       +        if (!markuptype) {
       +                printansi("\033[0m"); /* reset all attributes */
       +                curmarkup = markuptype;
       +                return;
       +        }
       +
       +        /* set */
       +        if (!(curmarkup & MarkupBold) && (markuptype & MarkupBold))
       +                printansi("\033[1m");
       +        if (!(curmarkup & MarkupItalic) && (markuptype & MarkupItalic))
       +                printansi("\033[3m");
       +        if (!(curmarkup & MarkupUnderline) && (markuptype & MarkupUnderline))
       +                printansi("\033[4m");
       +        if (!(curmarkup & MarkupBlink) && (markuptype & MarkupBlink))
       +                printansi("\033[5m");
       +        if (!(curmarkup & MarkupReverse) && (markuptype & MarkupReverse))
       +                printansi("\033[7m");
       +        if (!(curmarkup & MarkupStrike) && (markuptype & MarkupStrike))
       +                printansi("\033[9m");
       +
       +        /* unset */
       +        if ((curmarkup & MarkupBold) && !(markuptype & MarkupBold))
       +                printansi("\033[22m"); /* reset bold or faint */
       +        if ((curmarkup & MarkupItalic) && !(markuptype & MarkupItalic))
       +                printansi("\033[23m"); /* reset italic */
       +        if ((curmarkup & MarkupUnderline) && !(markuptype & MarkupUnderline))
       +                printansi("\033[24m"); /* reset underline */
       +        if ((curmarkup & MarkupBlink) && !(markuptype & MarkupBlink))
       +                printansi("\033[25m"); /* reset blink */
       +        if ((curmarkup & MarkupReverse) && !(markuptype & MarkupReverse))
       +                printansi("\033[27m"); /* reset reverse */
       +        if ((curmarkup & MarkupStrike) && !(markuptype & MarkupStrike))
       +                printansi("\033[29m"); /* reset strike */
       +
       +        curmarkup = markuptype;
       +}
       +
       +static void
       +startmarkup(int markuptype)
       +{
       +        setmarkup(curmarkup | markuptype);
       +}
       +
       +static void
       +endmarkup(int markuptype)
       +{
       +        setmarkup(curmarkup & ~markuptype);
       +}
       +
       +/* rough cell width of a unicode codepoint by counting a unicode codepoint as 1
       +   cell in general.
       +   NOTE: this is of course incorrect since characters can be 2 width aswell,
       +   in the future maybe replace this with wcwidth() or similar */
       +int
       +utfwidth(int c)
       +{
       +        /* not the start of a codepoint */
       +        if ((c & 0xc0) == 0x80)
       +                return 0;
       +        /* count TAB as 8 */
       +        if (c == '\t')
       +                return 8;
       +        return 1;
       +}
       +
       +/* write a character, handling state of repeated newlines, some HTML
       +   white-space rules, indentation and word-wrapping */
       +static void
       +hputchar(int c)
       +{
       +        struct node *cur = &nodes[curnode];
       +        cur->hasdata = 1;
       +
       +        if (c == '\n') {
       +                if (nbytesline <= 0)
       +                        hadnewline = 0;
       +
       +                /* start a new line, no chars on this line yet */
       +                whitespace_mode &= ~2; /* no chars on this line yet */
       +                nbytesline = 0;
       +                ncells = 0;
       +
       +                if (hadnewline)
       +                        currentnewlines++; /* repeating newlines */
       +                hadnewline = 1;
       +        } else {
       +                hadnewline = 0;
       +                currentnewlines = 0;
       +        }
       +
       +        /* skip initial/leading white-space */
       +        if (ISSPACE((unsigned char)c)) {
       +                if (skipinitialws)
       +                        return;
       +        } else {
       +                skipinitialws = 0;
       +        }
       +
       +        if (!(c == '\n' || c == '\t' || !ISCNTRL((unsigned char)c)))
       +                return;
       +
       +        if (!linewrap) {
       +                if (c == '\n') {
       +                        putchar('\n');
       +                        nbytesline = 0;
       +                        ncells = 0;
       +                } else {
       +                        if (!nbytesline) {
       +                                emitmarkup(0);
       +                                rindent();
       +                                /* emit code again per line, needed for GNU/less -R */
       +                                emitmarkup(curmarkup);
       +                        }
       +                        putchar(c);
       +                        nbytesline++;
       +                        ncells += utfwidth(c);
       +                }
       +                return;
       +        }
       +
       +        /* really too long: the whole word doesn't even fit, flush it */
       +        if (ncells + rnbufcells >= termwidth || rbuflen >= sizeof(rbuf) - 1) {
       +                putchar('\n');
       +                nbytesline = 0;
       +                ncells = 0;
       +                hflush();
       +        }
       +
       +        if (c == '\n') {
       +                putchar('\n');
       +                hflush();
       +                return;
       +        } else if (ISSPACE((unsigned char)c) || c == '-') {
       +                if (ncells + rnbufcells >= termwidth) {
       +                        putchar('\n');
       +                        nbytesline = 0;
       +                        ncells = 0;
       +                }
       +                rbuf[rbuflen++] = c;
       +                rnbufcells += utfwidth(c);
       +                hflush();
       +                return;
       +        }
       +
       +        rbuf[rbuflen++] = c;
       +        rnbufcells += utfwidth(c);
       +}
       +
       +/* calculate indentation of current node depth, using the sum of each
       +   indentation per node */
       +static int
       +calcindent(void)
       +{
       +        int i, n = 0;
       +
       +        for (i = curnode; i >= 0; i--)
       +                n += nodes[i].indent;
       +
       +        return n;
       +}
       +
       +static void
       +hprint(const char *s)
       +{
       +        for (; *s; ++s)
       +                hputchar(*s);
       +}
       +
       +/* printf(), max 256 bytes for now */
       +static void
       +hprintf(const char *fmt, ...)
       +{
       +        va_list ap;
       +        char buf[256];
       +
       +        va_start(ap, fmt);
       +        vsnprintf(buf, sizeof(buf), fmt, ap);
       +        va_end(ap);
       +
       +        /* use hprint() formatting logic. */
       +        hprint(buf);
       +}
       +
       +static void
       +newline(void)
       +{
       +        if (skipinitialws)
       +                return;
       +        hputchar('\n');
       +}
       +
       +static int
       +parentcontainerhasdata(int curtype, int n)
       +{
       +        int i;
       +
       +        for (i = n; i >= 0; i--) {
       +                if (nodes[i].tag.displaytype & (DisplayList|DisplayTable))
       +                        break;
       +                if (nodes[i].hasdata)
       +                        return 1;
       +        }
       +
       +        return 0;
       +}
       +
       +static int
       +parenthasdata(int n)
       +{
       +        int i;
       +
       +        for (i = n; i >= 0; i--)
       +                return nodes[i].hasdata;
       +
       +        return 0;
       +}
       +
       +/* start on a newline for the start of a block element or not */
       +static void
       +startblock(void)
       +{
       +        hflush();
       +        whitespace_mode &= ~2; /* no characters on this line yet */
       +        if (nbytesline <= 0)
       +                return;
       +        if (!hadnewline && parenthasdata(curnode - 1))
       +                hputchar('\n');
       +}
       +
       +/* start on a newline for the end of a block element or not */
       +static void
       +endblock(void)
       +{
       +        hflush();
       +        whitespace_mode &= ~2; /* no characters on this line yet */
       +        if (nbytesline <= 0)
       +                return;
       +        if (!hadnewline)
       +                hputchar('\n');
       +}
       +
       +/* print one character safely: no control characters,
       +   handle HTML white-space rules */
       +static void
       +printc(int c)
       +{
       +        if (ISSPACE((unsigned char)c)) {
       +                if (whitespace_mode == 2)
       +                        hputchar(' ');
       +                whitespace_mode |= 1;
       +        } else {
       +                whitespace_mode = 2;
       +                if (!ISCNTRL((unsigned char)c))
       +                        hputchar(c);
       +        }
       +}
       +
       +static void
       +printpre(const char *s, size_t len)
       +{
       +        struct node *cur;
       +        size_t i;
       +
       +        /* reset state of newlines because this data is printed literally */
       +        hadnewline = 0;
       +        currentnewlines = 0;
       +
       +        /* skip leading white-space */
       +        i = 0;
       +        if (skipinitialws) {
       +                for (; *s && i < len; s++, i++) {
       +                        if (!ISSPACE((unsigned char)*s))
       +                                break;
       +                }
       +        }
       +
       +        hflush();
       +
       +        skipinitialws = 0;
       +
       +        if (*s) {
       +                cur = &nodes[curnode];
       +                cur->hasdata = 1;
       +        }
       +
       +        for (; *s && i < len; s++, i++) {
       +                switch (*s) {
       +                case '\n':
       +                        putchar('\n');
       +                        nbytesline = 0;
       +                        ncells = 0;
       +                        break;
       +                case '\t':
       +                        hadnewline = 0;
       +                        if (!nbytesline) {
       +                                emitmarkup(0);
       +                                rindent();
       +                                /* emit code again per line, needed for GNU/less -R */
       +                                emitmarkup(curmarkup);
       +                        }
       +
       +                        /* TAB to 8 spaces */
       +                        fputs("        ", stdout);
       +                        nbytesline += 8;
       +                        ncells += 8;
       +                        break;
       +                default:
       +                        if (ISCNTRL((unsigned char)*s))
       +                                continue;
       +
       +                        if (!nbytesline) {
       +                                emitmarkup(0);
       +                                rindent();
       +                                /* emit code again per line, needed for GNU/less -R */
       +                                emitmarkup(curmarkup);
       +                        }
       +
       +                        putchar(*s);
       +                        nbytesline++;
       +                        /* start of rune: incorrectly assume 1 rune is 1 cell for now */
       +                        ncells += utfwidth((unsigned char)*s);
       +                }
       +        }
       +}
       +
       +static struct node *
       +findparenttype(int cur, int findtype)
       +{
       +        int i;
       +
       +        for (i = cur; i >= 0; i--) {
       +                if ((nodes[i].tag.displaytype & findtype))
       +                        return &nodes[i];
       +        }
       +        return NULL;
       +}
       +
       +int
       +isclassmatch(const char *haystack, const char *needle)
       +{
       +        const char *p;
       +        size_t needlelen;
       +        size_t matched = 0;
       +
       +        needlelen = strlen(needle);
       +        for (p = haystack; *p; p++) {
       +                if (ISSPACE((unsigned char)*p)) {
       +                        matched = 0;
       +                        continue;
       +                }
       +                if (needle[matched] == *p)
       +                        matched++;
       +                else
       +                        matched = 0;
       +                if (matched == needlelen) {
       +                        if (*(p + 1) == '\0' || ISSPACE((unsigned char)*(p + 1)))
       +                                return 1;
       +                }
       +        }
       +
       +        return 0;
       +}
       +
       +/* very limited CSS-like selector, supports: main, main#id, main.class,
       +   ".class", "#id", "ul li a" */
       +int
       +compileselector(const char *sel, struct selectornode *nodes, size_t maxnodes)
       +{
       +        int depth = 0, len;
       +        const char *s, *start;
       +        char tmp[256];
       +        int nameset = 0;
       +
       +        memset(&nodes[0], 0, sizeof(nodes[0]));
       +
       +        s = sel;
       +        for (; *s && ISSPACE((unsigned char)*s); s++)
       +                ;
       +
       +        start = s;
       +        for (; ; s++) {
       +                /* end of tag */
       +                if (!nameset &&
       +                    (*s == '#' || *s == '.' || *s == '[' ||
       +                     *s == '\0' || ISSPACE((unsigned char)*s))) {
       +                        nameset = 1;
       +                        len = s - start; /* tag name */
       +                        if (len >= sizeof(tmp))
       +                                return 0;
       +                        if (len)
       +                                memcpy(tmp, start, len);
       +                        tmp[len] = '\0';
       +
       +                        memcpy(nodes[depth].tagname, tmp, len + 1);
       +                }
       +
       +                /* end */
       +                if (*s == '\0' || ISSPACE((unsigned char)*s)) {
       +                        for (; ISSPACE((unsigned char)*s); s++)
       +                                ;
       +                        start = s; /* start of a new tag */
       +                        depth++;
       +                        if (depth >= maxnodes)
       +                                return 0;
       +
       +                        nameset = 0;
       +                        memset(&nodes[depth], 0, sizeof(nodes[depth]));
       +
       +                        /* end of selector */
       +                        if (*s == '\0')
       +                                break;
       +                }
       +
       +                /* id */
       +                if (*s == '#') {
       +                        len = strcspn(s + 1, ".#[ \t\n");
       +                        if (len >= sizeof(tmp))
       +                                return 0;
       +                        memcpy(tmp, s + 1, len);
       +                        tmp[len] = '\0';
       +                        memcpy(nodes[depth].id, tmp, len + 1);
       +                        s += len;
       +                        start = s + 1;
       +                        continue;
       +                }
       +
       +                /* class */
       +                if (*s == '.') {
       +                        len = strcspn(s + 1, ".#[ \t\n");
       +                        if (len >= sizeof(tmp))
       +                                return 0;
       +                        memcpy(tmp, s + 1, len);
       +                        tmp[len] = '\0';
       +                        /* allow only one classname for now */
       +                        memcpy(nodes[depth].classnames, tmp, len + 1);
       +                        s += len;
       +                        start = s + 1;
       +                        continue;
       +                }
       +        }
       +
       +        return depth;
       +}
       +
       +struct selector *
       +newselector(const char *q)
       +{
       +        struct selector *sel;
       +        int r;
       +
       +        sel = ecalloc(1, sizeof(*sel));
       +        sel->text = estrdup(q);
       +
       +        r = compileselector(sel->text, sel->nodes, LEN(sel->nodes));
       +        if (r <= 0) {
       +                free(sel);
       +                return NULL;
       +        }
       +        sel->depth = r;
       +
       +        return sel;
       +}
       +
       +struct selectors *
       +compileselectors(const char *q)
       +{
       +        struct selectors *sels = NULL;
       +        struct selector *sel;
       +        const char *start;
       +        char *qe;
       +        int count = 0;
       +        size_t siz;
       +
       +        sels = ecalloc(1, sizeof(*sels));
       +
       +        start = q;
       +        for (; ; q++) {
       +                if (*q == ',' || *q == '\0') {
       +                        qe = estrndup(start, q - start);
       +                        sel = newselector(qe);
       +                        free(qe);
       +
       +                        /* add new selector */
       +                        siz = (count + 1) * sizeof(struct selector *);
       +                        sels->selectors = erealloc(sels->selectors, siz);
       +                        sels->selectors[count] = sel;
       +                        count++;
       +
       +                        if (*q == '\0')
       +                                break;
       +                        start = q + 1;
       +                }
       +        }
       +        sels->count = count;
       +
       +        return sels;
       +}
       +
       +/* very limited CSS-like matcher, supports: main, main#id, main.class,
       +   ".class", "#id", "ul li a" */
       +int
       +iscssmatch(struct selector *sel, struct node *root, int maxdepth)
       +{
       +        int d, md = 0;
       +
       +        for (d = 0; d <= maxdepth; d++) {
       +                /* tag matched? */
       +                if (sel->nodes[md].tagname[0] &&
       +                    strcasecmp(sel->nodes[md].tagname, root[d].tagname))
       +                        continue; /* no */
       +
       +                /* id matched? */
       +                if (sel->nodes[md].id[0] && strcmp(sel->nodes[md].id, root[d].id))
       +                        continue; /* no */
       +
       +                /* class matched, for now allow only one classname in the selector,
       +                   matching multiple classnames */
       +                if (sel->nodes[md].classnames[0] &&
       +                    !isclassmatch(root[d].classnames, sel->nodes[md].classnames))
       +                        continue; /* no */
       +
       +                md++;
       +                /* all matched of one selector */
       +                if (md == sel->depth)
       +                        return 1;
       +        }
       +
       +        return 0;
       +}
       +
       +int
       +iscssmatchany(struct selectors *sels, struct node *root, int maxdepth)
       +{
       +        struct selector *sel;
       +        int i;
       +
       +        for (i = 0; i < sels->count; i++) {
       +                sel = sels->selectors[i];
       +                if (iscssmatch(sel, root, maxdepth))
       +                        return 1;
       +        }
       +        return 0;
       +}
       +
       +static void
       +handleinlinealt(void)
       +{
       +        struct node *cur;
       +        char *start, *s, *e;
       +
       +        /* do not show the alt text if the element is hidden */
       +        cur = &nodes[curnode];
       +        if (cur->tag.displaytype & DisplayNone)
       +                return;
       +
       +        /* show img alt attribute as text. */
       +        if (attr_alt.len) {
       +                start = attr_alt.data;
       +                e = attr_alt.data + attr_alt.len;
       +
       +                for (s = start; s < e; s++)
       +                        printc((unsigned char)*s);
       +                hflush(); /* TODO: this flush should not be needed */
       +        }
       +}
       +
       +static void
       +addlinkref(const char *url, const char *_type, int ishidden)
       +{
       +        /* add to linked list */
       +        if (!links_head)
       +                links_cur = links_head = ecalloc(1, sizeof(*links_head));
       +        else
       +                links_cur = links_cur->next = ecalloc(1, sizeof(*links_head));
       +        links_cur->url = estrdup(url);
       +        links_cur->type = estrdup(_type);
       +        links_cur->ishidden = ishidden;
       +}
       +
       +/* TODO: make parsed base URL global and overwrite it once. */
       +static void
       +handleinlinelink(void)
       +{
       +        struct uri base, newuri, olduri;
       +        struct node *cur;
       +        char buf[4096], *url;
       +        int b, r;
       +
       +        /* show links as reference at the bottom */
       +        if ((showrefbottom || resources) && (attr_src.len || attr_href.len)) {
       +                /* by default use the original URL */
       +                if (attr_src.len)
       +                        url = attr_src.data;
       +                else
       +                        url = attr_href.data;
       +
       +                b = -1;
       +                if (uri_hasscheme(url))
       +                        ; /* already absolute: nothing to do */
       +                else if (basehref[0]) /* prefer -b option over <base> */
       +                        b = uri_parse(basehref, &base);
       +                else if (basehrefdoc[0])
       +                        b = uri_parse(basehrefdoc, &base);
       +
       +                if (b != -1 &&
       +                    uri_parse(url, &olduri) != -1 &&
       +                    uri_makeabs(&newuri, &olduri, &base) != -1 &&
       +                    newuri.proto[0]) {
       +                        r = uri_format(buf, sizeof(buf), &newuri);
       +                        if (r >= 0 && (size_t)r < sizeof(buf))
       +                                url = buf;
       +                }
       +
       +                if (!url[0])
       +                        return;
       +
       +                cur = &nodes[curnode];
       +
       +                if (showrefinline && !(cur->tag.displaytype & DisplayNone)) {
       +                        string_clear(&nodes_links[curnode]);
       +                        string_append(&nodes_links[curnode], url, strlen(url));
       +                }
       +
       +                /* add hidden links directly to the reference,
       +                   the order doesn't matter */
       +                if (cur->tag.displaytype & DisplayNone)
       +                        addlinkref(url, cur->tag.name, 1);
       +        }
       +}
       +
       +void
       +printlinkrefs(void)
       +{
       +        size_t i;
       +        int hashiddenrefs = 0;
       +
       +        if (!links_head)
       +                return;
       +
       +        if (resources) {
       +                for (i = 1, links_cur = links_head; links_cur; links_cur = links_cur->next, i++)
       +                        dprintf(3, "%s\t%s\n", links_cur->type, links_cur->url);
       +        }
       +
       +        printf("\n\nReferences\n\n");
       +
       +        i = 1;
       +        for (links_cur = links_head; links_cur; links_cur = links_cur->next) {
       +                if (links_cur->ishidden) {
       +                        hashiddenrefs = 1;
       +                        continue;
       +                }
       +                printf(" %zu. %s (%s)\n", i, links_cur->url, links_cur->type);
       +                i++;
       +        }
       +
       +        if (hashiddenrefs)
       +                printf("\n\nHidden references\n\n");
       +        for (links_cur = links_head; links_cur; links_cur = links_cur->next) {
       +                if (!links_cur->ishidden)
       +                        continue;
       +                printf(" %zu. %s (%s)\n", i, links_cur->url, links_cur->type);
       +                i++;
       +        }
       +}
       +
       +static void
       +xmldatastart(XMLParser *p)
       +{
       +}
       +
       +static void
       +xmldataend(XMLParser *p)
       +{
       +        struct node *cur;
       +        char *start, *s, *e;
       +
       +        if (!htmldata.data || !htmldata.len)
       +                return;
       +
       +        cur = &nodes[curnode];
       +
       +        if (reader_ignore || (cur->tag.displaytype & DisplayNone)) {
       +                /* print nothing */
       +        } else if ((cur->tag.displaytype & DisplayPre) ||
       +                   findparenttype(curnode - 1, DisplayPre)) {
       +                printpre(htmldata.data, htmldata.len);
       +        } else {
       +                start = htmldata.data;
       +                e = htmldata.data + htmldata.len;
       +
       +                for (s = start; s < e; s++)
       +                        printc((unsigned char)*s);
       +        }
       +
       +        string_clear(&htmldata);
       +}
       +
       +static void
       +xmldata(XMLParser *p, const char *data, size_t datalen)
       +{
       +        struct node *cur;
       +
       +        if (reader_ignore)
       +                return;
       +
       +        cur = &nodes[curnode];
       +        if (cur->tag.displaytype & DisplayNone)
       +                return;
       +
       +        string_append(&htmldata, data, datalen);
       +}
       +
       +static void
       +xmldataentity(XMLParser *p, const char *data, size_t datalen)
       +{
       +        struct node *cur;
       +        char buf[16];
       +        int n;
       +
       +        if (reader_ignore)
       +                return;
       +
       +        cur = &nodes[curnode];
       +        if (cur->tag.displaytype & DisplayNone)
       +                return;
       +
       +        n = xml_entitytostr(data, buf, sizeof(buf));
       +        if (n > 0)
       +                xmldata(p, buf, (size_t)n);
       +        else
       +                xmldata(p, data, datalen);
       +}
       +
       +static void
       +xmlcdatastart(XMLParser *p)
       +{
       +        xmldatastart(p);
       +}
       +
       +static void
       +xmlcdataend(XMLParser *p)
       +{
       +        xmldataend(p); /* treat CDATA as data */
       +}
       +
       +static void
       +xmlcdata(XMLParser *p, const char *data, size_t datalen)
       +{
       +        xmldata(p, data, datalen); /* treat CDATA as data */
       +}
       +
       +/* compare tag name (case-insensitive) */
       +int
       +tagcmp(const char *s1, const char *s2)
       +{
       +        return strcasecmp(s1, s2);
       +}
       +
       +/* compare attribute name (case-insensitive) */
       +int
       +attrcmp(const char *s1, const char *s2)
       +{
       +        return strcasecmp(s1, s2);
       +}
       +
       +/* lookup function to compare tag name (case-insensitive) for sort functions */
       +int
       +findtagcmp(const void *v1, const void *v2)
       +{
       +        struct tag *t1 = (struct tag *)v1;
       +        struct tag *t2 = (struct tag *)v2;
       +
       +        return strcasecmp(t1->name, t2->name);
       +}
       +
       +/* binary search tag by tag name */
       +struct tag *
       +findtag(const char *t)
       +{
       +        struct tag find = { 0 };
       +
       +        find.name = t;
       +
       +        return bsearch(&find, tags, LEN(tags), sizeof(*tags), findtagcmp);
       +}
       +
       +static void
       +handleendtag(struct tag *tag)
       +{
       +        int i, marginbottom;
       +
       +        if (tag->displaytype & DisplayNone)
       +                return;
       +        if (reader_ignore)
       +                return;
       +
       +        if (tag->displaytype & (DisplayBlock | DisplayHeader | DisplayTable | DisplayTableRow |
       +                DisplayList | DisplayListItem | DisplayPre)) {
       +                endblock(); /* break line if needed */
       +        }
       +
       +        /* when a list ends and its not inside a list add an extra bottom margin */
       +        marginbottom = tag->marginbottom;
       +
       +        if (marginbottom > 0) {
       +                if (tag->displaytype & DisplayList) {
       +                        if (findparenttype(curnode - 1, DisplayList))
       +                                marginbottom--;
       +                }
       +        }
       +
       +        if (marginbottom > 0) {
       +                hflush();
       +                for (i = currentnewlines; i < marginbottom; i++) {
       +                        putchar('\n');
       +                        currentnewlines++;
       +                }
       +                nbytesline = 0;
       +                ncells = 0;
       +                hadnewline = 1;
       +        }
       +}
       +
       +static void
       +endnode(struct node *cur)
       +{
       +        int i, ishidden;
       +
       +        /* set a flag indicating the element and its parent containers have data.
       +           This is used for some formatting */
       +        if (cur->hasdata) {
       +                for (i = curnode; i >= 0; i--)
       +                        nodes[i].hasdata = 1;
       +        }
       +
       +        endmarkup(cur->tag.markuptype);
       +
       +        ishidden = reader_ignore || (cur->tag.displaytype & DisplayNone);
       +
       +        /* add link and show the link number in the visible order */
       +        if (!ishidden && nodes_links[curnode].len > 0) {
       +                addlinkref(nodes_links[curnode].data, cur->tag.name, ishidden);
       +#if 1
       +                hprintf("[%zu]", ++linkcount);
       +#else
       +                hprintf("[%s: %s]", cur->tag.name, nodes_links[curnode].data);
       +#endif
       +        }
       +
       +        handleendtag(&(cur->tag));
       +}
       +
       +static void
       +xmltagend(XMLParser *p, const char *t, size_t tl, int isshort)
       +{
       +        struct tag *found, *tag;
       +        const char *child;
       +        int i, j, parenttype;
       +
       +        /* ignore closing of void elements, like </br>, which is not allowed */
       +        if ((found = findtag(t))) {
       +                if (!isshort && found->isvoid)
       +                        return;
       +        }
       +
       +        /* TODO: implement more complete optional tag handling.
       +           in reality the optional tag rules are more complex, see:
       +           https://html.spec.whatwg.org/multipage/syntax.html#optional-tags */
       +
       +        child = NULL;
       +        parenttype = 0;
       +
       +        if (found && found->displaytype & DisplayPre) {
       +                skipinitialws = 0; /* do not skip white-space, for margins */
       +        } else if (found && found->displaytype & DisplayList) {
       +                child = "li";
       +                parenttype = DisplayList;
       +        } else if (found && found->displaytype & DisplayTableRow) {
       +                child = "td";
       +                parenttype = DisplayTableRow;
       +        } else if (found && found->displaytype & DisplayTable) {
       +                child = "td";
       +                parenttype = DisplayTable;
       +        }
       +
       +        if (child && parenttype) {
       +                for (i = curnode; i >= 0; i--) {
       +                        if ((nodes[i].tag.displaytype & parenttype))
       +                                break;
       +                        if (!tagcmp(nodes[i].tag.name, child)) {
       +                                /* fake closing the previous tags */
       +                                for (j = curnode; j >= i; j--)
       +                                        endnode(&nodes[j]);
       +                                curnode = j;
       +                                break;
       +                        }
       +                }
       +        }
       +
       +        /* if the current closing tag matches the current open tag */
       +        if (nodes[curnode].tag.name &&
       +            !tagcmp(nodes[curnode].tag.name, t)) {
       +                endnode(&nodes[curnode]);
       +                if (curnode)
       +                        curnode--;
       +        } else {
       +                /* ... else lookup the first matching start tag. This is also
       +                   for handling optional closing tags */
       +                tag = NULL;
       +                for (i = curnode; i >= 0; i--) {
       +                        if (nodes[curnode].tag.name &&
       +                            !tagcmp(nodes[i].tag.name, t)) {
       +                                endnode(&nodes[i]);
       +                                curnode = i > 0 ? i - 1 : 0;
       +                                tag = &nodes[i].tag;
       +                                break;
       +                        }
       +                }
       +                /* unmatched closing tag found */
       +                if (!tag && found)
       +                        handleendtag(found);
       +        }
       +        indent = calcindent();
       +
       +        /* restore markup of the tag we are in now */
       +        startmarkup(nodes[curnode].tag.markuptype);
       +
       +        /* check if the current node still matches the visible selector */
       +        if (reader_mode && sel_show && !reader_ignore) {
       +                if (!iscssmatchany(sel_show, nodes, curnode)) {
       +                        reader_ignore = 1;
       +                        newline();
       +                }
       +        }
       +}
       +
       +static void
       +xmltagstart(XMLParser *p, const char *t, size_t tl)
       +{
       +        struct tag *found;
       +        struct node *cur;
       +        const char *child;
       +        char *s;
       +        int i, j, parenttype;
       +
       +        if (curnode >= MAX_DEPTH - 2)
       +                errx(1, "max tag depth reached: %d\n", curnode);
       +
       +        cur = &nodes[curnode];
       +
       +        string_clear(&attr_alt);
       +        string_clear(&attr_class);
       +        string_clear(&attr_href);
       +        string_clear(&attr_id);
       +        string_clear(&attr_src);
       +        string_clear(&attr_type);
       +        string_clear(&attr_value);
       +
       +        /* match tag */
       +        found = findtag(t);
       +
       +        /* TODO: implement more complete optional tag handling.
       +           in reality the optional tag rules are more complex, see:
       +           https://html.spec.whatwg.org/multipage/syntax.html#optional-tags */
       +
       +        child = NULL;
       +        parenttype = 0;
       +
       +        /* if optional tag <p> is open and a block element is found, close </p>. */
       +        if (found && found->displaytype & DisplayList) {
       +                /* not inside a list */
       +                child = "p";
       +                parenttype = DisplayList;
       +        } else if (found && found->isoptional) {
       +                if (!tagcmp(t, "li")) {
       +                        child = "li";
       +                        parenttype = DisplayList;
       +                } else if (!tagcmp(t, "td")) {
       +                        child = "td";
       +                        parenttype = DisplayTableRow;
       +                } else if (!tagcmp(t, "tr")) {
       +                        child = "tr";
       +                        parenttype = DisplayTable;
       +                } else if (!tagcmp(t, cur->tag.name)) {
       +                        /* fake closing the previous tag if it is the same and repeated */
       +                        xmltagend(p, t, tl, 0);
       +                }
       +        }
       +
       +        if (child && parenttype) {
       +                for (i = curnode; i >= 0; i--) {
       +                        if ((nodes[i].tag.displaytype & parenttype))
       +                                break;
       +                        if (!tagcmp(nodes[i].tag.name, child)) {
       +                                /* fake closing the previous tags */
       +                                for (j = curnode; j >= i; j--)
       +                                        xmltagend(p, nodes[j].tag.name, strlen(nodes[j].tag.name), 0);
       +                                break;
       +                        }
       +                }
       +        }
       +
       +        curnode++;
       +        string_clear(&nodes_links[curnode]); /* clear possible link reference for this node */
       +        cur = &nodes[curnode];
       +        memset(cur, 0, sizeof(*cur)); /* clear / reset node */
       +        /* tag defaults */
       +        cur->tag.displaytype = DisplayInline;
       +        cur->tag.name = cur->tagname;
       +        strlcpy(cur->tagname, t, sizeof(cur->tagname));
       +        /* force to lowercase */
       +        for (s = cur->tagname; *s; s++)
       +                *s = TOLOWER((unsigned char)*s);
       +
       +        /* matched tag: copy tag information to current node */
       +        if (found)
       +                memcpy(&(cur->tag), found, sizeof(*found));
       +
       +        /* parent tag is hidden, so hide ourself too */
       +        if (curnode > 0 && (nodes[curnode - 1].tag.displaytype & DisplayNone))
       +                cur->tag.displaytype |= DisplayNone;
       +}
       +
       +static void
       +xmltagstartparsed(XMLParser *p, const char *t, size_t tl, int isshort)
       +{
       +        struct node *cur, *parent;
       +        int i, margintop;
       +
       +        /* temporary replace the callback except the reader and end of tag
       +           restore the context once we receive the same ignored tag in the
       +           end tag handler */
       +        if (!tagcmp(t, "script")) {
       +                ignorestate = endtag = "</script>";
       +                getnext = p->getnext; /* for restore */
       +                p->getnext = getnext_ignore;
       +                xmltagend(p, t, tl, 0); /* fake the call the tag was ended */
       +                return;
       +        } else if (!tagcmp(t, "style")) {
       +                ignorestate = endtag = "</style>";
       +                getnext = p->getnext; /* for restore */
       +                p->getnext = getnext_ignore;
       +                xmltagend(p, t, tl, 0); /* fake the call the tag was ended */
       +                return;
       +        }
       +
       +        cur = &nodes[curnode];
       +
       +        /* copy attributes if set */
       +        if (attr_id.len)
       +                strlcpy(cur->id, attr_id.data, sizeof(cur->id));
       +        else
       +                cur->id[0] = '\0';
       +        if (attr_class.len)
       +                strlcpy(cur->classnames, attr_class.data, sizeof(cur->classnames));
       +        else
       +                cur->classnames[0] = '\0';
       +
       +        /* parent node */
       +        if (curnode > 0) {
       +                parent = &nodes[curnode - 1];
       +                parent->nchildren++; /* increase child node count */
       +                /* count visible childnodes */
       +                if (!(cur->tag.displaytype & DisplayNone))
       +                        parent->visnchildren++;
       +        } else {
       +                parent = NULL;
       +        }
       +
       +        if (reader_mode && sel_show && reader_ignore &&
       +            iscssmatchany(sel_show, nodes, curnode))
       +                reader_ignore = 0;
       +
       +        /* hide element */
       +        if (reader_mode && sel_hide &&
       +            iscssmatchany(sel_hide, nodes, curnode))
       +                cur->tag.displaytype |= DisplayNone;
       +
       +        /* indent for this tag */
       +        cur->indent = cur->tag.indent;
       +
       +        if (!reader_ignore) {
       +                /* add link reference, print links and alt text */
       +                handleinlinelink();
       +                handleinlinealt();
       +        }
       +
       +        if (cur->tag.displaytype & DisplayNone)
       +                return;
       +
       +        if (reader_ignore)
       +                return;
       +
       +        indent = calcindent();
       +
       +        if ((cur->tag.displaytype & (DisplayBlock | DisplayHeader | DisplayPre |
       +                DisplayTable | DisplayTableRow |
       +                DisplayList | DisplayListItem))) {
       +                startblock(); /* break line if needed */
       +        }
       +
       +        margintop = cur->tag.margintop;
       +        if (cur->tag.displaytype & (DisplayList)) {
       +                for (i = curnode - 1; i >= 0; i--) {
       +                        if (nodes[i].tag.displaytype & DisplayList)
       +                                break;
       +                        if (!(nodes[i].tag.displaytype & DisplayListItem))
       +                                continue;
       +                        if (nodes[i].hasdata && margintop > 0) {
       +                                margintop--;
       +                                break;
       +                        }
       +                }
       +        } else if (cur->tag.displaytype & (DisplayBlock|DisplayTable)) {
       +                if (!parentcontainerhasdata(cur->tag.displaytype, curnode - 1)) {
       +                        if (margintop > 0)
       +                                margintop--;
       +                }
       +        }
       +
       +        if (margintop > 0) {
       +                hflush();
       +                for (i = currentnewlines; i < margintop; i++) {
       +                        putchar('\n');
       +                        currentnewlines++;
       +                }
       +                nbytesline = 0;
       +                ncells = 0;
       +                hadnewline = 1;
       +        }
       +
       +        if (cur->tag.displaytype & DisplayPre) {
       +                skipinitialws = 1;
       +        } else if (cur->tag.displaytype & DisplayTableCell) {
       +                if (parent && parent->visnchildren > 1)
       +                        hputchar('\t');
       +        } else if (cur->tag.displaytype & DisplayListItem) {
       +                /* find first parent node and ordered numbers or unordered */
       +                if (parent) {
       +                        skipinitialws = 0;
       +
       +                        /* print bullet, add columns to indentation level */
       +                        if (parent->tag.displaytype & DisplayListOrdered) {
       +                                hprintf("%4zu. ", parent->nchildren);
       +                                cur->indent = 6;
       +                                indent += cur->indent; /* align to number */
       +                        } else if (parent->tag.displaytype & DisplayList) {
       +                                hprint(str_bullet_item);
       +                                cur->indent = 2;
       +                                indent += 2; /* align to bullet */
       +                        }
       +                }
       +                skipinitialws = 0;
       +        }
       +
       +        if (!tagcmp(cur->tag.name, "input")) {
       +                if (!attr_type.len) {
       +                        hprintf("[%-15s]", attr_value.len ? attr_value.data : ""); /* default: text */
       +                } else if (!strcasecmp(attr_type.data, "text")) {
       +                        hprintf("[%-15s]", attr_value.len ? attr_value.data : ""); /* text */
       +                } else if (!strcasecmp(attr_type.data, "search")) {
       +                        hprintf("[%-15s]", attr_value.len ? attr_value.data : "");
       +                } else if (!strcasecmp(attr_type.data, "button")) {
       +                        hprintf("[%s]", attr_value.len ? attr_value.data : "");
       +                } else if (!strcasecmp(attr_type.data, "submit")) {
       +                        hprintf("[%s]", attr_value.len ? attr_value.data : "");
       +                } else if (!strcasecmp(attr_type.data, "checkbox")) {
       +                        hprint("[ ]"); /* TODO: show x or unicode checkmark when selected? */
       +                } else if (!strcasecmp(attr_type.data, "radio")) {
       +                        hprint("( )"); /* TODO: show x or unicode checkmark when selected? */
       +                }
       +        }
       +
       +        startmarkup(cur->tag.markuptype);
       +
       +        /* do not count data such as an item bullet as part of the data for
       +           the node */
       +        cur->hasdata = 0;
       +
       +        if (!tagcmp(t, "hr")) { /* ruler */
       +                i = termwidth - indent - defaultindent;
       +                for (; i > 0; i--)
       +                        hprint(str_ruler);
       +                cur->hasdata = 1; /* treat <hr/> as data */
       +        } else if (!tagcmp(t, "br")) {
       +                hflush();
       +                hadnewline = 0; /* forced newline */
       +                hputchar('\n');
       +                cur->hasdata = 1; /* treat <br/> as data */
       +        }
       +
       +        /* autoclose tags, such as <br>, pretend we are <br/> */
       +        if (!isshort && cur->tag.isvoid)
       +                xmltagend(p, t, tl, 1); /* pretend close of short tag */
       +}
       +
       +static void
       +xmlattr(XMLParser *p, const char *tag, size_t taglen, const char *name,
       +        size_t namelen, const char *value, size_t valuelen)
       +{
       +        struct node *cur;
       +
       +        cur = &nodes[curnode];
       +
       +        if (!attrcmp(name, "class"))
       +                string_append(&attr_class, value, valuelen);
       +        else if (!attrcmp(name, "id"))
       +                string_append(&attr_id, value, valuelen);
       +
       +        /* <base href="..." /> */
       +        if (!attrcmp(name, "href") && !tagcmp(tag, "base"))
       +                strlcat(basehrefdoc, value, sizeof(basehrefdoc));
       +
       +        /* hide tags with attribute aria-hidden or hidden */
       +        if (!attrcmp(name, "aria-hidden") || !attrcmp(name, "hidden"))
       +                cur->tag.displaytype |= DisplayNone;
       +
       +        if (!tagcmp(tag, "a") && !attrcmp(name, "href"))
       +                string_append(&attr_src, value, valuelen);
       +
       +        if ((!tagcmp(tag, "img") || !tagcmp(tag, "video") ||
       +             !tagcmp(tag, "source") || !tagcmp(tag, "track") ||
       +             !tagcmp(tag, "audio")) &&
       +            !attrcmp(name, "src") && valuelen)
       +                string_append(&attr_href, value, valuelen);
       +
       +        /* show img alt attribute as text. */
       +        if (!tagcmp(tag, "img") && !attrcmp(name, "alt"))
       +                string_append(&attr_alt, value, valuelen);
       +
       +        if (!attrcmp(name, "type"))
       +                string_append(&attr_type, value, valuelen);
       +        if (!attrcmp(name, "value"))
       +                string_append(&attr_value, value, valuelen);
       +}
       +
       +static void
       +xmlattrentity(XMLParser *p, const char *tag, size_t taglen, const char *name,
       +        size_t namelen, const char *value, size_t valuelen)
       +{
       +        char buf[16];
       +        int n;
       +
       +        n = xml_entitytostr(value, buf, sizeof(buf));
       +        if (n > 0)
       +                xmlattr(p, tag, taglen, name, namelen, buf, (size_t)n);
       +        else
       +                xmlattr(p, tag, taglen, name, namelen, value, valuelen);
       +}
       +
       +static void
       +xmlattrend(XMLParser *p, const char *t, size_t tl, const char *n,
       +        size_t nl)
       +{
       +}
       +
       +static void
       +xmlattrstart(XMLParser *p, const char *t, size_t tl, const char *n,
       +        size_t nl)
       +{
       +        if (!attrcmp(n, "alt"))
       +                string_clear(&attr_alt);
       +        else if (!attrcmp(n, "class"))
       +                string_clear(&attr_class);
       +        else if (!attrcmp(n, "href"))
       +                string_clear(&attr_href);
       +        else if (!attrcmp(n, "id"))
       +                string_clear(&attr_id);
       +        else if (!attrcmp(n, "src"))
       +                string_clear(&attr_src);
       +        else if (!attrcmp(n, "type"))
       +                string_clear(&attr_type);
       +        else if (!attrcmp(n, "value"))
       +                string_clear(&attr_value);
       +
       +        if (!attrcmp(n, "href") && !tagcmp(t, "base"))
       +                basehrefdoc[0] = '\0';
       +}
       +
       +void
       +usage(void)
       +{
       +        fprintf(stderr, "%s [-8ailrx] [-b basehref] [-s selector] [-u selector] [-w termwidth]\n", argv0);
       +        exit(1);
       +}
       +
       +int
       +main(int argc, char **argv)
       +{
       +        if (pledge("stdio", NULL) < 0)
       +                err(1, "pledge");
       +
       +        ARGBEGIN {
       +        case '8':
       +                str_bullet_item = "\xe2\x80\xa2 ";
       +                str_ruler = "\xe2\x94\x80"; /* symbol: "light horizontal" */
       +                break;
       +        case 'a':
       +                allowansi = !allowansi;
       +                break;
       +        case 'b':
       +                basehref = EARGF(usage());
       +                break;
       +        case 'i':
       +                showrefinline = !showrefinline;
       +                break;
       +        case 'l':
       +                showrefbottom = !showrefbottom;
       +                break;
       +        case 'r':
       +                linewrap = !linewrap;
       +                break;
       +        case 's':
       +                sel_show = compileselectors(EARGF(usage()));
       +                /* switch to reader/selector mode, ignore all data except when matched */
       +                reader_mode = 1;
       +                reader_ignore = 1;
       +                break;
       +        case 'u':
       +                sel_hide = compileselectors(EARGF(usage()));
       +                /* switch to reader/selector mode */
       +                reader_mode = 1;
       +                break;
       +        case 'w':
       +                if ((termwidth = strtol(EARGF(usage()), NULL, 10)) < 1)
       +                        usage();
       +                break;
       +        case 'x':
       +                resources = !resources;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND
       +
       +        /* top-most document root needs initialization */
       +        nodes[0].tag.name = "";
       +
       +        parser.xmlattrstart = xmlattrstart;
       +        parser.xmlattr = xmlattr;
       +        parser.xmlattrentity = xmlattrentity;
       +        parser.xmlattrend = xmlattrend;
       +        parser.xmlcdatastart = xmlcdatastart;
       +        parser.xmlcdata = xmlcdata;
       +        parser.xmlcdataend = xmlcdataend;
       +        parser.xmldatastart = xmldatastart;
       +        parser.xmldata = xmldata;
       +        parser.xmldataentity = xmldataentity;
       +        parser.xmldataend = xmldataend;
       +        parser.xmltagstart = xmltagstart;
       +        parser.xmltagstartparsed = xmltagstartparsed;
       +        parser.xmltagend = xmltagend;
       +
       +        parser.getnext = getchar;
       +        xml_parse(&parser);
       +
       +        if (showrefbottom || resources)
       +                printlinkrefs();
       +
       +        hflush();
       +        if (ncells > 0)
       +                newline();
       +
       +        hflush();
       +        setmarkup(0);
       +
       +        return 0;
       +}
 (DIR) diff --git a/xml.c b/xml.c
       @@ -0,0 +1,489 @@
       +#include <errno.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +
       +#include "xml.h"
       +
       +/* ifdef for HTML mode. To differentiate xml.c and webdump HTML changes */
       +#define HTML_MODE
       +
       +#define ISALPHA(c) ((((unsigned)c) | 32) - 'a' < 26)
       +#define ISSPACE(c) ((c) == ' ' || ((((unsigned)c) - '\t') < 5))
       +
       +static void
       +xml_parseattrs(XMLParser *x)
       +{
       +        size_t namelen = 0, valuelen;
       +        int c, endsep, endname = 0, valuestart = 0;
       +
       +        while ((c = GETNEXT()) != EOF) {
       +                if (ISSPACE(c)) {
       +                        if (namelen)
       +                                endname = 1;
       +                        continue;
       +                } else if (c == '?')
       +                        ; /* ignore */
       +                else if (c == '=') {
       +                        x->name[namelen] = '\0';
       +                        valuestart = 1;
       +                        endname = 1;
       +                } else if (namelen && ((endname && !valuestart && ISALPHA(c)) || (c == '>' || c == '/'))) {
       +                        /* attribute without value */
       +                        x->name[namelen] = '\0';
       +                        if (x->xmlattrstart)
       +                                x->xmlattrstart(x, x->tag, x->taglen, x->name, namelen);
       +                        if (x->xmlattr)
       +                                x->xmlattr(x, x->tag, x->taglen, x->name, namelen, "", 0);
       +                        if (x->xmlattrend)
       +                                x->xmlattrend(x, x->tag, x->taglen, x->name, namelen);
       +                        endname = 0;
       +                        x->name[0] = c;
       +                        namelen = 1;
       +                } else if (namelen && valuestart) {
       +                        /* attribute with value */
       +                        if (x->xmlattrstart)
       +                                x->xmlattrstart(x, x->tag, x->taglen, x->name, namelen);
       +
       +                        valuelen = 0;
       +                        if (c == '\'' || c == '"') {
       +                                endsep = c;
       +                        } else {
       +                                endsep = ' '; /* ISSPACE() */
       +                                goto startvalue;
       +                        }
       +
       +                        while ((c = GETNEXT()) != EOF) {
       +startvalue:
       +                                if (c == '&') { /* entities */
       +                                        x->data[valuelen] = '\0';
       +                                        /* call data function with data before entity if there is data */
       +                                        if (valuelen && x->xmlattr)
       +                                                x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
       +                                        x->data[0] = c;
       +                                        valuelen = 1;
       +                                        while ((c = GETNEXT()) != EOF) {
       +                                                if (c == endsep || (endsep == ' ' && (c == '>' || ISSPACE(c))))
       +                                                        break;
       +                                                if (valuelen < sizeof(x->data) - 1)
       +                                                        x->data[valuelen++] = c;
       +                                                else {
       +                                                        /* entity too long for buffer, handle as normal data */
       +                                                        x->data[valuelen] = '\0';
       +                                                        if (x->xmlattr)
       +                                                                x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
       +                                                        x->data[0] = c;
       +                                                        valuelen = 1;
       +                                                        break;
       +                                                }
       +                                                if (c == ';') {
       +                                                        x->data[valuelen] = '\0';
       +                                                        if (x->xmlattrentity)
       +                                                                x->xmlattrentity(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
       +                                                        valuelen = 0;
       +                                                        break;
       +                                                }
       +                                        }
       +                                } else if (c != endsep && !(endsep == ' ' && (c == '>' || ISSPACE(c)))) {
       +                                        if (valuelen < sizeof(x->data) - 1) {
       +                                                x->data[valuelen++] = c;
       +                                        } else {
       +                                                x->data[valuelen] = '\0';
       +                                                if (x->xmlattr)
       +                                                        x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
       +                                                x->data[0] = c;
       +                                                valuelen = 1;
       +                                        }
       +                                }
       +                                if (c == endsep || (endsep == ' ' && (c == '>' || ISSPACE(c)))) {
       +                                        x->data[valuelen] = '\0';
       +                                        if (x->xmlattr)
       +                                                x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
       +                                        if (x->xmlattrend)
       +                                                x->xmlattrend(x, x->tag, x->taglen, x->name, namelen);
       +                                        break;
       +                                }
       +                        }
       +                        namelen = endname = valuestart = 0;
       +                } else if (namelen < sizeof(x->name) - 1) {
       +                        x->name[namelen++] = c;
       +                }
       +                if (c == '>') {
       +                        break;
       +                } else if (c == '/') {
       +                        x->isshorttag = 1;
       +                        x->name[0] = '\0';
       +                        namelen = 0;
       +                }
       +        }
       +}
       +
       +static void
       +xml_parsecomment(XMLParser *x)
       +{
       +        size_t datalen = 0, i = 0;
       +        int c;
       +
       +        if (x->xmlcommentstart)
       +                x->xmlcommentstart(x);
       +        while ((c = GETNEXT()) != EOF) {
       +                if (c == '-' || c == '>') {
       +                        if (x->xmlcomment && datalen) {
       +                                x->data[datalen] = '\0';
       +                                x->xmlcomment(x, x->data, datalen);
       +                                datalen = 0;
       +                        }
       +                }
       +
       +                if (c == '-') {
       +                        if (++i > 2) {
       +                                if (x->xmlcomment)
       +                                        for (; i > 2; i--)
       +                                                x->xmlcomment(x, "-", 1);
       +                                i = 2;
       +                        }
       +                        continue;
       +                } else if (c == '>' && i == 2) {
       +                        if (x->xmlcommentend)
       +                                x->xmlcommentend(x);
       +                        return;
       +                } else if (i) {
       +                        if (x->xmlcomment) {
       +                                for (; i > 0; i--)
       +                                        x->xmlcomment(x, "-", 1);
       +                        }
       +                        i = 0;
       +                }
       +
       +                if (datalen < sizeof(x->data) - 1) {
       +                        x->data[datalen++] = c;
       +                } else {
       +                        x->data[datalen] = '\0';
       +                        if (x->xmlcomment)
       +                                x->xmlcomment(x, x->data, datalen);
       +                        x->data[0] = c;
       +                        datalen = 1;
       +                }
       +        }
       +}
       +
       +static void
       +xml_parsecdata(XMLParser *x)
       +{
       +        size_t datalen = 0, i = 0;
       +        int c;
       +
       +        if (x->xmlcdatastart)
       +                x->xmlcdatastart(x);
       +        while ((c = GETNEXT()) != EOF) {
       +                if (c == ']' || c == '>') {
       +                        if (x->xmlcdata && datalen) {
       +                                x->data[datalen] = '\0';
       +                                x->xmlcdata(x, x->data, datalen);
       +                                datalen = 0;
       +                        }
       +                }
       +
       +                if (c == ']') {
       +                        if (++i > 2) {
       +                                if (x->xmlcdata)
       +                                        for (; i > 2; i--)
       +                                                x->xmlcdata(x, "]", 1);
       +                                i = 2;
       +                        }
       +                        continue;
       +                } else if (c == '>' && i == 2) {
       +                        if (x->xmlcdataend)
       +                                x->xmlcdataend(x);
       +                        return;
       +                } else if (i) {
       +                        if (x->xmlcdata)
       +                                for (; i > 0; i--)
       +                                        x->xmlcdata(x, "]", 1);
       +                        i = 0;
       +                }
       +
       +                if (datalen < sizeof(x->data) - 1) {
       +                        x->data[datalen++] = c;
       +                } else {
       +                        x->data[datalen] = '\0';
       +                        if (x->xmlcdata)
       +                                x->xmlcdata(x, x->data, datalen);
       +                        x->data[0] = c;
       +                        datalen = 1;
       +                }
       +        }
       +}
       +
       +static int
       +codepointtoutf8(long r, char *s)
       +{
       +        if (r == 0) {
       +                return 0; /* NUL byte */
       +        } else if (r <= 0x7F) {
       +                /* 1 byte: 0aaaaaaa */
       +                s[0] = r;
       +                return 1;
       +        } else if (r <= 0x07FF) {
       +                /* 2 bytes: 00000aaa aabbbbbb */
       +                s[0] = 0xC0 | ((r & 0x0007C0) >>  6); /* 110aaaaa */
       +                s[1] = 0x80 |  (r & 0x00003F);        /* 10bbbbbb */
       +                return 2;
       +        } else if (r <= 0xFFFF) {
       +                /* 3 bytes: aaaabbbb bbcccccc */
       +                s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
       +                s[1] = 0x80 | ((r & 0x000FC0) >>  6); /* 10bbbbbb */
       +                s[2] = 0x80 |  (r & 0x00003F);        /* 10cccccc */
       +                return 3;
       +        } else {
       +                /* 4 bytes: 000aaabb bbbbcccc ccdddddd */
       +                s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
       +                s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
       +                s[2] = 0x80 | ((r & 0x000FC0) >>  6); /* 10cccccc */
       +                s[3] = 0x80 |  (r & 0x00003F);        /* 10dddddd */
       +                return 4;
       +        }
       +}
       +
       +struct namedentity {
       +        const char *entity;
       +        long cp;
       +};
       +
       +int
       +namedentitycmp(const void *v1, const void *v2)
       +{
       +        struct namedentity *n1 = (struct namedentity *)v1;
       +        struct namedentity *n2 = (struct namedentity *)v2;
       +
       +        return strcmp(n1->entity, n2->entity);
       +}
       +
       +static int
       +namedentitytostr(const char *e, char *buf, size_t bufsiz)
       +{
       +        static const struct namedentity entities[] = {
       +#include "namedentities.h"
       +        };
       +        struct namedentity find, *found;
       +        size_t i;
       +
       +        /* buffer is too small */
       +        if (bufsiz < 5)
       +                return -1;
       +
       +        find.entity = e;
       +        found = bsearch(&find, entities, sizeof(entities) / sizeof(*entities),
       +                sizeof(*entities), namedentitycmp);
       +        if (found) {
       +                i = codepointtoutf8(found->cp, buf);
       +                buf[i] = '\0';
       +                return i;
       +        }
       +        return -1;
       +}
       +
       +static int
       +numericentitytostr(const char *e, char *buf, size_t bufsiz)
       +{
       +        long l;
       +        int len;
       +        char *end;
       +
       +        /* buffer is too small */
       +        if (bufsiz < 5)
       +                return -1;
       +
       +        errno = 0;
       +        /* hex (16) or decimal (10) */
       +        if (*e == 'x')
       +                l = strtol(++e, &end, 16);
       +        else
       +                l = strtol(e, &end, 10);
       +        /* invalid value or not a well-formed entity or invalid code point */
       +        if (errno || e == end || *end != ';' || l < 0 || l > 0x10ffff ||
       +            (l >= 0xd800 && l <= 0xdfff))
       +                return -1;
       +        len = codepointtoutf8(l, buf);
       +        buf[len] = '\0';
       +
       +        return len;
       +}
       +
       +/* convert named- or numeric entity string to buffer string
       + * returns byte-length of string or -1 on failure. */
       +int
       +xml_entitytostr(const char *e, char *buf, size_t bufsiz)
       +{
       +        /* doesn't start with & */
       +        if (e[0] != '&')
       +                return -1;
       +        /* numeric entity */
       +        if (e[1] == '#')
       +                return numericentitytostr(e + 2, buf, bufsiz);
       +        else /* named entity */
       +                return namedentitytostr(e + 1, buf, bufsiz);
       +}
       +
       +void
       +xml_parse(XMLParser *x)
       +{
       +        size_t datalen, tagdatalen;
       +        int c, isend;
       +
       +#ifdef HTML_MODE
       +        goto read_data;
       +#else
       +        /* HTML: process data before a tag occured aswell */
       +        while ((c = GETNEXT()) != EOF && c != '<')
       +                ; /* skip until < */
       +#endif
       +
       +        while (c != EOF) {
       +                if (c == '<') { /* parse tag */
       +                        if ((c = GETNEXT()) == EOF)
       +                                return;
       +
       +                        if (c == '!') { /* CDATA and comments */
       +                                for (tagdatalen = 0; (c = GETNEXT()) != EOF;) {
       +                                        /* NOTE: sizeof(x->data) must be at least sizeof("[CDATA[") */
       +                                        if (tagdatalen <= sizeof("[CDATA[") - 1)
       +                                                x->data[tagdatalen++] = c;
       +                                        if (c == '>')
       +                                                break;
       +                                        else if (c == '-' && tagdatalen == sizeof("--") - 1 &&
       +                                                        (x->data[0] == '-')) {
       +                                                xml_parsecomment(x);
       +                                                break;
       +                                        } else if (c == '[') {
       +                                                if (tagdatalen == sizeof("[CDATA[") - 1 &&
       +                                                    !strncmp(x->data, "[CDATA[", tagdatalen)) {
       +                                                        xml_parsecdata(x);
       +                                                        break;
       +                                                }
       +                                        }
       +                                }
       +                        } else {
       +                                /* normal tag (open, short open, close), processing instruction. */
       +                                x->tag[0] = c;
       +                                x->taglen = 1;
       +                                x->isshorttag = isend = 0;
       +
       +                                /* treat processing instruction as shorttag, don't strip "?" prefix. */
       +                                if (c == '?') {
       +                                        x->isshorttag = 1;
       +                                } else if (c == '/') {
       +                                        if ((c = GETNEXT()) == EOF)
       +                                                return;
       +                                        x->tag[0] = c;
       +                                        isend = 1;
       +                                }
       +
       +                                while ((c = GETNEXT()) != EOF) {
       +                                        if (c == '/')
       +                                                x->isshorttag = 1; /* short tag */
       +                                        else if (c == '>' || ISSPACE(c)) {
       +                                                x->tag[x->taglen] = '\0';
       +                                                if (isend) { /* end tag, starts with </ */
       +                                                        if (x->xmltagend)
       +                                                                x->xmltagend(x, x->tag, x->taglen, x->isshorttag);
       +                                                        x->tag[0] = '\0';
       +                                                        x->taglen = 0;
       +                                                } else {
       +                                                        /* start tag */
       +                                                        if (x->xmltagstart)
       +                                                                x->xmltagstart(x, x->tag, x->taglen);
       +                                                        if (ISSPACE(c))
       +                                                                xml_parseattrs(x);
       +                                                        if (x->xmltagstartparsed)
       +                                                                x->xmltagstartparsed(x, x->tag, x->taglen, x->isshorttag);
       +                                                }
       +                                                /* call tagend for shortform or processing instruction */
       +                                                if (x->isshorttag) {
       +                                                        if (x->xmltagend)
       +                                                                x->xmltagend(x, x->tag, x->taglen, x->isshorttag);
       +                                                        x->tag[0] = '\0';
       +                                                        x->taglen = 0;
       +                                                }
       +                                                break;
       +                                        } else if (x->taglen < sizeof(x->tag) - 1)
       +                                                x->tag[x->taglen++] = c; /* NOTE: tag name truncation */
       +                                }
       +                        }
       +                } else {
       +#ifdef HTML_MODE
       +read_data:
       +#endif
       +                        /* parse tag data */
       +                        datalen = 0;
       +                        if (x->xmldatastart)
       +                                x->xmldatastart(x);
       +                        while ((c = GETNEXT()) != EOF) {
       +                                if (c == '&') {
       +                                        if (datalen) {
       +                                                x->data[datalen] = '\0';
       +                                                if (x->xmldata)
       +                                                        x->xmldata(x, x->data, datalen);
       +                                        }
       +                                        x->data[0] = c;
       +                                        datalen = 1;
       +                                        while ((c = GETNEXT()) != EOF) {
       +                                                if (c == '<')
       +                                                        break;
       +                                                if (datalen < sizeof(x->data) - 1)
       +                                                        x->data[datalen++] = c;
       +                                                else {
       +                                                        /* entity too long for buffer, handle as normal data */
       +                                                        x->data[datalen] = '\0';
       +                                                        if (x->xmldata)
       +                                                                x->xmldata(x, x->data, datalen);
       +                                                        x->data[0] = c;
       +                                                        datalen = 1;
       +                                                        break;
       +                                                }
       +                                                if (c == ';') {
       +                                                        x->data[datalen] = '\0';
       +                                                        if (x->xmldataentity)
       +                                                                x->xmldataentity(x, x->data, datalen);
       +                                                        datalen = 0;
       +                                                        break;
       +                                                }
       +                                        }
       +                                } else if (c != '<') {
       +                                        if (datalen < sizeof(x->data) - 1) {
       +                                                x->data[datalen++] = c;
       +                                        } else {
       +                                                x->data[datalen] = '\0';
       +                                                if (x->xmldata)
       +                                                        x->xmldata(x, x->data, datalen);
       +                                                x->data[0] = c;
       +                                                datalen = 1;
       +                                        }
       +                                }
       +                                if (c == '<') {
       +                                        x->data[datalen] = '\0';
       +                                        if (x->xmldata && datalen)
       +                                                x->xmldata(x, x->data, datalen);
       +                                        if (x->xmldataend)
       +                                                x->xmldataend(x);
       +#ifdef HTML_MODE
       +                                        datalen = 0;
       +#endif
       +                                        break;
       +                                }
       +                        }
       +
       +#ifdef HTML_MODE
       +                        /* pending data, even if a tag didn't close (EOF, etc). */
       +                        if (datalen) {
       +                                x->data[datalen] = '\0';
       +                                if (x->xmldata && datalen)
       +                                        x->xmldata(x, x->data, datalen);
       +                                if (x->xmldataend)
       +                                        x->xmldataend(x);
       +                                datalen = 0;
       +                        }
       +#endif
       +                }
       +        }
       +}
 (DIR) diff --git a/xml.h b/xml.h
       @@ -0,0 +1,49 @@
       +#ifndef _XML_H_
       +#define _XML_H_
       +
       +#include <stdio.h>
       +
       +typedef struct xmlparser {
       +        /* handlers */
       +        void (*xmlattr)(struct xmlparser *, const char *, size_t,
       +              const char *, size_t, const char *, size_t);
       +        void (*xmlattrend)(struct xmlparser *, const char *, size_t,
       +              const char *, size_t);
       +        void (*xmlattrstart)(struct xmlparser *, const char *, size_t,
       +              const char *, size_t);
       +        void (*xmlattrentity)(struct xmlparser *, const char *, size_t,
       +              const char *, size_t, const char *, size_t);
       +        void (*xmlcdatastart)(struct xmlparser *);
       +        void (*xmlcdata)(struct xmlparser *, const char *, size_t);
       +        void (*xmlcdataend)(struct xmlparser *);
       +        void (*xmlcommentstart)(struct xmlparser *);
       +        void (*xmlcomment)(struct xmlparser *, const char *, size_t);
       +        void (*xmlcommentend)(struct xmlparser *);
       +        void (*xmldata)(struct xmlparser *, const char *, size_t);
       +        void (*xmldataend)(struct xmlparser *);
       +        void (*xmldataentity)(struct xmlparser *, const char *, size_t);
       +        void (*xmldatastart)(struct xmlparser *);
       +        void (*xmltagend)(struct xmlparser *, const char *, size_t, int);
       +        void (*xmltagstart)(struct xmlparser *, const char *, size_t);
       +        void (*xmltagstartparsed)(struct xmlparser *, const char *,
       +              size_t, int);
       +
       +#ifndef GETNEXT
       +        #define GETNEXT (x)->getnext
       +        int (*getnext)(void);
       +#endif
       +
       +        /* current tag */
       +        char tag[1024];
       +        size_t taglen;
       +        /* current tag is in shortform ? <tag /> */
       +        int isshorttag;
       +        /* current attribute name */
       +        char name[1024];
       +        /* data buffer used for tag data, CDATA and attribute data */
       +        char data[BUFSIZ];
       +} XMLParser;
       +
       +int xml_entitytostr(const char *, char *, size_t);
       +void xml_parse(XMLParser *);
       +#endif