/*
   This file was generated by

   ./tools/make-c-file.pl
*/
#include <limits.h>
#include <locale.h>
#include "tidy-html5.h"
#ifndef __FORWARD_H__
#define __FORWARD_H__

/* forward.h -- Forward declarations for major Tidy structures

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Avoids many include file circular dependencies.

  Try to keep this file down to the minimum to avoid
  cross-talk between modules.

  Header files include this file.  C files include tidy-int.h.

*/

/* #include "tidyplatform.h" */
/* #include "tidy.h" */

/* Internal symbols are prefixed to avoid clashes with other libraries */
#define TYDYAPPEND(str1,str2) str1##str2
#define TY_(str) TYDYAPPEND(prvTidy,str)

struct _StreamIn;
typedef struct _StreamIn StreamIn;

struct _StreamOut;
typedef struct _StreamOut StreamOut;

struct _TidyDocImpl;
typedef struct _TidyDocImpl TidyDocImpl;

struct _TidyMessageImpl;
typedef struct _TidyMessageImpl TidyMessageImpl;

/* @todo: this name isn't very instructive! */
struct _Dict;
typedef struct _Dict Dict;

struct _Attribute;
typedef struct _Attribute Attribute;

struct _AttVal;
typedef struct _AttVal AttVal;

struct _Node;
typedef struct _Node Node;

struct _IStack;
typedef struct _IStack IStack;

struct _Lexer;
typedef struct _Lexer Lexer;

extern TidyAllocator TY_(g_default_allocator);

/** Wrappers for easy memory allocation using an allocator */
#define TidyAlloc(allocator, size) ((allocator)->vtbl->alloc((allocator), (size)))
#define TidyRealloc(allocator, block, size) ((allocator)->vtbl->realloc((allocator), (block), (size)))
#define TidyFree(allocator, block) ((allocator)->vtbl->free((allocator), (block)))
#define TidyPanic(allocator, msg) ((allocator)->vtbl->panic((allocator), (msg)))
#define TidyClearMemory(block, size) memset((block), 0, (size))
 

#endif /* __FORWARD_H__ */
#ifndef __ACCESS_H__
#define __ACCESS_H__

/*********************************************************************
 * carry out accessibility checks
 *
 * This module carries out processes for all accessibility checks. It
 * traverses through all the content within the tree and evaluates the
 * tags for accessibility.
 *
 * To perform the following checks, 'AccessibilityChecks' must be
 * called AFTER the tree structure has been formed.
 *
 * If, in the command prompt or configuration file, there is no
 * specification of which accessibility priorities to check, then no
 * accessibility checks will be performed.
 *
 * The accessibility checks to perform depending on user's desire:
 *   1. priority 1
 *   2. priority 1 & 2
 *   3. priority 1, 2, & 3
 *
 * Reference document: http://www.w3.org/TR/WAI-WEBCONTENT/
 *
 * Copyright University of Toronto
 * Portions (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
 * See `tidy.h` for the copyright notice.
 * Programmed by: Mike Lam and Chris Ridpath
 * Modifications by: Terry Teague (TRT)
 * Further modifications: consult git log.
 *********************************************************************/

/* #include "forward.h" */


enum {
  TEXTBUF_SIZE=128u
};

struct _TidyAccessImpl;
typedef struct _TidyAccessImpl TidyAccessImpl;

struct _TidyAccessImpl
{
    /* gets set from Tidy variable AccessibilityCheckLevel */
    int PRIORITYCHK; /**< */

    /* Number of characters that are found within the concatenated text */
    int counter;

    /* list of characters in the text nodes found within a container element */
    tmbchar textNode[ TEXTBUF_SIZE ]; 

    /* The list of characters found within one text node */
    tmbchar text[ TEXTBUF_SIZE ]; 

    /* Number of frame elements found within a frameset */
    int numFrames; 

    /* Number of 'longdesc' attributes found within a frameset */
    int HasCheckedLongDesc; 

    int  CheckedHeaders;
    int  ListElements;
    int  OtherListElements;

    /* For 'USEMAP' identifier */
    Bool HasUseMap; 
    Bool HasName; 
    Bool HasMap;

    /* For tracking nodes that are deleted from the original parse tree - TRT */
    /* Node *access_tree; */

    Bool HasTH;
    Bool HasValidFor;
    Bool HasValidId;
    Bool HasValidRowHeaders;
    Bool HasValidColumnHeaders;
    Bool HasInvalidRowHeader;
    Bool HasInvalidColumnHeader;
    int  ForID;

};


void TY_(AccessibilityChecks)( TidyDocImpl* doc );


#endif /* __ACCESS_H__ */
#ifndef __ATTRDICT_H__
#define __ATTRDICT_H__

/* attrdict.h -- extended attribute information

   (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
   See tidy.h for the copyright notice.

*/

/* #include "tidy.h" */

typedef struct _AttrVersion
{
    TidyAttrId attribute;
    unsigned int versions;
} AttrVersion;

extern const AttrVersion TY_(W3CAttrsFor_A)[];
extern const AttrVersion TY_(W3CAttrsFor_ABBR)[];
extern const AttrVersion TY_(W3CAttrsFor_ACRONYM)[];
extern const AttrVersion TY_(W3CAttrsFor_ADDRESS)[];
extern const AttrVersion TY_(W3CAttrsFor_APPLET)[];
extern const AttrVersion TY_(W3CAttrsFor_AREA)[];
extern const AttrVersion TY_(W3CAttrsFor_B)[];
extern const AttrVersion TY_(W3CAttrsFor_BASE)[];
extern const AttrVersion TY_(W3CAttrsFor_BASEFONT)[];
extern const AttrVersion TY_(W3CAttrsFor_BDO)[];
extern const AttrVersion TY_(W3CAttrsFor_BIG)[];
extern const AttrVersion TY_(W3CAttrsFor_BLOCKQUOTE)[];
extern const AttrVersion TY_(W3CAttrsFor_BODY)[];
extern const AttrVersion TY_(W3CAttrsFor_BR)[];
extern const AttrVersion TY_(W3CAttrsFor_BUTTON)[];
extern const AttrVersion TY_(W3CAttrsFor_CAPTION)[];
extern const AttrVersion TY_(W3CAttrsFor_CENTER)[];
extern const AttrVersion TY_(W3CAttrsFor_CITE)[];
extern const AttrVersion TY_(W3CAttrsFor_CODE)[];
extern const AttrVersion TY_(W3CAttrsFor_COL)[];
extern const AttrVersion TY_(W3CAttrsFor_COLGROUP)[];
extern const AttrVersion TY_(W3CAttrsFor_DD)[];
extern const AttrVersion TY_(W3CAttrsFor_DEL)[];
extern const AttrVersion TY_(W3CAttrsFor_DFN)[];
extern const AttrVersion TY_(W3CAttrsFor_DIR)[];
extern const AttrVersion TY_(W3CAttrsFor_DIV)[];
extern const AttrVersion TY_(W3CAttrsFor_DL)[];
extern const AttrVersion TY_(W3CAttrsFor_DT)[];
extern const AttrVersion TY_(W3CAttrsFor_EM)[];
extern const AttrVersion TY_(W3CAttrsFor_FIELDSET)[];
extern const AttrVersion TY_(W3CAttrsFor_FONT)[];
extern const AttrVersion TY_(W3CAttrsFor_FORM)[];
extern const AttrVersion TY_(W3CAttrsFor_FRAME)[];
extern const AttrVersion TY_(W3CAttrsFor_FRAMESET)[];
extern const AttrVersion TY_(W3CAttrsFor_H1)[];
extern const AttrVersion TY_(W3CAttrsFor_H2)[];
extern const AttrVersion TY_(W3CAttrsFor_H3)[];
extern const AttrVersion TY_(W3CAttrsFor_H4)[];
extern const AttrVersion TY_(W3CAttrsFor_H5)[];
extern const AttrVersion TY_(W3CAttrsFor_H6)[];
extern const AttrVersion TY_(W3CAttrsFor_HEAD)[];
extern const AttrVersion TY_(W3CAttrsFor_HR)[];
extern const AttrVersion TY_(W3CAttrsFor_HTML)[];
extern const AttrVersion TY_(W3CAttrsFor_I)[];
extern const AttrVersion TY_(W3CAttrsFor_IFRAME)[];
extern const AttrVersion TY_(W3CAttrsFor_IMG)[];
extern const AttrVersion TY_(W3CAttrsFor_INPUT)[];
extern const AttrVersion TY_(W3CAttrsFor_INS)[];
extern const AttrVersion TY_(W3CAttrsFor_ISINDEX)[];
extern const AttrVersion TY_(W3CAttrsFor_KBD)[];
extern const AttrVersion TY_(W3CAttrsFor_LABEL)[];
extern const AttrVersion TY_(W3CAttrsFor_LEGEND)[];
extern const AttrVersion TY_(W3CAttrsFor_LI)[];
extern const AttrVersion TY_(W3CAttrsFor_LINK)[];
extern const AttrVersion TY_(W3CAttrsFor_LISTING)[];
extern const AttrVersion TY_(W3CAttrsFor_MAP)[];
extern const AttrVersion TY_(W3CAttrsFor_MATHML)[]; /* [i_a]2 */
extern const AttrVersion TY_(W3CAttrsFor_MENU)[];
extern const AttrVersion TY_(W3CAttrsFor_META)[];
extern const AttrVersion TY_(W3CAttrsFor_NEXTID)[];
extern const AttrVersion TY_(W3CAttrsFor_NOFRAMES)[];
extern const AttrVersion TY_(W3CAttrsFor_NOSCRIPT)[];
extern const AttrVersion TY_(W3CAttrsFor_OBJECT)[];
extern const AttrVersion TY_(W3CAttrsFor_OL)[];
extern const AttrVersion TY_(W3CAttrsFor_OPTGROUP)[];
extern const AttrVersion TY_(W3CAttrsFor_OPTION)[];
extern const AttrVersion TY_(W3CAttrsFor_P)[];
extern const AttrVersion TY_(W3CAttrsFor_PARAM)[];
extern const AttrVersion TY_(W3CAttrsFor_PICTURE)[]; /* Issue #151 - html5 */
extern const AttrVersion TY_(W3CAttrsFor_PLAINTEXT)[];
extern const AttrVersion TY_(W3CAttrsFor_PRE)[];
extern const AttrVersion TY_(W3CAttrsFor_Q)[];
extern const AttrVersion TY_(W3CAttrsFor_RB)[];
extern const AttrVersion TY_(W3CAttrsFor_RBC)[];
extern const AttrVersion TY_(W3CAttrsFor_RP)[];
extern const AttrVersion TY_(W3CAttrsFor_RT)[];
extern const AttrVersion TY_(W3CAttrsFor_RTC)[];
extern const AttrVersion TY_(W3CAttrsFor_RUBY)[];
extern const AttrVersion TY_(W3CAttrsFor_S)[];
extern const AttrVersion TY_(W3CAttrsFor_SAMP)[];
extern const AttrVersion TY_(W3CAttrsFor_SCRIPT)[];
extern const AttrVersion TY_(W3CAttrsFor_SELECT)[];
extern const AttrVersion TY_(W3CAttrsFor_SMALL)[];
extern const AttrVersion TY_(W3CAttrsFor_SPAN)[];
extern const AttrVersion TY_(W3CAttrsFor_STRIKE)[];
extern const AttrVersion TY_(W3CAttrsFor_STRONG)[];
extern const AttrVersion TY_(W3CAttrsFor_STYLE)[];
extern const AttrVersion TY_(W3CAttrsFor_SUB)[];
extern const AttrVersion TY_(W3CAttrsFor_SUP)[];
extern const AttrVersion TY_(W3CAttrsFor_SVG)[];
extern const AttrVersion TY_(W3CAttrsFor_TABLE)[];
extern const AttrVersion TY_(W3CAttrsFor_TBODY)[];
extern const AttrVersion TY_(W3CAttrsFor_TD)[];
extern const AttrVersion TY_(W3CAttrsFor_TEXTAREA)[];
extern const AttrVersion TY_(W3CAttrsFor_TFOOT)[];
extern const AttrVersion TY_(W3CAttrsFor_TH)[];
extern const AttrVersion TY_(W3CAttrsFor_THEAD)[];
extern const AttrVersion TY_(W3CAttrsFor_TITLE)[];
extern const AttrVersion TY_(W3CAttrsFor_TR)[];
extern const AttrVersion TY_(W3CAttrsFor_TT)[];
extern const AttrVersion TY_(W3CAttrsFor_U)[];
extern const AttrVersion TY_(W3CAttrsFor_UL)[];
extern const AttrVersion TY_(W3CAttrsFor_VAR)[];
extern const AttrVersion TY_(W3CAttrsFor_XMP)[];

extern const AttrVersion TY_(W3CAttrsFor_TRACK)[];
extern const AttrVersion TY_(W3CAttrsFor_SUMMARY)[];
extern const AttrVersion TY_(W3CAttrsFor_FIGCAPTION)[];
extern const AttrVersion TY_(W3CAttrsFor_HGROUP)[];
extern const AttrVersion TY_(W3CAttrsFor_FIGURE)[];
extern const AttrVersion TY_(W3CAttrsFor_ARTICLE)[];
extern const AttrVersion TY_(W3CAttrsFor_ASIDE)[];
extern const AttrVersion TY_(W3CAttrsFor_BDI)[];
extern const AttrVersion TY_(W3CAttrsFor_NAV)[];
extern const AttrVersion TY_(W3CAttrsFor_SECTION)[];
extern const AttrVersion TY_(W3CAttrsFor_FOOTER)[];
extern const AttrVersion TY_(W3CAttrsFor_HEADER)[];
extern const AttrVersion TY_(W3CAttrsFor_DETAILS)[];
extern const AttrVersion TY_(W3CAttrsFor_DIALOG)[];
extern const AttrVersion TY_(W3CAttrsFor_COMMAND)[];
extern const AttrVersion TY_(W3CAttrsFor_MAIN)[];
extern const AttrVersion TY_(W3CAttrsFor_MARK)[];
extern const AttrVersion TY_(W3CAttrsFor_OUTPUT)[];
extern const AttrVersion TY_(W3CAttrsFor_MENUITEM)[];
extern const AttrVersion TY_(W3CAttrsFor_METER)[];
extern const AttrVersion TY_(W3CAttrsFor_PROGRESS)[];
extern const AttrVersion TY_(W3CAttrsFor_TEMPLATE)[];
extern const AttrVersion TY_(W3CAttrsFor_TIME)[];
extern const AttrVersion TY_(W3CAttrsFor_DATA)[];
extern const AttrVersion TY_(W3CAttrsFor_DATALIST)[];
extern const AttrVersion TY_(W3CAttrsFor_AUDIO)[];
extern const AttrVersion TY_(W3CAttrsFor_VIDEO)[];
extern const AttrVersion TY_(W3CAttrsFor_CANVAS)[];
extern const AttrVersion TY_(W3CAttrsFor_SOURCE)[];
extern const AttrVersion TY_(W3CAttrsFor_EMBED)[];
extern const AttrVersion TY_(W3CAttrsFor_KEYGEN)[];
extern const AttrVersion TY_(W3CAttrsFor_WBR)[];

#endif /* __ATTRDICT_H__ */
#ifndef __ATTRS_H__
#define __ATTRS_H__

/* attrs.h -- recognize HTML attributes

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "forward.h" */

/* declaration for methods that check attribute values */
typedef void (AttrCheck)(TidyDocImpl* doc, Node *node, AttVal *attval);

struct _Attribute
{
    TidyAttrId  id;
    tmbstr      name;
    AttrCheck*  attrchk;

    struct _Attribute* next;
};


/*
 Anchor/Node linked list
*/

struct _Anchor
{
    struct _Anchor *next;
    Node *node;
    char *name;
};

typedef struct _Anchor Anchor;

enum
{
    ATTRIBUTE_HASH_SIZE=178u
};

struct _AttrHash
{
    Attribute const*  attr;
    struct _AttrHash* next;
};

typedef struct _AttrHash AttrHash;

enum
{
    ANCHOR_HASH_SIZE=1021u
};

/* Keeps a list of attributes that are sorted ahead of the others. */
typedef struct _priorityAttribs {
    tmbstr* list;
    unsigned int count;
    unsigned int capacity;
} PriorityAttribs;

struct _TidyAttribImpl
{
    /* anchor/node lookup */
    Anchor*    anchor_hash[ANCHOR_HASH_SIZE];

    /* Declared literal attributes */
    Attribute* declared_attr_list;

    /* Prioritized list of attributes to write */
    PriorityAttribs priorityAttribs;

    AttrHash*  hashtab[ATTRIBUTE_HASH_SIZE];
};

typedef struct _TidyAttribImpl TidyAttribImpl;

#define XHTML_NAMESPACE "http://www.w3.org/1999/xhtml"

AttrCheck TY_(CheckUrl);

/* public method for finding attribute definition by name */
const Attribute* TY_(CheckAttribute)( TidyDocImpl* doc, Node *node, AttVal *attval );

const Attribute* TY_(FindAttribute)( TidyDocImpl* doc, AttVal *attval );

AttVal* TY_(GetAttrByName)( Node *node, ctmbstr name );

void TY_(DropAttrByName)( TidyDocImpl* doc, Node *node, ctmbstr name );

AttVal* TY_(AddAttribute)( TidyDocImpl* doc,
                           Node *node, ctmbstr name, ctmbstr value );

AttVal* TY_(RepairAttrValue)(TidyDocImpl* doc, Node* node, ctmbstr name, ctmbstr value);

/* Add an item to the list of priority attributes to write first. */
void TY_(DefinePriorityAttribute)(TidyDocImpl* doc, ctmbstr name);

/* Start an iterator for priority attributes. */
TidyIterator TY_(getPriorityAttrList)( TidyDocImpl* doc );

/* Get the next priority attribute. */
ctmbstr TY_(getNextPriorityAttr)( TidyDocImpl* doc, TidyIterator* iter );

Bool TY_(IsUrl)( TidyDocImpl* doc, ctmbstr attrname );

/* Bool IsBool( TidyDocImpl* doc, ctmbstr attrname ); */

Bool TY_(IsScript)( TidyDocImpl* doc, ctmbstr attrname );

/* may id or name serve as anchor? */
Bool TY_(IsAnchorElement)( TidyDocImpl* doc, Node* node );

/*
  In CSS1, selectors can contain only the characters A-Z, 0-9, and
  Unicode characters 161-255, plus dash (-); they cannot start with
  a dash or a digit; they can also contain escaped characters and any
  Unicode character as a numeric code (see next item).

  The backslash followed by at most four hexadecimal digits (0..9A..F)
  stands for the Unicode character with that number.

  Any character except a hexadecimal digit can be escaped to remove its
  special meaning, by putting a backslash in front.

  #508936 - CSS class naming for -clean option
*/
Bool TY_(IsCSS1Selector)( ctmbstr buf );

Bool TY_(IsValidHTMLID)(ctmbstr id);
Bool TY_(IsValidXMLID)(ctmbstr id);

/* removes anchor for specific node */
void TY_(RemoveAnchorByNode)( TidyDocImpl* doc, ctmbstr name, Node *node );

/* free all anchors */
void TY_(FreeAnchors)( TidyDocImpl* doc );


/* public methods for inititializing/freeing attribute dictionary */
void TY_(InitAttrs)( TidyDocImpl* doc );
void TY_(FreeAttrTable)( TidyDocImpl* doc );

void TY_(FreeAttrPriorityList)( TidyDocImpl* doc );

void TY_(AppendToClassAttr)( TidyDocImpl* doc, AttVal *classattr, ctmbstr classname );
/*
 the same attribute name can't be used
 more than once in each element
*/
void TY_(RepairDuplicateAttributes)( TidyDocImpl* doc, Node* node, Bool isXml );
void TY_(SortAttributes)(TidyDocImpl* doc, Node* node, TidyAttrSortStrategy strat);

Bool TY_(IsBoolAttribute)( AttVal* attval );
Bool TY_(attrIsEvent)( AttVal* attval );

AttVal* TY_(AttrGetById)( Node* node, TidyAttrId id );

unsigned int TY_(NodeAttributeVersions)( Node* node, TidyAttrId id );

Bool TY_(AttributeIsProprietary)(Node* node, AttVal* attval);
Bool TY_(AttributeIsMismatched)(Node* node, AttVal* attval, TidyDocImpl* doc);


/* 0 == TidyAttr_UNKNOWN  */
#define AttrId(av) ((av) && (av)->dict ? (av)->dict->id : TidyAttr_UNKNOWN)
#define AttrIsId(av, atid) ((av) && (av)->dict && ((av)->dict->id == atid))

#define AttrHasValue(attr)      ((attr) && (attr)->value)
#define AttrValueIs(attr, val)  (AttrHasValue(attr) && \
                                 TY_(tmbstrcasecmp)((attr)->value, val) == 0)
#define AttrContains(attr, val) (AttrHasValue(attr) && \
                                 TY_(tmbsubstr)((attr)->value, val) != NULL)
#define AttrVersions(attr)      ((attr) && (attr)->dict ? (attr)->dict->versions : VERS_PROPRIETARY)

#define AttrsHaveSameId(a, b) (a && b && a->dict && b->dict && a->dict->id && \
                               b->dict->id && a->dict->id == b->dict->id)

#define attrIsABBR(av)              AttrIsId( av, TidyAttr_ABBR  )
#define attrIsACCEPT(av)            AttrIsId( av, TidyAttr_ACCEPT  )
#define attrIsACCEPT_CHARSET(av)    AttrIsId( av, TidyAttr_ACCEPT_CHARSET  )
#define attrIsACCESSKEY(av)         AttrIsId( av, TidyAttr_ACCESSKEY  )
#define attrIsACTION(av)            AttrIsId( av, TidyAttr_ACTION  )
#define attrIsADD_DATE(av)          AttrIsId( av, TidyAttr_ADD_DATE  )
#define attrIsALIGN(av)             AttrIsId( av, TidyAttr_ALIGN  )
#define attrIsALINK(av)             AttrIsId( av, TidyAttr_ALINK  )
#define attrIsALT(av)               AttrIsId( av, TidyAttr_ALT  )
#define attrIsARCHIVE(av)           AttrIsId( av, TidyAttr_ARCHIVE  )
#define attrIsAXIS(av)              AttrIsId( av, TidyAttr_AXIS  )
#define attrIsBACKGROUND(av)        AttrIsId( av, TidyAttr_BACKGROUND  )
#define attrIsBGCOLOR(av)           AttrIsId( av, TidyAttr_BGCOLOR  )
#define attrIsBGPROPERTIES(av)      AttrIsId( av, TidyAttr_BGPROPERTIES  )
#define attrIsBORDER(av)            AttrIsId( av, TidyAttr_BORDER  )
#define attrIsBORDERCOLOR(av)       AttrIsId( av, TidyAttr_BORDERCOLOR  )
#define attrIsBOTTOMMARGIN(av)      AttrIsId( av, TidyAttr_BOTTOMMARGIN  )
#define attrIsCELLPADDING(av)       AttrIsId( av, TidyAttr_CELLPADDING  )
#define attrIsCELLSPACING(av)       AttrIsId( av, TidyAttr_CELLSPACING  )
#define attrIsCHARSET(av)           AttrIsId( av, TidyAttr_CHARSET  )
#define attrIsCHAR(av)              AttrIsId( av, TidyAttr_CHAR  )
#define attrIsCHAROFF(av)           AttrIsId( av, TidyAttr_CHAROFF  )
#define attrIsCHARSET(av)           AttrIsId( av, TidyAttr_CHARSET  )
#define attrIsCHECKED(av)           AttrIsId( av, TidyAttr_CHECKED  )
#define attrIsCITE(av)              AttrIsId( av, TidyAttr_CITE  )
#define attrIsCLASS(av)             AttrIsId( av, TidyAttr_CLASS  )
#define attrIsCLASSID(av)           AttrIsId( av, TidyAttr_CLASSID  )
#define attrIsCLEAR(av)             AttrIsId( av, TidyAttr_CLEAR  )
#define attrIsCODE(av)              AttrIsId( av, TidyAttr_CODE  )
#define attrIsCODEBASE(av)          AttrIsId( av, TidyAttr_CODEBASE  )
#define attrIsCODETYPE(av)          AttrIsId( av, TidyAttr_CODETYPE  )
#define attrIsCOLOR(av)             AttrIsId( av, TidyAttr_COLOR  )
#define attrIsCOLS(av)              AttrIsId( av, TidyAttr_COLS  )
#define attrIsCOLSPAN(av)           AttrIsId( av, TidyAttr_COLSPAN  )
#define attrIsCOMPACT(av)           AttrIsId( av, TidyAttr_COMPACT  )
#define attrIsCONTENT(av)           AttrIsId( av, TidyAttr_CONTENT  )
#define attrIsCOORDS(av)            AttrIsId( av, TidyAttr_COORDS  )
#define attrIsDATA(av)              AttrIsId( av, TidyAttr_DATA  )
#define attrIsDATAFLD(av)           AttrIsId( av, TidyAttr_DATAFLD  )
#define attrIsDATAFORMATAS(av)      AttrIsId( av, TidyAttr_DATAFORMATAS  )
#define attrIsDATAPAGESIZE(av)      AttrIsId( av, TidyAttr_DATAPAGESIZE  )
#define attrIsDATASRC(av)           AttrIsId( av, TidyAttr_DATASRC  )
#define attrIsDATETIME(av)          AttrIsId( av, TidyAttr_DATETIME  )
#define attrIsDECLARE(av)           AttrIsId( av, TidyAttr_DECLARE  )
#define attrIsDEFER(av)             AttrIsId( av, TidyAttr_DEFER  )
#define attrIsDIR(av)               AttrIsId( av, TidyAttr_DIR  )
#define attrIsDISABLED(av)          AttrIsId( av, TidyAttr_DISABLED  )
#define attrIsENCODING(av)          AttrIsId( av, TidyAttr_ENCODING  )
#define attrIsENCTYPE(av)           AttrIsId( av, TidyAttr_ENCTYPE  )
#define attrIsFACE(av)              AttrIsId( av, TidyAttr_FACE  )
#define attrIsFOR(av)               AttrIsId( av, TidyAttr_FOR  )
#define attrIsFRAME(av)             AttrIsId( av, TidyAttr_FRAME  )
#define attrIsFRAMEBORDER(av)       AttrIsId( av, TidyAttr_FRAMEBORDER  )
#define attrIsFRAMESPACING(av)      AttrIsId( av, TidyAttr_FRAMESPACING  )
#define attrIsGRIDX(av)             AttrIsId( av, TidyAttr_GRIDX  )
#define attrIsGRIDY(av)             AttrIsId( av, TidyAttr_GRIDY  )
#define attrIsHEADERS(av)           AttrIsId( av, TidyAttr_HEADERS  )
#define attrIsHEIGHT(av)            AttrIsId( av, TidyAttr_HEIGHT  )
#define attrIsHREF(av)              AttrIsId( av, TidyAttr_HREF  )
#define attrIsHREFLANG(av)          AttrIsId( av, TidyAttr_HREFLANG  )
#define attrIsHSPACE(av)            AttrIsId( av, TidyAttr_HSPACE  )
#define attrIsHTTP_EQUIV(av)        AttrIsId( av, TidyAttr_HTTP_EQUIV  )
#define attrIsID(av)                AttrIsId( av, TidyAttr_ID  )
#define attrIsISMAP(av)             AttrIsId( av, TidyAttr_ISMAP  )
#define attrIsITEMID(av)            AttrIsId( av, TidyAttr_ITEMID  )
#define attrIsITEMPROP(av)          AttrIsId( av, TidyAttr_ITEMPROP  )
#define attrIsITEMREF(av)           AttrIsId( av, TidyAttr_ITEMREF  )
#define attrIsITEMSCOPE(av)         AttrIsId( av, TidyAttr_ITEMSCOPE  )
#define attrIsITEMTYPE(av)          AttrIsId( av, TidyAttr_ITEMTYPE  )
#define attrIsLABEL(av)             AttrIsId( av, TidyAttr_LABEL  )
#define attrIsLANG(av)              AttrIsId( av, TidyAttr_LANG  )
#define attrIsLANGUAGE(av)          AttrIsId( av, TidyAttr_LANGUAGE  )
#define attrIsLAST_MODIFIED(av)     AttrIsId( av, TidyAttr_LAST_MODIFIED  )
#define attrIsLAST_VISIT(av)        AttrIsId( av, TidyAttr_LAST_VISIT  )
#define attrIsLEFTMARGIN(av)        AttrIsId( av, TidyAttr_LEFTMARGIN  )
#define attrIsLINK(av)              AttrIsId( av, TidyAttr_LINK  )
#define attrIsLONGDESC(av)          AttrIsId( av, TidyAttr_LONGDESC  )
#define attrIsLOWSRC(av)            AttrIsId( av, TidyAttr_LOWSRC  )
#define attrIsMARGINHEIGHT(av)      AttrIsId( av, TidyAttr_MARGINHEIGHT  )
#define attrIsMARGINWIDTH(av)       AttrIsId( av, TidyAttr_MARGINWIDTH  )
#define attrIsMAXLENGTH(av)         AttrIsId( av, TidyAttr_MAXLENGTH  )
#define attrIsMEDIA(av)             AttrIsId( av, TidyAttr_MEDIA  )
#define attrIsMETHOD(av)            AttrIsId( av, TidyAttr_METHOD  )
#define attrIsMULTIPLE(av)          AttrIsId( av, TidyAttr_MULTIPLE  )
#define attrIsNAME(av)              AttrIsId( av, TidyAttr_NAME  )
#define attrIsNOHREF(av)            AttrIsId( av, TidyAttr_NOHREF  )
#define attrIsNORESIZE(av)          AttrIsId( av, TidyAttr_NORESIZE  )
#define attrIsNOSHADE(av)           AttrIsId( av, TidyAttr_NOSHADE  )
#define attrIsNOWRAP(av)            AttrIsId( av, TidyAttr_NOWRAP  )
#define attrIsOBJECT(av)            AttrIsId( av, TidyAttr_OBJECT  )
#define attrIsOnAFTERUPDATE(av)     AttrIsId( av, TidyAttr_OnAFTERUPDATE  )
#define attrIsOnBEFOREUNLOAD(av)    AttrIsId( av, TidyAttr_OnBEFOREUNLOAD  )
#define attrIsOnBEFOREUPDATE(av)    AttrIsId( av, TidyAttr_OnBEFOREUPDATE  )
#define attrIsOnBLUR(av)            AttrIsId( av, TidyAttr_OnBLUR  )
#define attrIsOnCHANGE(av)          AttrIsId( av, TidyAttr_OnCHANGE  )
#define attrIsOnCLICK(av)           AttrIsId( av, TidyAttr_OnCLICK  )
#define attrIsOnDATAAVAILABLE(av)   AttrIsId( av, TidyAttr_OnDATAAVAILABLE  )
#define attrIsOnDATASETCHANGED(av)  AttrIsId( av, TidyAttr_OnDATASETCHANGED  )
#define attrIsOnDATASETCOMPLETE(av) AttrIsId( av, TidyAttr_OnDATASETCOMPLETE  )
#define attrIsOnDBLCLICK(av)        AttrIsId( av, TidyAttr_OnDBLCLICK  )
#define attrIsOnERRORUPDATE(av)     AttrIsId( av, TidyAttr_OnERRORUPDATE  )
#define attrIsOnFOCUS(av)           AttrIsId( av, TidyAttr_OnFOCUS  )
#define attrIsOnKEYDOWN(av)         AttrIsId( av, TidyAttr_OnKEYDOWN  )
#define attrIsOnKEYPRESS(av)        AttrIsId( av, TidyAttr_OnKEYPRESS  )
#define attrIsOnKEYUP(av)           AttrIsId( av, TidyAttr_OnKEYUP  )
#define attrIsOnLOAD(av)            AttrIsId( av, TidyAttr_OnLOAD  )
#define attrIsOnMOUSEDOWN(av)       AttrIsId( av, TidyAttr_OnMOUSEDOWN  )
#define attrIsOnMOUSEMOVE(av)       AttrIsId( av, TidyAttr_OnMOUSEMOVE  )
#define attrIsOnMOUSEOUT(av)        AttrIsId( av, TidyAttr_OnMOUSEOUT  )
#define attrIsOnMOUSEOVER(av)       AttrIsId( av, TidyAttr_OnMOUSEOVER  )
#define attrIsOnMOUSEUP(av)         AttrIsId( av, TidyAttr_OnMOUSEUP  )
#define attrIsOnRESET(av)           AttrIsId( av, TidyAttr_OnRESET  )
#define attrIsOnROWENTER(av)        AttrIsId( av, TidyAttr_OnROWENTER  )
#define attrIsOnROWEXIT(av)         AttrIsId( av, TidyAttr_OnROWEXIT  )
#define attrIsOnSELECT(av)          AttrIsId( av, TidyAttr_OnSELECT  )
#define attrIsOnSUBMIT(av)          AttrIsId( av, TidyAttr_OnSUBMIT  )
#define attrIsOnUNLOAD(av)          AttrIsId( av, TidyAttr_OnUNLOAD  )
#define attrIsPROFILE(av)           AttrIsId( av, TidyAttr_PROFILE  )
#define attrIsPROMPT(av)            AttrIsId( av, TidyAttr_PROMPT  )
#define attrIsRBSPAN(av)            AttrIsId( av, TidyAttr_RBSPAN  )
#define attrIsREADONLY(av)          AttrIsId( av, TidyAttr_READONLY  )
#define attrIsREL(av)               AttrIsId( av, TidyAttr_REL  )
#define attrIsREV(av)               AttrIsId( av, TidyAttr_REV  )
#define attrIsRIGHTMARGIN(av)       AttrIsId( av, TidyAttr_RIGHTMARGIN  )
#define attrIsROLE(av)              AttrIsId( av, TidyAttr_ROLE  )
#define attrIsROWS(av)              AttrIsId( av, TidyAttr_ROWS  )
#define attrIsROWSPAN(av)           AttrIsId( av, TidyAttr_ROWSPAN  )
#define attrIsRULES(av)             AttrIsId( av, TidyAttr_RULES  )
#define attrIsSCHEME(av)            AttrIsId( av, TidyAttr_SCHEME  )
#define attrIsSCOPE(av)             AttrIsId( av, TidyAttr_SCOPE  )
#define attrIsSCROLLING(av)         AttrIsId( av, TidyAttr_SCROLLING  )
#define attrIsSELECTED(av)          AttrIsId( av, TidyAttr_SELECTED  )
#define attrIsSHAPE(av)             AttrIsId( av, TidyAttr_SHAPE  )
#define attrIsSHOWGRID(av)          AttrIsId( av, TidyAttr_SHOWGRID  )
#define attrIsSHOWGRIDX(av)         AttrIsId( av, TidyAttr_SHOWGRIDX  )
#define attrIsSHOWGRIDY(av)         AttrIsId( av, TidyAttr_SHOWGRIDY  )
#define attrIsSIZE(av)              AttrIsId( av, TidyAttr_SIZE  )
#define attrIsSPAN(av)              AttrIsId( av, TidyAttr_SPAN  )
#define attrIsSRC(av)               AttrIsId( av, TidyAttr_SRC  )
#define attrIsSTANDBY(av)           AttrIsId( av, TidyAttr_STANDBY  )
#define attrIsSTART(av)             AttrIsId( av, TidyAttr_START  )
#define attrIsSTYLE(av)             AttrIsId( av, TidyAttr_STYLE  )
#define attrIsSUMMARY(av)           AttrIsId( av, TidyAttr_SUMMARY  )
#define attrIsTABINDEX(av)          AttrIsId( av, TidyAttr_TABINDEX  )
#define attrIsTARGET(av)            AttrIsId( av, TidyAttr_TARGET  )
#define attrIsTEXT(av)              AttrIsId( av, TidyAttr_TEXT  )
#define attrIsTITLE(av)             AttrIsId( av, TidyAttr_TITLE  )
#define attrIsTOPMARGIN(av)         AttrIsId( av, TidyAttr_TOPMARGIN  )
#define attrIsTYPE(av)              AttrIsId( av, TidyAttr_TYPE  )
#define attrIsUSEMAP(av)            AttrIsId( av, TidyAttr_USEMAP  )
#define attrIsVALIGN(av)            AttrIsId( av, TidyAttr_VALIGN  )
#define attrIsVALUE(av)             AttrIsId( av, TidyAttr_VALUE  )
#define attrIsVALUETYPE(av)         AttrIsId( av, TidyAttr_VALUETYPE  )
#define attrIsVERSION(av)           AttrIsId( av, TidyAttr_VERSION  )
#define attrIsVLINK(av)             AttrIsId( av, TidyAttr_VLINK  )
#define attrIsVSPACE(av)            AttrIsId( av, TidyAttr_VSPACE  )
#define attrIsWIDTH(av)             AttrIsId( av, TidyAttr_WIDTH  )
#define attrIsWRAP(av)              AttrIsId( av, TidyAttr_WRAP  )
#define attrIsXMLNS(av)             AttrIsId( av, TidyAttr_XMLNS  )
#define attrIsXML_LANG(av)          AttrIsId( av, TidyAttr_XML_LANG  )
#define attrIsXML_SPACE(av)         AttrIsId( av, TidyAttr_XML_SPACE  )
#define attrIsARIA_ACTIVEDESCENDANT(av) AttrIsId( av,  TidyAttr_ARIA_ACTIVEDESCENDANT  )
#define attrIsARIA_ATOMIC(av)           AttrIsId( av,  TidyAttr_ARIA_ATOMIC  )
#define attrIsARIA_AUTOCOMPLETE(av)     AttrIsId( av,  TidyAttr_ARIA_AUTOCOMPLETE  )
#define attrIsARIA_BUSY(av)             AttrIsId( av,  TidyAttr_ARIA_BUSY  )
#define attrIsARIA_CHECKED(av)          AttrIsId( av,  TidyAttr_ARIA_CHECKED  )
#define attrIsARIA_CONTROLS(av)         AttrIsId( av,  TidyAttr_ARIA_CONTROLS  )
#define attrIsARIA_DESCRIBEDBY(av)      AttrIsId( av,  TidyAttr_ARIA_DESCRIBEDBY  )
#define attrIsARIA_DISABLED(av)         AttrIsId( av,  TidyAttr_ARIA_DISABLED  )
#define attrIsARIA_DROPEFFECT(av)       AttrIsId( av,  TidyAttr_ARIA_DROPEFFECT  )
#define attrIsARIA_EXPANDED(av)         AttrIsId( av,  TidyAttr_ARIA_EXPANDED  )
#define attrIsARIA_FLOWTO(av)           AttrIsId( av,  TidyAttr_ARIA_FLOWTO  )
#define attrIsARIA_GRABBED(av)          AttrIsId( av,  TidyAttr_ARIA_GRABBED  )
#define attrIsARIA_HASPOPUP(av)         AttrIsId( av,  TidyAttr_ARIA_HASPOPUP  )
#define attrIsARIA_HIDDEN(av)           AttrIsId( av,  TidyAttr_ARIA_HIDDEN  )
#define attrIsARIA_INVALID(av)          AttrIsId( av,  TidyAttr_ARIA_INVALID  )
#define attrIsARIA_LABEL(av)            AttrIsId( av,  TidyAttr_ARIA_LABEL  )
#define attrIsARIA_LABELLEDBY(av)       AttrIsId( av,  TidyAttr_ARIA_LABELLEDBY  )
#define attrIsARIA_LEVEL(av)            AttrIsId( av,  TidyAttr_ARIA_LEVEL  )
#define attrIsARIA_LIVE(av)             AttrIsId( av,  TidyAttr_ARIA_LIVE  )
#define attrIsARIA_MULTILINE(av)        AttrIsId( av,  TidyAttr_ARIA_MULTILINE  )
#define attrIsARIA_MULTISELECTABLE(av)  AttrIsId( av,  TidyAttr_ARIA_MULTISELECTABLE  )
#define attrIsARIA_ORIENTATION(av)      AttrIsId( av,  TidyAttr_ARIA_ORIENTATION  )
#define attrIsARIA_OWNS(av)             AttrIsId( av,  TidyAttr_ARIA_OWNS  )
#define attrIsARIA_POSINSET(av)         AttrIsId( av,  TidyAttr_ARIA_POSINSET  )
#define attrIsARIA_PRESSED(av)          AttrIsId( av,  TidyAttr_ARIA_PRESSED  )
#define attrIsARIA_READONLY(av)         AttrIsId( av,  TidyAttr_ARIA_READONLY  )
#define attrIsARIA_RELEVANT(av)         AttrIsId( av,  TidyAttr_ARIA_RELEVANT  )
#define attrIsARIA_REQUIRED(av)         AttrIsId( av,  TidyAttr_ARIA_REQUIRED  )
#define attrIsARIA_SELECTED(av)         AttrIsId( av,  TidyAttr_ARIA_SELECTED  )
#define attrIsARIA_SETSIZE(av)          AttrIsId( av,  TidyAttr_ARIA_SETSIZE  )
#define attrIsARIA_SORT(av)             AttrIsId( av,  TidyAttr_ARIA_SORT  )
#define attrIsARIA_VALUEMAX(av)         AttrIsId( av,  TidyAttr_ARIA_VALUEMAX  )
#define attrIsARIA_VALUEMIN(av)         AttrIsId( av,  TidyAttr_ARIA_VALUEMIN  )
#define attrIsARIA_VALUENOW(av)         AttrIsId( av,  TidyAttr_ARIA_VALUENOW  )
#define attrIsARIA_VALUETEXT(av)        AttrIsId( av,  TidyAttr_ARIA_VALUETEXT  )



/* Attribute Retrieval macros
*/
#define attrGetHREF( nod )        TY_(AttrGetById)( nod, TidyAttr_HREF  )
#define attrGetSRC( nod )         TY_(AttrGetById)( nod, TidyAttr_SRC  )
#define attrGetID( nod )          TY_(AttrGetById)( nod, TidyAttr_ID  )
#define attrGetNAME( nod )        TY_(AttrGetById)( nod, TidyAttr_NAME  )
#define attrGetSUMMARY( nod )     TY_(AttrGetById)( nod, TidyAttr_SUMMARY  )
#define attrGetALT( nod )         TY_(AttrGetById)( nod, TidyAttr_ALT  )
#define attrGetLONGDESC( nod )    TY_(AttrGetById)( nod, TidyAttr_LONGDESC  )
#define attrGetUSEMAP( nod )      TY_(AttrGetById)( nod, TidyAttr_USEMAP  )
#define attrGetISMAP( nod )       TY_(AttrGetById)( nod, TidyAttr_ISMAP  )
#define attrGetLANGUAGE( nod )    TY_(AttrGetById)( nod, TidyAttr_LANGUAGE  )
#define attrGetTYPE( nod )        TY_(AttrGetById)( nod, TidyAttr_TYPE  )
#define attrGetVALUE( nod )       TY_(AttrGetById)( nod, TidyAttr_VALUE  )
#define attrGetCONTENT( nod )     TY_(AttrGetById)( nod, TidyAttr_CONTENT  )
#define attrGetTITLE( nod )       TY_(AttrGetById)( nod, TidyAttr_TITLE  )
#define attrGetXMLNS( nod )       TY_(AttrGetById)( nod, TidyAttr_XMLNS  )
#define attrGetDATAFLD( nod )     TY_(AttrGetById)( nod, TidyAttr_DATAFLD  )
#define attrGetWIDTH( nod )       TY_(AttrGetById)( nod, TidyAttr_WIDTH  )
#define attrGetHEIGHT( nod )      TY_(AttrGetById)( nod, TidyAttr_HEIGHT  )
#define attrGetFOR( nod )         TY_(AttrGetById)( nod, TidyAttr_FOR  )
#define attrGetSELECTED( nod )    TY_(AttrGetById)( nod, TidyAttr_SELECTED  )
#define attrGetCHARSET( nod )     TY_(AttrGetById)( nod, TidyAttr_CHARSET  )
#define attrGetCHECKED( nod )     TY_(AttrGetById)( nod, TidyAttr_CHECKED  )
#define attrGetLANG( nod )        TY_(AttrGetById)( nod, TidyAttr_LANG  )
#define attrGetTARGET( nod )      TY_(AttrGetById)( nod, TidyAttr_TARGET  )
#define attrGetHTTP_EQUIV( nod )  TY_(AttrGetById)( nod, TidyAttr_HTTP_EQUIV  )
#define attrGetREL( nod )         TY_(AttrGetById)( nod, TidyAttr_REL  )

#define attrGetOnMOUSEMOVE( nod ) TY_(AttrGetById)( nod, TidyAttr_OnMOUSEMOVE  )
#define attrGetOnMOUSEDOWN( nod ) TY_(AttrGetById)( nod, TidyAttr_OnMOUSEDOWN  )
#define attrGetOnMOUSEUP( nod )   TY_(AttrGetById)( nod, TidyAttr_OnMOUSEUP  )
#define attrGetOnCLICK( nod )     TY_(AttrGetById)( nod, TidyAttr_OnCLICK  )
#define attrGetOnMOUSEOVER( nod ) TY_(AttrGetById)( nod, TidyAttr_OnMOUSEOVER  )
#define attrGetOnMOUSEOUT( nod )  TY_(AttrGetById)( nod, TidyAttr_OnMOUSEOUT  )
#define attrGetOnKEYDOWN( nod )   TY_(AttrGetById)( nod, TidyAttr_OnKEYDOWN  )
#define attrGetOnKEYUP( nod )     TY_(AttrGetById)( nod, TidyAttr_OnKEYUP  )
#define attrGetOnKEYPRESS( nod )  TY_(AttrGetById)( nod, TidyAttr_OnKEYPRESS  )
#define attrGetOnFOCUS( nod )     TY_(AttrGetById)( nod, TidyAttr_OnFOCUS  )
#define attrGetOnBLUR( nod )      TY_(AttrGetById)( nod, TidyAttr_OnBLUR  )

#define attrGetBGCOLOR( nod )     TY_(AttrGetById)( nod, TidyAttr_BGCOLOR  )

#define attrGetLINK( nod )        TY_(AttrGetById)( nod, TidyAttr_LINK  )
#define attrGetALINK( nod )       TY_(AttrGetById)( nod, TidyAttr_ALINK  )
#define attrGetVLINK( nod )       TY_(AttrGetById)( nod, TidyAttr_VLINK  )

#define attrGetTEXT( nod )        TY_(AttrGetById)( nod, TidyAttr_TEXT  )
#define attrGetSTYLE( nod )       TY_(AttrGetById)( nod, TidyAttr_STYLE  )
#define attrGetABBR( nod )        TY_(AttrGetById)( nod, TidyAttr_ABBR  )
#define attrGetCOLSPAN( nod )     TY_(AttrGetById)( nod, TidyAttr_COLSPAN  )
#define attrGetFONT( nod )        TY_(AttrGetById)( nod, TidyAttr_FONT  )
#define attrGetBASEFONT( nod )    TY_(AttrGetById)( nod, TidyAttr_BASEFONT  )
#define attrGetROWSPAN( nod )     TY_(AttrGetById)( nod, TidyAttr_ROWSPAN  )

#define attrGetROLE( nod )        TY_(AttrGetById)( nod, TidyAttr_ROLE  )

#define attrGetARIA_ACTIVEDESCENDANT( nod ) TY_(AttrGetById)( nod,  TidyAttr_ARIA_ACTIVEDESCENDANT  )
#define attrGetARIA_ATOMIC( nod )           TY_(AttrGetById)( nod,  TidyAttr_ARIA_ATOMIC  )
#define attrGetARIA_AUTOCOMPLETE( nod )     TY_(AttrGetById)( nod,  TidyAttr_ARIA_AUTOCOMPLETE  )
#define attrGetARIA_BUSY( nod )             TY_(AttrGetById)( nod,  TidyAttr_ARIA_BUSY  )
#define attrGetARIA_CHECKED( nod )          TY_(AttrGetById)( nod,  TidyAttr_ARIA_CHECKED  )
#define attrGetARIA_CONTROLS( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_CONTROLS  )
#define attrGetARIA_DESCRIBEDBY( nod )      TY_(AttrGetById)( nod,  TidyAttr_ARIA_DESCRIBEDBY  )
#define attrGetARIA_DISABLED( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_DISABLED  )
#define attrGetARIA_DROPEFFECT( nod )       TY_(AttrGetById)( nod,  TidyAttr_ARIA_DROPEFFECT  )
#define attrGetARIA_EXPANDED( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_EXPANDED  )
#define attrGetARIA_FLOWTO( nod )           TY_(AttrGetById)( nod,  TidyAttr_ARIA_FLOWTO  )
#define attrGetARIA_GRABBED( nod )          TY_(AttrGetById)( nod,  TidyAttr_ARIA_GRABBED  )
#define attrGetARIA_HASPOPUP( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_HASPOPUP  )
#define attrGetARIA_HIDDEN( nod )           TY_(AttrGetById)( nod,  TidyAttr_ARIA_HIDDEN  )
#define attrGetARIA_INVALID( nod )          TY_(AttrGetById)( nod,  TidyAttr_ARIA_INVALID  )
#define attrGetARIA_LABEL( nod )            TY_(AttrGetById)( nod,  TidyAttr_ARIA_LABEL  )
#define attrGetARIA_LABELLEDBY( nod )       TY_(AttrGetById)( nod,  TidyAttr_ARIA_LABELLEDBY  )
#define attrGetARIA_LEVEL( nod )            TY_(AttrGetById)( nod,  TidyAttr_ARIA_LEVEL  )
#define attrGetARIA_LIVE( nod )             TY_(AttrGetById)( nod,  TidyAttr_ARIA_LIVE  )
#define attrGetARIA_MULTILINE( nod )        TY_(AttrGetById)( nod,  TidyAttr_ARIA_MULTILINE  )
#define attrGetARIA_MULTISELECTABLE( nod )  TY_(AttrGetById)( nod,  TidyAttr_ARIA_MULTISELECTABLE  )
#define attrGetARIA_ORIENTATION( nod )      TY_(AttrGetById)( nod,  TidyAttr_ARIA_ORIENTATION  )
#define attrGetARIA_OWNS( nod )             TY_(AttrGetById)( nod,  TidyAttr_ARIA_OWNS  )
#define attrGetARIA_POSINSET( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_POSINSET  )
#define attrGetARIA_PRESSED( nod )          TY_(AttrGetById)( nod,  TidyAttr_ARIA_PRESSED  )
#define attrGetARIA_READONLY( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_READONLY  )
#define attrGetARIA_RELEVANT( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_RELEVANT  )
#define attrGetARIA_REQUIRED( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_REQUIRED  )
#define attrGetARIA_SELECTED( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_SELECTED  )
#define attrGetARIA_SETSIZE( nod )          TY_(AttrGetById)( nod,  TidyAttr_ARIA_SETSIZE  )
#define attrGetARIA_SORT( nod )             TY_(AttrGetById)( nod,  TidyAttr_ARIA_SORT  )
#define attrGetARIA_VALUEMAX( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_VALUEMAX  )
#define attrGetARIA_VALUEMIN( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_VALUEMIN  )
#define attrGetARIA_VALUENOW( nod )         TY_(AttrGetById)( nod,  TidyAttr_ARIA_VALUENOW  )
#define attrGetARIA_VALUETEXT( nod )        TY_(AttrGetById)( nod,  TidyAttr_ARIA_VALUETEXT  )

#endif /* __ATTRS_H__ */
/* charsets.h -- character set information and mappings

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

unsigned int TY_(GetEncodingIdFromName)(ctmbstr name);
unsigned int TY_(GetEncodingIdFromCodePage)(unsigned int cp);
unsigned int TY_(GetEncodingCodePageFromName)(ctmbstr name);
unsigned int TY_(GetEncodingCodePageFromId)(unsigned int id);
ctmbstr TY_(GetEncodingNameFromId)(unsigned int id);
ctmbstr TY_(GetEncodingNameFromCodePage)(unsigned int cp);
#ifndef __CLEAN_H__
#define __CLEAN_H__

/* clean.h -- clean up misuse of presentation markup

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

void TY_(FixNodeLinks)(Node *node);

void TY_(FreeStyles)( TidyDocImpl* doc );

/* Add class="foo" to node
*/
void TY_(AddStyleAsClass)( TidyDocImpl* doc, Node *node, ctmbstr stylevalue );
void TY_(AddStyleProperty)(TidyDocImpl* doc, Node *node, ctmbstr property );

void TY_(CleanDocument)( TidyDocImpl* doc );

/* simplifies <b><b> ... </b> ...</b> etc. */
void TY_(NestedEmphasis)( TidyDocImpl* doc, Node* node );

/* replace i by em and b by strong */
void TY_(EmFromI)( TidyDocImpl* doc, Node* node );

/*
 Some people use dir or ul without an li
 to indent the content. The pattern to
 look for is a list with a single implicit
 li. This is recursively replaced by an
 implicit blockquote.
*/
void TY_(List2BQ)( TidyDocImpl* doc, Node* node );

/*
 Replace implicit blockquote by div with an indent
 taking care to reduce nested blockquotes to a single
 div with the indent set to match the nesting depth
*/
void TY_(BQ2Div)( TidyDocImpl* doc, Node* node );


void TY_(DropSections)( TidyDocImpl* doc, Node* node );


/*
 This is a major clean up to strip out all the extra stuff you get
 when you save as web page from Word 2000. It doesn't yet know what
 to do with VML tags, but these will appear as errors unless you
 declare them as new tags, such as o:p which needs to be declared
 as inline.
*/
void TY_(CleanWord2000)( TidyDocImpl* doc, Node *node);

Bool TY_(IsWord2000)( TidyDocImpl* doc );

/* where appropriate move object elements from head to body */
void TY_(BumpObject)( TidyDocImpl* doc, Node *html );

Bool TY_(TidyMetaCharset)(TidyDocImpl* doc);

void TY_(DropComments)(TidyDocImpl* doc, Node* node);
void TY_(DropFontElements)(TidyDocImpl* doc, Node* node, Node **pnode);
void TY_(WbrToSpace)(TidyDocImpl* doc, Node* node);
void TY_(DowngradeTypography)(TidyDocImpl* doc, Node* node);
void TY_(ReplacePreformattedSpaces)(TidyDocImpl* doc, Node* node);
void TY_(NormalizeSpaces)(Lexer *lexer, Node *node);
void TY_(ConvertCDATANodes)(TidyDocImpl* doc, Node* node);

void TY_(FixAnchors)(TidyDocImpl* doc, Node *node, Bool wantName, Bool wantId);
void TY_(FixXhtmlNamespace)(TidyDocImpl* doc, Bool wantXmlns);
void TY_(FixLanguageInformation)(TidyDocImpl* doc, Node* node, Bool wantXmlLang, Bool wantLang);

/* Issue #567 - move style elements from body to head */
void TY_(CleanStyle)(TidyDocImpl* doc, Node *html);

#endif /* __CLEAN_H__ */
#ifndef __FILEIO_H__
#define __FILEIO_H__

/** @file fileio.h - does standard C I/O

  Implementation of a FILE* based TidyInputSource and 
  TidyOutputSink.

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "tidybuffio.h" */
#ifdef __cplusplus
extern "C" {
#endif

/** Allocate and initialize file input source */
int TY_(initFileSource)( TidyAllocator *allocator, TidyInputSource* source, FILE* fp );

/** Free file input source */
void TY_(freeFileSource)( TidyInputSource* source, Bool closeIt );

#if SUPPORT_POSIX_MAPPED_FILES
/** Allocate and initialize file input source using Standard C I/O */
int TY_(initStdIOFileSource)( TidyAllocator *allocator, TidyInputSource* source, FILE* fp );

/** Free file input source using Standard C I/O */
void TY_(freeStdIOFileSource)( TidyInputSource* source, Bool closeIt );
#endif

/** Initialize file output sink */
void TY_(initFileSink)( TidyOutputSink* sink, FILE* fp );

/* Needed for internal declarations */
void TIDY_CALL TY_(filesink_putByte)( void* sinkData, byte bv );

#ifdef __cplusplus
}
#endif
#endif /* __FILEIO_H__ */
#ifndef __STREAMIO_H__
#define __STREAMIO_H__

/* streamio.h -- handles character stream I/O

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Wrapper around Tidy input source and output sink
  that calls appropriate interfaces, and applies 
  necessary char encoding transformations: to/from
  ISO-10646 and/or UTF-8.

*/

/* #include "forward.h" */
/* #include "tidybuffio.h" */
/* #include "fileio.h" */

#ifdef __cplusplus
extern "C"
{
#endif
typedef enum
{
  FileIO,
  BufferIO,
  UserIO
} IOType;

/* states for ISO 2022

 A document in ISO-2022 based encoding uses some ESC sequences called
 "designator" to switch character sets. The designators defined and
 used in ISO-2022-JP are:

    "ESC" + "(" + ?     for ISO646 variants

    "ESC" + "$" + ?     and
    "ESC" + "$" + "(" + ?   for multibyte character sets
*/
typedef enum
{
  FSM_ASCII,
  FSM_ESC,
  FSM_ESCD,
  FSM_ESCDP,
  FSM_ESCP,
  FSM_NONASCII
} ISO2022State;

/************************
** Source
************************/

enum
{
    CHARBUF_SIZE=5,
    LASTPOS_SIZE=64
};

/* non-raw input is cleaned up*/
struct _StreamIn
{
    ISO2022State    state;     /* FSM for ISO2022 */
    Bool   pushed;
    TidyAllocator *allocator;
    tchar* charbuf;
    unsigned int   bufpos;
    unsigned int   bufsize;
    int    tabs;
    int    lastcols[LASTPOS_SIZE];
    unsigned short curlastpos; /* current last position in lastcols */ 
    unsigned short firstlastpos; /* first valid last position in lastcols */ 
    int    curcol;
    int    curline;
    int    encoding;
    IOType iotype;

    TidyInputSource source;

    /* Pointer back to document for error reporting */
    TidyDocImpl* doc;
};

StreamIn* TY_(initStreamIn)( TidyDocImpl* doc, int encoding );
void TY_(freeStreamIn)(StreamIn* in);

StreamIn* TY_(FileInput)( TidyDocImpl* doc, FILE* fp, int encoding );
StreamIn* TY_(BufferInput)( TidyDocImpl* doc, TidyBuffer* content, int encoding );
StreamIn* TY_(UserInput)( TidyDocImpl* doc, TidyInputSource* source, int encoding );

int       TY_(ReadBOMEncoding)(StreamIn *in);
unsigned int      TY_(ReadChar)( StreamIn* in );
void      TY_(UngetChar)( unsigned int c, StreamIn* in );
Bool      TY_(IsEOF)( StreamIn* in );


/************************
** Sink
************************/

struct _StreamOut
{
    int   encoding;
    ISO2022State   state;     /* for ISO 2022 */
    unsigned int  nl;
    IOType iotype;
    TidyOutputSink sink;
};

StreamOut* TY_(FileOutput)( TidyDocImpl *doc, FILE* fp, int encoding, unsigned int newln );
StreamOut* TY_(BufferOutput)( TidyDocImpl *doc, TidyBuffer* buf, int encoding, unsigned int newln );
StreamOut* TY_(UserOutput)( TidyDocImpl *doc, TidyOutputSink* sink, int encoding, unsigned int newln );

StreamOut* TY_(StdErrOutput)(void);
/* StreamOut* StdOutOutput(void); */
void       TY_(ReleaseStreamOut)( TidyDocImpl *doc, StreamOut* out );

void TY_(WriteChar)( unsigned int c, StreamOut* out );
void TY_(outBOM)( StreamOut *out );

ctmbstr TY_(GetEncodingNameFromTidyId)(unsigned int id);
ctmbstr TY_(GetEncodingOptNameFromTidyId)(unsigned int id);
int TY_(GetCharEncodingFromOptName)(ctmbstr charenc);

/************************
** Misc
************************/

/* character encodings
*/
#define RAW         0
#define ASCII       1
#define LATIN0      2
#define LATIN1      3
#define UTF8        4
#define ISO2022     5
#define MACROMAN    6
#define WIN1252     7
#define IBM858      8
#define UTF16LE     9
#define UTF16BE     10
#define UTF16       11
#define BIG5        12
#define SHIFTJIS    13

/* Function for conversion from Windows-1252 to Unicode */
unsigned int TY_(DecodeWin1252)(unsigned int c);

/* Function to convert from MacRoman to Unicode */
unsigned int TY_(DecodeMacRoman)(unsigned int c);

#ifdef __cplusplus
}
#endif


/* Use numeric constants as opposed to escape chars (\r, \n)
** to avoid conflict Mac compilers that may re-define these.
*/
/* #define '\r'    0xD */
/* #define '\n'    0xA */

#if defined(MAC_OS_CLASSIC)
#  define DEFAULT_NL_CONFIG TidyCR
#elif defined(_WIN32) || defined(OS2_OS)
#  define DEFAULT_NL_CONFIG TidyCRLF
#else
#  define DEFAULT_NL_CONFIG TidyLF
#endif


#endif /* __STREAMIO_H__ */
#ifndef __CONFIG_H__
#define __CONFIG_H__

/**************************************************************************//**
 * @file
 * Read configuration files and manage configuration properties.
 *
 * Config files associate a property name with a value.
 *
 * // comments can start at the beginning of a line
 * # comments can start at the beginning of a line
 * name: short values fit onto one line
 * name: a really long value that
 *  continues on the next line
 *
 * Property names are case insensitive and should be less than 60 characters
 * in length, and must start at the begining of the line, as whitespace at
 * the start of a line signifies a line continuation.
 *
 * @author  HTACG, et al (consult git log)
 * 
 * @copyright
 *     Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
 *     Institute of Technology, European Research Consortium for Informatics
 *     and Mathematics, Keio University) and HTACG.
 * @par
 *     All Rights Reserved.
 * @par
 *     See `tidy.h` for the complete license.
 *
 * @date Additional updates: consult git log
 *
 ******************************************************************************/

/* #include "forward.h" */
/* #include "tidy.h" */
/* #include "streamio.h" */

/** @addtogroup internal_api */
/** @{ */


/***************************************************************************//**
 ** @defgroup configuration_options Configuration Options
 **
 ** This module organizes all of Tidy's configuration options, including
 ** picklist management, option setting and retrieval, option file utilities,
 ** and so on.
 **
 ** @{
 ******************************************************************************/


/** Determines the maximum number of items in an option's picklist. PickLists
 ** may have up to 16 items. For some reason, this limit has been hard-coded
 ** into Tidy for some time. Feel free to increase this as needed.
 */
#define TIDY_PL_SIZE 16


/** Structs of this type contain information needed in order to present
 ** picklists, relate picklist entries to public enum values, and parse
 ** strings that are accepted in order to assign the value.
 */
typedef struct PickListItem {
    ctmbstr label;      /**< PickList label for this item. */
    const int value;    /**< The option value represented by this label. */
    ctmbstr inputs[10]; /**< String values that can select this value. */
} PickListItem;


/** An array of PickListItems, fixed in size for in-code declarations. 
 ** Arrays must be populated in 0 to 10 order, as the option value is assigned
 ** based on this index and *not* on the structures' value field. It remains
 ** a best practice, however, to assign a public enum value with the proper
 ** index value.
 */
typedef const PickListItem PickListItems[TIDY_PL_SIZE];


struct _tidy_option; /* forward */

/** The TidyOptionImpl type implements the `_tidy_option` structure.
 */
typedef struct _tidy_option TidyOptionImpl;


/** This typedef describes a function that is used for parsing the input
 ** given for a particular Tidy option.
 */
typedef Bool (ParseProperty)( TidyDocImpl* doc, const TidyOptionImpl* opt );


/** This structure defines the internal representation of a Tidy option.
 */
struct _tidy_option
{
    TidyOptionId        id;              /**< The unique identifier for this option. */
    TidyConfigCategory  category;        /**< The category of the option. */
    ctmbstr             name;            /**< The name of the option. */
    TidyOptionType      type;            /**< The date type for the option. */
    unsigned int               dflt;            /**< Default value for TidyInteger and TidyBoolean */
    ParseProperty*      parser;          /**< Function to parse input; read-only if NULL. */
    PickListItems*      pickList;        /**< The picklist of possible values for this option. */
    ctmbstr             pdflt;           /**< Default value for TidyString. */
};


/** Stored option values can be one of two internal types.
 */
typedef union
{
  unsigned int v;  /**< Value for TidyInteger and TidyBoolean */
  char *p;  /**< Value for TidyString */
} TidyOptionValue;


/** This type is used to define a structure for keeping track of the values
 ** for each option.
 */
typedef struct _tidy_config
{
    TidyOptionValue value[ N_TIDY_OPTIONS + 1 ];     /**< Current config values. */
    TidyOptionValue snapshot[ N_TIDY_OPTIONS + 1 ];  /**< Snapshot of values to be restored later. */
    unsigned int  defined_tags;                              /**< Tracks user-defined tags. */
    unsigned int c;                                          /**< Current char in input stream for reading options. */
    StreamIn* cfgIn;                                 /**< Current input source for reading options.*/
} TidyConfigImpl;


/** Used to build a table of documentation cross-references.
 */
typedef struct {
  TidyOptionId opt;          /**< Identifier. */
  TidyOptionId const *links; /**< Cross references. Last element must be 'TidyUnknownOption'. */
} TidyOptionDoc;


/** Given an option name, return an instance of an option.
 ** @param optnam The option name to retrieve.
 ** @returns The instance of the requested option.
 */
const TidyOptionImpl* TY_(lookupOption)( ctmbstr optnam );


/** Given an option ID, return an instance of an option.
 ** @param optId The option ID to retrieve.
 ** @returns The instance of the requested option.
 */
const TidyOptionImpl* TY_(getOption)( TidyOptionId optId );

/** Given an option ID, indicates whether or not the option is a list.
 ** @param optId The option ID to check.
 ** @returns Returns yes if the option value is a list.
 */
const Bool TY_(getOptionIsList)( TidyOptionId optId );

/** Initiates an iterator to cycle through all of the available options.
 ** @param doc The Tidy document to get options.
 ** @returns An iterator token to be used with TY_(getNextOption)().
 */
TidyIterator TY_(getOptionList)( TidyDocImpl* doc );


/** Gets the next option provided by the iterator.
 ** @param doc The Tidy document to get options.
 ** @param iter The iterator token initialized by TY_(getOptionList)().
 ** @returns The instance of the next option.
 */
const TidyOptionImpl* TY_(getNextOption)( TidyDocImpl* doc, TidyIterator* iter );


/** Initiates an iterator to cycle through all of the available picklist
 ** possibilities.
 ** @param option An instance of an option for which to iterate a picklist.
 ** @returns An interator token to be used with TY_(getNextOptionPick)().
 */
TidyIterator TY_(getOptionPickList)( const TidyOptionImpl* option );


/** Gets the next picklist possibility provided by the iterator.
 ** @param option The instance of the option for which to iterate a picklist.
 ** @param iter The iterator token initialized by TY_(getOptionPickList)().
 ** @returns The next picklist entry.
 */
ctmbstr TY_(getNextOptionPick)( const TidyOptionImpl* option, TidyIterator* iter );


#if SUPPORT_CONSOLE_APP
/** Returns the cross-reference information structure for optID, which is
 ** used for generating documentation.
 ** @param optId The option ID to get cross-reference information for.
 ** @returns Cross reference information.
 */
const TidyOptionDoc* TY_(OptGetDocDesc)( TidyOptionId optId );
#endif /* SUPPORT_CONSOLE_APP */


/** Initialize the configuration for the given Tidy document.
 ** @param doc The Tidy document.
 */
void TY_(InitConfig)( TidyDocImpl* doc );


/** Frees the configuration memory for the given Tidy document.
 ** @param doc The Tidy document.
 */
void TY_(FreeConfig)( TidyDocImpl* doc );


/** Gets the picklist label for a given value.
 ** @param optId the option id having a picklist to check.
 ** @param pick the picklist item to retrieve.
 ** @returns The label for the pick.
 */
ctmbstr TY_(GetPickListLabelForPick)( TidyOptionId optId, unsigned int pick );


/** Sets the integer value for the given option Id.
 ** @param doc The Tidy document.
 ** @param optId The option ID to set.
 ** @param val The value to set.
 ** @returns Success or failure.
 */
Bool TY_(SetOptionInt)( TidyDocImpl* doc, TidyOptionId optId, unsigned int val );


/** Sets the bool value for the given option Id.
 ** @param doc The Tidy document.
 ** @param optId The option ID to set.
 ** @param val The value to set.
 ** @returns Success or failure.
 */
Bool TY_(SetOptionBool)( TidyDocImpl* doc, TidyOptionId optId, Bool val );


/** Resets the given option to its default value.
 ** @param doc The Tidy document.
 ** @param optId The option ID to set.
 ** @returns Success or failure.
 */
Bool TY_(ResetOptionToDefault)( TidyDocImpl* doc, TidyOptionId optId );


/** Resets all options in the document to their default values.
 ** @param doc The Tidy document.
 */
void TY_(ResetConfigToDefault)( TidyDocImpl* doc );


/** Stores a snapshot of all of the configuration values that can be
 ** restored later.
 ** @param doc The Tidy document.
 */
void TY_(TakeConfigSnapshot)( TidyDocImpl* doc );


/** Restores all of the configuration values to their snapshotted values.
 ** @param doc The Tidy document.
 */
void TY_(ResetConfigToSnapshot)( TidyDocImpl* doc );


/** Copies the configuration from one document to another.
 ** @param docTo The destination Tidy document.
 ** @param docFrom The source Tidy document.
 */
void TY_(CopyConfig)( TidyDocImpl* docTo, TidyDocImpl* docFrom );


/** Attempts to parse the given config file into the document.
 ** @param doc The Tidy document.
 ** @param cfgfil The file to load.
 ** @returns a file system error code.
 */
int  TY_(ParseConfigFile)( TidyDocImpl* doc, ctmbstr cfgfil );


/** Attempts to parse the given config file into the document, using
 ** the provided encoding.
 ** @param doc The Tidy document.
 ** @param cfgfil The file to load.
 ** @param charenc The name of the encoding to use for reading the file.
 ** @returns a file system error code.
 */
int  TY_(ParseConfigFileEnc)( TidyDocImpl* doc,
                              ctmbstr cfgfil, ctmbstr charenc );


/** Saves the current configuration for options not having default values
 ** into the specified file.
 ** @param doc The Tidy document.
 ** @param cfgfil The file to save.
 ** @returns a file system error code.
 */
int  TY_(SaveConfigFile)( TidyDocImpl* doc, ctmbstr cfgfil );


/** Writes the current configuration for options not having default values
 ** into the specified sink.
 ** @param doc The Tidy document.
 ** @param sink The sink to save into.
 ** @returns a file system error code.
 */
int  TY_(SaveConfigSink)( TidyDocImpl* doc, TidyOutputSink* sink );


/** Attempts to parse the provided value for the given option name. Returns
 ** false if unknown option, missing parameter, or the option doesn't
 ** use the parameter.
 ** @param doc The Tidy document.
 ** @param optnam The name of the option to be set.
 ** @param optVal The string value to attempt to parse.
 ** @returns Success or failure.
 */
Bool  TY_(ParseConfigOption)( TidyDocImpl* doc, ctmbstr optnam, ctmbstr optVal );


/** Attempts to parse the provided value for the given option id. Returns
 ** false if unknown option, missing parameter, or the option doesn't
 ** use the parameter.
 ** @param doc The Tidy document.
 ** @param optId The ID of the option to be set.
 ** @param optVal The string value to attempt to parse.
 ** @returns Success or failure.
 */
Bool  TY_(ParseConfigValue)( TidyDocImpl* doc, TidyOptionId optId, ctmbstr optVal );


/** Ensure that char encodings are self consistent.
 ** @param doc The Tidy document to adjust.
 ** @param encoding The encoding being applied.
 ** @returns A bool indicating success or failure.
 */
Bool  TY_(AdjustCharEncoding)( TidyDocImpl* doc, int encoding );


/** Indicates whether or not the current configuration is completely default.
 ** @param doc The Tidy document.
 ** @returns The result.
 */
Bool  TY_(ConfigDiffThanDefault)( TidyDocImpl* doc );


/** Indicates whether or not the current configuration is different from the
 ** stored snapshot.
 ** @param doc The Tidy document.
 ** @returns The result.
 */
Bool  TY_(ConfigDiffThanSnapshot)( TidyDocImpl* doc );


/** Returns the character encoding ID for the given character encoding
 ** string.
 ** @param doc The Tidy document.
 ** @param charenc The name of the character encoding.
 ** @returns The Id of the character encoding.
 */
int TY_(CharEncodingId)( TidyDocImpl* doc, ctmbstr charenc );


/** Returns the full name of the encoding for the given ID.
 ** @param encoding The Id of the encoding.
 ** @returns The name of the character encoding.
 */
ctmbstr TY_(CharEncodingName)( int encoding );


/** Returns the Tidy command line option name of the encoding for the given ID.
 ** @param encoding The Id of the encoding.
 ** @returns The Tidy command line option representing the encoding.
 */
ctmbstr TY_(CharEncodingOptName)( int encoding );


/** Coordinates Config update and list data.
 ** @param doc The Tidy document.
 ** @param opt The option the list item is intended for.
 ** @param name The name of the new list item.
 */
void TY_(DeclareListItem)( TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name );

#ifdef _DEBUG

/* Debug lookup functions will be type-safe and assert option type match */
unsigned int   TY_(_cfgGet)( TidyDocImpl* doc, TidyOptionId optId );
Bool    TY_(_cfgGetBool)( TidyDocImpl* doc, TidyOptionId optId );
TidyTriState TY_(_cfgGetAutoBool)( TidyDocImpl* doc, TidyOptionId optId );
ctmbstr TY_(_cfgGetString)( TidyDocImpl* doc, TidyOptionId optId );

#define cfg(doc, id)            TY_(_cfgGet)( (doc), (id) )
#define cfgBool(doc, id)        TY_(_cfgGetBool)( (doc), (id) )
#define cfgAutoBool(doc, id)    TY_(_cfgGetAutoBool)( (doc), (id) )
#define cfgStr(doc, id)         TY_(_cfgGetString)( (doc), (id) )

#else

/* Release build macros for speed */

/** Access the raw, non-string unsigned int value of the given option ID. */
#define cfg(doc, id)            ((doc)->config.value[ (id) ].v)

/** Access the Bool value of the given option ID. */
#define cfgBool(doc, id)        ((Bool) cfg(doc, id))

/** Access the TidyTriState value of the given option ID. */
#define cfgAutoBool(doc, id)    ((TidyTriState) cfg(doc, id))

/** Access the string value of the given option ID. */
#define cfgStr(doc, id)         ((ctmbstr) (doc)->config.value[ (id) ].p)

#endif /* _DEBUG */


/** @} configuration_options group */
/** @} internal_api addtogroup */


#endif /* __CONFIG_H__ */
#ifndef __ENTITIES_H__
#define __ENTITIES_H__

/* entities.h -- recognize character entities

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "forward.h" */

/* entity starting with "&" returns zero on error */
/* unsigned int    EntityCode( ctmbstr name, unsigned int versions ); */
ctmbstr TY_(EntityName)( unsigned int charCode, unsigned int versions );
Bool    TY_(EntityInfo)( ctmbstr name, Bool isXml, unsigned int* code, unsigned int* versions );

#endif /* __ENTITIES_H__ */
#ifndef __GDOC_H__
#define __GDOC_H__

/* gdoc.h -- clean up html exported by Google Docs

  (c) 2012 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  - strip the script element, as the style sheet is a mess
  - strip class attributes
  - strip span elements, leaving their content in place
  - replace <a name=...></a> by id on parent element
  - strip empty <p> elements

*/

void TY_(CleanGoogleDocument)( TidyDocImpl* doc );

#endif /* __GDOC_H__ */
#ifndef language_h
#define language_h

/*********************************************************************
 * Localization support for HTML Tidy.
 *
 * This header provides the public (within libtidy) interface to
 * basic localization support. To add your own localization, create
 * a new `language_xx.h` file and add it to the struct in 
 * `language.c`.
 *
 * (c) 2015 HTACG
 * See `tidy.h` for the copyright notice.
 *********************************************************************/

/* #include "forward.h" */


/** @name Exposed Data Structures */
/** @{ */


/**
 *  These enumerations are used within instances of `languageDefinition`
 *  structures to provide additional metadata, and are localizable
 *  therein.
 */
typedef enum {
    
    /* Specifies the language code for a particular language. */
    TIDY_LANGUAGE = 400,
    
    /* Marker for the last key in the structure. */
    TIDY_MESSAGE_TYPE_LAST
    
} tidyLanguage;


/**
 *  Describes a record for a localization string.
 *  - key must correspond with one of Tidy's enums (see `tidyMessageTypes`
 *    below)
 *  - pluralForm corresponds to gettext plural forms case (not singularity).
 *    Most entries should be case 0, representing the single case.:
 *    https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
 */
typedef struct languageDictionaryEntry {
    unsigned int key;
    unsigned int pluralForm;
    ctmbstr value;
} languageDictionaryEntry;


/**
 *  For now we'll just use an array to hold all of the dictionary
 *  entries. In the future we can convert this to a hash structure
 *  which will make looking up strings faster.
 */
typedef languageDictionaryEntry const languageDictionary[600];


/**
 *  Finally, a complete language definition. The item `pluralForm`
 *  is a function pointer that will provide the correct plural
 *  form given the value `n`. The actual function is present in
 *  each language header and is language dependent.
 */
typedef struct languageDefinition {
    unsigned int (*whichPluralForm)(unsigned int n);
    languageDictionary messages;
} languageDefinition;


/**
 *  The function getNextWindowsLanguage() returns pointers to this type;
 *  it gives LibTidy implementors the ability to determine how Windows
 *  locale names are mapped to POSIX language codes.
 */
typedef struct tidyLocaleMapItemImpl {
    ctmbstr winName;
    ctmbstr POSIXName;
} tidyLocaleMapItemImpl;


/** @} */
/** @name Localization Related Functions */
/** @{ */


/**
 **  Determines the current locale without affecting the C locale.
 **  Tidy has always used the default C locale, and at this point
 **  in its development we're not going to tamper with that.
 **  @param  result The buffer to use to return the string.
 **          Returns NULL on failure.
 **  @return The same buffer for convenience.
 */
tmbstr TY_(tidySystemLocale)(tmbstr result);

/**
 *  Tells Tidy to use a different language for output.
 *  @param  languageCode A Windows or POSIX language code, and must match
 *          a TIDY_LANGUAGE for an installed language.
 *  @result Indicates that a setting was applied, but not necessarily the
 *          specific request, i.e., true indicates a language and/or region
 *          was applied. If es_mx is requested but not installed, and es is
 *          installed, then es will be selected and this function will return
 *          true. However the opposite is not true; if es is requested but
 *          not present, Tidy will not try to select from the es_XX variants.
 */
Bool TY_(tidySetLanguage)( ctmbstr languageCode );

/**
 *  Gets the current language used by Tidy.
 */
ctmbstr TY_(tidyGetLanguage)(void);


/**
 *  Indicates whether or not the current language was set by a
 *  LibTidy user or internally by the library. This flag prevents
 *  subsequently created instances of TidyDocument from changing the
 *  user's language.
 *  @returns Returns yes to indicate that the current language was
 *    specified by an API user.
 */
Bool TY_(tidyGetLanguageSetByUser)(void);


/**
 *  Specifies to LibTidy that the user (rather than the library)
 *  selected the current language. This flag prevents subsequently
 *  created instances of TidyDocument from changing the user's language.
 */
void TY_(tidySetLanguageSetByUser)( void );


/**
 *  Provides a string given `messageType` in the current
 *  localization for `quantity`.
 */
ctmbstr TY_(tidyLocalizedStringN)( unsigned int messageType, unsigned int quantity );

/**
 *  Provides a string given `messageType` in the current
 *  localization for the single case.
 */
ctmbstr TY_(tidyLocalizedString)( unsigned int messageType );


/** @} */
/** @name Documentation Generation */
/** @{ */


/**
 *  Provides a string given `messageType` in the default
 *  localization (which is `en`).
 */
ctmbstr TY_(tidyDefaultString)( unsigned int messageType );

/*
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's list of localization string keys. Note that
 *  these are provided for documentation generation purposes
 *  and probably aren't useful for LibTidy implementors.
 */
TidyIterator TY_(getStringKeyList)(void);

/*
 *  Provides the next key value in Tidy's list of localized
 *  strings. Note that these are provided for documentation
 *  generation purposes and probably aren't useful to
 *  libtidy implementors.
 */
unsigned int TY_(getNextStringKey)( TidyIterator* iter );

/**
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's structure of Windows<->POSIX local mapping.
 *  Items can be retrieved with getNextWindowsLanguage();
 */
TidyIterator TY_(getWindowsLanguageList)(void);

/**
 *  Returns the next record of type `localeMapItem` in
 *  Tidy's structure of Windows<->POSIX local mapping.
 */
const tidyLocaleMapItemImpl *TY_(getNextWindowsLanguage)( TidyIterator* iter );

/**
 *  Given a `tidyLocaleMapItemImpl, return the Windows name.
 */
ctmbstr TY_(TidyLangWindowsName)( const tidyLocaleMapItemImpl *item );

/**
 *  Given a `tidyLocaleMapItemImpl, return the POSIX name.
 */
ctmbstr TY_(TidyLangPosixName)( const tidyLocaleMapItemImpl *item );

/**
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's list of installed language codes.
 *  Items can be retrieved with getNextInstalledLanguage();
 */
TidyIterator TY_(getInstalledLanguageList)(void);

/**
 *  Returns the next installed language.
 */
ctmbstr TY_(getNextInstalledLanguage)( TidyIterator* iter );


/** @} */

#endif /* language_h */
#ifndef language_en_h
#define language_en_h
/*
 * language_en.h
 * Localization support for HTML Tidy.
 *
 * This file consists of the strings for Tidy's base language and is a
 * required localization for Tidy to compile and work. Unlike the other
 * localization files this file is NOT machine-generated.
 *
 * This file also serves as the master template for generating additional
 * language localizations. As such do not edit PO files for this language;
 * modify this file directly.
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Created by Jim Derry on 11/28/15.
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_en(unsigned int n) {
    /* Plural-Forms: nplurals=2; */
    return n != 1;
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 *
 *  This file serves as the master template for generating `gettext`
 *  PO and POT files using our `potool.rb` script. Certain comments
 *  entered below will be included in the PO/POT files as developer
 *  comments. To enable this, use only standard C-style comments that
 *  begin immediately after the opening brace without whitespace.
 */

static languageDefinition language_en = { whichPluralForm_en, {
    /***************************************
     ** This MUST be present and first.
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,                0,   "en"
    },

    /*********************************************************************
     ** Options Documentation
     **  As of 2016-January these descriptions are used uniquely by the
     **  console application but are made available for LibTidy users as
     **  well. Because we generate documentation from these descriptions
     **  it's important to use ONLY the following tags:
     **    <code>, <em>, <strong>, <br/>, <p>
     **  Note that the xslt processor requires <br/> to be self closing!
     ** @remark enum source is TidyOptionId
     *********************************************************************/
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyAccessibilityCheckLevel,  0,
        "This option specifies what level of accessibility checking, if any, "
        "that Tidy should perform. "
        "<br/>"
        "Level <var>0 (Tidy Classic)</var> is equivalent to Tidy Classic's accessibility "
        "checking. "
        "<br/>"
        "For more information on Tidy's accessibility checking, visit "
        "<a href=\"http://www.html-tidy.org/accessibility/\"> Tidy's Accessibility Page</a>. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyAltText,                  0,
        "This option specifies the default <code>alt=</code> text Tidy uses for "
        "<code>&lt;img&gt;</code> attributes when the <code>alt=</code> attribute "
        "is missing. "
        "<br/>"
        "Use with care, as it is your responsibility to make your documents accessible "
        "to people who cannot see the images. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyAnchorAsName,             0,
        "This option controls the deletion or addition of the <code>name</code> "
        "attribute in elements where it can serve as anchor. "
        "<br/>"
        "If set to <var>yes</var> a <code>name</code> attribute, if not already "
        "existing, is added along an existing <code>id</code> attribute if the DTD "
        "allows it. "
        "<br/>"
        "If set to <var>no</var> any existing name attribute is removed if an "
        "<code>id</code> attribute exists or has been added. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyAsciiChars,               0,
        "Can be used to modify behavior of the <code>clean</code> option when set "
        "to <var>yes</var>. "
        "<br/>"
        "If set to <var>yes</var> when using <code>clean</code>, "
        "<code>&amp;emdash;</code>, <code>&amp;rdquo;</code>, and other named "
        "character entities are downgraded to their closest ASCII equivalents. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyBlockTags,                0,
        "This option specifies new block-level tags. This option takes a space or "
        "comma separated list of tag names. "
        "<br/>"
        "Unless you declare new tags, Tidy will refuse to generate a tidied file if "
        "the input includes previously unknown tags. "
        "<br/>"
        "Note you can't change the content model for elements such as "
        "<code>&lt;table&gt;</code>, <code>&lt;ul&gt;</code>, "
        "<code>&lt;ol&gt;</code> and <code>&lt;dl&gt;</code>. "
        "<br/>"
        "This option is ignored in XML mode. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyBodyOnly,                 0,
        "This option specifies if Tidy should print only the contents of the "
        "body tag as an HTML fragment. "
        "<br/>"
        "If set to <var>auto</var>, this is performed only if the body tag has "
        "been inferred. "
        "<br/>"
        "Useful for incorporating existing whole pages as a portion of another "
        "page. "
        "<br/>"
        "This option has no effect if XML output is requested. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyBreakBeforeBR,            0,
        "This option specifies if Tidy should output a line break before each "
        "<code>&lt;br&gt;</code> element. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyCharEncoding,             0,
        "This option specifies the character encoding Tidy uses for input, and "
        "when set, automatically chooses an appropriate character encoding to "
        "be used for output. The output encoding Tidy chooses may be different "
        "from the input encoding. "
        "<br/>"
        "For <var>ascii</var>, <var>latin0</var>, <var>ibm858</var>, "
        "<var>mac</var>, and <var>win1252</var> input encodings, the "
        "<code>output-encoding</code> option will automatically be set to "
        "<var>ascii</var>. You can set <code>output-encoding</code> manually "
        "to override this. "
        "<br/>"
        "For other input encodings, the <code>output-encoding</code> option "
        "will automatically be set to the the same value. "
        "<br/>"
        "Regardless of the preset value, you can set "
        "<code>output-encoding</code> manually to override this. "
        "<br/>"
        "Tidy is not an encoding converter. Although the Latin and UTF "
        "encodings can be mixed freely, it is not possible to convert Asian "
        "encodings to Latin encodings with Tidy. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyCoerceEndTags,            0,
        "This option specifies if Tidy should coerce a start tag into an end tag "
        "in cases where it looks like an end tag was probably intended; "
        "for example, given "
        "<br/>"
        "<code>&lt;span&gt;foo &lt;b&gt;bar&lt;b&gt; baz&lt;/span&gt;</code> "
        "<br/>"
        "Tidy will output "
        "<br/>"
        "<code>&lt;span&gt;foo &lt;b&gt;bar&lt;/b&gt; baz&lt;/span&gt;</code> "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyCSSPrefix,                0,
        "This option specifies the prefix that Tidy uses for styles rules. "
        "<br/>"
        "By default, <var>c</var> will be used. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyDecorateInferredUL,       0,
        "This option specifies if Tidy should decorate inferred "
        "<code>&lt;ul&gt;</code> elements with some CSS markup to avoid indentation "
        "to the right. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyDoctype,                  0,
        "This option specifies the DOCTYPE declaration generated by Tidy. "
        "<br/>"
        "If set to <var>omit</var> the output won't contain a DOCTYPE "
        "declaration. Note this this also implies <code>numeric-entities</code> is "
        "set to <var>yes</var>."
        "<br/>"
        "If set to <var>html5</var> the DOCTYPE is set to "
        "<code>&lt;!DOCTYPE html&gt;</code>."
        "<br/>"
        "If set to <var>auto</var> (the default) Tidy will use an educated guess "
        "based upon the contents of the document. Note that selecting this option "
        "will <em>not</em> change the current document's DOCTYPE on output. "
        "<br/>"
        "If set to <var>strict</var>, Tidy will set the DOCTYPE to the HTML4 or "
        "XHTML1 strict DTD."
        "<br/>"
        "If set to <var>loose</var>, the DOCTYPE is set to the HTML4 or XHTML1 "
        "loose (transitional) DTD."
        "<br/>"
        "Alternatively, you can supply a string for the formal public identifier "
        "(FPI)."
        "<br/>"
        "For example: "
        "<br/>"
        "<code>doctype: \"-//ACME//DTD HTML 3.14159//EN\"</code>"
        "<br/>"
        "If you specify the FPI for an XHTML document, Tidy will set the "
        "system identifier to an empty string. For an HTML document, Tidy adds a "
        "system identifier only if one was already present in order to preserve "
        "the processing mode of some browsers. Tidy leaves the DOCTYPE for "
        "generic XML documents unchanged. "
        "<br/>"
        "This option does not offer a validation of document conformance. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyDropEmptyElems,           0,
        "This option specifies if Tidy should discard empty elements. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyDropEmptyParas,           0,
        "This option specifies if Tidy should discard empty paragraphs. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyDropPropAttrs,            0,
        "This option specifies if Tidy should strip out proprietary attributes, "
        "such as Microsoft data binding attributes. Additionally attributes "
        "that aren't permitted in the output version of HTML will be dropped "
        "if used with <code>strict-tags-attributes</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyDuplicateAttrs,           0,
        "This option specifies if Tidy should keep the first or last attribute, if "
        "an attribute is repeated, e.g. has two <code>align</code> attributes. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyEmacs,                    0,
        "This option specifies that Tidy should change the format for reporting "
        "errors and warnings to a format that is more easily parsed by GNU Emacs "
        "or some other program.  It changes them from the default "
        "<br/>"
        "  line &lt;line number&gt; column &lt;column number&gt; - (Error|Warning): &lt;message&gt; "
        "<br/>"
        "to a form which includes the input filename: "
        "<br/>"
        "  &lt;filename&gt;:&lt;line number&gt;:&lt;column number&gt;: (Error|Warning): &lt;message&gt; "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyEmptyTags,                0,
        "This option specifies new empty inline tags. This option takes a space "
        "or comma separated list of tag names. "
        "<br/>"
        "Unless you declare new tags, Tidy will refuse to generate a tidied file if "
        "the input includes previously unknown tags. "
        "<br/>"
        "Remember to also declare empty tags as either inline or blocklevel. "
        "<br/>"
        "This option is ignored in XML mode. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyEncloseBlockText,         0,
        "This option specifies if Tidy should insert a <code>&lt;p&gt;</code> "
        "element to enclose any text it finds in any element that allows mixed "
        "content for HTML transitional but not HTML strict. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyEncloseBodyText,          0,
        "This option specifies if Tidy should enclose any text it finds in the "
        "body element within a <code>&lt;p&gt;</code> element."
        "<br/>"
        "This is useful when you want to take existing HTML and use it with a "
        "style sheet. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyErrFile,                  0,
        "This option specifies the error file Tidy uses for errors and warnings. "
        "Normally errors and warnings are output to <code>stderr</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyEscapeCdata,              0,
        "This option specifies if Tidy should convert "
        "<code>&lt;![CDATA[]]&gt;</code> sections to normal text. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyEscapeScripts,          0,
        "This option causes items that look like closing tags, like "
        "<code>&lt;/g</code> to be escaped to <code>&lt;\\/g</code>. Set "
        "this option to <var>no</var> if you do not want this."
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyFixBackslash,             0,
        "This option specifies if Tidy should replace backslash characters "
        "<code>\\</code> in URLs with forward slashes <code>/</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyFixComments,              0,
        "This option specifies if Tidy should replace unexpected hyphens with "
        "<code>=</code> characters when it comes across adjacent hyphens. "
        "<br/>"
        "The default is <var>auto</var> will which will act as <var>no</var> "
        "for HTML5 document types, and <var>yes</var> for all other document "
        "types. "
        "<br/>"
        "HTML has abandonded SGML comment syntax, and allows adjacent hypens "
        "for all versions of HTML, although XML and XHTML do not. If you plan "
        "to support older browsers that require SGML comment syntax, then "
        "consider setting this value to <var>yes</var>."
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyFixUri,                   0,
        "This option specifies if Tidy should check attribute values that carry "
        "URIs for illegal characters and if such are found, escape them as HTML4 "
        "recommends. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyForceOutput,              0,
        "This option specifies if Tidy should produce output even if errors are "
        "encountered. "
        "<br/>"
        "Use this option with care; if Tidy reports an error, this "
        "means Tidy was not able to (or is not sure how to) fix the error, so the "
        "resulting output may not reflect your intention. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyGDocClean,                0,
        "This option specifies if Tidy should enable specific behavior for "
        "cleaning up HTML exported from Google Docs. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyHideComments,             0,
        "This option specifies if Tidy should not print out comments. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyHtmlOut,                  0,
        "This option specifies if Tidy should generate pretty printed output, "
        "writing it as HTML. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyInCharEncoding,           0,
        "This option specifies the character encoding Tidy uses for input. "
        "Tidy makes certain assumptions about some of the input encodings. "
        "<br/>"
        "For <var>ascii</var>, Tidy will accept Latin-1 (ISO-8859-1) character "
        "values and convert them to entities as necessary. "
        "<br/>"
        "For <var>raw</var>, Tidy will make no assumptions about the character "
        "values and will pass them unchanged to output. "
        "<br/>"
        "For <var>mac</var> and <var>win1252</var>, vendor specific characters "
        "values will be accepted and converted to entities as necessary. "
        "<br/>"
        "Asian encodings such as <var>iso2022</var> will be handled "
        "appropriately assuming the corresponding <code>output-encoding</code> "
        "is also specified. "
        "<br/>"
        "Tidy is not an encoding converter. Although the Latin and UTF "
        "encodings can be mixed freely, it is not possible to convert Asian "
        "encodings to Latin encodings with Tidy. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyIndentAttributes,         0,
        "This option specifies if Tidy should begin each attribute on a new line. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyIndentCdata,              0,
        "This option specifies if Tidy should indent "
        "<code>&lt;![CDATA[]]&gt;</code> sections. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyIndentContent,            0,
        "This option specifies if Tidy should indent block-level tags. "
        "<br/>"
        "If set to <var>auto</var> Tidy will decide whether or not to indent the "
        "content of tags such as <code>&lt;title&gt;</code>, "
        "<code>&lt;h1&gt;</code>-<code>&lt;h6&gt;</code>, <code>&lt;li&gt;</code>, "
        "<code>&lt;td&gt;</code>, or <code>&lt;p&gt;</code> "
        "based on the content including a block-level element. "
        "<br/>"
        "Setting <code>indent</code> to <var>yes</var> can expose layout bugs in "
        "some browsers. "
        "<br/>"
        "Use the option <code>indent-spaces</code> to control the number of spaces "
        "or tabs output per level of indent, and <code>indent-with-tabs</code> to "
        "specify whether spaces or tabs are used. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyIndentSpaces,             0,
        "This option specifies the number of spaces or tabs that Tidy uses to "
        "indent content when <code>indent</code> is enabled. "
        "<br/>"
        "Note that the default value for this option is dependent upon the value of "
        "<code>indent-with-tabs</code> (see also). "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyInlineTags,               0,
        "This option specifies new non-empty inline tags. This option takes a "
        "space or comma separated list of tag names. "
        "<br/>"
        "Unless you declare new tags, Tidy will refuse to generate a tidied file if "
        "the input includes previously unknown tags. "
        "<br/>"
        "This option is ignored in XML mode. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyJoinClasses,              0,
        "This option specifies if Tidy should combine class names to generate "
        "a single, new class name if multiple class assignments are detected on "
        "an element. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyJoinStyles,               0,
        "This option specifies if Tidy should combine styles to generate a single, "
        "new style if multiple style values are detected on an element. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyKeepFileTimes,            0,
        "This option specifies if Tidy should keep the original modification time "
        "of files that Tidy modifies in place. "
        "<br/>"
        "Setting the option to <var>yes</var> allows you to tidy files without "
        "changing the file modification date, which may be useful with certain "
        "tools that use the modification date for things such as automatic server "
        "deployment."
        "<br/>"
        "Note this feature is not supported on some platforms. "
    },
    {/* Important notes for translators:
     - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
     <br/>.
     - Entities, tags, attributes, etc., should be enclosed in <code></code>.
     - Option values should be enclosed in <var></var>.
     - It's very important that <br/> be self-closing!
     - The strings "Tidy" and "HTML Tidy" are the program name and must not
     be translated. */
        TidyKeepTabs,            0,
        "With the default <var>no</var> Tidy will replace all source tabs with spaces, "
        "controlled by the option <code>tab-size</code>, and the current line offset. "
        "Of course, except in the special blocks/elements enumerated below, this will later "
        "be reduced to just one space. "
        "<br/>"
        "If set <var>yes</var> this option specifies Tidy should keep certain tabs "
        "found in the source, but only "
        "in preformatted blocks like <code>&lt;pre&gt;</code>, and other CDATA elements like "
        "<code>&lt;script&gt;</code>, <code>&lt;style&gt;</code>, and other pseudo elements like "
        "<code>&lt;?php ... ?&gt;</code>. As always, all other tabs, or sequences of tabs, in "
        "the source will continue to be replaced with a space. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyLiteralAttribs,           0,
        "This option specifies how Tidy deals with whitespace characters within "
        "attribute values. "
        "<br/>"
        "If the value is <var>no</var> Tidy normalizes attribute values by "
        "replacing any newline or tab with a single space, and further by replacing "
        "any contiguous whitespace with a single space. "
        "<br/>"
        "To force Tidy to preserve the original, literal values of all attributes "
        "and ensure that whitespace within attribute values is passed "
        "through unchanged, set this option to <var>yes</var>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyLogicalEmphasis,          0,
        "This option specifies if Tidy should replace any occurrence of "
        "<code>&lt;i&gt;</code> with <code>&lt;em&gt;</code> and any occurrence of "
        "<code>&lt;b&gt;</code> with <code>&lt;strong&gt;</code>. Any attributes "
        "are preserved unchanged. "
        "<br/>"
        "This option can be set independently of the <code>clean</code> option. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyLowerLiterals,            0,
        "This option specifies if Tidy should convert the value of an attribute "
        "that takes a list of predefined values to lower case. "
        "<br/>"
        "This is required for XHTML documents. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMakeBare,                 0,
        "This option specifies if Tidy should strip Microsoft specific HTML "
        "from Word 2000 documents, and output spaces rather than non-breaking "
        "spaces where they exist in the input. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMakeClean,                0,
        "This option specifies if Tidy should perform cleaning of some legacy "
        "presentational tags (currently <code>&lt;i&gt;</code>, "
        "<code>&lt;b&gt;</code>, <code>&lt;center&gt;</code> when enclosed "
        "within appropriate inline tags, and <code>&lt;font&gt;</code>). If "
        "set to <var>yes</var>, then the legacy tags will be replaced with CSS "
        "<code>&lt;style&gt;</code> tags and structural markup as appropriate. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMark,                     0,
        "This option specifies if Tidy should add a <code>meta</code> element to "
        "the document head to indicate that the document has been tidied. "
        "<br/>"
        "Tidy won't add a meta element if one is already present. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMergeDivs,                0,
        "This option can be used to modify the behavior of <code>clean</code> when "
        "set to <var>yes</var>."
        "<br/>"
        "This option specifies if Tidy should merge nested <code>&lt;div&gt;</code> "
        "such as <code>&lt;div&gt;&lt;div&gt;...&lt;/div&gt;&lt;/div&gt;</code>. "
        "<br/>"
        "If set to <var>auto</var> the attributes of the inner "
        "<code>&lt;div&gt;</code> are moved to the outer one. Nested "
        "<code>&lt;div&gt;</code> with <code>id</code> attributes are <em>not</em> "
        "merged. "
        "<br/>"
        "If set to <var>yes</var> the attributes of the inner "
        "<code>&lt;div&gt;</code> are discarded with the exception of "
        "<code>class</code> and <code>style</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMergeEmphasis,            0,
        "This option specifies if Tidy should merge nested <code>&lt;b&gt;</code> "
        "and <code>&lt;i&gt;</code> elements; for example, for the case "
        "<br/>"
        "<code>&lt;b class=\"rtop-2\"&gt;foo &lt;b class=\"r2-2\"&gt;bar&lt;/b&gt; baz&lt;/b&gt;</code>, "
        "<br/>"
        "Tidy will output <code>&lt;b class=\"rtop-2\"&gt;foo bar baz&lt;/b&gt;</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMergeSpans,               0,
        "This option can be used to modify the behavior of <code>clean</code> when "
        "set to <var>yes</var>."
        "<br/>"
        "This option specifies if Tidy should merge nested <code>&lt;span&gt;</code> "
        "such as <code>&lt;span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;</code>. "
        "<br/>"
        "The algorithm is identical to the one used by <code>merge-divs</code>. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyNCR,                      0,
        "This option specifies if Tidy should allow numeric character references. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyNewline,                  0,
        "The default is appropriate to the current platform. "
        "<br/>"
        "Genrally <var>CRLF</var> on PC-DOS, Windows and OS/2; <var>'\r'</var> "
        "on Classic Mac OS; and <var>'\n'</var> everywhere else (Linux, macOS, "
        "and Unix). "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyNumEntities,              0,
        "This option specifies if Tidy should output entities other than the "
        "built-in HTML entities (<code>&amp;amp;</code>, <code>&amp;lt;</code>, "
        "<code>&amp;gt;</code>, and <code>&amp;quot;</code>) in the numeric rather "
        "than the named entity form. "
        "<br/>"
        "Only entities compatible with the DOCTYPE declaration generated are used. "
        "<br/>"
        "Entities that can be represented in the output encoding are translated "
        "correspondingly. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyOmitOptionalTags,         0,
        "This option specifies if Tidy should omit optional start tags and end tags "
        "when generating output. "
        "<br/>"
        "Setting this option causes all tags for the <code>&lt;html&gt;</code>, "
        "<code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code> elements to be "
        "omitted from output, as well as such end tags as <code>&lt;/p&gt;</code>, "
        "<code>&lt;/li&gt;</code>, <code>&lt;/dt&gt;</code>, "
        "<code>&lt;/dd&gt;</code>, <code>&lt;/option&gt;</code>, "
        "<code>&lt;/tr&gt;</code>, <code>&lt;/td&gt;</code>, and "
        "<code>&lt;/th&gt;</code>. "
        "<br/>"
        "This option is ignored for XML output. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyOutCharEncoding,          0,
        "This option specifies the character encoding Tidy uses for "
        "output. Some of the output encodings affect whether or not "
        "some characters are translated to entities, although in all "
        "cases, some entities will be written according to other Tidy "
        "configuration options. "
        "<br/>"
        "For <var>ascii</var>, <var>mac</var>, and <var>win1252</var> "
        "output encodings, entities will be used for all characters "
        "with values over 127. "
        "<br/>"
        "For <var>raw</var> output, Tidy will write values above 127 "
        "without translating them to entities. "
        "<br/>"
        "Output using <var>latin1</var> will cause Tidy to write "
        "character values higher than 255 as entities. "
        "<br/>"
        "The UTF family such as <var>utf8</var> will write output "
        "in the respective UTF encoding. "
        "<br/>"
        "Asian output encodings such as <var>iso2022</var> will write "
        "output in the specified encoding, assuming a corresponding "
        "<code>input-encoding</code> was specified. "
        "<br/>"
        "Tidy is not an encoding converter. Although the Latin and UTF "
        "encodings can be mixed freely, it is not possible to convert Asian "
        "encodings to Latin encodings with Tidy. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyOutFile,                  0,
        "This option specifies the output file Tidy uses for markup. Normally "
        "markup is written to <code>stdout</code>. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyOutputBOM,                0,
        "This option specifies if Tidy should write a Unicode Byte Order Mark "
        "character (BOM; also known as Zero Width No-Break Space; has value of "
        "U+FEFF) to the beginning of the output, and only applies to UTF-8 and "
        "UTF-16 output encodings. "
        "<br/>"
        "If set to <var>auto</var> this option causes Tidy to write a BOM to "
        "the output only if a BOM was present at the beginning of the input. "
        "<br/>"
        "A BOM is always written for XML/XHTML output using UTF-16 output "
        "encodings. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyPPrintTabs,               0,
        "This option specifies if Tidy should indent with tabs instead of spaces, "
        "assuming <code>indent</code> is <var>yes</var>. "
        "<br/>"
        "Set it to <var>yes</var> to indent using tabs instead of the default "
        "spaces. "
        "<br/>"
        "Use the option <code>indent-spaces</code> to control the number of tabs "
        "output per level of indent. Note that when <code>indent-with-tabs</code> "
        "is enabled the default value of <code>indent-spaces</code> is reset to "
        "<var>1</var>. "
        "<br/>"
        "Note <code>tab-size</code> controls converting input tabs to spaces. Set "
        "it to zero to retain input tabs. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyPreserveEntities,         0,
        "This option specifies if Tidy should preserve well-formed entities "
        "as found in the input. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyPreTags,                  0,
        "This option specifies new tags that are to be processed in exactly the "
        "same way as HTML's <code>&lt;pre&gt;</code> element. This option takes a "
        "space or comma separated list of tag names. "
        "<br/>"
        "Unless you declare new tags, Tidy will refuse to generate a tidied file if "
        "the input includes previously unknown tags. "
        "<br/>"
        "Note you cannot as yet add new CDATA elements. "
        "<br/>"
        "This option is ignored in XML mode. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyPriorityAttributes,       0,
        "This option allows prioritizing the writing of attributes in tidied "
        "documents, allowing them to written before the other attributes of an "
        "element. For example, you might specify that <strong>id</strong> and "
        "<strong>name</strong> are written before every other attribute. "
        "<br/>"
        "This option takes a space or comma separated list of attribute names. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyPunctWrap,                0,
        "This option specifies if Tidy should line wrap after some Unicode or "
        "Chinese punctuation characters. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyQuiet,                    0,
        "When enabled, this option limits Tidy's non-document output to report "
        "only document warnings and errors. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyQuoteAmpersand,           0,
        "This option specifies if Tidy should output unadorned <code>&amp;</code> "
        "characters as <code>&amp;amp;</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyQuoteMarks,               0,
        "This option specifies if Tidy should output <code>&quot;</code> characters "
        "as <code>&amp;quot;</code> as is preferred by some editing environments. "
        "<br/>"
        "The apostrophe character <code>'</code> is written out as "
        "<code>&amp;#39;</code> since many web browsers don't yet support "
        "<code>&amp;apos;</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyQuoteNbsp,                0,
        "This option specifies if Tidy should output non-breaking space characters "
        "as entities, rather than as the Unicode character value 160 (decimal). "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyReplaceColor,             0,
        "This option specifies if Tidy should replace numeric values in color "
        "attributes with HTML/XHTML color names where defined, e.g. replace "
        "<code>#ffffff</code> with <code>white</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyShowErrors,               0,
        "This option specifies the number Tidy uses to determine if further errors "
        "should be shown. If set to <var>0</var>, then no errors are shown. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyShowFilename,             0,
        "This option specifies if Tidy should show the filename in messages. eg: "
        "<br/>"
        " tidy -q -e --show-filename yes index.html<br/>"
        " index.html: line 43 column 3 - Warning: replacing invalid UTF-8 bytes (char. code U+00A9) "
    },

    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyShowInfo,                 0,
        "This option specifies if Tidy should display info-level messages. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyShowMarkup,               0,
        "This option specifies if Tidy should generate a pretty printed version "
        "of the markup. Note that Tidy won't generate a pretty printed version if "
        "it finds significant errors (see <code>force-output</code>). "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyShowWarnings,             0,
        "This option specifies if Tidy should suppress warnings. This can be "
        "useful when a few errors are hidden in a flurry of warnings. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidySkipNested,               0,
        "This option specifies that Tidy should skip nested tags when parsing "
        "script and style data. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidySortAttributes,           0,
        "This option specifies that Tidy should sort attributes within an element "
        "using the specified sort algorithm. If set to <var>alpha</var>, the "
        "algorithm is an ascending alphabetic sort. "
        "<br/>"
        "When used while sorting with <code>priority-attributes</code>, any "
        "attribute sorting will take place after the priority attributes have "
        "been output. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMuteReports,           0,
        "Use this option to prevent Tidy from displaying certain types of "
        "report output, for example, for conditions that you wish to ignore. "
        "<br/>"
        "This option takes a list of one or more keys indicating the message "
        "type to mute. You can discover these message keys by using the "
        "<code>mute-id</code> configuration option and examining Tidy's "
        "output. " 
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyMuteShow,              0,
        "This option indicates whether or not Tidy should display message ID's "
        "with each of its error reports. This could be useful if you wanted to "
        "use the <code>mute</code> configuration option in order to filter "
        "out certain report messages. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyStrictTagsAttr,           0,
        "This options ensures that tags and attributes are applicable for the "
        "version of HTML that Tidy outputs. When set to <var>yes</var> and the "
        "output document type is a strict doctype, then Tidy will report "
        "errors. If the output document type is a loose or transitional "
        "doctype, then Tidy will report warnings. "
        "<br/>"
        "Additionally if <code>drop-proprietary-attributes</code> is enabled, "
        "then not applicable attributes will be dropped, too. "
        "<br/>"
        "When set to <var>no</var>, these checks are not performed. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyTabSize,                  0,
        "This option specifies the number of columns that Tidy uses between "
        "successive tab stops. It is used to map tabs to spaces when reading the "
        "input. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyUpperCaseAttrs,           0,
        "This option specifies if Tidy should output attribute names in upper "
        "case. "
        "<br/>"
        "When set to <var>no</var>, attribute names will be written in lower "
        "case. Specifying <var>yes</var> will output attribute names in upper "
        "case, and <var>preserve</var> can used to leave attribute names "
        "untouched. "
        "<br/>"
        "When using XML input, the original case is always preserved. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyUpperCaseTags,            0,
        "This option specifies if Tidy should output tag names in upper case. "
        "<br/>"
        "The default is <var>no</var> which results in lower case tag names, "
        "except for XML input where the original case is preserved. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyUseCustomTags,          0,
        "This option enables the use of tags for autonomous custom elements, "
        "e.g. <code>&lt;flag-icon&gt;</code> with Tidy. Custom tags are "
        "disabled if this value is <var>no</var>. Other settings - "
        "<var>blocklevel</var>, <var>empty</var>, <var>inline</var>, and "
        "<var>pre</var> will treat <em>all</em> detected custom tags "
        "accordingly. "
        "<br/>"
        "The use of <code>new-blocklevel-tags</code>, "
        "<code>new-empty-tags</code>, <code>new-inline-tags</code>, or "
        "<code>new-pre-tags</code> will override the treatment of custom tags "
        "by this configuration option. This may be useful if you have "
        "different types of custom tags."
        "<br/>"
        "When enabled these tags are determined during the processing of your "
        "document using opening tags; matching closing tags will be recognized "
        "accordingly, and unknown closing tags will be discarded. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyVertSpace,                0,
        "This option specifies if Tidy should add some extra empty lines for "
        "readability. "
        "<br/>"
        "The default is <var>no</var>. "
        "<br/>"
        "If set to <var>auto</var> Tidy will eliminate nearly all newline "
        "characters."
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWarnPropAttrs,            0,
        "This option specifies if Tidy should warn on proprietary attributes."
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWord2000,                 0,
        "This option specifies if Tidy should go to great pains to strip out "
        "all the surplus stuff Microsoft Word 2000 inserts when you save Word "
        "documents as \"Web pages\". It doesn't handle embedded images or VML. "
        "<br/>"
        "You should consider saving using Word's <strong>Save As...</strong>, "
        "and choosing <strong>Web Page, Filtered</strong>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapAsp,                  0,
        "This option specifies if Tidy should line wrap text contained within ASP "
        "pseudo elements, which look like: <code>&lt;% ... %&gt;</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapAttVals,              0,
        "This option specifies if Tidy should line-wrap attribute values, meaning "
        "that if the value of an attribute causes a line to exceed the width "
        "specified by <code>wrap</code>, Tidy will add one or more line breaks to "
        "the value, causing it to be wrapped into multiple lines. "
        "<br/>"
        "Note that this option can be set independently of "
        "<code>wrap-script-literals</code>. "
        "By default Tidy replaces any newline or tab with a single space and "
        "replaces any sequences of whitespace with a single space. "
        "<br/>"
        "To force Tidy to preserve the original, literal values of all attributes, "
        "and ensure that whitespace characters within attribute values are passed "
        "through unchanged, set <code>literal-attributes</code> to "
        "<var>yes</var>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapJste,                 0,
        "This option specifies if Tidy should line wrap text contained within "
        "JSTE pseudo elements, which look like: <code>&lt;# ... #&gt;</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapLen,                  0,
        "This option specifies the right margin Tidy uses for line wrapping. "
        "<br/>"
        "Tidy tries to wrap lines so that they do not exceed this length. "
        "<br/>"
        "Set <code>wrap</code> to <var>0</var> (zero) if you want to disable "
        "line wrapping. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapPhp,                  0,
        "This option specifies if Tidy should line wrap text contained within PHP "
        "pseudo elements, which look like: <code>&lt;?php ... ?&gt;</code>. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapScriptlets,           0,
        "This option specifies if Tidy should line wrap string literals that "
        "appear in script attributes. "
        "<br/>"
        "Tidy wraps long script string literals by inserting a backslash character "
        "before the line break. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWrapSection,              0,
        "This option specifies if Tidy should line wrap text contained within "
        "<code>&lt;![ ... ]&gt;</code> section tags. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyWriteBack,                0,
        "This option specifies if Tidy should write back the tidied markup to the "
        "same file it read from. "
        "<br/>"
        "You are advised to keep copies of important files before tidying them, as "
        "on rare occasions the result may not be what you expect. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyXhtmlOut,                 0,
        "This option specifies if Tidy should generate pretty printed output, "
        "writing it as extensible HTML. "
        "<br/>"
        "This option causes Tidy to set the DOCTYPE and default namespace as "
        "appropriate to XHTML, and will use the corrected value in output "
        "regardless of other sources. "
        "<br/>"
        "For XHTML, entities can be written as named or numeric entities according "
        "to the setting of <code>numeric-entities</code>. "
        "<br/>"
        "The original case of tags and attributes will be preserved, regardless of "
        "other options. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyXmlDecl,                  0,
        "This option specifies if Tidy should add the XML declaration when "
        "outputting XML or XHTML. "
        "<br/>"
        "Note that if the input already includes an <code>&lt;?xml ... ?&gt;</code> "
        "declaration then this option will be ignored. "
        "<br/>"
        "If the encoding for the output is different from <var>ascii</var>, one "
        "of the <var>utf*</var> encodings, or <var>raw</var>, then the "
        "declaration is always added as required by the XML standard. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyXmlOut,                   0,
        "This option specifies if Tidy should pretty print output, writing it as "
        "well-formed XML. "
        "<br/>"
        "Any entities not defined in XML 1.0 will be written as numeric entities to "
        "allow them to be parsed by an XML parser. "
        "<br/>"
        "The original case of tags and attributes will be preserved, regardless of "
        "other options. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyXmlPIs,                   0,
        "This option specifies if Tidy should change the parsing of processing "
        "instructions to require <code>?&gt;</code> as the terminator rather than "
        "<code>&gt;</code>. "
        "<br/>"
        "This option is automatically set if the input is in XML. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
      be translated. */
        TidyXmlSpace,                 0,
        "This option specifies if Tidy should add "
        "<code>xml:space=\"preserve\"</code> to elements such as "
        "<code>&lt;pre&gt;</code>, <code>&lt;style&gt;</code> and "
        "<code>&lt;script&gt;</code> when generating XML. "
        "<br/>"
        "This is needed if the whitespace in such elements is to "
        "be parsed appropriately without having access to the DTD. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyXmlTags,                  0,
        "This option specifies if Tidy should use the XML parser rather than the "
        "error correcting HTML parser. "
    },
    {/* Important notes for translators:
        - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
          <br/>.
        - Entities, tags, attributes, etc., should be enclosed in <code></code>.
        - Option values should be enclosed in <var></var>.
        - It's very important that <br/> be self-closing!
        - The strings "Tidy" and "HTML Tidy" are the program name and must not
          be translated. */
      TidyMetaCharset,             0,
        "This option, when enabled, adds a <code>&lt;meta&gt;</code> element "
        "and sets the <code>charset</code> attribute to the encoding of the "
        "document. Set this option to <var>yes</var> to enable it. "
    },
    {/* Important notes for translators:
      - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
      <br/>.
      - Entities, tags, attributes, etc., should be enclosed in <code></code>.
      - Option values should be enclosed in <var></var>.
      - It's very important that <br/> be self-closing!
      - The strings "Tidy" and "HTML Tidy" are the program name and must not
        be translated. */
      TidyShowMetaChange,             0,
        "This option enables a message whenever Tidy changes the "
        "<code>content</code> attribute of a meta charset declaration to match "
        "the encoding of the document. Set this option to <var>yes</var> to "
        "enable it. "
    },
    {/* Important notes for translators:
     - Use only <code></code>, <var></var>, <em></em>, <strong></strong>, and
     <br/>.
     - Entities, tags, attributes, etc., should be enclosed in <code></code>.
     - Option values should be enclosed in <var></var>.
     - It's very important that <br/> be self-closing!
     - The strings "Tidy" and "HTML Tidy" are the program name and must not
       be translated. */
      TidyStyleTags,                  0,
        "This option specifies if Tidy should move all style tags to the "
        "head of the document. "
    },


    /********************************************
     ** Message Severity Level
     ** @remark enum source TidyConfigCategory
     ********************************************/
    { TidyInfo,               0,   "Info: "          },
    { TidyWarning,            0,   "Warning: "       },
    { TidyConfig,             0,   "Config: "        },
    { TidyAccess,             0,   "Access: "        },
    { TidyError,              0,   "Error: "         },
    { TidyBadDocument,        0,   "Document: "      },
    { TidyFatal,              0,   "Panic: "         },
    { TidyDialogueSummary,    0,   "Summary: "       },
    { TidyDialogueInfo,       0,   "Information: "   },
    { TidyDialogueFootnote,   0,   "Footnote: "      },
    
    
    /********************************************
     ** Miscellaneous Strings
     ** @remark enum source TidyStrings
     ** @remark enum generator FOREACH_MSG_MISC
     ********************************************/
    { LINE_COLUMN_STRING,           0,   "line %d column %d - "                                                    },
    { FN_LINE_COLUMN_STRING,        0,   "%s: line %d column %d - "                                                },
    {/* For example, "discarding invalid UTF-16 surrogate pair" */
      STRING_DISCARDING,            0,   "discarding"
    },
    { STRING_ERROR_COUNT_ERROR,     0,   "error"                                                                   },
    { STRING_ERROR_COUNT_ERROR,     1,   "errors"                                                                  },
    { STRING_ERROR_COUNT_WARNING,   0,   "warning"                                                                 },
    { STRING_ERROR_COUNT_WARNING,   1,   "warnings"                                                                },
    { STRING_HELLO_ACCESS,          0,   "\nAccessibility Checks:\n"                                               },
    {/* This is not a formal name and can be translated. */
      STRING_HTML_PROPRIETARY,      0,   "HTML Proprietary"
    },
    { STRING_XML_DECLARATION,       0,   "XML declaration"                                                         },
    { STRING_PLAIN_TEXT,            0,   "plain text"                                                              },
    {/* For example, "replacing invalid UTF-8 bytes" */
      STRING_REPLACING,             0,   "replacing"
    },
    {/* For example, "you should avoid using the specified encoding." */
      STRING_SPECIFIED,             0,   "specified"
    },
    { TIDYCUSTOMNO_STRING,          0,   "no"                                                                      },
    { TIDYCUSTOMBLOCKLEVEL_STRING,  0,   "block level"                                                             },
    { TIDYCUSTOMEMPTY_STRING,       0,   "empty"                                                                   },
    { TIDYCUSTOMINLINE_STRING,      0,   "inline"                                                                  },
    { TIDYCUSTOMPRE_STRING,         0,   "pre"                                                                     },
  
    
    /********************************************
     ** Footnote Strings
     ** @remark enum source TidyStrings
     ** @rename enum generator FOREACH_FOOTNOTE_MSG
     ********************************************/
    {/* This console output should be limited to 78 characters per line. */
      TEXT_HTML_T_ALGORITHM,        0,
        "\n"
        "      - First, search left from the cell's position to find row header cells.\n"
        "      - Then search upwards to find column header cells.\n"
        "      - The search in a given direction stops when the edge of the table is\n"
        "        reached or when a data cell is found after a header cell.\n"
        "      - Row headers are inserted into the list in the order they appear in\n"
        "        the table. \n"
        "      - For left-to-right tables, headers are inserted from left to right.\n"
        "      - Column headers are inserted after row headers, in \n"
        "        the order they appear in the table, from top to bottom. \n"
        "      - If a header cell has the headers attribute set, then the headers \n"
        "        referenced by this attribute are inserted into the list and the \n"
        "        search stops for the current direction.\n"
        "        TD cells that set the axis attribute are also treated as header cells.\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - %s represents a string-encoding name which may be localized in your language. */
      TEXT_VENDOR_CHARS,            0,
        "It is unlikely that vendor-specific, system-dependent encodings\n"
        "work widely enough on the World Wide Web; you should avoid using the \n"
        "%s character encoding, instead you are recommended to\n"
        "use named entities, e.g. &trade;.\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - %s represents a string-encoding name which may be localized in your language.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TEXT_SGML_CHARS,              0,
        "Character codes 128 to 159 (U+0080 to U+009F) are not allowed in HTML;\n"
        "even if they were, they would likely be unprintable control characters.\n"
        "Tidy assumed you wanted to refer to a character with the same byte value in the \n"
        "%s encoding and replaced that reference with the Unicode \n"
        "equivalent.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_INVALID_UTF8,            0,
        "Character codes for UTF-8 must be in the range: U+0000 to U+10FFFF.\n"
        "The definition of UTF-8 in Annex D of ISO/IEC 10646-1:2000 also\n"
        "allows for the use of five- and six-byte sequences to encode\n"
        "characters that are outside the range of the Unicode character set;\n"
        "those five- and six-byte sequences are illegal for the use of\n"
        "UTF-8 as a transformation of Unicode characters. ISO/IEC 10646\n"
        "does not allow mapping of unpaired surrogates, nor U+FFFE and U+FFFF\n"
        "(but it does allow other noncharacters). For more information please refer to\n"
        "http://www.unicode.org/ and http://www.cl.cam.ac.uk/~mgk25/unicode.html\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_INVALID_UTF16,           0,
        "Character codes for UTF-16 must be in the range: U+0000 to U+10FFFF.\n"
        "The definition of UTF-16 in Annex C of ISO/IEC 10646-1:2000 does not allow the\n"
        "mapping of unpaired surrogates. For more information please refer to\n"
        "http://www.unicode.org/ and http://www.cl.cam.ac.uk/~mgk25/unicode.html\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TEXT_INVALID_URI,             0,
        "URIs must be properly escaped, they must not contain unescaped\n"
        "characters below U+0021 including the space character and not\n"
        "above U+007E. Tidy escapes the URI for you as recommended by\n"
        "HTML 4.01 section B.2.1 and XML 1.0 section 4.2.2. Some user agents\n"
        "use another algorithm to escape such URIs and some server-sided\n"
        "scripts depend on that. If you want to depend on that, you must\n"
        "escape the URI on your own. For more information please refer to\n"
        "http://www.w3.org/International/O-URL-and-ident.html\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_BAD_FORM,                0,
        "You may need to move one or both of the <form> and </form>\n"
        "tags. HTML elements should be properly nested and form elements\n"
        "are no exception. For instance you should not place the <form>\n"
        "in one table cell and the </form> in another. If the <form> is\n"
        "placed before a table, the </form> cannot be placed inside the\n"
        "table! Note that one form can't be nested inside another!\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_BAD_MAIN,                0,
        "Only one <main> element is allowed in a document.\n"
        "Subsequent <main> elements have been discarded, which may\n"
        "render the document invalid.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_M_SUMMARY,               0,
        "The table summary attribute should be used to describe\n"
        "the table structure. It is very helpful for people using\n"
        "non-visual browsers. The scope and headers attributes for\n"
        "table cells are useful for specifying which headers apply\n"
        "to each table cell, enabling non-visual browsers to provide\n"
        "a meaningful context for each cell.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_M_IMAGE_ALT,             0,
        "The alt attribute should be used to give a short description\n"
        "of an image; longer descriptions should be given with the\n"
        "longdesc attribute which takes a URL linked to the description.\n"
        "These measures are needed for people using non-graphical browsers.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_M_IMAGE_MAP,             0,
        "Use client-side image maps in preference to server-side image\n"
        "maps as the latter are inaccessible to people using non-\n"
        "graphical browsers. In addition, client-side maps are easier\n"
        "to set up and provide immediate feedback to users.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_M_LINK_ALT,              0,
        "For hypertext links defined using a client-side image map, you\n"
        "need to use the alt attribute to provide a textual description\n"
        "of the link for people using non-graphical browsers.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_USING_FRAMES,            0,
        "Pages designed using frames present problems for\n"
        "people who are either blind or using a browser that\n"
        "doesn't support frames. A frames-based page should always\n"
        "include an alternative layout inside a NOFRAMES element.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      FOOTNOTE_TRIM_EMPTY_ELEMENT,  0,
        "One or more empty elements were present in the source document but\n"
        "dropped on output. If these elements are necessary or you don't want\n"
        "this behavior, then consider setting the option \"drop-empty-elements\"\n"
        "to no.\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The URL should not be translated unless you find a matching URL in your language. */
      TEXT_ACCESS_ADVICE1,          0,
        "For further advice on how to make your pages accessible\n"
        "see http://www.w3.org/WAI/GL."
    },
    {/* This console output should be limited to 78 characters per line.
        - The URL should not be translated unless you find a matching URL in your language. */
      TEXT_ACCESS_ADVICE2,          0,
        "For further advice on how to make your pages accessible\n"
        "see http://www.w3.org/WAI/GL and http://www.html-tidy.org/accessibility/."
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_USING_LAYER,             0,
        "The Cascading Style Sheets (CSS) Positioning mechanism\n"
        "is recommended in preference to the proprietary <LAYER>\n"
        "element due to limited vendor support for LAYER.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_USING_SPACER,            0,
        "You are recommended to use CSS for controlling white\n"
        "space (e.g. for indentation, margins and line spacing).\n"
        "The proprietary <SPACER> element has limited vendor support.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_USING_FONT,              0,
        "You are recommended to use CSS to specify the font and\n"
        "properties such as its size and color. This will reduce\n"
        "the size of HTML files and make them easier to maintain\n"
        "compared with using <FONT> elements.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_USING_NOBR,              0,
        "You are recommended to use CSS to control line wrapping.\n"
        "Use \"white-space: nowrap\" to inhibit wrapping in place\n"
        "of inserting <NOBR>...</NOBR> into the markup.\n"
    },
    {/* This console output should be limited to 78 characters per line. */
      TEXT_USING_BODY,              0,
        "You are recommended to use CSS to specify page and link colors"
    },
    
    /********************************************
     ** Miscellaneous Dialogue Strings
     ** @remark enum source TidyStrings
     ** @rename enum generator FOREACH_DIALOG_MSG
     ********************************************/
    { STRING_CONTENT_LOOKS,         0,   "Document content looks like %s"                                          },
    { STRING_DOCTYPE_GIVEN,         0,   "Doctype given is \"%s\""                                                 },
    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      STRING_ERROR_COUNT,           0,   "Tidy found %u %s and %u %s!\n"
    },
    {/* This console output should be limited to 78 characters per line.
      - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      STRING_NEEDS_INTERVENTION,    0,
        "This document has errors that must be fixed before\n"
        "using HTML Tidy to generate a tidied up version.\n"
    },
    { STRING_NO_ERRORS,             0,   "No warnings or errors were found.\n"                                     },
    { STRING_NO_SYSID,              0,   "No system identifier in emitted doctype"                                 },
    { STRING_NOT_ALL_SHOWN,         0,   "Tidy found %u %s and %u %s! Not all warnings/errors were shown.\n"       },
    {/* This console output should be limited to 78 characters per line.
      - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TEXT_GENERAL_INFO,            0,
        "About HTML Tidy: https://github.com/htacg/tidy-html5\n"
        "Bug reports and comments: https://github.com/htacg/tidy-html5/issues\n"
        "Official mailing list: https://lists.w3.org/Archives/Public/public-htacg/\n"
        "Latest HTML specification: http://dev.w3.org/html5/spec-author-view/\n"
        "Validate your HTML documents: http://validator.w3.org/nu/\n"
        "Lobby your company to join the W3C: http://www.w3.org/Consortium\n"
    },
    {/* This console output should be limited to 78 characters per line. 
      - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
      - Don't terminate the last line with a newline. */
      TEXT_GENERAL_INFO_PLEA,       0,
        "Do you speak a language other than English, or a different variant of \n"
        "English? Consider helping us to localize HTML Tidy. For details please see \n"
        "https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md"
    },
    

    /********************************************
     ** Report Output
     ** @remark enum source TidyStrings
     ** @rename enum generator FOREACH_REPORT_MSG
     ********************************************/    
    { ADDED_MISSING_CHARSET,        0,   "Added appropriate missing <meta charset=...> to %s"                      },
    { ANCHOR_NOT_UNIQUE,            0,   "%s anchor \"%s\" already defined"                                        },
    { ANCHOR_DUPLICATED,            0,   "Implicit %s anchor \"%s\" duplicated by Tidy."                           },
    { APOS_UNDEFINED,               0,   "named entity &apos; only defined in XML/XHTML"                           },
    { ATTR_VALUE_NOT_LCASE,         0,   "%s attribute value \"%s\" must be lower case for XHTML"                  },
    { ATTRIBUTE_IS_NOT_ALLOWED,     0,   "%s attribute \"is\" not allowed for autonomous custom tags."             },
    { ATTRIBUTE_VALUE_REPLACED,     0,   "%s attribute \"%s\", incorrect value \"%s\" replaced"                    },
    { BACKSLASH_IN_URI,             0,   "%s URI reference contains backslash. Typo?"                              },
    { BAD_ATTRIBUTE_VALUE_REPLACED, 0,   "%s attribute \"%s\" had invalid value \"%s\" and has been replaced"      },
    { BAD_ATTRIBUTE_VALUE,          0,   "%s attribute \"%s\" has invalid value \"%s\""                            },
    { BAD_CDATA_CONTENT,            0,   "'<' + '/' + letter not allowed here"                                     },
    { BAD_SUMMARY_HTML5,            0,   "The summary attribute on the %s element is obsolete in HTML5"            },
    { BAD_SURROGATE_LEAD,           0,   "Trailing (Low) surrogate pair U+%04X, with no leading (High) entity, replaced with U+FFFD." },
    { BAD_SURROGATE_PAIR,           0,   "Have out-of-range surrogate pair U+%04X:U+%04X, replaced with U+FFFD value."                },
    { BAD_SURROGATE_TAIL,           0,   "Leading (High) surrogate pair U+%04X, with no trailing (Low) entity, replaced with U+FFFD." },
    { CANT_BE_NESTED,               0,   "%s can't be nested"                                                      },
    { COERCE_TO_ENDTAG,             0,   "<%s> is probably intended as </%s>"                                      },
    { CONTENT_AFTER_BODY,           0,   "content occurs after end of body"                                        },
    { CUSTOM_TAG_DETECTED,          0,   "detected autonomous custom tag %s; will treat as %s"                     },
    { DISCARDING_UNEXPECTED,        0,   "discarding unexpected %s"                                                },
    { DOCTYPE_AFTER_TAGS,           0,   "<!DOCTYPE> isn't allowed after elements"                                 },
    { DUPLICATE_FRAMESET,           0,   "repeated FRAMESET element"                                               },
    { ELEMENT_NOT_EMPTY,            0,   "%s element not empty or not closed"                                      },
    { ELEMENT_VERS_MISMATCH_ERROR,  0,   "%s element not available in %s"                                          },
    { ELEMENT_VERS_MISMATCH_WARN,   0,   "%s element not available in %s"                                          },
    { ENCODING_MISMATCH,            0,   "specified input encoding (%s) does not match actual input encoding (%s)" },
    { ESCAPED_ILLEGAL_URI,          0,   "%s escaping malformed URI reference"                                     },
    { FILE_CANT_OPEN,               0,   "Can't open \"%s\"\n"                                                     },
    { FILE_CANT_OPEN_CFG,           0,   "Can't open configuration file \"%s\"\n"                                  },
    { FILE_NOT_FILE,                0,   "\"%s\" is not a file!\n"                                                 },
    { FIXED_BACKSLASH,              0,   "%s converting backslash in URI to slash"                                 },
    { FOUND_STYLE_IN_BODY,          0,   "found <style> tag in <body>! fix-style-tags: yes to move."               },
    { ID_NAME_MISMATCH,             0,   "%s id and name attribute value mismatch"                                 },
    { ILLEGAL_NESTING,              0,   "%s shouldn't be nested"                                                  },
    { ILLEGAL_URI_CODEPOINT,        0,   "%s illegal characters found in URI"                                      },
    { ILLEGAL_URI_REFERENCE,        0,   "%s improperly escaped URI reference"                                     },
    { INSERTING_AUTO_ATTRIBUTE,     0,   "%s inserting \"%s\" attribute using value \"%s\""                        },
    { INSERTING_TAG,                0,   "inserting implicit <%s>"                                                 },
    { INVALID_ATTRIBUTE,            0,   "%s attribute name \"%s\" (value=\"%s\") is invalid"                      },
    { INVALID_NCR,                  0,   "%s invalid numeric character reference %s"                               },
    { INVALID_SGML_CHARS,           0,   "%s invalid character code %s"                                            },
    { INVALID_UTF8,                 0,   "%s invalid UTF-8 bytes (char. code %s)"                                  },
    { INVALID_UTF16,                0,   "%s invalid UTF-16 surrogate pair (char. code %s)"                        },
    { INVALID_XML_ID,               0,   "%s cannot copy name attribute to id"                                     },
    { JOINING_ATTRIBUTE,            0,   "%s joining values of repeated attribute \"%s\""                          },
    { MALFORMED_COMMENT,            0,   "tidy replaced adjacent \"-\" with \"=\""                                 },
    { MALFORMED_COMMENT_DROPPING,   0,   "dropping a possible comment due to a missing hyphen"                     },
    { MALFORMED_COMMENT_EOS,        0,   "the end of the document was reached before the end of the comment"       },
    { MALFORMED_COMMENT_WARN,       0,   "detected adjacent hyphens within the comment; consider fix-bad-comments" },
    { MALFORMED_DOCTYPE,            0,   "discarding malformed <!DOCTYPE>"                                         },
    { MISMATCHED_ATTRIBUTE_ERROR,   0,   "%s attribute \"%s\" not allowed for %s"                                  },
    { MISMATCHED_ATTRIBUTE_WARN,    0,   "%s attribute \"%s\" not allowed for %s"                                  },
    { MISSING_ATTR_VALUE,           0,   "%s attribute \"%s\" lacks value"                                         },
    { MISSING_ATTRIBUTE,            0,   "%s lacks \"%s\" attribute"                                               },
    { MISSING_DOCTYPE,              0,   "missing <!DOCTYPE> declaration"                                          },
    { MISSING_ENDTAG_BEFORE,        0,   "missing </%s> before %s"                                                 },
    { MISSING_ENDTAG_FOR,           0,   "missing </%s>"                                                           },
    { MISSING_ENDTAG_OPTIONAL,      0,   "missing optional end tag </%s>"                                          },
    { MISSING_IMAGEMAP,             0,   "%s should use client-side image map"                                     },
    { MISSING_QUOTEMARK,            0,   "%s attribute with missing trailing quote mark"                           },
    { MISSING_QUOTEMARK_OPEN,       0,   "value for attribute \"%s\" missing quote marks"                          },
    { MISSING_SEMICOLON_NCR,        0,   "numeric character reference \"%s\" doesn't end in ';'"                   },
    { MISSING_SEMICOLON,            0,   "entity \"%s\" doesn't end in ';'"                                        },
    { MISSING_STARTTAG,             0,   "missing <%s>"                                                            },
    { MISSING_TITLE_ELEMENT,        0,   "inserting missing 'title' element"                                       },
    { MOVED_STYLE_TO_HEAD,          0,   "moved <style> tag to <head>! fix-style-tags: no to avoid."               },
    { NESTED_EMPHASIS,              0,   "nested emphasis %s"                                                      },
    { NESTED_QUOTATION,             0,   "nested q elements, possible typo."                                       },
    { NEWLINE_IN_URI,               0,   "%s discarding newline in URI reference"                                  },
    { NOFRAMES_CONTENT,             0,   "%s not inside 'noframes' element"                                        },
    { NON_MATCHING_ENDTAG,          0,   "replacing unexpected %s with </%s>"                                      },
    { OBSOLETE_ELEMENT,             0,   "replacing obsolete element %s with %s"                                   },
    { OPTION_REMOVED,               0,   "option \"%s\" no longer exists, and no replacement could be found."      },
    { OPTION_REMOVED_APPLIED,       0,   "option \"%s\" replaced with \"%s\", which Tidy has set to \"%s\"."       },
    { OPTION_REMOVED_UNAPPLIED,     0,   "option \"%s\" replaced with \"%s\", but Tidy could not set it for you."  },
    { PREVIOUS_LOCATION,            0,   "<%s> previously mentioned"                                               },
    { PROPRIETARY_ATTR_VALUE,       0,   "%s proprietary attribute value \"%s\""                                   },
    { PROPRIETARY_ATTRIBUTE,        0,   "%s proprietary attribute \"%s\""                                         },
    { PROPRIETARY_ELEMENT,          0,   "%s is not approved by W3C"                                               },
    { REMOVED_HTML5,                0,   "%s element removed from HTML5"                                           },
    { REPEATED_ATTRIBUTE,           0,   "%s dropping value \"%s\" for repeated attribute \"%s\""                  },
    { REPLACING_ELEMENT,            0,   "replacing %s with %s"                                                    },
    { REPLACING_UNEX_ELEMENT,       0,   "replacing unexpected %s with %s"                                         },
    { SPACE_PRECEDING_XMLDECL,      0,   "removing whitespace preceding XML Declaration"                           },
    { STRING_ARGUMENT_BAD,          0,   "option \"%s\" given bad argument \"%s\""                                 },
    { STRING_MISSING_MALFORMED,     0,   "missing or malformed argument for option: %s"                            },
    { STRING_MUTING_TYPE,           0,   "messages of type \"%s\" will not be output"                              },
    { STRING_UNKNOWN_OPTION,        0,   "unknown option: %s"                                                      },
    { SUSPECTED_MISSING_QUOTE,      0,   "suspected missing quote mark for attribute value"                        },
    { TAG_NOT_ALLOWED_IN,           0,   "%s isn't allowed in <%s> elements"                                       },
    { TOO_MANY_ELEMENTS_IN,         0,   "too many %s elements in <%s>"                                            },
    { TOO_MANY_ELEMENTS,            0,   "too many %s elements"                                                    },
    { TRIM_EMPTY_ELEMENT,           0,   "trimming empty %s"                                                       },
    { UNESCAPED_AMPERSAND,          0,   "unescaped & which should be written as &amp;"                            },
    { UNEXPECTED_END_OF_FILE_ATTR,  0,   "%s end of file while parsing attributes"                                 },
    { UNEXPECTED_END_OF_FILE,       0,   "unexpected end of file %s"                                               },
    { UNEXPECTED_ENDTAG_ERR,        0,   "unexpected </%s>"                                                        },
    { UNEXPECTED_ENDTAG_IN,         0,   "unexpected </%s> in <%s>"                                                },
    { UNEXPECTED_ENDTAG,            0,   "unexpected </%s>"                                                        },
    { UNEXPECTED_EQUALSIGN,         0,   "%s unexpected '=', expected attribute name"                              },
    { UNEXPECTED_GT,                0,   "%s missing '>' for end of tag"                                           },
    { UNEXPECTED_QUOTEMARK,         0,   "%s unexpected or duplicate quote mark"                                   },
    { UNKNOWN_ELEMENT_LOOKS_CUSTOM, 0,   "%s is not recognized! Did you mean to enable the custom-tags option?"    },
    { UNKNOWN_ELEMENT,              0,   "%s is not recognized!"                                                   },
    { UNKNOWN_ENTITY,               0,   "unescaped & or unknown entity \"%s\""                                    },
    { USING_BR_INPLACE_OF,          0,   "using <br> in place of %s"                                               },
    { VENDOR_SPECIFIC_CHARS,        0,   "%s invalid character code %s"                                            },
    { WHITE_IN_URI,                 0,   "%s discarding whitespace in URI reference"                               },
    { XML_DECLARATION_DETECTED,     0,   "An XML declaration was detected. Did you mean to use input-xml?"         },
    { XML_ID_SYNTAX,                0,   "%s ID \"%s\" uses XML ID syntax"                                         },


    /***************************************
     ** Report Output -- Accessibility
     ***************************************/
    { IMG_MISSING_ALT,                               0,   "[1.1.1.1]: <img> missing 'alt' text."                                     },
    { IMG_ALT_SUSPICIOUS_FILENAME,                   0,   "[1.1.1.2]: suspicious 'alt' text (filename)."                             },
    { IMG_ALT_SUSPICIOUS_FILE_SIZE,                  0,   "[1.1.1.3]: suspicious 'alt' text (file size)."                            },
    { IMG_ALT_SUSPICIOUS_PLACEHOLDER,                0,   "[1.1.1.4]: suspicious 'alt' text (placeholder)."                          },
    { IMG_ALT_SUSPICIOUS_TOO_LONG,                   0,   "[1.1.1.10]: suspicious 'alt' text (too long)."                            },
    { IMG_MISSING_LONGDESC_DLINK,                    0,   "[1.1.2.1]: <img> missing 'longdesc' and d-link."                          },
    { IMG_MISSING_DLINK,                             0,   "[1.1.2.2]: <img> missing d-link."                                         },
    { IMG_MISSING_LONGDESC,                          0,   "[1.1.2.3]: <img> missing 'longdesc'."                                     },
    { IMG_BUTTON_MISSING_ALT,                        0,   "[1.1.3.1]: <img> (button) missing 'alt' text."                            },
    { APPLET_MISSING_ALT,                            0,   "[1.1.4.1]: <applet> missing alternate content."                           },
    { OBJECT_MISSING_ALT,                            0,   "[1.1.5.1]: <object> missing alternate content."                           },
    { AUDIO_MISSING_TEXT_WAV,                        0,   "[1.1.6.1]: audio missing text transcript (wav)."                          },
    { AUDIO_MISSING_TEXT_AU,                         0,   "[1.1.6.2]: audio missing text transcript (au)."                           },
    { AUDIO_MISSING_TEXT_AIFF,                       0,   "[1.1.6.3]: audio missing text transcript (aiff)."                         },
    { AUDIO_MISSING_TEXT_SND,                        0,   "[1.1.6.4]: audio missing text transcript (snd)."                          },
    { AUDIO_MISSING_TEXT_RA,                         0,   "[1.1.6.5]: audio missing text transcript (ra)."                           },
    { AUDIO_MISSING_TEXT_RM,                         0,   "[1.1.6.6]: audio missing text transcript (rm)."                           },
    { FRAME_MISSING_LONGDESC,                        0,   "[1.1.8.1]: <frame> may require 'longdesc'."                               },
    { AREA_MISSING_ALT,                              0,   "[1.1.9.1]: <area> missing 'alt' text."                                    },
    { SCRIPT_MISSING_NOSCRIPT,                       0,   "[1.1.10.1]: <script> missing <noscript> section."                         },
    { ASCII_REQUIRES_DESCRIPTION,                    0,   "[1.1.12.1]: ascii art requires description."                              },
    { IMG_MAP_SERVER_REQUIRES_TEXT_LINKS,            0,   "[1.2.1.1]: image map (server-side) requires text links."                  },
    { MULTIMEDIA_REQUIRES_TEXT,                      0,   "[1.4.1.1]: multimedia requires synchronized text equivalents."            },
    { IMG_MAP_CLIENT_MISSING_TEXT_LINKS,             0,   "[1.5.1.1]: image map (client-side) missing text links."                   },
    { INFORMATION_NOT_CONVEYED_IMAGE,                0,   "[2.1.1.1]: ensure information not conveyed through color alone (image)."  },
    { INFORMATION_NOT_CONVEYED_APPLET,               0,   "[2.1.1.2]: ensure information not conveyed through color alone (applet)." },
    { INFORMATION_NOT_CONVEYED_OBJECT,               0,   "[2.1.1.3]: ensure information not conveyed through color alone (object)." },
    { INFORMATION_NOT_CONVEYED_SCRIPT,               0,   "[2.1.1.4]: ensure information not conveyed through color alone (script)." },
    { INFORMATION_NOT_CONVEYED_INPUT,                0,   "[2.1.1.5]: ensure information not conveyed through color alone (input)."  },
    { COLOR_CONTRAST_TEXT,                           0,   "[2.2.1.1]: poor color contrast (text)."                                   },
    { COLOR_CONTRAST_LINK,                           0,   "[2.2.1.2]: poor color contrast (link)."                                   },
    { COLOR_CONTRAST_ACTIVE_LINK,                    0,   "[2.2.1.3]: poor color contrast (active link)."                            },
    { COLOR_CONTRAST_VISITED_LINK,                   0,   "[2.2.1.4]: poor color contrast (visited link)."                           },
    { DOCTYPE_MISSING,                               0,   "[3.2.1.1]: <doctype> missing."                                            },
    { STYLE_SHEET_CONTROL_PRESENTATION,              0,   "[3.3.1.1]: use style sheets to control presentation."                     },
    { HEADERS_IMPROPERLY_NESTED,                     0,   "[3.5.1.1]: headers improperly nested."                                    },
    { POTENTIAL_HEADER_BOLD,                         0,   "[3.5.2.1]: potential header (bold)."                                      },
    { POTENTIAL_HEADER_ITALICS,                      0,   "[3.5.2.2]: potential header (italics)."                                   },
    { POTENTIAL_HEADER_UNDERLINE,                    0,   "[3.5.2.3]: potential header (underline)."                                 },
    { HEADER_USED_FORMAT_TEXT,                       0,   "[3.5.3.1]: header used to format text."                                   },
    { LIST_USAGE_INVALID_UL,                         0,   "[3.6.1.1]: list usage invalid <ul>."                                      },
    { LIST_USAGE_INVALID_OL,                         0,   "[3.6.1.2]: list usage invalid <ol>."                                      },
    { LIST_USAGE_INVALID_LI,                         0,   "[3.6.1.4]: list usage invalid <li>."                                      },
    { LANGUAGE_NOT_IDENTIFIED,                       0,   "[4.3.1.1]: language not identified."                                      },
    { LANGUAGE_INVALID,                              0,   "[4.3.1.2]: language attribute invalid."                                   },
    { DATA_TABLE_MISSING_HEADERS,                    0,   "[5.1.2.1]: data <table> missing row/column headers (all)."                },
    { DATA_TABLE_MISSING_HEADERS_COLUMN,             0,   "[5.1.2.2]: data <table> missing row/column headers (1 col)."              },
    { DATA_TABLE_MISSING_HEADERS_ROW,                0,   "[5.1.2.3]: data <table> missing row/column headers (1 row)."              },
    { DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS,      0,   "[5.2.1.1]: data <table> may require markup (column headers)."             },
    { DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS,         0,   "[5.2.1.2]: data <table> may require markup (row headers)."                },
    { LAYOUT_TABLES_LINEARIZE_PROPERLY,              0,   "[5.3.1.1]: verify layout tables linearize properly."                      },
    { LAYOUT_TABLE_INVALID_MARKUP,                   0,   "[5.4.1.1]: invalid markup used in layout <table>."                        },
    { TABLE_MISSING_SUMMARY,                         0,   "[5.5.1.1]: <table> missing summary."                                      },
    { TABLE_SUMMARY_INVALID_NULL,                    0,   "[5.5.1.2]: <table> summary invalid (null)."                               },
    { TABLE_SUMMARY_INVALID_SPACES,                  0,   "[5.5.1.3]: <table> summary invalid (spaces)."                             },
    { TABLE_SUMMARY_INVALID_PLACEHOLDER,             0,   "[5.5.1.6]: <table> summary invalid (placeholder text)."                   },
    { TABLE_MISSING_CAPTION,                         0,   "[5.5.2.1]: <table> missing <caption>."                                    },
    { TABLE_MAY_REQUIRE_HEADER_ABBR,                 0,   "[5.6.1.1]: <table> may require header abbreviations."                     },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_NULL,            0,   "[5.6.1.2]: <table> header abbreviations invalid (null)."                  },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES,          0,   "[5.6.1.3]: <table> header abbreviations invalid (spaces)."                },
    { STYLESHEETS_REQUIRE_TESTING_LINK,              0,   "[6.1.1.1]: style sheets require testing (link)."                          },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT,     0,   "[6.1.1.2]: style sheets require testing (style element)."                 },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR,        0,   "[6.1.1.3]: style sheets require testing (style attribute)."               },
    { FRAME_SRC_INVALID,                             0,   "[6.2.1.1]: <frame> source invalid."                                       },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET,      0,   "[6.2.2.1]: text equivalents require updating (applet)."                   },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT,      0,   "[6.2.2.2]: text equivalents require updating (script)."                   },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT,      0,   "[6.2.2.3]: text equivalents require updating (object)."                   },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT,   0,   "[6.3.1.1]: programmatic objects require testing (script)."                },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT,   0,   "[6.3.1.2]: programmatic objects require testing (object)."                },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED,    0,   "[6.3.1.3]: programmatic objects require testing (embed)."                 },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET,   0,   "[6.3.1.4]: programmatic objects require testing (applet)."                },
    { FRAME_MISSING_NOFRAMES,                        0,   "[6.5.1.1]: <frameset> missing <noframes> section."                        },
    { NOFRAMES_INVALID_NO_VALUE,                     0,   "[6.5.1.2]: <noframes> section invalid (no value)."                        },
    { NOFRAMES_INVALID_CONTENT,                      0,   "[6.5.1.3]: <noframes> section invalid (content)."                         },
    { NOFRAMES_INVALID_LINK,                         0,   "[6.5.1.4]: <noframes> section invalid (link)."                            },
    { REMOVE_FLICKER_SCRIPT,                         0,   "[7.1.1.1]: remove flicker (script)."                                      },
    { REMOVE_FLICKER_OBJECT,                         0,   "[7.1.1.2]: remove flicker (object)."                                      },
    { REMOVE_FLICKER_EMBED,                          0,   "[7.1.1.3]: remove flicker (embed)."                                       },
    { REMOVE_FLICKER_APPLET,                         0,   "[7.1.1.4]: remove flicker (applet)."                                      },
    { REMOVE_FLICKER_ANIMATED_GIF,                   0,   "[7.1.1.5]: remove flicker (animated gif)."                                },
    { REMOVE_BLINK_MARQUEE,                          0,   "[7.2.1.1]: remove blink/marquee."                                         },
    { REMOVE_AUTO_REFRESH,                           0,   "[7.4.1.1]: remove auto-refresh."                                          },
    { REMOVE_AUTO_REDIRECT,                          0,   "[7.5.1.1]: remove auto-redirect."                                         },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT, 0,   "[8.1.1.1]: ensure programmatic objects are accessible (script)."          },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT, 0,   "[8.1.1.2]: ensure programmatic objects are accessible (object)."          },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET, 0,   "[8.1.1.3]: ensure programmatic objects are accessible (applet)."          },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED,  0,   "[8.1.1.4]: ensure programmatic objects are accessible (embed)."           },
    { IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION,     0,   "[9.1.1.1]: image map (server-side) requires conversion."                  },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN,  0,   "[9.3.1.1]: <script> not keyboard accessible (onMouseDown)."               },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP,    0,   "[9.3.1.2]: <script> not keyboard accessible (onMouseUp)."                 },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK,       0,   "[9.3.1.3]: <script> not keyboard accessible (onClick)."                   },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER,  0,   "[9.3.1.4]: <script> not keyboard accessible (onMouseOver)."               },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT,   0,   "[9.3.1.5]: <script> not keyboard accessible (onMouseOut)."                },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE,  0,   "[9.3.1.6]: <script> not keyboard accessible (onMouseMove)."               },
    { NEW_WINDOWS_REQUIRE_WARNING_NEW,               0,   "[10.1.1.1]: new windows require warning (_new)."                          },
    { NEW_WINDOWS_REQUIRE_WARNING_BLANK,             0,   "[10.1.1.2]: new windows require warning (_blank)."                        },
    { REPLACE_DEPRECATED_HTML_APPLET,                0,   "[11.2.1.1]: replace deprecated html <applet>."                            },
    { REPLACE_DEPRECATED_HTML_BASEFONT,              0,   "[11.2.1.2]: replace deprecated html <basefont>."                          },
    { REPLACE_DEPRECATED_HTML_CENTER,                0,   "[11.2.1.3]: replace deprecated html <center>."                            },
    { REPLACE_DEPRECATED_HTML_DIR,                   0,   "[11.2.1.4]: replace deprecated html <dir>."                               },
    { REPLACE_DEPRECATED_HTML_FONT,                  0,   "[11.2.1.5]: replace deprecated html <font>."                              },
    { REPLACE_DEPRECATED_HTML_ISINDEX,               0,   "[11.2.1.6]: replace deprecated html <isindex>."                           },
    { REPLACE_DEPRECATED_HTML_MENU,                  0,   "[11.2.1.7]: replace deprecated html <menu>."                              },
    { REPLACE_DEPRECATED_HTML_S,                     0,   "[11.2.1.8]: replace deprecated html <s>."                                 },
    { REPLACE_DEPRECATED_HTML_STRIKE,                0,   "[11.2.1.9]: replace deprecated html <strike>."                            },
    { REPLACE_DEPRECATED_HTML_U,                     0,   "[11.2.1.10]: replace deprecated html <u>."                                },
    { FRAME_MISSING_TITLE,                           0,   "[12.1.1.1]: <frame> missing title."                                       },
    { FRAME_TITLE_INVALID_NULL,                      0,   "[12.1.1.2]: <frame> title invalid (null)."                                },
    { FRAME_TITLE_INVALID_SPACES,                    0,   "[12.1.1.3]: <frame> title invalid (spaces)."                              },
    { ASSOCIATE_LABELS_EXPLICITLY,                   0,   "[12.4.1.1]: associate labels explicitly with form controls."              },
    { ASSOCIATE_LABELS_EXPLICITLY_FOR,               0,   "[12.4.1.2]: associate labels explicitly with form controls (for)."        },
    { ASSOCIATE_LABELS_EXPLICITLY_ID,                0,   "[12.4.1.3]: associate labels explicitly with form controls (id)."         },
    { LINK_TEXT_NOT_MEANINGFUL,                      0,   "[13.1.1.1]: link text not meaningful."                                    },
    { LINK_TEXT_MISSING,                             0,   "[13.1.1.2]: link text missing."                                           },
    { LINK_TEXT_TOO_LONG,                            0,   "[13.1.1.3]: link text too long."                                          },
    { LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE,           0,   "[13.1.1.4]: link text not meaningful (click here)."                       },
    { METADATA_MISSING,                              0,   "[13.2.1.1]: Metadata missing."                                            },
    { METADATA_MISSING_REDIRECT_AUTOREFRESH,         0,   "[13.2.1.3]: Metadata missing (redirect/auto-refresh)."                    },
    { SKIPOVER_ASCII_ART,                            0,   "[13.10.1.1]: skip over ascii art."                                        },
    
    
#if SUPPORT_CONSOLE_APP
    /********************************************************
     ** Console Application
     **  Although these strings are not used within LibTidy
     **  and only for the console application, they are
     **  provided as part of LibTidy for convenience to
     **  developers.
     ********************************************************/
    { TC_LABEL_COL,                 0,   "column"                                                                  },
    { TC_LABEL_FILE,                0,   "file"                                                                    },
    { TC_LABEL_LANG,                0,   "lang"                                                                    },
    { TC_LABEL_LEVL,                0,   "level"                                                                   },
    { TC_LABEL_OPT,                 0,   "option"                                                                  },
    { TC_MAIN_ERROR_LOAD_CONFIG,    0,   "Loading config file \"%s\" problems, err = %d"                             },
    { TC_OPT_ACCESS,                0,
        "do additional accessibility checks (<level> = 0, 1, 2, 3). 0 is "
        "assumed if <level> is missing."
    },
    { TC_OPT_ASCII,                 0,   "use ISO-8859-1 for input, US-ASCII for output"                           },
    { TC_OPT_ASHTML,                0,   "force XHTML to well formed HTML"                                         },
    { TC_OPT_ASXML,                 0,   "convert HTML to well formed XHTML"                                       },
    { TC_OPT_BARE,                  0,   "strip out smart quotes and em dashes, etc."                              },
    { TC_OPT_BIG5,                  0,   "use Big5 for both input and output"                                      },
    { TC_OPT_CLEAN,                 0,   "replace FONT, NOBR and CENTER tags with CSS"                             },
    { TC_OPT_CONFIG,                0,   "set configuration options from the specified <file>"                     },
    { TC_OPT_ERRORS,                0,   "show only errors and warnings"                                           },
    { TC_OPT_FILE,                  0,   "write errors and warnings to the specified <file>"                       },
    { TC_OPT_GDOC,                  0,   "produce clean version of html exported by Google Docs"                   },
    { TC_OPT_HELP,                  0,   "list the command line options"                                           },
    { TC_OPT_HELPCFG,               0,   "list all configuration options"                                          },
    { TC_OPT_HELPENV,               0,   "show information about the environment and runtime configuration"        },
    { TC_OPT_HELPOPT,               0,   "show a description of the <option>"                                      },
    { TC_OPT_IBM858,                0,   "use IBM-858 (CP850+Euro) for input, US-ASCII for output"                 },
    { TC_OPT_INDENT,                0,   "indent element content"                                                  },
    { TC_OPT_ISO2022,               0,   "use ISO-2022 for both input and output"                                  },

    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_OPT_LANGUAGE,              0,
        "set Tidy's output language to <lang>. Specify '-language help' for more help. "
        "Use before output-causing arguments to ensure the language takes effect, e.g.,"
        "`tidy -lang es -lang help`."
    },

    { TC_OPT_LATIN0,                0,   "use ISO-8859-15 for input, US-ASCII for output"                          },
    { TC_OPT_LATIN1,                0,   "use ISO-8859-1 for both input and output"                                },
    { TC_OPT_MAC,                   0,   "use MacRoman for input, US-ASCII for output"                             },
    { TC_OPT_MODIFY,                0,   "modify the original input files"                                         },
    { TC_OPT_NUMERIC,               0,   "output numeric rather than named entities"                               },
    { TC_OPT_OMIT,                  0,   "omit optional start tags and end tags"                                   },
    { TC_OPT_OUTPUT,                0,   "write output to the specified <file>"                                    },
    { TC_OPT_QUIET,                 0,   "suppress nonessential output"                                            },
    { TC_OPT_RAW,                   0,   "output values above 127 without conversion to entities"                  },
    { TC_OPT_SHIFTJIS,              0,   "use Shift_JIS for both input and output"                                 },
    { TC_OPT_SHOWCFG,               0,   "list the current configuration settings"                                 },
    { TC_OPT_EXP_CFG,               0,   "list the current configuration settings, suitable for a config file"     },
    { TC_OPT_EXP_DEF,               0,   "list the default configuration settings, suitable for a config file"     },
    { TC_OPT_UPPER,                 0,   "force tags to upper case"                                                },
    { TC_OPT_UTF16,                 0,   "use UTF-16 for both input and output"                                    },
    { TC_OPT_UTF16BE,               0,   "use UTF-16BE for both input and output"                                  },
    { TC_OPT_UTF16LE,               0,   "use UTF-16LE for both input and output"                                  },
    { TC_OPT_UTF8,                  0,   "use UTF-8 for both input and output"                                     },

    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_OPT_VERSION,               0,   "show the version of Tidy"
    },

    { TC_OPT_WIN1252,               0,   "use Windows-1252 for input, US-ASCII for output"                         },
    { TC_OPT_WRAP,                  0,
        "wrap text at the specified <column>. 0 is assumed if <column> is "
        "missing. When this option is omitted, the default of the "
        "configuration option 'wrap' applies."
    },
    { TC_OPT_XML,                   0,   "specify the input is well formed XML"                                    },
    { TC_OPT_XMLCFG,                0,   "list all configuration options in XML format"                            },
    { TC_OPT_XMLHELP,               0,   "list the command line options in XML format"                             },

    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_OPT_XMLSTRG,               0,   "output all of Tidy's strings in XML format"
    },

    { TC_OPT_XMLERRS,               0,   "output error constants and strings in XML format"                        },

    { TC_OPT_XMLOPTS,               0,   "output option descriptions in XML format"                                },
    
    { TC_STRING_CONF_HEADER,        0,   "Configuration File Settings:"                                            },

    {/* Must be 27 characters or fewer. */
      TC_STRING_CONF_NAME,          0,   "Name"
    },
    {/* Must be 9 characters or fewer. */
      TC_STRING_CONF_TYPE,          0,   "Type"
    },
    {/* Must be 40 characters or fewer. */
      TC_STRING_CONF_VALUE,         0,   "Current Value"
    },

    { TC_STRING_OPT_NOT_DOCUMENTED, 0,   "Warning: option `%s' is not documented."                                 },
    { TC_STRING_OUT_OF_MEMORY,      0,   "Out of memory. Bailing out."                                             },
    { TC_STRING_FATAL_ERROR,        0,   "Fatal error: impossible value for id='%d'."                              },
    { TC_STRING_FILE_MANIP,         0,   "File manipulation"                                                       },
    { TC_STRING_PROCESS_DIRECTIVES, 0,   "Processing directives"                                                   },
    { TC_STRING_CHAR_ENCODING,      0,   "Character encodings"                                                     },
    { TC_STRING_LANG_MUST_SPECIFY,  0,   "A POSIX or Windows locale must be specified."                            },

    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_STRING_LANG_NOT_FOUND,     0,   "Tidy doesn't have language '%s,' will use '%s' instead."
    },

    { TC_STRING_MISC,               0,   "Miscellaneous"                                                           },
    { TC_STRING_XML,                0,   "XML"                                                                     },
    { TC_STRING_MUST_SPECIFY,       0,   "A Tidy option name must be specified."                                   },

    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_STRING_UNKNOWN_OPTION,     0,   "HTML Tidy: unknown option: %c"
    },
    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_STRING_UNKNOWN_OPTION_B,   0,   "HTML Tidy: unknown option."
    },
    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_STRING_VERS_A,             0,   "HTML Tidy for %s version %s"
    },
    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_STRING_VERS_B,             0,   "HTML Tidy version %s"
    },

    {/* This console output should be limited to 78 characters per line.
        - First %s represents the name of the executable from the file system, and is mostly like going to be "tidy".
        - Second %s represents a version number, typically x.x.xx.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_1,                0,
        "%s [options...] [file...] [options...] [file...]\n"
        "Utility to clean up and pretty print HTML/XHTML/XML.\n"
        "\n"
        "This is modern HTML Tidy version %s.\n"
        "\n"
    },
    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
        - %s represents the platform, for example, "Mac OS X" or "Windows". */
      TC_TXT_HELP_2A,               0,
        "Command Line Arguments for HTML Tidy for %s:"
    },
    {/* The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_2B,               0,
        "Command Line Arguments for HTML Tidy:"
    },
    {/* This console output should be limited to 78 characters per line. 
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
        - %s represents either a blank line, or TC_TXT_HELP_3A explaining environment options. */
      TC_TXT_HELP_3,                0,
        "\n"
        "Tidy Configuration Options\n"
        "==========================\n"
        " Use Tidy's configuration options as command line arguments in the form\n"
        " of \"--some-option <value>\", for example, \"--indent-with-tabs yes\".\n"
        "\n"
        " You can also specify a file containing configuration options with the \n"
        " -options <file> directive, or in one or more files specific to your \n"
        " environment (see next section). \n"
        "\n"
        " For a list of all configuration options, use \"-help-config\" or refer\n"
        " to the man page (if your OS has one).\n"
        "\n"
        "Configuration Files\n"
        "===================\n"
        " If your environment has an $HTML_TIDY variable set to point to a Tidy \n"
        " configuration file, then Tidy will attempt to use it. \n"
        "%s"
        " Use \"-help-env\" for more information about how you can use the environment. \n"
        " to specify Tidy options. \n"
        "\n"
        "Other\n"
        "=====\n"
        " Input/Output default to stdin/stdout respectively.\n"
        "\n"
        " Single letter options apart from -f may be combined\n"
        " as in:  tidy -f errs.txt -imu foo.html\n"
        "\n"
        "Information\n"
        "===========\n"
        " For more information about HTML Tidy, see\n"
        "  http://www.html-tidy.org/\n"
        "\n"
        " For more information on HTML, see the following:\n"
        "\n"
        "   HTML: Edition for Web Authors (the latest HTML specification)\n"
        "   http://dev.w3.org/html5/spec-author-view\n"
        "\n"
        "   HTML: The Markup Language (an HTML language reference)\n"
        "   http://dev.w3.org/html5/markup/\n"
        "\n"
        " File bug reports at https://github.com/htacg/tidy-html5/issues/\n"
        " or send questions and comments to public-htacg@w3.org.\n"
        "\n"
        " Validate your HTML documents using the W3C Nu Markup Validator:\n"
        "   http://validator.w3.org/nu/\n"
        "\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
        - Both parameters %s reflect file paths and names. */
      TC_TXT_HELP_3A,               0,
        "\n"
        " Additionally, Tidy will automatically attempt to use configuration specified \n"
        " in these files, if present: \n"
        "\n"
        "  %s \n"
        "  %s \n"
        "\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_CONFIG,           0,
        "\n"
        "HTML Tidy Configuration Settings\n"
        "\n"
        "Within a file, use the form:\n"
        "\n"
        "wrap: 72\n"
        "indent: no\n"
        "\n"
        "When specified on the command line, use the form:\n"
        "\n"
        "--wrap 72 --indent no\n"
        "\n"
    },
    { TC_TXT_HELP_CONFIG_NAME,      0,   "Name"                                                                    },
    { TC_TXT_HELP_CONFIG_TYPE,      0,   "Type"                                                                    },
    { TC_TXT_HELP_CONFIG_ALLW,      0,   "Allowable values"                                                        },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
        - The first %s indicates two more list items, or an empty string.
        - The second %s indicates a file name, or a message indicating no file name. */
      TC_TXT_HELP_ENV_1,           0,
        "\n"
        "Tidy can configure its option values from multiple sources, in the \n"
        "order below. Subsequent use of the same option overrides previous \n"
        "option settings. \n"
        "\n"
        " - Tidy's built-in default values. \n"
        "%s" /* rc files */
        " - The file specified in the $HTML_TIDY environment variable: \n"
        "     %s \n"
        " - Options in a file specified on the command line. \n"
        " - Options set directly on the command line. \n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_ENV_1A,          0,
        " - The system runtime configuration file: \n"
        "     %s \n"
        " - The user runtime configuration file: \n"
        "     %s \n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
        - This message indicates that a file name is not currently set. */
      TC_TXT_HELP_ENV_1B,          0,
        "(not currently set)"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_ENV_1C,          0,
        "\n"
        "Note that because $HTML_TIDY is set, the user runtime configuration file \n"
        "%s will not be used. \n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_LANG_1,           0,
        "\n"
        "The -language (or -lang) option indicates which language Tidy \n"
        "should use to communicate its output. Please note that this is not \n"
        "a document translation service, and only affects the messages that \n"
        "Tidy communicates to you. \n"
        "\n"
        "When used from the command line the -language argument must \n"
        "be used before any arguments that result in output, otherwise Tidy \n"
        "will produce output before it knows which language to use. \n"
        "\n"
        "In addition to standard POSIX language codes, Tidy is capable of \n"
        "understanding legacy Windows language codes. Please note that this \n"
        "list indicates codes Tidy understands, and does not indicate that \n"
        "the language is currently installed. \n"
        "\n"
        "The rightmost column indicates how Tidy will understand the \n"
        "legacy Windows name.\n"
        "\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated. */
      TC_TXT_HELP_LANG_2,           0,
        "\n"
        "The following languages are currently installed in Tidy. Please \n"
        "note that there's no guarantee that they are complete; only that \n"
        "one developer or another started to add the language indicated. \n"
        "\n"
        "Incomplete localizations will default to \"en\" when necessary. \n"
        "Please report instances of incorrect strings to the Tidy team. \n"
        "\n"
    },
    {/* This console output should be limited to 78 characters per line.
        - The strings "Tidy" and "HTML Tidy" are the program name and must not be translated.
        - The parameter %s is likely to be two to five characters, e.g., en or en_US. */
      TC_TXT_HELP_LANG_3,           0,
        "\n"
        "If Tidy is able to determine your locale then Tidy will use the \n"
        "locale's language automatically. For example Unix-like systems use a \n"
        "$LANG and/or $LC_ALL environment variable. Consult your operating \n"
        "system documentation for more information. \n"
        "\n"
        "Tidy is currently using locale %s. \n"
        "\n"
    },
#endif /* SUPPORT_CONSOLE_APP */
    
    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST,      0,   NULL
    }
}};


#endif /* language_en_h */
#ifndef language_en_gb_h
#define language_en_gb_h
/*
 * language_en_gb.h
 * Localization support for HTML Tidy.
 *
 *
 * This file is a localization file for HTML Tidy. It will have been machine
 * generated or created and/or edited by hand. Both are valid options, but
 * please help keep our localization efforts simple to maintain by maintaining
 * the structure of this file, and changing the check box below if you make
 * changes (so others know the file origin):
 *
 * [X] THIS FILE IS MACHINE GENERATED. It is a localization file for the
 *     language (and maybe region) "en_gb". The source of
 *     these strings is a gettext PO file in Tidy's source, probably called 
 *     "language_en_gb.po".
 *
 * [ ] THIS FILE WAS HAND MODIFIED. Translators, please feel to edit this file
 *     directly (and check this box). If you prefer to edit PO files then use
 *     `poconvert.rb msgunfmt language_en_gb.h` (our own
 *     conversion tool) to generate a fresh PO from this file first!
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Template Created by Jim Derry on 01/14/2016.
 *
 * Orginating PO file metadata:
 *   PO_LAST_TRANSLATOR=jderry
 *   PO_REVISION_DATE=2017-10-03 12:44:37
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_en_gb(unsigned int n) {
    /* Plural-Forms: nplurals=2; */
    return n != 1;
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 */
static languageDefinition language_en_gb = { whichPluralForm_en_gb, {
    /***************************************
     ** This MUST be present and first. 
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,                    0, "en_gb"
    },
    { TidyAsciiChars,                   0,        
        "Can be used to modify behaviour of the <code>clean</code> option when set "
        "to <var>yes</var>. "
        "<br/>"
        "If set to <var>yes</var> when using <code>clean</code>, "
        "<code>&amp;emdash;</code>, <code>&amp;rdquo;</code>, and other named "
        "character entities are downgraded to their closest ASCII equivalents. "
    },
    { TidyGDocClean,                    0,        
        "This option specifies if Tidy should enable specific behaviour for "
        "cleaning up HTML exported from Google Docs. "
    },
    { TidyLiteralAttribs,               0,        
        "This option specifies how Tidy deals with whitespace characters within "
        "attribute values. "
        "<br/>"
        "If the value is <var>no</var> Tidy normalises attribute values by "
        "replacing any newline or tab with a single space, and further by replacing "
        "any contiguous whitespace with a single space. "
        "<br/>"
        "To force Tidy to preserve the original, literal values of all attributes "
        "and ensure that whitespace within attribute values is passed "
        "through unchanged, set this option to <var>yes</var>. "
    },
    { TidyMergeDivs,                    0,        
        "This option can be used to modify the behaviour of <code>clean</code> when "
        "set to <code>yes</code>."
        "<br/>"
        "This option specifies if Tidy should merge nested <code>&lt;div&gt;</code> "
        "such as <code>&lt;div&gt;&lt;div&gt;...&lt;/div&gt;&lt;/div&gt;</code>. "
        "<br/>"
        "If set to <code>auto</code> the attributes of the inner "
        "<code>&lt;div&gt;</code> are moved to the outer one. Nested "
        "<code>&lt;div&gt;</code> with <code>id</code> attributes are <em>not</em> "
        "merged. "
        "<br/>"
        "If set to <code>yes</code> the attributes of the inner "
        "<code>&lt;div&gt;</code> are discarded with the exception of "
        "<code>class</code> and <code>style</code>. "
    },
    { TidyMergeSpans,                   0,        
        "This option can be used to modify the behaviour of <code>clean</code> when "
        "set to <code>yes</code>."
        "<br/>"
        "This option specifies if Tidy should merge nested <code>&lt;span&gt;</code> "
        "such as <code>&lt;span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;</code>. "
        "<br/>"
        "The algorithm is identical to the one used by <code>merge-divs</code>. "
    },
    { TidyReplaceColor,                 0,        
        "This option specifies if Tidy should replace numeric values in colour "
        "attributes with HTML/XHTML colour names where defined, e.g. replace "
        "<code>#ffffff</code> with <code>white</code>. "
    },
    { TidyUseCustomTags,                0,        
        "This option enables the use of tags for autonomous custom elements, "
        "e.g. &lt;flag-icon&gt; with Tidy. Custom tags are disabled if this "
        "value is <var>no</var>. Other settings - <var>blocklevel</var>, "
        "<var>empty</var>, <var>inline</var>, and <var>pre</var> will treat "
        "<em>all</em> detected custom tags accordingly. "
        "<br/>"
        "The use of <code>new-blocklevel-tags</code>, "
        "<code>new-empty-tags</code>, <code>new-inline-tags</code>, or "
        "<code>new-pre-tags</code> will override the treatment of custom tags "
        "by this configuration option. This may be useful if you have "
        "different types of custom tags."
        "<br/>"
        "When enabled these tags are determined during the processing of your "
        "document using opening tags; matching closing tags will be recognised "
        "accordingly, and unknown closing tags will be discarded. "
    },
    { TEXT_USING_FONT,                  0,        
        "You are recommended to use CSS to specify the font and\n"
        "properties such as its size and colour. This will reduce\n"
        "the size of HTML files and make them easier to maintain\n"
        "compared with using <FONT> elements.\n\n"
    },
    { TEXT_USING_BODY,                  0, "You are recommended to use CSS to specify page and link colours\n"           },
    { TEXT_GENERAL_INFO_PLEA,           0,        
        "\n"
        "Would you like to see Tidy in proper, British English? Please consider \n"
        "helping us to localise HTML Tidy. For details please see \n"
        "https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md\n"
    },
    { UNKNOWN_ELEMENT_LOOKS_CUSTOM,     0, "%s is not recognised! Did you mean to enable the custom-tags option?"        },
    { UNKNOWN_ELEMENT,                  0, "%s is not recognised!"                                                       },
    { MULTIMEDIA_REQUIRES_TEXT,         0, "[1.4.1.1]: multimedia requires synchronised text equivalents."               },
    { INFORMATION_NOT_CONVEYED_IMAGE,   0, "[2.1.1.1]: ensure information not conveyed through colour alone (image)."    },
    { INFORMATION_NOT_CONVEYED_APPLET,  0, "[2.1.1.2]: ensure information not conveyed through colour alone (applet)."   },
    { INFORMATION_NOT_CONVEYED_OBJECT,  0, "[2.1.1.3]: ensure information not conveyed through colour alone (object)."   },
    { INFORMATION_NOT_CONVEYED_SCRIPT,  0, "[2.1.1.4]: ensure information not conveyed through colour alone (script)."   },
    { INFORMATION_NOT_CONVEYED_INPUT,   0, "[2.1.1.5]: ensure information not conveyed through colour alone (input)."    },
    { COLOR_CONTRAST_TEXT,              0, "[2.2.1.1]: poor colour contrast (text)."                                     },
    { COLOR_CONTRAST_LINK,              0, "[2.2.1.2]: poor colour contrast (link)."                                     },
    { COLOR_CONTRAST_ACTIVE_LINK,       0, "[2.2.1.3]: poor colour contrast (active link)."                              },
    { COLOR_CONTRAST_VISITED_LINK,      0, "[2.2.1.4]: poor colour contrast (visited link)."                             },
    { LAYOUT_TABLES_LINEARIZE_PROPERLY, 0, "[5.3.1.1]: verify layout tables linearise properly."                         },

#if SUPPORT_CONSOLE_APP
    { TC_TXT_HELP_LANG_2,               0,        
        "\n"
        "The following languages are currently installed in Tidy. Please \n"
        "note that there's no guarantee that they are complete; only that \n"
        "one developer or another started to add the language indicated. \n"
        "\n"
        "Incomplete localisations will default to \"en\" when necessary. \n"
        "Please report instances of incorrect strings to the Tidy team. \n"
        "\n"
    },
#endif /* SUPPORT_CONSOLE_APP */

    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST,           0, NULL
    }

}};


#endif /* language_en_gb_h */

#ifndef language_es_h
#define language_es_h
/*
 * language_es.h
 * Localization support for HTML Tidy.
 *
 *
 * This file is a localization file for HTML Tidy. It will have been machine
 * generated or created and/or edited by hand. Both are valid options, but
 * please help keep our localization efforts simple to maintain by maintaining
 * the structure of this file, and changing the check box below if you make
 * changes (so others know the file origin):
 *
 * [X] THIS FILE IS MACHINE GENERATED. It is a localization file for the
 *     language (and maybe region) "es". The source of
 *     these strings is a gettext PO file in Tidy's source, probably called 
 *     "language_es.po".
 *
 * [ ] THIS FILE WAS HAND MODIFIED. Translators, please feel to edit this file
 *     directly (and check this box). If you prefer to edit PO files then use
 *     `poconvert.rb msgunfmt language_es.h` (our own
 *     conversion tool) to generate a fresh PO from this file first!
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Template Created by Jim Derry on 01/14/2016.
 *
 * Orginating PO file metadata:
 *   PO_LAST_TRANSLATOR=jderry
 *   PO_REVISION_DATE=2017-10-03 12:44:37
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_es(unsigned int n) {
    /* Plural-Forms: nplurals=2; */
    return n != 1;
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 */
static languageDefinition language_es = { whichPluralForm_es, {
    /***************************************
     ** This MUST be present and first. 
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,          0, "es"
    },
    { TidyMakeClean,          0,        
        "Esta opción especifica si Tidy debe realizar la limpieza de algún legado etiquetas de "
        "presentación (actualmente <code>&lt;i&gt;</code>, <code>&lt;b&gt;</code>, <code>&lt;center&gt;</"
        "code> cuando encerrados dentro de las etiquetas apropiadas en línea y <code>&lt;font&gt;</"
        "code>). Si se establece en <code>yes</code>, entonces etiquetas existentes serán reemplazados "
        "con CSS <code>&lt;style&gt;</code> y estructural markup según corresponda. "
    },
    { TidyNCR,                0, "Esta opción especifica si Tidy debe permitir referencias de caracteres numéricos. "   },
    { TEXT_GENERAL_INFO_PLEA, 0,        
        "\n"
        "¿Le gustaría ver Tidy en un español correcto? Por favor considere \n"
        "ayudarnos a localizar HTML Tidy. Para más detalles consulte \n"
        "https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md \n"
    },

#if SUPPORT_CONSOLE_APP
    { TC_TXT_HELP_LANG_1,     0,        
        "\n"
        "La opción -language (o -lang) indica el lenguaje Tidy debe \n"
        "utilizar para comunicar su salida. Tenga en cuenta que esto no es \n"
        "un servicio de traducción de documentos, y sólo afecta a los mensajes \n"
        "que Tidy comunica a usted. \n"
        "\n"
        "Cuando se utiliza la línea de comandos el argumento -language debe \n"
        "utilizarse antes de cualquier argumento que dan lugar a la producción, \n"
        "de lo contrario Tidy producirá la salida antes de que se conozca el \n"
        "idioma a utilizar. \n"
        "\n"
        "Además de los códigos de idioma estándar POSIX, Tidy es capaz de \n"
        "entender códigos de idioma legados de Windows. Tenga en cuenta que \n"
        "este lista indica los códigos Tidy entiende, y no indica que \n"
        "actualmente el idioma está instalado. \n"
        "\n"
        "La columna más a la derecha indica cómo Tidy comprenderá el \n"
        "legado nombre de Windows.\n"
        "\n"
        "Tidy está utilizando la configuración regional %s. \n"
        "\n"
    },
    { TC_TXT_HELP_LANG_2,     0,        
        "\n"
        "Los siguientes idiomas están instalados actualmente en Tidy. Tenga \n"
        "en cuenta que no hay garantía de que están completos; sólo quiere decir \n"
        "que un desarrollador u otro comenzaron a añadir el idioma indicado. \n"
        "\n"
        "Localizaciones incompletas por defecto se usan \"en\" cuando sea \n"
        "necesario. ¡Favor de informar los desarrolladores de estes casos! \n"
        "\n"
    },
    { TC_TXT_HELP_LANG_3,     0,        
        "\n"
        "Si Tidy es capaz de determinar la configuración regional entonces \n"
        "Tidy utilizará el lenguaje de forma automática de la configuración \n"
        "regional. Por ejemplo los sistemas de tipo Unix utilizan los variables \n"
        "$LANG y/o $LC_ALL. Consulte a su documentación del sistema para \n"
        "obtener más información.\n"
        "\n"
        "Tidy está utilizando la configuración regional %s. \n"
        "\n"
    },
#endif /* SUPPORT_CONSOLE_APP */

    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST, 0, NULL
    }

}};


#endif /* language_es_h */

#ifndef language_es_mx_h
#define language_es_mx_h
/*
 * language_es_mx.h
 * Localization support for HTML Tidy.
 *
 *
 * This file is a localization file for HTML Tidy. It will have been machine
 * generated or created and/or edited by hand. Both are valid options, but
 * please help keep our localization efforts simple to maintain by maintaining
 * the structure of this file, and changing the check box below if you make
 * changes (so others know the file origin):
 *
 * [X] THIS FILE IS MACHINE GENERATED. It is a localization file for the
 *     language (and maybe region) "es_mx". The source of
 *     these strings is a gettext PO file in Tidy's source, probably called 
 *     "language_es_mx.po".
 *
 * [ ] THIS FILE WAS HAND MODIFIED. Translators, please feel to edit this file
 *     directly (and check this box). If you prefer to edit PO files then use
 *     `poconvert.rb msgunfmt language_es_mx.h` (our own
 *     conversion tool) to generate a fresh PO from this file first!
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Template Created by Jim Derry on 01/14/2016.
 *
 * Orginating PO file metadata:
 *   PO_LAST_TRANSLATOR=jderry
 *   PO_REVISION_DATE=2017-10-03 12:44:37
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_es_mx(unsigned int n) {
    /* Plural-Forms: nplurals=2; */
    return n != 1;
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 */
static languageDefinition language_es_mx = { whichPluralForm_es_mx, {
    /***************************************
     ** This MUST be present and first. 
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,          0, "es_mx"
    },
    { TEXT_GENERAL_INFO_PLEA, 0,        
        "\n"
        "¿Le gustaría ver Tidy en adecuada, español mexicano? Por favor considere \n"
        "ayudarnos a localizar HTML Tidy. Para más detalles consulte \n"
        "https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md \n"
    },

    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST, 0, NULL
    }

}};


#endif /* language_es_mx_h */

#ifndef language_fr_h
#define language_fr_h
/*
 * language_fr.h
 * Localization support for HTML Tidy.
 *
 *
 * This file is a localization file for HTML Tidy. It will have been machine
 * generated or created and/or edited by hand. Both are valid options, but
 * please help keep our localization efforts simple to maintain by maintaining
 * the structure of this file, and changing the check box below if you make
 * changes (so others know the file origin):
 *
 * [X] THIS FILE IS MACHINE GENERATED. It is a localization file for the
 *     language (and maybe region) "fr". The source of
 *     these strings is a gettext PO file in Tidy's source, probably called 
 *     "language_fr.po".
 *
 * [ ] THIS FILE WAS HAND MODIFIED. Translators, please feel to edit this file
 *     directly (and check this box). If you prefer to edit PO files then use
 *     `poconvert.rb msgunfmt language_fr.h` (our own
 *     conversion tool) to generate a fresh PO from this file first!
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Template Created by Jim Derry on 01/14/2016.
 *
 * Orginating PO file metadata:
 *   PO_LAST_TRANSLATOR=jderry
 *   PO_REVISION_DATE=2017-10-05 15:13:40
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_fr(unsigned int n) {
    /* Plural-Forms: nplurals=2; */
    return (n > 1);
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 */
static languageDefinition language_fr = { whichPluralForm_fr, {
    /***************************************
     ** This MUST be present and first. 
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,                                 0, "fr"
    },
    { TidyAccessibilityCheckLevel,                   0,        
        "Cette option précise le niveau de contrôle d'accessibilité que Tidy doit éventuellement exécuter. "
        "Le <br/>niveau <var>0 (Tidy Classic)</var> est équivalent au contrôle d'accessibilité de Tidy "
        "Classic. <br/>Pour plus d'informations sur le contrôle d'accessibilité de Tidy, consultez <a href="
        "\"http://www.html-tidy.org/accessibility/\"> la page d'accessibilité de Tidy</a>. "
    },
    { TidyAltText,                                   0,        
        "Cette option précise la valeur par défaut du texte <code>alt=</code> qu'utilise Tidy pour les "
        "attributs <code>&lt;img&gt;</code> lorsque l'attribut <code>alt=</code> est absent. <br/> Utiliser "
        "avec toute l'attention nécessaire, il est en effet de votre responsabilité de rendre vos documents "
        "accessibles aux personnes qui ne peuvent pas voir les images."
    },
    { TidyAnchorAsName,                              0,        
        "Cette option contrôle la suppression ou l'ajout de l'attribut <code>name</code> pour les éléments "
        "qui peuvent servir d'ancre. <br/>Si la valeur de l'attribut <code>name</code> est <var>yes</var>, "
        "et qu'il n'existe pas déjà, il est ajouté à la suite d'un attribut <code>id</code> existant, si la "
        "DTD le permet. <br/>Si sa valeur est <var>no</var>, tout attribut <code>name</code> existant est "
        "supprimé, si un attribut <code>id</code> existe ou a été ajouté. "
    },
    { TidyAsciiChars,                                0,        
        "Peut être utilisé pour modifier le comportement de l'option <code>clean</code> si sa valeur est "
        "<var>yes</var>. <br/> Lorsque la valeur de <code>clean</code> vaut <var>yes</var>, <code>&amp;"
        "emdash;</code>, <code>&amp;rdquo;</code>, et d'autres entités nommées sont déclassées vers leurs "
        "plus proches équivalents ASCII."
    },
    { TidyBlockTags,                                 0,        
        "Cette option définit de nouvelles balises de type bloc. Elle prend une liste de noms de balises "
        "séparés par un espace ou une virgule. <br/>À moins que vous ne déclariez de nouvelles balises, Tidy "
        "refusera de produire une sortie si l'entrée introduit préalablement des balises inconnues. <br/"
        ">Notez qu'il est impossible de modifier le modèle de contenu pour des éléments comme <code>&lt;"
        "table&gt;</code>, <code>&lt;ul&gt;</code>, <code>&lt;ol&gt;</code> et <code>&lt;dl&gt;</code>. <br/"
        ">Cette option est ignorée avec le mode XML. "
    },
    { TidyBodyOnly,                                  0,        
        "Cette option précise si Tidy doit seulement afficher les contenus de la balise <code>&lt;body&gt;</"
        "code> en tant que fragment HTML. <br/>Si sa valeur est <var>auto</var>, ceci est effectué seulement "
        "si la balise <code>&lt;body&gt;</code> a été déduite. <br/>L'intérêt est de pouvoir incorporer "
        "entièrement des pages existantes en tant que partie d'une autre page. <br/>Cette option n'a pas "
        "d'effet si la sortie XML a été demandée. "
    },
    { TidyBreakBeforeBR,                             0,        
        "Cette option précise si Tidy doit ajouter un saut de ligne avant chaque élément <code>&lt;br&gt;</"
        "code>."
    },
    { TidyCharEncoding,                              0,        
        "Cette option permet de préciser l'encodage des caractères qui sera utilisé par Tidy pour l'entrée "
        "et la sortie. <br/>Pour l'<var>ascii</var> Tidy acceptera les valeurs de caractère Latin-1 "
        "(ISO-8859-1), mais utilisera les entités pour tous les caractères de valeur &gt;127. <br/>Pour la "
        "valeur <var>raw</var>, Tidy produira des valeurs au dessus de 127, sans les traduires en entités. "
        "<br/>Pour <var>latin1</var>, les caractères au dessus de 255 seront écrits en entités. <br/>Pour "
        "<var>utf8</var>, Tidy suppose qu'aussi bien l'entrée que la sortie sont encodés en UTF-8. <br/>Vous "
        "pouvez utiliser <var>iso2022</var> pour les fichiers utilisant la famille d'encodage ISO-2022, par "
        "exemple ISO-2022-JP. <br/>Pour <var>mac</var> et <var>win1252</var>, Tidy acceptera les valeurs de "
        "caractères spécifiques de l'éditeur, mais utilisera les entités pour tous les caractères de valeur "
        "&gt;127. <br/>Pour les encodages non supportés, utilisez un utilitaire tiers pour convertir depuis "
        "et vers l'UTF-8. "
    },
    { TidyCoerceEndTags,                             0,        
        "Cette option précise si Tidy doit forcer la fermeture d'une balise d'ouverture, dans les cas où il "
        "semble qu'une balise de fin soit attendue; Dans cet exemple,<br/><code>&lt;span&gt;foo &lt;b&gt;"
        "bar&lt;b&gt; baz&lt;/span&gt;</code> <br/>Tidy va produire <br/><code>&lt;span&gt;foo &lt;b&gt;"
        "bar&lt;/b&gt; baz&lt;/span&gt;</code> "
    },
    { TidyCSSPrefix,                                 0,        
        "Cette option précise le préfixe que Tidy utilise pour les règles de styles. <br/> Par défaut, "
        "<var>c</var> sera utilisé."
    },
    { TidyDecorateInferredUL,                        0,        
        "Cette option précise si Tidy doit décorer le code déduit des éléments <code>&lt;ul&gt;</code> avec "
        "du balisage CSS pour éviter un décalage d'indentation vers la droite. "
    },
    { TidyDoctype,                                   0,        
        "Cette option spécifie la déclaration DOCTYPE générée par Tidy. <br/> Si <var>omit</var>, la sortie "
        "ne contiendra pas de déclaration DOCTYPE. Notez que cela implique aussi que <code>numeric-entities</"
        "code> soit réglé sur <var>yes</var>. <br/> Si <code>html5</code>, la déclaration DOCTYPE est réglée "
        "sur <code>&lt;! DOCTYPE html&gt;</code>. <br/> Si <var>auto</var> (par défaut), Tidy tentera de "
        "déduire la déclaration DOCTYPE à partir du contenu du document. <br/> Si elle est définie "
        "<var>strict</var>, Tidy utilisera la déclaration DOCTYPE HTML4 ou XHTML 1 DTD strict. <br/> Si "
        "<var>loose</var>, la déclaration DOCTYPE est réglée sur HTML4 ou XHTML1 loose (transitional) DTD. "
        "<br/> En alternative, vous pouvez fournir une chaîne pour l'identificateur public formel (FPI).<br/"
        "> Par exemple: <br/> <code>doctype: \"- // ACME // DTD HTML. 3,14159 //EN\"</code> <br/> Si vous "
        "spécifiez le FPI pour un document XHTML, Tidy établira l'identifiant système à une chaîne vide. "
        "Pour un document HTML, Tidy ajoute un identifiant système seulement s'il était déjà présent, dans "
        "le but de préserver le mode de rendu de certains navigateurs. Tidy ne tient pas compte de la "
        "déclaration DOCTYPE pour les documents XML génériques inchangés. <br/> Cette option ne permet pas "
        "une validation de la conformité du document."
    },
    { TidyDropEmptyElems,                            0, "Cette option précise si Tidy doit rejeter les éléments vides."                                          },
    { TidyDropEmptyParas,                            0, "Cette option précise si Tidy doit rejeter les paragraphes vides."                                       },
    { TidyDropPropAttrs,                             0,        
        "Cette option précise si Tidy doit enlever les attributs propriétaires, comme les attributs de "
        "liaison de données Microsoft. Les attributs supplémentaires qui ne sont pas autorisés dans la "
        "version HTML en sortie, seront supprimés avec l'utilisation conjointe de l'option <code>strict-tags-"
        "attributes</code>."
    },
    { TidyDuplicateAttrs,                            0,        
        "Cette option précise quel attribut, du premier ou du dernier, Tidy doit garder s'il est répété, par "
        "exemple dans le cas de deux attributs <code>align</code>."
    },
    { TidyEmacs,                                     0,        
        "Cette option précise si Tidy doit adopter un format de rapports d'erreurs et d'avertissements plus "
        "facilement exploitable par GNU Emacs."
    },
    { TidyEmptyTags,                                 0,        
        "Cette option précise les nouvelles balises inline. Cette option prend une liste de noms de balises "
        "séparés par un espace ou une virgule. <br/>Tant que vous n'avez pas déclaré de nouvelles balises, "
        "Tidy refusera de générer un fichier nettoyé si l'entrée contient des balises inconnues. <br/> "
        "pensez aussi à déclarer les balises vides, soit inline, soit bloc. <br/>Cette option est ignorée "
        "par le mode XML."
    },
    { TidyEncloseBlockText,                          0,        
        "Cette option précise si Tidy doit insérer un élément <code>&lt;p&gt;</code> pour encadrer un "
        "quelconque texte trouvé, dans n'importe quel élément qui permet de mélanger du contenu pour "
        "<var>HTML transitional</var> mais pas HTML strict. "
    },
    { TidyEncloseBodyText,                           0,        
        "Cette option précise si Tidy doit encadrer les textes trouvés dans l'élément <code>body</code>, par "
        "un élément <code>&lt;p&gt;</code>. <br/>Elle peut être utile lorsque vous voulez modifier du HTML "
        "existant au moyen d'une feuille de style. "
    },
    { TidyErrFile,                                   0,        
        "Cette option précise le fichier d'erreur que Tidy utilise pour les erreurs et avertissements. En "
        "principe les erreurs et avertissements sont envoyés vers la sortie <code>stderr</code>."
    },
    { TidyEscapeCdata,                               0,        
        "Cette option précise si Tidy doit convertir les sections <code>&lt;![CDATA[]]&gt;</code> en texte "
        "normal. "
    },
    { TidyEscapeScripts,                             0,        
        "Cette option entraîne l'échappement des items qui semblent être des balises de fermeture, ainsi "
        "<code>&lt;/g</code> sera échappée en <code>&lt;\\/g</code>. Positionner cette option à <var>no</"
        "var> si vous ne voulez pas cette fonctionnalité."
    },
    { TidyFixBackslash,                              0,        
        "Cette option précise si Tidy doit remplacer les caractères de barre oblique inversée (anti-slash, "
        "<code>\\</code>) dans les URLs avec des barres obliques (slash, <code>/</code>). "
    },
    { TidyFixComments,                               0,        
        "Cette option précise si Tidy doit remplacer les traits d'unions par le caractère <code>=</code> "
        "s'il rencontre des traits-d'unions adjacents. <br/>La valeur par défaut est <var>yes</var>. <br/"
        ">Cette option est fourni pour les utilisateurs de ColdFusion qui utilisent la syntaxe de "
        "commentaire: <code>&lt;!--- ---&gt;</code>. "
    },
    { TidyFixUri,                                    0,        
        "Cette option précise si Tidy doit vérifier les valeurs d'attributs qui comportent des caractères "
        "interdits pour les URI, et auquel cas les échapper selon les recommandations HTML 4."
    },
    { TidyForceOutput,                               0,        
        "Cette option précise si Tidy doit produire une sortie, même si des erreurs ont été rencontrées. <br/"
        ">Utilisez cette option avec attention; si Tidy affiche une erreur, cela implique que Tidy n'a pas "
        "été en mesure (ou n'est pas sûr) de pouvoir corriger cette erreur; en conséquence le résultat en "
        "sortie pourrait ne pas être conforme à vos attentes. "
    },
    { TidyGDocClean,                                 0,        
        "Cette option précise si Tidy doit activer un comportement spécifique pour le nettoyage du HTML "
        "exporté à partir de Google Docs."
    },
    { TidyHideComments,                              0, "Cette option précise si Tidy doit afficher en sortie les commentaires."                                 },
    { TidyHtmlOut,                                   0, "Cette option précise si Tidy doit embellir les sorties, lorsqu'il produit du HTML."                     },
    { TidyInCharEncoding,                            0,        
        "Cette option précise l'encodage de caractère que Tidy utilise pour l'entrée. Voir <code>char-"
        "encoding</code> pour plus d'informations."
    },
    { TidyIndentAttributes,                          0, "Cette option précise si Tidy doit placer chaque attribut sur une nouvelle ligne."                       },
    { TidyIndentCdata,                               0, "Cette option précise si Tidy doit indenter les sections <code>&lt;![CDATA[]]&gt;</code>."               },
    { TidyIndentContent,                             0,        
        "Cette option précise si Tidy doit indenter les balises de portée bloc. <br/>Si la valeur est "
        "<var>auto</var> Tidy décidera d'indenter ou pas le contenu des balises comme <code>&lt;title&gt;</"
        "code>, <code>&lt;h1&gt;</code>-<code>&lt;h6&gt;</code>, <code>&lt;li&gt;</code>, <code>&lt;td&gt;</"
        "code>, or <code>&lt;p&gt;</code> en s'appuyant sur le contenu incluant un élément de bloc. <br/"
        ">Positionner <code>indent</code> à <var>yes</var> peut engendrer des bugs de structure pour "
        "certains navigateurs. <br/>Utiliser l'option <code>indent-spaces</code> pour contrôler le nombre "
        "d'espaces ou de tabulations en sortie par niveau d'indentation, et <code>indent-with-tabs</code> "
        "pour préciser si les espaces ou tabulations sont utilisées. "
    },
    { TidyIndentSpaces,                              0,        
        "Cette option précise le nombre d'espaces ou de tabulations que Tidy utilise pour indenter le "
        "contenu lorsque <code>indent</code> est activé. <br/>Notez que la valeur par défaut pour cette "
        "option dépend de la valeur de <code>indent-with-tabs</code> (voir aussi cette option). "
    },
    { TidyInlineTags,                                0,        
        "Cette option porte sur les nouvelles balises inline non vides. Elle prend en valeur une liste de "
        "noms de balises, séparés par un espace ou une virgule. <br/>Sans déclaration de nouvelles balises, "
        "Tidy refusera de générer un fichier de sortie, si l'entrée comporte des balises inconnues. <br/"
        ">Cette option est ignorée avec le mode XML. "
    },
    { TidyJoinClasses,                               0,        
        "Cette option précise si Tidy doit combiner les noms de classe pour produire un nouveau nom de "
        "classe unique, lorsque plusieurs affectations de classes sont détectées sur un élément."
    },
    { TidyJoinStyles,                                0,        
        "Cette option indique si Tidy doit combiner les styles pour produire un nouveau style unique, "
        "lorsque plusieurs styles sont détectés sur un élément."
    },
    { TidyKeepFileTimes,                             0,        
        "Cette option précise si Tidy doit préserver la date de modification des fichiers sur lesquels il "
        "travaille directement. <br/>Mettre cette option à <var>yes</var> vous autorise à nettoyer les "
        "fichiers sans changer la date de modification, ce qui peut avoir une utilité avec certains outils "
        "qui utilisent la date de modification pour des traitements comme le déploiement automatique.<br/"
        ">Notez que cette fonctionnalité n'est pas supportée par toutes les plateformes. "
    },
    { TidyLiteralAttribs,                            0,        
        "Cette option précise le comportement de Tidy avec les caractères d'espacement pour les valeurs "
        "d'attributs. <br/>Si la valeur de l'option est <var>no</var>, Tidy normalise les valeurs "
        "d'attributs en remplaçant n'importe quel nouveau saut de ligne ou tabulation par un espace unique, "
        "et ensuite en remplaçant n'importe quel espace contigu par un espace unique. <br/>Pour forcer Tidy "
        "à préserver les valeurs initiales, les valeurs littérales de tous les attributs, et assurer que les "
        "espacements dans les valeurs d'attributs soient inchangés, passer cette option à <var>yes</var>. "
    },
    { TidyLogicalEmphasis,                           0,        
        "Cette option précise si Tidy doit remplacer les occurrences de <code>&lt;i&gt;</code> par <code>&lt;"
        "em&gt;</code> et les occurrences de <code>&lt;b&gt;</code> par <code>&lt;strong&gt;</code>. Les "
        "attributs sont préservés et inchangés. <br/>Cette option peut être indiquée indépendamment de "
        "l'option <code>clean</code>. "
    },
    { TidyLowerLiterals,                             0,        
        "Cette option précise si Tidy doit convertir en minuscules la valeur d'un attribut qui prend une "
        "liste de valeur prédéfinies. <br/>Ceci est requis pour les documents XHTML. "
    },
    { TidyMakeBare,                                  0,        
        "Cette option précise si Tidy doit supprimer des documents Word 2000, le HTML spécifique de "
        "Microsoft, et afficher des espaces en sortie plutôt que des espaces insécables, lorsque ceux-ci "
        "sont présents en entrée."
    },
    { TidyMakeClean,                                 0,        
        "Cette option précise si Tidy doit effectuer le nettoyage de certaines balises historiques de "
        "présentation (actuellement <code>&lt; i&gt;</code>, <code>&lt;b&gt;</code>, <code>&lt;center&gt;</"
        "code> lorsque placé entre les balises inline appropriées, ainsi que <code>&lt; font&gt;</code>). Si "
        "la valeur est <var>yes</var>, les balises historiques seront remplacées par des balises CSS "
        "<code>&lt;style&gt;</code> et par une structure de balisage appropriée."
    },
    { TidyMark,                                      0,        
        "Cette option précise si Tidy doit ajouter un élément <code>meta</code> dans l'entête de document, "
        "pour indiquer que le document a été nettoyé par Tidy. <br/>Tidy n'ajoutera pas cet élément "
        "<code>meta</code> s'il existe déjà. "
    },
    { TidyMergeDivs,                                 0,        
        "Cette option peut être utilisée pour modifier le comportement de l'option <code>clean</code>, "
        "lorsqu'elle vaut <var>yes</var>. <br/>Cette option précise si Tidy doit concaténer les éléments "
        "<code>&lt;div&gt;</code> imbriqués, comme <code>&lt;div&gt;&lt;div&gt;...&lt;/div&gt;&lt;/div&gt;</"
        "code>. <br/>Si la valeur vaut <var>auto</var>, les attributs internes du <code>&lt;div&gt;</code> "
        "sont déplacés vers son div externe. Les <code>&lt;div&gt;</code> imbriqués avec des attributs "
        "<code>id</code> ne sont <em>pas</em> concaténés. <br/>Si la valeur vaut <var>yes</var>, les "
        "attributs du <code>&lt;div&gt;</code> interne ne sont pas pris en compte, à l'exception de "
        "<code>class</code> et de <code>style</code>. "
    },
    { TidyMergeEmphasis,                             0,        
        "Cette option précise si Tidy doit concaténer les éléments <code>&lt;b&gt;</code> et <code>&lt;i&gt;"
        "</code>; par exemple, pour le cas <br/><code>&lt;b class=\"rtop-2\"&gt;foo &lt;b class=\"r2-2\"&gt;"
        "bar&lt;/b&gt; baz&lt;/b&gt;</code>, <br/>Tidy produira la sortie <code>&lt;b class=\"rtop-2\"&gt;"
        "foo bar baz&lt;/b&gt;</code>. "
    },
    { TidyMergeSpans,                                0,        
        "Cette option peut être utlisée pour modifier le comportement de <code>clean</code>, si elle vaut "
        "<var>yes</var>.<br/>Cette option précise si Tidy doit concaténer les <code>&lt;span&gt;</code> "
        "imbriqués, comme suit : <code>&lt;span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;</code>. <br/"
        ">L'algorithme est le même que celui de <code>merge-divs</code>. "
    },
    { TidyNCR,                                       0, "Cette option précise si Tidy doit autoriser les références numériques de caractères. "                  },
    { TidyNewline,                                   0,        
        "La valeur par défaut est appropriée à la plateforme d'exécution de Tidy. <br/>Généralement "
        "<var>CRLF</var> sur PC-DOS, Windows et OS/2; <var>'\r'</var> sur Classic Mac OS; et <var>'\n'</var> "
        "partout ailleurs (Linux, Mac OS X, et Unix). "
    },
    { TidyNumEntities,                               0,        
        "Cette option précise si Tidy doit afficher les entités autres que les entités HTML intégrées "
        "(<code>&amp;amp;</code>, <code>&amp;lt;</code>, <code>&amp;gt;</code>, et <code>&amp;quot;</code>) "
        "dans la forme numérique plutôt que dans la forme nommée. <br/>Seules les entités compatibles avec "
        "la déclaration DOCTYPE générée sont utilisées. <br/>Les entités qui peuvent être représentées dans "
        "l'encodage de sortie sont traduites avec leur correspondance. "
    },
    { TidyOmitOptionalTags,                          0,        
        "Cette option précise si Tidy doit omettre les balises optionnelles ouvrantes et fermantes, "
        "lorsqu'il produit une sortie. <br/>Activer cette option entraîne l'omission en sortie de toutes les "
        "balises correspondantes aux éléments <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and "
        "<code>&lt;body&gt;</code>, de même que les balises de fermeture comme <code>&lt;/p&gt;</code>, "
        "<code>&lt;/li&gt;</code>, <code>&lt;/dt&gt;</code>, <code>&lt;/dd&gt;</code>, <code>&lt;/option&gt;"
        "</code>, <code>&lt;/tr&gt;</code>, <code>&lt;/td&gt;</code>, et <code>&lt;/th&gt;</code>. <br/"
        ">Cette option est ignorée pour la sortie XML. "
    },
    { TidyOutCharEncoding,                           0,        
        "Cette option précise l'encodage de caractère utilisé par Tidy pour la sortie. <br/>Notez que cela "
        "peut être différent de <code>input-encoding</code> seulement pour les encodages latins (<var>ascii</"
        "var>, <var>latin0</var>, <var>latin1</var>, <var>mac</var>, <var>win1252</var>, <var>ibm858</var>)."
        "<br/>Voir <code>char-encoding</code> pour plus d'informations."
    },
    { TidyOutFile,                                   0,        
        "Cette option précise le fichier de sortie que Tidy utilise pour la structure de balises. En "
        "principe la structure est écrite vers <code>stdout</code>. "
    },
    { TidyOutputBOM,                                 0,        
        "Cette option précise si Tidy doit écrire un caractère indicateur d'ordre des octets (Unicode Byte "
        "Order Mark ou BOM; connu aussi sous Zero Width No-Break Space; a la valeur de U+FEFF) au début de "
        "la sortie, ce qui ne s'applique qu'aux sorties encodées en UTF-8 et UTF-16. <br/>Si l'option vaut "
        "<var>auto</var>, Tidy écrira un BOM vers la sortie seulement si un BOM était présent au début de "
        "l'entrée. <br/>Un BOM est toujours écrit pour la sortie XML/XHTML des sorties encodées en UTF-16. "
    },
    { TidyPPrintTabs,                                0,        
        "Cette option précise si tidy doit indenter avec des tabulations plutôt que des espaces, en "
        "supposant que <code>indent</code> vaut <var>yes</var>. <br/>Définir cette option à <var>yes</var> "
        "indente avec des tabulations plutôt que des espaces, valeur par défaut. <br />Utilisez l'option "
        "<code>indent-spaces</code> pour redéfinir le nombre de tabulations en sortie par niveau "
        "d'indentation. Notez que lorsque <code>indent-with-tabs</code> est activé, la valeur par défaut de "
        "<code>indent-spaces</code> est réinitialisée à <var>1</var>. <br/>Notez que <code>tab-size</code> "
        "contrôle la conversion des tabulations d'entrée en des espaces de sortie. Définissez-la à zéro pour "
        "conserver les tabulations en entrée."
    },
    { TidyPreserveEntities,                          0, "Cette option précise si Tidy doit préserver les entités bien formées telles que trouvées en entrée. "   },
    { TidyPreTags,                                   0,        
        "Cette option précise les nouvelles balises qui doivent être traitées exactement de la même façon "
        "que l'élément HTML <code>&lt;pre&gt;</code>. Cette option prend une liste de nom de balises "
        "séparées par un espace ou une virgule. <br/>Sauf si vous déclarez de nouvelles balises, Tidy "
        "refusera de générer un fichier Tidy en sortie si l'entrée inclut préalablement des balises "
        "inconnues. <br/>Notez que vous ne pouvez encore ajouter de nouveaux éléments CDATA. <br/>Cette "
        "option est ignorée avec le mode XML. "
    },
    { TidyPunctWrap,                                 0,        
        "Cette option précise si Tidy doit passer à la ligne après certains caractères de ponctuation "
        "Unicode ou chinois."
    },
    { TidyQuiet,                                     0,        
        "Cette option précise si Tidy doit afficher le résumé du nombre des erreurs et avertissements, ou "
        "les messages de bienvenue et d'information."
    },
    { TidyQuoteAmpersand,                            0,        
        "Cette option précise si Tidy doit afficher en sortie les caractères <code>&amp;</code> en les "
        "écrivant <code>&amp;amp;</code>. "
    },
    { TidyQuoteMarks,                                0,        
        "Cette option précise si Tidy doit afficher les caractères <code>&quot;</code> comme <code>&amp;quot;"
        "</code> comme préféré par certains environnements d'édition. <br/>Le caractère apostrophe <code>'</"
        "code> est écrit <code>&amp;#39;</code> car de nombreux navigateurs webs ne supportent pas encore "
        "l'écriture <code>&amp;apos;</code>. "
    },
    { TidyQuoteNbsp,                                 0,        
        "Cette option précise si Tidy doit afficher les espaces insécables en tant qu'entités, plutôt qu'en "
        "utilisant la valeur de caractère unicode 160 (décimale). "
    },
    { TidyReplaceColor,                              0,        
        "Cette option précise si Tidy doit remplacer les valeurs numériques dans les attributs de couleur "
        "par les noms de couleurs HTML/XHTML lorsque définies, par exemple en remplaçant <code>#ffffff</"
        "code> par <code>white</code>. "
    },
    { TidyShowErrors,                                0,        
        "Cette option précise le nombre utilisé par Tidy pour déterminer si les erreurs suivantes doivent "
        "être montrées. Si la valeur est <var>0</var>, aucune erreur n'est affichée. "
    },
    { TidyShowInfo,                                  0, "Cette option précise si Tidy doit afficher les messages de niveau info-level."                          },
    { TidyShowMarkup,                                0,        
        "Cette option précise si Tidy doit générer un affichage embelli de la structure de balises. Notez "
        "que Tidy ne générera pas un affichage embelli s'il trouve des erreurs significatives (voir "
        "<code>force-output</code>). "
    },
    { TidyShowWarnings,                              0,        
        "Cette option précise si Tidy doit supprimer les avertissements. Cela peut être utile lorsque "
        "quelques erreurs sont cachées dans une masse d'avertissements. "
    },
    { TidySkipNested,                                0,        
        "Cette option précise que Tidy doit ignorer les balises imbriquées lors de l'analyse des données de "
        "script et de style."
    },
    { TidySortAttributes,                            0,        
        "Cette option précise que Tidy doit classer les attributs d'un élément en utilisant un algorithme de "
        "classement. Si la valeur est <var>alpha</var>, l'algorithme est un classement alphabétique "
        "ascendant. "
    },
    { TidyStrictTagsAttr,                            0,        
        "Ces options garantissent que les balises et attributs sont valides pour la version HTML en sortie "
        "de Tidy. Si la valeur est <var>yes</var> (par défaut) et que le type de document en sortie est une "
        "déclaration doctype stricte, alors Tidy rapportera les erreurs. Si le type de document en sortie "
        "est une déclaration doctype loose ou transitional, alors Tidy rapportera les avertissements. <br/"
        ">En complément, si l'option <code>drop-proprietary-attributes</code> est activée, alors les "
        "attributs non valables seront aussi supprimés. <br/>Si la valeur est <var>no</var>, ces contrôles "
        "ne sont pas effectués. "
    },
    { TidyTabSize,                                   0,        
        "Cette option précise le nombre de colonnes que Tidy utilise entre deux tabulations successives. "
        "Ceci est utilisé pour lier les tabulations aux espaces pendant la lecture de l'entrée."
    },
    { TidyUpperCaseAttrs,                            0,        
        "Cette option précise si Tidy doit afficher les noms d'attributs en majuscules. <br/>La valeur par "
        "défaut est <var>no</var>, ce qui produit un affichage des attributs en minuscules, excepté pour une "
        "entrée XML, pour laquelle la casse originale est préservée. "
    },
    { TidyUpperCaseTags,                             0,        
        "Cette option précise si Tidy doit afficher les noms de balises en majuscules. <br/>La valeur par "
        "défaut est <var>no</var>, ce qui produit un affichage des balises en minuscules, excepté pour une "
        "entrée XML, pour laquelle la casse originale est préservée. "
    },
    { TidyUseCustomTags,                             0,        
        "Cette option active dans Tidy l'utilisation de balises pour les éléments personnalisés autonomes, "
        "par exemple &lt;flag-icon&gt;. Les balises personnalisées sont désactivées si cette valeur est "
        "<var>no</var>. Autres configurations - <var>blocklevel</var>, <var>empty</var>, <var>inline</var>, "
        "et <var>pre</var> seront <em>all</em> traités en conséquence comme des balises personnalisées "
        "détectées. <br/>L'usage de <code>new-blocklevel-tags</code>, <code>new-empty-tags</code>, <code>new-"
        "inline-tags</code>, ou <code>new-pre-tags</code> surchargera le traitement des balises "
        "personnalisées par cette option de configuration. Ceci peut être utile si vous avez différents "
        "types de balises personnalisées. <br/>Lorsque l'option est activée, ces balises sont déterminées "
        "pendant la phase de traitement de votre document, par la balise d'ouverture; les balises de "
        "fermeture correspondantes seront reconnues en conséquence, et les balises de fermeture inconnues "
        "seront ignorées. "
    },
    { TidyVertSpace,                                 0,        
        "Cette option précise si Tidy doit ajouter quelques lignes vides supplémentaires pour la lisibilité. "
        "<br/>La valeur par défaut est <var>no</var>. <br/>Si la valeur est <var>auto</var> Tidy éliminera "
        "presque tous les caractères de nouvelle ligne."
    },
    { TidyWarnPropAttrs,                             0, "Cette option précise si Tidy doit avertir des attributs propriétaires."                                 },
    { TidyWord2000,                                  0,        
        "Cette option précise si Tidy doit se donner du mal pour supprimer tous les surplus que Microsoft "
        "Word 2000 ajoute lorsque vous enregistrez des documents Word comme des \"pages Web\". Il ne prend "
        "pas en charge les images embarquées ou le VML. <br/>Vous devriez songer à utiliser la "
        "fonctionnalité de Word \"Enregistrer Sous: Page Web, Filtrée\". "
    },
    { TidyWrapAsp,                                   0,        
        "Cette option précise si Tidy doit ajouter un saut de ligne au texte contenu dans les pseudos-"
        "éléments ASP, qui ressemblent à <code>&lt;% ... %&gt;</code>. "
    },
    { TidyWrapAttVals,                               0,        
        "Cette option précise si Tidy doit ajouter des sauts de ligne aux valeurs d'attributs, ce qui "
        "signifie que si la valeur d'un attribut entraîne le dépassement de la largeur précisée par "
        "<code>wrap</code>, Tidy ajoutera un ou plusieurs sauts de lignes à la valeur, ce qui implique son "
        "découpage en plusieurs lignes. <br/>Notez que cette option peut être précisée indépendamment de "
        "<code>wrap-script-literals</code>. Par défaut, Tidy remplace n'importe quelle nouvelle ligne ou "
        "tabulation par un espace simple et remplace n'importe quelle séquence d'espacement par un espace "
        "simple. <br/>Pour forcer Tidy à préserver les valeurs littérales initiales de tous les attributs, "
        "et garantir que les caractères d'espacement dans les valeurs d'attributs sont maintenus inchangés, "
        "préciser la valeur de <code>literal-attributes</code> à <var>yes</var>. "
    },
    { TidyWrapJste,                                  0,        
        "Cette option précise si Tidy doit ajouter un saut de ligne au texte contenu dans les pseudos-"
        "éléments JSTE, qui ressemblent à <code>&lt;# ... #&gt;</code>. "
    },
    { TidyWrapLen,                                   0,        
        "Cette option précise à Tidy la marge de droite à utiliser pour le saut de ligne. <br/> Tidy tente "
        "de couper les lignes de façon à ce qu'elles ne dépassent pas cette longueur. <br/>Passer la valeur "
        "de <code>wrap</code> à <var>0</var>(zéro) désactive l'ajout de saut de ligne. "
    },
    { TidyWrapPhp,                                   0,        
        "Cette option précise si Tidy doit ajouter un saut de ligne au texte contenu dans les pseudos-"
        "éléments PHP, qui ressemblent à: <code>&lt;?php ... ?&gt;</code>. "
    },
    { TidyWrapScriptlets,                            0,        
        "Cette option précise si Tidy doit ajouter des sauts de lignes aux chaînes littérales dans les "
        "attributs de script. <br/>Tidy prend en charge la césure des longues chaînes littérales de scripts "
        "en ajoutant un caractère de barre oblique arrière (backslash) avant le saut de ligne. "
    },
    { TidyWrapSection,                               0,        
        "Cette option précise si Tidy doit ajouter des sauts de ligne pour le texte compris dans des balises "
        "de section <code>&lt;![ ... ]&gt;</code> section tags. "
    },
    { TidyWriteBack,                                 0,        
        "Cette option précise si Tidy doit réécrire la structure de balise qu'il a produit vers le même "
        "fichier à partir duquel il l'a lu. <br/> Il est conseillé de garder une copie des fichiers "
        "importants avant de les faire modifier par Tidy, car dans de rares occasions le résultat peut être "
        "inattendu. "
    },
    { TidyXhtmlOut,                                  0,        
        "Cette option précise si Tidy doit afficher une sortie embellie, en l'écrivant avec HTML étendu. <br/"
        "> Avec cette option activée, Tidy définit la déclaration DOCTYPE et l'espace de nom par défaut "
        "approprié pour du XHTML, et utilisera la valeur corrigée en sortie indépendamment des autres "
        "sources. <br/>Pour le XHTML, les entités seront écrites en entités nommées ou numériques "
        "conformément à la valeur de configuration de <code>numeric-entities</code>. <br/>La casse originale "
        "des balises et attributs sera préservée, indépendamment des autres options. "
    },
    { TidyXmlDecl,                                   0,        
        "Cette option précise si Tidy doit ajouter la déclaration XML lors de la sortie XML ou XHTML. <br/> "
        "Notez que si l'entrée comprend déjà une déclaration <code>&lt;?xml ... ?&gt;</code>, alors cette "
        "option sera ignorée. <br/>Si l'encodage pour la sortie est différent de <var>ascii</var>, de l'un "
        "des encodages <var>utf*</var> ou <var>raw</var>, alors la déclaration est toujours ajoutée, comme "
        "indiqué dans le standard XML."
    },
    { TidyXmlOut,                                    0,        
        "Cette option précise si Tidy doit afficher une sortie embellie, en l'écrivant avec du XML bien "
        "structuré. <br/> Toutes les entités non définies en XML 1.0 seront réécrites en entités numériques "
        "pour leur permettre d'être parcourues par un analyseur XML. <br/>La casse originale des balises et "
        "attributs sera préservée, indépendamment des autres options. "
    },
    { TidyXmlPIs,                                    0,        
        "Cette option précise si Tidy doit modifier l'analyse syntaxique des instructions de traitement pour "
        "exiger <code>?&gt;</code> comme terminaison plutôt que <code>&gt;</code>. <br/> Cette option est "
        "automatiquement activée si l'entrée est en XML."
    },
    { TidyXmlSpace,                                  0,        
        "Cette option précise si tidy doit ajouter <code>xml:space=\"preserve\"</code> pour des éléments "
        "tels que <code>&lt;pre&gt;</code>, <code>&lt;style&gt;</code> and <code>&lt;script&gt;</code> lors "
        "de la production de XML. <br />Ceci est nécessaire si l'espace blanc dans de tels éléments doit "
        "être analysé convenablement sans avoir accès à la DTD."
    },
    { TidyXmlTags,                                   0,        
        "Cette option précise si Tidy doit utiliser l'analyseur XML plutôt que l'analyseur de correction "
        "d'erreur HTML."
    },
    { TidyInfo,                                      0, "Info:"                                                                                                  },
    { TidyWarning,                                   0, "Avertissement:"                                                                                         },
    { TidyConfig,                                    0, "Config:"                                                                                                },
    { TidyAccess,                                    0, "Accès:"                                                                                                 },
    { TidyError,                                     0, "Erreur:"                                                                                                },
    { TidyBadDocument,                               0, "Document:"                                                                                              },
    { TidyFatal,                                     0, "Panique:"                                                                                               },
    { TidyDialogueSummary,                           0, "Résumé:"                                                                                                },
    { TidyDialogueInfo,                              0, "Informations: "                                                                                         },
    { TidyDialogueFootnote,                          0, "Remarque:"                                                                                              },
    { LINE_COLUMN_STRING,                            0, "Ligne: %d Col: %d - "                                                                                   },
    { STRING_DISCARDING,                             0, "rejet"                                                                                                  },
    { STRING_ERROR_COUNT_ERROR,                      0, "erreur"                                                                                                 },
    { STRING_ERROR_COUNT_ERROR,                      1, "erreurs"                                                                                                },
    { STRING_ERROR_COUNT_WARNING,                    0, "avertissement"                                                                                          },
    { STRING_ERROR_COUNT_WARNING,                    1, "avertissements"                                                                                         },
    { STRING_HELLO_ACCESS,                           0,        
        "\n"
        "Contrôles d'accessibilité:\n"
    },
    { STRING_HTML_PROPRIETARY,                       0, "HTML Propriétaire"                                                                                      },
    { STRING_XML_DECLARATION,                        0, "déclaration XML"                                                                                        },
    { STRING_PLAIN_TEXT,                             0, "texte brut"                                                                                             },
    { STRING_REPLACING,                              0, "remplacement"                                                                                           },
    { STRING_SPECIFIED,                              0, "précisé"                                                                                                },
    { TIDYCUSTOMNO_STRING,                           0, "aucune"                                                                                                 },
    { TIDYCUSTOMBLOCKLEVEL_STRING,                   0, "élément de bloc"                                                                                        },
    { TIDYCUSTOMEMPTY_STRING,                        0, "vide"                                                                                                   },
    { TEXT_HTML_T_ALGORITHM,                         0,        
        "\n"
        "       - D'abord, cherchez depuis la gauche de la position de la cellule \n"
        "         pour trouver la rangée des cellules d'entête de lignes. \n"
        "       - Puis rechercher vers le haut pour trouver les cellules d'entête \n"
        "         de colonne.\n"
        "       - La recherche dans une direction donnée s'arrête lorsque le bout \n"
        "         du tableau est atteint ou lorsque la cellule de données est \n"
        "         trouvée après une cellule d'en-tête.\n"
        "       - Les entêtes de ligne sont insérés dans la liste, dans l'ordre dans \n"
        "         lequel ils apparaissent dans le tableau.\n"
        "       - Pour les tableaux de gauche à droite, les entêtes sont insérés de \n"
        "         gauche à droite.\n"
        "       - Les entêtes de colonnes sont insérés après les entêtes de ligne,\n"
        "         dans l'ordre dans lequel ils apparaissent dans le tableau, de haut \n"
        "         en bas.\n"
        "       - Si une cellule d'entête a ses entêtes d'attributs complétés, alors \n"
        "         les entêtes référencés par cet attribut sont insérés dans la \n"
        "         liste et la recherche s'arrête pour la direction courante.\n"
        "         Les cellules TD qui fixent l'attribut de l'axe sont également \n"
        "         traitées comme des cellules d'entête.\n"
    },
    { TEXT_VENDOR_CHARS,                             0,        
        "Il est peu probable que des encodages spécifiques à un éditeur,\n"
        "dépendants d'un système, fonctionnent suffisamment largement\n"
        "pour le World Wide Web; vous devriez éviter d'utiliser l'encodage\n"
        "de caractère %s, et utiliser plutôt des entités nommées,\n"
        "par exemple &trade;.\n"
    },
    { TEXT_SGML_CHARS,                               0,        
        "Les codes de caractères 128 à 159 (U + 0080 à U + 009F) ne sont pas \n"
        "autorisés en HTML; même si ils l'étaient, il seraient probablement non \n"
        "imprimables comme des caractères de contrôle .\n"
        "Tidy a supposé que vous vouliez faire référence à un caractère avec la \n"
        "même valeur d'encodage d'octet %s et a remplacé cette référence par \n"
        "son équivalent Unicode.\n"
    },
    { TEXT_INVALID_UTF8,                             0,        
        "Les codes de caractères UTF-8 doivent être dans l'intervalle : U+0000 à U+10FFFF.\n"
        "La définition de l'UTF-8 à l'annexe D de la norme ISO/CEI 10646-1: 2000 permet \n"
        "également l'utilisation de séquences de cinq et six octets pour coder des caractères \n"
        "qui sont en dehors de l'intervalle des caractères Unicode;\n"
        "ces séquences de cinq et six octets sont inappropriées pour l'utilisation de l'UTF-8 \n"
        "dans l'objectif de transformation de caractères Unicode. ISO/IEC 10646 \n"
        "ne permet pas la liaison des substituts non appairés, ni U+FFFE ni U+FFFF \n"
        "(mais il permet d'autres non-caractères). Pour plus d'informations veuillez-vous\n"
        "référer à http://www.unicode.org/ et http://www.cl.cam.ac.uk/~mgk25/unicode.html\n"
    },
    { TEXT_INVALID_UTF16,                            0,        
        "Les codes de caractères pour UTF-16 doivent être dans l'intervalle: U+0000 à U+10FFFF.\n"
        "La définition de UTF-16 dans l'annexe C de l'ISO/IEC 10646-1:2000 n'autorise pas la \n"
        "liaison de substituts non appairés. Pour plus d'informations, veuillez vous référer\n"
        "à http://www.unicode.org/ et http://www.cl.cam.ac.uk/~mgk25/unicode.html\n"
    },
    { TEXT_INVALID_URI,                              0,        
        "Les URIs doivent être correctement protégés, ils ne doivent pas contenir \n"
        "les caractères non-échappés ci-après U+0021, y-compris le caractère \n"
        "d'espacement et non plus le U+007E. Tidy échappe l'URI pour vous \n"
        "comme recommandé par HTML 4.01 section B.2.1 et XML 1.0 \n"
        "section 4.2.2. Certains user-agents utilisent un autre algorithme pour \n"
        "échapper ces URI et quelques scripts côté serveur dépendent de ceci. \n"
        "Si vous voulez dépendre de ceci, vous devez échapper l'URI de votre \n"
        "côté. Pour plus d'informations, veuillez vous référer à\n"
        "http://www.w3.org/International/O-URL-and-ident.html\n"
    },
    { TEXT_BAD_FORM,                                 0,        
        "Vous devrez peut-être déplacer une, ou les deux, balises <form>et</form>. \n"
        "Les éléments HTML doivent être correctement imbriquées et les éléments \n"
        "de formulaire ne font pas exception. Par exemple, vous ne devez pas placer \n"
        "<form>dans une cellule et </form>dans une autre. Si <form>est placé devant \n"
        "un tableau, </form> ne peut pas être placé à l'intérieur du tableau !\n"
        "Notez qu'un form ne peut pas être imbriqué dans un autre !\n"
    },
    { TEXT_BAD_MAIN,                                 0,        
        "Un seul élément <main> est permis dans un document.\n"
        "Les éléments <main> suivants ont été rejetés, ce qui peut rendre \n"
        "le document non valide.\n"
    },
    { TEXT_M_SUMMARY,                                0,        
        "L'attribut summary du tableau devrait servir à décrire la structure\n"
        "du tableau. Il est très utile pour les personnes utilisant des \n"
        "navigateurs non visuels. Les attributs de portée et entêtes \n"
        "pour les cellules d'un tableau sont utiles pour préciser les entêtes \n"
        "s'appliquant à chaque cellule du tableau, permettant aux navigateurs \n"
        "non visuels de fournir un contexte significatif pour chaque cellule.\n"
        "\n"
    },
    { TEXT_M_IMAGE_ALT,                              0,        
        "L'attribut alt devrait servir à donner une brève description d'une\n"
        "image ; Il faudrait aussi des descriptions plus longues avec l'attribut\n"
        "longdesc qui prend une URL liée à la description. Ces mesures sont\n"
        "nécessaires pour les personnes utilisant des navigateurs textuels.\n"
        "\n"
    },
    { TEXT_M_IMAGE_MAP,                              0,        
        "Utiliser des images interactives côté client est préférable à celles côté \n"
        "serveur, ces dernières sont inaccessibles aux personnes utilisant des \n"
        "navigateurs non-graphiques. En outre, les cartes côté client sont plus \n"
        "faciles à mettre en place et fournissent une interactivité immédiate \n"
        "aux utilisateurs.\n"
        "\n"
    },
    { TEXT_M_LINK_ALT,                               0,        
        "Pour les liens hypertextes définis à l'aide d'une image interactive \n"
        "côté client, vous devez utiliser l'attribut alt pour fournir une \n"
        "description textuelle du lien, pour les personnes utilisant des \n"
        "\n"
    },
    { TEXT_USING_FRAMES,                             0,        
        "Les pages conçues à l'aide de cadres posent des problèmes aux \n"
        "personnes malvoyantes ou à celles qui utilisent un navigateur ne \n"
        "supportant pas les frames. Une structure de page basée sur des \n"
        "cadres doit toujours inclure une structure alternative à l'intérieur \n"
        "d'un élément NOFRAMES.\n"
        "\n"
    },
    { TEXT_ACCESS_ADVICE1,                           0,        
        "Pour plus d'informations sur la façon de rendre vos pages\n"
        "accessibles, voir http://www.w3.org/WAI/GL"
    },
    { TEXT_ACCESS_ADVICE2,                           0,        
        "Pour plus d'informations sur la façon de rendre vos pages \n"
        "accessibles, voir http://www.w3.org/WAI/GL et \n"
        "http://www.html-tidy.org/Accessibility/"
    },
    { TEXT_USING_LAYER,                              0,        
        "Le mécanisme de positionnement au moyen des feuilles de style \n"
        "en cascade (CSS) est préférable à l'élément propriétaire <LAYER>, \n"
        "en raison du support limité des éditeurs pour LAYER.\n"
    },
    { TEXT_USING_SPACER,                             0,        
        "Il est recommandé d'utiliser les CSS pour contrôler les espacements \n"
        "(par exemple pour le retrait, les marges et les interlignes).\n"
        "L'élément propriétaire <SPACER> a un soutien limité des éditeurs.\n"
        "\n"
    },
    { TEXT_USING_FONT,                               0,        
        "Il est recommandé d'utiliser les CSS pour préciser la police et les \n"
        "propriétés telles que la taille et la couleur. Cela permettra de réduire \n"
        "la taille des fichiers HTML et de les rendre plus faciles à entretenir \n"
        "\n"
    },
    { TEXT_USING_NOBR,                               0,        
        "Il est recommandé d'utiliser les CSS pour contrôler les sauts de ligne.\n"
        "Utilisez \"white-space: nowrap\" pour inhiber les sauts de ligne plutôt que \n"
        "d'insérer <NOBR> ... </ NOBR> dans la structure de balises.\n"
        "\n"
    },
    { TEXT_USING_BODY,                               0,        
        "Il est recommandé d'utiliser les CSS pour préciser les couleurs \n"
        "de la page et des liens"
    },
    { STRING_CONTENT_LOOKS,                          0, "Le contenu du document ressemble à %s"                                                                  },
    { STRING_DOCTYPE_GIVEN,                          0, "DOCTYPE donnée est «%s»"                                                                                },
    { STRING_ERROR_COUNT,                            0, "Tidy a trouvé %u %s et %u %s!\n"                                                                        },
    { STRING_NEEDS_INTERVENTION,                     0,        
        "Ce document contient des erreurs qui doivent d'abord être résolues\n"
        "en utilisant HTML Tidy pour produire une version nettoyée.\n"
    },
    { STRING_NO_ERRORS,                              0, "Aucun avertissement ou erreur trouvée.\n"                                                               },
    { STRING_NO_SYSID,                               0, "Aucun identifiant système dans le doctype soumis"                                                       },
    { STRING_NOT_ALL_SHOWN,                          0, "Tidy a trouvé %u %s et %u %s! Tous les avertissements et erreurs n'ont pas été affichés.\n"             },
    { TEXT_GENERAL_INFO,                             0,        
        "À propos de HTML Tidy: https://github.com/htacg/tidy-html5\n"
        "Rapports de bugs et commentaires: https://github.com/htacg/tidy-html5/issues\n"
        "Liste officielle de diffusion: https://lists.w3.org/Archives/Public/public-htacg/\n"
        "Dernière spécification HTML: http://dev.w3.org/html5/spec-author-view/\n"
        "Validez vos documents HTML: http://validator.w3.org/nu/\n"
        "Encouragez votre entreprise à rejoindre le W3C: http://www.w3.org/Consortium\n"
        "\n"
    },
    { TEXT_GENERAL_INFO_PLEA,                        0,        
        "Parlez-vous une autre langue que le français, ou une variante du français?\n"
        "Merci de nous aider à traduire HTML Tidy. Pour plus d'informations, consultez \n"
        "https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md"
    },
    { ANCHOR_NOT_UNIQUE,                             0, "%s ancre \"%s\" déjà défini"                                                                            },
    { APOS_UNDEFINED,                                0, "l'entité nommée &apos; est défini seulement en XML/XHTML"                                               },
    { ATTR_VALUE_NOT_LCASE,                          0, "valeur d'attribut de %s « %s » doit être en minuscule pour XHTML"                                       },
    { ATTRIBUTE_IS_NOT_ALLOWED,                      0, "L'attribut %s n'\"est\" pas autorisé pour les balises personnalisées autonomes."                        },
    { BACKSLASH_IN_URI,                              0, "La référence d'URI %s contient des anti-slash. Faute de frappe ?"                                       },
    { BAD_ATTRIBUTE_VALUE_REPLACED,                  0, "%s l'attribut « %s » a une valeur non valide « %s » et a été remplacé"                                  },
    { BAD_ATTRIBUTE_VALUE,                           0, "%s l'attribut \"%s\" a une valeur non valide \"%s\""                                                    },
    { BAD_CDATA_CONTENT,                             0, "'<' + '/' + lettres non permises ici"                                                                   },
    { BAD_SUMMARY_HTML5,                             0, "L'attribut summary sur l'élément %s est obsolète avec HTML5"                                            },
    { BAD_SURROGATE_LEAD,                            0,        
        "Paire de substitution U+%04X de terminaison (Bas), sans entité principale (Haut), remplacée par U"
        "+FFFD."
    },
    { BAD_SURROGATE_PAIR,                            0, "Présence d'une paire de substitution hors intervalle U+%04X:U+%04X, remplacée par la valeur U+FFFD."    },
    { BAD_SURROGATE_TAIL,                            0,        
        "Paire de substitution principale (Haute) U+%04X, sans entité de terminaison (Haut), remplacée par U"
        "+FFFD."
    },
    { CANT_BE_NESTED,                                0, "%s ne peut pas être imbriqué"                                                                           },
    { COERCE_TO_ENDTAG,                              0, "<%s> est probablement souhaité pour </%s>"                                                              },
    { CONTENT_AFTER_BODY,                            0, "contenu trouvé après la fin de body"                                                                    },
    { CUSTOM_TAG_DETECTED,                           0, "balise personnalisée autonome détectée %s; sera traitée comme %s"                                       },
    { DISCARDING_UNEXPECTED,                         0, "inhibition de valeur inattendue %s"                                                                     },
    { DOCTYPE_AFTER_TAGS,                            0, "<!DOCTYPE> n'est pas autorisée après les éléments"                                                      },
    { DUPLICATE_FRAMESET,                            0, "élément répété FRAMESET"                                                                                },
    { ELEMENT_NOT_EMPTY,                             0, "%s élément non vide ou non fermé"                                                                       },
    { ELEMENT_VERS_MISMATCH_ERROR,                   0, "%s élément non disponible dans %s"                                                                      },
    { ELEMENT_VERS_MISMATCH_WARN,                    0, "%s élément non disponible dans %s"                                                                      },
    { ENCODING_MISMATCH,                             0, "l'encodage de caractère précisé en entrée (%s) ne correspond pas à l'encodage réellement entré (%s)"    },
    { ESCAPED_ILLEGAL_URI,                           0, "%s échappement de la référence d''URI mal formée"                                                       },
    { FILE_CANT_OPEN,                                0, "Impossible d'ouvrir « %s »\n"                                                                           },
    { FILE_NOT_FILE,                                 0, "\"%s\" n'est pas un fichier!\n"                                                                         },
    { FIXED_BACKSLASH,                               0, "%s conversion des antislash vers slash dans l'URI "                                                     },
    { ID_NAME_MISMATCH,                              0, "%s discordance entre id et valeur de nom d'attribut"                                                    },
    { ILLEGAL_NESTING,                               0, "%s ne doit pas être imbriqué"                                                                           },
    { ILLEGAL_URI_CODEPOINT,                         0, "%s caractères interdits trouvés dans l'URI"                                                             },
    { ILLEGAL_URI_REFERENCE,                         0, "%s mal échappé dans la référence d'URI"                                                                 },
    { INSERTING_AUTO_ATTRIBUTE,                      0, "%s insertion de l'attribut « %s », en utilisant la valeur « %s »"                                       },
    { INSERTING_TAG,                                 0, "insertion implicite de <%s>"                                                                            },
    { INVALID_ATTRIBUTE,                             0, "%s nom d'attribut « %s » (valeur=« %s ») n'est pas valide"                                              },
    { INVALID_NCR,                                   0, "%s référence de caractère numérique non valide %s"                                                      },
    { INVALID_SGML_CHARS,                            0, "%s code de caractère non valide %s"                                                                     },
    { INVALID_UTF8,                                  0, "%s octets UTF-8 non valides (code de caract. %s)"                                                       },
    { INVALID_UTF16,                                 0, "%s paire de substitution UFT-16 non valide (code de caract. %s)"                                        },
    { INVALID_XML_ID,                                0, "%s impossible de copier le nom attribut vers id"                                                        },
    { JOINING_ATTRIBUTE,                             0, "%s regroupement des valeurs répétées de l'attribut « %s »"                                              },
    { MALFORMED_COMMENT,                             0, "tirets adjacents dans un commentaire"                                                                   },
    { MALFORMED_DOCTYPE,                             0, "inhibition de la <!DOCTYPE> mal formée"                                                                 },
    { MISMATCHED_ATTRIBUTE_ERROR,                    0, "%s attribut \"%s\" non permis pour %s"                                                                  },
    { MISMATCHED_ATTRIBUTE_WARN,                     0, "%s attribut \"%s\" non permis pour %s"                                                                  },
    { MISSING_ATTR_VALUE,                            0, "%s attribut \"%s\" n'a pas de valeur"                                                                   },
    { MISSING_ATTRIBUTE,                             0, "%s absence d'attribut \"%s\""                                                                           },
    { MISSING_DOCTYPE,                               0, "déclaration <!DOCTYPE> manquante"                                                                       },
    { MISSING_ENDTAG_BEFORE,                         0, "absence de </%s> avant %s"                                                                              },
    { MISSING_ENDTAG_FOR,                            0, "absence de </%s>"                                                                                       },
    { MISSING_IMAGEMAP,                              0, "%s doivent utiliser une image-map côté client"                                                          },
    { MISSING_QUOTEMARK,                             0, "%s attribut avec apostrophe de fin manquante"                                                           },
    { MISSING_SEMICOLON_NCR,                         0, "La référence de caractère numérique « %s » ne se termine pas par « ; »"                                 },
    { MISSING_SEMICOLON,                             0, "l'entité « %s » ne se termine pas par « ; »"                                                            },
    { MISSING_STARTTAG,                              0, "absence de <%s>"                                                                                        },
    { MISSING_TITLE_ELEMENT,                         0, "ajout d'un élément 'title' manquant"                                                                    },
    { NESTED_EMPHASIS,                               0, "accentuation imbriquée %s"                                                                              },
    { NESTED_QUOTATION,                              0, "éléments \"q\" imbriqués, erreur typographique possible"                                                },
    { NEWLINE_IN_URI,                                0, "%s inhibition des nouvelles lignes dans la référence d'URI"                                             },
    { NOFRAMES_CONTENT,                              0, "%s non positionné dans l'élément 'noframes'"                                                            },
    { NON_MATCHING_ENDTAG,                           0, "remplacement des %s inattendus par </%s>"                                                               },
    { OBSOLETE_ELEMENT,                              0, "remplacement de l'élément obsolète %s par %s"                                                           },
    { PREVIOUS_LOCATION,                             0, "<%s> précédemment mentionnés"                                                                           },
    { PROPRIETARY_ATTR_VALUE,                        0, "%s valeur d'attribut propriétaire « %s »"                                                               },
    { PROPRIETARY_ATTRIBUTE,                         0, "%s attribut propriétaire \"%s\""                                                                        },
    { PROPRIETARY_ELEMENT,                           0, "%s n'est pas approuvé par le W3C"                                                                       },
    { REMOVED_HTML5,                                 0, "élément %s retiré de HTML5"                                                                             },
    { REPEATED_ATTRIBUTE,                            0, "%s abandon de la valeur « %s » pour l'attribut répété « %s »"                                           },
    { REPLACING_ELEMENT,                             0, "remplacement de %s par %s"                                                                              },
    { REPLACING_UNEX_ELEMENT,                        0, "remplacement des %s inattendus par %s"                                                                  },
    { SPACE_PRECEDING_XMLDECL,                       0, "suppression de l'espace précédant la déclaration XML"                                                   },
    { STRING_MISSING_MALFORMED,                      0, "argument manquant ou incorrect pour l'option: %s"                                                       },
    { STRING_UNKNOWN_OPTION,                         0, "option inconnue: %s"                                                                                    },
    { SUSPECTED_MISSING_QUOTE,                       0, "absence de guillemet pour la valeur d'attribut"                                                         },
    { TAG_NOT_ALLOWED_IN,                            0, "%s n'est pas permis dans les éléments <%s>"                                                             },
    { TOO_MANY_ELEMENTS_IN,                          0, "trop d'éléments %s dans <%s>"                                                                           },
    { TOO_MANY_ELEMENTS,                             0, "trop d'éléments %s"                                                                                     },
    { TRIM_EMPTY_ELEMENT,                            0, "réduction des %s vides"                                                                                 },
    { UNESCAPED_AMPERSAND,                           0, "symbole & non échappé qui devrait être écrit &amp;"                                                     },
    { UNEXPECTED_END_OF_FILE_ATTR,                   0, "%s fin de fichier lors de l'analyse des attributs"                                                      },
    { UNEXPECTED_END_OF_FILE,                        0, "fin de fichier inattendue %s"                                                                           },
    { UNEXPECTED_ENDTAG_ERR,                         0, "</%s> inattendu"                                                                                        },
    { UNEXPECTED_ENDTAG_IN,                          0, "</%s> inattendu dans <%s>"                                                                              },
    { UNEXPECTED_ENDTAG,                             0, "</%s> inattendu"                                                                                        },
    { UNEXPECTED_EQUALSIGN,                          0, "%s symbole imprévu '=', nom d'attribut attendu"                                                         },
    { UNEXPECTED_GT,                                 0, "%s symbole '>' manquant pour la fin de balise"                                                          },
    { UNEXPECTED_QUOTEMARK,                          0, "%s guillemet double inattendu ou dupliqué"                                                              },
    { UNKNOWN_ELEMENT_LOOKS_CUSTOM,                  0, "%s n'est pas reconnue! Vouliez-vous activer l'option custom-tags?"                                      },
    { UNKNOWN_ELEMENT,                               0, "%s n'est pas reconnue!"                                                                                 },
    { UNKNOWN_ENTITY,                                0, "symbole & non échappé ou entité inconnue « %s »"                                                        },
    { USING_BR_INPLACE_OF,                           0, "utilisation de <br> à la place de %s"                                                                   },
    { VENDOR_SPECIFIC_CHARS,                         0, "%s code de caractère non valide %s"                                                                     },
    { WHITE_IN_URI,                                  0, "%s rejet des espaces dans la référence URI"                                                             },
    { XML_DECLARATION_DETECTED,                      0, "Une déclaration XML a été détectée. Voulez-vous utiliser l'option input-xml?"                           },
    { XML_ID_SYNTAX,                                 0, "%s ID « %s » utilise la syntaxe XML ID"                                                                 },
    { IMG_MISSING_ALT,                               0, "[1.1.1.1]: <img> texte manquant 'alt'."                                                                 },
    { IMG_ALT_SUSPICIOUS_FILENAME,                   0, "[1.1.1.2]: texte 'alt' suspect (nom de fichier)."                                                       },
    { IMG_ALT_SUSPICIOUS_FILE_SIZE,                  0, "[1.1.1.3]: texte 'alt' suspect (taille de fichier)."                                                    },
    { IMG_ALT_SUSPICIOUS_PLACEHOLDER,                0, "[1.1.1.4]: texte 'alt' suspect (espace réservé)."                                                       },
    { IMG_ALT_SUSPICIOUS_TOO_LONG,                   0, "[1.1.1.10]: texte 'alt' suspect (trop long)."                                                           },
    { IMG_MISSING_LONGDESC_DLINK,                    0, "[1.1.2.1]: <img> absence de 'longdesc' et d-link."                                                      },
    { IMG_MISSING_DLINK,                             0, "[1.1.2.2]: <img> absence de d-link."                                                                    },
    { IMG_MISSING_LONGDESC,                          0, "[1.1.2.3]: <img> absence de 'longdesc'."                                                                },
    { IMG_BUTTON_MISSING_ALT,                        0, "[1.1.3.1]: <img> (bouton) absence de texte 'alt'."                                                      },
    { APPLET_MISSING_ALT,                            0, "[1.1.4.1]: <applet> absence de contenu alternatif."                                                     },
    { OBJECT_MISSING_ALT,                            0, "[1.1.5.1]: <object> absence de contenu alternatif."                                                     },
    { AUDIO_MISSING_TEXT_WAV,                        0, "[1.1.6.1]: texte de transcription audio manquant (wav)."                                                },
    { AUDIO_MISSING_TEXT_AU,                         0, "[1.1.6.2]: texte de transcription audio manquant (au)."                                                 },
    { AUDIO_MISSING_TEXT_AIFF,                       0, "[1.1.6.3]: texte de transcription audio manquant (aiff)."                                               },
    { AUDIO_MISSING_TEXT_SND,                        0, "[1.1.6.4]: texte de transcription audio manquant (snd)."                                                },
    { AUDIO_MISSING_TEXT_RA,                         0, "[1.1.6.5]: texte de transcription audio manquant (ra)."                                                 },
    { AUDIO_MISSING_TEXT_RM,                         0, "[1.1.6.6]: texte de transcription audio manquant (rm)."                                                 },
    { FRAME_MISSING_LONGDESC,                        0, "[1.1.8.1]: <frame> peut nécessiter 'longdesc'."                                                         },
    { AREA_MISSING_ALT,                              0, "[1.1.9.1]: <area> absence de texte 'alt'."                                                              },
    { SCRIPT_MISSING_NOSCRIPT,                       0, "[1.1.10.1]: <script> section <noscript> manquante."                                                     },
    { ASCII_REQUIRES_DESCRIPTION,                    0, "[1.1.12.1]: ascii art nécessite une description."                                                       },
    { IMG_MAP_SERVER_REQUIRES_TEXT_LINKS,            0, "[1.2.1.1]: image map (côté serveur) nécessite des liens textes."                                        },
    { MULTIMEDIA_REQUIRES_TEXT,                      0, "[1.4.1.1]: le multimédia nécessite une équivalence de textes correspondants."                           },
    { IMG_MAP_CLIENT_MISSING_TEXT_LINKS,             0, "[1.5.1.1]: image map (côté client) liens textes manquants."                                             },
    { INFORMATION_NOT_CONVEYED_IMAGE,                0, "[2.1.1.1]: Vérifiez que l'information n'est pas transmise uniquement par la couleur (image)."           },
    { INFORMATION_NOT_CONVEYED_APPLET,               0, "[2.1.1.2]: Vérifiez que l'information n'est pas transmise uniquement par la couleur (applet)."          },
    { INFORMATION_NOT_CONVEYED_OBJECT,               0, "[2.1.1.3]: Vérifiez que l'information n'est pas transmise uniquement par la couleur (object)."          },
    { INFORMATION_NOT_CONVEYED_SCRIPT,               0, "[2.1.1.4]: Vérifiez que l'information n'est pas transmise uniquement par la couleur (script)."          },
    { INFORMATION_NOT_CONVEYED_INPUT,                0,        
        "[2.1.1.5]: Vérifiez que l'information n'est pas transmise uniquement par la couleur (champs de "
        "formulaire)."
    },
    { COLOR_CONTRAST_TEXT,                           0, "[2.2.1.1]: contraste couleur faible (texte)."                                                           },
    { COLOR_CONTRAST_LINK,                           0, "2.2.1.2]: contraste couleur faible (lien)."                                                             },
    { COLOR_CONTRAST_ACTIVE_LINK,                    0, "2.2.1.3]: contraste couleur faible (lien actif)."                                                       },
    { COLOR_CONTRAST_VISITED_LINK,                   0, "2.2.1.4]: contraste couleur faible (lien visité)."                                                      },
    { DOCTYPE_MISSING,                               0, "[3.2.1.1]: déclaration <doctype> manquante."                                                            },
    { STYLE_SHEET_CONTROL_PRESENTATION,              0, "[3.3.1.1]: Utiliser les feuilles de style pour contrôler la présentation."                              },
    { HEADERS_IMPROPERLY_NESTED,                     0, "[3.5.1.1]: entêtes imbriqués incorrectement."                                                           },
    { POTENTIAL_HEADER_BOLD,                         0, "[3.5.2.1]: entête potentiel (gras)."                                                                    },
    { POTENTIAL_HEADER_ITALICS,                      0, "[3.5.2.2]: entête potentiel (italique)."                                                                },
    { POTENTIAL_HEADER_UNDERLINE,                    0, "[3.5.2.3]: entête potentiel (soulignement)."                                                            },
    { HEADER_USED_FORMAT_TEXT,                       0, "[3.5.3.1]: entête utilisé pour formater du texte."                                                      },
    { LIST_USAGE_INVALID_UL,                         0, "[3.6.1.1]: Usage non valide de liste <ul>."                                                             },
    { LIST_USAGE_INVALID_OL,                         0, "[3.6.1.2]: usage non valide de liste <ol>."                                                             },
    { LIST_USAGE_INVALID_LI,                         0, "[3.6.1.4]: usage non valide de liste <li>."                                                             },
    { LANGUAGE_NOT_IDENTIFIED,                       0, "[4.3.1.1]: langage non identifié."                                                                      },
    { LANGUAGE_INVALID,                              0, "[4.3.1.2]: attribut de langage non valide."                                                             },
    { DATA_TABLE_MISSING_HEADERS,                    0, "[5.1.2.1]: data <table> absence d'entêtes rangée/colonne (tous)."                                       },
    { DATA_TABLE_MISSING_HEADERS_COLUMN,             0, "[5.1.2.2]: data <table> absence d'entêtes rang/colonne (1 col)."                                        },
    { DATA_TABLE_MISSING_HEADERS_ROW,                0, "[5.1.2.3]: data <table> absence d'entêtes rang/colonne (1 rang)."                                       },
    { DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS,      0, "[5.2.1.1]: data <table> peut nécessiter une structure de balises (entêtes de colonne)."                 },
    { DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS,         0, "[5.2.1.1]: data <table> peut nécessiter une structure de balises (entêtes de rangée)."                  },
    { LAYOUT_TABLES_LINEARIZE_PROPERLY,              0, "[5.3.1.1]: vérifie que la structure des tableaux est correctement sérialisée."                          },
    { LAYOUT_TABLE_INVALID_MARKUP,                   0, "[5.4.1.1]: structure de balises incorrecte dans l'agencement de <table>."                               },
    { TABLE_MISSING_SUMMARY,                         0, "[5.5.1.1]: <table> absence de résumé."                                                                  },
    { TABLE_SUMMARY_INVALID_NULL,                    0, "[5.5.1.2]: <table> résumé non valide (null)."                                                           },
    { TABLE_SUMMARY_INVALID_SPACES,                  0, "[5.5.1.3]: <table> résumé non valide (espaces)."                                                        },
    { TABLE_SUMMARY_INVALID_PLACEHOLDER,             0, "[5.5.1.6]: <table> résumé non valide (texte de l'emplacement réservé)."                                 },
    { TABLE_MISSING_CAPTION,                         0, "[5.5.2.1]: <table> absence de légende (<caption>)."                                                     },
    { TABLE_MAY_REQUIRE_HEADER_ABBR,                 0, "[5.6.1.1]: <table> peut nécessiter des abréviations d'entête."                                          },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_NULL,            0, "[5.6.1.2]: <table> abréviations d'entête non valide (null)."                                            },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES,          0, "[5.6.1.3]: <table> abréviations d'entête non valide (espaces)."                                         },
    { STYLESHEETS_REQUIRE_TESTING_LINK,              0, "[6.1.1.1]: les feuilles de style nécessitent un examen (link)."                                         },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT,     0, "[6.1.1.2]: les feuilles de style nécessitent un examen (élément style)."                                },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR,        0, "[6.1.1.3]: les feuilles de style nécessitent un examen (attribut style)."                               },
    { FRAME_SRC_INVALID,                             0, "[6.2.1.1]: <frame> source non valide."                                                                  },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET,      0, "[6.2.2.1]: les équivalences de texte nécessitent une mise à jour (applet)."                             },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT,      0, "[6.2.2.2]: les équivalences de texte nécessitent une mise à jour (script)."                             },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT,      0, "[6.2.2.3]: les équivalences de texte nécessitent une mise à jour (object)."                             },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT,   0, "[6.3.1.1]: les objets programmatiques nécessitent un examen (script)."                                  },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT,   0, "[6.3.1.2]: les objets programmatiques nécessitent un examen (object)."                                  },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED,    0, "[6.3.1.3]: les objets programmatiques nécessitent un examen (embed)."                                   },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET,   0, "[6.3.1.4]: les objets programmatiques nécessitent un examen (applet)."                                  },
    { FRAME_MISSING_NOFRAMES,                        0, "[6.5.1.1]: <frameset> section <noframes> manquante."                                                    },
    { NOFRAMES_INVALID_NO_VALUE,                     0, "[6.5.1.2]: <noframes> section non valide (pas de valeur)."                                              },
    { NOFRAMES_INVALID_CONTENT,                      0, "[6.5.1.3]: <noframes> section non valide (contenu)."                                                    },
    { NOFRAMES_INVALID_LINK,                         0, "[6.5.1.4]: <noframes> section non valide (lien)."                                                       },
    { REMOVE_FLICKER_SCRIPT,                         0, "[7.1.1.1]: suppression de scintillement (script)."                                                      },
    { REMOVE_FLICKER_OBJECT,                         0, "[7.1.1.2]: suppression de scintillement (object)."                                                      },
    { REMOVE_FLICKER_EMBED,                          0, "[7.1.1.1]: suppression de scintillement (embed)."                                                       },
    { REMOVE_FLICKER_APPLET,                         0, "[7.1.1.1]: suppression de scintillement (applet)."                                                      },
    { REMOVE_FLICKER_ANIMATED_GIF,                   0, "[7.1.1.1]: suppression de scintillement (gif animé)."                                                   },
    { REMOVE_BLINK_MARQUEE,                          0, "[7.2.1.1]: suppression de blink/marquee."                                                               },
    { REMOVE_AUTO_REFRESH,                           0, "[7.4.1.1]: suppression de auto-refresh."                                                                },
    { REMOVE_AUTO_REDIRECT,                          0, "[7.5.1.1]: suppression de auto-redirect."                                                               },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT, 0, "[8.1.1.1]: garantir que les objets programmatiques sont accessibles (script)."                          },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT, 0, "[8.1.1.2]: garantir que les objets programmatiques sont accessibles (object)."                          },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET, 0, "[8.1.1.3]: garantir que les objets programmatiques sont accessibles (applet)."                          },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED,  0, "[8.1.1.4]: garantir que les objets programmatiques sont accessibles (embed)."                           },
    { IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION,     0, "[9.1.1.1]: image map (côté serveur) nécessite une conversion."                                          },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN,  0, "[9.3.1.1]: <script> non accessible par le clavier (onMouseDown)."                                       },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP,    0, "[9.3.1.2]: <script> non accessible par le clavier (onMouseUp)."                                         },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK,       0, "[9.3.1.3]: <script> non accessible par le clavier (onClick)."                                           },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER,  0, "[9.3.1.4]: <script> non accessible par le clavier (onMouseOver)."                                       },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT,   0, "[9.3.1.5]: <script> non accessible par le clavier (onMouseOut)."                                        },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE,  0, "[9.3.1.6]: <script> non accessible par le clavier (onMouseMove)."                                       },
    { NEW_WINDOWS_REQUIRE_WARNING_NEW,               0, "[10.1.1.1]: les nouvelles fenêtres nécessitent un avertissement (_new)."                                },
    { NEW_WINDOWS_REQUIRE_WARNING_BLANK,             0, "[10.1.1.2]: les nouvelles fenêtres nécessitent un avertissement (_blank)."                              },
    { REPLACE_DEPRECATED_HTML_APPLET,                0, "[11.2.1.1]: remplacer l'élément HTML déprécié <applet>."                                                },
    { REPLACE_DEPRECATED_HTML_BASEFONT,              0, "[11.2.1.2]: remplacer l'élément HTML déprécié <basefont>."                                              },
    { REPLACE_DEPRECATED_HTML_CENTER,                0, "[11.2.1.3]: remplacer l'élément HTML déprécié <center>."                                                },
    { REPLACE_DEPRECATED_HTML_DIR,                   0, "[11.2.1.4]: remplacer l'élément HTML déprécié <dir>."                                                   },
    { REPLACE_DEPRECATED_HTML_FONT,                  0, "[11.2.1.5]: remplacer l'élément HTML déprécié <font>."                                                  },
    { REPLACE_DEPRECATED_HTML_ISINDEX,               0, "[11.2.1.6]: remplacer l'élément HTML déprécié <isindex>."                                               },
    { REPLACE_DEPRECATED_HTML_MENU,                  0, "[11.2.1.7]: remplacer l'élément HTML déprécié <menu>."                                                  },
    { REPLACE_DEPRECATED_HTML_S,                     0, "[11.2.1.8]: remplacer l'élément HTML déprécié <s>."                                                     },
    { REPLACE_DEPRECATED_HTML_STRIKE,                0, "[11.2.1.9]: remplacer l'élément HTML déprécié <strike>."                                                },
    { REPLACE_DEPRECATED_HTML_U,                     0, "[11.2.1.10]: remplacer l'élément HTML déprécié <u>."                                                    },
    { FRAME_MISSING_TITLE,                           0, "[12.1.1.1]: <frame> absence de titre."                                                                  },
    { FRAME_TITLE_INVALID_NULL,                      0, "[12.1.1.2]: <frame> titre non valide (null)."                                                           },
    { FRAME_TITLE_INVALID_SPACES,                    0, "[12.1.1.3]: <frame> titre non valide (espaces)."                                                        },
    { ASSOCIATE_LABELS_EXPLICITLY,                   0, "[12.4.1.1]: associer explicitement les étiquettes avec les contrôles de formulaire."                    },
    { ASSOCIATE_LABELS_EXPLICITLY_FOR,               0, "[12.4.1.2]: associer explicitement les étiquettes avec les contrôles de formulaire (for)."              },
    { ASSOCIATE_LABELS_EXPLICITLY_ID,                0, "[12.4.1.3]: associer explicitement les étiquettes avec les contrôles de formulaire (id)."               },
    { LINK_TEXT_NOT_MEANINGFUL,                      0, "[13.1.1.1]: texte du lien peu significatif."                                                            },
    { LINK_TEXT_MISSING,                             0, "[13.1.1.2]: texte du lien manquant."                                                                    },
    { LINK_TEXT_TOO_LONG,                            0, "[13.1.1.3]: texte du lien trop long."                                                                   },
    { LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE,           0, "[13.1.1.4]: texte du lien peu significatif (click here)."                                               },
    { METADATA_MISSING,                              0, "[13.2.1.1]: Métadonnées manquantes."                                                                    },
    { METADATA_MISSING_REDIRECT_AUTOREFRESH,         0, "[13.2.1.3]: Métadonnées manquantes (redirect/auto-refresh)."                                            },
    { SKIPOVER_ASCII_ART,                            0, "[13.10.1.1]: ignore l'ascii art."                                                                       },

#if SUPPORT_CONSOLE_APP
    { TC_LABEL_COL,                                  0, "colonne"                                                                                                },
    { TC_LABEL_FILE,                                 0, "fichier"                                                                                                },
    { TC_LABEL_LANG,                                 0, "langue"                                                                                                 },
    { TC_LABEL_LEVL,                                 0, "niveau"                                                                                                 },
    { TC_LABEL_OPT,                                  0, "option"                                                                                                 },
    { TC_MAIN_ERROR_LOAD_CONFIG,                     0, "Le chargement du fichier de configuration \"%s\" a échoué, err = %d"                                    },
    { TC_OPT_ACCESS,                                 0,        
        "faire des vérifications d'accessibilité supplémentaires (<niveau> = 0, 1, 2, 3). implicitement 0 si "
        "<niveau> est manquant."
    },
    { TC_OPT_ASCII,                                  0, "utilise ISO-8859-1 pour l'entrée, US-ASCII pour la sortie"                                              },
    { TC_OPT_ASHTML,                                 0, "force le XHTML en HTML bien structuré"                                                                  },
    { TC_OPT_ASXML,                                  0, "converti le HTML en XHTML bien structuré"                                                               },
    { TC_OPT_BARE,                                   0, "enlève les guillemets à double chevron et les tirets longs."                                            },
    { TC_OPT_BIG5,                                   0, "utilise Big5 pour l'entrée et la sortie"                                                                },
    { TC_OPT_CLEAN,                                  0, "remplace les balises FONT, NOBR et CENTER par du CSS"                                                   },
    { TC_OPT_CONFIG,                                 0, "détermine les options de configuration à partir du <fichier> spécifié "                                 },
    { TC_OPT_ERRORS,                                 0, "affiche seulement les erreurs et avertissements"                                                        },
    { TC_OPT_FILE,                                   0, "écrit les erreurs et avertissements vers le <fichier> précisé "                                         },
    { TC_OPT_GDOC,                                   0, "produit une version nettoyée du html exporté par Google Docs"                                           },
    { TC_OPT_HELP,                                   0, "liste toutes les options de ligne de commande"                                                          },
    { TC_OPT_HELPCFG,                                0, "liste toutes les options de configuration"                                                              },
    { TC_OPT_HELPOPT,                                0, "Affiche une description de l'<option>"                                                                  },
    { TC_OPT_IBM858,                                 0, "utilise IBM-858 (CP850+Euro) pour l'entrée, US-ASCII pour la sortie"                                    },
    { TC_OPT_INDENT,                                 0, "indente le contenu d'un élément"                                                                        },
    { TC_OPT_ISO2022,                                0, "utilise ISO-2022 pour l'entrée et la sortie"                                                            },
    { TC_OPT_LANGUAGE,                               0,        
        "Précise le langage de sortie de Tidy pour <lang>. Ajouter '-language help' pour plus d'aide. "
        "Utiliser avant les arguments produisant des sorties pour garantir que le langage sera pris en "
        "compte, par exemple `tidy -lang fr -lang help`."
    },
    { TC_OPT_LATIN0,                                 0, "utilise ISO-8859-15 pour l'entrée, US-ASCII pour la sortie"                                             },
    { TC_OPT_LATIN1,                                 0, "utilise ISO-8859-1 pour l'entrée et la sortie"                                                          },
    { TC_OPT_MAC,                                    0, "utilise MacRoman pour l'entrée, US-ASCII pour la sortie"                                                },
    { TC_OPT_MODIFY,                                 0, "modifie le fichier original en entrée"                                                                  },
    { TC_OPT_NUMERIC,                                0, "sortie numérique plutôt qu'entités nommées"                                                             },
    { TC_OPT_OMIT,                                   0, "Omettre les tags optionnels d'ouverture et de fermeture"                                                },
    { TC_OPT_OUTPUT,                                 0, "écrit la sortie vers le fichier <file>"                                                                 },
    { TC_OPT_QUIET,                                  0, "supprime les sorties non-essentielles"                                                                  },
    { TC_OPT_RAW,                                    0, "Valeurs de sortie supérieures à 127 sans conversion en entités"                                         },
    { TC_OPT_SHIFTJIS,                               0, "utilise Shift_JIS à la fois pour l'entrée et la sortie"                                                 },
    { TC_OPT_SHOWCFG,                                0, "liste les options de configuration"                                                                     },
    { TC_OPT_UPPER,                                  0, "force les balises en lettres majuscules"                                                                },
    { TC_OPT_UTF16,                                  0, "utilise UTF-16 à la fois pour l'entrée et la sortie"                                                    },
    { TC_OPT_UTF16BE,                                0, "utilise UTF-16BE à la fois pour l'entrée et la sortie"                                                  },
    { TC_OPT_UTF16LE,                                0, "utilise UTF-16LE à la fois pour l'entrée et la sortie"                                                  },
    { TC_OPT_UTF8,                                   0, "utilise UTF-8 à la fois pour l'entrée et la sortie"                                                     },
    { TC_OPT_VERSION,                                0, "affiche la version de Tidy"                                                                             },
    { TC_OPT_WIN1252,                                0, "utilise Windows-1252 pour l'entrée, US-ASCII pour la sortie"                                            },
    { TC_OPT_WRAP,                                   0,        
        "coupe le texte à la colonne <column>. 0 est supposé si <column> est manquante. Si cette option "
        "n'est pas précisée, la valeur par défaut de l'option 'wrap' s'applique."
    },
    { TC_OPT_XML,                                    0, "précise que l'entrée est un XML bien structuré"                                                         },
    { TC_OPT_XMLCFG,                                 0, "liste toutes les options de configuration au format XML"                                                },
    { TC_OPT_XMLHELP,                                0, "liste les options de ligne de commande au format XML"                                                   },
    { TC_OPT_XMLSTRG,                                0, "sortie de toutes les chaînes Tidy au format XML"                                                        },
    { TC_OPT_XMLERRS,                                0, "constantes et chaînes de sortie d'erreur au format XML"                                                 },
    { TC_OPT_XMLOPTS,                                0, "descriptions des options de sortie au format XML"                                                       },
    { TC_STRING_CONF_HEADER,                         0, "Fichier de configuration:"                                                                              },
    { TC_STRING_CONF_NAME,                           0, "Nom"                                                                                                    },
    { TC_STRING_CONF_TYPE,                           0, "Type"                                                                                                   },
    { TC_STRING_CONF_VALUE,                          0, "Valeur courante"                                                                                        },
    { TC_STRING_OPT_NOT_DOCUMENTED,                  0, "Attention: l'option `%s' n'est pas documentée."                                                         },
    { TC_STRING_OUT_OF_MEMORY,                       0, "Mémoire insuffisante. Abandon."                                                                         },
    { TC_STRING_FATAL_ERROR,                         0, "Erreur fatale: valeur impossible pour id='%d'."                                                         },
    { TC_STRING_FILE_MANIP,                          0, "Manipulation de fichier"                                                                                },
    { TC_STRING_PROCESS_DIRECTIVES,                  0, "Directives de traitement"                                                                               },
    { TC_STRING_CHAR_ENCODING,                       0, "Encodages de caractère"                                                                                 },
    { TC_STRING_LANG_MUST_SPECIFY,                   0, "Une locale POSIX ou Windows doit être précisée."                                                        },
    { TC_STRING_LANG_NOT_FOUND,                      0, "Tidy n'a pas la langue '%s', '%s' sera utilisé à la place."                                             },
    { TC_STRING_MISC,                                0, "Divers"                                                                                                 },
    { TC_STRING_XML,                                 0, "XML"                                                                                                    },
    { TC_STRING_MUST_SPECIFY,                        0, "Un nom d'option doit être précisé."                                                                     },
    { TC_STRING_UNKNOWN_OPTION,                      0, "HTML Tidy: option inconnue: %c"                                                                         },
    { TC_STRING_UNKNOWN_OPTION_B,                    0, "HTML Tidy: option inconnue."                                                                            },
    { TC_STRING_VERS_A,                              0, "HTML Tidy pour %s version %s"                                                                           },
    { TC_STRING_VERS_B,                              0, "HTML Tidy version %s"                                                                                   },
    { TC_TXT_HELP_1,                                 0,        
        "\n"
        "%s [options...] [fichier...] [options...] [fichier...]\n"
        "Utilitaire pour nettoyer et embellir le HTML/XHTML/XML.\n"
        "\n"
        "Ceci est le HTML Tidy modernisé version %s.\n"
        "\n"
    },
    { TC_TXT_HELP_2A,                                0, "Arguments en ligne de commande de HTML Tidy pour %s:"                                                   },
    { TC_TXT_HELP_2B,                                0, "Arguments en ligne de commande de HTML Tidy:"                                                           },
    { TC_TXT_HELP_3,                                 0,        
        "\n"
        "Options de configuration de Tidy\n"
        "==========================\n"
        "Utilisez les options de configuration de Tidy comme arguments de \n"
        "ligne de commande, sous la forme «--option <valeur>\", par exemple \n"
        "\"--indent-with-tabs yes\"\n"
        "\n"
        "Pour une liste de toutes les options de configuration, utilisez \n"
        "\"-help-config\" ou consultez la page de manuel (si votre OS a la \n"
        "commande man).\n"
        "\n"
        "Si votre environnement a déclaré une variable $HTML_TIDY qui pointe \n"
        "vers un fichier de configuration, alors Tidy tentera de l'utiliser.\n"
        "\n"
        "Sur certaines plateformes, Tidy essaiera également d'utiliser une \n"
        "configuration décrite dans /etc/tidy.conf ou ~/.tidy.conf.\n"
        "\n"
        "Autre\n"
        "=====\n"
        "Pour l'entrée/sortie par défaut, utilisez stdin/stdout respectivement. \n"
        "\n"
        "Les options en lettre simple, en dehors de -f, peuvent être combinées \n"
        "comme dans: tidy -f errs.txt -imu foo.html\n"
        "\n"
        "Renseignements\n"
        "===========\n"
        "Pour plus d'informations à propos de HTML Tidy, voir\n"
        "  http://www.html-tidy.org/\n"
        "\n"
        "Pour plus d'informations sur le langage HTML, consultez les rubriques suivantes:\n"
        "\n"
        "  HTML: Édition pour les auteurs Web (de la dernière spécification HTML)\n"
        "  http://dev.w3.org/html5/spec-author-view\n"
        "\n"
    },
    { TC_TXT_HELP_CONFIG,                            0,        
        "\n"
        "Paramètres de configuration de HTML Tidy\n"
        "\n"
        "Dans un fichier, utilisez la forme:\n"
        "\n"
        "wrap: 72\n"
        "indent: no\n"
        "\n"
        "Quand il sont précisés en ligne de commande, utilisez la forme:\n"
        "\n"
        "--wrap 72 --indent no\n"
        "\n"
    },
    { TC_TXT_HELP_CONFIG_NAME,                       0, "Nom"                                                                                                    },
    { TC_TXT_HELP_CONFIG_TYPE,                       0, "Type"                                                                                                   },
    { TC_TXT_HELP_CONFIG_ALLW,                       0, "Valeurs possibles"                                                                                      },
    { TC_TXT_HELP_LANG_1,                            0,        
        "\n"
        "L'option -language (ou -lang) indique la langue que Tidy doit utiliser \n"
        "en sortie. Veuillez noter que ce n'est pas un service de traduction de \n"
        "documents, et que cela affecte uniquement les messages que Tidy \n"
        "renvoie.\n"
        "\n"
        "Lorsqu'il est utilisé depuis la ligne de commande, l'argument -language \n"
        "doit être utilisé avant des arguments qui ont un impact sur la sortie, \n"
        "sinon Tidy va produire une sortie avant de connaître la langue à utiliser.\n"
        "\n"
        "En plus des codes de langue du standard POSIX, Tidy est capable de\n"
        "comprendre les codes de langue historiques de Windows. \n"
        "Veuillez noter que cette liste indique les codes que Tidy comprend, et \n"
        "ne signifie pas que la langue est pour autant installée.\n"
        "\n"
        "La colonne de droite indique comment Tidy comprendra le nom \n"
        "Windows historique.\n"
        "\n"
    },
    { TC_TXT_HELP_LANG_2,                            0,        
        "\n"
        "Les langages suivants sont installés pour le moment dans Tidy.\n"
        "Veuillez noter qu'il n'y a pas de garantie qu'ils soient complets ; \n"
        "Seul un développeur (ou plusieurs) a commencé à ajouter le \n"
        "langage indiqué.\n"
        "\n"
    },
    { TC_TXT_HELP_LANG_3,                            0,        
        "\n"
        "Si Tidy est capable de déterminer votre locale, Tidy utilisera alors la langue \n"
        "locale automatiquement. Par exemple, les systèmes basés sur Unix utilisent \n"
        "une variable d'environnement $LANG et/ou $LC_ALL.\n"
        "Consultez la documentation de votre système d'exploitation pour plus \n"
        "d'informations. \n"
        "\n"
        "Tidy utilise pour l'instant la locale %s. \n"
        "\n"
    },
#endif /* SUPPORT_CONSOLE_APP */

    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST,                        0, NULL
    }

}};


#endif /* language_fr_h */

#ifndef language_pt_br_h
#define language_pt_br_h
/*
 * language_pt_br.h
 * Localization support for HTML Tidy.
 *
 *
 * This file is a localization file for HTML Tidy. It will have been machine
 * generated or created and/or edited by hand. Both are valid options, but
 * please help keep our localization efforts simple to maintain by maintaining
 * the structure of this file, and changing the check box below if you make
 * changes (so others know the file origin):
 *
 * [X] THIS FILE IS MACHINE GENERATED. It is a localization file for the
 *     language (and maybe region) "pt_br". The source of
 *     these strings is a gettext PO file in Tidy's source, probably called 
 *     "language_pt_br.po".
 *
 * [ ] THIS FILE WAS HAND MODIFIED. Translators, please feel to edit this file
 *     directly (and check this box). If you prefer to edit PO files then use
 *     `poconvert.rb msgunfmt language_pt_br.h` (our own
 *     conversion tool) to generate a fresh PO from this file first!
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Template Created by Jim Derry on 01/14/2016.
 *
 * Orginating PO file metadata:
 *   PO_LAST_TRANSLATOR=jderry
 *   PO_REVISION_DATE=2017-10-05 15:13:40
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_pt_br(unsigned int n) {
    /* Plural-Forms: nplurals=2; */
    return (n > 1);
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 */
static languageDefinition language_pt_br = { whichPluralForm_pt_br, {
    /***************************************
     ** This MUST be present and first. 
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,                                 0, "pt_br"
    },
    { TidyAccessibilityCheckLevel,                   0,        
        "Esta opção especifica o nível de verificação de acessibilidade, se houver, "
        "que Tidy deve executar. <br/>Nível <var>0 (Tidy Classic)</var> é equivalente "
        "à verificação de acessibilidade do Tidy Classic.<br/> Para obter mais "
        "informações sobre a verificação de acessibilidade do Tidy, visite <a href=\""
        "http://www.html-tidy.org/accessibility/\"> Página de acessibilidade do "
        "Tidy</a>. "
    },
    { TidyAltText,                                   0,        
        "Esta opção especifica o texto padrão <code>alt=</code> que o Tidy usa para "
        "atributos <code>&lt;img&gt;</code> quando o atributo <code>alt=</code> está "
        "faltando. <br/>Use com cuidado, pois é sua responsabilidade tornar seus "
        "documentos acessíveis para pessoas que não conseguem ver as imagens. "
    },
    { TidyAnchorAsName,                              0,        
        "Esta opção controla a exclusão ou adição do atributo <code>name</code> em "
        "elementos onde ele pode servir como âncora. <br/>Se configurado para "
        "<var>yes</var>, um atributo <code>name</code>, se não já existir, é "
        "adicionado ao longo de um atributo <code>id</code> existente se o DTD o "
        "permitir. <br/>Se configurado para <var>no</var> qualquer atributo de nome "
        "existente é removido se um atributo <code>id</code> existir ou tenha sido "
        "adicionado. "
    },
    { TidyAsciiChars,                                0,        
        "Pode ser usado para modificar o comportamento da opção <code>clean</code> "
        "quando configurado para <var>yes</var>. <br/>Se configurado para "
        "<var>yes</var> ao usar <code>clean</code>, <code>&amp;emdash;</code>, "
        "<code>&amp;rdquo;</code>, e outras entidades de caracteres nomeadas são "
        "rebaixadas para os equivalentes ASCII mais próximos. "
    },
    { TidyBlockTags,                                 0,        
        "Esta opção especifica novas tags de nível de bloco. Esta opção possui uma "
        "lista separada por vírgulas ou espaço de nomes de tags. <br/>A menos que "
        "você declare novas tags, o Tidy se recusará a gerar um arquivo arrumado se a "
        "entrada incluir tags anteriormente desconhecidas. <br/>Note que você não "
        "pode alterar o modelo de conteúdo para elementos como "
        "<code>&lt;table&gt;</code>, <code>&lt;ul&gt;</code>, <code>&lt;ol&gt;</code> "
        "e <code>&lt;dl&gt;</code>. <br/>Esta opção é ignorada no modo XML. "
    },
    { TidyBodyOnly,                                  0,        
        "Esta opção especifica se o Tidy deve imprimir apenas o conteúdo da tag body "
        "como um fragmento HTML. <br/>Se configurado para <var>auto</var>, isso é "
        "realizado somente se a tag body tiver sido inferida. <br/>Útil para "
        "incorporar páginas inteiras existentes como uma porção de outra página. <br/>"
        "Esta opção não tem efeito se a saída XML for solicitada. "
    },
    { TidyBreakBeforeBR,                             0,        
        "Esta opção especifica se o Tidy deve emitir uma quebra de linha antes de "
        "cada elemento <code>&lt;br&gt;</code>. "
    },
    { TidyCharEncoding,                              0,        
        "Esta opção especifica a codificação de caracteres que o Tidy usa tanto para "
        "a entrada como para a saída. <br/>Para <var>ascii</var>, o Tidy aceitará "
        "valores de caracteres Latin-1 (ISO-8859-1), mas usará entidades para todos "
        "os caracteres cujo valor seja &gt;127. <br/>Para <var>raw</var>, o Tidy "
        "emitirá valores acima de 127 sem traduzi-los em entidades. <br/>Para "
        "<var>latin1</var>, os caracteres acima de 255 serão escritos como entidades. "
        "<br/>Para <var>utf8</var>, Tidy presume que tanto a entrada como a saída são "
        "codificadas como UTF-8. <br/>Você pode usar <var>iso2022</var> para arquivos "
        "codificados usando a família de codificações ISO-2022, p.ex. ISO-2022-JP. "
        "<br/> Para <var>mac</var> e <var>win1252</var>, o Tidy aceitará valores de "
        "caracteres específicos do fornecedor, mas usará entidades para todos os "
        "caracteres cujo valor seja &gt;127. <br/>Para codificações sem suporte, use "
        "um utilitário externo para converter de e para UTF-8. "
    },
    { TidyCoerceEndTags,                             0,        
        "Esta opção especifica se o Tidy deve coagir uma tag de início em uma tag de "
        "fim nos casos em que parece que uma tag de fim provavelmente foi projetada; "
        "por exemplo, dado <br/><code>&lt;span&gt;foo &lt;b&gt;bar&lt;b&gt; "
        "baz&lt;/span&gt;</code>, <br/>Tidy vai emitir <br/><code>&lt;span&gt;foo "
        "&lt;b&gt;bar&lt;/b&gt; baz&lt;/span&gt;</code> "
    },
    { TidyCSSPrefix,                                 0,        
        "Esta opção especifica o prefixo que o Tidy usa para regras de estilo. <br/>Por padrão, <var>c</"
        "var> será usado. "
    },
    { TidyDecorateInferredUL,                        0,        
        "Esta opção especifica se o Tidy deve decorar elementos inferidos "
        "<code>&lt;ul&gt;</code> com algumas marcações CSS para evitar recuo para a "
        "direita. "
    },
    { TidyDoctype,                                   0,        
        "Esta opção especifica a declaração DOCTYPE gerada pelo Tidy. <br/>Se "
        "configurado para <var>omit</var>, a saída não conterá uma declaração "
        "DOCTYPE. Note que isso também implica que <code>numeric-entity</code> esteja "
        "definido para <var>yes</var>. <br/>Se configurado para <var>html5</var>, o "
        "DOCTYPE é configurado para <code>&lt;!DOCTYPE html&gt;</code>. <br/>Se "
        "configurado para <var>auto</var> (o padrão), Tidy usará um palpite educado "
        "com base no conteúdo do documento. <br/>Se configurado para <var>strict</var>"
        ", o Tidy configurará o DOCTYPE para o DTD estrito HTML4 ou XHTML1. <br/>Se "
        "configurado para <var>loose</var>, o DOCTYPE é definido como o DTD loose "
        "(transicional) HTML4 ou XHTML1. <br/>Alternativamente, você pode fornecer "
        "uma string para o identificador público formal (FPI). <br/>Por exemplo: "
        "<br/><code>doctype: \"-//ACME//DTD HTML 3.14159//EN\"</code><br/>Se você "
        "especificar o FPI para um documento XHTML, o Tidy irá definir o "
        "identificador do sistema em uma string vazia. Para um documento HTML, a Tidy "
        "adiciona um identificador de sistema somente se um já estivesse presente "
        "para preservar o modo de processamento de alguns navegadores. Tidy deixa o "
        "DOCTYPE para documentos genéricos XML inalterados. <br/>Esta opção não "
        "oferece uma validação da conformidade do documento. "
    },
    { TidyDropEmptyElems,                            0, "Esta opção especifica se Tidy deve descartar elementos vazios. "                                 },
    { TidyDropEmptyParas,                            0, "Esta opção especifica se Tidy deve descartar parágrafos vazios. "                                },
    { TidyDropPropAttrs,                             0,        
        "Esta opção especifica se o Tidy deve remover os atributos de propriedade, "
        "como os atributos de ligação de dados da Microsoft. Além disso, os atributos "
        "que não são permitidos na versão de saída do HTML serão descartados se "
        "usados com <code>strict-tags-attributes</code>. "
    },
    { TidyDuplicateAttrs,                            0,        
        "Esta opção especifica se o Tidy deve manter o primeiro ou último atributo, "
        "se um atributo estiver repetido, p.ex. possui dois atributos "
        "<code>align</code>. "
    },
    { TidyEmacs,                                     0,        
        "Esta opção especifica se o Tidy deve alterar o formato para relatar erros e "
        "avisos para um formato que é analisado mais facilmente pelo GNU Emacs. "
    },
    { TidyEmptyTags,                                 0,        
        "Esta opção especifica novas tags em-linha vazias. Esta opção possui uma "
        "lista separada por espaço ou vírgulas de nomes de tags. <br/>A menos que "
        "você declare novas tags, o Tidy se recusará a gerar um arquivo arrumado se a "
        "entrada incluir tags anteriormente desconhecidas. <br/>Lembre-se de declarar "
        "tags vazias como em linha ou bloqueio. <br/>Esta opção é ignorada no modo "
        "XML. "
    },
    { TidyEncloseBlockText,                          0,        
        "Esta opção especifica se Tidy deve inserir um elemento <code>&lt;p&gt;</code>"
        " para incluir qualquer texto que encontre em qualquer elemento que permita o "
        "conteúdo misto para HTML transicional mas não HTML estrito. "
    },
    { TidyEncloseBodyText,                           0,        
        "Esta opção especifica se o Tidy deve incluir qualquer texto encontrado no "
        "elemento do corpo dentro de um elemento <code>&lt;p&gt;</code>. <br/>Isso é "
        "útil quando você deseja usar o HTML existente e usá-lo com uma folha de "
        "estilo. "
    },
    { TidyErrFile,                                   0,        
        "Esta opção especifica o arquivo de erro que o Tidy usa para erros e avisos. "
        "Normalmente, erros e avisos são emitidos para <code>stderr</code>. "
    },
    { TidyEscapeCdata,                               0,        
        "Esta opção especifica se o Tidy deve converter seções "
        "<code>&lt;![CDATA[]]&gt;</code> em texto normal. "
    },
    { TidyEscapeScripts,                             0,        
        "Esta opção faz com que itens que se parecem com tags de fechamento, como <code>&lt;/g</code> "
        "sejam escapadas para <code>&lt;\\/g</code>. Defina esta opção para <var>no</var> se você não "
        "deseja isso."
    },
    { TidyFixBackslash,                              0,        
        "Esta opção especifica se o Tidy deve substituir caracteres de barra "
        "invertida <code>\\</code> em URLs com barras <code>/</code>. "
    },
    { TidyFixComments,                               0,        
        "Esta opção especifica se Tidy deve substituir hífenes inesperados com "
        "caracteres <code>=</code> quando se trata de hífenes adjacentes. <br/>O "
        "padrão é <var>yes</var>. <br/>Esta opção é fornecida para usuários do Cold "
        "Fusion que usam a sintaxe do comentário: <code>&lt;!--- ---&gt;</code>. "
    },
    { TidyFixUri,                                    0,        
        "Esta opção especifica se o Tidy deve verificar valores de atributos que "
        "carregam URIs para caracteres ilegais e, se tal for encontrado, escapa-os "
        "conforme o HTML4 recomenda. "
    },
    { TidyForceOutput,                               0,        
        "Esta opção especifica se o Tidy deve produzir saída, mesmo se forem "
        "encontrados erros. <br/>Use esta opção com cuidado; Se o Tidy relatar um "
        "erro, significa que o Tidy não conseguiu corrigir o erro (ou não sabe como), "
        "então a saída resultante pode não refletir sua intenção. "
    },
    { TidyGDocClean,                                 0,        
        "Esta opção especifica se o Tidy deve habilitar comportamento específico para "
        "limpeza de HTML exportado do Google Docs. "
    },
    { TidyHideComments,                              0, "Esta opção especifica se Tidy deve imprimir os comentários. "                                    },
    { TidyHtmlOut,                                   0,        
        "Esta opção especifica se o Tidy deve gerar uma impressão amigável, "
        "escrevendo como HTML. "
    },
    { TidyInCharEncoding,                            0,        
        "Esta opção especifica a codificação de caracteres que o Tidy usa para a "
        "entrada. Veja <code>char-encoding</code> para mais informações. "
    },
    { TidyIndentAttributes,                          0,        
        "Esta opção especifica se o Tidy deve começar cada atributo em uma nova "
        "linha. "
    },
    { TidyIndentCdata,                               0,        
        "Esta opção especifica se o Tidy deve aplicar recuo nas seções "
        "<code>&lt;![CDATA[]]&gt;</code>. "
    },
    { TidyIndentContent,                             0,        
        "Esta opção especifica se Tidy deve aplicar recuo nas tags de nível de bloco. "
        "<br/>Se configurado para <var>auto</var>, Tidy decidirá se aplica ou não "
        "recuo no conteúdo das tags, como <code>&lt;title&gt;</code>, "
        "<code>&lt;h1&gt;</code>-<code>&lt;h6&gt;</code>, <code>&lt;li&gt;</code>, "
        "<code>&lt;td&gt;</code> ou <code>&lt;p&gt;</code> com base no conteúdo, "
        "incluindo um elemento de nível de bloco. <br/>Configurar <code>indent</code> "
        "para <var>yes</var> pode expor erros de layout em alguns navegadores. <br/>"
        "Use a opção <code>indent-spaces</code> para controlar o número de espaços ou "
        "tabulações de saída por nível de recuo e <code>indent-with-tabs</code> para "
        "especificar se espaços ou tabulações são usados. "
    },
    { TidyIndentSpaces,                              0,        
        "Esta opção especifica o número de espaços ou guias que o Tidy usa para "
        "recuar o conteúdo quando <code>indent</code> está habilitado. <br/>Note que "
        "o valor padrão para esta opção depende do valor de <code>indent-with-"
        "tabs</code> (veja também). "
    },
    { TidyInlineTags,                                0,        
        "Esta opção especifica novas tags em-linha não vazias. Esta opção possui uma "
        "lista separada por espaço ou vírgulas de nomes de tags. <br/>A menos que "
        "você declare novas tags, o Tidy se recusará a gerar um arquivo arrumado se a "
        "entrada incluir tags anteriormente desconhecidas. <br/>Esta opção é ignorada "
        "no modo XML. "
    },
    { TidyJoinClasses,                               0,        
        "Esta opção especifica se o Tidy deve combinar os nomes das classes para "
        "gerar um nome de classe único e novo se várias atribuições de classe forem "
        "detectadas em um elemento. "
    },
    { TidyJoinStyles,                                0,        
        "Esta opção especifica se o Tidy deve combinar os estilos para gerar um "
        "estilo único e novo se vários valores de estilo forem detectados em um "
        "elemento. "
    },
    { TidyKeepFileTimes,                             0,        
        "Esta opção especifica se o Tidy deve manter o tempo de modificação original "
        "dos arquivos que o Tidy modifica no local. <br/>Configurar a opção para "
        "<var>yes</var> permite arrumar arquivos sem alterar a data de modificação do "
        "arquivo, o que pode ser útil com determinadas ferramentas que usam a data de "
        "modificação para coisas como a implantação automática do servidor. <br/>Note "
        "que não há suporte a este recurso em algumas plataformas. "
    },
    { TidyLiteralAttribs,                            0,        
        "Esta opção especifica como o Tidy lida com caracteres de espaço em branco "
        "dentro de valores de atributos. <br/>Se o valor for <var>no</var>, Tidy "
        "normaliza os valores dos atributos substituindo qualquer nova linha ou "
        "tabulação por um único espaço, além de substituir qualquer espaço contíguo "
        "em espaço único. <br/>Para forçar o Tidy a preservar os valores literais "
        "originais de todos os atributos e garantir que os espaços em branco dentro "
        "dos valores de atributo sejam passados inalterados através, defina esta "
        "opção como <var>yes</var>. "
    },
    { TidyLogicalEmphasis,                           0,        
        "Esta opção especifica se o Tidy deve substitui qualquer ocorrência de "
        "<code>&lt;i&gt;</code> com <code>&lt;em&gt;</code> e qualquer ocorrência de "
        "<code>&lt;b&gt;</code> com <code>&lt;strong&gt;</code>. Quaisquer atributos "
        "são preservados inalterados. <br/>Esta opção pode ser definida "
        "independentemente da opção <code>clean</code>. "
    },
    { TidyLowerLiterals,                             0,        
        "Esta opção especifica se o Tidy deve converter o valor de um atributo que "
        "leva uma lista de valores predefinidos para minúsculas. <br/>Isto é "
        "necessário para documentos XHTML. "
    },
    { TidyMakeBare,                                  0,        
        "Esta opção especifica se o Tidy deve retirar o HTML específico da Microsoft "
        "de documentos do Word 2000 e exibir espaços em vez de espaços rígidos (nbsp) "
        "nos quais eles existam na entrada. "
    },
    { TidyMakeClean,                                 0,        
        "Esta opção especifica se o Tidy deve executar a limpeza de algumas tags de "
        "apresentação legadas (atualmente <code>&lt;i&gt;</code>, "
        "<code>&lt;b&gt;</code>, <code>&lt;center&gt;</code> quando incluídas nas "
        "tags em-linha apropriadas e <code>&lt;font&gt;</code>). Se configurado para "
        "<var>yes</var>, as tags legadas serão substituídas por tags CSS "
        "<code>&lt;style&gt;</code> e marcação estrutural conforme apropriado. "
    },
    { TidyMark,                                      0,        
        "Esta opção especifica se o Tidy deve adicionar um elemento <code>meta</code> "
        "ao cabeçalho do documento para indicar que o documento foi arrumado. <br/>"
        "Tidy não adicionará um elemento meta se um já estiver presente. "
    },
    { TidyMergeDivs,                                 0,        
        "Esta opção pode ser usada para modificar o comportamento de "
        "<code>clean</code> quando configurado para <var>yes</var>. <br/>Esta opção "
        "especifica se o Tidy deve mesclar <code>&lt;div&gt;</code> aninhados, como "
        "<code>&lt;div&gt;&lt;div&gt;...&lt;/div&gt;&lt;/div&gt;</code>. <br/>Se "
        "configurado para <var>auto</var>, os atributos do <code>&lt;div&gt;</code> "
        "internos são movidos para o externo. <code>&lt;div&gt;</code> aninhados com "
        "os atributos <code>id</code> <em>não</em> são mesclados. <br/>Se configurado "
        "para <var>yes</var>, os atributos de <code>&lt;div&gt;</code> interno são "
        "descartados com a exceção de <code>class</code> e <code>style</code>. "
    },
    { TidyMergeEmphasis,                             0,        
        "Esta opção especifica se o Tidy deve mesclar elementos <code>&lt;b&gt;</code>"
        " e <code>&lt;i&gt;</code> aninhados; por exemplo, para o caso de "
        "<br/><code>&lt;b class=\"rtop-2\"&gt;foo &lt;b class=\"r2-2\""
        "&gt;bar&lt;/b&gt; baz&lt;/b&gt;</code>, <br/>Tidy vai emitir <code>&lt;b "
        "class=\"rtop-2\"&gt;foo bar baz&lt;/b&gt;</code>. "
    },
    { TidyMergeSpans,                                0,        
        "Esta opção pode ser usada para modificar o comportamento de "
        "<code>clean</code> quando configurado para <var>yes</var>. <br/>Esta opção "
        "especifica se o Tidy deve mesclar <code>&lt;span&gt;</code> aninhados como "
        "<code>&lt;span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;</code>. <br/>O "
        "algoritmo é idêntico àquele usado por <code>merge-divs</code>. "
    },
    { TidyNCR,                                       0,        
        "Esta opção especifica se o Tidy deve permitir referências de caracteres "
        "numéricos. "
    },
    { TidyNewline,                                   0,        
        "O padrão é apropriado para a plataforma atual. <br/>Geralmente, CRLF no PC-"
        "DOS, Windows e OS/2; '\r' no Mac OS Clássico; e '\n' nos demais (Linux, Mac OS X "
        "e Unix). "
    },
    { TidyNumEntities,                               0,        
        "Esta opção especifica se o Tidy deve produzir entidades diferentes das "
        "entidades HTML integradas (<code>&amp;amp;</code>, <code>&amp;lt;</code>, "
        "<code>&amp;gt;</code> e <code>&amp;quot;</code>) no formulário numérico em "
        "vez do formulário nomeado. <br/>Somente são usadas entidades compatíveis com "
        "a declaração DOCTYPE gerada. <br/>As entidades que podem ser representadas "
        "na codificação de saída são traduzidas correspondentemente. "
    },
    { TidyOmitOptionalTags,                          0,        
        "Esta opção especifica se o Tidy deve omitir tags de início e de fim "
        "opcionais ao gerar saída. <br/>Configurar essa opção causa todas as tags "
        "para os elementos <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code> e "
        "<code>&lt;body&gt;</code> serem omitidos da saída, assim como tags de saída "
        "como <code>&lt;/p&gt;</code>, <code>&lt;/li&gt;</code>, "
        "<code>&lt;/dt&gt;</code>, <code>&lt;/dd&gt;</code>, "
        "<code>&lt;/option&gt;</code>, <code>&lt;/tr&gt;</code>, "
        "<code>&lt;/td&gt;</code> e <code>&lt;/th&gt;</code>. <br/>Essa opção é "
        "ignorada para saída XML. "
    },
    { TidyOutCharEncoding,                           0,        
        "Esta opção especifica a codificação de caracteres que o Tidy usa para a saída. <br/>Note que "
        "isso só pode ser diferente de <code>input-encoding</code> para codificações latinas "
        "(<var>ascii</var>, <var>latin0</var>, <var>latin1</var>, <var>mac</var>, <var>win1252</var>, "
        "<var>ibm858</var>). <br/>Veja <code>char-encoding</code> para mais informações"
    },
    { TidyOutFile,                                   0,        
        "Essa opção especifica o arquivo de saída que o Tidy usa para marcação. "
        "Normalmente, a marcação é escrita para <code>stdout</code>. "
    },
    { TidyOutputBOM,                                 0,        
        "Esta opção especifica se o Tidy deve escrever um caractere Unicode de marca "
        "de ordem de byte (BOM, também conhecido como Zero Width No Break Break, tem "
        "valor de U+FEFF) no início da saída, e aplica-se apenas a codificações de "
        "saída UTF-8 e UTF-16. <br/>Se configurado para <var>auto</var>, esta opção "
        "faz com que Tidy escreva um BOM para a saída somente se um BOM estiver "
        "presente no início da entrada. <br/>Um BOM está sempre escrita para saída "
        "XML/XHTML usando codificações de saída UTF-16. "
    },
    { TidyPPrintTabs,                                0,        
        "Esta opção especifica se o Tidy deve aplicar recuo com tabulações em vez de "
        "espaços, presumindo que <code>indent</code> seja <var>yes</var>. <br/>Defina-"
        "o para <var>yes</var> para recuar usando tabulações em vez dos espaços "
        "padrão. <br/>Use a opção <code>indent-spaces</code> para controlar o número "
        "de saídas de tabulação por nível de recuo. Note que quando <code>indent-with-"
        "tabs</code> está habilitado, o valor padrão de <code>indent-spaces</code> é "
        "reiniciado para <var>1</var>. <br/>Note que <code>tab-size</code> controla a "
        "conversão de tabulações de entrada em espaços. Coloque-o em zero para reter "
        "as tabulações de entrada. "
    },
    { TidyPreserveEntities,                          0,        
        "Esta opção especifica se o Tidy deve preservar entidades bem-formadas como "
        "localizado na entrada. "
    },
    { TidyPreTags,                                   0,        
        "Esta opção especifica novas tags que devem ser processadas exatamente da "
        "mesma forma que o elemento <code>&lt;pre&gt;</code> de HTML. Esta opção "
        "possui uma lista separada por vírgulas ou espaços de nomes de tag. <br/>A "
        "menos que você declare novas tags, o Tidy se recusará a gerar um arquivo "
        "arrumado se a entrada incluir tags anteriormente desconhecidas. <br/>Note "
        "que você ainda não pode adicionar novos elementos CDATA. <br/>Esta opção é "
        "ignorada no modo XML. "
    },
    { TidyPunctWrap,                                 0,        
        "Essa opção especifica se o Tidy deve quebrar linha após alguns Unicode ou "
        "caracteres de pontuação chineses. "
    },
    { TidyQuiet,                                     0,        
        "Essa opção especifica se o Tidy deve emitir o resumo dos números de erros e "
        "avisos, ou as mensagens de boas-vidas ou informacionais. "
    },
    { TidyQuoteAmpersand,                            0,        
        "Essa opção especifica se o Tidy deve emitir caracteres <code>&amp;</code> "
        "sem adornos como <code>&amp;amp;</code>. "
    },
    { TidyQuoteMarks,                                0,        
        "Esta opção especifica se o Tidy deve enviar caracteres <code>&quot;</code> "
        "como <code>&quot;</code> como é preferido por alguns ambientes de edição. "
        "<br/>O caractere do apóstrofe <code>'</code> é escrito como "
        "<code>&amp;#39;</code> porque muitos navegadores web ainda não oferecem "
        "suporte a <code>&amp;apos;</code>. "
    },
    { TidyQuoteNbsp,                                 0,        
        "Esta opção especifica se o Tidy deve produzir caracteres de espaço rígido "
        "como entidades, em vez de como o caractere Unicode de valor 160 (decimal). "
    },
    { TidyReplaceColor,                              0,        
        "Esta opção especifica se o Tidy deve substituir os valores numéricos nos atributos de cor com "
        "nomes de cor HTML/XHTML onde definido, p.ex. substituir <code>#ffffff</code> com <code>white</"
        "code>. "
    },
    { TidyShowErrors,                                0,        
        "Esta opção especifica o número que o Tidy usa para determinar se outros "
        "erros devem ser exibidos. Se configurado para <var>0</var>, nenhum erro será "
        "mostrado. "
    },
    { TidyShowInfo,                                  0,        
        "Esta opção especifica se o Tidy deve exibir mensagens de nível "
        "informacional. "
    },
    { TidyShowMarkup,                                0,        
        "Esta opção especifica se o Tidy deve gerar uma versão de impressão amigável "
        "da marcação. Note que o Tidy não gerará uma versão de impressão amigável se "
        "encontrar erros significativos (veja <code>force-output</code>). "
    },
    { TidyShowWarnings,                              0,        
        "Esta opção especifica se o Tidy deve suprimir avisos. Isso pode ser útil "
        "quando alguns erros estão ocultos em uma agitação de avisos. "
    },
    { TidySkipNested,                                0,        
        "Esta opção especifica que o Tidy deve pular tags aninhadas ao analisar "
        "script e dados de estilo. "
    },
    { TidySortAttributes,                            0,        
        "Esta opção especifica que o Tidy deve ordenar atributos dentro de um "
        "elemento usando o algoritmo de ordenação especificado. Se configurado para "
        "<var>alpha</var>, o algoritmo é uma ordenação alfabética ascendente. "
    },
    { TidyStrictTagsAttr,                            0,        
        "Esta opção garante que tags e atributos sejam aplicáveis à versão do HTML "
        "que o Tidy emite. Quando definido para <var>yes</var> e o tipo de documento "
        "de saída é um doctype estrito, então o Tidy informará os erros. Se o tipo de "
        "documento de saída for um tipo de documento loose ou transicional, o Tidy "
        "informará os avisos. <br/>Além disso, se <code>drop-proprietary-"
        "attributes</code> estiver habilitado, os atributos não aplicáveis também "
        "serão descartados. <br/>Quando configurado para <var>no</var>, essas "
        "verificações não são executadas. "
    },
    { TidyTabSize,                                   0,        
        "Esta opção especifica o número de colunas que o Tidy usa entre paradas de "
        "tabulação sucessivas. Ela é usada para mapear tabulações para espaços ao ler "
        "a entrada. "
    },
    { TidyUpperCaseAttrs,                            0,        
        "Esta opção especifica se o Tidy deve produzir nomes de atributo em "
        "maiúsculo. <br/>Quando configurado para <var>no</var>, os nomes dos "
        "atributos serão escritos em minúsculas. Especificar <var>yes</var> exibirá "
        "nomes de atributos em maiúsculas e <var>preserve</var> pode ser usado para "
        "deixar nomes de atributos intactos. <br/>Ao usar a entrada XML, o "
        "maiusculização original é sempre preservada. "
    },
    { TidyUpperCaseTags,                             0,        
        "Esta opção especifica se o Tidy deve emitir nomes de tags em maiúsculo. <br/>"
        "O padrão é <var>no</var>, o que resulta em nomes de tags minúsculos, exceto "
        "para entrada XML na qual a maiusculização original é preservada. "
    },
    { TidyUseCustomTags,                             0,        
        "Esta opção permite o uso de tags para elementos personalizados autônomos, "
        "p.ex. &lt;flag-icon&gt; com Tidy. As tags personalizadas são desativadas se "
        "esse valor for <var>no</var>. Outras configurações - <var>blocklevel</var>, "
        "<var>empty</var>, <var>inline</var> e <var>pre</var> tratarão <em>todas</em> "
        "as tags personalizadas detectadas em conformidade. <br/>O uso de <code>new-"
        "blocklevel-tags</code>, <code>new-empty-tags</code>, <code>new-inline-"
        "tags</code> ou <code>new-pre-tags</code> substituirá o tratamento de tags "
        "personalizadas por esta opção de configuração. Isso pode ser útil se você "
        "tiver diferentes tipos de tags personalizadas. <br/>Quando habilitado, essas "
        "tags são determinadas durante o processamento do documento usando tags de "
        "abertura; As tags de fechamento de correspondência serão reconhecidas de "
        "acordo, e as tags de fechamento desconhecidas serão descartadas. "
    },
    { TidyVertSpace,                                 0,        
        "Esta opção especifica se o Tidy deve adicionar algumas linhas vazias extras para legibilidade. "
        "<br/>O padrão é <var>no</var>. <br/>Se configurado para <var>auto</var>, Tidy vai eliminar "
        "quase todos os caracteres de nova linha."
    },
    { TidyWarnPropAttrs,                             0, "Essa opção especifica se o Tidy deve avisar sobre atributos proprietários."                      },
    { TidyWord2000,                                  0,        
        "Esta opção especifica se o Tidy deve se esforçar duro para tirar todas as "
        "coisas excedentes que o Microsoft Word 2000 insere quando você salva os "
        "documentos do Word como \"páginas web\". Não manipula imagens embutidas ou "
        "VML. <br/>Você deve considerar usar o Word \"Salvar Como: Página da Web, "
        "Filtrada\". "
    },
    { TidyWrapAsp,                                   0,        
        "Essa opção especifica se o Tidy deve quebrar linha de textos contidos em "
        "pseudoelementos do ASP, que se parecem com: <code>&lt;% ... %&gt;</code>. "
    },
    { TidyWrapAttVals,                               0,        
        "Esta opção especifica se Tidy deve incluir valores de atributos de linha, o "
        "que significa que, se o valor de um atributo faz com que uma linha exceda a "
        "largura especificada por <code>wrap</code>, Tidy irá adicionar uma ou mais "
        "quebras de linha ao valor, fazendo com que ele seja embrulhado em várias "
        "linhas. <br/>Note que esta opção pode ser definida independentemente de <code"
        ">wrap-script-literals</code>. Por padrão, o Tidy substitui qualquer nova "
        "linha ou tabulação com um único espaço e substitui qualquer sequência de "
        "espaços em branco com um único espaço. <br/>Para forçar a Tidy a preservar "
        "os valores literais originais de todos os atributos e garantir que os "
        "caracteres de espaço em branco nos valores de atributos sejam passados "
        "através de alterações, configure <code>literal-attributes</code> para "
        "<var>yes</var>. "
    },
    { TidyWrapJste,                                  0,        
        "Essa opção especifica se o Tidy deve quebrar linha de textos contidos em "
        "pseudoelementos do JSTE, que se parecem com: <code>&lt;# ... #&gt;</code>. "
    },
    { TidyWrapLen,                                   0,        
        "Esta opção especifica a margem direita que o Tidy usa para quebra de linha. "
        "<br/>Tidy tenta quebrar linhas para que não excedam esse comprimento. <br/>"
        "Defina <code>wrap</code> para <var>0</var> (zero) se desejar desativar a "
        "quebra de linha. "
    },
    { TidyWrapPhp,                                   0,        
        "Essa opção especifica se o Tidy deve quebrar linha de textos contidos em "
        "pseudoelementos do PHP, que se parecem com: <code>&lt;?php ... ?&gt;</code>. "
    },
    { TidyWrapScriptlets,                            0,        
        "Esta opção especifica se Tidy deve efetuar quebra de linha em string "
        "literais que aparecem em atributos de script. <br/>Tidy efetua essa quebra "
        "em string literais de scripts longos inserindo um caractere de barra "
        "invertida antes da quebra de linha. "
    },
    { TidyWrapSection,                               0,        
        "Essa opção especifica se o Tidy deve efetuar quebra de linha de textos "
        "contidos em tags de seção <code>&lt;![ ... ]&gt;</code>. "
    },
    { TidyWriteBack,                                 0,        
        "Esta opção especifica se o Tidy deve escrever novamente a marcação arrumada "
        "para o mesmo arquivo que lê. <br/> É aconselhável manter cópias de arquivos "
        "importantes antes de ordená-los, como em ocasiões raras, o resultado pode "
        "não ser o que você espera. "
    },
    { TidyXhtmlOut,                                  0,        
        "Esta opção especifica se o Tidy deve gerar uma impressão amigável, "
        "escrevendo como HTML extensível. <br/>Esta opção faz com que o Tidy "
        "configure o DOCTYPE e o espaço de nomes padrão conforme apropriado para "
        "XHTML e use o valor corrigido no resultado, independentemente de outras "
        "fontes. <br/> Para XHTML, as entidades podem ser escritas como entidades "
        "nomeadas ou numéricas de acordo com a configuração de <code>numeric-"
        "entities</code>. <br/>A maiusculização original de tags e atributos será "
        "preservada, independentemente de outras opções. "
    },
    { TidyXmlDecl,                                   0,        
        "Esta opção especifica se o Tidy deve adicionar a declaração XML ao enviar "
        "XML ou XHTML. <br/>Note que, se a entrada já incluir uma declaração "
        "<code>&lt;?xml ... ?&gt;</code>, esta opção será ignorada. <br/>Se a "
        "codificação para a saída for diferente de <var>ascii</var>, uma das "
        "codificações <var>utf*</var> ou de <var>raw</var>, então a declaração é "
        "sempre adicionado conforme exigido pelo padrão XML. "
    },
    { TidyXmlOut,                                    0,        
        "Esta opção especifica se o Tidy deve emitir impressão amigável, escrevendo-o "
        "como XML bem formado. <br/>Todas as entidades não definidas no XML 1.0 serão "
        "escritas como entidades numéricas para permitir que elas sejam analisadas "
        "por um analisador XML. <br/>A maiusculização original de tags e atributos "
        "será preservada, independentemente de outras opções. "
    },
    { TidyXmlPIs,                                    0,        
        "Esta opção especifica se o Tidy deve alterar a análise das instruções de "
        "processamento para exigir <code>?&gt;</code> como o terminador, em vez de "
        "<code>&gt;</code>. <br/>Esta opção é configurada automaticamente se a "
        "entrada for um XML. "
    },
    { TidyXmlSpace,                                  0,        
        "Esta opção especifica se o Tidy deve adicionar <code>xml:space=\"preserve\"</code> para "
        "elementos tais como <code>&lt;pre&gt;</code>, <code>&lt;style&gt;</code> e <code>&lt;script&gt;"
        "</code> ao gerar o XML. <br/>Isso é necessário se o espaço em branco em tais elementos deve ser "
        "analisado apropriadamente sem ter acesso ao DTD. "
    },
    { TidyXmlTags,                                   0,        
        "Esta opção especifica se o Tidy deve usar o analisador XML em vez do "
        "analisador HTML de correção de erro. "
    },
    { TidyMetaCharset,                               0,        
        "Esta opção, quando ativada, adiciona um elemento <code>&lt;meta&gt;</code> e "
        "define o atributo <code>charset</code> para a codificação do documento. "
        "Configure esta opção para <var>yes</var> para habilitá-lo. "
    },
    { TidyShowMetaChange,                            0,        
        "Esta opção habilita uma mensagem sempre que o Tidy alterar o atributo "
        "<code>content</code> de uma declaração de meta conjunto de caracteres para "
        "coincidir com a codificação do documento. Defina esta opção para "
        "<var>yes</var> para habilitá-lo. "
    },
    { TidyStyleTags,                                 0,        
        "Esta opção especifica se o Tidy deve mover todas as tags de estilo para o "
        "cabeçalho do documento. "
    },
    { TidyWarning,                                   0, "Acesso: "                                                                                        },
    { TidyAccess,                                    0, "Acesso: "                                                                                        },
    { TidyError,                                     0, "Erro: "                                                                                          },
    { TidyBadDocument,                               0, "Documento: "                                                                                     },
    { TidyFatal,                                     0, "Pânico: "                                                                                        },
    { TidyDialogueSummary,                           0, "Resumo: "                                                                                        },
    { TidyDialogueInfo,                              0, "Informação: "                                                                                    },
    { TidyDialogueFootnote,                          0, "Nota de rodapé: "                                                                                },
    { LINE_COLUMN_STRING,                            0, "linha %d coluna %d - "                                                                           },
    { STRING_DISCARDING,                             0, "descartando"                                                                                     },
    { STRING_ERROR_COUNT_ERROR,                      0, "erro"                                                                                            },
    { STRING_ERROR_COUNT_ERROR,                      1, "erros"                                                                                           },
    { STRING_ERROR_COUNT_WARNING,                    0, "aviso"                                                                                           },
    { STRING_ERROR_COUNT_WARNING,                    1, "avisos"                                                                                          },
    { STRING_HELLO_ACCESS,                           0,        
        "\n"
        "Verificações de acessibilidade:\n"
    },
    { STRING_HTML_PROPRIETARY,                       0, "Proprietário HTML"                                                                               },
    { STRING_XML_DECLARATION,                        0, "declaração XML"                                                                                  },
    { STRING_PLAIN_TEXT,                             0, "texto simples"                                                                                   },
    { STRING_REPLACING,                              0, "substituindo"                                                                                    },
    { STRING_SPECIFIED,                              0, "especificada"                                                                                    },
    { TIDYCUSTOMNO_STRING,                           0, "não"                                                                                             },
    { TIDYCUSTOMBLOCKLEVEL_STRING,                   0, "nível de bloco"                                                                                  },
    { TIDYCUSTOMEMPTY_STRING,                        0, "vazio"                                                                                           },
    { TIDYCUSTOMINLINE_STRING,                       0, "em-linha"                                                                                        },
    { TIDYCUSTOMPRE_STRING,                          0, "pré"                                                                                             },
    { TEXT_HTML_T_ALGORITHM,                         0,        
        "\n"
        "      - Primeiro, pesquisa à esquerda da posição da célula para\n"
        "        localizar células de cabeçalho de linha.\n"
        "      - Então, pesquisa para cima para localizar células de cabeçalho\n"
        "        de coluna.\n"
        "      - A pesquisa em uma direção dada interrompe quando a borda da\n"
        "        tabela é atingida ou quando uma célula de dados é localizada\n"
        "        após uma célula de cabeçalho.\n"
        "      - Cabeçalhos de linha são inseridas em uma linha na ordem que\n"
        "        elas aparecem na tabela.\n"
        "      - Para tabelas esquerda-para-direita, cabeçalhos são inseridas\n"
        "        da esquerda para direita.\n"
        "      - Cabeçalhos de coluna são inseridas após cabeçalhos de linha,\n"
        "        na ordem que elas aparecem na tabela, de cima para baixo.\n"
        "      - Se uma célula de cabeçalho tem atributo de cabeçalhos configurado,\n"
        "        então os cabeçalhos referenciados por este atributo são inseridos\n"
        "        na lisa e a pesquisa interrompe para a direção atual.\n"
        "        células TD que configuram o atributo de eixo também são tratadas\n"
        "        com células de cabeçalho.\n"
    },
    { TEXT_VENDOR_CHARS,                             0,        
        "É improvável que as codificações dependentes do sistema específicas\n"
        "do fornecedor funcionem amplamente na World Wide Web; você deve\n"
        "evitar o uso da codificação de caracteres %s; em vez disso,\n"
        "recomenda-se que você use entidades nomeadas, p.ex. &trade;.\n"
    },
    { TEXT_SGML_CHARS,                               0,        
        "Os códigos de caracteres 128 a 159 (U+0080 a U+009F)\n"
        "não são aceitos no HTML; mesmo se eles fossem, eles\n"
        "provavelmente seriam caracteres de controle não imprimíveis.\n"
        "Tidy presumiu que você queria se referir a um caractere\n"
        "com o mesmo valor de bytes na codificação %s e substituiu\n"
        "aquela referência com o equivalente Unicode.\n"
    },
    { TEXT_INVALID_UTF8,                             0,        
        "Os códigos de caracteres para UTF-8 devem estar dentro\n"
        "do intervalo: U+0000 a U+10FFFF. A definição de UTF-8\n"
        "no Anexo D do ISO/IEC 10646-1:2000 também permite para\n"
        "o uso de sequências de cinco e seis bytes para codificar\n"
        "caracteres que estão fora do intervalo do conjunto de\n"
        "caracteres do Unicode; aquelas sequências de cinco e\n"
        "seis bytes são ilegais para o uso de UTF-8 como uma\n"
        "transformação de caracteres Unicode. ISO/IEC 10646 não\n"
        "permite mapeamento de substitutos não pareados, nem\n"
        "U+FFFE e U+FFFF (mas permite outros não caracteres).\n"
        "Para mais informações, veja http://www.unicode.org/ e\n"
        "http://www.cl.cam.ac.uk/~mgk25/unicode.html\n"
    },
    { TEXT_INVALID_UTF16,                            0,        
        "Os códigos de caracteres para UTF-16 devem estar dentro\n"
        "do intervalo: U+0000 a U+10FFFF. A definição de UTF-16\n"
        "no Anexo C da ISO/IEC 10646-1:2000 não permite o mapeamento\n"
        "de substitutos não pareados. Para mais informações,\n"
        "por favor veja http://www.unicode.org/ e\n"
        "http://www.cl.cam.ac.uk/~mgk25/unicode.html\n"
    },
    { TEXT_INVALID_URI,                              0,        
        "URIs devem ser devidamente escapadas, elas não devem\n"
        "conter caracteres não elaborados abaixo de U+0021,\n"
        "incluindo o caractere de espaço e não acima de U+007E.\n"
        "Tidy escapa a URI para você conforme recomendado pelo\n"
        "HTML 4.01 seção B.2.1 e XML 1.0 seção 4.2.2. Alguns\n"
        "agentes de usuários usam outro algoritmo para escapar\n"
        "tais URIs e alguns scripts de servidor dependem disso.\n"
        "Se você quiser depender disso, você deve escapar a URI\n"
        "por conta própria. Para mais informações, consulte\n"
        "http://www.w3.org/International/O-URL-and-ident.html\n"
    },
    { TEXT_BAD_FORM,                                 0,        
        "Talvez seja necessário mover uma ou ambas as tags <form>\n"
        "e </form>. Os elementos HTML devem estar adequadamente\n"
        "aninhados e os elementos de formulário não são uma exceção.\n"
        "Por exemplo, você não deve colocar o <form> em uma célula\n"
        "de tabela e </form> em outra. Se o <form> for colocado\n"
        "antes de uma tabela, o </form> não pode ser colocado dentro\n"
        "da tabela! Note que um formulário não pode ser aninhado\n"
        "dentro de outro!\n"
    },
    { TEXT_BAD_MAIN,                                 0,        
        "Apenas um elemento <main> é permitido em um documento.\n"
        "Elementos <main> subsequentes foram descartados, o que\n"
        "pode tornar o documento inválido.\n"
    },
    { TEXT_M_SUMMARY,                                0,        
        "O atributo de resumo da tabela deve ser usado para\n"
        "descrever a estrutura da tabela. É muito útil para\n"
        "pessoas que usam navegadores não visuais. Os atributos\n"
        "de escopo e cabeçalho para células de tabela são\n"
        "úteis para especificar quais cabeçalhos se aplicam\n"
        "a cada célula de tabela, permitindo que navegadores\n"
        "não visuais forneçam um contexto significativo para\n"
        "cada célula.\n"
    },
    { TEXT_M_IMAGE_ALT,                              0,        
        "O atributo alt deve ser usado para dar uma breve descrição\n"
        "de uma imagem; descrições mais longas devem ser fornecidas\n"
        "com o atributo longdesc que leva uma URL vinculada à\n"
        "descrição. Essas medidas são necessárias para pessoas que\n"
        "usam navegadores não-gráficos.\n"
    },
    { TEXT_M_IMAGE_MAP,                              0,        
        "Use os mapas de imagens do lado do cliente de preferência\n"
        "aos mapas de imagens do lado do servidor, pois estes são\n"
        "inacessíveis para pessoas que usam navegadores não gráficos.\n"
        "Além disso, os mapas do lado do cliente são mais fáceis\n"
        "de configurar e fornecer feedback imediato aos usuários.\n"
    },
    { TEXT_M_LINK_ALT,                               0,        
        "Para links de hipertexto definidos usando um mapa de imagem\n"
        "do lado do cliente, você precisa usar o atributo alt para\n"
        "fornecer uma descrição textual do link para pessoas que usam\n"
        "navegadores não gráficos.\n"
    },
    { TEXT_USING_FRAMES,                             0,        
        "Páginas desenhadas usando quadros apresentam problemas\n"
        "para pessoas que são cegas ou que usam um navegador que\n"
        "não oferece suporte a quadros. Uma página baseada em\n"
        "quadros deve sempre incluir um layout alternativo dentro\n"
        "de um elemento NOFRAMES.\n"
    },
    { TEXT_ACCESS_ADVICE1,                           0,        
        "Para mais conselhos sobre como tornar suas páginas\n"
        "acessíveis, veja http://www.w3.org/WAI/GL."
    },
    { TEXT_ACCESS_ADVICE2,                           0,        
        "Para mais conselhos sobre como tornar suas páginas\n"
        "acessíveis, veja http://www.w3.org/WAI/GL e\n"
        "http://www.html-tidy.org/accessibility/."
    },
    { TEXT_USING_LAYER,                              0,        
        "O mecanismo de posicionamento do Cascading Style\n"
        "Sheets (CSS) é recomendado em preferência ao\n"
        "elemento proprietário <LAYER> devido ao suporte\n"
        "de fornecedor limitado a LAYER.\n"
    },
    { TEXT_USING_SPACER,                             0,        
        "É recomendável usar CSS para controlar o espaço em\n"
        "branco (p.ex., para recuo, margens e espaçamento\n"
        "entre linhas). O elemento proprietário <SPACER>\n"
        "possui suporte limitado para fornecedores.\n"
    },
    { TEXT_USING_FONT,                               0,        
        "É recomendável usar o CSS para especificar a fonte e\n"
        "as propriedades, como seu tamanho e cor. Isso reduzirá\n"
        "o tamanho dos arquivos HTML e facilitando a manutenção\n"
        "em comparação com o uso de elementos <FONT>.\n"
    },
    { TEXT_USING_NOBR,                               0,        
        "É recomendável usar CSS para controlar a quebra de linha.\n"
        "Use \"white-space: nowrap\" para inibir a quebra em vez\n"
        "de inserir <NOBR>...</NOBR> na marcação.\n"
    },
    { TEXT_USING_BODY,                               0, "É recomendável usar CSS para especificar cores de página e link"                                 },
    { STRING_CONTENT_LOOKS,                          0, "O conteúdo do documento se parece com %s"                                                        },
    { STRING_DOCTYPE_GIVEN,                          0, "Doctype dado é \"%s\""                                                                           },
    { STRING_ERROR_COUNT,                            0, "Tidy encontrou %u %s e %u %s!\n"                                                                 },
    { STRING_NEEDS_INTERVENTION,                     0,        
        "Esse documento possui erros que devem ser corrigidos\n"
        "antes de usar HTML Tidy para gerar uma versão arrumada.\n"
    },
    { STRING_NO_ERRORS,                              0, "Nenhum aviso ou erro foi localizado.\n"                                                          },
    { STRING_NO_SYSID,                               0, "Nenhum identificado de sistema no doctype emitido"                                               },
    { STRING_NOT_ALL_SHOWN,                          0, "Tidy encontrou %u %s e %u %s! Nem todos avisos/erros foram mostrados.\n"                         },
    { TEXT_GENERAL_INFO,                             0,        
        "Sobre o HTML Tidy: https://github.com/htacg/tidy-html5\n"
        "Relatórios de erro e comentários: https://github.com/htacg/tidy-html5/"
        "issues\n"
        "Lista de discussão: https://lists.w3.org/Archives/Public/public-htacg/\n"
        "Especificação HTML mais recente: http://dev.w3.org/html5/spec-author-view/\n"
        "Valide seus documentos HTML: http://validator.w3.org/nu/\n"
        "Incentive sua empresa a se juntar à W3C: http://www.w3.org/Consortium\n"
    },
    { TEXT_GENERAL_INFO_PLEA,                        0,        
        "Você fala um idioma diferente do português brasileiro, ou uma variante \n"
        "diferente do português? Considere em ajudar a traduzir o HTML Tidy. \n"
        "Para mais detalhes, por favor veja: \n"
        "https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md"
    },
    { ADDED_MISSING_CHARSET,                         0, "Adicionado o <meta charset=...> apropriado em falta ao %s"                                       },
    { ANCHOR_NOT_UNIQUE,                             0, "âncora de %s \"%s\" já está definido"                                                            },
    { APOS_UNDEFINED,                                0, "a entidade declarada &apos; só definida em XML/XHTML"                                            },
    { ATTR_VALUE_NOT_LCASE,                          0, "valor do atributo de %s \"%s\" deve ser minúsculo para XHTML"                                    },
    { ATTRIBUTE_IS_NOT_ALLOWED,                      0, "atributo de %s \"is\" não permitido para tags personalizadas autônomas."                         },
    { ATTRIBUTE_VALUE_REPLACED,                      0, "atributo %s \"%s\", valor incorreto \"%s\" substituído"                                          },
    { BACKSLASH_IN_URI,                              0, "referência da URI %s contém barra invertida. Erro de escrita?"                                   },
    { BAD_ATTRIBUTE_VALUE_REPLACED,                  0, "atributo %s \"%s\" tinha valor inválido \"%s\" e foi substituído"                                },
    { BAD_ATTRIBUTE_VALUE,                           0, "atributo %s \"%s\" possui valor inválido \"%s\""                                                 },
    { BAD_CDATA_CONTENT,                             0, "'<' + '/' + letra não permitido aqui"                                                            },
    { BAD_SUMMARY_HTML5,                             0, "O atributo de resumo no elemento %s é obsoleto no HTML5"                                         },
    { BAD_SURROGATE_LEAD,                            0,        
        "Par substituto ao final (baixo) U+%04X, com nenhuma entidade precedente "
        "(Alta), substituído por U+FFFD."
    },
    { BAD_SURROGATE_PAIR,                            0,        
        "Possui par substituto U+%04X:U+%04X fora do intervalo, substituído pelo "
        "valor U+FFFD."
    },
    { BAD_SURROGATE_TAIL,                            0,        
        "Par substituto precedente (alto) U+%04X, com nenhuma entidade ao final "
        "(Baixo), substituído por U+FFFD."
    },
    { CANT_BE_NESTED,                                0, "%s não pode ser aninhado"                                                                        },
    { COERCE_TO_ENDTAG,                              0, "<%s> provavelmente deveria ser </%s>"                                                            },
    { CONTENT_AFTER_BODY,                            0, "o conteúdo ocorre após o fim do corpo"                                                           },
    { CUSTOM_TAG_DETECTED,                           0, "tag personalizada autônoma %s detectada; será tratada como %s"                                   },
    { DISCARDING_UNEXPECTED,                         0, "descartando %s inesperado"                                                                       },
    { DOCTYPE_AFTER_TAGS,                            0, "<!DOCTYPE> não é permitido após elementos"                                                       },
    { DUPLICATE_FRAMESET,                            0, "elemento FRAMESET repetido"                                                                      },
    { ELEMENT_NOT_EMPTY,                             0, "%s elemento não vazio ou não fechado"                                                            },
    { ELEMENT_VERS_MISMATCH_ERROR,                   0, "%s elemento não disponível na %s"                                                                },
    { ELEMENT_VERS_MISMATCH_WARN,                    0, "%s elemento não disponível na %s"                                                                },
    { ENCODING_MISMATCH,                             0,        
        "a codificação de entrada especificada (%s) não corresponde à codificação de "
        "entrada atual (%s)"
    },
    { ESCAPED_ILLEGAL_URI,                           0, "%s escapando referência de URI malformada"                                                       },
    { FILE_CANT_OPEN,                                0, "Não foi possível abrir \"%s\"\n"                                                                 },
    { FILE_CANT_OPEN_CFG,                            0, "Não foi possível abrir o arquivo de configuração \"%s\"\n"                                       },
    { FILE_NOT_FILE,                                 0, "\"%s\" não é um arquivo!\n"                                                                      },
    { FIXED_BACKSLASH,                               0, "%s convertendo barra invertida em URI para barra"                                                },
    { FOUND_STYLE_IN_BODY,                           0, "encontrada tag <style> em <body>! fix-style-tags: yes para mover."                               },
    { ID_NAME_MISMATCH,                              0, "%s valores dos atributos id e name incompatíveis"                                                },
    { ILLEGAL_NESTING,                               0, "%s não devem ser aninhados"                                                                      },
    { ILLEGAL_URI_CODEPOINT,                         0, "%s caracteres ilegais localizados na URI"                                                        },
    { ILLEGAL_URI_REFERENCE,                         0, "referência de URI %s inadequadamente escapada"                                                   },
    { INSERTING_AUTO_ATTRIBUTE,                      0, "%s inserindo atributo \"%s\" usando valor \"%s\""                                                },
    { INSERTING_TAG,                                 0, "inserindo <%s> implícita"                                                                        },
    { INVALID_ATTRIBUTE,                             0, "nome do atributo de %s \"%s\" (valor=\"%s\") é inválido"                                         },
    { INVALID_NCR,                                   0, "%s referência de caractere numérico %s"                                                          },
    { INVALID_SGML_CHARS,                            0, "%s código de caracteres inválido %s"                                                             },
    { INVALID_UTF8,                                  0, "%s bytes de UTF-8 inválido (código de caracteres %s)"                                            },
    { INVALID_UTF16,                                 0, "%s par de substituto de UTF-16 inválido (código de caracteres %s)"                               },
    { INVALID_XML_ID,                                0, "%s não pôde copiar atributo de nome para id"                                                     },
    { JOINING_ATTRIBUTE,                             0, "%s juntando valores de atributo repetido \"%s\""                                                 },
    { MALFORMED_COMMENT,                             0, "hífenes adjacentes dentro de comentário"                                                         },
    { MALFORMED_DOCTYPE,                             0, "descartando <!DOCTYPE> malformado"                                                               },
    { MISMATCHED_ATTRIBUTE_ERROR,                    0, "atributo de %s \"%s\" não permitido para %s"                                                     },
    { MISMATCHED_ATTRIBUTE_WARN,                     0, "atributo de %s \"%s\" não permitido para %s"                                                     },
    { MISSING_ATTR_VALUE,                            0, "atributo de %s \"%s\" carece de valor"                                                           },
    { MISSING_ATTRIBUTE,                             0, "%s carece de atributo \"%s\""                                                                    },
    { MISSING_DOCTYPE,                               0, "faltando declaração <!DOCTYPE>"                                                                  },
    { MISSING_ENDTAG_BEFORE,                         0, "faltando </%s> antes de %s"                                                                      },
    { MISSING_ENDTAG_FOR,                            0, "faltando </%s>"                                                                                  },
    { MISSING_IMAGEMAP,                              0, "%s deve usar mapa de imagem no lado de cliente"                                                  },
    { MISSING_QUOTEMARK,                             0, "atributo de %s faltando aspas ao final"                                                          },
    { MISSING_SEMICOLON_NCR,                         0, "referência de caractere numérico \"%s\" não termina em ';'"                                      },
    { MISSING_SEMICOLON,                             0, "entidade \"%s\" não termina em ';'"                                                              },
    { MISSING_STARTTAG,                              0, "faltando <%s>"                                                                                   },
    { MISSING_TITLE_ELEMENT,                         0, "inserindo elemento faltante 'title'"                                                             },
    { MOVED_STYLE_TO_HEAD,                           0, "tag <style> movida para <head>! fix-style-tags: no para evitar."                                 },
    { NESTED_EMPHASIS,                               0, "ênfase aninhada %s"                                                                              },
    { NESTED_QUOTATION,                              0, "elementos q aninhados, possível erro de escrita."                                                },
    { NEWLINE_IN_URI,                                0, "%s descartando nova linha na referência de URI"                                                  },
    { NOFRAMES_CONTENT,                              0, "%s não dentre de elemento 'noframes'"                                                            },
    { NON_MATCHING_ENDTAG,                           0, "substituindo %s inesperada por </%s>"                                                            },
    { OBSOLETE_ELEMENT,                              0, "substituindo elemento obsoleto %s por %s"                                                        },
    { PREVIOUS_LOCATION,                             0, "<%s> anteriormente mencionada"                                                                   },
    { PROPRIETARY_ATTR_VALUE,                        0, "atributo proprietário %s com valor \"%s\""                                                       },
    { PROPRIETARY_ATTRIBUTE,                         0, "atributo proprietário %s \"%s\""                                                                 },
    { PROPRIETARY_ELEMENT,                           0, "%s não é aprovado pela W3C"                                                                      },
    { REMOVED_HTML5,                                 0, "elemento %s removido do HTML5"                                                                   },
    { REPEATED_ATTRIBUTE,                            0, "%s descartando valor \"%s\" para atributo repetido \"%s\""                                       },
    { REPLACING_ELEMENT,                             0, "substituindo %s por %s"                                                                          },
    { REPLACING_UNEX_ELEMENT,                        0, "substituindo %s inesperada por %s"                                                               },
    { SPACE_PRECEDING_XMLDECL,                       0, "removendo espaço em branco precedendo a declaração XML"                                          },
    { STRING_MISSING_MALFORMED,                      0, "argumento faltando ou malformado para opção: %s"                                                 },
    { STRING_UNKNOWN_OPTION,                         0, "opção desconhecida: %s"                                                                          },
    { SUSPECTED_MISSING_QUOTE,                       0, "faltando aspas para o valor de atributo"                                                         },
    { TAG_NOT_ALLOWED_IN,                            0, "%s não é permitido em elementos <%s>"                                                            },
    { TOO_MANY_ELEMENTS_IN,                          0, "número excessivo de elementos %s em <%s>"                                                        },
    { TOO_MANY_ELEMENTS,                             0, "número excessivo de elementos %s"                                                                },
    { TRIM_EMPTY_ELEMENT,                            0, "aparando %s vazio"                                                                               },
    { UNESCAPED_AMPERSAND,                           0, "& não escapado que deve ser escrito como &amp;"                                                  },
    { UNEXPECTED_END_OF_FILE_ATTR,                   0, "%s fim de arquivo enquanto analisava atributos"                                                  },
    { UNEXPECTED_END_OF_FILE,                        0, "fim do arquivo %s inesperado"                                                                    },
    { UNEXPECTED_ENDTAG_ERR,                         0, "</%s> inesperada"                                                                                },
    { UNEXPECTED_ENDTAG_IN,                          0, "</%s> inesperada em <%s>"                                                                        },
    { UNEXPECTED_ENDTAG,                             0, "</%s> inesperada"                                                                                },
    { UNEXPECTED_EQUALSIGN,                          0, "%s inesperado '=', esperava nome de atributo"                                                    },
    { UNEXPECTED_GT,                                 0, "%s carece de '>' para o fim da tag"                                                              },
    { UNEXPECTED_QUOTEMARK,                          0, "%s aspas inesperadas ou duplicadas"                                                              },
    { UNKNOWN_ELEMENT_LOOKS_CUSTOM,                  0, "%s não é reconhecido! Você queria habilitar a opção custom-tags?"                                },
    { UNKNOWN_ELEMENT,                               0, "%s não é reconhecido!"                                                                           },
    { UNKNOWN_ENTITY,                                0, "& não escapado ou entidade desconhecida \"%s\""                                                  },
    { USING_BR_INPLACE_OF,                           0, "usando <br> no lugar de %s"                                                                      },
    { VENDOR_SPECIFIC_CHARS,                         0, "%s código de caractere inválido %s"                                                              },
    { WHITE_IN_URI,                                  0, "%s descartando espaço em branco na referência de URI"                                            },
    { XML_DECLARATION_DETECTED,                      0, "Uma declaração XML foi detectada. Você queria usar input-xml?"                                   },
    { XML_ID_SYNTAX,                                 0, "%s ID \"%s\" usa sintaxe de ID de XML"                                                           },
    { IMG_MISSING_ALT,                               0, "[1.1.1.1]: <img> carece de texto 'alt'."                                                         },
    { IMG_ALT_SUSPICIOUS_FILENAME,                   0, "[1.1.1.2]: texto 'alt' suspeito (nome de arquivo)."                                              },
    { IMG_ALT_SUSPICIOUS_FILE_SIZE,                  0, "[1.1.1.3]: texto 'alt' suspeito (tamanho de arquivo)."                                           },
    { IMG_ALT_SUSPICIOUS_PLACEHOLDER,                0, "[1.1.1.4]: texto 'alt' suspeito (espaço reservado)."                                             },
    { IMG_ALT_SUSPICIOUS_TOO_LONG,                   0, "[1.1.1.10]: texto 'alt' suspeito (longo demais)."                                                },
    { IMG_MISSING_LONGDESC_DLINK,                    0, "[1.1.2.1]: <img> carece de 'longdesc' e d-link."                                                 },
    { IMG_MISSING_DLINK,                             0, "[1.1.2.2]: <img> carece de d-link."                                                              },
    { IMG_MISSING_LONGDESC,                          0, "[1.1.2.3]: <img> carece de 'longdesc'."                                                          },
    { IMG_BUTTON_MISSING_ALT,                        0, "[1.1.3.1]: <img> (botão) carece de texto 'alt'."                                                 },
    { APPLET_MISSING_ALT,                            0, "[1.1.4.1]: <applet> carece de conteúdo alternativo."                                             },
    { OBJECT_MISSING_ALT,                            0, "[1.1.5.1]: <object> carece de conteúdo alternativo."                                             },
    { AUDIO_MISSING_TEXT_WAV,                        0, "[1.1.6.1]: áudio carece de transcrição de texto (wav)."                                          },
    { AUDIO_MISSING_TEXT_AU,                         0, "[1.1.6.2]: áudio carece de transcrição de texto (au)."                                           },
    { AUDIO_MISSING_TEXT_AIFF,                       0, "[1.1.6.3]: áudio carece de transcrição de texto (aiff)."                                         },
    { AUDIO_MISSING_TEXT_SND,                        0, "[1.1.6.4]: áudio carece de transcrição de texto (snd)."                                          },
    { AUDIO_MISSING_TEXT_RA,                         0, "[1.1.6.5]: áudio carece de transcrição de texto (ra)."                                           },
    { AUDIO_MISSING_TEXT_RM,                         0, "[1.1.6.6]: áudio carece de transcrição de texto (rm)."                                           },
    { FRAME_MISSING_LONGDESC,                        0, "[1.1.8.1]: <frame> pode exigir 'longdesc'."                                                      },
    { AREA_MISSING_ALT,                              0, "[1.1.9.1]: <area> carece de texto 'alt'."                                                        },
    { SCRIPT_MISSING_NOSCRIPT,                       0, "[1.1.10.1]: <script> carece de seção <noscript>."                                                },
    { ASCII_REQUIRES_DESCRIPTION,                    0, "[1.1.12.1]: arte em ascii exige descrição."                                                      },
    { IMG_MAP_SERVER_REQUIRES_TEXT_LINKS,            0, "[1.2.1.1]: mapa de imagem (lado do servidor) exige links de texto."                              },
    { MULTIMEDIA_REQUIRES_TEXT,                      0, "[1.4.1.1]: multimídia exibe equivalentes de texto sincronizado."                                 },
    { IMG_MAP_CLIENT_MISSING_TEXT_LINKS,             0, "[1.5.1.1]: mapa da imagem (lado do cliente) carece de links de texto."                           },
    { INFORMATION_NOT_CONVEYED_IMAGE,                0, "[2.1.1.1]: certificar de que as informações não sejam transmitidas apenas por cores (imagem)."   },
    { INFORMATION_NOT_CONVEYED_APPLET,               0, "[2.1.1.2]: certificar de que as informações não sejam transmitidas apenas por cores (applet)."   },
    { INFORMATION_NOT_CONVEYED_OBJECT,               0, "[2.1.1.3]: certificar de que as informações não sejam transmitidas apenas por cores (objeto)."   },
    { INFORMATION_NOT_CONVEYED_SCRIPT,               0, "[2.1.1.4]: certificar de que as informações não sejam transmitidas apenas por cores (script)."   },
    { INFORMATION_NOT_CONVEYED_INPUT,                0,        
        "[2.1.1.5]: certificar de que as informações não sejam transmitidas apenas por cores "
        "(entrada)."
    },
    { COLOR_CONTRAST_TEXT,                           0, "[2.2.1.1]: contraste de cores ruim (texto)."                                                     },
    { COLOR_CONTRAST_LINK,                           0, "[2.2.1.2]: contraste de cores ruim (link)."                                                      },
    { COLOR_CONTRAST_ACTIVE_LINK,                    0, "[2.2.1.3]: contraste de cores ruim (link ativo)."                                                },
    { COLOR_CONTRAST_VISITED_LINK,                   0, "[2.2.1.4]: contraste de cores ruim (link visitado)."                                             },
    { DOCTYPE_MISSING,                               0, "[3.2.1.1]: faltando <doctype>."                                                                  },
    { STYLE_SHEET_CONTROL_PRESENTATION,              0, "[3.3.1.1]: use folhas de estilo para controlar apresentação."                                    },
    { HEADERS_IMPROPERLY_NESTED,                     0, "[3.5.1.1]: cabeçalhos aninhados incorretamente."                                                 },
    { POTENTIAL_HEADER_BOLD,                         0, "[3.5.2.1]: cabeçalho potencial (negrito)."                                                       },
    { POTENTIAL_HEADER_ITALICS,                      0, "[3.5.2.2]: cabeçalho potencial (itálico)."                                                       },
    { POTENTIAL_HEADER_UNDERLINE,                    0, "[3.5.2.3]: cabeçalho potencial (sublinhado)."                                                    },
    { HEADER_USED_FORMAT_TEXT,                       0, "[3.5.3.1]: cabeçalho usado para formatar o texto."                                               },
    { LIST_USAGE_INVALID_UL,                         0, "[3.6.1.1]: uso de lista inválido <ul>."                                                          },
    { LIST_USAGE_INVALID_OL,                         0, "[3.6.1.2]: uso de lista inválido <ol>."                                                          },
    { LIST_USAGE_INVALID_LI,                         0, "[3.6.1.4]: uso de lista inválido <li>."                                                          },
    { LANGUAGE_NOT_IDENTIFIED,                       0, "[4.3.1.1]: idioma não identificado."                                                             },
    { LANGUAGE_INVALID,                              0, "[4.3.1.2]: atributo de idioma inválido."                                                         },
    { DATA_TABLE_MISSING_HEADERS,                    0, "[5.1.2.1]: <table> de dados carece de cabeçalhos de linha/coluna (todos)."                       },
    { DATA_TABLE_MISSING_HEADERS_COLUMN,             0, "[5.1.2.2]: <table> de dados carece de cabeçalhos de linha/coluna (1 col)."                       },
    { DATA_TABLE_MISSING_HEADERS_ROW,                0, "[5.1.2.3]: <table> de dados carece de cabeçalhos de linha/coluna (1 lin)."                       },
    { DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS,      0, "[5.2.1.1]: <table> pode exigir marcação (cabeçalhos de coluna)."                                 },
    { DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS,         0, "[5.2.1.2]: <table> pode exigir marcação (cabeçalhos de linha)."                                  },
    { LAYOUT_TABLES_LINEARIZE_PROPERLY,              0, "[5.3.1.1]: verifique se tabelas de layout linearizaram corretamente."                            },
    { LAYOUT_TABLE_INVALID_MARKUP,                   0, "[5.4.1.1]: marcação inválida usada em <table> de layout."                                        },
    { TABLE_MISSING_SUMMARY,                         0, "[5.5.1.1]: <table> carece de sumário."                                                           },
    { TABLE_SUMMARY_INVALID_NULL,                    0, "[5.5.1.2]: resumo da <table> inválido (nulo)."                                                   },
    { TABLE_SUMMARY_INVALID_SPACES,                  0, "[5.5.1.3]: resumo da <table> inválido (espaços)."                                                },
    { TABLE_SUMMARY_INVALID_PLACEHOLDER,             0, "[5.5.1.6]: resumo da <table> inválido (texto de espaço reservado)."                              },
    { TABLE_MISSING_CAPTION,                         0, "[5.5.2.1]: <table> carece de <caption>."                                                         },
    { TABLE_MAY_REQUIRE_HEADER_ABBR,                 0, "[5.6.1.1]: <table> pode exigir abreviações de cabeçalho."                                        },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_NULL,            0, "[5.6.1.2]: abreviações de cabeçalho de <table> inválidas (nula)."                                },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES,          0, "[5.6.1.3]: abreviações de cabeçalho de <table> inválidas (espaços)."                             },
    { STYLESHEETS_REQUIRE_TESTING_LINK,              0, "[6.1.1.1]: folhas de estilo exigem teste (link)."                                                },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT,     0, "[6.1.1.2]: folhas de estilo exigem teste (elemento de estilo)."                                  },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR,        0, "[6.1.1.3]: folhas de estilo exigem teste (atributo de estilo)."                                  },
    { FRAME_SRC_INVALID,                             0, "[6.2.1.1]: fonte de <frame> inválida."                                                           },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET,      0, "[6.2.2.1]: equivalentes de texto exigem atualização (applet)."                                   },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT,      0, "[6.2.2.2]: equivalentes de texto exigem atualização (script)."                                   },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT,      0, "[6.2.2.3]: equivalentes de texto exigem atualização (object)."                                   },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT,   0, "[6.3.1.1]: objetos programáticos exigem teste (script)."                                         },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT,   0, "[6.3.1.2]: objetos programáticos exigem teste (object)."                                         },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED,    0, "[6.3.1.3]: objetos programáticos exigem teste (embed)."                                          },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET,   0, "[6.3.1.4]: objetos programáticos exigem teste (applet)."                                         },
    { FRAME_MISSING_NOFRAMES,                        0, "[6.5.1.1]: <frameset> carece de seção <noframes>."                                               },
    { NOFRAMES_INVALID_NO_VALUE,                     0, "[6.5.1.2]: seção <noframes> inválida (sem valor)."                                               },
    { NOFRAMES_INVALID_CONTENT,                      0, "[6.5.1.3]: seção <noframes> inválida (conteúdo)."                                                },
    { NOFRAMES_INVALID_LINK,                         0, "[6.5.1.4]: seção <noframes> inválida (link)."                                                    },
    { REMOVE_FLICKER_SCRIPT,                         0, "[7.1.1.1]: remoção de cintilação (script)."                                                      },
    { REMOVE_FLICKER_OBJECT,                         0, "[7.1.1.2]: remoção de cintilação (object)."                                                      },
    { REMOVE_FLICKER_EMBED,                          0, "[7.1.1.3]: remoção de cintilação (embed)."                                                       },
    { REMOVE_FLICKER_APPLET,                         0, "[7.1.1.4]: remoção de cintilação (applet)."                                                      },
    { REMOVE_FLICKER_ANIMATED_GIF,                   0, "[7.1.1.5]: remoção de cintilação (gif animado)."                                                 },
    { REMOVE_BLINK_MARQUEE,                          0, "[7.2.1.1]: remoção de blink/marquee."                                                            },
    { REMOVE_AUTO_REFRESH,                           0, "[7.4.1.1]: remoção de autorrenovação."                                                           },
    { REMOVE_AUTO_REDIRECT,                          0, "[7.5.1.1]: remoção de autorredirecionamento."                                                    },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT, 0, "[8.1.1.1]: certifique-se que objetos programáticos sejam acessíveis (script)."                   },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT, 0, "[8.1.1.2]: certifique-se que objetos programáticos sejam acessíveis (object)."                   },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET, 0, "[8.1.1.3]: certifique-se que objetos programáticos sejam acessíveis (applet)."                   },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED,  0, "[8.1.1.43]: certifique-se que objetos programáticos sejam acessíveis (embed)."                   },
    { IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION,     0, "[9.1.1.1]: mapa de imagem (lado do servidor) exige conversão."                                   },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN,  0, "[9.3.1.1]: <script> não é acessível por teclado (onMouseDown)."                                  },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP,    0, "[9.3.1.2]: <script> não é acessível por teclado (onMouseUp)."                                    },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK,       0, "[9.3.1.3]: <script> não é acessível por teclado (onClick)."                                      },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER,  0, "[9.3.1.4]: <script> não é acessível por teclado (onMouseOver)."                                  },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT,   0, "[9.3.1.5]: <script> não é acessível por teclado (onMouseOut)."                                   },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE,  0, "[9.3.1.6]: <script> não é acessível por teclado (onMouseMove)."                                  },
    { NEW_WINDOWS_REQUIRE_WARNING_NEW,               0, "[10.1.1.1]: novas janelas exigem aviso (_new)."                                                  },
    { NEW_WINDOWS_REQUIRE_WARNING_BLANK,             0, "[10.1.1.2]: novas janelas exigem aviso (_blank)."                                                },
    { REPLACE_DEPRECATED_HTML_APPLET,                0, "[11.2.1.1]: substituir o elemento html obsoleto <applet>."                                       },
    { REPLACE_DEPRECATED_HTML_BASEFONT,              0, "[11.2.1.2]: substituir o elemento html obsoleto <basefont>."                                     },
    { REPLACE_DEPRECATED_HTML_CENTER,                0, "[11.2.1.3]: substituir o elemento html obsoleto <center>."                                       },
    { REPLACE_DEPRECATED_HTML_DIR,                   0, "[11.2.1.4]: substituir o elemento html obsoleto <dir>."                                          },
    { REPLACE_DEPRECATED_HTML_FONT,                  0, "[11.2.1.5]: substituir o elemento html obsoleto <font>."                                         },
    { REPLACE_DEPRECATED_HTML_ISINDEX,               0, "[11.2.1.6]: substituir o elemento html obsoleto <isindex>."                                      },
    { REPLACE_DEPRECATED_HTML_MENU,                  0, "[11.2.1.7]: substituir o elemento html obsoleto <menu>."                                         },
    { REPLACE_DEPRECATED_HTML_S,                     0, "[11.2.1.8]: substituir o elemento html obsoleto <s>."                                            },
    { REPLACE_DEPRECATED_HTML_STRIKE,                0, "[11.2.1.9]: substituir o elemento html obsoleto <strike>."                                       },
    { REPLACE_DEPRECATED_HTML_U,                     0, "[11.2.1.10]: substituir o elemento html obsoleto <u>."                                           },
    { FRAME_MISSING_TITLE,                           0, "[12.1.1.1]: <frame> carece de título."                                                           },
    { FRAME_TITLE_INVALID_NULL,                      0, "[12.1.1.2]: título de <frame> inválido (nulo)."                                                  },
    { FRAME_TITLE_INVALID_SPACES,                    0, "[12.1.1.3]: título de <frame> inválido (espaços)."                                               },
    { ASSOCIATE_LABELS_EXPLICITLY,                   0, "[12.4.1.1]: associar rótulos explicitamente com controles de formulário."                        },
    { ASSOCIATE_LABELS_EXPLICITLY_FOR,               0,        
        "[12.4.1.2]: associar rótulos explicitamente com controles de formulário "
        "(for)."
    },
    { ASSOCIATE_LABELS_EXPLICITLY_ID,                0, "[12.4.1.3]: associar rótulos explicitamente com controles de formulário (id)."                   },
    { LINK_TEXT_NOT_MEANINGFUL,                      0, "[13.1.1.1]: texto de link não significativo."                                                    },
    { LINK_TEXT_MISSING,                             0, "[13.1.1.2]: faltando texto de link."                                                             },
    { LINK_TEXT_TOO_LONG,                            0, "[13.1.1.3]: texto de link longo demais."                                                         },
    { LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE,           0, "[13.1.1.4]: texto de link não significativo (clique aqui)."                                      },
    { METADATA_MISSING,                              0, "[13.2.1.1]: faltando metadados."                                                                 },
    { METADATA_MISSING_REDIRECT_AUTOREFRESH,         0, "[13.2.1.3]: faltando metadados (redirecionamento/autorrenovação)."                               },
    { SKIPOVER_ASCII_ART,                            0, "[13.10.1.1]: pular arte em ascii."                                                               },

#if SUPPORT_CONSOLE_APP
    { TC_LABEL_COL,                                  0, "coluna"                                                                                          },
    { TC_LABEL_FILE,                                 0, "arquivo"                                                                                         },
    { TC_LABEL_LANG,                                 0, "idioma"                                                                                          },
    { TC_LABEL_LEVL,                                 0, "nível"                                                                                           },
    { TC_LABEL_OPT,                                  0, "opção"                                                                                           },
    { TC_MAIN_ERROR_LOAD_CONFIG,                     0, "Falha ao carregar o arquivo de config \"%s\", err = %d"                                          },
    { TC_OPT_ACCESS,                                 0,        
        " faz verificações adicionais de acessibilidade (<nível> = 0, 1, 2, 3). 0 é "
        "presumido se <nível> estiver faltando."
    },
    { TC_OPT_ASCII,                                  0, "usa ISO-8859-1 para entrada, US-ASCII para saída"                                                },
    { TC_OPT_ASHTML,                                 0, "força XHTML para HTML bem formatado"                                                             },
    { TC_OPT_ASXML,                                  0, "converte HTML para XHTML bem formatado"                                                          },
    { TC_OPT_BARE,                                   0, "retira aspas inteligentes, travessões etc."                                                      },
    { TC_OPT_BIG5,                                   0, "usa Big5 para tanto entrada quanto saída"                                                        },
    { TC_OPT_CLEAN,                                  0, "substitui tags FONT, NOBR e CENTER com CSS"                                                      },
    { TC_OPT_CONFIG,                                 0, "define opções de configuração a partir do <arquivo> especificado"                                },
    { TC_OPT_ERRORS,                                 0, "mostra apenas erros e avisos"                                                                    },
    { TC_OPT_FILE,                                   0, "escreve erros e avisos para o <arquivo> especificado"                                            },
    { TC_OPT_GDOC,                                   0, "produz versão limpa do html exportado pelo Google Docs"                                          },
    { TC_OPT_HELP,                                   0, "lista as opções de linha de comando"                                                             },
    { TC_OPT_HELPCFG,                                0, "lista todas as opções de configuração"                                                           },
    { TC_OPT_HELPOPT,                                0, "  mostra uma descrição da <opção>"                                                               },
    { TC_OPT_IBM858,                                 0, "usa IBM-858 (CP850+Euro) para entrada, US-ASCII para saída"                                      },
    { TC_OPT_INDENT,                                 0, "recua o conteúdo do elemento"                                                                    },
    { TC_OPT_ISO2022,                                0, "usa ISO-2022 para tanto entrada quanto saída"                                                    },
    { TC_OPT_LANGUAGE,                               0,        
        "define o idioma de saída do Tidy para <idioma>. Especifique '-language help' "
        "para mais ajuda. Use antes de argumentos que gerem saída para garantir que o "
        "idioma surta efeitos, p.ex.:\n"
        "`tidy -lang es -lang help`."
    },
    { TC_OPT_LATIN0,                                 0, "usa ISO-8859-15 para entrada, US-ASCII para saída"                                               },
    { TC_OPT_LATIN1,                                 0, "usa ISO-8859-1 para tanto entrada quanto saída"                                                  },
    { TC_OPT_MAC,                                    0, "usa MacRoman para entrada, US-ASCII para saída"                                                  },
    { TC_OPT_MODIFY,                                 0, "modifica os arquivos de entrada originais"                                                       },
    { TC_OPT_NUMERIC,                                0, "emite entidades numéricas em vez de nomeadas"                                                    },
    { TC_OPT_OMIT,                                   0, "omite tags opcionais de início e de fim"                                                         },
    { TC_OPT_OUTPUT,                                 0, "escreve a saída para o <arquivo> especificado"                                                   },
    { TC_OPT_QUIET,                                  0, "suprime saída não essencial"                                                                     },
    { TC_OPT_RAW,                                    0, "emite valores acima de 127 sem conversão para entidades"                                         },
    { TC_OPT_SHIFTJIS,                               0, "usa Shift_JIS para tanto entrada quanto saída"                                                   },
    { TC_OPT_SHOWCFG,                                0, "lista as definições da configuração atual"                                                       },
    { TC_OPT_UPPER,                                  0, "força tags para maiúsculo"                                                                       },
    { TC_OPT_UTF16,                                  0, "usa UTF-16 para tanto entrada quanto saída"                                                      },
    { TC_OPT_UTF16BE,                                0, "usa UTF-16BE para tanto entrada quanto saída"                                                    },
    { TC_OPT_UTF16LE,                                0, "usa UTF-16LE para tanto entrada quanto saída"                                                    },
    { TC_OPT_UTF8,                                   0, "usa UTF-8 para tanto entrada quanto saída"                                                       },
    { TC_OPT_VERSION,                                0, "mostra a versão do Tidy"                                                                         },
    { TC_OPT_WIN1252,                                0, "usa Windows--1252 para entrada, US-ASCII para saída"                                             },
    { TC_OPT_WRAP,                                   0,        
        "efetua quebra de texto na <coluna> especificada, 0 é presumido se <coluna> "
        "estiver faltando. Quando esta opção é omitida, o padrão da opção da "
        "configuração 'wrap' é aplicado."
    },
    { TC_OPT_XML,                                    0, "especifica a entrada é XML bem formatado"                                                        },
    { TC_OPT_XMLCFG,                                 0, "lista todas as opções de configuração no formato XML"                                            },
    { TC_OPT_XMLHELP,                                0, "lista as opções de linha de comando no formato XML"                                              },
    { TC_OPT_XMLSTRG,                                0, "emite todas as strings do Tidy no formato XML"                                                   },
    { TC_OPT_XMLERRS,                                0, "emite constantes de erro e strings no formato XML"                                               },
    { TC_OPT_XMLOPTS,                                0, "emite descrições de opção no formato XML"                                                        },
    { TC_STRING_CONF_HEADER,                         0, "Definições do arquivo de configuração:"                                                          },
    { TC_STRING_CONF_NAME,                           0, "Nome"                                                                                            },
    { TC_STRING_CONF_TYPE,                           0, "Tipo"                                                                                            },
    { TC_STRING_CONF_VALUE,                          0, "Valor atual"                                                                                     },
    { TC_STRING_OPT_NOT_DOCUMENTED,                  0, "Aviso: a opção '%s' não está documentada."                                                       },
    { TC_STRING_OUT_OF_MEMORY,                       0, "Memória insuficiente. Saindo."                                                                   },
    { TC_STRING_FATAL_ERROR,                         0, "Erro fatal: valor impossível para id='%d'."                                                      },
    { TC_STRING_FILE_MANIP,                          0, "Manipulação de arquivo"                                                                          },
    { TC_STRING_PROCESS_DIRECTIVES,                  0, "Diretivas de processamento"                                                                      },
    { TC_STRING_CHAR_ENCODING,                       0, "Codificações de caracteres"                                                                      },
    { TC_STRING_LANG_MUST_SPECIFY,                   0, "Uma localidade POSIX ou Windows deve ser especificada."                                          },
    { TC_STRING_LANG_NOT_FOUND,                      0, "Tidy não possui o idioma '%s'; em vez desta, usará '%s'."                                        },
    { TC_STRING_MISC,                                0, "Diversos"                                                                                        },
    { TC_STRING_XML,                                 0, "XML"                                                                                             },
    { TC_STRING_MUST_SPECIFY,                        0, "Um nome de opção Tidy deve ser especificado."                                                    },
    { TC_STRING_UNKNOWN_OPTION,                      0, "HTML Tidy: opção desconhecida: %c"                                                               },
    { TC_STRING_UNKNOWN_OPTION_B,                    0, "HTML Tidy: opção desconhecida."                                                                  },
    { TC_STRING_VERS_A,                              0, "HTML Tidy para %s versão %s"                                                                     },
    { TC_STRING_VERS_B,                              0, "HTML Tidy versão %s"                                                                             },
    { TC_TXT_HELP_1,                                 0,        
        "\n"
        "%s [opções...] [arquivo...] [opções...] [arquivo...]\n"
        "Utilitário para limpar e melhor imprimir HTML/XHTML/XML.\n"
        "\n"
        "Essa é o HTML Tidy moderno versão %s.\n"
        "\n"
    },
    { TC_TXT_HELP_2A,                                0, "Os argumentos de linha de comando para HTML Tidy para %s:"                                       },
    { TC_TXT_HELP_2B,                                0, "Os argumentos de linha de comando para HTML Tidy:"                                               },
    { TC_TXT_HELP_3,                                 0,        
        "\n"
        "Opções de configuração do Tidy\n"
        "==========================\n"
        "Use as opções de configuração do Tidy como argumentos de linha de comando\n"
        "no forma de \"--alguma-opcao <valor>\", por exemplo \"--indent-with-tabs "
        "yes\".\n"
        "\n"
        "Para uma lista de todas as opções de configuração, use \"-help-config\" ou\n"
        "veja a página man (se seu SO tiver uma).\n"
        "\n"
        "Se seu ambiente tem uma variável $HTML_TIDY definida, aponte para um "
        "arquivo\n"
        "de configuração Tidy e, então, Tidy vai tentar usá-la.\n"
        "\n"
        "Em algumas plataformas, Tidy também vai tentar usar uma configuração\n"
        "especificada no /etc/tidy.conf ou ~/.tidy.conf.\n"
        "\n"
        "Outro\n"
        "=====\n"
        "Entrada/Saída usa, por padrão, stdin/stdout respectivamente.\n"
        "\n"
        "Opções de uma só letra, com exceção de -f, podem ser combinadas\n"
        "como em: tidy -f errs.txt -imu foo.html\n"
        "\n"
        "Informação\n"
        "===========\n"
        "Para mais informações sobre HTML Tidy, veja\n"
        "  http://www.html-tidy.org/\n"
        "\n"
        "Para mais informações sobre HTML, veja o seguinte:\n"
        "\n"
        "  HTML: Edition for Web Authors (the latest HTML specification)\n"
        "  http://dev.w3.org/html5/spec-author-view\n"
        "\n"
        "  HTML: The Markup Language (an HTML language reference)\n"
        "  http://dev.w3.org/html5/markup/\n"
        "\n"
        "Preencha relatórios de erros em https://github.com/htacg/tidy-html5/issues/\n"
        "ou envie perguntas e comentários para public-htacg@w3.org.\n"
        "\n"
        "Valide seus documentos HTML usando Nu, o validador de marcação da W3C:\n"
        "  http://validator.w3.org/nu/\n"
        "\n"
    },
    { TC_TXT_HELP_CONFIG,                            0,        
        "\n"
        "Definições de configuração do HTML Tidy\n"
        "\n"
        "Dentro de um arquivo, use a forma:\n"
        "\n"
        "wrap: 72\n"
        "indent: no\n"
        "\n"
        "Quando especificado na linha de comando, use a forma:\n"
        "\n"
        "--wrap 72 --indent no\n"
        "\n"
    },
    { TC_TXT_HELP_CONFIG_NAME,                       0, "Nome"                                                                                            },
    { TC_TXT_HELP_CONFIG_TYPE,                       0, "Tipo"                                                                                            },
    { TC_TXT_HELP_CONFIG_ALLW,                       0, "Valores permitidos"                                                                              },
    { TC_TXT_HELP_LANG_1,                            0,        
        "\n"
        "A opção -language (ou -lang) indica qual idioma o Tidy deve usar\n"
        "para comunicar sua saída. Por favor, note que este não é um serviço\n"
        "de tradução de documentos e afeta apenas as mensagens com as quais\n"
        "o Tidy se comunica com você.\n"
        "\n"
        "Quando usado a partir da linha de comando, o argumento -language\n"
        "deve ser usado antes de qualquer argumento que resulte em saída; do\n"
        "contrário, o Tidy produzirá saída antes de saber qual idioma usar.\n"
        "\n"
        "Além dos códigos de idioma POSIX padrão, o Tidy é capaz de entender\n"
        "os códigos legados de idioma do Windows. Por favor, note que esta\n"
        "lista indica códigos Tidy entende e não indica que o idioma esteja\n"
        "instalado no momento.\n"
        "\n"
        "A coluna mais à direita indica como o Tidy vai entender o nome do\n"
        "Windows legado.\n"
        "\n"
    },
    { TC_TXT_HELP_LANG_2,                            0,        
        "\n"
        "Os seguintes idiomas estão atualmente instalados em Tidy. Por favor, \n"
        "note que não há garantia de que eles estejam completos; apenas que \n"
        "esse desenvolvedor ou outro começou a adicionar o idioma indicado. \n"
        "\n"
        "As localizações incompletas serão padrão para \"en\" quando necessário. \n"
        "Informe as instâncias de strings incorretas para a equipe do Tidy. \n"
        "\n"
    },
    { TC_TXT_HELP_LANG_3,                            0,        
        "\n"
        "Se o Tidy for capaz de determinar sua localidade, o Tidy usará \n"
        "o idioma da localidade automaticamente. Por exemplo, os sistemas \n"
        "tipo Unix usam uma variável de ambiente $LANG e/ou $LC_ALL. \n"
        "Consulte a documentação de seu sistema operacional para obter \n"
        "mais informações. \n"
        "\n"
        "Tidy está usando a localidade %s. \n"
        "\n"
    },
#endif /* SUPPORT_CONSOLE_APP */

    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST,                        0, NULL
    }

}};


#endif /* language_pt_br_h */

#ifndef language_zh_cn_h
#define language_zh_cn_h
/*
 * language_zh_cn.h
 * Localization support for HTML Tidy.
 *
 *
 * This file is a localization file for HTML Tidy. It will have been machine
 * generated or created and/or edited by hand. Both are valid options, but
 * please help keep our localization efforts simple to maintain by maintaining
 * the structure of this file, and changing the check box below if you make
 * changes (so others know the file origin):
 *
 * [X] THIS FILE IS MACHINE GENERATED. It is a localization file for the
 *     language (and maybe region) "zh_cn". The source of
 *     these strings is a gettext PO file in Tidy's source, probably called 
 *     "language_zh_cn.po".
 *
 * [ ] THIS FILE WAS HAND MODIFIED. Translators, please feel to edit this file
 *     directly (and check this box). If you prefer to edit PO files then use
 *     `poconvert.rb msgunfmt language_zh_cn.h` (our own
 *     conversion tool) to generate a fresh PO from this file first!
 *
 * (c) 2015-2017 HTACG
 * See tidy.h and access.h for the copyright notice.
 *
 * Template Created by Jim Derry on 01/14/2016.
 *
 * Orginating PO file metadata:
 *   PO_LAST_TRANSLATOR=jderry
 *   PO_REVISION_DATE=2017-10-03 12:44:37
 */

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif


/**
 *  This language-specific function returns the correct pluralForm
 *  to use given n items, and is used as a member of each language
 *  definition.
 */
static unsigned int whichPluralForm_zh_cn(unsigned int n) {
    /* Plural-Forms: nplurals=1; */
    return 0;
}


/**
 *  This structure specifies all of the strings needed by Tidy for a
 *  single language. Static definition in a header file makes it
 *  easy to include and exclude languages without tinkering with
 *  the build system.
 */
static languageDefinition language_zh_cn = { whichPluralForm_zh_cn, {
    /***************************************
     ** This MUST be present and first. 
     ** Specify the code for this language.
     ***************************************/
    {/* Specify the ll or ll_cc language code here. */
      TIDY_LANGUAGE,          0, "zh_cn"
    },
    { LINE_COLUMN_STRING,     0, "行 %d 列 %d - "            },
    { STRING_CONTENT_LOOKS,   0, "文档内容看起来像 %s"             },
    { FILE_CANT_OPEN,         0, "无法打开”%s”\n"              },

#if SUPPORT_CONSOLE_APP
    { TC_STRING_VERS_A,       0, "HTML Tidy 用于 %s 版本 %s"   },
    { TC_STRING_VERS_B,       0, "HTML Tidy 版本 %s"         },
#endif /* SUPPORT_CONSOLE_APP */

    {/* This MUST be present and last. */
      TIDY_MESSAGE_TYPE_LAST, 0, NULL
    }

}};


#endif /* language_zh_cn_h */

#ifndef __LEXER_H__
#define __LEXER_H__

/* lexer.h -- Lexer for html parser
  
   (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
   See tidy.h for the copyright notice.

  Given an input source, it returns a sequence of tokens.

     GetToken(source) gets the next token
     UngetToken(source) provides one level undo

  The tags include an attribute list:

    - linked list of attribute/value nodes
    - each node has 2 NULL-terminated strings.
    - entities are replaced in attribute values

  white space is compacted if not in preformatted mode
  If not in preformatted mode then leading white space
  is discarded and subsequent white space sequences
  compacted to single space characters.

  If XmlTags is no then Tag names are folded to upper
  case and attribute names to lower case.

 Not yet done:
    -   Doctype subset and marked sections
*/

#ifdef __cplusplus
extern "C" {
#endif

/* #include "forward.h" */

/* lexer character types
*/
#define digit       1u
#define letter      2u
#define namechar    4u
#define white       8u
#define newline     16u
#define lowercase   32u
#define uppercase   64u
#define digithex    128u


/* node->type is one of these values
*/
typedef enum
{
  RootNode,
  DocTypeTag,
  CommentTag,
  ProcInsTag,
  TextNode,
  StartTag,
  EndTag,
  StartEndTag,
  CDATATag,
  SectionTag,
  AspTag,
  JsteTag,
  PhpTag,
  XmlDecl
} NodeType;



/* lexer GetToken states
*/
typedef enum
{
  LEX_CONTENT,
  LEX_GT,
  LEX_ENDTAG,
  LEX_STARTTAG,
  LEX_COMMENT,
  LEX_DOCTYPE,
  LEX_PROCINSTR,
  LEX_CDATA,
  LEX_SECTION,
  LEX_ASP,
  LEX_JSTE,
  LEX_PHP,
  LEX_XMLDECL
} LexerState;

/* ParseDocTypeDecl state constants */
typedef enum
{
  DT_INTERMEDIATE,
  DT_DOCTYPENAME,
  DT_PUBLICSYSTEM,
  DT_QUOTEDSTRING,
  DT_INTSUBSET
} ParseDocTypeDeclState;

/* content model shortcut encoding

   Descriptions are tentative.
*/
#define CM_UNKNOWN      0
/* Elements with no content. Map to HTML specification. */
#define CM_EMPTY        (1 << 0)
/* Elements that appear outside of "BODY". */
#define CM_HTML         (1 << 1)
/* Elements that can appear within HEAD. */
#define CM_HEAD         (1 << 2)
/* HTML "block" elements. */
#define CM_BLOCK        (1 << 3)
/* HTML "inline" elements. */
#define CM_INLINE       (1 << 4)
/* Elements that mark list item ("LI"). */
#define CM_LIST         (1 << 5)
/* Elements that mark definition list item ("DL", "DT"). */
#define CM_DEFLIST      (1 << 6)
/* Elements that can appear inside TABLE. */
#define CM_TABLE        (1 << 7)
/* Used for "THEAD", "TFOOT" or "TBODY". */
#define CM_ROWGRP       (1 << 8)
/* Used for "TD", "TH" */
#define CM_ROW          (1 << 9)
/* Elements whose content must be protected against white space movement.
   Includes some elements that can found in forms. */
#define CM_FIELD        (1 << 10)
/* Used to avoid propagating inline emphasis inside some elements
   such as OBJECT or APPLET. */
#define CM_OBJECT       (1 << 11)
/* Elements that allows "PARAM". */
#define CM_PARAM        (1 << 12)
/* "FRAME", "FRAMESET", "NOFRAMES". Used in ParseFrameSet. */
#define CM_FRAMES       (1 << 13)
/* Heading elements (h1, h2, ...). */
#define CM_HEADING      (1 << 14)
/* Elements with an optional end tag. */
#define CM_OPT          (1 << 15)
/* Elements that use "align" attribute for vertical position. */
#define CM_IMG          (1 << 16)
/* Elements with inline and block model. Used to avoid calling InlineDup. */
#define CM_MIXED        (1 << 17)
/* Elements whose content needs to be indented only if containing one 
   CM_BLOCK element. */
#define CM_NO_INDENT    (1 << 18)
/* Elements that are obsolete (such as "dir", "menu"). */
#define CM_OBSOLETE     (1 << 19)
/* User defined elements. Used to determine how attributes wihout value
   should be printed. */
#define CM_NEW          (1 << 20)
/* Elements that cannot be omitted. */
#define CM_OMITST       (1 << 21)

/* If the document uses just HTML 2.0 tags and attributes described
** it as HTML 2.0 Similarly for HTML 3.2 and the 3 flavors of HTML 4.0.
** If there are proprietary tags and attributes then describe it as
** HTML Proprietary. If it includes the xml-lang or xmlns attributes
** but is otherwise HTML 2.0, 3.2 or 4.0 then describe it as one of the
** flavors of Voyager (strict, loose or frameset).
*/

/* unknown */
#define xxxx                   0u

/* W3C defined HTML/XHTML family document types */
#define HT20                   1u
#define HT32                   2u
#define H40S                   4u
#define H40T                   8u
#define H40F                  16u
#define H41S                  32u
#define H41T                  64u
#define H41F                 128u
#define X10S                 256u
#define X10T                 512u
#define X10F                1024u
#define XH11                2048u
#define XB10                4096u

/* proprietary stuff */
#define VERS_SUN            8192u
#define VERS_NETSCAPE      16384u
#define VERS_MICROSOFT     32768u

/* special flag */
#define VERS_XML           65536u

/* HTML5 */
#define HT50              131072u
#define XH50              262144u

/* compatibility symbols */
#define VERS_UNKNOWN       (xxxx)
#define VERS_HTML20        (HT20)
#define VERS_HTML32        (HT32)
#define VERS_HTML40_STRICT (H40S|H41S|X10S)
#define VERS_HTML40_LOOSE  (H40T|H41T|X10T)
#define VERS_FRAMESET      (H40F|H41F|X10F)
#define VERS_XHTML11       (XH11)
#define VERS_BASIC         (XB10)
/* HTML5 */
#define VERS_HTML5         (HT50|XH50)

/* meta symbols */
#define VERS_HTML40        (VERS_HTML40_STRICT|VERS_HTML40_LOOSE|VERS_FRAMESET)
#define VERS_IFRAME        (VERS_HTML40_LOOSE|VERS_FRAMESET)
#define VERS_LOOSE         (VERS_HTML20|VERS_HTML32|VERS_IFRAME)
#define VERS_EVENTS        (VERS_HTML40|VERS_XHTML11)
#define VERS_FROM32        (VERS_HTML32|VERS_HTML40|HT50)
#define VERS_FROM40        (VERS_HTML40|VERS_XHTML11|VERS_BASIC|VERS_HTML5)
#define VERS_XHTML         (X10S|X10T|X10F|XH11|XB10|XH50)

/* strict */
#define VERS_STRICT        (VERS_HTML5|VERS_HTML40_STRICT)

/* all W3C defined document types */
#define VERS_ALL           (VERS_HTML20|VERS_HTML32|VERS_FROM40|XH50|HT50)

/* all proprietary types */
#define VERS_PROPRIETARY   (VERS_NETSCAPE|VERS_MICROSOFT|VERS_SUN)

/* Linked list of class names and styles
*/
struct _Style;
typedef struct _Style TagStyle;

struct _Style
{
    tmbstr tag;
    tmbstr tag_class;
    tmbstr properties;
    TagStyle *next;
};


/* Linked list of style properties
*/
struct _StyleProp;
typedef struct _StyleProp StyleProp;

struct _StyleProp
{
    tmbstr name;
    tmbstr value;
    StyleProp *next;
};




/* Attribute/Value linked list node
*/

struct _AttVal
{
    AttVal*           next;
    const Attribute*  dict;
    Node*             asp;
    Node*             php;
    int               delim;
    tmbstr            attribute;
    tmbstr            value;
};



/*
  Mosaic handles inlines via a separate stack from other elements
  We duplicate this to recover from inline markup errors such as:

     <i>italic text
     <p>more italic text</b> normal text

  which for compatibility with Mosaic is mapped to:

     <i>italic text</i>
     <p><i>more italic text</i> normal text

  Note that any inline end tag pop's the effect of the current
  inline start tag, so that </b> pop's <i> in the above example.
*/
struct _IStack
{
    IStack*     next;
    const Dict* tag;        /* tag's dictionary definition */
    tmbstr      element;    /* name (NULL for text nodes) */
    AttVal*     attributes;
};


/* HTML/XHTML/XML Element, Comment, PI, DOCTYPE, XML Decl,
** etc. etc.
*/

struct _Node
{
    Node*       parent;         /* tree structure */
    Node*       prev;
    Node*       next;
    Node*       content;
    Node*       last;

    AttVal*     attributes;
    const Dict* was;            /* old tag when it was changed */
    const Dict* tag;            /* tag's dictionary definition */

    tmbstr      element;        /* name (NULL for text nodes) */

    unsigned int        start;          /* start of span onto text array */
    unsigned int        end;            /* end of span onto text array */
    NodeType    type;           /* TextNode, StartTag, EndTag etc. */

    unsigned int        line;           /* current line of document */
    unsigned int        column;         /* current column of document */

    Bool        closed;         /* true if closed by explicit end tag */
    Bool        implicit;       /* true if inferred */
    Bool        linebreak;      /* true if followed by a line break */
};


/*
  The following are private to the lexer
  Use NewLexer() to create a lexer, and
  FreeLexer() to free it.
*/

struct _Lexer
{
    unsigned int lines;             /* lines seen */
    unsigned int columns;           /* at start of current token */
    Bool waswhite;          /* used to collapse contiguous white space */
    Bool pushed;            /* true after token has been pushed back */
    Bool insertspace;       /* when space is moved after end tag */
    Bool excludeBlocks;     /* Netscape compatibility */
    Bool exiled;            /* true if moved out of table */
    Bool isvoyager;         /* true if xmlns attribute on html element */
    unsigned int versions;          /* bit vector of HTML versions */
    unsigned int doctype;           /* version as given by doctype (if any) */
    unsigned int versionEmitted;    /* version of doctype emitted */
    Bool bad_doctype;       /* e.g. if html or PUBLIC is missing */
    unsigned int txtstart;          /* start of current node */
    unsigned int txtend;            /* end of current node */
    LexerState state;       /* state of lexer's finite state machine */

    Node* token;            /* last token returned by GetToken() */
    Node* itoken;           /* last duplicate inline returned by GetToken() */
    Node* root;             /* remember root node of the document */
    Node* parent;           /* remember parent node for CDATA elements */
    
    Bool seenEndBody;       /* true if a </body> tag has been encountered */
    Bool seenEndHtml;       /* true if a </html> tag has been encountered */

    /*
      Lexer character buffer

      Parse tree nodes span onto this buffer
      which contains the concatenated text
      contents of all of the elements.

      lexsize must be reset for each file.
    */
    tmbstr lexbuf;          /* MB character buffer */
    unsigned int lexlength;         /* allocated */
    unsigned int lexsize;           /* used */

    /* Inline stack for compatibility with Mosaic */
    Node* inode;            /* for deferring text node */
    IStack* insert;         /* for inferring inline tags */
    IStack* istack;
    unsigned int istacklength;      /* allocated */
    unsigned int istacksize;        /* used */
    unsigned int istackbase;        /* start of frame */

    TagStyle *styles;          /* used for cleaning up presentation markup */

    TidyAllocator* allocator; /* allocator */
};


/* Lexer Functions
*/

/* choose what version to use for new doctype */
int TY_(HTMLVersion)( TidyDocImpl* doc );

/* everything is allowed in proprietary version of HTML */
/* this is handled here rather than in the tag/attr dicts */

void TY_(ConstrainVersion)( TidyDocImpl* doc, unsigned int vers );

Bool TY_(IsWhite)(unsigned int c);
Bool TY_(IsDigit)(unsigned int c);
Bool TY_(IsLetter)(unsigned int c);
Bool TY_(IsHTMLSpace)(unsigned int c);
Bool TY_(IsNewline)(unsigned int c);
Bool TY_(IsNamechar)(unsigned int c);
Bool TY_(IsXMLLetter)(unsigned int c);
Bool TY_(IsXMLNamechar)(unsigned int c);

/* Bool IsLower(unsigned int c); */
Bool TY_(IsUpper)(unsigned int c);
unsigned int TY_(ToLower)(unsigned int c);
unsigned int TY_(ToUpper)(unsigned int c);

Lexer* TY_(NewLexer)( TidyDocImpl* doc );
void TY_(FreeLexer)( TidyDocImpl* doc );

/* store character c as UTF-8 encoded byte stream */
void TY_(AddCharToLexer)( Lexer *lexer, unsigned int c );

/*
  Used for elements and text nodes
  element name is NULL for text nodes
  start and end are offsets into lexbuf
  which contains the textual content of
  all elements in the parse tree.

  parent and content allow traversal
  of the parse tree in any direction.
  attributes are represented as a linked
  list of AttVal nodes which hold the
  strings for attribute/value pairs.
*/
Node* TY_(NewNode)( TidyAllocator* allocator, Lexer* lexer );


/* used to clone heading nodes when split by an <HR> */
Node* TY_(CloneNode)( TidyDocImpl* doc, Node *element );

/* free node's attributes */
void TY_(FreeAttrs)( TidyDocImpl* doc, Node *node );

/* doesn't repair attribute list linkage */
void TY_(FreeAttribute)( TidyDocImpl* doc, AttVal *av );

/* detach attribute from node */
void TY_(DetachAttribute)( Node *node, AttVal *attr );

/* detach attribute from node then free it
*/
void TY_(RemoveAttribute)( TidyDocImpl* doc, Node *node, AttVal *attr );

/*
  Free document nodes by iterating through peers and recursing
  through children. Set next to NULL before calling FreeNode()
  to avoid freeing peer nodes. Doesn't patch up prev/next links.
 */
void TY_(FreeNode)( TidyDocImpl* doc, Node *node );

Node* TY_(TextToken)( Lexer *lexer );

/* used for creating preformatted text from Word2000 */
Node* TY_(NewLineNode)( Lexer *lexer );

/* used for adding a &nbsp; for Word2000 */
Node* TY_(NewLiteralTextNode)(Lexer *lexer, ctmbstr txt );

void TY_(AddStringLiteral)( Lexer* lexer, ctmbstr str );
/* void AddStringLiteralLen( Lexer* lexer, ctmbstr str, int len ); */

/* find element */
Node* TY_(FindDocType)( TidyDocImpl* doc );
Node* TY_(FindHTML)( TidyDocImpl* doc );
Node* TY_(FindHEAD)( TidyDocImpl* doc );
Node* TY_(FindTITLE)(TidyDocImpl* doc);
Node* TY_(FindBody)( TidyDocImpl* doc );
Node* TY_(FindXmlDecl)(TidyDocImpl* doc);

/* Returns containing block element, if any */
Node* TY_(FindContainer)( Node* node );

/* add meta element for Tidy */
Bool TY_(AddGenerator)( TidyDocImpl* doc );

unsigned int TY_(ApparentVersion)( TidyDocImpl* doc );

ctmbstr TY_(HTMLVersionNameFromCode)( unsigned int vers, Bool isXhtml );

unsigned int TY_(HTMLVersionNumberFromCode)( unsigned int vers );

Bool TY_(WarnMissingSIInEmittedDocType)( TidyDocImpl* doc );

Bool TY_(SetXHTMLDocType)( TidyDocImpl* doc );


/* fixup doctype if missing */
Bool TY_(FixDocType)( TidyDocImpl* doc );

/* ensure XML document starts with <?xml version="1.0"?> */
/* add encoding attribute if not using ASCII or UTF-8 output */
Bool TY_(FixXmlDecl)( TidyDocImpl* doc );

Node* TY_(InferredTag)(TidyDocImpl* doc, TidyTagId id);

void TY_(UngetToken)( TidyDocImpl* doc );


/*
  modes for GetToken()

  MixedContent   -- for elements which don't accept PCDATA
  Preformatted   -- white space preserved as is
  IgnoreMarkup   -- for CDATA elements such as script, style
*/
typedef enum
{
  IgnoreWhitespace,
  MixedContent,
  Preformatted,
  IgnoreMarkup,
  OtherNamespace,
  CdataContent
} GetTokenMode;

Node* TY_(GetToken)( TidyDocImpl* doc, GetTokenMode mode );

void TY_(InitMap)(void);


/* create a new attribute */
AttVal* TY_(NewAttribute)( TidyDocImpl* doc );

/* create a new attribute with given name and value */
AttVal* TY_(NewAttributeEx)( TidyDocImpl* doc, ctmbstr name, ctmbstr value,
                             int delim );

/* insert attribute at the end of attribute list of a node */
void TY_(InsertAttributeAtEnd)( Node *node, AttVal *av );

/* insert attribute at the start of attribute list of a node */
void TY_(InsertAttributeAtStart)( Node *node, AttVal *av );

/*************************************
  In-line Stack functions
*************************************/


/* duplicate attributes */
AttVal* TY_(DupAttrs)( TidyDocImpl* doc, AttVal* attrs );

/*
  push a copy of an inline node onto stack
  but don't push if implicit or OBJECT or APPLET
  (implicit tags are ones generated from the istack)

  One issue arises with pushing inlines when
  the tag is already pushed. For instance:

      <p><em>text
      <p><em>more text

  Shouldn't be mapped to

      <p><em>text</em></p>
      <p><em><em>more text</em></em>
*/
void TY_(PushInline)( TidyDocImpl* doc, Node* node );

/* pop inline stack */
void TY_(PopInline)( TidyDocImpl* doc, Node* node );

Bool TY_(IsPushed)( TidyDocImpl* doc, Node* node );
Bool TY_(IsPushedLast)( TidyDocImpl* doc, Node *element, Node *node );

/*
  This has the effect of inserting "missing" inline
  elements around the contents of blocklevel elements
  such as P, TD, TH, DIV, PRE etc. This procedure is
  called at the start of ParseBlock. when the inline
  stack is not empty, as will be the case in:

    <i><h1>italic heading</h1></i>

  which is then treated as equivalent to

    <h1><i>italic heading</i></h1>

  This is implemented by setting the lexer into a mode
  where it gets tokens from the inline stack rather than
  from the input stream.
*/
int TY_(InlineDup)( TidyDocImpl* doc, Node *node );

/*
 defer duplicates when entering a table or other
 element where the inlines shouldn't be duplicated
*/
void TY_(DeferDup)( TidyDocImpl* doc );
Node* TY_(InsertedToken)( TidyDocImpl* doc );

/* stack manipulation for inline elements */
Bool TY_(SwitchInline)( TidyDocImpl* doc, Node* element, Node* node );
Bool TY_(InlineDup1)( TidyDocImpl* doc, Node* node, Node* element );

#ifdef __cplusplus
}
#endif


#endif /* __LEXER_H__ */
#ifndef __TIDY_MAPPED_IO_H__
#define __TIDY_MAPPED_IO_H__

/* Interface to mmap style I/O

   (c) 2006 (W3C) MIT, ERCIM, Keio University
   See tidy.h for the copyright notice.

*/

#if defined(_WIN32)
int TY_(DocParseFileWithMappedFile)( TidyDocImpl* doc, ctmbstr filnam );
#endif

#endif /* __TIDY_MAPPED_IO_H__ */
#ifndef __MESSAGE_H__
#define __MESSAGE_H__

/******************************************************************************
 * @file
 * Provides General Message Writing Routines
 *
 * This module handles LibTidy's high level output routines, as well as
 * provides lookup functions and management for keys used for retrieval
 * of these messages.
 *
 * LibTidy emits two general types of output:
 *
 *  - Reports, which contain data relating to what Tidy discovered in your
 *    source file, and/or what Tidy did to your source file. In some cases
 *    general information about your source file is emitted as well. Reports
 *    are emitted in the current output buffer, but LibTidy users will probably
 *    prefer to hook into a callback in order to take advantage of the data
 *    that are available in a more flexible way.
 *
 *  - Dialogue, consisting of footnotes related to your source file, and of
 *    general information that's not related to your source file in particular.
 *    This is also written to the current output buffer when appropriate, and
 *    available via callbacks.
 *
 * Report information typically takes the form of a warning, an error, info,
 * etc., and the output routines keep track of the count of these.
 *
 * The preferred way of handling Tidy diagnostics output is either
 *   - define a new output sink, or
 *   - use a message filter callback routine.
 *
 * @author  HTACG, et al (consult git log)
 * 
 * @copyright
 *     Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
 *     Institute of Technology, European Research Consortium for Informatics
 *     and Mathematics, Keio University) and HTACG.
 * @par
 *     All Rights Reserved.
 * @par
 *     See `tidy.h` for the complete license.
 *
 * @date Additional updates: consult git log
 *
 ******************************************************************************/

/* #include "forward.h" */
/* #include "config.h" */

/** @addtogroup internal_api */
/** @{ */


/***************************************************************************//**
 ** @defgroup message_releaseinfo Tidy Release Information
 **
 ** These functions return information about the current release version date
 ** and version number. Note that the latest release date or the highest
 ** version number alone do not guarantee the latest Tidy release, as we may
 ** backport important fixes to older releases of Tidy.
 **
 ** @{
 ******************************************************************************/

/**
 *  Returns the release date of this instance of HTML Tidy.
 */
ctmbstr TY_(ReleaseDate)(void);

/** 
 *  Returns the release version of this instance of HTML Tidy.
 */
ctmbstr TY_(tidyLibraryVersion)(void);


/** @} message_releaseinfo group */


/***************************************************************************//**
 ** @defgroup message_reporting Report and Dialogue Writing Functions
 **
 ** These simple functions perform the vast majority of Tidy's output, and
 ** one these should be your first choice when adding your own output.
 **
 ** A report is typically diagnostic output that is generated each time Tidy
 ** detects an issue in your document or makes a change. A dialogue is a piece
 ** of information such as a summary, a footnote, or other non-tabular data.
 ** Some of these functions emit multiple reports or dialogue in order to
 ** effect a summary.
 **
 ** @{
 ******************************************************************************/

/** @name General Report Writing 
 ** If one of the convenience reporting functions does not fit your required
 ** message signature, then this designated reporting function will fit the
 ** bill. Be sure to see if a message formatter exists that can handle the
 ** variable arguments.
 */
/** @{ */


/**
 *  The designated report writing function. When a proper formatter exists,
 *  this one function can hanle all report output.
 */
void TY_(Report)(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, ...);


/** @} */
/** @name Convenience Reporting Functions
 ** These convenience reporting functions are able to handle the bulk of Tidy's
 ** necessary reporting, and avoid the danger of using a variadic if you are
 ** unfamiliar with Tidy.
 */
/** @{ */


void TY_(ReportAccessError)( TidyDocImpl* doc, Node* node, unsigned int code );
void TY_(ReportAttrError)(TidyDocImpl* doc, Node *node, AttVal *av, unsigned int code);
void TY_(ReportBadArgument)( TidyDocImpl* doc, ctmbstr option );
void TY_(ReportEntityError)( TidyDocImpl* doc, unsigned int code, ctmbstr entity, int c );
void TY_(ReportFileError)( TidyDocImpl* doc, ctmbstr file, unsigned int code );
void TY_(ReportEncodingError)(TidyDocImpl* doc, unsigned int code, unsigned int c, Bool discarded);
void TY_(ReportEncodingWarning)(TidyDocImpl* doc, unsigned int code, unsigned int encoding);
void TY_(ReportMissingAttr)( TidyDocImpl* doc, Node* node, ctmbstr name );
void TY_(ReportSurrogateError)(TidyDocImpl* doc, unsigned int code, unsigned int c1, unsigned int c2);
void TY_(ReportUnknownOption)( TidyDocImpl* doc, ctmbstr option );


/** @} */
/** @name General Dialogue Writing
 ** These functions produce dialogue output such as individual messages, or
 ** several messages in summary form.
 */
/** @{ */


/**
 *  Emits a single dialogue message, and is capable of accepting a variadic
 *  that is passed to the correct message formatter as needed.
 */
void TY_(Dialogue)( TidyDocImpl* doc, unsigned int code, ... );


/** @} */
/** @name Output Dialogue Information */
/** @{ */


/** 
 *  Outputs the footnotes and other dialogue information after document cleanup
 *  is complete. LibTidy users might consider capturing these individually in
 *  the message callback rather than capturing this entire buffer.
 *  Called by `tidyErrorSummary()`, in console.
 *  @todo: This name is a bit misleading and should probably be renamed to
 *  indicate its focus on printing footnotes.
 */
void TY_(ErrorSummary)( TidyDocImpl* doc );


/** 
 *  Outputs document HTML version and version-related information as the final
 *  report(s) in the report table.
 *  Called by `tidyRunDiagnostics()`, from console.
 *  Called by `tidyDocReportDoctype()`, currently unused.
 */
void TY_(ReportMarkupVersion)( TidyDocImpl* doc );


/**
 *  Reports the number of warnings and errors found in the document as dialogue
 *  inforation.
 *  Called by `tidyRunDiagnostics()`, from console.
 */
void TY_(ReportNumWarnings)( TidyDocImpl* doc );


/** @} */
/** @} message_reporting group */


/***************************************************************************//**
 ** @defgroup message_mutinging Message Muting
 **
 ** Message types included in the `mute` option will be be printed in
 ** messageOut().
 **
 ** @{
 ******************************************************************************/

/** Maintains a list of messages not to display. */
typedef struct _mutedMessages {
    tidyStrings* list; /**< A list of messages that won't be output. */
    unsigned int count;        /**< Current count of the list. */
    unsigned int capacity;     /**< Current capacity of the list. */
} TidyMutedMessages;


/** Frees the list of muted messages.
 ** @param doc The Tidy document.
 */
void TY_(FreeMutedMessageList)( TidyDocImpl* doc );

/** Adds a new message ID to the list of muted messages.
 ** @param doc The Tidy document.
 ** @param opt The option that is defining the muted message.
 ** @param name The message code as a string.
 */
void TY_(DefineMutedMessage)( TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name );

/** Start an iterator for muted messages.
 ** @param doc The Tidy document.
 ** @returns Returns an iterator token.
 */
TidyIterator TY_(getMutedMessageList)( TidyDocImpl* doc );

/** Get the next priority attribute.
 ** @param doc The Tidy document.
 ** @param iter The iterator token.
 ** @returns The next priority attribute.
 */
ctmbstr TY_(getNextMutedMessage)( TidyDocImpl* doc, TidyIterator* iter );


/** @} message_muting group */


/***************************************************************************//**
 ** @defgroup message_keydiscovery Key Discovery
 **
 ** LibTidy users may want to use `TidyReportCallback` to enable their own
 ** localization lookup features. Because Tidy's report codes are enums the
 ** specific values can change over time. Using these functions provides the
 ** ability for LibTidy users to use LibTidy's enum values as strings for
 ** lookup purposes.
 **
 ** @{
 ******************************************************************************/

/**
 *  This function returns a string representing the enum value name that can
 *  be used as a lookup key independent of changing string values. 
 *  `TidyReportCallback` will return this general string as the report 
 *  message key.
 */
ctmbstr TY_(tidyErrorCodeAsKey)(unsigned int code);

/**
 *  Given an error code string, return the integer value of it, or UINT_MAX
 *  as an error flag.
 */
unsigned int TY_(tidyErrorCodeFromKey)(ctmbstr code);


/**
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's list of error codes that can be return with
 *  `TidyReportFilter3`.
 *  Items can be retrieved with getNextErrorCode();
 */
TidyIterator TY_(getErrorCodeList)(void);

/**
 *  Returns the next error code having initialized the iterator
 *  with `getErrorCodeList()`. You can use tidyErrorCodeAsKey
 *  to determine the key for this value.
 */
unsigned int TY_(getNextErrorCode)( TidyIterator* iter );


/** @} message_keydiscovery group */
/** @} internal_api addtogroup */



/* accessibility flaws */

#define BA_MISSING_IMAGE_ALT       1
#define BA_MISSING_LINK_ALT        2
#define BA_MISSING_SUMMARY         4
#define BA_MISSING_IMAGE_MAP       8
#define BA_USING_FRAMES            16
#define BA_USING_NOFRAMES          32
#define BA_INVALID_LINK_NOFRAMES   64  /* WAI [6.5.1.4] */  
#define BA_WAI                     (1 << 31)

/* presentation flaws */

#define USING_SPACER            1
#define USING_LAYER             2
#define USING_NOBR              4
#define USING_FONT              8
#define USING_BODY              16

/* badchar bit field */

#define BC_VENDOR_SPECIFIC_CHARS   1
#define BC_INVALID_SGML_CHARS      2
#define BC_INVALID_UTF8            4
#define BC_INVALID_UTF16           8
#define BC_ENCODING_MISMATCH       16 /* fatal error */
#define BC_INVALID_URI             32
#define BC_INVALID_NCR             64

/* other footnote bit field (temporary until formalized) */

#define FN_TRIM_EMPTY_ELEMENT     1

/* Lexer and I/O Macros */

#define REPLACED_CHAR           0
#define DISCARDED_CHAR          1


#endif /* __MESSAGE_H__ */
#ifndef messageobj_h
#define messageobj_h

/**************************************************************************//**
 * @file
 * Provides an external, extensible API for message reporting.
 *
 * This module implements the `_TidyMessageImpl` structure (declared in
 * `tidy-int.h`) in order to abstract the reporting of reports and dialogue
 * from the rest of Tidy, and to enable a robust and extensible API for
 * message interrogation by LibTidy users.
 *
 * @author    Jim Derry
 * @copyright Copyright (c) 2017 HTACG. See tidy.h for license.
 * @date      Created 2017-March-10
 *
 ******************************************************************************/

/* #include "forward.h" */

/** @addtogroup internal_api */
/** @{ */


/** @defgroup messageobj_instantiation Message Creation and Releasing */
/** @{ */


/** Creates a TidyMessageImpl, but without line numbers, such as used for
 ** information report output.
 */
TidyMessageImpl *TY_(tidyMessageCreate)( TidyDocImpl *doc,
                                         unsigned int code,
                                         TidyReportLevel level,
                                         ... );

/** Creates a TidyMessageImpl, using the line and column from the provided
 ** Node as the message position source.
 */
TidyMessageImpl *TY_(tidyMessageCreateWithNode)( TidyDocImpl *doc,
                                                 Node *node,
                                                 unsigned int code,
                                                 TidyReportLevel level,
                                                 ... );

/** Creates a TidyMessageImpl, using the line and column from the provided
 ** document's Lexer as the message position source.
 */
TidyMessageImpl *TY_(tidyMessageCreateWithLexer)( TidyDocImpl *doc,
                                                  unsigned int code,
                                                  TidyReportLevel level,
                                                  ... );

/** Deallocates a TidyMessageImpl in order to free up its allocated memory
 ** when you're done using it.
 */
void TY_(tidyMessageRelease)( TidyMessageImpl *message );


/** @} end messageobj_instantiation group */
/** @defgroup messageobj_message_api Report and Dialogue API */
/** @{ */


/** get the document the message came from. */
TidyDocImpl* TY_(getMessageDoc)( TidyMessageImpl message );

/** get the message key code. */
unsigned int TY_(getMessageCode)( TidyMessageImpl message );

/** get the message key string. */
ctmbstr TY_(getMessageKey)( TidyMessageImpl message );

/** get the line number the message applies to. */
int TY_(getMessageLine)( TidyMessageImpl message );

/** get the column the message applies to. */
int TY_(getMessageColumn)( TidyMessageImpl message );

/** get the TidyReportLevel of the message. */
TidyReportLevel TY_(getMessageLevel)( TidyMessageImpl message );

/** get whether or not the message was muted by the configuration. */
Bool TY_(getMessageIsMuted)( TidyMessageImpl message );

/** the built-in format string */
ctmbstr TY_(getMessageFormatDefault)( TidyMessageImpl message );

/** the localized format string */
ctmbstr TY_(getMessageFormat)( TidyMessageImpl message );

/** the message, formatted, default language */
ctmbstr TY_(getMessageDefault)( TidyMessageImpl message );

/** the message, formatted, localized */
ctmbstr TY_(getMessage)( TidyMessageImpl message );

/** the position part, default language */
ctmbstr TY_(getMessagePosDefault)( TidyMessageImpl message );

/** the position part, localized */
ctmbstr TY_(getMessagePos)( TidyMessageImpl message );

/** the prefix part, default language */
ctmbstr TY_(getMessagePrefixDefault)( TidyMessageImpl message );

/** the prefix part, localized */
ctmbstr TY_(getMessagePrefix)( TidyMessageImpl message );

/** the complete message, as would be output in the CLI */
ctmbstr TY_(getMessageOutputDefault)( TidyMessageImpl message );

/* the complete message, as would be output in the CLI, localized */
ctmbstr TY_(getMessageOutput)( TidyMessageImpl message );


/** @} end messageobj_message_api group */
/** @defgroup messageobj_args_api Report Arguments Interrogation API */
/** @{ */

/**
 *  Initializes the TidyIterator to point to the first item in the message's
 *  argument. Use `TY_(getNextMEssageArgument)` to get an opaque instance of
 *  `TidyMessageArgument` for which the subsequent interrogators will be of use.
 */
TidyIterator TY_(getMessageArguments)( TidyMessageImpl message );

/**
 *  Returns the next `TidyMessageArgument`, for the given message, which can
 *  then be interrogated with the API, and advances the iterator.
 */
TidyMessageArgument TY_(getNextMessageArgument)( TidyMessageImpl message, TidyIterator* iter );


/**
 *  Returns the `TidyFormatParameterType` of the given message argument.
 */
TidyFormatParameterType TY_(getArgType)( TidyMessageImpl message, TidyMessageArgument* arg );


/**
 *  Returns the format specifier of the given message argument. The memory for
 *  this string is cleared upon termination of the callback, so do be sure to
 *  make your own copy.
 */
ctmbstr TY_(getArgFormat)( TidyMessageImpl message, TidyMessageArgument* arg );


/**
 *  Returns the string value of the given message argument. An assertion
 *  will be generated if the argument type is not a string.
 */
ctmbstr TY_(getArgValueString)( TidyMessageImpl message, TidyMessageArgument* arg );


/**
 *  Returns the unsigned integer value of the given message argument. An
 *  assertion will be generated if the argument type is not an unsigned
 *  integer.
 */
unsigned int TY_(getArgValueUInt)( TidyMessageImpl message, TidyMessageArgument* arg );


/**
 *  Returns the integer value of the given message argument. An assertion
 *  will be generated if the argument type is not an integer.
 */
int TY_(getArgValueInt)( TidyMessageImpl message, TidyMessageArgument* arg );


/**
 *  Returns the double value of the given message argument. An assertion
 *  will be generated if the argument type is not a double.
 */
double TY_(getArgValueDouble)( TidyMessageImpl message, TidyMessageArgument* arg );


/** @} end messageobj_args_api group */
/** @} end internal_api group */

#endif /* messageobj_h */
#ifndef __PARSER_H__
#define __PARSER_H__

/**************************************************************************//**
 * @file
 * HTML and XML Parsers.
 *
 * Tidy's HTML parser corrects many conditions and enforces certain user
 * preferences during the parsing process. The XML parser produces a tree
 * of nodes useful to Tidy but also suitable for use in other XML processing
 * applications.
 *
 * @author  HTACG, et al (consult git log)
 *
 * @copyright
 *     Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
 *     Institute of Technology, European Research Consortium for Informatics
 *     and Mathematics, Keio University) and HTACG.
 * @par
 *     All Rights Reserved.
 * @par
 *     See `tidy.h` for the complete license.
 *
 * @date Additional updates: consult git log
 *
 ******************************************************************************/

/* #include "forward.h" */

/** @addtogroup internal_api */
/** @{ */


/***************************************************************************//**
 ** @defgroup parser_h HTML and XML Parsing
 **
 ** These functions and structures form the internal API for document
 ** parsing.
 **
 ** @{
 ******************************************************************************/


/**
 *  Is used to perform a node integrity check recursively after parsing
 *  an HTML or XML document.
 *  @note Actual performance of this check can be disabled by defining the
 *  macro NO_NODE_INTEGRITY_CHECK.
 *  @param node The root node for the integrity check.
 *  @returns Returns yes or no indicating integrity of the node structure.
 */
Bool TY_(CheckNodeIntegrity)(Node *node);


/**
 *  Indicates whether or not a text node ends with a space or newline.
 *  @note Implementation of this method is found in `pprint.c` for
 *  some reason.
 *  @param lexer A reference to the lexer used to lex the document.
 *  @param node The node to check.
 *  @returns The result of the check.
 */
Bool TY_(TextNodeEndWithSpace)( Lexer *lexer, Node *node );


/**
 *  Used to check if a node uses CM_NEW, which determines how attributes
 *  without values should be printed. This was introduced to deal with
 *  user-defined tags e.g. ColdFusion.
 *  @param node The node to check.
 *  @returns The result of the check.
 */
Bool TY_(IsNewNode)(Node *node);


/**
 *  Transforms a given node to another element, for example, from a `p`
 *  to a `br`.
 *  @param doc The document which the node belongs to.
 *  @param node The node to coerce.
 *  @param tid The tag type to coerce the node into.
 *  @param obsolete If the old node was obsolete, a report will be generated.
 *  @param expected If the old node was not expected to be found in this
 *    particular location, a report will be generated.
 */
void TY_(CoerceNode)(TidyDocImpl* doc, Node *node, TidyTagId tid, Bool obsolete, Bool expected);


/**
 *  Extract a node and its children from a markup tree.
 *  @param node The node to remove.
 *  @returns Returns the removed node.
 */
Node *TY_(RemoveNode)(Node *node);


/**
 *  Remove node from markup tree and discard it.
 *  @param doc The Tidy document from which to discarb the node.
 *  @param element The node to discard.
 *  @returns Returns the next node.
 */
Node *TY_(DiscardElement)( TidyDocImpl* doc, Node *element);


/**
 *  Insert node into markup tree as the firt element of content of element.
 *  @param element The new destination node.
 *  @param node The node to insert.
 */
void TY_(InsertNodeAtStart)(Node *element, Node *node);


/**
 *  Insert node into markup tree as the last element of content of element.
 *  @param element The new destination node.
 *  @param node The node to insert.
 */
void TY_(InsertNodeAtEnd)(Node *element, Node *node);


/**
 *  Insert node into markup tree before element.
 *  @param element The node before which the node is inserted.
 *  @param node The node to insert.
 */
void TY_(InsertNodeBeforeElement)(Node *element, Node *node);


/**
 *  Insert node into markup tree after element.
 *  @param element The node after which the node is inserted.
 *  @param node The node to insert.
 */
void TY_(InsertNodeAfterElement)(Node *element, Node *node);


/**
 *  Trims a single, empty element, returning the next node.
 *  @param doc The Tidy document.
 *  @param element The element to trim.
 *  @returns Returns the next node.
 */
Node *TY_(TrimEmptyElement)( TidyDocImpl* doc, Node *element );


/**
 *  Trims a tree of empty elements recursively, returning the next node.
 *  @param doc The Tidy document.
 *  @param node The element to trim.
 *  @returns Returns the next node.
 */
Node* TY_(DropEmptyElements)(TidyDocImpl* doc, Node* node);


/**
 *  Indicates whether or not a text node is blank, meaning that it consists
 *  of nothing, or a single space.
 *  @param lexer The lexer used to lex the document.
 *  @param node The node to test.
 *  @returns Returns the result of the test.
 */
Bool TY_(IsBlank)(Lexer *lexer, Node *node);


/**
 *  Indicates whether or not a node is declared as containing javascript
 *  code.
 *  @param node The node to test.
 *  @returns Returns the result of the test.
 */
Bool TY_(IsJavaScript)(Node *node);


/**
 *  Parses a document after lexing using the HTML parser. It begins by properly
 *  configuring the overall HTML structure, and subsequently processes all
 *  remaining nodes. HTML is the root node.
 *  @param doc The Tidy document.
 */
void TY_(ParseDocument)( TidyDocImpl* doc );


/**
 *  Indicates whether or not whitespace is to be preserved in XHTML/XML
 *  documents.
 *  @param doc The Tidy document.
 *  @param element The node to test.
 *  @returns Returns the result of the test.
 */
Bool TY_(XMLPreserveWhiteSpace)( TidyDocImpl* doc, Node *element );


/**
 *  Parses a document after lexing using the XML parser.
 *  @param doc The Tidy document.
 */
void TY_(ParseXMLDocument)( TidyDocImpl* doc );


/** @} end parser_h group */
/** @} end internal_api group */

#endif /* __PARSER_H__ */

#ifndef __PPRINT_H__
#define __PPRINT_H__

/* pprint.h -- pretty print parse tree  
  
   (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
   See tidy.h for the copyright notice.
  
*/

/* #include "forward.h" */

/*
  Block-level and unknown elements are printed on
  new lines and their contents indented 2 spaces

  Inline elements are printed inline.

  Inline content is wrapped on spaces (except in
  attribute values or preformatted text, after
  start tags and before end tags
*/

#define NORMAL        0u
#define PREFORMATTED  1u
#define COMMENT       2u
#define ATTRIBVALUE   4u
#define NOWRAP        8u
#define CDATA         16u


/* The pretty printer keeps at most two lines of text in the
** buffer before flushing output.  We need to capture the
** indent state (indent level) at the _beginning_ of _each_
** line, not the end of just the second line.
**
** We must also keep track "In Attribute" and "In String"
** states at the _end_ of each line, 
*/

typedef struct _TidyIndent
{
    int spaces;
    int attrValStart;
    int attrStringStart;
} TidyIndent;

typedef struct _TidyPrintImpl
{
    TidyAllocator *allocator; /* Allocator */

    unsigned int *linebuf;
    unsigned int lbufsize;
    unsigned int linelen;
    unsigned int wraphere;
    unsigned int line;
  
    unsigned int ixInd;
    TidyIndent indent[2];  /* Two lines worth of indent state */
} TidyPrintImpl;


void TY_(InitPrintBuf)( TidyDocImpl* doc );
void TY_(FreePrintBuf)( TidyDocImpl* doc );

void TY_(PFlushLine)( TidyDocImpl* doc, unsigned int indent );


/* print just the content of the body element.
** useful when you want to reuse material from
** other documents.
** 
** -- Sebastiano Vigna <vigna@dsi.unimi.it>
*/

void TY_(PrintBody)( TidyDocImpl* doc );       /* you can print an entire document */
                                          /* node as body using PPrintTree() */

void TY_(PPrintTree)( TidyDocImpl* doc, unsigned int mode, unsigned int indent, Node *node );

void TY_(PPrintXMLTree)( TidyDocImpl* doc, unsigned int mode, unsigned int indent, Node *node );

/*\
 * 20150515 - support using tabs instead of spaces
\*/
void TY_(PPrintTabs)(void);
void TY_(PPrintSpaces)(void);

#endif /* __PPRINT_H__ */
#ifndef _SPRTF_HXX_
#define _SPRTF_HXX_

/**************************************************************************//**
 * @file
 * Log output utility - part of the HTML Tidy project
 *
 * @author  Geoff R. McLane [reports _at_ geoffair _dot_ info]
 *
 * @copyright
 *     Copyright (c) 1998-2017 Geoff R. McLane and HTACG.
 * @par
 *     All Rights Reserved.
 * @par
 *     See `tidy.h` for the complete license.
 *
 * @date 2017/02/12 17:06:02 Revision 1.0.2  geoff - correct license and coding style
 * @date 2012/11/06 13:01:25 Revision 1.0.1  geoff
 * @date 2012/10/17 00:00:00 Revision 1.0.0  geoff
 * @date Additional updates: consult git log
 *
 ******************************************************************************/

/* #include "tidyplatform.h" */

#ifdef   __cplusplus
extern "C" {
#endif
#ifdef ENABLE_DEBUG_LOG
    /*=============================================================================
    * EXTRA Debugging, and information aid.
    *
    *  When building and defining the ENABLE_DEBUG_LOG macro, Tidy will output
    *  extensive debug information. In addition to this macro, you can supply
    *  cmake build flags for additional diagnostic information:
    *    - -DENABLE_ALLOC_DEBUG:BOOL=ON   - DEBUG_ALLOCATION
    *    - -DENABLE_MEMORY_DEBUG:BOOL=ON  - DEBUG_MEMORY
    *    - -DENABLE_CRTDBG_MEMORY:BOOL=ON - _CRTDBG_MAP_ALLOC (WIN32 only)
    *
    *  _MSC_VER Only - ENABLE_DEBUG_LOG is automatically enabled in the Debug
    *  build, unless DISABLE_DEBUG_LOG is defined. See 'tidyplatform.h'
    *
    *  You can use DEBUG_LOG( SPRTF() ) to avoid #ifdef ENABLE_DEBUG_LOG for
    *  one-liners.
    *
    *  This EXTRA Debug information is also written to a 'temptidy.txt' log
    *  file, for review, and analysis.
    *
    *===========================================================================*/

#ifndef SPRTF
#  define SPRTF sprtf
#endif

#ifdef _MSC_VER
#  define MCDECL _cdecl
#else
#  define MCDECL
#endif

TIDY_EXPORT int add_std_out( int val );
TIDY_EXPORT int add_sys_time( int val );
TIDY_EXPORT int add_sys_date( int val );

TIDY_EXPORT int add_screen_out( int val );
TIDY_EXPORT int add_list_out( int val );
TIDY_EXPORT int add_append_log( int val );

TIDY_EXPORT int open_log_file( void );
TIDY_EXPORT void close_log_file( void );
TIDY_EXPORT void set_log_file( char * nf, int open );
TIDY_EXPORT char * get_log_file( void );

TIDY_EXPORT int MCDECL sprtf( const char *pf, ... );
#define M_MAX_SPRTF 2048
TIDY_EXPORT int direct_out_it( char *cp );

TIDY_EXPORT char *GetNxtBuf(void);

#define EndBuf(a)   ( a + strlen(a) )

TIDY_EXPORT char *get_date_stg(void);
TIDY_EXPORT char *get_time_stg(void);
TIDY_EXPORT char *get_date_time_stg(void);

#ifdef _MSC_VER
TIDY_EXPORT int gettimeofday(struct timeval *tp, void *tzp);
#endif

#  define DEBUG_LOG(ARG) do { ARG; } while(0)

#else
#  define DEBUG_LOG(ARG)
#endif

#ifdef   __cplusplus
}
#endif
#endif /* #ifndef _SPRTF_HXX_*/
/* eof - sprtf.h */
#ifndef __TAGS_H__
#define __TAGS_H__

/**************************************************************************//**
 * @file
 * Recognize HTML Tags.
 *
 * The HTML tags are stored as 8 bit ASCII strings.
 * Use lookupw() to find a tag given a wide char string.
 *
 * @author  HTACG, et al (consult git log)
 *
 * @copyright
 *     Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
 *     Institute of Technology, European Research Consortium for Informatics
 *     and Mathematics, Keio University) and HTACG.
 * @par
 *     All Rights Reserved.
 * @par
 *     See `tidy.h` for the complete license.
 *
 * @date Additional updates: consult git log
 *
 ******************************************************************************/

/* #include "forward.h" */
/* #include "attrdict.h" */

/** @addtogroup internal_api */
/** @{ */


/***************************************************************************//**
 ** @defgroup tags_h HTML Tags
 **
 ** This module organizes all of Tidy's HTML tag operations, such as parsing
 ** tags, defining tags, and user-defined tags.
 **
 ** @{
 ******************************************************************************/


/** @name Basic Structures and Tag Operations.
 ** These structures form the backbone of Tidy tag processing, and the
 ** functions in this group provide basic operations with tags and nodes.
 */
/** @{ */


/** This enumeration defines the types of user-defined tags that can be
 ** created.
 */
typedef enum
{
    tagtype_null = 0,   /**< First item marker. */
    tagtype_empty = 1,  /**< Tag is an empty element. */
    tagtype_inline = 2, /**< Tag is an inline element. */
    tagtype_block = 4,  /**< Tag is a block level element. */
    tagtype_pre = 8     /**< Tag is a preformatted tag. */
} UserTagType;


/** This typedef describes a function to be used to parse HTML of a Tidy tag.
 */
typedef void (Parser)( TidyDocImpl* doc, Node *node, GetTokenMode mode );


/** This typedef describes a function be be used to check the attributes
 ** of a Tidy tag.
 */
typedef void (CheckAttribs)( TidyDocImpl* doc, Node *node );


/** Defines a dictionary entry for a single Tidy tag, including all of the
 ** relevant information that it requires.
 */
struct _Dict
{
    TidyTagId           id;       /**< Identifier for this tag. */
    tmbstr              name;     /**< The tag name. */
    unsigned int                versions; /**< Accumulates potential HTML versions. See TY_(ConstrainVersion). */
    AttrVersion const * attrvers; /**< Accumulates potential HTML versions for attributes. */
    unsigned int                model;    /**< Indicates the relevant content models for the tag. See lexer.h; there is no enum. */
    Parser*             parser;   /**< Specifies the parser to use for this tag. */
    CheckAttribs*       chkattrs; /**< Specifies the function to check this tag's attributes. */
    Dict*               next;     /**< Link to next tag. */
};


/** This enum indicates the maximum size of the has table for tag hash lookup.
 */
enum
{
    ELEMENT_HASH_SIZE=178u  /**< Maximum number of tags in the hash table. */
};


/** This structure provide hash lookup for Tidy tags.
 */
typedef struct _DictHash
{
    Dict const*         tag;   /**< The current tag. */
    struct _DictHash*   next;  /**< The next tag. */
} DictHash;


/** This structure consists of the lists of all tags known to Tidy.
 */
typedef struct _TidyTagImpl
{
    Dict* xml_tags;                        /**< Placeholder for all xml tags. */
    Dict* declared_tag_list;               /**< User-declared tags. */
    DictHash* hashtab[ELEMENT_HASH_SIZE];  /**< All of Tidy's built-in tags. */
} TidyTagImpl;


/** Coordinates Config update and Tags data.
 ** @param doc The Tidy document.
 ** @param opt The option the tag is intended for.
 ** @param name The name of the new tag.
 */
void TY_(DeclareUserTag)( TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name );


/** Interface for finding a tag by TidyTagId.
 ** @param tid The TidyTagId to search for.
 ** @returns An instance of a Tidy tag.
 */
const Dict* TY_(LookupTagDef)( TidyTagId tid );

/** Assigns the node's tag.
 ** @param doc The Tidy document.
 ** @param node The node to assign the tag to.
 ** @returns Returns a bool indicating whether or not the tag was assigned.
 */
Bool    TY_(FindTag)( TidyDocImpl* doc, Node *node );


/** Finds the parser function for a given node.
 ** @param doc The Tidy document.
 ** @param node The node to lookup.
 ** @returns The parser for the given node.
 */
Parser* TY_(FindParser)( TidyDocImpl* doc, Node *node );


/** Defines a new user-defined tag.
 ** @param doc The Tidy document.
 ** @param tagType The type of user-defined tag to define.
 ** @param name The name of the new tag.
 */
void    TY_(DefineTag)( TidyDocImpl* doc, UserTagType tagType, ctmbstr name );


/** Frees user-defined tags of the given type, or all user tags in given
 ** `tagtype_null`.
 ** @param doc The Tidy document.
 ** @param tagType The type of tag to free, or `tagtype_null` to free all
 **        user-defined tags.
 */
void    TY_(FreeDeclaredTags)( TidyDocImpl* doc, UserTagType tagType );


/** Initiates an iterator for a list of user-declared tags, including autonomous
 ** custom tags detected in the document if @ref TidyUseCustomTags is not set to
 ** **no**.
 ** @param doc An instance of a TidyDocImp to query.
 ** @result Returns a TidyIterator, which is a token used to represent the
 **         current position in a list within LibTidy.
 */
TidyIterator   TY_(GetDeclaredTagList)( TidyDocImpl* doc );


/** Given a valid TidyIterator initiated with TY_(GetDeclaredTagList)(),
 ** returns a string representing a user-declared or autonomous custom tag.
 ** @remark Specifying tagType limits the scope of the tags to one of
 **         @ref UserTagType types. Note that autonomous custom tags (if used)
 **         are added to one of these option types, depending on the value of
 **         @ref TidyUseCustomTags.
 ** @param doc The Tidy document.
 ** @param tagType The type of tag to iterate through.
 ** @param iter The iterator token provided initially by
 **        TY_(GetDeclaredTagList)().
 ** @result A string containing the next tag.
 */
ctmbstr        TY_(GetNextDeclaredTag)( TidyDocImpl* doc, UserTagType tagType,
                                        TidyIterator* iter );


/** Initializes tags and tag structures for the given Tidy document.
 ** @param doc The Tidy document.
 */
void TY_(InitTags)( TidyDocImpl* doc );


/** Frees the tags and structures used by Tidy for tags.
 ** @param doc The Tidy document.
 */
void TY_(FreeTags)( TidyDocImpl* doc );


/** Tidy defaults to HTML5 mode. If the <!DOCTYPE ...> is found to NOT be
 ** HTML5, then adjust the tags table to HTML4 mode.
 ** @param doc The Tidy document.
 */
void TY_(AdjustTags)( TidyDocImpl *doc );


/** Reset the tags table back to default HTML5 mode.
 ** @param doc The Tidy document.
 */
void TY_(ResetTags)( TidyDocImpl *doc );


/** Indicates whether or not the Tidy is procesing in HTML5 mode.
 ** @param doc The Tidy document.
 ** @returns Returns `yes` if processing in HTML5 mode.
 */
Bool TY_(IsHTML5Mode)( TidyDocImpl *doc );


/** @} */
/** @name Parser Methods And Attribute Checker Functions for Tags
 ** These functions define the parsers and attribute checking functions for
 ** each of Tidy's tags.
 */
/** @{ */


Parser TY_(ParseHTML);
Parser TY_(ParseHead);
Parser TY_(ParseTitle);
Parser TY_(ParseScript);
Parser TY_(ParseFrameSet);
Parser TY_(ParseNoFrames);
Parser TY_(ParseBody);
Parser TY_(ParsePre);
Parser TY_(ParseList);
Parser TY_(ParseDefList);
Parser TY_(ParseBlock);
Parser TY_(ParseInline);
Parser TY_(ParseEmpty);
Parser TY_(ParseTableTag);
Parser TY_(ParseColGroup);
Parser TY_(ParseRowGroup);
Parser TY_(ParseRow);
Parser TY_(ParseSelect);
Parser TY_(ParseOptGroup);
Parser TY_(ParseText);
Parser TY_(ParseDatalist);
Parser TY_(ParseNamespace);

CheckAttribs TY_(CheckAttributes);


/** @} */
/** @name Other Tag and Node Lookup Functions
 ** These functions perform additional lookup on tags and nodes.
 */
/** @{ */


/** Gets the TidyTagId of the given node. 0 == TidyTag_UNKNOWN.
 */
#define TagId(node)        ((node) && (node)->tag ? (node)->tag->id : TidyTag_UNKNOWN)


/** Determines if the given node is of the given tag id type.
 */
#define TagIsId(node, tid) ((node) && (node)->tag && (node)->tag->id == tid)


/** Inquires whether or not the given node is a text node.
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeIsText)( Node* node );


/** Inquires whether or not the given node is an element node.
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeIsElement)( Node* node );


/** Inquires whether or not the given node has any text.
 ** @param doc The Tidy document.
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeHasText)( TidyDocImpl* doc, Node* node );


/** Inquires whether the given element looks like it's an autonomous custom
 ** element tag.
 ** @param element A string to be checked.
 ** @returns The status of the inquiry.
 */
Bool TY_(elementIsAutonomousCustomFormat)( ctmbstr element );


/** Inquires whether the given node looks like it's an autonomous custom
 ** element tag.
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeIsAutonomousCustomFormat)( Node* node );


/** True if the node looks like it's an autonomous custom element tag, and
 ** TidyCustomTags is not disabled, and we're in HTML5 mode, which are all
 ** requirements for valid autonomous custom tags.
 ** @param doc The Tidy document.
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeIsAutonomousCustomTag)( TidyDocImpl* doc, Node* node );


/** Does the node have the indicated content model? True if any of the bits
 ** requested are set.
 ** @param node The node being interrogated.
 ** @param contentModel The content model to check against.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeHasCM)( Node* node, unsigned int contentModel );


/** Does the content model of the node include block?
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeCMIsBlock)( Node* node );


/** Does the content model of the node include inline?
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeCMIsInline)( Node* node );


/** Does the content model of the node include empty?
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeCMIsEmpty)( Node* node );


/** Is the node a header, such as H1, H2, ..., H6?
 ** @param node The node being interrogated.
 ** @returns The status of the inquiry.
 */
Bool TY_(nodeIsHeader)( Node* node );


/** Inquires as to the header level of the given node: 1, 2, ..., 6.
 ** @param node The node being interrogated.
 ** @returns The header level.
 */
unsigned int TY_(nodeHeaderLevel)( Node* node );


#define nodeIsHTML( node )       TagIsId( node, TidyTag_HTML )
#define nodeIsHEAD( node )       TagIsId( node, TidyTag_HEAD )
#define nodeIsTITLE( node )      TagIsId( node, TidyTag_TITLE )
#define nodeIsBASE( node )       TagIsId( node, TidyTag_BASE )
#define nodeIsMETA( node )       TagIsId( node, TidyTag_META )
#define nodeIsBODY( node )       TagIsId( node, TidyTag_BODY )
#define nodeIsFRAMESET( node )   TagIsId( node, TidyTag_FRAMESET )
#define nodeIsFRAME( node )      TagIsId( node, TidyTag_FRAME )
#define nodeIsIFRAME( node )     TagIsId( node, TidyTag_IFRAME )
#define nodeIsNOFRAMES( node )   TagIsId( node, TidyTag_NOFRAMES )
#define nodeIsHR( node )         TagIsId( node, TidyTag_HR )
#define nodeIsH1( node )         TagIsId( node, TidyTag_H1 )
#define nodeIsH2( node )         TagIsId( node, TidyTag_H2 )
#define nodeIsPRE( node )        TagIsId( node, TidyTag_PRE )
#define nodeIsLISTING( node )    TagIsId( node, TidyTag_LISTING )
#define nodeIsP( node )          TagIsId( node, TidyTag_P )
#define nodeIsUL( node )         TagIsId( node, TidyTag_UL )
#define nodeIsOL( node )         TagIsId( node, TidyTag_OL )
#define nodeIsDL( node )         TagIsId( node, TidyTag_DL )
#define nodeIsDIR( node )        TagIsId( node, TidyTag_DIR )
#define nodeIsLI( node )         TagIsId( node, TidyTag_LI )
#define nodeIsDT( node )         TagIsId( node, TidyTag_DT )
#define nodeIsDD( node )         TagIsId( node, TidyTag_DD )
#define nodeIsTABLE( node )      TagIsId( node, TidyTag_TABLE )
#define nodeIsCAPTION( node )    TagIsId( node, TidyTag_CAPTION )
#define nodeIsTD( node )         TagIsId( node, TidyTag_TD )
#define nodeIsTH( node )         TagIsId( node, TidyTag_TH )
#define nodeIsTR( node )         TagIsId( node, TidyTag_TR )
#define nodeIsCOL( node )        TagIsId( node, TidyTag_COL )
#define nodeIsCOLGROUP( node )   TagIsId( node, TidyTag_COLGROUP )
#define nodeIsBR( node )         TagIsId( node, TidyTag_BR )
#define nodeIsA( node )          TagIsId( node, TidyTag_A )
#define nodeIsLINK( node )       TagIsId( node, TidyTag_LINK )
#define nodeIsB( node )          TagIsId( node, TidyTag_B )
#define nodeIsI( node )          TagIsId( node, TidyTag_I )
#define nodeIsSTRONG( node )     TagIsId( node, TidyTag_STRONG )
#define nodeIsEM( node )         TagIsId( node, TidyTag_EM )
#define nodeIsBIG( node )        TagIsId( node, TidyTag_BIG )
#define nodeIsSMALL( node )      TagIsId( node, TidyTag_SMALL )
#define nodeIsPARAM( node )      TagIsId( node, TidyTag_PARAM )
#define nodeIsOPTION( node )     TagIsId( node, TidyTag_OPTION )
#define nodeIsOPTGROUP( node )   TagIsId( node, TidyTag_OPTGROUP )
#define nodeIsIMG( node )        TagIsId( node, TidyTag_IMG )
#define nodeIsMAP( node )        TagIsId( node, TidyTag_MAP )
#define nodeIsAREA( node )       TagIsId( node, TidyTag_AREA )
#define nodeIsNOBR( node )       TagIsId( node, TidyTag_NOBR )
#define nodeIsWBR( node )        TagIsId( node, TidyTag_WBR )
#define nodeIsFONT( node )       TagIsId( node, TidyTag_FONT )
#define nodeIsLAYER( node )      TagIsId( node, TidyTag_LAYER )
#define nodeIsSPACER( node )     TagIsId( node, TidyTag_SPACER )
#define nodeIsCENTER( node )     TagIsId( node, TidyTag_CENTER )
#define nodeIsSTYLE( node )      TagIsId( node, TidyTag_STYLE )
#define nodeIsSCRIPT( node )     TagIsId( node, TidyTag_SCRIPT )
#define nodeIsNOSCRIPT( node )   TagIsId( node, TidyTag_NOSCRIPT )
#define nodeIsFORM( node )       TagIsId( node, TidyTag_FORM )
#define nodeIsTEXTAREA( node )   TagIsId( node, TidyTag_TEXTAREA )
#define nodeIsBLOCKQUOTE( node ) TagIsId( node, TidyTag_BLOCKQUOTE )
#define nodeIsAPPLET( node )     TagIsId( node, TidyTag_APPLET )
#define nodeIsOBJECT( node )     TagIsId( node, TidyTag_OBJECT )
#define nodeIsDIV( node )        TagIsId( node, TidyTag_DIV )
#define nodeIsSPAN( node )       TagIsId( node, TidyTag_SPAN )
#define nodeIsINPUT( node )      TagIsId( node, TidyTag_INPUT )
#define nodeIsQ( node )          TagIsId( node, TidyTag_Q )
#define nodeIsLABEL( node )      TagIsId( node, TidyTag_LABEL )
#define nodeIsH3( node )         TagIsId( node, TidyTag_H3 )
#define nodeIsH4( node )         TagIsId( node, TidyTag_H4 )
#define nodeIsH5( node )         TagIsId( node, TidyTag_H5 )
#define nodeIsH6( node )         TagIsId( node, TidyTag_H6 )
#define nodeIsADDRESS( node )    TagIsId( node, TidyTag_ADDRESS )
#define nodeIsXMP( node )        TagIsId( node, TidyTag_XMP )
#define nodeIsSELECT( node )     TagIsId( node, TidyTag_SELECT )
#define nodeIsBLINK( node )      TagIsId( node, TidyTag_BLINK )
#define nodeIsMARQUEE( node )    TagIsId( node, TidyTag_MARQUEE )
#define nodeIsEMBED( node )      TagIsId( node, TidyTag_EMBED )
#define nodeIsBASEFONT( node )   TagIsId( node, TidyTag_BASEFONT )
#define nodeIsISINDEX( node )    TagIsId( node, TidyTag_ISINDEX )
#define nodeIsS( node )          TagIsId( node, TidyTag_S )
#define nodeIsSTRIKE( node )     TagIsId( node, TidyTag_STRIKE )
#define nodeIsSUB( node )        TagIsId( node, TidyTag_SUB )
#define nodeIsSUP( node )        TagIsId( node, TidyTag_SUP )
#define nodeIsU( node )          TagIsId( node, TidyTag_U )
#define nodeIsMENU( node )       TagIsId( node, TidyTag_MENU )
#define nodeIsMAIN( node )       TagIsId( node, TidyTag_MAIN )
#define nodeIsBUTTON( node )     TagIsId( node, TidyTag_BUTTON )
#define nodeIsCANVAS( node )     TagIsId( node, TidyTag_CANVAS )
#define nodeIsPROGRESS( node )   TagIsId( node, TidyTag_PROGRESS )

#define nodeIsINS( node )        TagIsId( node, TidyTag_INS )
#define nodeIsDEL( node )        TagIsId( node, TidyTag_DEL )

/* HTML5 */
#define nodeIsDATALIST( node )   TagIsId( node, TidyTag_DATALIST )
#define nodeIsDATA( node )       TagIsId( node, TidyTag_DATA )
#define nodeIsMATHML( node )     TagIsId( node, TidyTag_MATHML ) /* #130 MathML attr and entity fix! */

/* NOT in HTML 5 */
#define nodeIsACRONYM( node )    TagIsId( node, TidyTag_ACRONYM )
#define nodesIsFRAME( node )     TagIsId( node, TidyTag_FRAME )
#define nodeIsTT( node )         TagIsId( node, TidyTag_TT )


/** @} name */
/** @} tags_h group */
/** @} internal_api addtogroup */


#endif /* __TAGS_H__ */
#ifndef __TIDY_INT_H__
#define __TIDY_INT_H__

/* tidy-int.h -- internal library declarations

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "tidy.h" */
/* #include "config.h" */
/* #include "lexer.h" */
/* #include "tags.h" */
/* #include "attrs.h" */
/* #include "pprint.h" */
/* #include "access.h" */
/* #include "message.h" */

#ifndef MAX
#define MAX(a,b) (((a) > (b))?(a):(b))
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b))?(a):(b))
#endif

/*\
 *  Issue #166 - repeated <main> element
 *  Change the previous on/off unsigned int flag badForm
 *  to a BIT flag to support other than <form>
 *  errors. This could be extended more...
\*/
#define flg_BadForm     0x00000001
#define flg_BadMain     0x00000002

struct _TidyDocImpl
{
    /* The Document Tree (and backing store buffer) */
    Node                root;       /* This MUST remain the first declared 
                                       variable in this structure */
    Lexer*              lexer;

    /* Config + Markup Declarations */
    TidyConfigImpl          config;
    TidyTagImpl             tags;
    TidyAttribImpl          attribs;
    TidyAccessImpl          access;
    TidyMutedMessages       muted;

    /* The Pretty Print buffer */
    TidyPrintImpl       pprint;

    /* I/O */
    StreamIn*                docIn;
    StreamOut*               docOut;
    StreamOut*               errout;
    TidyReportFilter         reportFilter;
    TidyReportCallback       reportCallback;
    TidyMessageCallback      messageCallback;
    TidyOptCallback          pOptCallback;
    TidyConfigCallback       pConfigCallback;
    TidyConfigChangeCallback pConfigChangeCallback;
    TidyPPProgress           progressCallback;

    /* Parse + Repair Results */
    unsigned int                optionErrors;
    unsigned int                errors;
    unsigned int                warnings;
    unsigned int                accessErrors;
    unsigned int                infoMessages;
    unsigned int                docErrors;
    int                 parseStatus;

    unsigned int                badAccess;   /* for accessibility errors */
    unsigned int                badLayout;   /* for bad style errors */
    unsigned int                badChars;    /* for bad char encodings */
    unsigned int                badForm;     /* bit field, for badly placed form tags, or other format errors */
    unsigned int                footnotes;   /* bit field, for other footnotes, until formalized */

    Bool                HTML5Mode;   /* current mode is html5 */
    Bool                xmlDetected; /* true if XML was used/detected */

    /* Memory allocator */
    TidyAllocator*      allocator;

    /* Miscellaneous */
    void*               appData;
    unsigned int                nClassId;
    Bool                inputHadBOM;

#if PRESERVE_FILE_TIMES
    struct utimbuf      filetimes;
#endif
    tmbstr              givenDoctype;
};

/** The basic struct for communicating a message within LibTidy. All of the
**  relevant information pertaining to a message can be retrieved with the
**  accessor functions and one of these records.
*/
struct _TidyMessageImpl
{
    TidyDocImpl         *tidyDoc;     /* document instance this message is attributed to */
    Node                *tidyNode;    /* the node reporting the message, if applicable */
    unsigned int                code;         /* the message code */
    int                 line;         /* the line message applies to */
    int                 column;       /* the column the message applies to */
    TidyReportLevel     level;        /* the severity level of the message */
    Bool                allowMessage; /* indicates whether or not a filter rejected a message */
    Bool                muted;        /* indicates whether or not a configuration mutes this message */
    
    int                 argcount;    /* the number of arguments */
    struct printfArg*   arguments;   /* the arguments' values and types */

    ctmbstr             messageKey;             /* the message code as a key string */

    ctmbstr             messageFormatDefault;   /* the built-in format string */
    ctmbstr             messageFormat;          /* the localized format string */

    tmbstr              messageDefault;         /* the message, formatted, default language */
    tmbstr              message;                /* the message, formatted, localized */

    tmbstr              messagePosDefault;      /* the position part, default language */
    tmbstr              messagePos;             /* the position part, localized */

    ctmbstr             messagePrefixDefault;   /* the prefix part, default language */
    ctmbstr             messagePrefix;          /* the prefix part, localized */
    
    tmbstr              messageOutputDefault;   /* the complete string Tidy would output */
    tmbstr              messageOutput;          /* the complete string, localized */
};


#define tidyDocToImpl( tdoc )           ((TidyDocImpl*)(tdoc))
#define tidyImplToDoc( doc )            ((TidyDoc)(doc))

#define tidyMessageToImpl( tmessage )   ((TidyMessageImpl*)(tmessage))
#define tidyImplToMessage( message )    ((TidyMessage)(message))

#define tidyNodeToImpl( tnod )          ((Node*)(tnod))
#define tidyImplToNode( node )          ((TidyNode)(node))

#define tidyAttrToImpl( tattr )         ((AttVal*)(tattr))
#define tidyImplToAttr( attval )        ((TidyAttr)(attval))

#define tidyOptionToImpl( topt )        ((const TidyOptionImpl*)(topt))
#define tidyImplToOption( option )      ((TidyOption)(option))


/** Wrappers for easy memory allocation using the document's allocator */
#define TidyDocAlloc(doc, size) TidyAlloc((doc)->allocator, size)
#define TidyDocRealloc(doc, block, size) TidyRealloc((doc)->allocator, block, size)
#define TidyDocFree(doc, block) TidyFree((doc)->allocator, block)
#define TidyDocPanic(doc, msg) TidyPanic((doc)->allocator, msg)

int          TY_(DocParseStream)( TidyDocImpl* impl, StreamIn* in );

/*
   [i_a] generic node tree traversal code; used in several spots.

   Define your own callback, which returns one of the NodeTraversalSignal values
   to instruct the tree traversal routine TraverseNodeTree() what to do.

   Pass custom data to/from the callback using the 'propagate' reference.
 */
typedef enum
{
    ContinueTraversal,       /* visit siblings and children */
    SkipChildren,            /* visit siblings of this node; ignore its children */
    SkipSiblings,            /* ignore subsequent siblings of this node; ignore their children; traverse  */
    SkipChildrenAndSiblings, /* visit siblings of this node; ignore its children */
    VisitParent,             /* REVERSE traversal: visit the parent of the current node */
    ExitTraversal            /* terminate traversal on the spot */
} NodeTraversalSignal;

typedef NodeTraversalSignal NodeTraversalCallBack(TidyDocImpl* doc, Node* node, void *propagate);

NodeTraversalSignal TY_(TraverseNodeTree)(TidyDocImpl* doc, Node* node, NodeTraversalCallBack *cb, void *propagate);

#endif /* __TIDY_INT_H__ */
#ifndef __TMBSTR_H__
#define __TMBSTR_H__

/* tmbstr.h - Tidy string utility functions

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "tidyplatform.h" */

#ifdef __cplusplus
extern "C"
{
#endif

/* like strdup but using an allocator */
tmbstr TY_(tmbstrdup)( TidyAllocator *allocator, ctmbstr str );

/* like strndup but using an allocator */
tmbstr TY_(tmbstrndup)( TidyAllocator *allocator, ctmbstr str, unsigned int len);

/* exactly same as strncpy */
unsigned int TY_(tmbstrncpy)( tmbstr s1, ctmbstr s2, unsigned int size );

unsigned int TY_(tmbstrcpy)( tmbstr s1, ctmbstr s2 );

unsigned int TY_(tmbstrcat)( tmbstr s1, ctmbstr s2 );

/* exactly same as strcmp */
int TY_(tmbstrcmp)( ctmbstr s1, ctmbstr s2 );

/* returns byte count, not char count */
unsigned int TY_(tmbstrlen)( ctmbstr str );

/*
  MS C 4.2 doesn't include strcasecmp.
  Note that tolower and toupper won't
  work on chars > 127.

  Neither do Lexer.ToLower() or Lexer.ToUpper()!

  We get away with this because, except for XML tags,
  we are always comparing to ascii element and
  attribute names defined by HTML specs.
*/
int TY_(tmbstrcasecmp)( ctmbstr s1, ctmbstr s2 );

int TY_(tmbstrncmp)( ctmbstr s1, ctmbstr s2, unsigned int n );

int TY_(tmbstrncasecmp)( ctmbstr s1, ctmbstr s2, unsigned int n );

/* return offset of cc from beginning of s1,
** -1 if not found.
*/
/* int TY_(tmbstrnchr)( ctmbstr s1, unsigned int len1, tmbchar cc ); */

ctmbstr TY_(tmbsubstrn)( ctmbstr s1, unsigned int len1, ctmbstr s2 );
/* ctmbstr TY_(tmbsubstrncase)( ctmbstr s1, unsigned int len1, ctmbstr s2 ); */
ctmbstr TY_(tmbsubstr)( ctmbstr s1, ctmbstr s2 );

/* transform string to lower case */
tmbstr TY_(tmbstrtolower)( tmbstr s );

/* Transform ASCII chars in string to upper case */
tmbstr TY_(tmbstrtoupper)( tmbstr s );

/* Bool TY_(tmbsamefile)( ctmbstr filename1, ctmbstr filename2 ); */

int TY_(tmbvsnprintf)(tmbstr buffer, size_t count, ctmbstr format, va_list args)
#ifdef __GNUC__
__attribute__((format(printf, 3, 0)))
#endif
;
int TY_(tmbsnprintf)(tmbstr buffer, size_t count, ctmbstr format, ...)
#ifdef __GNUC__
__attribute__((format(printf, 3, 4)))
#endif
;

#ifdef __cplusplus
}  /* extern "C" */
#endif

#endif /* __TMBSTR_H__ */
#ifndef __UTF8_H__
#define __UTF8_H__

/* utf8.h -- convert characters to/from UTF-8

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "tidyplatform.h" */
/* #include "tidybuffio.h" */

/* UTF-8 encoding/decoding support
** Does not convert character "codepoints", i.e. to/from 10646.
*/

int TY_(DecodeUTF8BytesToChar)( unsigned int* c, unsigned int firstByte, ctmbstr successorBytes,
                                TidyInputSource* inp, int* count );

int TY_(EncodeCharToUTF8Bytes)( unsigned int c, tmbstr encodebuf,
                                TidyOutputSink* outp, int* count );


unsigned int  TY_(GetUTF8)( ctmbstr str, unsigned int *ch );
tmbstr TY_(PutUTF8)( tmbstr buf, unsigned int c );

#define UNICODE_BOM_BE   0xFEFF   /* big-endian (default) UNICODE BOM */
#define UNICODE_BOM      UNICODE_BOM_BE
#define UNICODE_BOM_LE   0xFFFE   /* little-endian UNICODE BOM */
#define UNICODE_BOM_UTF8 0xEFBBBF /* UTF-8 UNICODE BOM */


Bool    TY_(IsValidUTF16FromUCS4)( tchar ucs4 );
Bool    TY_(IsHighSurrogate)( tchar ch );
Bool    TY_(IsLowSurrogate)( tchar ch );

Bool    TY_(IsCombinedChar)( tchar ch );
Bool    TY_(IsValidCombinedChar)( tchar ch );

tchar   TY_(CombineSurrogatePair)( tchar high, tchar low );
Bool    TY_(SplitSurrogatePair)( tchar utf16, tchar* high, tchar* low );



#endif /* __UTF8_H__ */
/* version information

  (c) 2007-2015 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

#ifdef RELEASE_DATE
static const char TY_(release_date)[] = RELEASE_DATE;
#else
static const char TY_(release_date)[] = "2015/01/22";
#endif
#ifdef LIBTIDY_VERSION
#ifdef RC_NUMBER
static const char TY_(library_version)[] = LIBTIDY_VERSION "." RC_NUMBER;
#else
static const char TY_(library_version)[] = LIBTIDY_VERSION;
#endif
#else
static const char TY_(library_version)[] = "5.0.0";
#endif

/* eof */
/* access.c -- carry out accessibility checks

  Copyright University of Toronto
  Portions (c) 1998-2009 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.
  
*/


/* #include "tidy-int.h" */
/* #include "access.h" */
/* #include "message.h" */
/* #include "tags.h" */
/* #include "attrs.h" */
/* #include "tmbstr.h" */


/* 
    The accessibility checks to perform depending on user's desire.

    1. priority 1
    2. priority 1 & 2
    3. priority 1, 2, & 3
*/

/* List of possible image types */
static const ctmbstr imageExtensions[] =
{".jpg", ".gif", ".tif", ".pct", ".pic", ".iff", ".dib",
 ".tga", ".pcx", ".png", ".jpeg", ".tiff", ".bmp"};

#define N_IMAGE_EXTS (sizeof(imageExtensions)/sizeof(ctmbstr))

/* List of possible sound file types */
static const ctmbstr soundExtensions[] =
{".wav", ".au", ".aiff", ".snd", ".ra", ".rm"};

static const int soundExtErrCodes[] = 
{
    AUDIO_MISSING_TEXT_WAV,
    AUDIO_MISSING_TEXT_AU,
    AUDIO_MISSING_TEXT_AIFF,
    AUDIO_MISSING_TEXT_SND,
    AUDIO_MISSING_TEXT_RA,
    AUDIO_MISSING_TEXT_RM
};

#define N_AUDIO_EXTS (sizeof(soundExtensions)/sizeof(ctmbstr))

/* List of possible media extensions */
static const ctmbstr mediaExtensions[] = 
{".mpg", ".mov", ".asx", ".avi", ".ivf", ".m1v", ".mmm", ".mp2v",
 ".mpa", ".mpe", ".mpeg", ".ram", ".smi", ".smil", ".swf",
 ".wm", ".wma", ".wmv"};

#define N_MEDIA_EXTS (sizeof(mediaExtensions)/sizeof(ctmbstr))

/* List of possible frame sources */
static const ctmbstr frameExtensions[] =
{".htm", ".html", ".shtm", ".shtml", ".cfm", ".cfml",
".asp", ".cgi", ".pl", ".smil"};

#define N_FRAME_EXTS (sizeof(frameExtensions)/sizeof(ctmbstr))

/* List of possible colour values */
static const int colorValues[][3] =
{
  {  0,  0,  0},
  {128,128,128},
  {192,192,192},
  {255,255,255},
  {192,  0,  0},
  {255,  0,  0},
  {128,  0,128},
  {255,  0,255},
  {  0,128,  0},
  {  0,255,  0},
  {128,128,  0},
  {255,255,  0},  
  {  0,  0,128},
  {  0,  0,255},
  {  0,128,128},
  {  0,255,255}
};

#define N_COLOR_VALS (sizeof(colorValues)/(sizeof(int[3]))

/* These arrays are used to convert color names to their RGB values */
static const ctmbstr colorNames[] =
{
  "black",
  "silver",
  "grey",
  "white",
  "maroon",
  "red",
  "purple",
  "fuchsia",
  "green",
  "lime",
  "olive",
  "yellow", 
  "navy",
  "blue",
  "teal",
  "aqua"
};

#define N_COLOR_NAMES (sizeof(colorNames)/sizeof(ctmbstr))
#define N_COLORS N_COLOR_NAMES


/* function prototypes */
static void InitAccessibilityChecks( TidyDocImpl* doc, int level123 );
static void FreeAccessibilityChecks( TidyDocImpl* doc );

static Bool GetRgb( ctmbstr color, int rgb[3] );
static Bool CompareColors( const int rgbBG[3], const int rgbFG[3] );
static int  ctox( tmbchar ch );

/*
static void CheckMapAccess( TidyDocImpl* doc, Node* node, Node* front);
static void GetMapLinks( TidyDocImpl* doc, Node* node, Node* front);
static void CompareAnchorLinks( TidyDocImpl* doc, Node* front, int counter);
static void FindMissingLinks( TidyDocImpl* doc, Node* node, int counter);
*/
static void CheckFormControls( TidyDocImpl* doc, Node* node );
static void MetaDataPresent( TidyDocImpl* doc, Node* node );
static void CheckEmbed( TidyDocImpl* doc, Node* node );
static void CheckListUsage( TidyDocImpl* doc, Node* node );

/*
    IsFilePath attempts to determine whether or not the URI indicated
    by path is a file rather than a TLD. For example, sample.com.au might
    be confused with an audio file.
*/
static Bool IsFilePath( ctmbstr path )
{
    const char *p = path;
    char c;
    typedef enum states { initial, protocol_found, slash_found, file_found } states;
    states state = initial;

    while ( ( c = *p++ ) != 0 && state != file_found )
    {
        switch ( state )
        {
            case initial:
                if ( c == ':' )
                    state = protocol_found;
                break;

            case protocol_found:
                if ( c =='/' )
                    state = slash_found;
                break;

            case slash_found:
                if ( c =='/' )
                    state = protocol_found;
                else
                    state = file_found;
                break;
                
            default:
                break;
        }
        
    }
    
    return state == file_found || state == initial;
}


/*
    GetFileExtension takes a path and returns the extension
    portion of the path (if any).
*/

static void GetFileExtension( ctmbstr path, tmbchar *ext, unsigned int maxExt )
{
    int i = TY_(tmbstrlen)(path) - 1;
    
    ext[0] = '\0';
    
    do {
        if ( path[i] == '/' || path[i] == '\\' )
            break;
        else if ( path[i] == '.' )
        {
            TY_(tmbstrncpy)( ext, path+i, maxExt );
            break;
        }
    } while ( --i > 0 );
}

/************************************************************************
* IsImage
*
* Checks if the given filename is an image file.
* Returns 'yes' if it is, 'no' if it's not.
************************************************************************/

static Bool IsImage( ctmbstr iType )
{
    unsigned int i;
    tmbchar ext[20];

    if ( !IsFilePath(iType) ) return 0;

    GetFileExtension( iType, ext, sizeof(ext) );

    /* Compare it to the array of known image file extensions */
    for (i = 0; i < N_IMAGE_EXTS; i++)
    {
        if ( TY_(tmbstrcasecmp)(ext, imageExtensions[i]) == 0 )
            return yes;
    }
    
    return no;
}


/***********************************************************************
* IsSoundFile
*
* Checks if the given filename is a sound file.
* Returns 'yes' if it is, 'no' if it's not.
***********************************************************************/

static int IsSoundFile( ctmbstr sType )
{
    unsigned int i;
    tmbchar ext[ 20 ];

    if ( !IsFilePath(sType) ) return 0;
    
    GetFileExtension( sType, ext, sizeof(ext) );
    
    for (i = 0; i < N_AUDIO_EXTS; i++)
    {
        if ( TY_(tmbstrcasecmp)(ext, soundExtensions[i]) == 0 )
            return soundExtErrCodes[i];
    }
    return 0;
}


/***********************************************************************
* IsValidSrcExtension
*
* Checks if the 'SRC' value within the FRAME element is valid
* The 'SRC' extension must end in ".htm", ".html", ".shtm", ".shtml", 
* ".cfm", ".cfml", ".asp", ".cgi", ".pl", or ".smil"
*
* Returns yes if it is, returns no otherwise.
***********************************************************************/

static Bool IsValidSrcExtension( ctmbstr sType )
{
    unsigned int i;
    tmbchar ext[20];
    
    if ( !IsFilePath(sType) ) return 0;
    
    GetFileExtension( sType, ext, sizeof(ext) );

    for (i = 0; i < N_FRAME_EXTS; i++)
    {
        if ( TY_(tmbstrcasecmp)(ext, frameExtensions[i]) == 0 )
            return yes;
    }
    return no;
}


/*********************************************************************
* IsValidMediaExtension
*
* Checks to warn the user that syncronized text equivalents are 
* required if multimedia is used.
*********************************************************************/

static Bool IsValidMediaExtension( ctmbstr sType )
{
    unsigned int i;
    tmbchar ext[20];

    if ( !IsFilePath(sType) ) return 0;

    GetFileExtension( sType, ext, sizeof(ext) );

    for (i = 0; i < N_MEDIA_EXTS; i++)
    {
        if ( TY_(tmbstrcasecmp)(ext, mediaExtensions[i]) == 0 )
            return yes;
    }
    return no;
}


/************************************************************************
* IsWhitespace
*
* Checks if the given string is all whitespace.
* Returns 'yes' if it is, 'no' if it's not.
************************************************************************/

static Bool IsWhitespace( ctmbstr pString )
{
    Bool isWht = yes;
    ctmbstr cp;

    for ( cp = pString; isWht && cp && *cp; ++cp )
    {
        isWht = TY_(IsWhite)( *cp );
    }
    return isWht;
}

static Bool hasValue( AttVal* av )
{
    return ( av && ! IsWhitespace(av->value) );
}

/***********************************************************************
* IsPlaceholderAlt
*  
* Checks to see if there is an image and photo place holder contained
* in the ALT text.
*
* Returns 'yes' if there is, 'no' if not.
***********************************************************************/

static Bool IsPlaceholderAlt( ctmbstr txt )
{
    return ( strstr(txt, "image") != NULL || 
             strstr(txt, "photo") != NULL );
}


/***********************************************************************
* IsPlaceholderTitle
*  
* Checks to see if there is an TITLE place holder contained
* in the 'ALT' text.
*
* Returns 'yes' if there is, 'no' if not.

static Bool IsPlaceHolderTitle( ctmbstr txt )
{
    return ( strstr(txt, "title") != NULL );
}
***********************************************************************/


/***********************************************************************
* IsPlaceHolderObject
*  
* Checks to see if there is an OBJECT place holder contained
* in the 'ALT' text.
*
* Returns 'yes' if there is, 'no' if not.
***********************************************************************/

static Bool IsPlaceHolderObject( ctmbstr txt )
{
    return ( strstr(txt, "object") != NULL );
}


/**********************************************************
* EndsWithBytes
*
* Checks to see if the ALT text ends with 'bytes'
* Returns 'yes', if true, 'no' otherwise.
**********************************************************/

static Bool EndsWithBytes( ctmbstr txt )
{
    unsigned int len = TY_(tmbstrlen)( txt );
    return ( len >= 5 && TY_(tmbstrcmp)(txt+len-5, "bytes") == 0 );
}


/*******************************************************
* textFromOneNode
*
* Returns a list of characters contained within one
* text node.
*******************************************************/

static ctmbstr textFromOneNode( TidyDocImpl* doc, Node* node )
{
    unsigned int i;
    unsigned int x = 0;
    tmbstr txt = doc->access.text;
    
    if ( node )
    {
        /* Copy contents of a text node */
        for (i = node->start; i < node->end; ++i, ++x )
        {
            txt[x] = doc->lexer->lexbuf[i];

            /* Check buffer overflow */
            if ( x >= sizeof(doc->access.text)-1 )
                break;
        }
    }

    txt[x] = '\0';
    return txt;
}


/*********************************************************
* getTextNode
*
* Locates text nodes within a container element.
* Retrieves text that are found contained within 
* text nodes, and concatenates the text.
*********************************************************/
    
static void getTextNode( TidyDocImpl* doc, Node* node )
{
    tmbstr txtnod = doc->access.textNode;       
    
    /* 
       Continues to traverse through container element until it no
       longer contains any more contents 
    */

    /* If the tag of the node is NULL, then grab the text within the node */
    if ( TY_(nodeIsText)(node) )
    {
        unsigned int i;

        /* Retrieves each character found within the text node */
        for (i = node->start; i < node->end; i++)
        {
            /* The text must not exceed buffer */
            if ( doc->access.counter >= TEXTBUF_SIZE-1 )
                return;

            txtnod[ doc->access.counter++ ] = doc->lexer->lexbuf[i];
        }

        /* Traverses through the contents within a container element */
        for ( node = node->content; node != NULL; node = node->next )
            getTextNode( doc, node );
    }   
}


/**********************************************************
* getTextNodeClear
*
* Clears the current 'textNode' and reloads it with new
* text.  The textNode must be cleared before use.
**********************************************************/

static tmbstr getTextNodeClear( TidyDocImpl* doc, Node* node )
{
    /* Clears list */
    TidyClearMemory( doc->access.textNode, TEXTBUF_SIZE );
    doc->access.counter = 0;

    getTextNode( doc, node->content );
    return doc->access.textNode;
}

/**********************************************************
* LevelX_Enabled
*
* Tell whether access "X" is enabled.
**********************************************************/

static Bool Level1_Enabled( TidyDocImpl* doc )
{
   return doc->access.PRIORITYCHK == 1 ||
          doc->access.PRIORITYCHK == 2 ||
          doc->access.PRIORITYCHK == 3;
}
static Bool Level2_Enabled( TidyDocImpl* doc )
{
    return doc->access.PRIORITYCHK == 2 ||
           doc->access.PRIORITYCHK == 3;
}
static Bool Level3_Enabled( TidyDocImpl* doc )
{
    return doc->access.PRIORITYCHK == 3;
}

/********************************************************
* CheckColorAvailable
*
* Verify that information conveyed with color is 
* available without color.
********************************************************/

static void CheckColorAvailable( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        if ( nodeIsIMG(node) )
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_IMAGE );

        else if ( nodeIsAPPLET(node) )
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_APPLET );

        else if ( nodeIsOBJECT(node) )
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_OBJECT );

        else if ( nodeIsSCRIPT(node) )
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_SCRIPT );

        else if ( nodeIsINPUT(node) )
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_INPUT );
    }
}

/*********************************************************************
* CheckColorContrast
*
* Checks elements for color contrast.  Must have valid contrast for
* valid visibility.
*
* This logic is extremely fragile as it does not recognize
* the fact that color is inherited by many components and
* that BG and FG colors are often set separately.  E.g. the
* background color may be set by for the body or a table 
* or a cell.  The foreground color may be set by any text
* element (p, h1, h2, input, textarea), either explicitly
* or by style.  Ergo, this test will not handle most real
* world cases.  It's a start, however.
*********************************************************************/

static void CheckColorContrast( TidyDocImpl* doc, Node* node )
{
    int rgbBG[3] = {255,255,255};   /* Black text on white BG */

    if (Level3_Enabled( doc ))
    {
        Bool gotBG = yes;
        AttVal* av;

        /* Check for 'BGCOLOR' first to compare with other color attributes */
        for ( av = node->attributes; av; av = av->next )
        {            
            if ( attrIsBGCOLOR(av) )
            {
                if ( hasValue(av) )
                    gotBG = GetRgb( av->value, rgbBG );
            }
        }
        
        /* 
           Search for COLOR attributes to compare with background color
           Must have valid colour contrast
        */
        for ( av = node->attributes; gotBG && av != NULL; av = av->next )
        {
            unsigned int errcode = 0;
            if ( attrIsTEXT(av) )
                errcode = COLOR_CONTRAST_TEXT;
            else if ( attrIsLINK(av) )
                errcode = COLOR_CONTRAST_LINK;
            else if ( attrIsALINK(av) )
                errcode = COLOR_CONTRAST_ACTIVE_LINK;
            else if ( attrIsVLINK(av) )
                errcode = COLOR_CONTRAST_VISITED_LINK;

            if ( errcode && hasValue(av) )
            {
                int rgbFG[3] = {0, 0, 0};  /* Black text */

                if ( GetRgb(av->value, rgbFG) &&
                     !CompareColors(rgbBG, rgbFG) )
                {
                    TY_(ReportAccessError)( doc, node, errcode );
                }
            }
        }
    }
}


/**************************************************************
* CompareColors
*
* Compares two RGB colors for good contrast.
**************************************************************/
static int minmax( int i1, int i2 )
{
   return MAX(i1, i2) - MIN(i1,i2);
}
static int brightness( const int rgb[3] )
{
   return ((rgb[0]*299) + (rgb[1]*587) + (rgb[2]*114)) / 1000;
}

static Bool CompareColors( const int rgbBG[3], const int rgbFG[3] )
{
    int brightBG = brightness( rgbBG );
    int brightFG = brightness( rgbFG );

    int diffBright = minmax( brightBG, brightFG );

    int diffColor = minmax( rgbBG[0], rgbFG[0] )
                  + minmax( rgbBG[1], rgbFG[1] )
                  + minmax( rgbBG[2], rgbFG[2] );

    return ( diffBright > 180 &&
             diffColor > 500 );
}


/*********************************************************************
* GetRgb
*
* Gets the red, green and blue values for this attribute for the 
* background.
*
* Example: If attribute is BGCOLOR="#121005" then red = 18, green = 16,
* blue = 5.
*********************************************************************/

static Bool GetRgb( ctmbstr color, int rgb[] )
{
    unsigned int x;

    /* Check if we have a color name */
    for (x = 0; x < N_COLORS; x++)
    {
        if ( strstr(colorNames[x], color) != NULL )
        {
            rgb[0] = colorValues[x][0];
            rgb[1] = colorValues[x][1];
            rgb[2] = colorValues[x][2];
            return yes;
        }
    }

    /*
       No color name so must be hex values 
       Is this a number in hexadecimal format?
    */
    
    /* Must be 7 characters in the RGB value (including '#') */
    if ( TY_(tmbstrlen)(color) == 7 && color[0] == '#' )
    {
        rgb[0] = (ctox(color[1]) * 16) + ctox(color[2]);
        rgb[1] = (ctox(color[3]) * 16) + ctox(color[4]);
        rgb[2] = (ctox(color[5]) * 16) + ctox(color[6]);
        return yes;
    }
    return no;
} 



/*******************************************************************
* ctox
*
* Converts a character to a number.
* Example: if given character is 'A' then returns 10.
*
* Returns the number that the character represents. Returns -1 if not a
* valid number.
*******************************************************************/

static int ctox( tmbchar ch )
{
    if ( ch >= '0' && ch <= '9' )
    {
         return ch - '0';
    }
    else if ( ch >= 'a' && ch <= 'f' )
    {
        return ch - 'a' + 10;
    }
    else if ( ch >= 'A' && ch <= 'F' )
    {
        return ch - 'A' + 10;
    }
    return -1;
}


/***********************************************************
* CheckImage
*
* Checks all image attributes for specific elements to
* check for validity of the values contained within
* the attributes.  An appropriate warning message is displayed
* to indicate the error.  
***********************************************************/

static void CheckImage( TidyDocImpl* doc, Node* node )
{
    Bool HasAlt = no;
    Bool HasIsMap = no;
    Bool HasLongDesc = no;
    Bool HasDLINK = no;
    Bool HasValidHeight = no;
    Bool HasValidWidthBullet = no;
    Bool HasValidWidthHR = no; 
    Bool HasTriggeredMissingLongDesc = no;

    AttVal* av;
                
    if (Level1_Enabled( doc ))
    {
        /* Checks all image attributes for invalid values within attributes */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            /* 
               Checks for valid ALT attribute.
               The length of the alt text must be less than 150 characters 
               long.
            */
            if ( attrIsALT(av) )
            {
                if (av->value != NULL) 
                {
                    if ((TY_(tmbstrlen)(av->value) < 150) &&
                        (IsPlaceholderAlt (av->value) == no) &&
                        (IsPlaceHolderObject (av->value) == no) &&
                        (EndsWithBytes (av->value) == no) &&
                        (IsImage (av->value) == no))
                    {
                        HasAlt = yes;
                    }

                    else if (TY_(tmbstrlen)(av->value) > 150)
                    {
                        HasAlt = yes;
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_TOO_LONG );
                    }

                    else if (IsImage (av->value) == yes)
                    {
                        HasAlt = yes;
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_FILENAME);
                    }
            
                    else if (IsPlaceholderAlt (av->value) == yes)
                    {
                        HasAlt = yes;
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_PLACEHOLDER);
                    }

                    else if (EndsWithBytes (av->value) == yes)
                    {
                        HasAlt = yes;
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_FILE_SIZE);
                    }
                }
            }

            /* 
               Checks for width values of 'bullets' and 'horizontal
               rules' for validity.

               Valid pixel width for 'bullets' must be < 30, and > 150 for
               horizontal rules.
            */
            else if ( attrIsWIDTH(av) )
            {
                /* Longdesc attribute needed if width attribute is not present. */
                if ( hasValue(av) )
                {
                    int width = atoi( av->value );
                    if ( width < 30 )
                        HasValidWidthBullet = yes;

                    if ( width > 150 )
                        HasValidWidthHR = yes;
                }
            }

            /* 
               Checks for height values of 'bullets' and horizontal
               rules for validity.

               Valid pixel height for 'bullets' and horizontal rules 
               mustt be < 30.
            */
            else if ( attrIsHEIGHT(av) )
            {
                /* Longdesc attribute needed if height attribute not present. */
                if ( hasValue(av) && atoi(av->value) < 30 )
                    HasValidHeight = yes;
            }

            /* 
               Checks for longdesc and determines validity.  
               The length of the 'longdesc' must be > 1
            */
            else if ( attrIsLONGDESC(av) )
            {
                if ( hasValue(av) && TY_(tmbstrlen)(av->value) > 1 )
                    HasLongDesc = yes;
              }

            /* 
               Checks for 'USEMAP' attribute.  Ensures that
               text links are provided for client-side image maps
            */
            else if ( attrIsUSEMAP(av) )
            {
                if ( hasValue(av) )
                    doc->access.HasUseMap = yes;
            }    

            else if ( attrIsISMAP(av) )
            {
                HasIsMap = yes;
            }
        }    
        
        
        /* 
            Check to see if a dLINK is present.  The ANCHOR element must
            be present following the IMG element.  The text found between 
            the ANCHOR tags must be < 6 characters long, and must contain
            the letter 'd'.
        */
        if ( nodeIsA(node->next) )
        {
            node = node->next;
            
            /* 
                Node following the anchor must be a text node
                for dLINK to exist 
            */

            if (node->content != NULL && (node->content)->tag == NULL)
            {
                /* Number of characters found within the text node */
                ctmbstr word = textFromOneNode( doc, node->content);
                    
                if ((TY_(tmbstrcmp)(word,"d") == 0)||
                    (TY_(tmbstrcmp)(word,"D") == 0))
                {
                    HasDLINK = yes;
                }
            }
        }
                    
        /*
            Special case check for dLINK.  This will occur if there is 
            whitespace between the <img> and <a> elements.  Ignores 
            whitespace and continues check for dLINK.
        */
        
        if ( node->next && !node->next->tag )
        {
            node = node->next;

            if ( nodeIsA(node->next) )
            {
                node = node->next;

                /* 
                    Node following the ANCHOR must be a text node
                    for dLINK to exist 
                */
                if (node->content != NULL && node->content->tag == NULL)
                {
                    /* Number of characters found within the text node */
                    ctmbstr word = textFromOneNode( doc, node->content );

                    if ((TY_(tmbstrcmp)(word, "d") == 0)||
                        (TY_(tmbstrcmp)(word, "D") == 0))
                    {
                        HasDLINK = yes;
                    }
                }
            }
        }

        if ((HasAlt == no)&&
            (HasValidWidthBullet == yes)&&
            (HasValidHeight == yes))
        {
        }

        if ((HasAlt == no)&&
            (HasValidWidthHR == yes)&&
            (HasValidHeight == yes))
        {
        }

        if (HasAlt == no)
        {
            TY_(ReportAccessError)( doc, node, IMG_MISSING_ALT);
        }

        if ((HasLongDesc == no)&&
            (HasValidHeight ==yes)&&
            ((HasValidWidthHR == yes)||
             (HasValidWidthBullet == yes)))
        {
            HasTriggeredMissingLongDesc = yes;
        }

        if (HasTriggeredMissingLongDesc == no)
        {
            if ((HasDLINK == yes)&&
                (HasLongDesc == no))
            {
                TY_(ReportAccessError)( doc, node, IMG_MISSING_LONGDESC);
            }

            if ((HasLongDesc == yes)&&
                (HasDLINK == no))
            {
                TY_(ReportAccessError)( doc, node, IMG_MISSING_DLINK);
            }

            if ((HasLongDesc == no)&&
                (HasDLINK == no))
            {
                TY_(ReportAccessError)( doc, node, IMG_MISSING_LONGDESC_DLINK);
            }
        }

        if (HasIsMap == yes)
        {
            TY_(ReportAccessError)( doc, node, IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION);

            TY_(ReportAccessError)( doc, node, IMG_MAP_SERVER_REQUIRES_TEXT_LINKS);
        }
    }
}


/***********************************************************
* CheckApplet
*
* Checks APPLET element to check for validity pertaining 
* the 'ALT' attribute.  An appropriate warning message is 
* displayed  to indicate the error. An appropriate warning 
* message is displayed to indicate the error.  If no 'ALT'
* text is present, then there must be alternate content
* within the APPLET element.
***********************************************************/

static void CheckApplet( TidyDocImpl* doc, Node* node )
{
    Bool HasAlt = no;
    Bool HasDescription = no;

    AttVal* av;
        
    if (Level1_Enabled( doc ))
    {
        /* Checks for attributes within the APPLET element */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            /*
               Checks for valid ALT attribute.
               The length of the alt text must be > 4 characters in length
               but must be < 150 characters long.
            */

            if ( attrIsALT(av) )
            {
                if (av->value != NULL)
                {
                    HasAlt = yes;
                }
            }
        }

        if (HasAlt == no)
        {
            /* Must have alternate text representation for that element */
            if (node->content != NULL) 
            {
                ctmbstr word = NULL;

                if ( node->content->tag == NULL )
                    word = textFromOneNode( doc, node->content);

                if ( node->content->content != NULL &&
                     node->content->content->tag == NULL )
                {
                    word = textFromOneNode( doc, node->content->content);
                }
                
                if ( word != NULL && !IsWhitespace(word) )
                    HasDescription = yes;
            }
        }

        if ( !HasDescription && !HasAlt )
        {
            TY_(ReportAccessError)( doc, node, APPLET_MISSING_ALT );
        }
    }
}


/*******************************************************************
* CheckObject
*
* Checks to verify whether the OBJECT element contains
* 'ALT' text, and to see that the sound file selected is 
* of a valid sound file type.  OBJECT must have an alternate text 
* representation.
*******************************************************************/

static void CheckObject( TidyDocImpl* doc, Node* node )
{
    Bool HasAlt = no;
    Bool HasDescription = no;

    if (Level1_Enabled( doc ))
    {
        if ( node->content != NULL)
        {
            if ( node->content->type != TextNode )
            {
                Node* tnode = node->content;
                AttVal* av;

                for ( av=tnode->attributes; av; av = av->next )
                {
                    if ( attrIsALT(av) )
                    {
                        HasAlt = yes;
                        break;
                    }
                }
            }

            /* Must have alternate text representation for that element */
            if ( !HasAlt )
            {
                ctmbstr word = NULL;

                if ( TY_(nodeIsText)(node->content) )
                    word = textFromOneNode( doc, node->content );

                if ( word == NULL &&
                     TY_(nodeIsText)(node->content->content) )
                {
                    word = textFromOneNode( doc, node->content->content );
                }
                    
                if ( word != NULL && !IsWhitespace(word) )
                    HasDescription = yes;
            }
        }

        if ( !HasAlt && !HasDescription )
        {
            TY_(ReportAccessError)( doc, node, OBJECT_MISSING_ALT );
        }
    }
}


/***************************************************************
* CheckMissingStyleSheets
*
* Ensures that stylesheets are used to control the presentation.
***************************************************************/

static Bool CheckMissingStyleSheets( TidyDocImpl* doc, Node* node )
{
    AttVal* av;
    Node* content;
    Bool sspresent = no;

    for ( content = node->content;
          !sspresent && content != NULL;
          content = content->next )
    {
        sspresent = ( nodeIsLINK(content)  ||
                      nodeIsSTYLE(content) ||
                      nodeIsFONT(content)  ||
                      nodeIsBASEFONT(content) );

        for ( av = content->attributes;
              !sspresent && av != NULL;
              av = av->next )
        {
            sspresent = ( attrIsSTYLE(av) || attrIsTEXT(av)  ||
                          attrIsVLINK(av) || attrIsALINK(av) ||
                          attrIsLINK(av) );

            if ( !sspresent && attrIsREL(av) )
            {
                sspresent = AttrValueIs(av, "stylesheet");
            }
        }

        if ( ! sspresent )
            sspresent = CheckMissingStyleSheets( doc, content );
    }
    return sspresent;
}


/*******************************************************************
* CheckFrame
*
* Checks if the URL is valid and to check if a 'LONGDESC' is needed
* within the FRAME element.  If a 'LONGDESC' is needed, the value must 
* be valid. The URL must end with the file extension, htm, or html. 
* Also, checks to ensure that the 'SRC' and 'TITLE' values are valid. 
*******************************************************************/

static void CheckFrame( TidyDocImpl* doc, Node* node )
{
    Bool HasTitle = no;
    AttVal* av;

    doc->access.numFrames++;

    if (Level1_Enabled( doc ))
    {
        /* Checks for attributes within the FRAME element */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            /* Checks if 'LONGDESC' value is valid only if present */
            if ( attrIsLONGDESC(av) )
            {
                if ( hasValue(av) && TY_(tmbstrlen)(av->value) > 1 )
                {
                    doc->access.HasCheckedLongDesc++;
                }
            }

            /* Checks for valid 'SRC' value within the frame element */
            else if ( attrIsSRC(av) )
            {
                if ( hasValue(av) && !IsValidSrcExtension(av->value) )
                {
                    TY_(ReportAccessError)( doc, node, FRAME_SRC_INVALID );
                }
            }

            /* Checks for valid 'TITLE' value within frame element */
            else if ( attrIsTITLE(av) )
            {
                if ( hasValue(av) )
                    HasTitle = yes;

                if ( !HasTitle )
                {
                    if ( av->value == NULL || TY_(tmbstrlen)(av->value) == 0 )
                    {
                        HasTitle = yes;
                        TY_(ReportAccessError)( doc, node, FRAME_TITLE_INVALID_NULL);
                    }
                    else
                    {
                        if ( IsWhitespace(av->value) && TY_(tmbstrlen)(av->value) > 0 )
                        {
                            HasTitle = yes;
                            TY_(ReportAccessError)( doc, node, FRAME_TITLE_INVALID_SPACES );
                        }
                    }
                }
            }
        }

        if ( !HasTitle )
        {
            TY_(ReportAccessError)( doc, node, FRAME_MISSING_TITLE);
        }

        if ( doc->access.numFrames==3 && doc->access.HasCheckedLongDesc<3 )
        {
            doc->access.numFrames = 0;
            TY_(ReportAccessError)( doc, node, FRAME_MISSING_LONGDESC );
        }
    }
}


/****************************************************************
* CheckIFrame
*
* Checks if 'SRC' value is valid.  Must end in appropriate
* file extension.
****************************************************************/

static void CheckIFrame( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        /* Checks for valid 'SRC' value within the IFRAME element */
        AttVal* av = attrGetSRC( node );
        if ( hasValue(av) )
        {
            if ( !IsValidSrcExtension(av->value) )
                TY_(ReportAccessError)( doc, node, FRAME_SRC_INVALID );
        }
    }
}


/**********************************************************************
* CheckAnchorAccess
*
* Checks that the sound file is valid, and to ensure that
* text transcript is present describing the 'HREF' within the 
* ANCHOR element.  Also checks to see ensure that the 'TARGET' attribute
* (if it exists) is not NULL and does not contain '_new' or '_blank'.
**********************************************************************/

static void CheckAnchorAccess( TidyDocImpl* doc, Node* node )
{
    AttVal* av;
    Bool HasDescription = no;
    Bool HasTriggeredLink = no;

    /* Checks for attributes within the ANCHOR element */
    for ( av = node->attributes; av != NULL; av = av->next )
    {
        if (Level1_Enabled( doc ))
        {
            /* Must be of valid sound file type */
            if ( attrIsHREF(av) )
            {
                if ( hasValue(av) )
                {
                    tmbchar ext[ 20 ];
                    GetFileExtension (av->value, ext, sizeof(ext) );

                    /* Checks to see if multimedia is used */
                    if ( IsValidMediaExtension(av->value) )
                    {
                        TY_(ReportAccessError)( doc, node, MULTIMEDIA_REQUIRES_TEXT );
                    }
            
                    /* 
                        Checks for validity of sound file, and checks to see if 
                        the file is described within the document, or by a link
                        that is present which gives the description.
                    */
                    if ( TY_(tmbstrlen)(ext) < 6 && TY_(tmbstrlen)(ext) > 0 )
                    {
                        int errcode = IsSoundFile( av->value );
                        if ( errcode )
                        {
                            if (node->next != NULL)
                            {
                                if (node->next->tag == NULL)
                                {
                                    ctmbstr word = textFromOneNode( doc, node->next);
                                
                                    /* Must contain at least one letter in the text */
                                    if (IsWhitespace (word) == no)
                                    {
                                        HasDescription = yes;
                                    }
                                }
                            }

                            /* Must contain text description of sound file */
                            if ( !HasDescription )
                            {
                                TY_(ReportAccessError)( doc, node, errcode );
                            }
                        }
                    }
                }
            }
        }

        if (Level2_Enabled( doc ))
        {
            /* Checks 'TARGET' attribute for validity if it exists */
            if ( attrIsTARGET(av) )
            {
                if (AttrValueIs(av, "_new"))
                {
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_NEW);
                }
                else if (AttrValueIs(av, "_blank"))
                {
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_BLANK);
                }
            }
        }
    }
    
    if (Level2_Enabled( doc ))
    {
        if ((node->content != NULL)&&
            (node->content->tag == NULL))
        {
            ctmbstr word = textFromOneNode( doc, node->content);

            if ((word != NULL)&&
                (IsWhitespace (word) == no))
            {
                if (TY_(tmbstrcmp) (word, "more") == 0)
                {
                    HasTriggeredLink = yes;
                }

                if (TY_(tmbstrcmp) (word, "click here") == 0)
                {
                    TY_(ReportAccessError)( doc, node, LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE);
                }

                if (HasTriggeredLink == no)
                {
                    if (TY_(tmbstrlen)(word) < 6)
                    {
                        TY_(ReportAccessError)( doc, node, LINK_TEXT_NOT_MEANINGFUL);
                    }
                }

                if (TY_(tmbstrlen)(word) > 60)
                {
                    TY_(ReportAccessError)( doc, node, LINK_TEXT_TOO_LONG);
                }

            }
        }
        
        if (node->content == NULL)
        {
            TY_(ReportAccessError)( doc, node, LINK_TEXT_MISSING);
        }
    }
}


/************************************************************
* CheckArea
*
* Checks attributes within the AREA element to 
* determine if the 'ALT' text and 'HREF' values are valid.
* Also checks to see ensure that the 'TARGET' attribute
* (if it exists) is not NULL and does not contain '_new' 
* or '_blank'.
************************************************************/

static void CheckArea( TidyDocImpl* doc, Node* node )
{
    Bool HasAlt = no;
    AttVal* av;

    /* Checks all attributes within the AREA element */
    for (av = node->attributes; av != NULL; av = av->next)
    {
        if (Level1_Enabled( doc ))
        {
            /*
              Checks for valid ALT attribute.
              The length of the alt text must be > 4 characters long
              but must be less than 150 characters long.
            */
                
            if ( attrIsALT(av) )
            {
                /* The check for validity */
                if (av->value != NULL) 
                {
                    HasAlt = yes;
                }
            }
        }

        if (Level2_Enabled( doc ))
        {
            if ( attrIsTARGET(av) )
            {
                if (AttrValueIs(av, "_new"))
                {
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_NEW);
                }
                else if (AttrValueIs(av, "_blank"))
                {
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_BLANK);
                }
            }
        }
    }

    if (Level1_Enabled( doc ))
    {
        /* AREA must contain alt text */
        if (HasAlt == no)
        {
            TY_(ReportAccessError)( doc, node, AREA_MISSING_ALT);
        }    
    }
}


/***************************************************
* CheckScript
*
* Checks the SCRIPT element to ensure that a
* NOSCRIPT section follows the SCRIPT.  
***************************************************/

static void CheckScriptAcc( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        /* NOSCRIPT element must appear immediately following SCRIPT element */
        if ( node->next == NULL || !nodeIsNOSCRIPT(node->next) )
        {
            TY_(ReportAccessError)( doc, node, SCRIPT_MISSING_NOSCRIPT);
        }
    }
}


/**********************************************************
* CheckRows
*
* Check to see that each table has a row of headers if
* a column of columns doesn't exist. 
**********************************************************/

static void CheckRows( TidyDocImpl* doc, Node* node )
{
    int numTR = 0;
    int numValidTH = 0;
    
    doc->access.CheckedHeaders++;

    for (; node != NULL; node = node->next )
    {
        numTR++;
        if ( nodeIsTH(node->content) )
        {
            doc->access.HasTH = yes;            
            if ( TY_(nodeIsText)(node->content->content) )
            {
                ctmbstr word = textFromOneNode( doc, node->content->content);
                if ( !IsWhitespace(word) )
                    numValidTH++;
            }
        }
    }

    if (numTR == numValidTH)
        doc->access.HasValidRowHeaders = yes;

    if ( numTR >= 2 &&
         numTR > numValidTH &&
         numValidTH >= 2 &&
         doc->access.HasTH == yes )
        doc->access.HasInvalidRowHeader = yes;
}


/**********************************************************
* CheckColumns
*
* Check to see that each table has a column of headers if
* a row of columns doesn't exist.  
**********************************************************/

static void CheckColumns( TidyDocImpl* doc, Node* node )
{
    Node* tnode;
    int numTH = 0;
    Bool isMissingHeader = no;

    doc->access.CheckedHeaders++;

    /* Table must have row of headers if headers for columns don't exist */
    if ( nodeIsTH(node->content) )
    {
        doc->access.HasTH = yes;

        for ( tnode = node->content; tnode; tnode = tnode->next )
        {
            if ( nodeIsTH(tnode) )
            {
                if ( TY_(nodeIsText)(tnode->content) )
                {
                    ctmbstr word = textFromOneNode( doc, tnode->content);
                    if ( !IsWhitespace(word) )
                        numTH++;
                }
            }
            else
            {
                isMissingHeader = yes;
            }
        }
    }

    if ( !isMissingHeader && numTH > 0 )
        doc->access.HasValidColumnHeaders = yes;

    if ( isMissingHeader && numTH >= 2 )
        doc->access.HasInvalidColumnHeader = yes;
}


/*****************************************************
* CheckTH
*
* Checks to see if the header provided for a table
* requires an abbreviation. (only required if the 
* length of the header is greater than 15 characters)
*****************************************************/

static void CheckTH( TidyDocImpl* doc, Node* node )
{
    Bool HasAbbr = no;
    ctmbstr word = NULL;
    AttVal* av;

    if (Level3_Enabled( doc ))
    {
        /* Checks TH element for 'ABBR' attribute */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            if ( attrIsABBR(av) )
            {
                /* Value must not be NULL and must be less than 15 characters */
                if ((av->value != NULL)&&
                    (IsWhitespace (av->value) == no))
                {
                    HasAbbr = yes;
                }

                if ((av->value == NULL)||
                    (TY_(tmbstrlen)(av->value) == 0))
                {
                    HasAbbr = yes;
                    TY_(ReportAccessError)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR_NULL);
                }
                
                if ((IsWhitespace (av->value) == yes)&&
                    (TY_(tmbstrlen)(av->value) > 0))
                {
                    HasAbbr = yes;
                    TY_(ReportAccessError)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES);
                }
            }
        }

        /* If the header is greater than 15 characters, an abbreviation is needed */
        word = textFromOneNode( doc, node->content);

        if ((word != NULL)&&
            (IsWhitespace (word) == no))
        {
            /* Must have 'ABBR' attribute if header is > 15 characters */
            if ((TY_(tmbstrlen)(word) > 15)&&
                (HasAbbr == no))
            {
                TY_(ReportAccessError)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR);
            }
        }
    }
}


/*****************************************************************
* CheckMultiHeaders
*
* Layout tables should make sense when linearized.
* TABLE must contain at least one TH element.
* This technique applies only to tables used for layout purposes, 
* not to data tables. Checks for column of multiple headers.
*****************************************************************/

static void CheckMultiHeaders( TidyDocImpl* doc, Node* node )
{
    Node* TNode;
    Node* temp;
    
    Bool validColSpanRows = yes;
    Bool validColSpanColumns = yes;

    int flag = 0;

    if (Level1_Enabled( doc ))
    {
        if (node->content != NULL)
        {
            TNode = node->content;

            /* 
               Checks for column of multiple headers found 
               within a data table. 
            */
            while (TNode != NULL)
            {
                if ( nodeIsTR(TNode) )
                {
                    flag = 0; /* Issue #168 - access test 5-2-1-2 */
                    if (TNode->content != NULL)
                    {
                        temp = TNode->content;

                        /* The number of TH elements found within TR element */
                        if (flag == 0)
                        {
                            while (temp != NULL)
                            {
                                /* 
                                   Must contain at least one TH element 
                                   within in the TR element 
                                */
                                if ( nodeIsTH(temp) )
                                {
                                    AttVal* av;
                                    for (av = temp->attributes; av != NULL; av = av->next)
                                    {
                                        if ( attrIsCOLSPAN(av)
                                             && (atoi(av->value) > 1) )
                                            validColSpanColumns = no;

                                        if ( attrIsROWSPAN(av)
                                             && (atoi(av->value) > 1) )
                                            validColSpanRows = no;
                                    }
                                }

                                temp = temp->next;
                            }    

                            flag = 1;
                        }
                    }
                }
            
                TNode = TNode->next;
            }

            /* Displays HTML 4 Table Algorithm when multiple column of headers used */
            if (validColSpanRows == no)
            {
                TY_(ReportAccessError)( doc, node, DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS );
                TY_(Dialogue)( doc, TEXT_HTML_T_ALGORITHM );
            }

            if (validColSpanColumns == no)
            {
                TY_(ReportAccessError)( doc, node, DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS );
                TY_(Dialogue)( doc, TEXT_HTML_T_ALGORITHM );
            }
        }
    }
}


/****************************************************
* CheckTable
*
* Checks the TABLE element to ensure that the
* table is not missing any headers.  Must have either
* a row or column of headers.  
****************************************************/

static void CheckTable( TidyDocImpl* doc, Node* node )
{
    Node* TNode;
    Node* temp;

    tmbstr word = NULL;

    int numTR = 0;

    Bool HasSummary = no;
    Bool HasCaption = no;

    if (Level3_Enabled( doc ))
    {
        AttVal* av;
        /* Table must have a 'SUMMARY' describing the purpose of the table */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            if ( attrIsSUMMARY(av) )
            {
                if ( hasValue(av) )
                {
                    HasSummary = yes;

                    if (AttrContains(av, "summary") && 
                        AttrContains(av, "table"))
                    {
                        TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_PLACEHOLDER );
                    }
                }

                if ( av->value == NULL || TY_(tmbstrlen)(av->value) == 0 )
                {
                    HasSummary = yes;
                    TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_NULL );
                }
                else if ( IsWhitespace(av->value) && TY_(tmbstrlen)(av->value) > 0 )
                {
                    HasSummary = yes;
                    TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_SPACES );
                }
            }
        }

        /* TABLE must have content. */
        if (node->content == NULL)
        {
            TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS);
        
            return;
        }
    }

    if (Level1_Enabled( doc ))
    {
        /* Checks for multiple headers */
        CheckMultiHeaders( doc, node );
    }
    
    if (Level2_Enabled( doc ))
    {
        /* Table must have a CAPTION describing the purpose of the table */
        if ( nodeIsCAPTION(node->content) )
        {
            TNode = node->content;

            if (TNode->content && TNode->content->tag == NULL)
            {
                word = getTextNodeClear( doc, TNode);
            }

            if ( !IsWhitespace(word) )
            {
                HasCaption = yes;
            }
        }

        if (HasCaption == no)
        {
            TY_(ReportAccessError)( doc, node, TABLE_MISSING_CAPTION);
        }
    }

    
    if (node->content != NULL)
    {
        if ( nodeIsCAPTION(node->content) && nodeIsTR(node->content->next) )
        {
            CheckColumns( doc, node->content->next );
        }
        else if ( nodeIsTR(node->content) )
        {
            CheckColumns( doc, node->content );
        }
    }
    
    if ( ! doc->access.HasValidColumnHeaders )
    {
        if (node->content != NULL)
        {
            if ( nodeIsCAPTION(node->content) && nodeIsTR(node->content->next) )
            {
                CheckRows( doc, node->content->next);
            }
            else if ( nodeIsTR(node->content) )
            {
                CheckRows( doc, node->content);
            }
        }
    }
    
    
    if (Level3_Enabled( doc ))
    {
        /* Suppress warning for missing 'SUMMARY for HTML 2.0 and HTML 3.2 */
        if (HasSummary == no)
        {
            TY_(ReportAccessError)( doc, node, TABLE_MISSING_SUMMARY);
        }
    }

    if (Level2_Enabled( doc ))
    {
        if (node->content != NULL)
        {
            temp = node->content;

            while (temp != NULL)
            {
                if ( nodeIsTR(temp) )
                {
                    numTR++;
                }

                temp = temp->next;
            }

            if (numTR == 1)
            {
                TY_(ReportAccessError)( doc, node, LAYOUT_TABLES_LINEARIZE_PROPERLY);
            }
        }
    
        if ( doc->access.HasTH )
        {
            TY_(ReportAccessError)( doc, node, LAYOUT_TABLE_INVALID_MARKUP);
        }
    }

    if (Level1_Enabled( doc ))
    {
        if ( doc->access.CheckedHeaders == 2 )
        {
            if ( !doc->access.HasValidRowHeaders &&
                 !doc->access.HasValidColumnHeaders &&
                 !doc->access.HasInvalidRowHeader &&
                 !doc->access.HasInvalidColumnHeader  )
            {
                TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS);
            }

            if ( !doc->access.HasValidRowHeaders && 
                 doc->access.HasInvalidRowHeader )
            {
                TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS_ROW);
            }

            if ( !doc->access.HasValidColumnHeaders &&
                 doc->access.HasInvalidColumnHeader )
            {
                TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS_COLUMN);
            }
        }
    }
}


/***************************************************
* CheckASCII
* 
* Checks for valid text equivalents for XMP and PRE
* elements for ASCII art.  Ensures that there is
* a skip over link to skip multi-lined ASCII art.
***************************************************/

static void CheckASCII( TidyDocImpl* doc, Node* node )
{
    Node* temp1;
    Node* temp2;

    tmbstr skipOver = NULL;
    Bool IsAscii = no;
    int HasSkipOverLink = 0;
        
    unsigned int i, x;
    int newLines = -1;
    tmbchar compareLetter;
    int matchingCount = 0;
    AttVal* av;
    
    if (Level1_Enabled( doc ) && node->content)
    {
        /* 
           Checks the text within the PRE and XMP tags to see if ascii 
           art is present 
        */
        for (i = node->content->start + 1; i < node->content->end; i++)
        {
            matchingCount = 0;

            /* Counts the number of lines of text */
            if (doc->lexer->lexbuf[i] == '\n')
            {
                newLines++;
            }
            
            compareLetter = doc->lexer->lexbuf[i];

            /* Counts consecutive character matches */
            for (x = i; x < i + 5; x++)
            {
                if (doc->lexer->lexbuf[x] == compareLetter)
                {
                    matchingCount++;
                }

                else
                {
                    break;
                }
            }

            /* Must have at least 5 consecutive character matches */
            if (matchingCount >= 5)
            {
                break;
            }
        }

        /* 
           Must have more than 6 lines of text OR 5 or more consecutive 
           letters that are the same for there to be ascii art 
        */
        if (newLines >= 6 || matchingCount >= 5)
        {
            IsAscii = yes;
        }

        /* Checks for skip over link if ASCII art is present */
        if (IsAscii == yes)
        {
            if (node->prev != NULL && node->prev->prev != NULL)
            {
                temp1 = node->prev->prev;

                /* Checks for 'HREF' attribute */
                for (av = temp1->attributes; av != NULL; av = av->next)
                {
                    if ( attrIsHREF(av) && hasValue(av) )
                    {
                        skipOver = av->value;
                        HasSkipOverLink++;
                    }
                }
            }
        }
    }

    if (Level2_Enabled( doc ))
    {
        /* 
           Checks for A element following PRE to ensure proper skipover link
           only if there is an A element preceding PRE.
        */
        if (HasSkipOverLink == 1)
        {
            if ( nodeIsA(node->next) )
            {
                temp2 = node->next;
                
                /* Checks for 'NAME' attribute */
                for (av = temp2->attributes; av != NULL; av = av->next)
                {
                    if ( attrIsNAME(av) && hasValue(av) )
                    {
                        /* 
                           Value within the 'HREF' attribute must be the same
                           as the value within the 'NAME' attribute for valid
                           skipover.
                        */
                        if ( strstr(skipOver, av->value) != NULL )
                        {
                            HasSkipOverLink++;
                        }
                    }
                }
            }
        }

        if (IsAscii == yes)
        {
            TY_(ReportAccessError)( doc, node, ASCII_REQUIRES_DESCRIPTION);
            if (Level3_Enabled( doc ) && (HasSkipOverLink < 2))
                TY_(ReportAccessError)( doc, node, SKIPOVER_ASCII_ART);
        }

    }
}


/***********************************************************
* CheckFormControls
*
* <form> must have valid 'FOR' attribute, and <label> must
* have valid 'ID' attribute for valid form control.
***********************************************************/

static void CheckFormControls( TidyDocImpl* doc, Node* node )
{
    if ( !doc->access.HasValidFor &&
         doc->access.HasValidId )
    {
        TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY_FOR);
    }    

    if ( !doc->access.HasValidId &&
         doc->access.HasValidFor )
    {
        TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY_ID);
    }

    if ( !doc->access.HasValidId &&
         !doc->access.HasValidFor )
    {
        TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY);
    }
}


/************************************************************
* CheckLabel
*
* Check for valid 'FOR' attribute within the LABEL element
************************************************************/

static void CheckLabel( TidyDocImpl* doc, Node* node )
{
    if (Level2_Enabled( doc ))
    {    
        /* Checks for valid 'FOR' attribute */
        AttVal* av = attrGetFOR( node );
        if ( hasValue(av) )
            doc->access.HasValidFor = yes;

        if ( ++doc->access.ForID == 2 )
        {
            doc->access.ForID = 0;
            CheckFormControls( doc, node );
        }
    }
}


/************************************************************
* CheckInputLabel
* 
* Checks for valid 'ID' attribute within the INPUT element.
* Checks to see if there is a LABEL directly before
* or after the INPUT element determined by the 'TYPE'.  
* Each INPUT element must have a LABEL describing the form.
************************************************************/

static void CheckInputLabel( TidyDocImpl* doc, Node* node )
{
    if (Level2_Enabled( doc ))
    {
        AttVal* av;

        /* Checks attributes within the INPUT element */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            /* Must have valid 'ID' value */
            if ( attrIsID(av) && hasValue(av) )
                doc->access.HasValidId = yes;
        }

        if ( ++doc->access.ForID == 2 )
        {
            doc->access.ForID = 0;
            CheckFormControls( doc, node );
        }
    }
}


/***************************************************************
* CheckInputAttributes 
*
* INPUT element must have a valid 'ALT' attribute if the
* 'VALUE' attribute is present.
***************************************************************/

static void CheckInputAttributes( TidyDocImpl* doc, Node* node )
{
    Bool HasAlt = no;
    Bool MustHaveAlt = no;
    AttVal* av;

    /* Checks attributes within the INPUT element */
    for (av = node->attributes; av != NULL; av = av->next)
    {
        /* 'VALUE' must be found if the 'TYPE' is 'text' or 'checkbox' */
        if ( attrIsTYPE(av) && hasValue(av) )
        {
            if (Level1_Enabled( doc ))
            {
                if (AttrValueIs(av, "image"))
                {
                    MustHaveAlt = yes;
                }
            }

        }

        if ( attrIsALT(av) && hasValue(av) )
        {
            HasAlt = yes;
        }
    }

    if ( MustHaveAlt && !HasAlt )
    {
        TY_(ReportAccessError)( doc, node, IMG_BUTTON_MISSING_ALT );
    }

}


/***************************************************************
* CheckFrameSet
*
* Frameset must have valid NOFRAME section.  Must contain some 
* text but must not contain information telling user to update 
* browsers, 
***************************************************************/

static void CheckFrameSet( TidyDocImpl* doc, Node* node )
{
    Node* temp;
    Bool HasNoFrames = no;

    if (Level1_Enabled( doc ))
    {
        if ( doc->badAccess & BA_INVALID_LINK_NOFRAMES )
        {
           TY_(ReportAccessError)( doc, node, NOFRAMES_INVALID_LINK);
           doc->badAccess &= ~BA_INVALID_LINK_NOFRAMES; /* emit only once */
        }
        for ( temp = node->content; temp != NULL ; temp = temp->next )
        {
            if ( nodeIsNOFRAMES(temp) )
            {
                HasNoFrames = yes;

                if ( temp->content && nodeIsP(temp->content->content) )
                {
                    Node* para = temp->content->content;
                    if ( TY_(nodeIsText)(para->content) )
                    {
                        ctmbstr word = textFromOneNode( doc, para->content );
                        if ( word && strstr(word, "browser") != NULL )
                            TY_(ReportAccessError)( doc, para, NOFRAMES_INVALID_CONTENT );
                    }
                }
                else if (temp->content == NULL)
                    TY_(ReportAccessError)( doc, temp, NOFRAMES_INVALID_NO_VALUE);
                else if ( temp->content &&
                          IsWhitespace(textFromOneNode(doc, temp->content)) )
                    TY_(ReportAccessError)( doc, temp, NOFRAMES_INVALID_NO_VALUE);
            }
        }

        if (HasNoFrames == no)
            TY_(ReportAccessError)( doc, node, FRAME_MISSING_NOFRAMES);
    }
}


/***********************************************************
* CheckHeaderNesting
*
* Checks for heading increases and decreases.  Headings must
* not increase by more than one header level, but may
* decrease at from any level to any level.  Text within 
* headers must not be more than 20 words in length.  
***********************************************************/

static void CheckHeaderNesting( TidyDocImpl* doc, Node* node )
{
    Node* temp;
    unsigned int i;
    int numWords = 1;

    Bool IsValidIncrease = no;
    Bool NeedsDescription = no;

    if (Level2_Enabled( doc ))
    {
        /* 
           Text within header element cannot contain more than 20 words without
           a separate description
        */
        if (node->content != NULL && node->content->tag == NULL)
        {
            ctmbstr word = textFromOneNode( doc, node->content);

            for (i = 0; i < TY_(tmbstrlen)(word); i++)
            {
                if (word[i] == ' ')
                {
                    numWords++;
                }
            }

            if (numWords > 20)
            {
                NeedsDescription = yes;
            }
        }

        /* Header following must be same level or same plus 1 for
        ** valid heading increase size.  E.g. H1 -> H1, H2.  H3 -> H3, H4
        */
        if ( TY_(nodeIsHeader)(node) )
        {
            unsigned int level = TY_(nodeHeaderLevel)( node );
            IsValidIncrease = yes;

            for ( temp = node->next; temp != NULL; temp = temp->next )
            {
                unsigned int nested = TY_(nodeHeaderLevel)( temp );
                if ( nested >= level )
                {
                    IsValidIncrease = ( nested <= level + 1 );
                    break;
                }
            }
        }

        if ( !IsValidIncrease )
            TY_(ReportAccessError)( doc, node, HEADERS_IMPROPERLY_NESTED );
    
        if ( NeedsDescription )
            TY_(ReportAccessError)( doc, node, HEADER_USED_FORMAT_TEXT );    
    }
}


/*************************************************************
* CheckParagraphHeader
*
* Checks to ensure that P elements are not headings.  Must be
* greater than 10 words in length, and they must not be in bold,
* or italics, or underlined, etc.
*************************************************************/

static void CheckParagraphHeader( TidyDocImpl* doc, Node* node )
{
    Bool IsNotHeader = no;
    Node* temp;

    if (Level2_Enabled( doc ))
    {
        /* Cannot contain text formatting elements */
        if (node->content != NULL)   
        {                     
            if (node->content->tag != NULL)
            {
                temp = node->content;

                while (temp != NULL)
                {
                    if (temp->tag == NULL)
                    {
                        IsNotHeader = yes;
                        break;
                    }
                        
                    temp = temp->next;
                }
            }

            if ( !IsNotHeader )
            {
                if ( nodeIsSTRONG(node->content) )
                {
                    TY_(ReportAccessError)( doc, node, POTENTIAL_HEADER_BOLD);
                }

                if ( nodeIsU(node->content) )
                {
                    TY_(ReportAccessError)( doc, node, POTENTIAL_HEADER_UNDERLINE);
                }

                if ( nodeIsEM(node->content) )
                {
                    TY_(ReportAccessError)( doc, node, POTENTIAL_HEADER_ITALICS);
                }
            }
        }
    }
}


/****************************************************************
* CheckEmbed
*
* Checks to see if 'SRC' is a multimedia type.  Must have 
* syncronized captions if used.
****************************************************************/

static void CheckEmbed( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        AttVal* av = attrGetSRC( node );
        if ( hasValue(av) && IsValidMediaExtension(av->value) )
        {
             TY_(ReportAccessError)( doc, node, MULTIMEDIA_REQUIRES_TEXT );
        }
    }
}


/*********************************************************************
* CheckHTMLAccess
*
* Checks HTML element for valid 'LANG' attribute.  Must be a valid
* language.  ie. 'fr' or 'en'
********************************************************************/

static void CheckHTMLAccess( TidyDocImpl* doc, Node* node )
{
    Bool ValidLang = no;

    if (Level3_Enabled( doc ))
    {
        AttVal* av = attrGetLANG( node );
        if ( av )
        {
            ValidLang = yes;
            if ( !hasValue(av) )
                TY_(ReportAccessError)( doc, node, LANGUAGE_INVALID );
        }
        if ( !ValidLang )
            TY_(ReportAccessError)( doc, node, LANGUAGE_NOT_IDENTIFIED );
    }
}


/********************************************************
* CheckBlink
*
* Document must not contain the BLINK element.  
* It is invalid HTML/XHTML.
*********************************************************/

static void CheckBlink( TidyDocImpl* doc, Node* node )
{
    
    if (Level2_Enabled( doc ))
    {
        /* Checks to see if text is found within the BLINK element. */
        if ( TY_(nodeIsText)(node->content) )
        {
            ctmbstr word = textFromOneNode( doc, node->content );
            if ( !IsWhitespace(word) )
            {
                TY_(ReportAccessError)( doc, node, REMOVE_BLINK_MARQUEE );
            }
        }
    }
}


/********************************************************
* CheckMarquee
*
* Document must not contain the MARQUEE element.
* It is invalid HTML/XHTML.
********************************************************/


static void CheckMarquee( TidyDocImpl* doc, Node* node )
{
    if (Level2_Enabled( doc ))
    {
        /* Checks to see if there is text in between the MARQUEE element */
        if ( TY_(nodeIsText)(node) )
        {
            ctmbstr word = textFromOneNode( doc, node->content);
            if ( !IsWhitespace(word) )
            {
                TY_(ReportAccessError)( doc, node, REMOVE_BLINK_MARQUEE );
            }
        }
    }
}


/**********************************************************
* CheckLink
*
* 'REL' attribute within the LINK element must not contain
* 'stylesheet'.  HTML/XHTML document is unreadable when
* style sheets are applied.  -- CPR huh?
**********************************************************/

static void CheckLink( TidyDocImpl* doc, Node* node )
{
    Bool HasRel = no;
    Bool HasType = no;

    if (Level1_Enabled( doc ))
    {
        AttVal* av;
        /* Check for valid 'REL' and 'TYPE' attribute */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            if ( attrIsREL(av) && hasValue(av) )
            {
                if (AttrContains(av, "stylesheet"))
                    HasRel = yes;
            }

            if ( attrIsTYPE(av) && hasValue(av) )
            {
                HasType = yes;
            }
        }

        if (HasRel && HasType)
            TY_(ReportAccessError)( doc, node, STYLESHEETS_REQUIRE_TESTING_LINK );
    }
}


/*******************************************************
* CheckStyle
*
* Document must not contain STYLE element.  HTML/XHTML 
* document is unreadable when style sheets are applied.
*******************************************************/

static void CheckStyle( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        TY_(ReportAccessError)( doc, node, STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT );
    }
}


/*************************************************************
* DynamicContent
*
* Verify that equivalents of dynamic content are updated and 
* available as often as the dynamic content.
*************************************************************/


static void DynamicContent( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        unsigned int msgcode = 0;
        if ( nodeIsAPPLET(node) )
            msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET;
        else if ( nodeIsSCRIPT(node) )
            msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT;
        else if ( nodeIsOBJECT(node) )
            msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT;

        if ( msgcode )
            TY_(ReportAccessError)( doc, node, msgcode );
    }
}


/*************************************************************
* ProgrammaticObjects
*
* Verify that the page is usable when programmatic objects 
* are disabled.
*************************************************************/

static void ProgrammaticObjects( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        int msgcode = 0;
        if ( nodeIsSCRIPT(node) )
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT;
        else if ( nodeIsOBJECT(node) )
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT;
        else if ( nodeIsEMBED(node) )
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED;
        else if ( nodeIsAPPLET(node) )
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET;

        if ( msgcode )
            TY_(ReportAccessError)( doc, node, msgcode );
    }
}


/*************************************************************
* AccessibleCompatible
*
* Verify that programmatic objects are directly accessible.
*************************************************************/

static void AccessibleCompatible( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        int msgcode = 0;
        if ( nodeIsSCRIPT(node) )
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT;
        else if ( nodeIsOBJECT(node) )
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT;
        else if ( nodeIsEMBED(node) )
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED;
        else if ( nodeIsAPPLET(node) )
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET;

        if ( msgcode )
            TY_(ReportAccessError)( doc, node, msgcode );
    }
}


/**************************************************
* CheckFlicker
*
* Verify that the page does not cause flicker.
**************************************************/

static void CheckFlicker( TidyDocImpl* doc, Node* node )
{
    if (Level1_Enabled( doc ))
    {
        int msgcode = 0;
        if ( nodeIsSCRIPT(node) )
            msgcode = REMOVE_FLICKER_SCRIPT;
        else if ( nodeIsOBJECT(node) )
            msgcode = REMOVE_FLICKER_OBJECT;
        else if ( nodeIsEMBED(node) )
            msgcode = REMOVE_FLICKER_EMBED;
        else if ( nodeIsAPPLET(node) )
            msgcode = REMOVE_FLICKER_APPLET;

        /* Checks for animated gif within the <img> tag. */
        else if ( nodeIsIMG(node) )
        {
            AttVal* av = attrGetSRC( node );
            if ( hasValue(av) )
            {
                tmbchar ext[20];
                GetFileExtension( av->value, ext, sizeof(ext) );
                if ( TY_(tmbstrcasecmp)(ext, ".gif") == 0 )
                    msgcode = REMOVE_FLICKER_ANIMATED_GIF;
            }
        }            

        if ( msgcode )
            TY_(ReportAccessError)( doc, node, msgcode );
    }
}


/**********************************************************
* CheckDeprecated
*
* APPLET, BASEFONT, CENTER, FONT, ISINDEX, 
* S, STRIKE, and U should not be used.  Becomes deprecated
* HTML if any of the above are used.
**********************************************************/

static void CheckDeprecated( TidyDocImpl* doc, Node* node )
{
    if (Level2_Enabled( doc ))
    {
        int msgcode = 0;
        if ( nodeIsAPPLET(node) )
            msgcode = REPLACE_DEPRECATED_HTML_APPLET;
        else if ( nodeIsBASEFONT(node) )
            msgcode = REPLACE_DEPRECATED_HTML_BASEFONT;
        else if ( nodeIsCENTER(node) )
            msgcode = REPLACE_DEPRECATED_HTML_CENTER;
        else if ( nodeIsDIR(node) )
            msgcode = REPLACE_DEPRECATED_HTML_DIR;
        else if ( nodeIsFONT(node) )
            msgcode = REPLACE_DEPRECATED_HTML_FONT;
        else if ( nodeIsISINDEX(node) )
            msgcode = REPLACE_DEPRECATED_HTML_ISINDEX;
        else if ( nodeIsMENU(node) )
            msgcode = REPLACE_DEPRECATED_HTML_MENU;
        else if ( nodeIsS(node) )
            msgcode = REPLACE_DEPRECATED_HTML_S;
        else if ( nodeIsSTRIKE(node) )
            msgcode = REPLACE_DEPRECATED_HTML_STRIKE;
        else if ( nodeIsU(node) )
            msgcode = REPLACE_DEPRECATED_HTML_U;

        if ( msgcode )
            TY_(ReportAccessError)( doc, node, msgcode );
    }
}


/************************************************************
* CheckScriptKeyboardAccessible
*
* Elements must have a device independent event handler if 
* they have any of the following device dependent event 
* handlers. 
************************************************************/

static void CheckScriptKeyboardAccessible( TidyDocImpl* doc, Node* node )
{
    Node* content;
    int HasOnMouseDown = 0;
    int HasOnMouseUp = 0;
    int HasOnClick = 0;
    int HasOnMouseOut = 0;
    int HasOnMouseOver = 0;
    int HasOnMouseMove = 0;

    if (Level2_Enabled( doc ))
    {
        AttVal* av;
        /* Checks all elements for their attributes */
        for (av = node->attributes; av != NULL; av = av->next)
        {
            /* Must also have 'ONKEYDOWN' attribute with 'ONMOUSEDOWN' */
            if ( attrIsOnMOUSEDOWN(av) )
                HasOnMouseDown++;

            /* Must also have 'ONKEYUP' attribute with 'ONMOUSEUP' */
            if ( attrIsOnMOUSEUP(av) )
                HasOnMouseUp++;

            /* Must also have 'ONKEYPRESS' attribute with 'ONCLICK' */
            if ( attrIsOnCLICK(av) )
                HasOnClick++;

            /* Must also have 'ONBLUR' attribute with 'ONMOUSEOUT' */
            if ( attrIsOnMOUSEOUT(av) )
                HasOnMouseOut++;

            if ( attrIsOnMOUSEOVER(av) )
                HasOnMouseOver++;

            if ( attrIsOnMOUSEMOVE(av) )
                HasOnMouseMove++;

            if ( attrIsOnKEYDOWN(av) )
                HasOnMouseDown++;

            if ( attrIsOnKEYUP(av) )
                HasOnMouseUp++;

            if ( attrIsOnKEYPRESS(av) )
                HasOnClick++;

            if ( attrIsOnBLUR(av) )
                HasOnMouseOut++;
        }

        if ( HasOnMouseDown == 1 )
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN);

        if ( HasOnMouseUp == 1 )
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP);

        if ( HasOnClick == 1 )
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK);
        if ( HasOnMouseOut == 1 )
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT);

        if ( HasOnMouseOver == 1 )
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER);

        if ( HasOnMouseMove == 1 )
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE);

        /* Recursively check all child nodes.
         */
        for ( content = node->content; content != NULL; content = content->next )
            CheckScriptKeyboardAccessible( doc, content );
    }
}


/**********************************************************
* CheckMetaData
*
* Must have at least one of these elements in the document.
* META, LINK, TITLE or ADDRESS.  <meta> must contain 
* a "content" attribute that doesn't contain a URL, and
* an "http-Equiv" attribute that doesn't contain 'refresh'.
**********************************************************/


static Bool CheckMetaData( TidyDocImpl* doc, Node* node, Bool HasMetaData )
{
    Bool HasHttpEquiv = no;
    Bool HasContent = no;
    Bool ContainsAttr = no;

    if (Level2_Enabled( doc ))
    {
        if ( nodeIsMETA(node) )
        {
            AttVal* av;
            for (av = node->attributes; av != NULL; av = av->next)
            {
                if ( attrIsHTTP_EQUIV(av) && hasValue(av) )
                {
                    ContainsAttr = yes;

                    /* Must not have an auto-refresh */
                    if (AttrValueIs(av, "refresh"))
                    {
                        HasHttpEquiv = yes;
                        TY_(ReportAccessError)( doc, node, REMOVE_AUTO_REFRESH );
                    }
                }

                if ( attrIsCONTENT(av) && hasValue(av) )
                {
                    ContainsAttr = yes;

                    /* If the value is not an integer, then it must not be a URL */
                    if ( TY_(tmbstrncmp)(av->value, "http:", 5) == 0)
                    {
                        HasContent = yes;
                        TY_(ReportAccessError)( doc, node, REMOVE_AUTO_REDIRECT);
                    }
                }
                if (TY_(IsHTML5Mode)(doc) && attrIsCHARSET(av) && hasValue(av))
                {
                    ContainsAttr = yes;
                }
            }
        
            if ( HasContent || HasHttpEquiv )
            {
                HasMetaData = yes;
                TY_(ReportAccessError)( doc, node, METADATA_MISSING_REDIRECT_AUTOREFRESH);
            }
            else
            {
                if ( ContainsAttr && !HasContent && !HasHttpEquiv )
                    HasMetaData = yes;                    
            }
        }

        if ( !HasMetaData && 
             nodeIsADDRESS(node) &&
             nodeIsA(node->content) )
        {
            HasMetaData = yes;
        }
            
        if ( !HasMetaData &&
             !nodeIsTITLE(node) &&
             TY_(nodeIsText)(node->content) )
        {
            ctmbstr word = textFromOneNode( doc, node->content );
            if ( !IsWhitespace(word) )
                HasMetaData = yes;
        }

        if( !HasMetaData && nodeIsLINK(node) )
        {
            AttVal* av = attrGetREL(node);
            if( !AttrContains(av, "stylesheet") )
                HasMetaData = yes;
        }
            
        /* Check for MetaData */
        for ( node = node->content; node; node = node->next )
        {
            HasMetaData = CheckMetaData( doc, node, HasMetaData );
        }
    }
    return HasMetaData;
}


/*******************************************************
* MetaDataPresent
*
* Determines if MetaData is present in document
*******************************************************/

static void MetaDataPresent( TidyDocImpl* doc, Node* node )
{
    if (Level2_Enabled( doc ))
    {
        TY_(ReportAccessError)( doc, node, METADATA_MISSING );
    }
}


/*****************************************************
* CheckDocType
*
* Checks that every HTML/XHTML document contains a 
* '!DOCTYPE' before the root node. ie.  <HTML>
*****************************************************/

static void CheckDocType( TidyDocImpl* doc )
{
    if (Level2_Enabled( doc ))
    {
        Node* DTnode = TY_(FindDocType)(doc);

        /* If the doctype has been added by tidy, DTnode->end will be 0. */
        if (DTnode && DTnode->end != 0)
        {
            ctmbstr word = textFromOneNode( doc, DTnode);
            if (TY_(IsHTML5Mode)(doc))
            {
                if ((strstr(word, "HTML") == NULL) &&
                    (strstr(word, "html") == NULL))
                    DTnode = NULL;
            }
            else {
                if ((strstr(word, "HTML PUBLIC") == NULL) &&
                    (strstr(word, "html PUBLIC") == NULL))
                    DTnode = NULL;
            }
        }
        if (!DTnode)
           TY_(ReportAccessError)( doc, &doc->root, DOCTYPE_MISSING);
    }
}



/********************************************************
* CheckMapLinks
*
* Checks to see if an HREF for A element matches HREF
* for AREA element.  There must be an HREF attribute 
* of an A element for every HREF of an AREA element. 
********************************************************/

static Bool urlMatch( ctmbstr url1, ctmbstr url2 )
{
  /* TODO: Make host part case-insensitive and
  ** remainder case-sensitive.
  */
  return ( TY_(tmbstrcmp)( url1, url2 ) == 0 );
}

static Bool FindLinkA( TidyDocImpl* doc, Node* node, ctmbstr url )
{
  Bool found = no;
  for ( node = node->content; !found && node; node = node->next )
  {
    if ( nodeIsA(node) )
    {
      AttVal* href = attrGetHREF( node );
      found = ( hasValue(href) && urlMatch(url, href->value) );
    }
    else
        found = FindLinkA( doc, node, url );
  }
  return found;
}

static void CheckMapLinks( TidyDocImpl* doc, Node* node )
{
    Node* child;

    if (!Level3_Enabled( doc ))
        return;

    /* Stores the 'HREF' link of an AREA element within a MAP element */
    for ( child = node->content; child != NULL; child = child->next )
    {
        if ( nodeIsAREA(child) )
        {
            /* Checks for 'HREF' attribute */                
            AttVal* href = attrGetHREF( child );
            if ( hasValue(href) &&
                 !FindLinkA( doc, &doc->root, href->value ) )
            {
                TY_(ReportAccessError)( doc, node, IMG_MAP_CLIENT_MISSING_TEXT_LINKS );
            }
        }
    }
}


/****************************************************
* CheckForStyleAttribute
*
* Checks all elements within the document to check 
* for the use of 'STYLE' attribute.
****************************************************/

static void CheckForStyleAttribute( TidyDocImpl* doc, Node* node )
{
    Node* content;
    if (Level1_Enabled( doc ))
    {
        /* Must not contain 'STYLE' attribute */
        AttVal* style = attrGetSTYLE( node );
        if ( hasValue(style) )
        {
            TY_(ReportAccessError)( doc, node, STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR );
        }
    }

    /* Recursively check all child nodes.
    */
    for ( content = node->content; content != NULL; content = content->next )
        CheckForStyleAttribute( doc, content );
}


/*****************************************************
* CheckForListElements
*
* Checks document for list elements (<ol>, <ul>, <li>)
*****************************************************/

static void CheckForListElements( TidyDocImpl* doc, Node* node )
{
    if ( nodeIsLI(node) )
    {
        doc->access.ListElements++;
    }
    else if ( nodeIsOL(node) || nodeIsUL(node) )
    {
        doc->access.OtherListElements++;
    }

    for ( node = node->content; node != NULL; node = node->next )
    {
        CheckForListElements( doc, node );
    }
}


/******************************************************
* CheckListUsage
*
* Ensures that lists are properly used.  <ol> and <ul>
* must contain <li> within itself, and <li> must not be
* by itself.
******************************************************/

static void CheckListUsage( TidyDocImpl* doc, Node* node )
{
    int msgcode = 0;

    if (!Level2_Enabled( doc ))
        return;

    if ( nodeIsOL(node) )
        msgcode = LIST_USAGE_INVALID_OL;
    else if ( nodeIsUL(node) )
        msgcode = LIST_USAGE_INVALID_UL;

    if ( msgcode )
    {
       /*
       ** Check that OL/UL
       ** a) has LI child,
       ** b) was not added by Tidy parser
       ** IFF OL/UL node is implicit
       */
       if ( !nodeIsLI(node->content) ) {
            TY_(ReportAccessError)( doc, node, msgcode );
       } else if ( node->implicit ) {  /* if a tidy added node */
            TY_(ReportAccessError)( doc, node, LIST_USAGE_INVALID_LI );
       }
    }
    else if ( nodeIsLI(node) )
    {
        /* Check that LI parent 
        ** a) exists,
        ** b) is either OL or UL
        ** IFF the LI parent was added by Tidy
        ** ie, if it is marked 'implicit', then
        ** emit warnings LIST_USAGE_INVALID_UL or 
        ** warning LIST_USAGE_INVALID_OL tests 
        */
        if ( node->parent == NULL ||
             ( !nodeIsOL(node->parent) && !nodeIsUL(node->parent) ) )
        {
            TY_(ReportAccessError)( doc, node, LIST_USAGE_INVALID_LI );
        } else if ( node->implicit && node->parent &&
                    ( nodeIsOL(node->parent) || nodeIsUL(node->parent) ) ) {
            /* if tidy added LI node, then */
            msgcode = nodeIsUL(node->parent) ?
                LIST_USAGE_INVALID_UL : LIST_USAGE_INVALID_OL;
            TY_(ReportAccessError)( doc, node, msgcode );
        }
    }
}

/************************************************************
* InitAccessibilityChecks
*
* Initializes the AccessibilityChecks variables as necessary
************************************************************/

static void InitAccessibilityChecks( TidyDocImpl* doc, int level123 )
{
    TidyClearMemory( &doc->access, sizeof(doc->access) );
    doc->access.PRIORITYCHK = level123;
}

/************************************************************
* CleanupAccessibilityChecks
*
* Cleans up the AccessibilityChecks variables as necessary
************************************************************/


static void FreeAccessibilityChecks( TidyDocImpl* ARG_UNUSED(doc) )
{
    /* free any memory allocated for the lists

    Linked List of Links not used.  Just search document as 
    AREA tags are encountered.  Same algorithm, but no
    data structures necessary.

    current = start;
    while (current)
    {
        void    *templink = (void *)current;
        
        current = current->next;
        TidyDocFree(doc, templink);
    }
    start = NULL;
    */
}

/************************************************************
* AccessibilityChecks
*
* Traverses through the individual nodes of the tree
* and checks attributes and elements for accessibility.
* after the tree structure has been formed.
************************************************************/

static void AccessibilityCheckNode( TidyDocImpl* doc, Node* node )
{
    Node* content;
    
    /* Check BODY for color contrast */
    if ( nodeIsBODY(node) )
    {
        CheckColorContrast( doc, node );
    }

    /* Checks document for MetaData */
    else if ( nodeIsHEAD(node) )
    {
        if ( !CheckMetaData( doc, node, no ) )
          MetaDataPresent( doc, node );
    }
    
    /* Check the ANCHOR tag */
    else if ( nodeIsA(node) )
    {
        CheckAnchorAccess( doc, node );
    }

    /* Check the IMAGE tag */
    else if ( nodeIsIMG(node) )
    {
        CheckFlicker( doc, node );
        CheckColorAvailable( doc, node );
        CheckImage( doc, node );
    }

        /* Checks MAP for client-side text links */
    else if ( nodeIsMAP(node) )
    {
        CheckMapLinks( doc, node );
    }

    /* Check the AREA tag */
    else if ( nodeIsAREA(node) )
    {
        CheckArea( doc, node );
    }

    /* Check the APPLET tag */
    else if ( nodeIsAPPLET(node) )
    {
        CheckDeprecated( doc, node );
        ProgrammaticObjects( doc, node );
        DynamicContent( doc, node );
        AccessibleCompatible( doc, node );
        CheckFlicker( doc, node );
        CheckColorAvailable( doc, node );
        CheckApplet(doc, node );
    }
    
    /* Check the OBJECT tag */
    else if ( nodeIsOBJECT(node) )
    {
        ProgrammaticObjects( doc, node );
        DynamicContent( doc, node );
        AccessibleCompatible( doc, node );
        CheckFlicker( doc, node );
        CheckColorAvailable( doc, node );
        CheckObject( doc, node );
    }
    
    /* Check the FRAME tag */
    else if ( nodeIsFRAME(node) )
    {
        CheckFrame( doc, node );
    }
    
    /* Check the IFRAME tag */
    else if ( nodeIsIFRAME(node) )
    {
        CheckIFrame( doc, node );
    }
    
    /* Check the SCRIPT tag */
    else if ( nodeIsSCRIPT(node) )
    {
        DynamicContent( doc, node );
        ProgrammaticObjects( doc, node );
        AccessibleCompatible( doc, node );
        CheckFlicker( doc, node );
        CheckColorAvailable( doc, node );
        CheckScriptAcc( doc, node );
    }

    /* Check the TABLE tag */
    else if ( nodeIsTABLE(node) )
    {
        CheckColorContrast( doc, node );
        CheckTable( doc, node );
    }

    /* Check the PRE for ASCII art */
    else if ( nodeIsPRE(node) || nodeIsXMP(node) )
    {
        CheckASCII( doc, node );
    }

    /* Check the LABEL tag */
    else if ( nodeIsLABEL(node) )
    {
        CheckLabel( doc, node );
    }

    /* Check INPUT tag for validity */
    else if ( nodeIsINPUT(node) )
    {
        CheckColorAvailable( doc, node );
        CheckInputLabel( doc, node );
        CheckInputAttributes( doc, node );
    }

    /* Checks FRAMESET element for NOFRAME section */
    else if ( nodeIsFRAMESET(node) )
    {
        CheckFrameSet( doc, node );
    }
    
    /* Checks for header elements for valid header increase */
    else if ( TY_(nodeIsHeader)(node) )
    {
        CheckHeaderNesting( doc, node );
    }

    /* Checks P element to ensure that it is not a header */
    else if ( nodeIsP(node) )
    {
        CheckParagraphHeader( doc, node );
    }

    /* Checks HTML elemnt for valid 'LANG' */
    else if ( nodeIsHTML(node) )
    {
        CheckHTMLAccess( doc, node );
    }

    /* Checks BLINK for any blinking text */
    else if ( nodeIsBLINK(node) )
    {
        CheckBlink( doc, node );
    }

    /* Checks MARQUEE for any MARQUEE text */
    else if ( nodeIsMARQUEE(node) )
    {
        CheckMarquee( doc, node );
    }

    /* Checks LINK for 'REL' attribute */
    else if ( nodeIsLINK(node) )
    {
        CheckLink( doc, node );
    }

    /* Checks to see if STYLE is used */
    else if ( nodeIsSTYLE(node) )
    {
        CheckColorContrast( doc, node );
        CheckStyle( doc, node );
    }

    /* Checks to see if EMBED is used */
    else if ( nodeIsEMBED(node) )
    {
        CheckEmbed( doc, node );
        ProgrammaticObjects( doc, node );
        AccessibleCompatible( doc, node );
        CheckFlicker( doc, node );
    }

    /* Deprecated HTML if the following tags are found in the document */
    else if ( nodeIsBASEFONT(node) ||
              nodeIsCENTER(node)   ||
              nodeIsISINDEX(node)  ||
              nodeIsU(node)        ||
              nodeIsFONT(node)     ||
              nodeIsDIR(node)      ||
              nodeIsS(node)        ||
              nodeIsSTRIKE(node)   ||
              nodeIsMENU(node) )
    {
        CheckDeprecated( doc, node );
    }

    /* Checks for 'ABBR' attribute if needed */
    else if ( nodeIsTH(node) )
    {
        CheckTH( doc, node );
    }

    /* Ensures that lists are properly used */
    else if ( nodeIsLI(node) || nodeIsOL(node) || nodeIsUL(node) )
    {
        CheckListUsage( doc, node );
    }

    /* Recursively check all child nodes.
    */
    for ( content = node->content; content != NULL; content = content->next )
    {
        AccessibilityCheckNode( doc, content );
    }
}


void TY_(AccessibilityChecks)( TidyDocImpl* doc )
{
    /* Initialize */
    InitAccessibilityChecks( doc, cfg(doc, TidyAccessibilityCheckLevel) );

    /* Hello there, ladies and gentlemen... */
    TY_(Dialogue)( doc, STRING_HELLO_ACCESS );

    /* Checks all elements for script accessibility */
    CheckScriptKeyboardAccessible( doc, &doc->root );

    /* Checks entire document for the use of 'STYLE' attribute */
    CheckForStyleAttribute( doc, &doc->root );

    /* Checks for '!DOCTYPE' */
    CheckDocType( doc );

    
    /* Checks to see if stylesheets are used to control the layout */
    if ( Level2_Enabled( doc )
         && ! CheckMissingStyleSheets( doc, &doc->root ) )
    {
        TY_(ReportAccessError)( doc, &doc->root, STYLE_SHEET_CONTROL_PRESENTATION );
    }

    /* Check to see if any list elements are found within the document */
    CheckForListElements( doc, &doc->root );

    /* Recursively apply all remaining checks to 
    ** each node in document.
    */
    AccessibilityCheckNode( doc, &doc->root );

    /* Cleanup */
    FreeAccessibilityChecks( doc );
}

/* alloc.c -- Default memory allocation routines.

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #define DEBUG_MEMORY very NOISY extra DEBUG of memory allocation, reallocation and free */

/* #include "tidy.h" */
/* #include "forward.h" */
/* #include "sprtf.h" */

static TidyMalloc  g_malloc  = NULL;
static TidyRealloc g_realloc = NULL;
static TidyFree    g_free    = NULL;
static TidyPanic   g_panic   = NULL;

#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_MEMORY)
static int alloccnt = 0;
static int realloccnt = 0;
static int freecnt = 0;
#endif


Bool TIDY_CALL tidySetMallocCall( TidyMalloc fmalloc )
{
  g_malloc  = fmalloc;
  return yes;
}
Bool TIDY_CALL tidySetReallocCall( TidyRealloc frealloc )
{
  g_realloc = frealloc;
  return yes;
}
Bool TIDY_CALL tidySetFreeCall( TidyFree ffree )
{
  g_free    = ffree;
  return yes;
}
Bool TIDY_CALL tidySetPanicCall( TidyPanic fpanic )
{
  g_panic   = fpanic;
  return yes;
}

static void TIDY_CALL defaultPanic( TidyAllocator* ARG_UNUSED(allocator), ctmbstr msg )
{
  if ( g_panic )
    g_panic( msg );
  else
  {
    /* 2 signifies a serious error */
    fprintf( stderr, "Fatal error: %s\n", msg );
#ifdef _DEBUG
    assert(0);
#endif
    exit(2);
  }
}

static void* TIDY_CALL defaultAlloc( TidyAllocator* allocator, size_t size )
{
    void *p = ( g_malloc ? g_malloc(size) : malloc(size) );
    if ( !p )
        defaultPanic( allocator,"Out of memory!");
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_MEMORY)
    alloccnt++;
    SPRTF("%d: alloc   MEM %p, size %d\n", alloccnt, p, (int)size );
    if (size == 0) {
        SPRTF("NOTE: An allocation of ZERO bytes!!!!!!\n");
    }
#endif
    return p;
}

static void* TIDY_CALL defaultRealloc( TidyAllocator* allocator, void* mem, size_t newsize )
{
    void *p;
    if ( mem == NULL )
        return defaultAlloc( allocator, newsize );

    p = ( g_realloc ? g_realloc(mem, newsize) : realloc(mem, newsize) );
    if (!p)
        defaultPanic( allocator, "Out of memory!");
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_MEMORY)
    realloccnt++;
    SPRTF("%d: realloc MEM %p, size %d\n", realloccnt, p, (int)newsize );
#endif
    return p;
}

static void TIDY_CALL defaultFree( TidyAllocator* ARG_UNUSED(allocator), void* mem )
{
    if ( mem )
    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_MEMORY)
        freecnt++;
        SPRTF("%d: free    MEM %p\n", freecnt, mem );
#endif
        if ( g_free )
            g_free( mem );
        else
            free( mem );
    }
}

static const TidyAllocatorVtbl defaultVtbl = {
    defaultAlloc,
    defaultRealloc,
    defaultFree,
    defaultPanic
};

TidyAllocator TY_(g_default_allocator) = {
    &defaultVtbl
};

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* attrdict.c -- extended attribute information

   (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
   See tidy.h for the copyright notice.

*/

/* #include "forward.h" */
/* #include "attrdict.h" */
/* #include "lexer.h" */

/* These items are added to elements that support them. */
#define INCLUDE_ARIA \
  { TidyAttr_ARIA_ACTIVEDESCENDANT, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_ATOMIC,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_AUTOCOMPLETE,     xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_BUSY,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_CHECKED,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_CONTROLS,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_DESCRIBEDBY,      xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_DISABLED,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_DROPEFFECT,       xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_EXPANDED,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_FLOWTO,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_GRABBED,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_HASPOPUP,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_HIDDEN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_INVALID,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_LABEL,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_LABELLEDBY,       xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_LEVEL,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_LIVE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_MULTILINE,        xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_MULTISELECTABLE,  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_ORIENTATION,      xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_OWNS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_POSINSET,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_PRESSED,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_READONLY,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_RELEVANT,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_REQUIRED,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_SELECTED,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_SETSIZE,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_SORT,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_VALUEMAX,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_VALUEMIN,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_VALUENOW,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ARIA_VALUETEXT,        xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \


/* These items are added to all elements below. */
#define INCLUDE_MICRODATA \
  { TidyAttr_ITEMID,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ITEMPROP,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ITEMREF,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ITEMSCOPE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ITEMTYPE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \


/* RDFa attributes. These were moved here from the hard code in attrs.c as-is. Note that RDFa allows the
   last three items in all versions of HTML. */
#define INCLUDE_RDFA \
  { TidyAttr_ABOUT,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_DATATYPE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_INLIST,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_PREFIX,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_PROPERTY,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_RESOURCE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_TYPEOF,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_VOCAB,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_CONTENT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, \
  { TidyAttr_REL,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, \
  { TidyAttr_REV,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, \


/* These are the core attributes that can apply to _any_ element starting with
   HTML5. In general they will be marked as not supported for previous versions
   of HTML, in which case please override the attribute in the specific item
   below. **This macro must be expanded at the END of each element. **
   Most of these attributes are defined as universal for HTML here:
     https://www.w3.org/TR/html-markup/global-attributes.html
   Attribute `role` is defined as universal for HTML5 here:
     https://www.w3.org/TR/html5/dom.html#wai-aria
 */
#define INCLUDE_CORE_ATTRIBS \
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_CONTENTEDITABLE,       xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_CONTEXTMENU,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_DRAGGABLE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_DROPZONE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_HIDDEN,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_IS,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_LANG,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_ROLE,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_SPELLCHECK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_TABINDEX,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_TRANSLATE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, \
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \


/* These are the core event-handler attributes that can apply to _any_ element
   starting with HTML5. In general they will be marked as not supported for
   previous versions of HTML, in which case please override the attribute in the
   specific item below. **This macro must be expanded at the END of each 
   element. **
   Most of these attributes are defined as universal for HTML5 here:
     https://www.w3.org/TR/html-markup/global-attributes.html
   Attribute `oncuechange` is defined as universal for HTML5 here:
     https://www.w3.org/TR/html5/webappapis.html
 */
#define INCLUDE_CORE_EVENTS \
  { TidyAttr_OnABORT,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnBLUR,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnCANPLAY,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnCANPLAYTHROUGH,      xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnCHANGE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnCONTEXTMENU,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnCUECHANGE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDRAG,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDRAGEND,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDRAGENTER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDRAGLEAVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDRAGOVER,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDRAGSTART,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDROP,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnDURATIONCHANGE,      xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnEMPTIED,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnENDED,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnERROR,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnFOCUS,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnINPUT,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnINVALID,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnLOAD,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnLOADEDDATA,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnLOADEDMETADATA,      xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnLOADSTART,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnMOUSEWHEEL,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnPAUSE,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnPLAY,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnPLAYING,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnPROGRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnRATECHANGE,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnREADYSTATECHANGE,    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnRESET,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSCROLL,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSEEKED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSEEKING,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSELECT,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSHOW,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSTALLED,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSUBMIT,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnSUSPEND,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnTIMEUPDATE,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnVOLUMECHANGE,        xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \
  { TidyAttr_OnWAITING,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, \


const AttrVersion TY_(W3CAttrsFor_A)[] =
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_CHARSET,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COORDS,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DOWNLOAD,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_HREF,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_HREFLANG,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MEDIA,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_METHODS,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_NAME,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_REL,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_REV,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SHAPE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TARGET,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TITLE,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_URN,                   HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_ABBR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_ACRONYM)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_ADDRESS)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_APPLET)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ALT,                   xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ARCHIVE,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_CODE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CODEBASE,              xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_HEIGHT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_HSPACE,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_NAME,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OBJECT,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_VSPACE,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_AREA)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ALT,                   xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_COORDS,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HREF,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_HREFLANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MEDIA,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NOHREF,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_REL,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SHAPE,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TARGET,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_ARTICLE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_ASIDE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_AUDIO)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_AUTOPLAY,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CONTROLS,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CROSSORIGIN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LOOP,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MEDIAGROUP,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_PRELOAD,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_B)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BASE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_HREF,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TARGET,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BASEFONT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_COLOR,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_FACE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_SIZE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BDI)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BDO)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BIG)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BLOCKQUOTE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CITE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BODY)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALINK,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_BACKGROUND,            xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_BGCOLOR,               xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LINK,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnAFTERPRINT,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnBEFOREPRINT,         xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnBEFOREUNLOAD,        xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnHASHCHANGE,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnLOAD,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMESSAGE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnOFFLINE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnONLINE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnPAGEHIDE,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnPAGESHOW,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnPOPSTATE,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnREDO,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnRESIZE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnSTORAGE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnUNDO,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnUNLOAD,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TEXT,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_VLINK,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_CLEAR,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_BUTTON)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_AUTOFOCUS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISABLED,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMACTION,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMENCTYPE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMMETHOD,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMNOVALIDATE,        xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMTARGET,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NAME,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_VALUE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_CANVAS)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_HEIGHT,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_WIDTH,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_CAPTION)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_CENTER)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_CITE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_CODE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_COL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SPAN,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_COLGROUP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SPAN,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_COMMAND)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CHECKED,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DISABLED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ICON,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LABEL,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_RADIOGROUP,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TYPE,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DATALIST)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DD)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DEL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CITE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DATETIME,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DETAILS)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_OPEN,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DFN)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DIALOG)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_OPEN,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DIR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_COMPACT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DIV)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COMPACT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_EM)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_EMBED)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_HEIGHT,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TYPE,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_WIDTH,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FIELDSET)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISABLED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FIGCAPTION)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FIGURE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FONT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_COLOR,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_FACE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_SIZE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FOOTER)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FORM)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCEPT,                xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_ACCEPT_CHARSET,        xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_ACTION,                HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_AUTOCOMPLETE,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ENCTYPE,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_METHOD,                HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NOVALIDATE,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnRESET,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnSUBMIT,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDASUFF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TARGET,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FRAME)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_FRAMEBORDER,           xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LONGDESC,              xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_MARGINHEIGHT,          xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_MARGINWIDTH,           xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_NORESIZE,              xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SCROLLING,             xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SRC,                   xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_FRAMESET)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_COLS,                  xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnLOAD,                xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnUNLOAD,              xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ROWS,                  xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_H1)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_H2)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_H3)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_H4)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_H5)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_H6)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_HEAD)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_PROFILE,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_HEADER)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_HGROUP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_HR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NOSHADE,               xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SIZE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_HTML)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MANIFEST,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_VERSION,               HT20|HT32|H40T|H41T|xxxx|H40F|H41F|xxxx|xxxx|xxxx|xxxx|XH11|XB10|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_I)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_IFRAME)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ALLOWFULLSCREEN,       xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_FRAMEBORDER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_HEIGHT,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LONGDESC,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_MARGINHEIGHT,          xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_MARGINWIDTH,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_NAME,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SANDBOX,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SCROLLING,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SEAMLESS,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRCDOC,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_WIDTH,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_IMG)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ALT,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_BORDER,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_CROSSORIGIN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HEIGHT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_HSPACE,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_ISMAP,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LONGDESC,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SIZES,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_SRCSET,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_USEMAP,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_VSPACE,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_INPUT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCEPT,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_ALIGN,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ALT,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_AUTOCOMPLETE,          xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_AUTOFOCUS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CHECKED,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIRNAME,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DISABLED,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMACTION,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMENCTYPE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMMETHOD,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMNOVALIDATE,        xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORMTARGET,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_HEIGHT,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_ISMAP,                 xxxx|xxxx|xxxx|H41T|xxxx|xxxx|H41F|xxxx|xxxx|H41S|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LIST,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MAX,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MAXLENGTH,             HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_MIN,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MULTIPLE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NAME,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCHANGE,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnSELECT,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_PATTERN,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_PLACEHOLDER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_READONLY,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_REQUIRED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SIZE,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_SRC,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_STEP,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_USEMAP,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_VALUE,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_WIDTH,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_INS)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CITE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DATETIME,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_ISINDEX)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_PROMPT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_KBD)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_KEYGEN)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_AUTOFOCUS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CHALLENGE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DISABLED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_KEYTYPE,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_LABEL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_FOR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_LEGEND)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_LI)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_VALUE,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_LINK)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_AS,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CHARSET,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COLOR,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* Is #686 */
  { TidyAttr_CROSSORIGIN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HREF,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_HREFLANG,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_INTEGRITY,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MEDIA,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_METHODS,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_REL,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_REV,                   HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SIZES,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TARGET,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_TITLE,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_URN,                   HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_LISTING)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_MAIN)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_MAP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NAME,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_MATHML)[] =  /* [i_a]2 */
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISPLAY,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HEIGHT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_MARK)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_MENU)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_COMPACT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LABEL,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_MENUITEM)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_AUTOFOCUS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CHALLENGE,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DISABLED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ICON,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_KEYTYPE,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LABEL,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_META)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CHARSET,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CONTENT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HTTP_EQUIV,            HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NAME,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_SCHEME,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_METER)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_HIGH,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LOW,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MAX,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MIN,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OPTIMUM,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_VALUE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_NAV)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_NEXTID)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_N,                     HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_NOFRAMES)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_NOSCRIPT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_OBJECT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ARCHIVE,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_BORDER,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_CLASSID,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_CODEBASE,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_CODETYPE,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_DATA,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_DECLARE,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_HEIGHT,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_HSPACE,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NAME,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STANDBY,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_USEMAP,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_VSPACE,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_OL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COMPACT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_REVERSED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_START,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_OPTGROUP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISABLED,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LABEL,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_OPTION)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISABLED,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LABEL,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SELECTED,              HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALUE,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_OUTPUT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_FOR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NAME,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_P)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_PARAM)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_NAME,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_VALUE,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_VALUETYPE,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};


const AttrVersion TY_(W3CAttrsFor_PICTURE)[] = /* Issue #151 - support for 'picture' tag - TODO: check list of attributes */
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_MEDIA,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SRCSET,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_PLAINTEXT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_SDAFORM,            HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,            0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_PRE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_WIDTH,                 HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  { TidyAttr_XML_SPACE,             xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_PROGRESS)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MAX,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_VALUE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_Q)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CITE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_RB)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_RBC)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_RP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_RT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_RBSPAN,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_RTC)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_RUBY)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_S)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SAMP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SCRIPT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ASYNC,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CHARSET,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CROSSORIGIN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_DEFER,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_EVENT,                 xxxx|xxxx|H40T|H41T|xxxx|H40F|H41F|xxxx|H40S|H41S|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_FOR,                   xxxx|xxxx|H40T|H41T|xxxx|H40F|H41F|xxxx|H40S|H41S|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_INTEGRITY,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LANGUAGE,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SRC,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_SPACE,             xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SECTION)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SELECT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_AUTOFOCUS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISABLED,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MULTIPLE,              HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_NAME,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCHANGE,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_REQUIRED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SIZE,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SMALL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SOURCE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_MEDIA,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRCSET,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TYPE,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SPAN)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_STRIKE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_STRONG)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_STYLE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MEDIA,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_SCOPED,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  { TidyAttr_XML_SPACE,             xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SUB)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SUMMARY)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SUP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_SVG)[] =
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HEIGHT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */

  /* svg xmln:xlink=uri */
  { TidyAttr_XMLNSXLINK,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },

  { TidyAttr_X,                     xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_Y,                     xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_VIEWBOX,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_PRESERVEASPECTRATIO,   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_ZOOMANDPAN,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_VERSION,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_BASEPROFILE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CONTENTSCRIPTTYPE,     xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CONTENTSTYLETYPE,      xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TABLE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_BGCOLOR,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_BORDER,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_CELLPADDING,           xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CELLSPACING,           xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DATAPAGESIZE,          xxxx|xxxx|H40T|H41T|xxxx|H40F|H41F|xxxx|H40S|H41S|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_FRAME,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_RULES,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SUMMARY,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TBODY)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TD)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ABBR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_AXIS,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_BGCOLOR,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COLSPAN,               xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HEADERS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_HEIGHT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NOWRAP,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ROWSPAN,               xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_SCOPE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TEXTAREA)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ACCESSKEY,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_AUTOFOCUS,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COLS,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DISABLED,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_FORM,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_MAXLENGTH,             xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_NAME,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_OnBLUR,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCHANGE,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnFOCUS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnSELECT,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_PLACEHOLDER,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_READONLY,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 },
  { TidyAttr_REQUIRED,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_ROWS,                  HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TABINDEX,              xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_WRAP,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TFOOT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TH)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ABBR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_AXIS,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_BGCOLOR,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COLSPAN,               xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_HEADERS,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_HEIGHT,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_NOWRAP,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ROWSPAN,               xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_SCOPE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_WIDTH,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_THEAD)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TEMPLATE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TIME)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_DATETIME,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_PUBDATE,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_DATA)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_VALUE,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TITLE)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_ALIGN,                 xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_BGCOLOR,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_CHAR,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CHAROFF,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx },
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_VALIGN,                xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TRACK)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_DEFAULT,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_KIND,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LABEL,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRCLANG,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_TT)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_U)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_UL)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_COMPACT,               HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_TYPE,                  xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_VAR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_CLASS,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_DIR,                   xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_ID,                    xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_LANG,                  xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|xxxx|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnCLICK,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnDBLCLICK,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYDOWN,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYPRESS,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnKEYUP,               xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEDOWN,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEMOVE,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOUT,            xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEOVER,           xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_OnMOUSEUP,             xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_STYLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50 }, /* CORE override */
  { TidyAttr_TITLE,                 xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XMLNS,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|XB10|HT50|XH50 }, /* CORE override */
  { TidyAttr_XML_LANG,              xxxx|xxxx|xxxx|xxxx|X10T|xxxx|xxxx|X10F|xxxx|xxxx|X10S|XH11|XB10|xxxx|XH50 }, /* CORE override */
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_VIDEO)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_AUTOPLAY,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CONTROLS,              xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_CROSSORIGIN,           xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_HEIGHT,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_LOOP,                  xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_MEDIAGROUP,            xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_POSTER,                xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_PRELOAD,               xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_SRC,                   xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  { TidyAttr_WIDTH,                 xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50 },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_WBR)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

const AttrVersion TY_(W3CAttrsFor_XMP)[] = 
{
  INCLUDE_ARIA
  INCLUDE_MICRODATA
  { TidyAttr_SDAFORM,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  { TidyAttr_SDAPREF,               HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx },
  INCLUDE_CORE_ATTRIBS
  INCLUDE_CORE_EVENTS
  INCLUDE_RDFA
  { TidyAttr_UNKNOWN,               0                                                                          },
};

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* attrs.c -- recognize HTML attributes

  (c) 1998-2009 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "tidy-int.h" */
/* #include "attrs.h" */
/* #include "message.h" */
/* #include "tmbstr.h" */
/* #include "utf8.h" */

/*
 Bind attribute types to procedures to check values.
 You can add new procedures for better validation
 and each procedure has access to the node in which
 the attribute occurred as well as the attribute name
 and its value.

 By default, attributes are checked without regard
 to the element they are found on. You have the choice
 of making the procedure test which element is involved
 or in writing methods for each element which controls
 exactly how the attributes of that element are checked.
 This latter approach is best for detecting the absence
 of required attributes.
*/

static AttrCheck CheckAction;
static AttrCheck CheckScript;
static AttrCheck CheckName;
static AttrCheck CheckId;
static AttrCheck CheckIs;
static AttrCheck CheckAlign;
static AttrCheck CheckValign;
static AttrCheck CheckBool;
static AttrCheck CheckLength;
static AttrCheck CheckTarget;
static AttrCheck CheckFsubmit;
static AttrCheck CheckClear;
static AttrCheck CheckShape;
static AttrCheck CheckNumber;
static AttrCheck CheckScope;
static AttrCheck CheckColor;
static AttrCheck CheckVType;
static AttrCheck CheckScroll;
static AttrCheck CheckTextDir;
static AttrCheck CheckLang;
static AttrCheck CheckType;
static AttrCheck CheckRDFaSafeCURIE;
static AttrCheck CheckRDFaTerm;
static AttrCheck CheckRDFaPrefix;

#define CH_PCDATA      NULL
#define CH_CHARSET     NULL
#define CH_TYPE        CheckType
#define CH_XTYPE       NULL
#define CH_CHARACTER   NULL
#define CH_URLS        NULL
#define CH_URL         TY_(CheckUrl)
#define CH_SCRIPT      CheckScript
#define CH_ALIGN       CheckAlign
#define CH_VALIGN      CheckValign
#define CH_COLOR       CheckColor
#define CH_CLEAR       CheckClear
#define CH_BORDER      CheckBool     /* kludge */
#define CH_LANG        CheckLang
#define CH_BOOL        CheckBool
#define CH_COLS        NULL
#define CH_NUMBER      CheckNumber
#define CH_LENGTH      CheckLength
#define CH_COORDS      NULL
#define CH_DATE        NULL
#define CH_TEXTDIR     CheckTextDir
#define CH_IDREFS      NULL
#define CH_IDREF       NULL
#define CH_IDDEF       CheckId
#define CH_ISDEF       CheckIs
#define CH_NAME        CheckName
#define CH_TFRAME      NULL
#define CH_FBORDER     NULL
#define CH_MEDIA       NULL
#define CH_FSUBMIT     CheckFsubmit
#define CH_LINKTYPES   NULL
#define CH_TRULES      NULL
#define CH_SCOPE       CheckScope
#define CH_SHAPE       CheckShape
#define CH_SCROLL      CheckScroll
#define CH_TARGET      CheckTarget
#define CH_VTYPE       CheckVType
#define CH_ACTION      CheckAction
#define CH_RDFAPREFIX  CheckRDFaPrefix
#define CH_RDFASCURIE  CheckRDFaSafeCURIE
#define CH_RDFASCURIES CheckRDFaSafeCURIE
#define CH_RDFATERM    CheckRDFaTerm
#define CH_RDFATERMS   CheckRDFaTerm

static const Attribute attribute_defs [] =
{
  { TidyAttr_UNKNOWN,                 "unknown!",                NULL         }, 
  { TidyAttr_ABBR,                    "abbr",                    CH_PCDATA    }, 
  { TidyAttr_ACCEPT,                  "accept",                  CH_XTYPE     }, 
  { TidyAttr_ACCEPT_CHARSET,          "accept-charset",          CH_CHARSET   }, 
  { TidyAttr_ACCESSKEY,               "accesskey",               CH_CHARACTER }, 
  { TidyAttr_ACTION,                  "action",                  CH_ACTION    }, 
  { TidyAttr_ADD_DATE,                "add_date",                CH_PCDATA    }, /* A */
  { TidyAttr_ALIGN,                   "align",                   CH_ALIGN     }, /* varies by element */
  { TidyAttr_ALINK,                   "alink",                   CH_COLOR     }, 
  { TidyAttr_ALLOWFULLSCREEN,         "allowfullscreen",         CH_BOOL      },
  { TidyAttr_ALT,                     "alt",                     CH_PCDATA    }, /* nowrap */
  { TidyAttr_ARCHIVE,                 "archive",                 CH_URLS      }, /* space or comma separated list */
  { TidyAttr_AXIS,                    "axis",                    CH_PCDATA    }, 
  { TidyAttr_BACKGROUND,              "background",              CH_URL       }, 
  { TidyAttr_BGCOLOR,                 "bgcolor",                 CH_COLOR     }, 
  { TidyAttr_BGPROPERTIES,            "bgproperties",            CH_PCDATA    }, /* BODY "fixed" fixes background */
  { TidyAttr_BORDER,                  "border",                  CH_BORDER    }, /* like LENGTH + "border" */
  { TidyAttr_BORDERCOLOR,             "bordercolor",             CH_COLOR     }, /* used on TABLE */
  { TidyAttr_BOTTOMMARGIN,            "bottommargin",            CH_NUMBER    }, /* used on BODY */
  { TidyAttr_CELLPADDING,             "cellpadding",             CH_LENGTH    }, /* % or pixel values */
  { TidyAttr_CELLSPACING,             "cellspacing",             CH_LENGTH    }, 
  { TidyAttr_CHAR,                    "char",                    CH_CHARACTER }, 
  { TidyAttr_CHAROFF,                 "charoff",                 CH_LENGTH    }, 
  { TidyAttr_CHARSET,                 "charset",                 CH_CHARSET   }, 
  { TidyAttr_CHECKED,                 "checked",                 CH_BOOL      }, /* i.e. "checked" or absent */
  { TidyAttr_CITE,                    "cite",                    CH_URL       }, 
  { TidyAttr_CLASS,                   "class",                   CH_PCDATA    }, 
  { TidyAttr_CLASSID,                 "classid",                 CH_URL       }, 
  { TidyAttr_CLEAR,                   "clear",                   CH_CLEAR     }, /* BR: left, right, all */
  { TidyAttr_CODE,                    "code",                    CH_PCDATA    }, /* APPLET */
  { TidyAttr_CODEBASE,                "codebase",                CH_URL       }, /* OBJECT */
  { TidyAttr_CODETYPE,                "codetype",                CH_XTYPE     }, /* OBJECT */
  { TidyAttr_COLOR,                   "color",                   CH_COLOR     }, /* BASEFONT, FONT */
  { TidyAttr_COLS,                    "cols",                    CH_COLS      }, /* TABLE & FRAMESET */
  { TidyAttr_COLSPAN,                 "colspan",                 CH_NUMBER    }, 
  { TidyAttr_COMPACT,                 "compact",                 CH_BOOL      }, /* lists */
  { TidyAttr_CONTENT,                 "content",                 CH_PCDATA    }, 
  { TidyAttr_COORDS,                  "coords",                  CH_COORDS    }, /* AREA, A */
  { TidyAttr_DATA,                    "data",                    CH_URL       }, /* OBJECT */
  { TidyAttr_DATAFLD,                 "datafld",                 CH_PCDATA    }, /* used on DIV, IMG */
  { TidyAttr_DATAFORMATAS,            "dataformatas",            CH_PCDATA    }, /* used on DIV, IMG */
  { TidyAttr_DATAPAGESIZE,            "datapagesize",            CH_NUMBER    }, /* used on DIV, IMG */
  { TidyAttr_DATASRC,                 "datasrc",                 CH_URL       }, /* used on TABLE */
  { TidyAttr_DATETIME,                "datetime",                CH_DATE      }, /* INS, DEL */
  { TidyAttr_DECLARE,                 "declare",                 CH_BOOL      }, /* OBJECT */
  { TidyAttr_DEFER,                   "defer",                   CH_BOOL      }, /* SCRIPT */
  { TidyAttr_DIR,                     "dir",                     CH_TEXTDIR   }, /* ltr, rtl or auto */
  { TidyAttr_DISABLED,                "disabled",                CH_BOOL      }, /* form fields */
  { TidyAttr_DOWNLOAD,                "download",                CH_PCDATA    }, /* anchor */
  { TidyAttr_ENCODING,                "encoding",                CH_PCDATA    }, /* <?xml?> */
  { TidyAttr_ENCTYPE,                 "enctype",                 CH_XTYPE     }, /* FORM */
  { TidyAttr_FACE,                    "face",                    CH_PCDATA    }, /* BASEFONT, FONT */
  { TidyAttr_FOR,                     "for",                     CH_IDREF     }, /* LABEL */
  { TidyAttr_FRAME,                   "frame",                   CH_TFRAME    }, /* TABLE */
  { TidyAttr_FRAMEBORDER,             "frameborder",             CH_FBORDER   }, /* 0 or 1 */
  { TidyAttr_FRAMESPACING,            "framespacing",            CH_NUMBER    }, 
  { TidyAttr_GRIDX,                   "gridx",                   CH_NUMBER    }, /* TABLE Adobe golive*/
  { TidyAttr_GRIDY,                   "gridy",                   CH_NUMBER    }, /* TABLE Adobe golive */
  { TidyAttr_HEADERS,                 "headers",                 CH_IDREFS    }, /* table cells */
  { TidyAttr_HEIGHT,                  "height",                  CH_LENGTH    }, /* pixels only for TH/TD */
  { TidyAttr_HREF,                    "href",                    CH_URL       }, /* A, AREA, LINK and BASE */
  { TidyAttr_HREFLANG,                "hreflang",                CH_LANG      }, /* A, LINK */
  { TidyAttr_HSPACE,                  "hspace",                  CH_NUMBER    }, /* APPLET, IMG, OBJECT */
  { TidyAttr_HTTP_EQUIV,              "http-equiv",              CH_PCDATA    }, /* META */
  { TidyAttr_ID,                      "id",                      CH_IDDEF     }, 
  { TidyAttr_IS,                      "is",                      CH_ISDEF     },
  { TidyAttr_ISMAP,                   "ismap",                   CH_BOOL      }, /* IMG */
  { TidyAttr_ITEMID,                  "itemid",                  CH_PCDATA    },
  { TidyAttr_ITEMPROP,                "itemprop",                CH_PCDATA    },
  { TidyAttr_ITEMREF,                 "itemref",                 CH_PCDATA    },
  { TidyAttr_ITEMSCOPE,               "itemscope",               CH_BOOL      },
  { TidyAttr_ITEMTYPE,                "itemtype",                CH_URL       },
  { TidyAttr_LABEL,                   "label",                   CH_PCDATA    }, /* OPT, OPTGROUP */
  { TidyAttr_LANG,                    "lang",                    CH_LANG      }, 
  { TidyAttr_LANGUAGE,                "language",                CH_PCDATA    }, /* SCRIPT */
  { TidyAttr_LAST_MODIFIED,           "last_modified",           CH_PCDATA    }, /* A */
  { TidyAttr_LAST_VISIT,              "last_visit",              CH_PCDATA    }, /* A */
  { TidyAttr_LEFTMARGIN,              "leftmargin",              CH_NUMBER    }, /* used on BODY */
  { TidyAttr_LINK,                    "link",                    CH_COLOR     }, /* BODY */
  { TidyAttr_LONGDESC,                "longdesc",                CH_URL       }, /* IMG */
  { TidyAttr_LOWSRC,                  "lowsrc",                  CH_URL       }, /* IMG */
  { TidyAttr_MARGINHEIGHT,            "marginheight",            CH_NUMBER    }, /* FRAME, IFRAME, BODY */
  { TidyAttr_MARGINWIDTH,             "marginwidth",             CH_NUMBER    }, /* ditto */
  { TidyAttr_MAXLENGTH,               "maxlength",               CH_NUMBER    }, /* INPUT */
  { TidyAttr_MEDIA,                   "media",                   CH_MEDIA     }, /* STYLE, LINK */
  { TidyAttr_METHOD,                  "method",                  CH_FSUBMIT   }, /* FORM: get or post */
  { TidyAttr_MULTIPLE,                "multiple",                CH_BOOL      }, /* SELECT */
  { TidyAttr_NAME,                    "name",                    CH_NAME      }, 
  { TidyAttr_NOHREF,                  "nohref",                  CH_BOOL      }, /* AREA */
  { TidyAttr_NORESIZE,                "noresize",                CH_BOOL      }, /* FRAME */
  { TidyAttr_NOSHADE,                 "noshade",                 CH_BOOL      }, /* HR */
  { TidyAttr_NOWRAP,                  "nowrap",                  CH_BOOL      }, /* table cells */
  { TidyAttr_OBJECT,                  "object",                  CH_PCDATA    }, /* APPLET */
  { TidyAttr_OnAFTERUPDATE,           "onafterupdate",           CH_SCRIPT    }, 
  { TidyAttr_OnBEFOREUNLOAD,          "onbeforeunload",          CH_SCRIPT    }, 
  { TidyAttr_OnBEFOREUPDATE,          "onbeforeupdate",          CH_SCRIPT    }, 
  { TidyAttr_OnBLUR,                  "onblur",                  CH_SCRIPT    }, /* event */
  { TidyAttr_OnCHANGE,                "onchange",                CH_SCRIPT    }, /* event */
  { TidyAttr_OnCLICK,                 "onclick",                 CH_SCRIPT    }, /* event */
  { TidyAttr_OnDATAAVAILABLE,         "ondataavailable",         CH_SCRIPT    }, /* object, applet */
  { TidyAttr_OnDATASETCHANGED,        "ondatasetchanged",        CH_SCRIPT    }, /* object, applet */
  { TidyAttr_OnDATASETCOMPLETE,       "ondatasetcomplete",       CH_SCRIPT    }, 
  { TidyAttr_OnDBLCLICK,              "ondblclick",              CH_SCRIPT    }, /* event */
  { TidyAttr_OnERRORUPDATE,           "onerrorupdate",           CH_SCRIPT    }, /* form fields */
  { TidyAttr_OnFOCUS,                 "onfocus",                 CH_SCRIPT    }, /* event */
  { TidyAttr_OnKEYDOWN,               "onkeydown",               CH_SCRIPT    }, /* event */
  { TidyAttr_OnKEYPRESS,              "onkeypress",              CH_SCRIPT    }, /* event */
  { TidyAttr_OnKEYUP,                 "onkeyup",                 CH_SCRIPT    }, /* event */
  { TidyAttr_OnLOAD,                  "onload",                  CH_SCRIPT    }, /* event */
  { TidyAttr_OnMOUSEDOWN,             "onmousedown",             CH_SCRIPT    }, /* event */
  { TidyAttr_OnMOUSEMOVE,             "onmousemove",             CH_SCRIPT    }, /* event */
  { TidyAttr_OnMOUSEOUT,              "onmouseout",              CH_SCRIPT    }, /* event */
  { TidyAttr_OnMOUSEOVER,             "onmouseover",             CH_SCRIPT    }, /* event */
  { TidyAttr_OnMOUSEUP,               "onmouseup",               CH_SCRIPT    }, /* event */
  { TidyAttr_OnRESET,                 "onreset",                 CH_SCRIPT    }, /* event */
  { TidyAttr_OnROWENTER,              "onrowenter",              CH_SCRIPT    }, /* form fields */
  { TidyAttr_OnROWEXIT,               "onrowexit",               CH_SCRIPT    }, /* form fields */
  { TidyAttr_OnSELECT,                "onselect",                CH_SCRIPT    }, /* event */
  { TidyAttr_OnSUBMIT,                "onsubmit",                CH_SCRIPT    }, /* event */
  { TidyAttr_OnUNLOAD,                "onunload",                CH_SCRIPT    }, /* event */
  { TidyAttr_PROFILE,                 "profile",                 CH_URL       }, /* HEAD */
  { TidyAttr_PROMPT,                  "prompt",                  CH_PCDATA    }, /* ISINDEX */
  { TidyAttr_RBSPAN,                  "rbspan",                  CH_NUMBER    }, /* ruby markup */
  { TidyAttr_READONLY,                "readonly",                CH_BOOL      }, /* form fields */
  { TidyAttr_REL,                     "rel",                     CH_LINKTYPES }, 
  { TidyAttr_REV,                     "rev",                     CH_LINKTYPES }, 
  { TidyAttr_RIGHTMARGIN,             "rightmargin",             CH_NUMBER    }, /* used on BODY */
  { TidyAttr_ROLE,                    "role",                    CH_PCDATA    },
  { TidyAttr_ROWS,                    "rows",                    CH_NUMBER    }, /* TEXTAREA */
  { TidyAttr_ROWSPAN,                 "rowspan",                 CH_NUMBER    }, /* table cells */
  { TidyAttr_RULES,                   "rules",                   CH_TRULES    }, /* TABLE */
  { TidyAttr_SCHEME,                  "scheme",                  CH_PCDATA    }, /* META */
  { TidyAttr_SCOPE,                   "scope",                   CH_SCOPE     }, /* table cells */
  { TidyAttr_SCROLLING,               "scrolling",               CH_SCROLL    }, /* yes, no or auto */
  { TidyAttr_SELECTED,                "selected",                CH_BOOL      }, /* OPTION */
  { TidyAttr_SHAPE,                   "shape",                   CH_SHAPE     }, /* AREA, A */
  { TidyAttr_SHOWGRID,                "showgrid",                CH_BOOL      }, /* TABLE Adobe golive */
  { TidyAttr_SHOWGRIDX,               "showgridx",               CH_BOOL      }, /* TABLE Adobe golive*/
  { TidyAttr_SHOWGRIDY,               "showgridy",               CH_BOOL      }, /* TABLE Adobe golive*/
  { TidyAttr_SIZE,                    "size",                    CH_NUMBER    }, /* HR, FONT, BASEFONT, SELECT */
  { TidyAttr_SPAN,                    "span",                    CH_NUMBER    }, /* COL, COLGROUP */
  { TidyAttr_SRC,                     "src",                     CH_URL       }, /* IMG, FRAME, IFRAME */
  { TidyAttr_SRCSET,                  "srcset",                  CH_PCDATA    }, /* IMG (HTML5) */
  { TidyAttr_STANDBY,                 "standby",                 CH_PCDATA    }, /* OBJECT */
  { TidyAttr_START,                   "start",                   CH_NUMBER    }, /* OL */
  { TidyAttr_STYLE,                   "style",                   CH_PCDATA    }, 
  { TidyAttr_SUMMARY,                 "summary",                 CH_PCDATA    }, /* TABLE */
  { TidyAttr_TABINDEX,                "tabindex",                CH_NUMBER    }, /* fields, OBJECT  and A */
  { TidyAttr_TARGET,                  "target",                  CH_TARGET    }, /* names a frame/window */
  { TidyAttr_TEXT,                    "text",                    CH_COLOR     }, /* BODY */
  { TidyAttr_TITLE,                   "title",                   CH_PCDATA    }, /* text tool tip */
  { TidyAttr_TOPMARGIN,               "topmargin",               CH_NUMBER    }, /* used on BODY */
  { TidyAttr_TRANSLATE,               "translate",               CH_BOOL      }, /* HTML5 global attribute */
  { TidyAttr_TYPE,                    "type",                    CH_TYPE      }, /* also used by SPACER */
  { TidyAttr_USEMAP,                  "usemap",                  CH_URL       }, /* things with images */
  { TidyAttr_VALIGN,                  "valign",                  CH_VALIGN    }, 
  { TidyAttr_VALUE,                   "value",                   CH_PCDATA    }, 
  { TidyAttr_VALUETYPE,               "valuetype",               CH_VTYPE     }, /* PARAM: data, ref, object */
  { TidyAttr_VERSION,                 "version",                 CH_PCDATA    }, /* HTML <?xml?> */
  { TidyAttr_VLINK,                   "vlink",                   CH_COLOR     }, /* BODY */
  { TidyAttr_VSPACE,                  "vspace",                  CH_NUMBER    }, /* IMG, OBJECT, APPLET */
  { TidyAttr_WIDTH,                   "width",                   CH_LENGTH    }, /* pixels only for TD/TH */
  { TidyAttr_WRAP,                    "wrap",                    CH_PCDATA    }, /* textarea */
  { TidyAttr_XML_LANG,                "xml:lang",                CH_LANG      }, /* XML language */
  { TidyAttr_XML_SPACE,               "xml:space",               CH_PCDATA    }, /* XML white space */

  /* todo: VERS_ALL is wrong! */
  { TidyAttr_XMLNS,                   "xmlns",                   CH_PCDATA    }, /* name space */
  { TidyAttr_EVENT,                   "event",                   CH_PCDATA    }, /* reserved for <script> */
  { TidyAttr_METHODS,                 "methods",                 CH_PCDATA    }, /* for <a>, never implemented */
  { TidyAttr_N,                       "n",                       CH_PCDATA    }, /* for <nextid> */
  { TidyAttr_SDAFORM,                 "sdaform",                 CH_PCDATA    }, /* SDATA attribute in HTML 2.0 */
  { TidyAttr_SDAPREF,                 "sdapref",                 CH_PCDATA    }, /* SDATA attribute in HTML 2.0 */
  { TidyAttr_SDASUFF,                 "sdasuff",                 CH_PCDATA    }, /* SDATA attribute in HTML 2.0 */
  { TidyAttr_URN,                     "urn",                     CH_PCDATA    }, /* for <a>, never implemented */

  /* HTML5 */
  { TidyAttr_ASYNC,                   "async",                   CH_BOOL     }, /* <script src="..." async> */
  { TidyAttr_AUTOCOMPLETE,            "autocomplete",            CH_PCDATA   },
  { TidyAttr_AUTOFOCUS,               "autofocus",               CH_PCDATA   },
  { TidyAttr_AUTOPLAY,                "autoplay",                CH_PCDATA   },
  { TidyAttr_CHALLENGE,               "challenge",               CH_PCDATA   },
  { TidyAttr_CONTENTEDITABLE,         "contenteditable",         CH_PCDATA   },
  { TidyAttr_CONTEXTMENU,             "contextmenu",             CH_PCDATA   },
  { TidyAttr_CONTROLS,                "controls",                CH_PCDATA   },
  { TidyAttr_CROSSORIGIN,             "crossorigin",             CH_PCDATA   },
  { TidyAttr_DEFAULT,                 "default",                 CH_PCDATA   },
  { TidyAttr_DIRNAME,                 "dirname",                 CH_PCDATA   },
  { TidyAttr_DRAGGABLE,               "draggable",               CH_PCDATA   },
  { TidyAttr_DROPZONE,                "dropzone",                CH_PCDATA   },
  { TidyAttr_FORM,                    "form",                    CH_PCDATA   },
  { TidyAttr_FORMACTION,              "formaction",              CH_PCDATA   },
  { TidyAttr_FORMENCTYPE,             "formenctype",             CH_PCDATA   },
  { TidyAttr_FORMMETHOD,              "formmethod",              CH_PCDATA   },
  { TidyAttr_FORMNOVALIDATE,          "formnovalidate",          CH_PCDATA   },
  { TidyAttr_FORMTARGET,              "formtarget",              CH_PCDATA   },
  { TidyAttr_HIDDEN,                  "hidden",                  CH_PCDATA   },
  { TidyAttr_HIGH,                    "high",                    CH_PCDATA   },
  { TidyAttr_ICON,                    "icon",                    CH_PCDATA   },
  { TidyAttr_KEYTYPE,                 "keytype",                 CH_PCDATA   },
  { TidyAttr_KIND,                    "kind",                    CH_PCDATA   },
  { TidyAttr_LIST,                    "list",                    CH_PCDATA   },
  { TidyAttr_LOOP,                    "loop",                    CH_PCDATA   },
  { TidyAttr_LOW,                     "low",                     CH_PCDATA   },
  { TidyAttr_MANIFEST,                "manifest",                CH_PCDATA   },
  { TidyAttr_MAX,                     "max",                     CH_PCDATA   },
  { TidyAttr_MEDIAGROUP,              "mediagroup",              CH_PCDATA   },
  { TidyAttr_MIN,                     "min",                     CH_PCDATA   },
  { TidyAttr_NOVALIDATE,              "novalidate",              CH_PCDATA   },
  { TidyAttr_OPEN,                    "open",                    CH_PCDATA   },
  { TidyAttr_OPTIMUM,                 "optimum",                 CH_PCDATA   },
  { TidyAttr_OnABORT,                 "onabort",                 CH_PCDATA   },
  { TidyAttr_OnAFTERPRINT,            "onafterprint",            CH_PCDATA   },
  { TidyAttr_OnBEFOREPRINT,           "onbeforeprint",           CH_PCDATA   },
  { TidyAttr_OnCANPLAY,               "oncanplay",               CH_PCDATA   },
  { TidyAttr_OnCANPLAYTHROUGH,        "oncanplaythrough",        CH_PCDATA   },
  { TidyAttr_OnCONTEXTMENU,           "oncontextmenu",           CH_PCDATA   },
  { TidyAttr_OnCUECHANGE,             "oncuechange",             CH_PCDATA   },
  { TidyAttr_OnDRAG,                  "ondrag",                  CH_PCDATA   },
  { TidyAttr_OnDRAGEND,               "ondragend",               CH_PCDATA   },
  { TidyAttr_OnDRAGENTER,             "ondragenter",             CH_PCDATA   },
  { TidyAttr_OnDRAGLEAVE,             "ondragleave",             CH_PCDATA   },
  { TidyAttr_OnDRAGOVER,              "ondragover",              CH_PCDATA   },
  { TidyAttr_OnDRAGSTART,             "ondragstart",             CH_PCDATA   },
  { TidyAttr_OnDROP,                  "ondrop",                  CH_PCDATA   },
  { TidyAttr_OnDURATIONCHANGE,        "ondurationchange",        CH_PCDATA   },
  { TidyAttr_OnEMPTIED,               "onemptied",               CH_PCDATA   },
  { TidyAttr_OnENDED,                 "onended",                 CH_PCDATA   },
  { TidyAttr_OnERROR,                 "onerror",                 CH_PCDATA   },
  { TidyAttr_OnHASHCHANGE,            "onhashchange",            CH_PCDATA   },
  { TidyAttr_OnINPUT,                 "oninput",                 CH_PCDATA   },
  { TidyAttr_OnINVALID,               "oninvalid",               CH_PCDATA   },
  { TidyAttr_OnLOADEDDATA,            "onloadeddata",            CH_PCDATA   },
  { TidyAttr_OnLOADEDMETADATA,        "onloadedmetadata",        CH_PCDATA   },
  { TidyAttr_OnLOADSTART,             "onloadstart",             CH_PCDATA   },
  { TidyAttr_OnMESSAGE,               "onmessage",               CH_PCDATA   },
  { TidyAttr_OnMOUSEWHEEL,            "onmousewheel",            CH_PCDATA   },
  { TidyAttr_OnOFFLINE,               "onoffline",               CH_PCDATA   },
  { TidyAttr_OnONLINE,                "ononline",                CH_PCDATA   },
  { TidyAttr_OnPAGEHIDE,              "onpagehide",              CH_PCDATA   },
  { TidyAttr_OnPAGESHOW,              "onpageshow",              CH_PCDATA   },
  { TidyAttr_OnPAUSE,                 "onpause",                 CH_PCDATA   },
  { TidyAttr_OnPLAY,                  "onplay",                  CH_PCDATA   },
  { TidyAttr_OnPLAYING,               "onplaying",               CH_PCDATA   },
  { TidyAttr_OnPOPSTATE,              "onpopstate",              CH_PCDATA   },
  { TidyAttr_OnPROGRESS,              "onprogress",              CH_PCDATA   },
  { TidyAttr_OnRATECHANGE,            "onratechange",            CH_PCDATA   },
  { TidyAttr_OnREADYSTATECHANGE,      "onreadystatechange",      CH_PCDATA   },
  { TidyAttr_OnREDO,                  "onredo",                  CH_PCDATA   },
  { TidyAttr_OnRESIZE,                "onresize",                CH_PCDATA   },
  { TidyAttr_OnSCROLL,                "onscroll",                CH_PCDATA   },
  { TidyAttr_OnSEEKED,                "onseeked",                CH_PCDATA   },
  { TidyAttr_OnSEEKING,               "onseeking",               CH_PCDATA   },
  { TidyAttr_OnSHOW,                  "onshow",                  CH_PCDATA   },
  { TidyAttr_OnSTALLED,               "onstalled",               CH_PCDATA   },
  { TidyAttr_OnSTORAGE,               "onstorage",               CH_PCDATA   },
  { TidyAttr_OnSUSPEND,               "onsuspend",               CH_PCDATA   },
  { TidyAttr_OnTIMEUPDATE,            "ontimeupdate",            CH_PCDATA   },
  { TidyAttr_OnUNDO,                  "onundo",                  CH_PCDATA   },
  { TidyAttr_OnVOLUMECHANGE,          "onvolumechange",          CH_PCDATA   },
  { TidyAttr_OnWAITING,               "onwaiting",               CH_PCDATA   },
  { TidyAttr_PATTERN,                 "pattern",                 CH_PCDATA   },
  { TidyAttr_PLACEHOLDER,             "placeholder",             CH_PCDATA   },
  { TidyAttr_POSTER,                  "poster",                  CH_PCDATA   },
  { TidyAttr_PRELOAD,                 "preload",                 CH_PCDATA   },
  { TidyAttr_PUBDATE,                 "pubdate",                 CH_PCDATA   },
  { TidyAttr_RADIOGROUP,              "radiogroup",              CH_PCDATA   },
  { TidyAttr_REQUIRED,                "required",                CH_PCDATA   },
  { TidyAttr_REVERSED,                "reversed",                CH_PCDATA   },
  { TidyAttr_SANDBOX,                 "sandbox",                 CH_PCDATA   },
  { TidyAttr_SCOPED,                  "scoped",                  CH_PCDATA   },
  { TidyAttr_SEAMLESS,                "seamless",                CH_PCDATA   },
  { TidyAttr_SIZES,                   "sizes",                   CH_PCDATA   },
  { TidyAttr_SPELLCHECK,              "spellcheck",              CH_PCDATA   },
  { TidyAttr_SRCDOC,                  "srcdoc",                  CH_PCDATA   },
  { TidyAttr_SRCLANG,                 "srclang",                 CH_PCDATA   },
  { TidyAttr_STEP,                    "step",                    CH_PCDATA   },

  /* HTML5 Aria Attributes */
  { TidyAttr_ARIA_ACTIVEDESCENDANT,   "aria-activedescendant",   CH_PCDATA   },
  { TidyAttr_ARIA_ATOMIC,             "aria-atomic",             CH_PCDATA   },
  { TidyAttr_ARIA_AUTOCOMPLETE,       "aria-autocomplete",       CH_PCDATA   },
  { TidyAttr_ARIA_BUSY,               "aria-busy",               CH_PCDATA   },
  { TidyAttr_ARIA_CHECKED,            "aria-checked",            CH_PCDATA   },
  { TidyAttr_ARIA_CONTROLS,           "aria-controls",           CH_PCDATA   },
  { TidyAttr_ARIA_DESCRIBEDBY,        "aria-describedby",        CH_PCDATA   },
  { TidyAttr_ARIA_DISABLED,           "aria-disabled",           CH_PCDATA   },
  { TidyAttr_ARIA_DROPEFFECT,         "aria-dropeffect",         CH_PCDATA   },
  { TidyAttr_ARIA_EXPANDED,           "aria-expanded",           CH_PCDATA   },
  { TidyAttr_ARIA_FLOWTO,             "aria-flowto",             CH_PCDATA   },
  { TidyAttr_ARIA_GRABBED,            "aria-grabbed",            CH_PCDATA   },
  { TidyAttr_ARIA_HASPOPUP,           "aria-haspopup",           CH_PCDATA   },
  { TidyAttr_ARIA_HIDDEN,             "aria-hidden",             CH_PCDATA   },
  { TidyAttr_ARIA_INVALID,            "aria-invalid",            CH_PCDATA   },
  { TidyAttr_ARIA_LABEL,              "aria-label",              CH_PCDATA   },
  { TidyAttr_ARIA_LABELLEDBY,         "aria-labelledby",         CH_PCDATA   },
  { TidyAttr_ARIA_LEVEL,              "aria-level",              CH_PCDATA   },
  { TidyAttr_ARIA_LIVE,               "aria-live",               CH_PCDATA   },
  { TidyAttr_ARIA_MULTILINE,          "aria-multiline",          CH_PCDATA   },
  { TidyAttr_ARIA_MULTISELECTABLE,    "aria-multiselectable",    CH_PCDATA   },
  { TidyAttr_ARIA_ORIENTATION,        "aria-orientation",        CH_PCDATA   },
  { TidyAttr_ARIA_OWNS,               "aria-owns",               CH_PCDATA   },
  { TidyAttr_ARIA_POSINSET,           "aria-posinset",           CH_PCDATA   },
  { TidyAttr_ARIA_PRESSED,            "aria-pressed",            CH_PCDATA   },
  { TidyAttr_ARIA_READONLY,           "aria-readonly",           CH_PCDATA   },
  { TidyAttr_ARIA_RELEVANT,           "aria-relevant",           CH_PCDATA   },
  { TidyAttr_ARIA_REQUIRED,           "aria-required",           CH_PCDATA   },
  { TidyAttr_ARIA_SELECTED,           "aria-selected",           CH_PCDATA   },
  { TidyAttr_ARIA_SETSIZE,            "aria-setsize",            CH_PCDATA   },
  { TidyAttr_ARIA_SORT,               "aria-sort",               CH_PCDATA   },
  { TidyAttr_ARIA_VALUEMAX,           "aria-valuemax",           CH_PCDATA   },
  { TidyAttr_ARIA_VALUEMIN,           "aria-valuemin",           CH_PCDATA   },
  { TidyAttr_ARIA_VALUENOW,           "aria-valuenow",           CH_PCDATA   },
  { TidyAttr_ARIA_VALUETEXT,          "aria-valuetext",          CH_PCDATA   },
  { TidyAttr_X,                       "x",                       CH_PCDATA    }, /* for <svg> */
  { TidyAttr_Y,                       "y",                       CH_PCDATA    }, /* for <svg> */
  { TidyAttr_VIEWBOX,                  "viewbox",                CH_PCDATA    }, /* for <svg> */
  { TidyAttr_PRESERVEASPECTRATIO,      "preserveaspectratio",    CH_PCDATA    }, /* for <svg> */
  { TidyAttr_ZOOMANDPAN,               "zoomandpan",             CH_PCDATA    }, /* for <svg> */
  { TidyAttr_BASEPROFILE,              "baseprofile",            CH_PCDATA    }, /* for <svg> */
  { TidyAttr_CONTENTSCRIPTTYPE,        "contentscripttype",      CH_PCDATA    }, /* for <svg> */
  { TidyAttr_CONTENTSTYLETYPE,         "contentstyletype",       CH_PCDATA    }, /* for <svg> */
  { TidyAttr_DISPLAY,                  "display",                CH_PCDATA   }, /* on MATH tag (html5) */

  /* RDFa Attributes */
  { TidyAttr_ABOUT,                    "about",                  CH_RDFASCURIE },
  { TidyAttr_DATATYPE,                 "datatype",               CH_RDFATERM   },
  { TidyAttr_INLIST,                   "inlist",                 CH_BOOL       },
  { TidyAttr_PREFIX,                   "prefix",                 CH_RDFAPREFIX },
  { TidyAttr_PROPERTY,                 "property",               CH_RDFATERMS  },
  { TidyAttr_RESOURCE,                 "resource",               CH_RDFASCURIE },
  { TidyAttr_TYPEOF,                   "typeof",                 CH_RDFATERMS  },
  { TidyAttr_VOCAB,                    "vocab",                  CH_URL        },

  { TidyAttr_INTEGRITY,                "integrity",              CH_PCDATA   },

  /* Preload spec: https://www.w3.org/TR/preload/ */
  { TidyAttr_AS,                       "as",                     CH_PCDATA   },

  /* for xmlns:xlink in <svg> */
  { TidyAttr_XMLNSXLINK,                "xmlns:xlink",           CH_URL       },

  /* this must be the final entry */
  { N_TIDY_ATTRIBS,                    NULL,                     NULL         }
};

static unsigned int AttributeVersions(Node* node, AttVal* attval)
{
    unsigned int i;

    /* Override or add to items in attrdict.c */
    if (attval && attval->attribute) {
        /* HTML5 data-* attributes can't be added generically; handle here. */
        if (TY_(tmbstrncmp)(attval->attribute, "data-", 5) == 0)
            return (XH50 | HT50);
    }
    /* TODO: maybe this should return VERS_PROPRIETARY instead? */
    if (!attval || !attval->dict)
        return VERS_UNKNOWN;

    if (!(!node || !node->tag || !node->tag->attrvers))
        for (i = 0; node->tag->attrvers[i].attribute; ++i)
            if (node->tag->attrvers[i].attribute == attval->dict->id)
                return node->tag->attrvers[i].versions;

    return VERS_PROPRIETARY;
}


/* return the version of the attribute "id" of element "node" */
unsigned int TY_(NodeAttributeVersions)( Node* node, TidyAttrId id )
{
    unsigned int i;

    if (!node || !node->tag || !node->tag->attrvers)
        return VERS_UNKNOWN;

    for (i = 0; node->tag->attrvers[i].attribute; ++i)
        if (node->tag->attrvers[i].attribute == id)
            return node->tag->attrvers[i].versions;

    return VERS_UNKNOWN;
}

/* returns true if the element is a W3C defined element
 * but the element/attribute combination is not. We're
 * only defining as "proprietary" items that are not in
 * the element's AttrVersion structure.
 */
Bool TY_(AttributeIsProprietary)(Node* node, AttVal* attval)
{
    if (!node || !attval)
        return no;

    if (!node->tag)
        return no;

    if (!(node->tag->versions & VERS_ALL))
        return no;

    if (AttributeVersions(node, attval) & VERS_ALL)
        return no;

    return yes;
}

/* returns true if the element is a W3C defined element
 * but the element/attribute combination is not. We're
 * considering it a mismatch if the document version
 * does not allow the attribute as called out in its
 * AttrVersion structure.
 */
Bool TY_(AttributeIsMismatched)(Node* node, AttVal* attval, TidyDocImpl* doc)
{
    unsigned int doctype;
    
    if (!node || !attval)
        return no;
    
    if (!node->tag)
        return no;
    
    if (!(node->tag->versions & VERS_ALL))
        return no;

    doctype = doc->lexer->versionEmitted == 0 ? doc->lexer->doctype : doc->lexer->versionEmitted;

    if (AttributeVersions(node, attval) & doctype)
        return no;
    
    return yes;
}


/* used by CheckColor() */
struct _colors
{
    ctmbstr name;
    ctmbstr hex;
};

static const struct _colors colors[] =
{
    { "black",   "#000000" },
    { "green",   "#008000" },
    { "silver",  "#C0C0C0" },
    { "lime",    "#00FF00" },
    { "gray",    "#808080" },
    { "olive",   "#808000" },
    { "white",   "#FFFFFF" },
    { "yellow",  "#FFFF00" },
    { "maroon",  "#800000" },
    { "navy",    "#000080" },
    { "red",     "#FF0000" },
    { "blue",    "#0000FF" },
    { "purple",  "#800080" },
    { "teal",    "#008080" },
    { "fuchsia", "#FF00FF" },
    { "aqua",    "#00FFFF" },
    { NULL,      NULL      }
};

static ctmbstr GetColorCode(ctmbstr name)
{
    unsigned int i;

    for (i = 0; colors[i].name; ++i)
        if (TY_(tmbstrcasecmp)(name, colors[i].name) == 0)
            return colors[i].hex;

    return NULL;
}

static ctmbstr GetColorName(ctmbstr code)
{
    unsigned int i;

    for (i = 0; colors[i].name; ++i)
        if (TY_(tmbstrcasecmp)(code, colors[i].hex) == 0)
            return colors[i].name;

    return NULL;
}

static unsigned int attrsHash(ctmbstr s)
{
    unsigned int hashval;

    for (hashval = 0; *s != '\0'; s++)
        hashval = *s + 31*hashval;

    return hashval % ATTRIBUTE_HASH_SIZE;
}

static const Attribute *attrsInstall(TidyDocImpl* doc, TidyAttribImpl * attribs,
                                const Attribute* old)
{
    AttrHash *np;
    unsigned int hashval;

    if (old)
    {
        np = (AttrHash *)TidyDocAlloc(doc, sizeof(*np));
        np->attr = old;

        hashval = attrsHash(old->name);
        np->next = attribs->hashtab[hashval];
        attribs->hashtab[hashval] = np;
    }

    return old;
}

static void attrsRemoveFromHash( TidyDocImpl* doc, TidyAttribImpl *attribs,
                            ctmbstr s )
{
    unsigned int h = attrsHash(s);
    AttrHash *p, *prev = NULL;
    for (p = attribs->hashtab[h]; p && p->attr; p = p->next)
    {
        if (TY_(tmbstrcmp)(s, p->attr->name) == 0)
        {
            AttrHash* next = p->next;
            if ( prev )
                prev->next = next; 
            else
                attribs->hashtab[h] = next;
            TidyDocFree(doc, p);
            return;
        }
        prev = p;
    }
}

static void attrsEmptyHash( TidyDocImpl* doc, TidyAttribImpl * attribs )
{
    AttrHash *dict, *next;
    unsigned int i;

    for (i = 0; i < ATTRIBUTE_HASH_SIZE; ++i)
    {
        dict = attribs->hashtab[i];

        while(dict)
        {
            next = dict->next;
            TidyDocFree(doc, dict);
            dict = next;
        }

        attribs->hashtab[i] = NULL;
    }
}

static const Attribute* attrsLookup(TidyDocImpl* doc,
                               TidyAttribImpl* ARG_UNUSED(attribs),
                               ctmbstr atnam)
{
    const Attribute *np;
    const AttrHash *p;

    if (!atnam)
        return NULL;

    for (p = attribs->hashtab[attrsHash(atnam)]; p && p->attr; p = p->next)
        if (TY_(tmbstrcasecmp)(atnam, p->attr->name) == 0)
            return p->attr;

    for (np = attribute_defs; np && np->name; ++np)
        if (TY_(tmbstrcasecmp)(atnam, np->name) == 0)
            return attrsInstall(doc, attribs, np);

    return NULL;
}


/* Locate attributes by type */
AttVal* TY_(AttrGetById)( Node* node, TidyAttrId id )
{
   AttVal* av;
   for ( av = node->attributes; av; av = av->next )
   {
     if ( AttrIsId(av, id) )
         return av;
   }
   return NULL;
}

/* public method for finding attribute definition by name */
const Attribute* TY_(FindAttribute)( TidyDocImpl* doc, AttVal *attval )
{
    if ( attval )
       return attrsLookup( doc, &doc->attribs, attval->attribute );
    return NULL;
}

AttVal* TY_(GetAttrByName)( Node *node, ctmbstr name )
{
    AttVal *attr;
    for (attr = node->attributes; attr != NULL; attr = attr->next)
    {
        if (attr->attribute && TY_(tmbstrcmp)(attr->attribute, name) == 0)
            break;
    }
    return attr;
}

void TY_(DropAttrByName)( TidyDocImpl* doc, Node *node, ctmbstr name )
{
    AttVal *attr, *prev = NULL, *next;

    for (attr = node->attributes; attr != NULL; prev = attr, attr = next)
    {
        next = attr->next;

        if (attr->attribute && TY_(tmbstrcmp)(attr->attribute, name) == 0)
        {
            if (prev)
                 prev->next = next;
            else
                 node->attributes = next;

            TY_(FreeAttribute)( doc, attr ); 
            break;
        }
    }
}

AttVal* TY_(AddAttribute)( TidyDocImpl* doc,
                           Node *node, ctmbstr name, ctmbstr value )
{
    AttVal *av = TY_(NewAttribute)(doc);
    av->delim = '"';
    av->attribute = TY_(tmbstrdup)(doc->allocator, name);

    if (value)
        av->value = TY_(tmbstrdup)(doc->allocator, value);
    else
        av->value = NULL;

    av->dict = attrsLookup(doc, &doc->attribs, name);

    TY_(InsertAttributeAtEnd)(node, av);
    return av;
}

AttVal* TY_(RepairAttrValue)(TidyDocImpl* doc, Node* node, ctmbstr name, ctmbstr value)
{
    AttVal* old = TY_(GetAttrByName)(node, name);

    if (old)
    {
        if (old->value)
            TidyDocFree(doc, old->value);
        if (value)
            old->value = TY_(tmbstrdup)(doc->allocator, value);
        else
            old->value = NULL;

        return old;
    }
    else
        return TY_(AddAttribute)(doc, node, name, value);
}


void TY_(FreeAttrPriorityList)( TidyDocImpl* doc )
{
    PriorityAttribs *priorities = &(doc->attribs.priorityAttribs);

    if ( priorities->list )
    {
        unsigned int i = 0;
        while ( priorities->list[i] != NULL )
        {
            TidyFree( doc->allocator, priorities->list[i] );
            i++;
        }

        TidyFree( doc->allocator, priorities->list );
    }
}


void TY_(DefinePriorityAttribute)(TidyDocImpl* doc, ctmbstr name)
{
    enum { capacity = 10 };
    PriorityAttribs *priorities = &(doc->attribs.priorityAttribs);

    if ( !priorities->list )
    {
        priorities->list = TidyAlloc(doc->allocator, sizeof(ctmbstr) * capacity );
        priorities->list[0] = NULL;
        priorities->capacity = capacity;
        priorities->count = 0;
    }

    if ( priorities->count >= priorities->capacity )
    {
        priorities->capacity = priorities->capacity * 2;
        priorities->list = TidyRealloc(doc->allocator, priorities->list, sizeof(tmbstr) * priorities->capacity + 1 );
    }

    priorities->list[priorities->count] = TY_(tmbstrdup)( doc->allocator, name);
    priorities->count++;
    priorities->list[priorities->count] = NULL;
}


TidyIterator TY_(getPriorityAttrList)( TidyDocImpl* doc )
{
    PriorityAttribs *priorities = &(doc->attribs.priorityAttribs);
    size_t result = priorities->count > 0 ? 1 : 0;

    return (TidyIterator) result;
}


ctmbstr  TY_(getNextPriorityAttr)( TidyDocImpl* doc, TidyIterator* iter )
{
    PriorityAttribs *priorities = &(doc->attribs.priorityAttribs);
    size_t index;
    ctmbstr result = NULL;
    assert( iter != NULL );
    index = (size_t)*iter;

    if ( index > 0 && index <= priorities->count )
    {
        result = priorities->list[index-1];
        index++;
    }
    *iter = (TidyIterator) ( index <= priorities->count ? index : (size_t)0 );

    return result;
}


static Bool CheckAttrType( TidyDocImpl* doc,
                           ctmbstr attrname, AttrCheck type )
{
    const Attribute* np = attrsLookup( doc, &doc->attribs, attrname );
    return (Bool)( np && np->attrchk == type );
}

Bool TY_(IsUrl)( TidyDocImpl* doc, ctmbstr attrname )
{
    return CheckAttrType( doc, attrname, CH_URL );
}

/*
Bool IsBool( TidyDocImpl* doc, ctmbstr attrname )
{
    return CheckAttrType( doc, attrname, CH_BOOL );
}
*/

Bool TY_(IsScript)( TidyDocImpl* doc, ctmbstr attrname )
{
    return CheckAttrType( doc, attrname, CH_SCRIPT );
}

/* may id or name serve as anchor? */
Bool TY_(IsAnchorElement)( TidyDocImpl* ARG_UNUSED(doc), Node* node)
{
    TidyTagId tid = TagId( node );
    if ( tid == TidyTag_A      ||
         tid == TidyTag_APPLET ||
         tid == TidyTag_FORM   ||
         tid == TidyTag_FRAME  ||
         tid == TidyTag_IFRAME ||
         tid == TidyTag_IMG    ||
         tid == TidyTag_MAP )
        return yes;

    return no;
}

/*
  In CSS1, selectors can contain only the characters A-Z, 0-9,
  and Unicode characters 161-255, plus dash (-); they cannot start
  with a dash or a digit; they can also contain escaped characters
  and any Unicode character as a numeric code (see next item).

  The backslash followed by at most four hexadecimal digits
  (0..9A..F) stands for the Unicode character with that number.

  Any character except a hexadecimal digit can be escaped to remove
  its special meaning, by putting a backslash in front.

  #508936 - CSS class naming for -clean option
*/
Bool TY_(IsCSS1Selector)( ctmbstr buf )
{
    Bool valid = yes;
    int esclen = 0;
    byte c;
    int pos;

    for ( pos=0; valid && (c = *buf++); ++pos )
    {
        if ( c == '\\' )
        {
            esclen = 1;  /* ab\555\444 is 4 chars {'a', 'b', \555, \444} */
        }
        else if ( isdigit( c ) )
        {
            /* Digit not 1st, unless escaped (Max length "\112F") */
            if ( esclen > 0 )
                valid = ( ++esclen < 6 );
            if ( valid )
                valid = ( pos>0 || esclen>0 );
        }
        else
        {
            valid = (
                esclen > 0                       /* Escaped? Anything goes. */
                || ( pos>0 && c == '-' )         /* Dash cannot be 1st char */
                || isalpha(c)                    /* a-z, A-Z anywhere */
                || ( c >= 161 )                  /* Unicode 161-255 anywhere */
            );
            esclen = 0;
        }
    }
    return valid;
}

/* free single anchor */
static void FreeAnchor(TidyDocImpl* doc, Anchor *a)
{
    if ( a )
        TidyDocFree( doc, a->name );
    TidyDocFree( doc, a );
}

static unsigned int anchorNameHash(ctmbstr s)
{
    unsigned int hashval = 0;
    /* Issue #149 - an inferred name can be null. avoid crash */
    if (s) 
    {
        for ( ; *s != '\0'; s++) {
            tmbchar c = TY_(ToLower)( *s );
            hashval = c + 31*hashval;
        }
    }
    return hashval % ANCHOR_HASH_SIZE;
}

/*\
 *  New Service for HTML5
 *  Issue #185 - Treat elements ids as case-sensitive
 *  if in HTML5 modes, make hash of value AS IS!
\*/
static unsigned int anchorNameHash5(ctmbstr s)
{
    unsigned int hashval = 0;
    /* Issue #149 - an inferred name can be null. avoid crash */
    if (s) 
    {
        for ( ; *s != '\0'; s++) {
            tmbchar c = *s;
            hashval = c + 31*hashval;
        }
    }
    return hashval % ANCHOR_HASH_SIZE;
}


/*\ 
 *  removes anchor for specific node 
 *  Issue #185 - Treat elements ids as case-sensitive
 *  if in HTML5 modes, make hash of value AS IS!
\*/
void TY_(RemoveAnchorByNode)( TidyDocImpl* doc, ctmbstr name, Node *node )
{
    TidyAttribImpl* attribs = &doc->attribs;
    Anchor *delme = NULL, *curr, *prev = NULL;
    unsigned int h;
    if (TY_(HTMLVersion)(doc) == HT50)
        h = anchorNameHash5(name);
    else
        h = anchorNameHash(name);

    for ( curr=attribs->anchor_hash[h]; curr!=NULL; curr=curr->next )
    {
        if ( curr->node == node )
        {
            if ( prev )
                prev->next = curr->next;
            else
                attribs->anchor_hash[h] = curr->next;
            delme = curr;
            break;
        }
        prev = curr;
    }
    FreeAnchor( doc, delme );
}

/* initialize new anchor 
   Is. #726 & #185 - HTML5 is case-sensitive
*/
static Anchor* NewAnchor( TidyDocImpl* doc, ctmbstr name, Node* node )
{
    Anchor *a = (Anchor*) TidyDocAlloc( doc, sizeof(Anchor) );

    a->name = TY_(tmbstrdup)( doc->allocator, name );
    if (!TY_(IsHTML5Mode)(doc)) /* Is. #726 - if NOT HTML5, to lowercase */
        a->name = TY_(tmbstrtolower)(a->name);
    a->node = node;
    a->next = NULL;

    return a;
}

/*\
 *  add new anchor to namespace 
 *  Issue #185 - Treat elements ids as case-sensitive
 *  if in HTML5 modes, make hash of value AS IS!
\*/
static Anchor* AddAnchor( TidyDocImpl* doc, ctmbstr name, Node *node )
{
    TidyAttribImpl* attribs = &doc->attribs;
    Anchor *a = NewAnchor( doc, name, node );
    unsigned int h;
    if (TY_(HTMLVersion)(doc) == HT50)
        h = anchorNameHash5(name);
    else
        h = anchorNameHash(name);

    if ( attribs->anchor_hash[h] == NULL)
         attribs->anchor_hash[h] = a;
    else
    {
        Anchor *here =  attribs->anchor_hash[h];
        while (here->next)
            here = here->next;
        here->next = a;
    }

    return attribs->anchor_hash[h];
}

/*\
 *  return node associated with anchor 
 *  Issue #185 - Treat elements ids as case-sensitive
 *  if in HTML5 modes, make hash of value AS IS!
\*/
static Node* GetNodeByAnchor( TidyDocImpl* doc, ctmbstr name )
{
    TidyAttribImpl* attribs = &doc->attribs;
    Anchor *found;
    unsigned int h;
    tmbstr lname = TY_(tmbstrdup)(doc->allocator, name);
    if (TY_(HTMLVersion)(doc) == HT50) {
        h = anchorNameHash5(name);
    }
    else
    {
        h = anchorNameHash(name);
        lname = TY_(tmbstrtolower)(lname);
    }

    for ( found = attribs->anchor_hash[h]; found != NULL; found = found->next )
    {
        if ( TY_(tmbstrcmp)(found->name, lname) == 0 )
            break;
    }
    
    TidyDocFree(doc, lname);
    if ( found )
        return found->node;
    return NULL;
}

/* free all anchors */
void TY_(FreeAnchors)( TidyDocImpl* doc )
{
    TidyAttribImpl* attribs = &doc->attribs;
    Anchor* a;
    unsigned int h;
    for (h = 0; h < ANCHOR_HASH_SIZE; h++) {
        while (NULL != (a = attribs->anchor_hash[h]) )
        {
            attribs->anchor_hash[h] = a->next;
            FreeAnchor(doc, a);
        }
    }
}

/* public method for inititializing attribute dictionary */
void TY_(InitAttrs)( TidyDocImpl* doc )
{
    TidyClearMemory( &doc->attribs, sizeof(TidyAttribImpl) );
#ifdef _DEBUG
    {
      /* Attribute ID is index position in Attribute type lookup table */
      unsigned int ix;
      for ( ix=0; ix < N_TIDY_ATTRIBS; ++ix )
      {
        const Attribute* dict = &attribute_defs[ ix ];
        assert( (unsigned int) dict->id == ix );
      }
    }
#endif
}

/* free all declared attributes */
static void FreeDeclaredAttributes( TidyDocImpl* doc )
{
    TidyAttribImpl* attribs = &doc->attribs;
    Attribute* dict;
    while ( NULL != (dict = attribs->declared_attr_list) )
    {
        attribs->declared_attr_list = dict->next;
        attrsRemoveFromHash( doc, &doc->attribs, dict->name );
        TidyDocFree( doc, dict->name );
        TidyDocFree( doc, dict );
    }
}

void TY_(FreeAttrTable)( TidyDocImpl* doc )
{
    attrsEmptyHash( doc, &doc->attribs );
    TY_(FreeAnchors)( doc );
    FreeDeclaredAttributes( doc );
}

void TY_(AppendToClassAttr)( TidyDocImpl* doc, AttVal *classattr, ctmbstr classname )
{
    unsigned int len = TY_(tmbstrlen)(classattr->value) +
        TY_(tmbstrlen)(classname) + 2;
    tmbstr s = (tmbstr) TidyDocAlloc( doc, len );
    s[0] = '\0';
    if (classattr->value)
    {
        TY_(tmbstrcpy)( s, classattr->value );
        TY_(tmbstrcat)( s, " " );
    }
    TY_(tmbstrcat)( s, classname );
    if (classattr->value)
        TidyDocFree( doc, classattr->value );
    classattr->value = s;
}

/* concatenate styles */
static void AppendToStyleAttr( TidyDocImpl* doc, AttVal *styleattr, ctmbstr styleprop )
{
    /*
    this doesn't handle CSS comments and
    leading/trailing white-space very well
    see http://www.w3.org/TR/css-style-attr
    */
    unsigned int end = TY_(tmbstrlen)(styleattr->value);

    if (end >0 && styleattr->value[end - 1] == ';')
    {
        /* attribute ends with declaration seperator */

        styleattr->value = (tmbstr) TidyDocRealloc(doc, styleattr->value,
            end + TY_(tmbstrlen)(styleprop) + 2);

        TY_(tmbstrcat)(styleattr->value, " ");
        TY_(tmbstrcat)(styleattr->value, styleprop);
    }
    else if (end >0 && styleattr->value[end - 1] == '}')
    {
        /* attribute ends with rule set */

        styleattr->value = (tmbstr) TidyDocRealloc(doc, styleattr->value,
            end + TY_(tmbstrlen)(styleprop) + 6);

        TY_(tmbstrcat)(styleattr->value, " { ");
        TY_(tmbstrcat)(styleattr->value, styleprop);
        TY_(tmbstrcat)(styleattr->value, " }");
    }
    else
    {
        /* attribute ends with property value */

        styleattr->value = (tmbstr) TidyDocRealloc(doc, styleattr->value,
            end + TY_(tmbstrlen)(styleprop) + 3);

        if (end > 0)
            TY_(tmbstrcat)(styleattr->value, "; ");
        TY_(tmbstrcat)(styleattr->value, styleprop);
    }
}

/*
 the same attribute name can't be used
 more than once in each element
*/
static Bool AttrsHaveSameName( AttVal* av1, AttVal* av2)
{
    TidyAttrId id1, id2;

    id1 = AttrId(av1);
    id2 = AttrId(av2);
    if (id1 != TidyAttr_UNKNOWN && id2 != TidyAttr_UNKNOWN)
        return AttrsHaveSameId(av1, av2);
    if (id1 != TidyAttr_UNKNOWN || id2 != TidyAttr_UNKNOWN)
        return no;
    if (av1->attribute && av2->attribute)
        return TY_(tmbstrcmp)(av1->attribute, av2->attribute) == 0;
     return no;
}

void TY_(RepairDuplicateAttributes)( TidyDocImpl* doc, Node *node, Bool isXml )
{
    AttVal *first;

    for (first = node->attributes; first != NULL;)
    {
        AttVal *second;
        Bool firstRedefined = no;

        if (!(first->asp == NULL && first->php == NULL))
        {
            first = first->next;
            continue;
        }

        for (second = first->next; second != NULL;)
        {
            AttVal *temp;

            if (!(second->asp == NULL && second->php == NULL
                  && AttrsHaveSameName(first, second)))
            {
                second = second->next;
                continue;
            }

            /* first and second attribute have same local name */
            /* now determine what to do with this duplicate... */

            if (!isXml
                && attrIsCLASS(first) && cfgBool(doc, TidyJoinClasses)
                && AttrHasValue(first) && AttrHasValue(second))
            {
                /* concatenate classes */

                TY_(AppendToClassAttr)(doc, first, second->value);

                temp = second->next;
                TY_(ReportAttrError)( doc, node, second, JOINING_ATTRIBUTE);
                TY_(RemoveAttribute)( doc, node, second );
                second = temp;
            }
            else if (!isXml
                     && attrIsSTYLE(first) && cfgBool(doc, TidyJoinStyles)
                     && AttrHasValue(first) && AttrHasValue(second))
            {
                AppendToStyleAttr( doc, first, second->value );

                temp = second->next;
                TY_(ReportAttrError)( doc, node, second, JOINING_ATTRIBUTE);
                TY_(RemoveAttribute)( doc, node, second );
                second = temp;
            }
            else if ( cfg(doc, TidyDuplicateAttrs) == TidyKeepLast )
            {
                temp = first->next;
                TY_(ReportAttrError)( doc, node, first, REPEATED_ATTRIBUTE);
                TY_(RemoveAttribute)( doc, node, first );
                firstRedefined = yes;
                first = temp;
                second = second->next;
            }
            else /* TidyDuplicateAttrs == TidyKeepFirst */
            {
                temp = second->next;
                TY_(ReportAttrError)( doc, node, second, REPEATED_ATTRIBUTE);
                TY_(RemoveAttribute)( doc, node, second );
                second = temp;
            }
        }
        if (!firstRedefined)
            first = first->next;
    }
}

/* ignore unknown attributes for proprietary elements */
const Attribute* TY_(CheckAttribute)( TidyDocImpl* doc, Node *node, AttVal *attval )
{
    const Attribute* attribute = attval->dict;

    if ( attribute != NULL )
    {
        if (attrIsXML_LANG(attval) || attrIsXML_SPACE(attval))
        {
            doc->lexer->isvoyager = yes;
            if (!cfgBool(doc, TidyHtmlOut))
            {
                TY_(SetOptionBool)(doc, TidyXhtmlOut, yes);
                TY_(SetOptionBool)(doc, TidyXmlOut, yes);
            }
        }

        TY_(ConstrainVersion)(doc, AttributeVersions(node, attval));
        
        if (attribute->attrchk)
            attribute->attrchk( doc, node, attval );
    }

    return attribute;
}

Bool TY_(IsBoolAttribute)(AttVal *attval)
{
    const Attribute *attribute = ( attval ? attval->dict : NULL );
    if ( attribute && attribute->attrchk == CH_BOOL )
        return yes;
    return no;
}

Bool TY_(attrIsEvent)( AttVal* attval )
{
    TidyAttrId atid = AttrId( attval );

    return (atid == TidyAttr_OnAFTERUPDATE     ||
            atid == TidyAttr_OnBEFOREUNLOAD    ||
            atid == TidyAttr_OnBEFOREUPDATE    ||
            atid == TidyAttr_OnBLUR            ||
            atid == TidyAttr_OnCHANGE          ||
            atid == TidyAttr_OnCLICK           ||
            atid == TidyAttr_OnDATAAVAILABLE   ||
            atid == TidyAttr_OnDATASETCHANGED  ||
            atid == TidyAttr_OnDATASETCOMPLETE ||
            atid == TidyAttr_OnDBLCLICK        ||
            atid == TidyAttr_OnERRORUPDATE     ||
            atid == TidyAttr_OnFOCUS           ||
            atid == TidyAttr_OnKEYDOWN         ||
            atid == TidyAttr_OnKEYPRESS        ||
            atid == TidyAttr_OnKEYUP           ||
            atid == TidyAttr_OnLOAD            ||
            atid == TidyAttr_OnMOUSEDOWN       ||
            atid == TidyAttr_OnMOUSEMOVE       ||
            atid == TidyAttr_OnMOUSEOUT        ||
            atid == TidyAttr_OnMOUSEOVER       ||
            atid == TidyAttr_OnMOUSEUP         ||
            atid == TidyAttr_OnRESET           ||
            atid == TidyAttr_OnROWENTER        ||
            atid == TidyAttr_OnROWEXIT         ||
            atid == TidyAttr_OnSELECT          ||
            atid == TidyAttr_OnSUBMIT          ||
            atid == TidyAttr_OnUNLOAD);
}

static void CheckLowerCaseAttrValue( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    tmbstr p;
    Bool hasUpper = no;
    
    if (!AttrHasValue(attval))
        return;

    p = attval->value;
    
    while (*p)
    {
        if (TY_(IsUpper)(*p)) /* #501230 - fix by Terry Teague - 09 Jan 02 */
        {
            hasUpper = yes;
            break;
        }
        p++;
    }

    if (hasUpper)
    {
        Lexer* lexer = doc->lexer;
        if (lexer->isvoyager)
            TY_(ReportAttrError)( doc, node, attval, ATTR_VALUE_NOT_LCASE);
  
        if ( lexer->isvoyager || cfgBool(doc, TidyLowerLiterals) )
            attval->value = TY_(tmbstrtolower)(attval->value);
    }
}

/* Issue #588 - use simple macros only!
   Seems 'isalnum(c)' is undefined and can
   cause an assert or a SIGSEGV in some libraries
   if 'c' is not EOF, or in the range 0 to 0xff,
   so avoid using it.
*/
#define ISUPPER(a) ((a >= 'A') && (a <= 'Z'))
#define ISLOWER(a) ((a >= 'a') && (a <= 'z'))
#define ISNUMERIC(a) ((a >= '0') && (a <= '9'))
#define ISALNUM(a) (ISUPPER(a) || ISLOWER(a) || ISNUMERIC(a))

static Bool IsURLCodePoint( ctmbstr p, unsigned int *increment )
{
    unsigned int c;
    *increment = TY_(GetUTF8)( p, &c ) + 1;

    return ISALNUM( c ) ||
        c == '%' ||    /* not a valid codepoint, but an escape sequence */
        c == '#' ||    /* not a valid codepoint, but a delimiter */
        c == '!' ||
        c == '$' ||
        c == '&' ||
        c == '\'' ||
        c == '(' ||
        c == ')' ||
        c == '*' ||
        c == '+' ||
        c == ',' ||
        c == '-' ||
        c == '.' ||
        c == '/' ||
        c == ':' ||
        c == ';' ||
        c == '=' ||
        c == '?' ||
        c == '@' ||
        c == '_' ||
        c == '~' ||
        (c >= 0x00A0 && c <= 0xD7FF) ||
        (c >= 0xE000 && c <= 0xFDCF) ||
        (c >= 0xFDF0 && c <= 0xFFEF) ||
        (c >= 0x10000 && c <= 0x1FFFD) ||
        (c >= 0x20000 && c <= 0x2FFFD) ||
        (c >= 0x30000 && c <= 0x3FFFD) ||
        (c >= 0x40000 && c <= 0x4FFFD) ||
        (c >= 0x50000 && c <= 0x5FFFD) ||
        (c >= 0x60000 && c <= 0x6FFFD) ||
        (c >= 0x70000 && c <= 0x7FFFD) ||
        (c >= 0x80000 && c <= 0x8FFFD) ||
        (c >= 0x90000 && c <= 0x9FFFD) ||
        (c >= 0xA0000 && c <= 0xAFFFD) ||
        (c >= 0xB0000 && c <= 0xBFFFD) ||
        (c >= 0xC0000 && c <= 0xCFFFD) ||
        (c >= 0xD0000 && c <= 0xDFFFD) ||
        (c >= 0xE0000 && c <= 0xEFFFD) ||
        (c >= 0xF0000 && c <= 0xFFFFD) ||
        (c >= 0x100000 && c <= 0x10FFFD);
}

void TY_(CheckUrl)( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    tmbchar c;
    tmbstr dest, p;
    unsigned int escape_count = 0, backslash_count = 0, bad_codepoint_count = 0;
    unsigned int i, pos = 0;
    unsigned int len;
    unsigned int increment;
    Bool isJavascript = no;

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    p = attval->value;

    isJavascript =
        TY_(tmbstrncmp)(p,"javascript:",sizeof("javascript:")-1)==0;

    for (i = 0; '\0' != (c = p[i]); ++i)
    {
        if (c == '\\')
        {
            ++backslash_count;
            if ( cfgBool(doc, TidyFixBackslash) && !isJavascript)
                p[i] = '/';
        }
        else if ((c > 0x7e) || (c <= 0x20) || (strchr("<>", c)))
            ++escape_count;
    }

    while ( *p != 0 )
    {
        if ( !IsURLCodePoint( p, &increment ) )
            ++bad_codepoint_count;
         p = p + increment;
    }
    p = attval->value;

    if ( cfgBool(doc, TidyFixUri) && escape_count )
    {
        Bool hadnonspace = no;
        len = TY_(tmbstrlen)(p) + escape_count * 2 + 1;
        dest = (tmbstr) TidyDocAlloc(doc, len);
 
        for (i = 0; 0 != (c = p[i]); ++i)
        {
            if ((c > 0x7e) || (c <= 0x20) || (strchr("<>", c)))
            {
                if (c == 0x20)
                {
                    /* #345 - special case for leading spaces - discard */
                    if (hadnonspace)
                        pos += sprintf( dest + pos, "%%%02X", (byte)c );
                }
                else
                {
                    pos += sprintf( dest + pos, "%%%02X", (byte)c );
                    hadnonspace = yes;
                }
            }
            else
            {
                hadnonspace = yes;
                dest[pos++] = c;
            }
        }
        dest[pos] = 0;

        TidyDocFree(doc, attval->value);
        attval->value = dest;
    }
    if ( backslash_count )
    {
        if ( cfgBool(doc, TidyFixBackslash) && !isJavascript )
            TY_(ReportAttrError)( doc, node, attval, FIXED_BACKSLASH );
        else
            TY_(ReportAttrError)( doc, node, attval, BACKSLASH_IN_URI );
    }
    if ( escape_count )
    {
        if ( cfgBool(doc, TidyFixUri) )
            TY_(ReportAttrError)( doc, node, attval, ESCAPED_ILLEGAL_URI);
        else if ( !(TY_(HTMLVersion)(doc) & VERS_HTML5) )
            TY_(ReportAttrError)( doc, node, attval, ILLEGAL_URI_REFERENCE);

        doc->badChars |= BC_INVALID_URI;
    }
    if ( bad_codepoint_count )
    {
        TY_(ReportAttrError)( doc, node, attval, ILLEGAL_URI_CODEPOINT );
    }
}

/* RFC 2396, section 4.2 states:
     "[...] in the case of HTML's FORM element, [...] an
     empty URI reference represents the base URI of the
     current document and should be replaced by that URI
     when transformed into a request."
*/
void CheckAction( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    if (AttrHasValue(attval))
        TY_(CheckUrl)( doc, node, attval );
}

void CheckScript( TidyDocImpl* ARG_UNUSED(doc), Node* ARG_UNUSED(node),
                  AttVal* ARG_UNUSED(attval))
{
}

Bool TY_(IsValidHTMLID)(ctmbstr id)
{
    ctmbstr s = id;

    if (!s)
        return no;

    while (*s)
        if (TY_(IsHTMLSpace)(*s++))
            return no;

    return yes;

}

Bool TY_(IsValidXMLID)(ctmbstr id)
{
    ctmbstr s = id;
    tchar c;

    if (!s)
        return no;

    c = *s++;
    if (c > 0x7F)
        s += TY_(GetUTF8)(s, &c);

    if (!(TY_(IsXMLLetter)(c) || c == '_' || c == ':'))
        return no;

    while (*s)
    {
        c = (unsigned char)*s;

        if (c > 0x7F)
            s += TY_(GetUTF8)(s, &c);

        ++s;

        if (!TY_(IsXMLNamechar)(c))
            return no;
    }

    return yes;
}

static Bool IsValidNMTOKEN(ctmbstr name)
{
    ctmbstr s = name;
    tchar c;

    if (!s)
        return no;

    while (*s)
    {
        c = (unsigned char)*s;

        if (c > 0x7F)
            s += TY_(GetUTF8)(s, &c);

        ++s;

        if (!TY_(IsXMLNamechar)(c))
            return no;
    }

    return yes;
}

static Bool AttrValueIsAmong(AttVal *attval, ctmbstr const list[])
{
    const ctmbstr *v;   
    for (v = list; *v; ++v)
        if (AttrValueIs(attval, *v))
            return yes;
    return no;
}

static void CheckAttrValidity( TidyDocImpl* doc, Node *node, AttVal *attval,
                               ctmbstr const list[])
{
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    CheckLowerCaseAttrValue( doc, node, attval );

    if (!AttrValueIsAmong(attval, list))
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
}

void CheckName( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    Node *old;

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    if ( TY_(IsAnchorElement)(doc, node) )
    {
        if (cfgBool(doc, TidyXmlOut) && !IsValidNMTOKEN(attval->value))
            TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);

        if ((old = GetNodeByAnchor(doc, attval->value)) &&  old != node)
        {
            if (node->implicit) /* Is #709 - improve warning text */
                TY_(ReportAttrError)(doc, node, attval, ANCHOR_DUPLICATED);
            else
                TY_(ReportAttrError)( doc, node, attval, ANCHOR_NOT_UNIQUE);
        }
        else
            AddAnchor( doc, attval->value, node );
    }
}

void CheckId( TidyDocImpl* doc, Node *node, AttVal *attval )
{
    Lexer* lexer = doc->lexer;
    Node *old;

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    if (!TY_(IsValidHTMLID)(attval->value))
    {
        if (lexer->isvoyager && TY_(IsValidXMLID)(attval->value))
            TY_(ReportAttrError)( doc, node, attval, XML_ID_SYNTAX);
        else
            TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }

    if ((old = GetNodeByAnchor(doc, attval->value)) &&  old != node)
    {
        if (node->implicit) /* Is #709 - improve warning text */
            TY_(ReportAttrError)(doc, node, attval, ANCHOR_DUPLICATED);
        else
            TY_(ReportAttrError)( doc, node, attval, ANCHOR_NOT_UNIQUE);
    }
    else
        AddAnchor( doc, attval->value, node );
}

void CheckIs( TidyDocImpl* doc, Node *node, AttVal *attval )
{
    const char *ptr;
    Bool go = yes;

    /* `is` MUST NOT be in an autonomous custom tag */
    ptr = strchr(node->element, '-');
    if ( ( ptr && (ptr - node->element > 0) ) )
    {
        TY_(ReportAttrError)( doc, node, attval, ATTRIBUTE_IS_NOT_ALLOWED);
    }

    /* Even if we fail the above test, we'll continue to emit reports because
       the user should *also* know that his attribute values are wrong, even
       if they should't be in custom tags anyway. */

    /* `is` MUST have a value */
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    /* `is` MUST contain a hyphen and no space. */
    ptr = strchr(attval->value, '-');
    go = ( ptr && (ptr - attval->value > 0) );
    ptr = strchr(attval->value, ' ');
    go = go & (ptr == NULL);
    if ( !go )
    {
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }
}

void CheckBool( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    if (!AttrHasValue(attval))
        return;

    CheckLowerCaseAttrValue( doc, node, attval );
}

void CheckAlign( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"left", "right", "center", "justify", NULL};

    /* IMG, OBJECT, APPLET and EMBED use align for vertical position */
    if (node->tag && (node->tag->model & CM_IMG))
    {
        CheckValign( doc, node, attval );
        return;
    }

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    CheckLowerCaseAttrValue( doc, node, attval);

    /* currently CheckCaption(...) takes care of the remaining cases */
    if (nodeIsCAPTION(node))
        return;

    if (!AttrValueIsAmong(attval, values))
    {
        /* align="char" is allowed for elements with CM_TABLE|CM_ROW
           except CAPTION which is excluded above, */
        if( !(AttrValueIs(attval, "char")
              && TY_(nodeHasCM)(node, CM_TABLE|CM_ROW)) )
             TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }
}

void CheckValign( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"top", "middle", "bottom", "baseline", NULL};
    ctmbstr const values2[] = {"left", "right", NULL};
    ctmbstr const valuesp[] = {"texttop", "absmiddle", "absbottom",
                               "textbottom", NULL};

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    CheckLowerCaseAttrValue( doc, node, attval );

    if (AttrValueIsAmong(attval, values))
    {
            /* all is fine */
    }
    else if (AttrValueIsAmong(attval, values2))
    {
        if (!(node->tag && (node->tag->model & CM_IMG)))
            TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }
    else if (AttrValueIsAmong(attval, valuesp))
    {
        TY_(ConstrainVersion)( doc, VERS_PROPRIETARY );
        TY_(ReportAttrError)( doc, node, attval, PROPRIETARY_ATTR_VALUE);
    }
    else
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
}

void CheckLength( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    tmbstr p;
    
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    /* don't check for <col width=...> and <colgroup width=...> */
    if (attrIsWIDTH(attval) && (nodeIsCOL(node) || nodeIsCOLGROUP(node)))
        return;

    p = attval->value;
    
    if (!TY_(IsDigit)(*p++))
    {
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }
    else
    {
        while (*p)
        {
            if (!TY_(IsDigit)(*p) && *p != '%')
            {
                TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
                break;
            }
            ++p;
        }
    }
}

void CheckTarget( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"_blank", "_self", "_parent", "_top", NULL};

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    /* target names must begin with A-Za-z ... */
    if (TY_(IsLetter)(attval->value[0]))
        return;

    /* or be one of the allowed list */
    if (!AttrValueIsAmong(attval, values))
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
}

void CheckFsubmit( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"get", "post", NULL};
    CheckAttrValidity( doc, node, attval, values );
}

void CheckClear( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"none", "left", "right", "all", NULL};

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        if (attval->value == NULL)
            attval->value = TY_(tmbstrdup)( doc->allocator, "none" );
        return;
    }

    CheckLowerCaseAttrValue( doc, node, attval );
        
    if (!AttrValueIsAmong(attval, values))
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
}

void CheckShape( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"rect", "default", "circle", "poly", NULL};
    CheckAttrValidity( doc, node, attval, values );
}

void CheckScope( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"row", "rowgroup", "col", "colgroup", NULL};
    CheckAttrValidity( doc, node, attval, values );
}

void CheckNumber( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    tmbstr p;
    
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    /* don't check <frameset cols=... rows=...> */
    if ( nodeIsFRAMESET(node) &&
        (attrIsCOLS(attval) || attrIsROWS(attval)))
     return;

    p  = attval->value;
    
    /* font size may be preceded by + or - */
    if ( nodeIsFONT(node) && (*p == '+' || *p == '-') )
        ++p;
    /* tabindex may be preceeded by - */
    if (attval->attribute && (strcmp(attval->attribute,"tabindex") == 0) && (*p == '-'))
        ++p;

    while (*p)
    {
        if (!TY_(IsDigit)(*p))
        {
            TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
            break;
        }
        ++p;
    }
}

/* check hexadecimal color value */
static Bool IsValidColorCode(ctmbstr color)
{
    unsigned int i;

    if (TY_(tmbstrlen)(color) != 6)
        return no;

    /* check if valid hex digits and letters */
    for (i = 0; i < 6; i++)
        if (!TY_(IsDigit)(color[i]) && !strchr("abcdef", TY_(ToLower)(color[i])))
            return no;

    return yes;
}

/* check color syntax and beautify value by option */
void CheckColor( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    Bool valid = no;
    tmbstr given;

    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    given = attval->value;

    /* 727851 - add hash to hash-less color values */
    if (given[0] != '#' && (valid = IsValidColorCode(given)))
    {
        tmbstr cp, s;

        cp = s = (tmbstr) TidyDocAlloc(doc, 2 + TY_(tmbstrlen)(given));
        *cp++ = '#';
        while ('\0' != (*cp++ = *given++))
            continue;

        TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE_REPLACED);

        TidyDocFree(doc, attval->value);
        given = attval->value = s;
    }

    if (!valid && given[0] == '#')
        valid = IsValidColorCode(given + 1);

    if (valid && given[0] == '#' && cfgBool(doc, TidyReplaceColor))
    {
        ctmbstr newName = GetColorName(given);

        if (newName)
        {
            TidyDocFree(doc, attval->value);
            given = attval->value = TY_(tmbstrdup)(doc->allocator, newName);
        }
    }

    /* if it is not a valid color code, it is a color name */
    if (!valid)
        valid = GetColorCode(given) != NULL;

    if (valid && given[0] == '#')
        attval->value = TY_(tmbstrtoupper)(attval->value);
    else if (valid)
        attval->value = TY_(tmbstrtolower)(attval->value);

    if (!valid)
        TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
}

/* check valuetype attribute for element param */
void CheckVType( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"data", "object", "ref", NULL};
    CheckAttrValidity( doc, node, attval, values );
}

/* checks scrolling attribute */
void CheckScroll( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values[] = {"no", "auto", "yes", NULL};
    CheckAttrValidity( doc, node, attval, values );
}

/* checks dir attribute */
void CheckTextDir( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const values4[] = { "rtl", "ltr", NULL };
    /* PR #712 - add 'auto' for HTML5 - @doronbehar */
    ctmbstr const values5[] = { "rtl", "ltr", "auto", NULL };
    CheckAttrValidity(doc, node, attval,
        (TY_(IsHTML5Mode)(doc) ? values5 : values4));
}

/* checks lang and xml:lang attributes */
void CheckLang( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    /* empty xml:lang is allowed through XML 1.0 SE errata */
    if (!AttrHasValue(attval) && !attrIsXML_LANG(attval))
    {
        if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
        {
            TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE );
        }
        return;
    }
}

/* checks type attribute */
void CheckType( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    ctmbstr const valuesINPUT[] = {
        "text", "password", "checkbox", "radio", "submit", "reset", "file",
        "hidden", "image", "button", "color", "date", "datetime",
        "datetime-local", "email", "month", "number", "range", "search",
        "tel", "time", "url", "week", NULL};
    ctmbstr const valuesBUTTON[] = {"button", "submit", "reset", NULL};
    ctmbstr const valuesUL[] = {"disc", "square", "circle", NULL};
    ctmbstr const valuesOL[] = {"1", "a", "i", NULL};

    if (nodeIsINPUT(node))
        CheckAttrValidity( doc, node, attval, valuesINPUT );
    else if (nodeIsBUTTON(node))
        CheckAttrValidity( doc, node, attval, valuesBUTTON );
    else if (nodeIsUL(node))
        CheckAttrValidity( doc, node, attval, valuesUL );
    else if (nodeIsOL(node))
    {
        if (!AttrHasValue(attval))
        {
            TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
            return;
        }
        if (!AttrValueIsAmong(attval, valuesOL))
            TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }
    else if (nodeIsLI(node))
    {
        if (!AttrHasValue(attval))
        {
            TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
            return;
        }
        if (AttrValueIsAmong(attval, valuesUL))
            CheckLowerCaseAttrValue( doc, node, attval );
        else if (!AttrValueIsAmong(attval, valuesOL))
            TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
    }
    return;
}

static
AttVal *SortAttVal( TidyDocImpl* doc, AttVal* list, TidyAttrSortStrategy strat );

void TY_(SortAttributes)(TidyDocImpl* doc, Node* node, TidyAttrSortStrategy strat)
{
    while (node)
    {
        node->attributes = SortAttVal( doc, node->attributes, strat );
        if (node->content)
            TY_(SortAttributes)(doc, node->content, strat);
        node = node->next;
    }
}

/**
* Attribute sorting contributed by Adrian Wilkins, 2007
* 
* Portions copyright Simon Tatham 2001.
*
* Merge sort algortithm adpated from listsort.c linked from 
* http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
* 
* Original copyright notice proceeds below.
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

typedef int(*ptAttValComparator)(AttVal *one, AttVal *two, ctmbstr *list);

/* Returns the index of the item in the array, or -1 if not in the array */
static
int indexof( ctmbstr item, ctmbstr *list )
{
    if ( list )
    {
        unsigned int i = 0;
        while ( list[i] != NULL ) {
            if ( TY_(tmbstrcasecmp)(item, list[i]) == 0 )
                return i;
            i++;
        }
    }

    return -1;
}

/* Comparison function for TidySortAttrAlpha. Will also consider items in
   the passed in list as higher-priority, and will group them first.
 */
static
int AlphaComparator(AttVal *one, AttVal *two, ctmbstr *list)
{
    int oneIndex = indexof( one->attribute, list );
    int twoIndex = indexof( two->attribute, list );

    /* If both on the list, the lower index has priority. */
    if ( oneIndex >= 0 && twoIndex >= 0 )
        return oneIndex < twoIndex ? -1 : 1;

    /* If A on the list but B not on the list, then A has priority. */
    if ( oneIndex >= 0 && twoIndex == -1 )
        return -1;

    /* If A not on the list but B is on the list, then B has priority. */
    if ( oneIndex == -1 && twoIndex >= 0 )
        return 1;

    /* Otherwise nothing is on the list, so just compare strings. */
    return TY_(tmbstrcmp)(one->attribute, two->attribute);
}


/* Comparison function for prioritizing list items. It doesn't otherwise
   sort.
 */
static
int PriorityComparator(AttVal *one, AttVal *two, ctmbstr *list)
{
    int oneIndex = indexof( one->attribute, list );
    int twoIndex = indexof( two->attribute, list );

    /* If both on the list, the lower index has priority. */
    if ( oneIndex >= 0 && twoIndex >= 0 )
        return oneIndex < twoIndex ? -1 : 1;

    /* If A on the list but B not on the list, then A has priority. */
    if ( oneIndex >= 0 && twoIndex == -1 )
        return -1;

    /* If A not on the list but B is on the list, then B has priority. */
    if ( oneIndex == -1 && twoIndex >= 0 )
        return 1;

    /* Otherwise nothing is on the list, so just mark them as the same. */
    return 0;
}


/* The "factory method" that returns a pointer to the comparator function */
static
ptAttValComparator GetAttValComparator(TidyAttrSortStrategy strat, ctmbstr *list)
{
    switch (strat)
    {
    case TidySortAttrAlpha:
        return AlphaComparator;
    case TidySortAttrNone:
        if ( list && list[0] )
            return PriorityComparator;
        break;
    }
    return 0;
}

/* The sort routine */
static
AttVal *SortAttVal( TidyDocImpl* doc, AttVal *list, TidyAttrSortStrategy strat)
{
    /* Get the list from the passed-in tidyDoc. */
    ctmbstr* priorityList = (ctmbstr*)doc->attribs.priorityAttribs.list;

    ptAttValComparator ptComparator = GetAttValComparator(strat, priorityList);
    AttVal *p, *q, *e, *tail;
    int insize, nmerges, psize, qsize, i;

    /*
    * Silly special case: if `list' was passed in as NULL, return
    * NULL immediately.
    */
    if (!list)
        return NULL;

    /* If no comparator, return the list as-is */
    if (ptComparator == 0)
        return list;

    insize = 1;

    while (1) {
        p = list;
        list = NULL;
        tail = NULL;

        nmerges = 0;  /* count number of merges we do in this pass */

        while (p) {
            nmerges++;  /* there exists a merge to be done */
            /* step `insize' places along from p */
            q = p;
            psize = 0;
            for (i = 0; i < insize; i++) {
                psize++;
                q = q->next;
                if(!q) break;
            }

            /* if q hasn't fallen off end, we have two lists to merge */
            qsize = insize;

            /* now we have two lists; merge them */
            while (psize > 0 || (qsize > 0 && q)) {

                /* decide whether next element of merge comes from p or q */
                if (psize == 0) {
                    /* p is empty; e must come from q. */
                    e = q; q = q->next; qsize--;
                } else if (qsize == 0 || !q) {
                    /* q is empty; e must come from p. */
                    e = p; p = p->next; psize--;
                } else if (ptComparator(p,q, priorityList) <= 0) {
                    /* First element of p is lower (or same);
                    * e must come from p. */
                    e = p; p = p->next; psize--;
                } else {
                    /* First element of q is lower; e must come from q. */
                    e = q; q = q->next; qsize--;
                }

                /* add the next element to the merged list */
                if (tail) {
                    tail->next = e;
                } else {
                    list = e;
                }

                tail = e;
            }

            /* now p has stepped `insize' places along, and q has too */
            p = q;
        }

        tail->next = NULL;

        /* If we have done only one merge, we're finished. */
        if (nmerges <= 1)   /* allow for nmerges==0, the empty list case */
            return list;

        /* Otherwise repeat, merging lists twice the size */
        insize *= 2;
    }
}

/* RDFA support checkers
 *
 */

/* CheckRDFAPrefix - ensure the prefix attribute value is
 * correct
 *
 * @prefix takes prefix value pairs in the form:
 * 
 *      NCName ':' ' '+ AnyURI
 */

void CheckRDFaPrefix ( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

    /* Copy the attribute value so we can split it */
    if (attval->value) {
        tmbstr t, tPtr ;

        unsigned int prefixCount = 0;
        /* isPrefix toggles - start at 1 and change to 0 as we
         * iterate over the components of the value */
        unsigned int isPrefix = 1;

        /* Copy it over */

        unsigned int len = TY_(tmbstrlen)(attval->value);
        tmbstr s = (tmbstr) TidyDocAlloc( doc, len + 1 );
        s[0] = '\0';
        TY_(tmbstrcpy)( s, attval->value );

        /* iterate over value */
        tPtr = s;

        while ( ( t = strtok(tPtr, " ") ) != NULL ) {
            tPtr = NULL;
            if (isPrefix) {
                /* this piece should be a prefix */
                /* prefix rules are that it can have any
                 * character except a colon - that one must be
                 * at the end */
                tmbstr i = strchr(t, ':') ;
                if (i == NULL) {
                    /* no colon - bad! */
                    TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
                } else if (i != ( t + TY_(tmbstrlen)(t) - 1) ) {
                    /* not at the end - also bad */
                    TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
                }
            } else {
                /* this piece should be a URL */
                prefixCount ++;
            }
            isPrefix = !isPrefix;
        }
        TidyDocFree( doc, s ) ;
    }
}

/* CheckRDFaTerm - are terms valid
 *
 */

void CheckRDFaTerm ( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

}

/* CheckRDFaSafeCURIE - is a CURIE legal
 *
 */

void CheckRDFaSafeCURIE ( TidyDocImpl* doc, Node *node, AttVal *attval)
{
    if (!AttrHasValue(attval))
    {
        TY_(ReportAttrError)( doc, node, attval, MISSING_ATTR_VALUE);
        return;
    }

}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* buffio.c -- Treat buffer as an I/O stream.

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Requires buffer to automatically grow as bytes are added.
  Must keep track of current read and write points.

*/

/* #include "tidy.h" */
/* #include "tidybuffio.h" */
/* #include "forward.h" */

/**************
   TIDY
**************/

static int TIDY_CALL insrc_getByte( void* appData )
{
  TidyBuffer* buf = (TidyBuffer*) appData;
  return tidyBufGetByte( buf );
}
static Bool TIDY_CALL insrc_eof( void* appData )
{
  TidyBuffer* buf = (TidyBuffer*) appData;
  return tidyBufEndOfInput( buf );
}
static void TIDY_CALL insrc_ungetByte( void* appData, byte bv )
{
  TidyBuffer* buf = (TidyBuffer*) appData;
  tidyBufUngetByte( buf, bv );
}

void TIDY_CALL tidyInitInputBuffer( TidyInputSource* inp, TidyBuffer* buf )
{
  inp->getByte    = insrc_getByte;
  inp->eof        = insrc_eof;
  inp->ungetByte  = insrc_ungetByte;
  inp->sourceData = buf;
}

static void TIDY_CALL outsink_putByte( void* appData, byte bv )
{
  TidyBuffer* buf = (TidyBuffer*) appData;
  tidyBufPutByte( buf, bv );
}

void TIDY_CALL tidyInitOutputBuffer( TidyOutputSink* outp, TidyBuffer* buf )
{
  outp->putByte  = outsink_putByte;
  outp->sinkData = buf;
}


void TIDY_CALL tidyBufInit( TidyBuffer* buf )
{
    assert( buf != NULL );
    tidyBufInitWithAllocator( buf, NULL );
}

void TIDY_CALL tidyBufAlloc( TidyBuffer* buf, unsigned int allocSize )
{
    tidyBufAllocWithAllocator( buf, NULL, allocSize );
}

void TIDY_CALL tidyBufInitWithAllocator( TidyBuffer* buf,
                                         TidyAllocator *allocator )
{
    assert( buf != NULL );
    TidyClearMemory( buf, sizeof(TidyBuffer) );
    buf->allocator = allocator ? allocator : &TY_(g_default_allocator);
}

void TIDY_CALL tidyBufAllocWithAllocator( TidyBuffer* buf,
                                          TidyAllocator *allocator,
                                          unsigned int allocSize )
{
    tidyBufInitWithAllocator( buf, allocator );
    tidyBufCheckAlloc( buf, allocSize, 0 );
    buf->next = 0;
}

void TIDY_CALL tidyBufFree( TidyBuffer* buf )
{
    assert( buf != NULL );
    TidyFree(  buf->allocator, buf->bp );
    tidyBufInitWithAllocator( buf, buf->allocator );
}

void TIDY_CALL tidyBufClear( TidyBuffer* buf )
{
    assert( buf != NULL );
    if ( buf->bp )
    {
        TidyClearMemory( buf->bp, buf->allocated );
        buf->size = 0;
    }
    buf->next = 0;
}

/* Many users do not call tidyBufInit() or tidyBufAlloc() or their allocator
   counterparts. So by default, set the default allocator.
*/
static void setDefaultAllocator( TidyBuffer* buf )
{
    buf->allocator = &TY_(g_default_allocator);
}

/* Avoid thrashing memory by doubling buffer size
** until larger than requested size.
   buf->allocated is bigger than allocSize+1 so that a trailing null byte is
   always available.
*/
void TIDY_CALL tidyBufCheckAlloc( TidyBuffer* buf, unsigned int allocSize, unsigned int chunkSize )
{
    assert( buf != NULL );

    if ( !buf->allocator )
        setDefaultAllocator( buf );
        
    if ( 0 == chunkSize )
        chunkSize = 256;
    if ( allocSize+1 > buf->allocated )
    {
        byte* bp;
        unsigned int allocAmt = chunkSize;
        if ( buf->allocated > 0 )
            allocAmt = buf->allocated;
        while ( allocAmt < allocSize+1 )
            allocAmt *= 2;

        bp = (byte*)TidyRealloc( buf->allocator, buf->bp, allocAmt );
        if ( bp != NULL )
        {
            TidyClearMemory( bp + buf->allocated, allocAmt - buf->allocated );
            buf->bp = bp;
            buf->allocated = allocAmt;
        }
    }
}

/* Attach buffer to a chunk O' memory w/out allocation */
void  TIDY_CALL tidyBufAttach( TidyBuffer* buf, byte* bp, unsigned int size )
{
    assert( buf != NULL );
    buf->bp = bp;
    buf->size = buf->allocated = size;
    buf->next = 0;
    if ( !buf->allocator )
        setDefaultAllocator( buf );
}

/* Clear pointer to memory w/out deallocation */
void TIDY_CALL tidyBufDetach( TidyBuffer* buf )
{
    tidyBufInitWithAllocator( buf, buf->allocator );
}


/**************
   OUTPUT
**************/

void TIDY_CALL tidyBufAppend( TidyBuffer* buf, void* vp, unsigned int size )
{
    assert( buf != NULL );
    if ( vp != NULL && size > 0 )
    {
        tidyBufCheckAlloc( buf, buf->size + size, 0 );
        memcpy( buf->bp + buf->size, vp, size );
        buf->size += size;
    }
}

void TIDY_CALL tidyBufPutByte( TidyBuffer* buf, byte bv )
{
    assert( buf != NULL );
    tidyBufCheckAlloc( buf, buf->size + 1, 0 );
    buf->bp[ buf->size++ ] = bv;
}


int TIDY_CALL tidyBufPopByte( TidyBuffer* buf )
{
    int bv = EOF;
    assert( buf != NULL );
    if ( buf->size > 0 )
      bv = buf->bp[ --buf->size ];
    return bv;
}

/**************
   INPUT
**************/

int TIDY_CALL tidyBufGetByte( TidyBuffer* buf )
{
    int bv = EOF;
    if ( ! tidyBufEndOfInput(buf) )
      bv = buf->bp[ buf->next++ ];
    return bv;
}

Bool TIDY_CALL tidyBufEndOfInput( TidyBuffer* buf )
{
    return ( buf->next >= buf->size );
}

void TIDY_CALL tidyBufUngetByte( TidyBuffer* buf, byte bv )
{
    if ( buf->next > 0 )
    {
        --buf->next;
        assert( bv == buf->bp[ buf->next ] );
    }
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* charsets.c -- character set information and mappings

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "forward.h" */
/* #include "tidy.h" */
/* #include "tmbstr.h" */
/* #include "charsets.h" */

/* todo: documentation of table and data       */
/* todo: integration of data and routines      */
/* todo: minor cleanup for ambiguous relations */
static struct _charsetInfo
{
    unsigned int id;
    ctmbstr charset;
    unsigned int codepage;
    unsigned int stateful;
} const charsetInfo[] =
{
  {   1, "adobe-standard-encoding",                           0,  no }, /* IANA */
  {   1, "csadobestandardencoding",                           0,  no }, /* IANA */
  {   2, "adobe-symbol-encoding",                             0,  no }, /* IANA */
  {   2, "cshppsmath",                                        0,  no }, /* IANA */
  {   3, "iso-ir-99",                                         0,  no }, /* IANA */
  {   3, "ansi_x3.110-1983",                                  0,  no }, /* IANA */
  {   3, "csa_t500-1983",                                     0,  no }, /* IANA */
  {   3, "naplps",                                            0,  no }, /* IANA */
  {   3, "csiso99naplps",                                     0,  no }, /* IANA */
  {   4, "us-ascii",                                      20127,  no }, /* IANA */
  {   4, "iso-ir-6",                                      20127,  no }, /* IANA */
  {   4, "ansi_x3.4-1968",                                20127,  no }, /* IANA */
  {   4, "ansi_x3.4-1986",                                20127,  no }, /* IANA */
  {   4, "iso_646.irv:1991",                              20127,  no }, /* IANA */
  {   4, "ascii",                                         20127,  no }, /* IANA */
  {   4, "iso646-us",                                     20127,  no }, /* IANA */
  {   4, "us",                                            20127,  no }, /* IANA */
  {   4, "ibm367",                                        20127,  no }, /* IANA */
  {   4, "cp367",                                         20127,  no }, /* IANA */
  {   4, "csascii",                                       20127,  no }, /* IANA */
  {   4, "iso-ir-6us",                                    20127,  no }, /* MICROSOFT */
  {   5, "iso-ir-89",                                         0,  no }, /* IANA */
  {   5, "asmo_449",                                          0,  no }, /* IANA */
  {   5, "iso_9036",                                          0,  no }, /* IANA */
  {   5, "arabic7",                                           0,  no }, /* IANA */
  {   5, "csiso89asmo449",                                    0,  no }, /* IANA */
  {   6, "big5",                                            950,  no }, /* IANA */
  {   6, "csbig5",                                          950,  no }, /* IANA */
  {   6, "cn-big5",                                         950,  no }, /* MICROSOFT */
  {   6, "x-x-big5",                                        950,  no }, /* MICROSOFT */
  {   7, "big5-hkscs",                                      950,  no }, /* IANA */
  {   7, "cn-big5",                                         950,  no }, /* MICROSOFT */
  {   7, "x-x-big5",                                        950,  no }, /* MICROSOFT */
  {   8, "bocu-1",                                            0,  no }, /* IANA */
  {   8, "csbocu-1",                                          0,  no }, /* IANA */
  {   9, "iso-ir-4",                                          0,  no }, /* IANA */
  {   9, "bs_4730",                                           0,  no }, /* IANA */
  {   9, "iso646-gb",                                         0,  no }, /* IANA */
  {   9, "gb",                                                0,  no }, /* IANA */
  {   9, "uk",                                                0,  no }, /* IANA */
  {   9, "csiso4unitedkingdom",                               0,  no }, /* IANA */
  {  10, "iso-ir-47",                                         0,  no }, /* IANA */
  {  10, "bs_viewdata",                                       0,  no }, /* IANA */
  {  10, "csiso47bsviewdata",                                 0,  no }, /* IANA */
  {  11, "cesu-8",                                            0,  no }, /* IANA */
  {  11, "cscesu-8",                                          0,  no }, /* IANA */
  {  12, "iso-ir-121",                                        0,  no }, /* IANA */
  {  12, "csa_z243.4-1985-1",                                 0,  no }, /* IANA */
  {  12, "iso646-ca",                                         0,  no }, /* IANA */
  {  12, "csa7-1",                                            0,  no }, /* IANA */
  {  12, "ca",                                                0,  no }, /* IANA */
  {  12, "csiso121canadian1",                                 0,  no }, /* IANA */
  {  13, "iso-ir-122",                                        0,  no }, /* IANA */
  {  13, "csa_z243.4-1985-2",                                 0,  no }, /* IANA */
  {  13, "iso646-ca2",                                        0,  no }, /* IANA */
  {  13, "csa7-2",                                            0,  no }, /* IANA */
  {  13, "csiso122canadian2",                                 0,  no }, /* IANA */
  {  14, "iso-ir-123",                                        0,  no }, /* IANA */
  {  14, "csa_z243.4-1985-gr",                                0,  no }, /* IANA */
  {  14, "csiso123csaz24341985gr",                            0,  no }, /* IANA */
  {  15, "iso-ir-139",                                        0,  no }, /* IANA */
  {  15, "csn_369103",                                        0,  no }, /* IANA */
  {  15, "csiso139csn369103",                                 0,  no }, /* IANA */
  {  16, "dec-mcs",                                           0,  no }, /* IANA */
  {  16, "dec",                                               0,  no }, /* IANA */
  {  16, "csdecmcs",                                          0,  no }, /* IANA */
  {  17, "iso-ir-21",                                     20106,  no }, /* IANA */
  {  17, "din_66003",                                     20106,  no }, /* IANA */
  {  17, "de",                                            20106,  no }, /* IANA */
  {  17, "iso646-de",                                     20106,  no }, /* IANA */
  {  17, "csiso21german",                                 20106,  no }, /* IANA */
  {  17, "x-ia5-german",                                  20106,  no }, /* MICROSOFT */
  {  18, "dk-us",                                             0,  no }, /* IANA */
  {  18, "csdkus",                                            0,  no }, /* IANA */
  {  19, "ds_2089",                                           0,  no }, /* IANA */
  {  19, "ds2089",                                            0,  no }, /* IANA */
  {  19, "iso646-dk",                                         0,  no }, /* IANA */
  {  19, "dk",                                                0,  no }, /* IANA */
  {  19, "csiso646danish",                                    0,  no }, /* IANA */
  {  20, "ebcdic-at-de",                                      0,  no }, /* IANA */
  {  20, "csibmebcdicatde",                                   0,  no }, /* IANA */
  {  21, "ebcdic-at-de-a",                                    0,  no }, /* IANA */
  {  21, "csebcdicatdea",                                     0,  no }, /* IANA */
  {  22, "ebcdic-ca-fr",                                      0,  no }, /* IANA */
  {  22, "csebcdiccafr",                                      0,  no }, /* IANA */
  {  23, "ebcdic-dk-no",                                      0,  no }, /* IANA */
  {  23, "csebcdicdkno",                                      0,  no }, /* IANA */
  {  24, "ebcdic-dk-no-a",                                    0,  no }, /* IANA */
  {  24, "csebcdicdknoa",                                     0,  no }, /* IANA */
  {  25, "ebcdic-es",                                         0,  no }, /* IANA */
  {  25, "csebcdices",                                        0,  no }, /* IANA */
  {  26, "ebcdic-es-a",                                       0,  no }, /* IANA */
  {  26, "csebcdicesa",                                       0,  no }, /* IANA */
  {  27, "ebcdic-es-s",                                       0,  no }, /* IANA */
  {  27, "csebcdicess",                                       0,  no }, /* IANA */
  {  28, "ebcdic-fi-se",                                      0,  no }, /* IANA */
  {  28, "csebcdicfise",                                      0,  no }, /* IANA */
  {  29, "ebcdic-fi-se-a",                                    0,  no }, /* IANA */
  {  29, "csebcdicfisea",                                     0,  no }, /* IANA */
  {  30, "ebcdic-fr",                                         0,  no }, /* IANA */
  {  30, "csebcdicfr",                                        0,  no }, /* IANA */
  {  31, "ebcdic-it",                                         0,  no }, /* IANA */
  {  31, "csebcdicit",                                        0,  no }, /* IANA */
  {  32, "ebcdic-pt",                                         0,  no }, /* IANA */
  {  32, "csebcdicpt",                                        0,  no }, /* IANA */
  {  33, "ebcdic-uk",                                         0,  no }, /* IANA */
  {  33, "csebcdicuk",                                        0,  no }, /* IANA */
  {  34, "ebcdic-us",                                         0,  no }, /* IANA */
  {  34, "csebcdicus",                                        0,  no }, /* IANA */
  {  35, "iso-ir-111",                                        0,  no }, /* IANA */
  {  35, "ecma-cyrillic",                                     0,  no }, /* IANA */
  {  35, "csiso111ecmacyrillic",                              0,  no }, /* IANA */
  {  36, "iso-ir-17",                                         0,  no }, /* IANA */
  {  36, "es",                                                0,  no }, /* IANA */
  {  36, "iso646-es",                                         0,  no }, /* IANA */
  {  36, "csiso17spanish",                                    0,  no }, /* IANA */
  {  37, "iso-ir-85",                                         0,  no }, /* IANA */
  {  37, "es2",                                               0,  no }, /* IANA */
  {  37, "iso646-es2",                                        0,  no }, /* IANA */
  {  37, "csiso85spanish2",                                   0,  no }, /* IANA */
  {  38, "euc-kr",                                        51949,  no }, /* IANA */
  {  38, "cseuckr",                                       51949,  no }, /* IANA */
  {  39, "extended_unix_code_fixed_width_for_japanese",       0,  no }, /* IANA */
  {  39, "cseucfixwidjapanese",                               0,  no }, /* IANA */
  {  40, "euc-jp",                                        51932,  no }, /* IANA */
  {  40, "extended_unix_code_packed_format_for_japanese", 51932,  no }, /* IANA */
  {  40, "cseucpkdfmtjapanese",                           51932,  no }, /* IANA */
  {  40, "x-euc-jp",                                      51932,  no }, /* MICROSOFT */
  {  40, "x-euc",                                         51932,  no }, /* MICROSOFT */
  {  41, "gb18030",                                       54936,  no }, /* IANA */
  {  42, "gb2312",                                          936,  no }, /* IANA */
  {  42, "csgb2312",                                        936,  no }, /* IANA */
  {  42, "csgb231280",                                      936,  no }, /* MICROSOFT */
  {  42, "gb2312-80",                                       936,  no }, /* MICROSOFT */
  {  42, "gb231280",                                        936,  no }, /* MICROSOFT */
  {  42, "cn-gb",                                           936,  no }, /* MICROSOFT */
  {  43, "iso-ir-57",                                         0,  no }, /* IANA */
  {  43, "gb_1988-80",                                        0,  no }, /* IANA */
  {  43, "cn",                                                0,  no }, /* IANA */
  {  43, "iso646-cn",                                         0,  no }, /* IANA */
  {  43, "csiso57gb1988",                                     0,  no }, /* IANA */
  {  44, "iso-ir-58",                                       936,  no }, /* IANA */
  {  44, "gb_2312-80",                                      936,  no }, /* IANA */
  {  44, "chinese",                                         936,  no }, /* IANA */
  {  44, "csiso58gb231280",                                 936,  no }, /* IANA */
  {  44, "csgb231280",                                      936,  no }, /* MICROSOFT */
  {  44, "gb2312-80",                                       936,  no }, /* MICROSOFT */
  {  44, "gb231280",                                        936,  no }, /* MICROSOFT */
  {  44, "cn-gb",                                           936,  no }, /* MICROSOFT */
  {  45, "gbk",                                             936,  no }, /* IANA */
  {  45, "cp936",                                           936,  no }, /* IANA */
  {  45, "ms936",                                           936,  no }, /* IANA */
  {  45, "windows-936",                                     936,  no }, /* IANA */
  {  45, "csgb231280",                                      936,  no }, /* MICROSOFT */
  {  45, "gb2312-80",                                       936,  no }, /* MICROSOFT */
  {  45, "gb231280",                                        936,  no }, /* MICROSOFT */
  {  45, "cn-gb",                                           936,  no }, /* MICROSOFT */
  {  46, "iso-ir-153",                                        0,  no }, /* IANA */
  {  46, "gost_19768-74",                                     0,  no }, /* IANA */
  {  46, "st_sev_358-88",                                     0,  no }, /* IANA */
  {  46, "csiso153gost1976874",                               0,  no }, /* IANA */
  {  47, "iso-ir-150",                                        0,  no }, /* IANA */
  {  47, "greek-ccitt",                                       0,  no }, /* IANA */
  {  47, "csiso150",                                          0,  no }, /* IANA */
  {  47, "csiso150greekccitt",                                0,  no }, /* IANA */
  {  48, "iso-ir-88",                                         0,  no }, /* IANA */
  {  48, "greek7",                                            0,  no }, /* IANA */
  {  48, "csiso88greek7",                                     0,  no }, /* IANA */
  {  49, "iso-ir-18",                                         0,  no }, /* IANA */
  {  49, "greek7-old",                                        0,  no }, /* IANA */
  {  49, "csiso18greek7old",                                  0,  no }, /* IANA */
  {  50, "hp-desktop",                                        0,  no }, /* IANA */
  {  50, "cshpdesktop",                                       0,  no }, /* IANA */
  {  51, "hp-legal",                                          0,  no }, /* IANA */
  {  51, "cshplegal",                                         0,  no }, /* IANA */
  {  52, "hp-math8",                                          0,  no }, /* IANA */
  {  52, "cshpmath8",                                         0,  no }, /* IANA */
  {  53, "hp-pi-font",                                        0,  no }, /* IANA */
  {  53, "cshppifont",                                        0,  no }, /* IANA */
  {  54, "hp-roman8",                                         0,  no }, /* IANA */
  {  54, "roman8",                                            0,  no }, /* IANA */
  {  54, "r8",                                                0,  no }, /* IANA */
  {  54, "cshproman8",                                        0,  no }, /* IANA */
  {  55, "hz-gb-2312",                                    52936, yes }, /* IANA */
  {  56, "ibm-symbols",                                       0,  no }, /* IANA */
  {  56, "csibmsymbols",                                      0,  no }, /* IANA */
  {  57, "ibm-thai",                                      20838,  no }, /* IANA */
  {  57, "csibmthai",                                     20838,  no }, /* IANA */
  {  57, "x-ebcdic-thai",                                 20838,  no }, /* MICROSOFT */
  {  58, "ibm00858",                                        858,  no }, /* IANA */
  {  58, "ccsid00858",                                      858,  no }, /* IANA */
  {  58, "cp00858",                                         858,  no }, /* IANA */
  {  58, "pc-multilingual-850+euro",                        858,  no }, /* IANA */
  {  59, "ibm00924",                                      20924,  no }, /* IANA */
  {  59, "ccsid00924",                                    20924,  no }, /* IANA */
  {  59, "cp00924",                                       20924,  no }, /* IANA */
  {  59, "ebcdic-latin9--euro",                           20924,  no }, /* IANA */
  {  60, "ibm01140",                                       1140,  no }, /* IANA */
  {  60, "ccsid01140",                                     1140,  no }, /* IANA */
  {  60, "cp01140",                                        1140,  no }, /* IANA */
  {  60, "ebcdic-us-37+euro",                              1140,  no }, /* IANA */
  {  60, "x-ebcdic-cp-us-euro",                            1140,  no }, /* MICROSOFT */
  {  61, "ibm01141",                                       1141,  no }, /* IANA */
  {  61, "ccsid01141",                                     1141,  no }, /* IANA */
  {  61, "cp01141",                                        1141,  no }, /* IANA */
  {  61, "ebcdic-de-273+euro",                             1141,  no }, /* IANA */
  {  61, "x-ebcdic-germany-euro",                          1141,  no }, /* MICROSOFT */
  {  62, "ibm01142",                                       1142,  no }, /* IANA */
  {  62, "ccsid01142",                                     1142,  no }, /* IANA */
  {  62, "cp01142",                                        1142,  no }, /* IANA */
  {  62, "ebcdic-dk-277+euro",                             1142,  no }, /* IANA */
  {  62, "ebcdic-no-277+euro",                             1142,  no }, /* IANA */
  {  62, "x-ebcdic-denmarknorway-euro",                    1142,  no }, /* MICROSOFT */
  {  63, "ibm01143",                                       1143,  no }, /* IANA */
  {  63, "ccsid01143",                                     1143,  no }, /* IANA */
  {  63, "cp01143",                                        1143,  no }, /* IANA */
  {  63, "ebcdic-fi-278+euro",                             1143,  no }, /* IANA */
  {  63, "ebcdic-se-278+euro",                             1143,  no }, /* IANA */
  {  63, "x-ebcdic-france",                                1143,  no }, /* MICROSOFT */
  {  63, "x-ebcdic-finlandsweden-euro",                    1143,  no }, /* MICROSOFT */
  {  64, "ibm01144",                                       1144,  no }, /* IANA */
  {  64, "ccsid01144",                                     1144,  no }, /* IANA */
  {  64, "cp01144",                                        1144,  no }, /* IANA */
  {  64, "ebcdic-it-280+euro",                             1144,  no }, /* IANA */
  {  64, "x-ebcdic-italy-euro",                            1144,  no }, /* MICROSOFT */
  {  65, "ibm01145",                                       1145,  no }, /* IANA */
  {  65, "ccsid01145",                                     1145,  no }, /* IANA */
  {  65, "cp01145",                                        1145,  no }, /* IANA */
  {  65, "ebcdic-es-284+euro",                             1145,  no }, /* IANA */
  {  65, "x-ebcdic-spain-euro",                            1145,  no }, /* MICROSOFT */
  {  66, "ibm01146",                                       1146,  no }, /* IANA */
  {  66, "ccsid01146",                                     1146,  no }, /* IANA */
  {  66, "cp01146",                                        1146,  no }, /* IANA */
  {  66, "ebcdic-gb-285+euro",                             1146,  no }, /* IANA */
  {  66, "x-ebcdic-uk-euro",                               1146,  no }, /* MICROSOFT */
  {  67, "ibm01147",                                       1147,  no }, /* IANA */
  {  67, "ccsid01147",                                     1147,  no }, /* IANA */
  {  67, "cp01147",                                        1147,  no }, /* IANA */
  {  67, "ebcdic-fr-297+euro",                             1147,  no }, /* IANA */
  {  67, "x-ebcdic-france-euro",                           1147,  no }, /* MICROSOFT */
  {  68, "ibm01148",                                       1148,  no }, /* IANA */
  {  68, "ccsid01148",                                     1148,  no }, /* IANA */
  {  68, "cp01148",                                        1148,  no }, /* IANA */
  {  68, "ebcdic-international-500+euro",                  1148,  no }, /* IANA */
  {  68, "x-ebcdic-international-euro",                    1148,  no }, /* MICROSOFT */
  {  69, "ibm01149",                                       1149,  no }, /* IANA */
  {  69, "ccsid01149",                                     1149,  no }, /* IANA */
  {  69, "cp01149",                                        1149,  no }, /* IANA */
  {  69, "ebcdic-is-871+euro",                             1149,  no }, /* IANA */
  {  69, "x-ebcdic-icelandic-euro",                        1149,  no }, /* MICROSOFT */
  {  70, "ibm037",                                           37,  no }, /* IANA */
  {  70, "cp037",                                            37,  no }, /* IANA */
  {  70, "ebcdic-cp-us",                                     37,  no }, /* IANA */
  {  70, "ebcdic-cp-ca",                                     37,  no }, /* IANA */
  {  70, "ebcdic-cp-wt",                                     37,  no }, /* IANA */
  {  70, "ebcdic-cp-nl",                                     37,  no }, /* IANA */
  {  70, "csibm037",                                         37,  no }, /* IANA */
  {  71, "ibm038",                                            0,  no }, /* IANA */
  {  71, "ebcdic-int",                                        0,  no }, /* IANA */
  {  71, "cp038",                                             0,  no }, /* IANA */
  {  71, "csibm038",                                          0,  no }, /* IANA */
  {  72, "ibm1026",                                        1026,  no }, /* IANA */
  {  72, "cp1026",                                         1026,  no }, /* IANA */
  {  72, "csibm1026",                                      1026,  no }, /* IANA */
  {  73, "ibm1047",                                           0,  no }, /* IANA */
  {  73, "ibm-1047",                                          0,  no }, /* IANA */
  {  74, "ibm273",                                        20273,  no }, /* IANA */
  {  74, "cp273",                                         20273,  no }, /* IANA */
  {  74, "csibm273",                                      20273,  no }, /* IANA */
  {  74, "x-ebcdic-germany",                              20273,  no }, /* MICROSOFT */
  {  75, "ibm274",                                            0,  no }, /* IANA */
  {  75, "ebcdic-be",                                         0,  no }, /* IANA */
  {  75, "cp274",                                             0,  no }, /* IANA */
  {  75, "csibm274",                                          0,  no }, /* IANA */
  {  76, "ibm275",                                            0,  no }, /* IANA */
  {  76, "ebcdic-br",                                         0,  no }, /* IANA */
  {  76, "cp275",                                             0,  no }, /* IANA */
  {  76, "csibm275",                                          0,  no }, /* IANA */
  {  77, "ibm277",                                        20277,  no }, /* IANA */
  {  77, "ebcdic-cp-dk",                                  20277,  no }, /* IANA */
  {  77, "ebcdic-cp-no",                                  20277,  no }, /* IANA */
  {  77, "csibm277",                                      20277,  no }, /* IANA */
  {  77, "x-ebcdic-denmarknorway",                        20277,  no }, /* MICROSOFT */
  {  78, "ibm278",                                        20278,  no }, /* IANA */
  {  78, "cp278",                                         20278,  no }, /* IANA */
  {  78, "ebcdic-cp-fi",                                  20278,  no }, /* IANA */
  {  78, "ebcdic-cp-se",                                  20278,  no }, /* IANA */
  {  78, "csibm278",                                      20278,  no }, /* IANA */
  {  78, "x-ebcdic-finlandsweden",                        20278,  no }, /* MICROSOFT */
  {  79, "ibm280",                                        20280,  no }, /* IANA */
  {  79, "cp280",                                         20280,  no }, /* IANA */
  {  79, "ebcdic-cp-it",                                  20280,  no }, /* IANA */
  {  79, "csibm280",                                      20280,  no }, /* IANA */
  {  79, "x-ebcdic-italy",                                20280,  no }, /* MICROSOFT */
  {  80, "ibm281",                                            0,  no }, /* IANA */
  {  80, "ebcdic-jp-e",                                       0,  no }, /* IANA */
  {  80, "cp281",                                             0,  no }, /* IANA */
  {  80, "csibm281",                                          0,  no }, /* IANA */
  {  81, "ibm284",                                        20284,  no }, /* IANA */
  {  81, "cp284",                                         20284,  no }, /* IANA */
  {  81, "ebcdic-cp-es",                                  20284,  no }, /* IANA */
  {  81, "csibm284",                                      20284,  no }, /* IANA */
  {  81, "x-ebcdic-spain",                                20284,  no }, /* MICROSOFT */
  {  82, "ibm285",                                        20285,  no }, /* IANA */
  {  82, "cp285",                                         20285,  no }, /* IANA */
  {  82, "ebcdic-cp-gb",                                  20285,  no }, /* IANA */
  {  82, "csibm285",                                      20285,  no }, /* IANA */
  {  82, "x-ebcdic-uk",                                   20285,  no }, /* MICROSOFT */
  {  83, "ibm290",                                        20290,  no }, /* IANA */
  {  83, "cp290",                                         20290,  no }, /* IANA */
  {  83, "ebcdic-jp-kana",                                20290,  no }, /* IANA */
  {  83, "csibm290",                                      20290,  no }, /* IANA */
  {  83, "x-ebcdic-japanesekatakana",                     20290,  no }, /* MICROSOFT */
  {  84, "ibm297",                                        20297,  no }, /* IANA */
  {  84, "cp297",                                         20297,  no }, /* IANA */
  {  84, "ebcdic-cp-fr",                                  20297,  no }, /* IANA */
  {  84, "csibm297",                                      20297,  no }, /* IANA */
  {  85, "ibm420",                                        20420,  no }, /* IANA */
  {  85, "cp420",                                         20420,  no }, /* IANA */
  {  85, "ebcdic-cp-ar1",                                 20420,  no }, /* IANA */
  {  85, "csibm420",                                      20420,  no }, /* IANA */
  {  85, "x-ebcdic-arabic",                               20420,  no }, /* MICROSOFT */
  {  86, "ibm423",                                        20423,  no }, /* IANA */
  {  86, "cp423",                                         20423,  no }, /* IANA */
  {  86, "ebcdic-cp-gr",                                  20423,  no }, /* IANA */
  {  86, "csibm423",                                      20423,  no }, /* IANA */
  {  86, "x-ebcdic-greek",                                20423,  no }, /* MICROSOFT */
  {  87, "ibm424",                                        20424,  no }, /* IANA */
  {  87, "cp424",                                         20424,  no }, /* IANA */
  {  87, "ebcdic-cp-he",                                  20424,  no }, /* IANA */
  {  87, "csibm424",                                      20424,  no }, /* IANA */
  {  87, "x-ebcdic-hebrew",                               20424,  no }, /* MICROSOFT */
  {  88, "ibm437",                                          437,  no }, /* IANA */
  {  88, "cp437",                                           437,  no }, /* IANA */
  {  88, "437",                                             437,  no }, /* IANA */
  {  88, "cspc8codepage437",                                437,  no }, /* IANA */
  {  88, "codepage437",                                     437,  no }, /* MICROSOFT */
  {  88, "cspc8",                                           437,  no }, /* MICROSOFT */
  {  89, "ibm500",                                          500,  no }, /* IANA */
  {  89, "cp500",                                           500,  no }, /* IANA */
  {  89, "ebcdic-cp-be",                                    500,  no }, /* IANA */
  {  89, "ebcdic-cp-ch",                                    500,  no }, /* IANA */
  {  89, "csibm500",                                        500,  no }, /* IANA */
  {  90, "ibm775",                                          775,  no }, /* IANA */
  {  90, "cp775",                                           775,  no }, /* IANA */
  {  90, "cspc775baltic",                                   775,  no }, /* IANA */
  {  91, "ibm850",                                          850,  no }, /* IANA */
  {  91, "cp850",                                           850,  no }, /* IANA */
  {  91, "850",                                             850,  no }, /* IANA */
  {  91, "cspc850multilingual",                             850,  no }, /* IANA */
  {  92, "ibm851",                                            0,  no }, /* IANA */
  {  92, "cp851",                                             0,  no }, /* IANA */
  {  92, "851",                                               0,  no }, /* IANA */
  {  92, "csibm851",                                          0,  no }, /* IANA */
  {  93, "ibm852",                                          852,  no }, /* IANA */
  {  93, "cp852",                                           852,  no }, /* IANA */
  {  93, "852",                                             852,  no }, /* IANA */
  {  93, "cspcp852",                                        852,  no }, /* IANA */
  {  94, "ibm855",                                          855,  no }, /* IANA */
  {  94, "cp855",                                           855,  no }, /* IANA */
  {  94, "855",                                             855,  no }, /* IANA */
  {  94, "csibm855",                                        855,  no }, /* IANA */
  {  95, "ibm857",                                          857,  no }, /* IANA */
  {  95, "cp857",                                           857,  no }, /* IANA */
  {  95, "857",                                             857,  no }, /* IANA */
  {  95, "csibm857",                                        857,  no }, /* IANA */
  {  96, "ibm860",                                          860,  no }, /* IANA */
  {  96, "cp860",                                           860,  no }, /* IANA */
  {  96, "860",                                             860,  no }, /* IANA */
  {  96, "csibm860",                                        860,  no }, /* IANA */
  {  97, "ibm861",                                          861,  no }, /* IANA */
  {  97, "cp861",                                           861,  no }, /* IANA */
  {  97, "861",                                             861,  no }, /* IANA */
  {  97, "cp-is",                                           861,  no }, /* IANA */
  {  97, "csibm861",                                        861,  no }, /* IANA */
  {  98, "ibm862",                                          862,  no }, /* IANA */
  {  98, "cp862",                                           862,  no }, /* IANA */
  {  98, "862",                                             862,  no }, /* IANA */
  {  98, "cspc862latinhebrew",                              862,  no }, /* IANA */
  {  98, "dos-862",                                         862,  no }, /* MICROSOFT */
  {  99, "ibm863",                                          863,  no }, /* IANA */
  {  99, "cp863",                                           863,  no }, /* IANA */
  {  99, "863",                                             863,  no }, /* IANA */
  {  99, "csibm863",                                        863,  no }, /* IANA */
  { 100, "ibm864",                                          864,  no }, /* IANA */
  { 100, "cp864",                                           864,  no }, /* IANA */
  { 100, "csibm864",                                        864,  no }, /* IANA */
  { 101, "ibm865",                                          865,  no }, /* IANA */
  { 101, "cp865",                                           865,  no }, /* IANA */
  { 101, "865",                                             865,  no }, /* IANA */
  { 101, "csibm865",                                        865,  no }, /* IANA */
  { 102, "ibm866",                                          866,  no }, /* IANA */
  { 102, "cp866",                                           866,  no }, /* IANA */
  { 102, "866",                                             866,  no }, /* IANA */
  { 102, "csibm866",                                        866,  no }, /* IANA */
  { 103, "ibm868",                                            0,  no }, /* IANA */
  { 103, "cp868",                                             0,  no }, /* IANA */
  { 103, "cp-ar",                                             0,  no }, /* IANA */
  { 103, "csibm868",                                          0,  no }, /* IANA */
  { 104, "ibm869",                                          869,  no }, /* IANA */
  { 104, "cp869",                                           869,  no }, /* IANA */
  { 104, "869",                                             869,  no }, /* IANA */
  { 104, "cp-gr",                                           869,  no }, /* IANA */
  { 104, "csibm869",                                        869,  no }, /* IANA */
  { 105, "ibm870",                                          870,  no }, /* IANA */
  { 105, "cp870",                                           870,  no }, /* IANA */
  { 105, "ebcdic-cp-roece",                                 870,  no }, /* IANA */
  { 105, "ebcdic-cp-yu",                                    870,  no }, /* IANA */
  { 105, "csibm870",                                        870,  no }, /* IANA */
  { 106, "ibm871",                                        20871,  no }, /* IANA */
  { 106, "cp871",                                         20871,  no }, /* IANA */
  { 106, "ebcdic-cp-is",                                  20871,  no }, /* IANA */
  { 106, "csibm871",                                      20871,  no }, /* IANA */
  { 106, "x-ebcdic-icelandic",                            20871,  no }, /* MICROSOFT */
  { 107, "ibm880",                                        20880,  no }, /* IANA */
  { 107, "cp880",                                         20880,  no }, /* IANA */
  { 107, "ebcdic-cyrillic",                               20880,  no }, /* IANA */
  { 107, "csibm880",                                      20880,  no }, /* IANA */
  { 107, "x-ebcdic-cyrillicrussian",                      20880,  no }, /* MICROSOFT */
  { 108, "ibm891",                                            0,  no }, /* IANA */
  { 108, "cp891",                                             0,  no }, /* IANA */
  { 108, "csibm891",                                          0,  no }, /* IANA */
  { 109, "ibm903",                                            0,  no }, /* IANA */
  { 109, "cp903",                                             0,  no }, /* IANA */
  { 109, "csibm903",                                          0,  no }, /* IANA */
  { 110, "ibm904",                                            0,  no }, /* IANA */
  { 110, "cp904",                                             0,  no }, /* IANA */
  { 110, "904",                                               0,  no }, /* IANA */
  { 110, "csibbm904",                                         0,  no }, /* IANA */
  { 111, "ibm905",                                        20905,  no }, /* IANA */
  { 111, "cp905",                                         20905,  no }, /* IANA */
  { 111, "ebcdic-cp-tr",                                  20905,  no }, /* IANA */
  { 111, "csibm905",                                      20905,  no }, /* IANA */
  { 111, "x-ebcdic-turkish",                              20905,  no }, /* MICROSOFT */
  { 112, "ibm918",                                            0,  no }, /* IANA */
  { 112, "cp918",                                             0,  no }, /* IANA */
  { 112, "ebcdic-cp-ar2",                                     0,  no }, /* IANA */
  { 112, "csibm918",                                          0,  no }, /* IANA */
  { 113, "iso-ir-143",                                        0,  no }, /* IANA */
  { 113, "iec_p27-1",                                         0,  no }, /* IANA */
  { 113, "csiso143iecp271",                                   0,  no }, /* IANA */
  { 114, "iso-ir-49",                                         0,  no }, /* IANA */
  { 114, "inis",                                              0,  no }, /* IANA */
  { 114, "csiso49inis",                                       0,  no }, /* IANA */
  { 115, "iso-ir-50",                                         0,  no }, /* IANA */
  { 115, "inis-8",                                            0,  no }, /* IANA */
  { 115, "csiso50inis8",                                      0,  no }, /* IANA */
  { 116, "iso-ir-51",                                         0,  no }, /* IANA */
  { 116, "inis-cyrillic",                                     0,  no }, /* IANA */
  { 116, "csiso51iniscyrillic",                               0,  no }, /* IANA */
  { 117, "invariant",                                         0,  no }, /* IANA */
  { 117, "csinvariant",                                       0,  no }, /* IANA */
  { 118, "iso-10646-j-1",                                     0,  no }, /* IANA */
  { 119, "iso-10646-ucs-2",                                1200,  no }, /* IANA */
  { 119, "csunicode",                                      1200,  no }, /* IANA */
  { 119, "unicode",                                        1200,  no }, /* MICROSOFT */
  { 120, "iso-10646-ucs-4",                                   0,  no }, /* IANA */
  { 120, "csucs4",                                            0,  no }, /* IANA */
  { 121, "iso-10646-ucs-basic",                               0,  no }, /* IANA */
  { 121, "csunicodeascii",                                    0,  no }, /* IANA */
  { 122, "iso-10646-unicode-latin1",                          0,  no }, /* IANA */
  { 122, "iso-10646",                                         0,  no }, /* IANA */
  { 122, "csunicodelatin1",                                   0,  no }, /* IANA */
  { 123, "iso-10646-utf-1",                                   0,  no }, /* IANA */
  { 123, "csiso10646utf1",                                    0,  no }, /* IANA */
  { 124, "iso-2022-cn",                                       0, yes }, /* IANA */
  { 125, "iso-2022-cn-ext",                                   0, yes }, /* IANA */
  { 126, "iso-2022-jp",                                   50220, yes }, /* IANA */
  { 126, "csiso2022jp",                                   50220, yes }, /* IANA */
  { 127, "iso-2022-jp-2",                                     0, yes }, /* IANA */
  { 127, "csiso2022jp2",                                      0, yes }, /* IANA */
  { 128, "iso-2022-kr",                                   50225, yes }, /* IANA */
  { 128, "csiso2022kr",                                   50225, yes }, /* IANA */
  { 129, "iso-8859-1-windows-3.0-latin-1",                    0,  no }, /* IANA */
  { 129, "cswindows30latin1",                                 0,  no }, /* IANA */
  { 130, "iso-8859-1-windows-3.1-latin-1",                    0,  no }, /* IANA */
  { 130, "cswindows31latin1",                                 0,  no }, /* IANA */
  { 131, "iso-8859-10",                                       0,  no }, /* IANA */
  { 131, "iso-ir-157",                                        0,  no }, /* IANA */
  { 131, "l6",                                                0,  no }, /* IANA */
  { 131, "iso_8859-10:1992",                                  0,  no }, /* IANA */
  { 131, "csisolatin6",                                       0,  no }, /* IANA */
  { 131, "latin6",                                            0,  no }, /* IANA */
  { 132, "iso-8859-13",                                   28603,  no }, /* IANA */
  { 133, "iso-8859-14",                                       0,  no }, /* IANA */
  { 133, "iso-ir-199",                                        0,  no }, /* IANA */
  { 133, "iso-celtic",                                        0,  no }, /* IANA */
  { 133, "iso_8859-14:1998",                                  0,  no }, /* IANA */
  { 133, "iso_8859-14",                                       0,  no }, /* IANA */
  { 133, "latin8",                                            0,  no }, /* IANA */
  { 133, "l8",                                                0,  no }, /* IANA */
  { 134, "iso-8859-15",                                   28605,  no }, /* IANA */
  { 134, "iso_8859-15",                                   28605,  no }, /* IANA */
  { 134, "latin-9",                                       28605,  no }, /* IANA */
  { 134, "l9",                                            28605,  no }, /* MICROSOFT */
  { 134, "latin9",                                        28605,  no }, /* MICROSOFT */
  { 135, "iso-8859-16",                                       0,  no }, /* IANA */
  { 135, "iso-ir-226",                                        0,  no }, /* IANA */
  { 135, "iso_8859-16:2001",                                  0,  no }, /* IANA */
  { 135, "iso_8859-16",                                       0,  no }, /* IANA */
  { 135, "latin10",                                           0,  no }, /* IANA */
  { 135, "l10",                                               0,  no }, /* IANA */
  { 136, "iso-8859-2-windows-latin-2",                        0,  no }, /* IANA */
  { 136, "cswindows31latin2",                                 0,  no }, /* IANA */
  { 137, "iso-8859-9-windows-latin-5",                        0,  no }, /* IANA */
  { 137, "cswindows31latin5",                                 0,  no }, /* IANA */
  { 138, "iso-ir-90",                                         0,  no }, /* IANA */
  { 138, "csiso90",                                           0,  no }, /* IANA */
  { 139, "iso-unicode-ibm-1261",                              0,  no }, /* IANA */
  { 139, "csunicodeibm1261",                                  0,  no }, /* IANA */
  { 140, "iso-unicode-ibm-1264",                              0,  no }, /* IANA */
  { 140, "csunicodeibm1264",                                  0,  no }, /* IANA */
  { 141, "iso-unicode-ibm-1265",                              0,  no }, /* IANA */
  { 141, "csunicodeibm1265",                                  0,  no }, /* IANA */
  { 142, "iso-unicode-ibm-1268",                              0,  no }, /* IANA */
  { 142, "csunicodeibm1268",                                  0,  no }, /* IANA */
  { 143, "iso-unicode-ibm-1276",                              0,  no }, /* IANA */
  { 143, "csunicodeibm1276",                                  0,  no }, /* IANA */
  { 144, "iso-ir-155",                                        0,  no }, /* IANA */
  { 144, "iso_10367-box",                                     0,  no }, /* IANA */
  { 144, "csiso10367box",                                     0,  no }, /* IANA */
  { 145, "iso-ir-98",                                         0,  no }, /* IANA */
  { 145, "iso_2033-1983",                                     0,  no }, /* IANA */
  { 145, "e13b",                                              0,  no }, /* IANA */
  { 145, "csiso2033",                                         0,  no }, /* IANA */
  { 146, "iso-ir-37",                                         0,  no }, /* IANA */
  { 146, "iso_5427",                                          0,  no }, /* IANA */
  { 146, "csiso5427cyrillic",                                 0,  no }, /* IANA */
  { 147, "iso-ir-54",                                         0,  no }, /* IANA */
  { 147, "iso_5427:1981",                                     0,  no }, /* IANA */
  { 147, "iso5427cyrillic1981",                               0,  no }, /* IANA */
  { 148, "iso-ir-55",                                         0,  no }, /* IANA */
  { 148, "iso_5428:1980",                                     0,  no }, /* IANA */
  { 148, "csiso5428greek",                                    0,  no }, /* IANA */
  { 149, "iso_646.basic:1983",                                0,  no }, /* IANA */
  { 149, "ref",                                               0,  no }, /* IANA */
  { 149, "csiso646basic1983",                                 0,  no }, /* IANA */
  { 150, "iso-ir-2",                                      20105,  no }, /* IANA */
  { 150, "iso_646.irv:1983",                              20105,  no }, /* IANA */
  { 150, "irv",                                           20105,  no }, /* IANA */
  { 150, "csiso2intlrefversion",                          20105,  no }, /* IANA */
  { 150, "x-ia5",                                         20105,  no }, /* MICROSOFT */
  { 151, "iso-ir-152",                                        0,  no }, /* IANA */
  { 151, "iso_6937-2-25",                                     0,  no }, /* IANA */
  { 151, "csiso6937add",                                      0,  no }, /* IANA */
  { 152, "iso-ir-142",                                        0,  no }, /* IANA */
  { 152, "iso_6937-2-add",                                    0,  no }, /* IANA */
  { 152, "csisotextcomm",                                     0,  no }, /* IANA */
  { 153, "iso-8859-1",                                    28591,  no }, /* IANA */
  { 153, "iso-ir-100",                                    28591,  no }, /* IANA */
  { 153, "iso_8859-1:1987",                               28591,  no }, /* IANA */
  { 153, "iso_8859-1",                                    28591,  no }, /* IANA */
  { 153, "latin1",                                        28591,  no }, /* IANA */
  { 153, "l1",                                            28591,  no }, /* IANA */
  { 153, "ibm819",                                        28591,  no }, /* IANA */
  { 153, "cp819",                                         28591,  no }, /* IANA */
  { 153, "csisolatin1",                                   28591,  no }, /* IANA */
  { 153, "iso8859-1",                                     28591,  no }, /* MICROSOFT */
  { 154, "iso-8859-2",                                    28592,  no }, /* IANA */
  { 154, "iso-ir-101",                                    28592,  no }, /* IANA */
  { 154, "iso_8859-2:1987",                               28592,  no }, /* IANA */
  { 154, "iso_8859-2",                                    28592,  no }, /* IANA */
  { 154, "latin2",                                        28592,  no }, /* IANA */
  { 154, "l2",                                            28592,  no }, /* IANA */
  { 154, "csisolatin2",                                   28592,  no }, /* IANA */
  { 154, "iso8859-2",                                     28592,  no }, /* MICROSOFT */
  { 155, "iso-8859-3",                                    28593,  no }, /* IANA */
  { 155, "iso-ir-109",                                    28593,  no }, /* IANA */
  { 155, "iso_8859-3:1988",                               28593,  no }, /* IANA */
  { 155, "iso_8859-3",                                    28593,  no }, /* IANA */
  { 155, "latin3",                                        28593,  no }, /* IANA */
  { 155, "l3",                                            28593,  no }, /* IANA */
  { 155, "csisolatin3",                                   28593,  no }, /* IANA */
  { 156, "iso-8859-4",                                    28594,  no }, /* IANA */
  { 156, "iso-ir-110",                                    28594,  no }, /* IANA */
  { 156, "iso_8859-4:1988",                               28594,  no }, /* IANA */
  { 156, "iso_8859-4",                                    28594,  no }, /* IANA */
  { 156, "latin4",                                        28594,  no }, /* IANA */
  { 156, "l4",                                            28594,  no }, /* IANA */
  { 156, "csisolatin4",                                   28594,  no }, /* IANA */
  { 157, "iso-8859-5",                                    28595,  no }, /* IANA */
  { 157, "iso-ir-144",                                    28595,  no }, /* IANA */
  { 157, "iso_8859-5:1988",                               28595,  no }, /* IANA */
  { 157, "iso_8859-5",                                    28595,  no }, /* IANA */
  { 157, "cyrillic",                                      28595,  no }, /* IANA */
  { 157, "csisolatincyrillic",                            28595,  no }, /* IANA */
  { 158, "iso-8859-6-e",                                      0,  no }, /* IANA */
  { 158, "iso_8859-6-e",                                      0,  no }, /* IANA */
  { 158, "csiso88596e",                                       0,  no }, /* IANA */
  { 159, "iso-8859-6-i",                                      0,  no }, /* IANA */
  { 159, "iso_8859-6-i",                                      0,  no }, /* IANA */
  { 159, "csiso88596i",                                       0,  no }, /* IANA */
  { 160, "iso-8859-6",                                    28596,  no }, /* IANA */
  { 160, "iso-ir-127",                                    28596,  no }, /* IANA */
  { 160, "iso_8859-6:1987",                               28596,  no }, /* IANA */
  { 160, "iso_8859-6",                                    28596,  no }, /* IANA */
  { 160, "ecma-114",                                      28596,  no }, /* IANA */
  { 160, "asmo-708",                                      28596,  no }, /* IANA */
  { 160, "arabic",                                        28596,  no }, /* IANA */
  { 160, "csisolatinarabic",                              28596,  no }, /* IANA */
  { 161, "iso-8859-7",                                    28597,  no }, /* IANA */
  { 161, "iso-ir-126",                                    28597,  no }, /* IANA */
  { 161, "iso_8859-7:1987",                               28597,  no }, /* IANA */
  { 161, "iso_8859-7",                                    28597,  no }, /* IANA */
  { 161, "elot_928",                                      28597,  no }, /* IANA */
  { 161, "ecma-118",                                      28597,  no }, /* IANA */
  { 161, "greek",                                         28597,  no }, /* IANA */
  { 161, "greek8",                                        28597,  no }, /* IANA */
  { 161, "csisolatingreek",                               28597,  no }, /* IANA */
  { 162, "iso-8859-8-e",                                      0,  no }, /* IANA */
  { 162, "iso_8859-8-e",                                      0,  no }, /* IANA */
  { 162, "csiso88598e",                                       0,  no }, /* IANA */
  { 163, "iso-8859-8-i",                                  38598,  no }, /* IANA */
  { 163, "iso_8859-8-i",                                  38598,  no }, /* IANA */
  { 163, "csiso88598i",                                   38598,  no }, /* IANA */
  { 164, "iso-8859-8",                                    28598,  no }, /* IANA */
  { 164, "iso-ir-138",                                    28598,  no }, /* IANA */
  { 164, "iso_8859-8:1988",                               28598,  no }, /* IANA */
  { 164, "iso_8859-8",                                    28598,  no }, /* IANA */
  { 164, "hebrew",                                        28598,  no }, /* IANA */
  { 164, "csisolatinhebrew",                              28598,  no }, /* IANA */
  { 164, "logical",                                       28598,  no }, /* MICROSOFT */
  { 164, "visual",                                        28598,  no }, /* MICROSOFT */
  { 165, "iso-8859-9",                                    28599,  no }, /* IANA */
  { 165, "iso-ir-148",                                    28599,  no }, /* IANA */
  { 165, "iso_8859-9:1989",                               28599,  no }, /* IANA */
  { 165, "iso_8859-9",                                    28599,  no }, /* IANA */
  { 165, "latin5",                                        28599,  no }, /* IANA */
  { 165, "l5",                                            28599,  no }, /* IANA */
  { 165, "csisolatin5",                                   28599,  no }, /* IANA */
  { 166, "iso-ir-154",                                        0,  no }, /* IANA */
  { 166, "iso_8859-supp",                                     0,  no }, /* IANA */
  { 166, "latin1-2-5",                                        0,  no }, /* IANA */
  { 166, "csiso8859supp",                                     0,  no }, /* IANA */
  { 167, "iso-ir-15",                                         0,  no }, /* IANA */
  { 167, "it",                                                0,  no }, /* IANA */
  { 167, "iso646-it",                                         0,  no }, /* IANA */
  { 167, "csiso15italian",                                    0,  no }, /* IANA */
  { 168, "iso-ir-13",                                         0,  no }, /* IANA */
  { 168, "jis_c6220-1969-jp",                                 0,  no }, /* IANA */
  { 168, "jis_c6220-1969",                                    0,  no }, /* IANA */
  { 168, "katakana",                                          0,  no }, /* IANA */
  { 168, "x0201-7",                                           0,  no }, /* IANA */
  { 168, "csiso13jisc6220jp",                                 0,  no }, /* IANA */
  { 169, "iso-ir-14",                                         0,  no }, /* IANA */
  { 169, "jis_c6220-1969-ro",                                 0,  no }, /* IANA */
  { 169, "jp",                                                0,  no }, /* IANA */
  { 169, "iso646-jp",                                         0,  no }, /* IANA */
  { 169, "csiso14jisc6220ro",                                 0,  no }, /* IANA */
  { 170, "iso-ir-42",                                         0,  no }, /* IANA */
  { 170, "jis_c6226-1978",                                    0,  no }, /* IANA */
  { 170, "csiso42jisc62261978",                               0,  no }, /* IANA */
  { 171, "iso-ir-87",                                         0,  no }, /* IANA */
  { 171, "jis_c6226-1983",                                    0,  no }, /* IANA */
  { 171, "x0208",                                             0,  no }, /* IANA */
  { 171, "jis_x0208-1983",                                    0,  no }, /* IANA */
  { 171, "csiso87jisx0208",                                   0,  no }, /* IANA */
  { 172, "iso-ir-91",                                         0,  no }, /* IANA */
  { 172, "jis_c6229-1984-a",                                  0,  no }, /* IANA */
  { 172, "jp-ocr-a",                                          0,  no }, /* IANA */
  { 172, "csiso91jisc62291984a",                              0,  no }, /* IANA */
  { 173, "iso-ir-92",                                         0,  no }, /* IANA */
  { 173, "jis_c6229-1984-b",                                  0,  no }, /* IANA */
  { 173, "iso646-jp-ocr-b",                                   0,  no }, /* IANA */
  { 173, "jp-ocr-b",                                          0,  no }, /* IANA */
  { 173, "csiso92jisc62991984b",                              0,  no }, /* IANA */
  { 174, "iso-ir-93",                                         0,  no }, /* IANA */
  { 174, "jis_c6229-1984-b-add",                              0,  no }, /* IANA */
  { 174, "jp-ocr-b-add",                                      0,  no }, /* IANA */
  { 174, "csiso93jis62291984badd",                            0,  no }, /* IANA */
  { 175, "iso-ir-94",                                         0,  no }, /* IANA */
  { 175, "jis_c6229-1984-hand",                               0,  no }, /* IANA */
  { 175, "jp-ocr-hand",                                       0,  no }, /* IANA */
  { 175, "csiso94jis62291984hand",                            0,  no }, /* IANA */
  { 176, "iso-ir-95",                                         0,  no }, /* IANA */
  { 176, "jis_c6229-1984-hand-add",                           0,  no }, /* IANA */
  { 176, "jp-ocr-hand-add",                                   0,  no }, /* IANA */
  { 176, "csiso95jis62291984handadd",                         0,  no }, /* IANA */
  { 177, "iso-ir-96",                                         0,  no }, /* IANA */
  { 177, "jis_c6229-1984-kana",                               0,  no }, /* IANA */
  { 177, "csiso96jisc62291984kana",                           0,  no }, /* IANA */
  { 178, "jis_encoding",                                      0,  no }, /* IANA */
  { 178, "csjisencoding",                                     0,  no }, /* IANA */
  { 179, "jis_x0201",                                         0,  no }, /* IANA */
  { 179, "x0201",                                             0,  no }, /* IANA */
  { 179, "cshalfwidthkatakana",                               0,  no }, /* IANA */
  { 180, "iso-ir-159",                                        0,  no }, /* IANA */
  { 180, "jis_x0212-1990",                                    0,  no }, /* IANA */
  { 180, "x0212",                                             0,  no }, /* IANA */
  { 180, "csiso159jisx02121990",                              0,  no }, /* IANA */
  { 181, "iso-ir-141",                                        0,  no }, /* IANA */
  { 181, "jus_i.b1.002",                                      0,  no }, /* IANA */
  { 181, "iso646-yu",                                         0,  no }, /* IANA */
  { 181, "js",                                                0,  no }, /* IANA */
  { 181, "yu",                                                0,  no }, /* IANA */
  { 181, "csiso141jusib1002",                                 0,  no }, /* IANA */
  { 182, "iso-ir-147",                                        0,  no }, /* IANA */
  { 182, "jus_i.b1.003-mac",                                  0,  no }, /* IANA */
  { 182, "macedonian",                                        0,  no }, /* IANA */
  { 182, "csiso147macedonian",                                0,  no }, /* IANA */
  { 183, "iso-ir-146",                                        0,  no }, /* IANA */
  { 183, "jus_i.b1.003-serb",                                 0,  no }, /* IANA */
  { 183, "serbian",                                           0,  no }, /* IANA */
  { 183, "csiso146serbian",                                   0,  no }, /* IANA */
  { 184, "koi8-r",                                        20866,  no }, /* IANA */
  { 184, "cskoi8r",                                       20866,  no }, /* IANA */
  { 184, "koi8",                                          20866,  no }, /* MICROSOFT */
  { 184, "koi",                                           20866,  no }, /* MICROSOFT */
  { 184, "koi8r",                                         20866,  no }, /* MICROSOFT */
  { 185, "koi8-u",                                        21866,  no }, /* IANA */
  { 185, "koi8-ru",                                       21866,  no }, /* MICROSOFT */
  { 186, "iso-ir-149",                                      949,  no }, /* IANA */
  { 186, "ks_c_5601-1987",                                  949,  no }, /* IANA */
  { 186, "ks_c_5601-1989",                                  949,  no }, /* IANA */
  { 186, "ksc_5601",                                        949,  no }, /* IANA */
  { 186, "korean",                                          949,  no }, /* IANA */
  { 186, "csksc56011987",                                   949,  no }, /* IANA */
  { 186, "ks_c_5601_1987",                                  949,  no }, /* MICROSOFT */
  { 186, "ksc5601",                                         949,  no }, /* MICROSOFT */
  { 186, "ks_c_5601",                                       949,  no }, /* MICROSOFT */
  { 187, "ksc5636",                                           0,  no }, /* IANA */
  { 187, "iso646-kr",                                         0,  no }, /* IANA */
  { 187, "csksc5636",                                         0,  no }, /* IANA */
  { 188, "iso-ir-19",                                         0,  no }, /* IANA */
  { 188, "latin-greek",                                       0,  no }, /* IANA */
  { 188, "csiso19latingreek",                                 0,  no }, /* IANA */
  { 189, "iso-ir-27",                                         0,  no }, /* IANA */
  { 189, "latin-greek-1",                                     0,  no }, /* IANA */
  { 189, "csiso27latingreek1",                                0,  no }, /* IANA */
  { 190, "iso-ir-158",                                        0,  no }, /* IANA */
  { 190, "latin-lap",                                         0,  no }, /* IANA */
  { 190, "lap",                                               0,  no }, /* IANA */
  { 190, "csiso158lap",                                       0,  no }, /* IANA */
  { 191, "macintosh",                                     10000,  no }, /* IANA */
  { 191, "mac",                                           10000,  no }, /* IANA */
  { 191, "csmacintosh",                                   10000,  no }, /* IANA */
  { 192, "microsoft-publishing",                              0,  no }, /* IANA */
  { 192, "csmicrosoftpublishing",                             0,  no }, /* IANA */
  { 193, "mnem",                                              0,  no }, /* IANA */
  { 193, "csmnem",                                            0,  no }, /* IANA */
  { 194, "mnemonic",                                          0,  no }, /* IANA */
  { 194, "csmnemonic",                                        0,  no }, /* IANA */
  { 195, "iso-ir-86",                                         0,  no }, /* IANA */
  { 195, "msz_7795.3",                                        0,  no }, /* IANA */
  { 195, "iso646-hu",                                         0,  no }, /* IANA */
  { 195, "hu",                                                0,  no }, /* IANA */
  { 195, "csiso86hungarian",                                  0,  no }, /* IANA */
  { 196, "iso-ir-9-1",                                        0,  no }, /* IANA */
  { 196, "nats-dano",                                         0,  no }, /* IANA */
  { 196, "csnatsdano",                                        0,  no }, /* IANA */
  { 197, "iso-ir-9-2",                                        0,  no }, /* IANA */
  { 197, "nats-dano-add",                                     0,  no }, /* IANA */
  { 197, "csnatsdanoadd",                                     0,  no }, /* IANA */
  { 198, "iso-ir-8-1",                                        0,  no }, /* IANA */
  { 198, "nats-sefi",                                         0,  no }, /* IANA */
  { 198, "csnatssefi",                                        0,  no }, /* IANA */
  { 199, "iso-ir-8-2",                                        0,  no }, /* IANA */
  { 199, "nats-sefi-add",                                     0,  no }, /* IANA */
  { 199, "csnatssefiadd",                                     0,  no }, /* IANA */
  { 200, "iso-ir-151",                                        0,  no }, /* IANA */
  { 200, "nc_nc00-10:81",                                     0,  no }, /* IANA */
  { 200, "cuba",                                              0,  no }, /* IANA */
  { 200, "iso646-cu",                                         0,  no }, /* IANA */
  { 200, "csiso151cuba",                                      0,  no }, /* IANA */
  { 201, "iso-ir-69",                                         0,  no }, /* IANA */
  { 201, "nf_z_62-010",                                       0,  no }, /* IANA */
  { 201, "iso646-fr",                                         0,  no }, /* IANA */
  { 201, "fr",                                                0,  no }, /* IANA */
  { 201, "csiso69french",                                     0,  no }, /* IANA */
  { 202, "iso-ir-25",                                         0,  no }, /* IANA */
  { 202, "nf_z_62-010_(1973)",                                0,  no }, /* IANA */
  { 202, "iso646-fr1",                                        0,  no }, /* IANA */
  { 202, "csiso25french",                                     0,  no }, /* IANA */
  { 203, "iso-ir-60",                                     20108,  no }, /* IANA */
  { 203, "ns_4551-1",                                     20108,  no }, /* IANA */
  { 203, "iso646-no",                                     20108,  no }, /* IANA */
  { 203, "no",                                            20108,  no }, /* IANA */
  { 203, "csiso60danishnorwegian",                        20108,  no }, /* IANA */
  { 203, "csiso60norwegian1",                             20108,  no }, /* IANA */
  { 203, "x-ia5-norwegian",                               20108,  no }, /* MICROSOFT */
  { 204, "iso-ir-61",                                         0,  no }, /* IANA */
  { 204, "ns_4551-2",                                         0,  no }, /* IANA */
  { 204, "iso646-no2",                                        0,  no }, /* IANA */
  { 204, "no2",                                               0,  no }, /* IANA */
  { 204, "csiso61norwegian2",                                 0,  no }, /* IANA */
  { 205, "pc8-danish-norwegian",                              0,  no }, /* IANA */
  { 205, "cspc8danishnorwegian",                              0,  no }, /* IANA */
  { 206, "pc8-turkish",                                       0,  no }, /* IANA */
  { 206, "cspc8turkish",                                      0,  no }, /* IANA */
  { 207, "iso-ir-16",                                         0,  no }, /* IANA */
  { 207, "pt",                                                0,  no }, /* IANA */
  { 207, "iso646-pt",                                         0,  no }, /* IANA */
  { 207, "csiso16portuguese",                                 0,  no }, /* IANA */
  { 208, "iso-ir-84",                                         0,  no }, /* IANA */
  { 208, "pt2",                                               0,  no }, /* IANA */
  { 208, "iso646-pt2",                                        0,  no }, /* IANA */
  { 208, "csiso84portuguese2",                                0,  no }, /* IANA */
  { 209, "ptcp154",                                           0,  no }, /* IANA */
  { 209, "csptcp154",                                         0,  no }, /* IANA */
  { 209, "pt154",                                             0,  no }, /* IANA */
  { 209, "cp154",                                             0,  no }, /* IANA */
  { 209, "cyrillic-asian",                                    0,  no }, /* IANA */
  { 210, "scsu",                                              0,  no }, /* IANA */
  { 211, "iso-ir-10",                                     20107,  no }, /* IANA */
  { 211, "sen_850200_b",                                  20107,  no }, /* IANA */
  { 211, "fi",                                            20107,  no }, /* IANA */
  { 211, "iso646-fi",                                     20107,  no }, /* IANA */
  { 211, "iso646-se",                                     20107,  no }, /* IANA */
  { 211, "se",                                            20107,  no }, /* IANA */
  { 211, "csiso10swedish",                                20107,  no }, /* IANA */
  { 211, "x-ia5-swedish",                                 20107,  no }, /* MICROSOFT */
  { 212, "iso-ir-11",                                         0,  no }, /* IANA */
  { 212, "sen_850200_c",                                      0,  no }, /* IANA */
  { 212, "iso646-se2",                                        0,  no }, /* IANA */
  { 212, "se2",                                               0,  no }, /* IANA */
  { 212, "csiso11swedishfornames",                            0,  no }, /* IANA */
  { 213, "shift_jis",                                       932,  no }, /* IANA */
  { 213, "ms_kanji",                                        932,  no }, /* IANA */
  { 213, "csshiftjis",                                      932,  no }, /* IANA */
  { 213, "shift-jis",                                       932,  no }, /* MICROSOFT */
  { 213, "x-ms-cp932",                                      932,  no }, /* MICROSOFT */
  { 213, "x-sjis",                                          932,  no }, /* MICROSOFT */
  { 214, "iso-ir-128",                                        0,  no }, /* IANA */
  { 214, "t.101-g2",                                          0,  no }, /* IANA */
  { 214, "csiso128t101g2",                                    0,  no }, /* IANA */
  { 215, "iso-ir-102",                                        0,  no }, /* IANA */
  { 215, "t.61-7bit",                                         0,  no }, /* IANA */
  { 215, "csiso102t617bit",                                   0,  no }, /* IANA */
  { 216, "iso-ir-103",                                        0,  no }, /* IANA */
  { 216, "t.61-8bit",                                         0,  no }, /* IANA */
  { 216, "t.61",                                              0,  no }, /* IANA */
  { 216, "csiso103t618bit",                                   0,  no }, /* IANA */
  { 217, "tis-620",                                         874,  no }, /* IANA */
  { 217, "windows-874",                                     874,  no }, /* MICROSOFT */
  { 217, "iso-8859-11",                                     874,  no }, /* MICROSOFT */
  { 217, "dos-874",                                         874,  no }, /* MICROSOFT */
  { 218, "unicode-1-1",                                       0,  no }, /* IANA */
  { 218, "csunicode11",                                       0,  no }, /* IANA */
  { 219, "unicode-1-1-utf-7",                             65000, yes }, /* IANA */
  { 219, "csunicode11utf7",                               65000, yes }, /* IANA */
  { 219, "x-unicode-2-0-utf-7",                           65000, yes }, /* MICROSOFT */
  { 220, "unknown-8bit",                                      0,  no }, /* IANA */
  { 220, "csunknown8bit",                                     0,  no }, /* IANA */
  { 221, "us-dk",                                             0,  no }, /* IANA */
  { 221, "csusdk",                                            0,  no }, /* IANA */
  { 222, "utf-16",                                         1200,  no }, /* IANA */
  { 222, "unicode",                                        1200,  no }, /* MICROSOFT */
  { 223, "utf-16be",                                       1201,  no }, /* IANA */
  { 223, "unicodefffe",                                    1201,  no }, /* MICROSOFT */
  { 224, "utf-16le",                                       1200,  no }, /* IANA */
  { 224, "unicode",                                        1200,  no }, /* MICROSOFT */
  { 225, "utf-32",                                            0,  no }, /* IANA */
  { 226, "utf-32be",                                          0,  no }, /* IANA */
  { 227, "utf-32le",                                          0,  no }, /* IANA */
  { 228, "utf-7",                                         65000, yes }, /* IANA */
  { 228, "x-unicode-2-0-utf-7",                           65000, yes }, /* MICROSOFT */
  { 229, "utf-8",                                         65001,  no }, /* IANA */
  { 229, "unicode-2-0-utf-8",                             65001,  no }, /* MICROSOFT */
  { 229, "unicode-1-1-utf-8",                             65001,  no }, /* MICROSOFT */
  { 229, "x-unicode-2-0-utf-8",                           65001,  no }, /* MICROSOFT */
  { 230, "ventura-international",                             0,  no }, /* IANA */
  { 230, "csventurainternational",                            0,  no }, /* IANA */
  { 231, "ventura-math",                                      0,  no }, /* IANA */
  { 231, "csventuramath",                                     0,  no }, /* IANA */
  { 232, "ventura-us",                                        0,  no }, /* IANA */
  { 232, "csventuraus",                                       0,  no }, /* IANA */
  { 233, "iso-ir-70",                                         0,  no }, /* IANA */
  { 233, "videotex-suppl",                                    0,  no }, /* IANA */
  { 233, "csiso70videotexsupp1",                              0,  no }, /* IANA */
  { 234, "viqr",                                              0,  no }, /* IANA */
  { 234, "csviqr",                                            0,  no }, /* IANA */
  { 235, "viscii",                                            0,  no }, /* IANA */
  { 235, "csviscii",                                          0,  no }, /* IANA */
  { 236, "windows-1250",                                   1250,  no }, /* IANA */
  { 236, "x-cp1250",                                       1250,  no }, /* MICROSOFT */
  { 237, "windows-1251",                                   1251,  no }, /* IANA */
  { 237, "x-cp1251",                                       1251,  no }, /* MICROSOFT */
  { 238, "windows-1252",                                   1252,  no }, /* IANA */
  { 238, "x-ansi",                                         1252,  no }, /* MICROSOFT */
  { 239, "windows-1253",                                   1253,  no }, /* IANA */
  { 240, "windows-1254",                                   1254,  no }, /* IANA */
  { 241, "windows-1255",                                   1255,  no }, /* IANA */
  { 242, "windows-1256",                                   1256,  no }, /* IANA */
  { 242, "cp1256",                                         1256,  no }, /* MICROSOFT */
  { 243, "windows-1257",                                   1257,  no }, /* IANA */
  { 244, "windows-1258",                                   1258,  no }, /* IANA */
  { 245, "windows-31j",                                     932,  no }, /* IANA */
  { 245, "cswindows31j",                                    932,  no }, /* IANA */
  { 245, "shift-jis",                                       932,  no }, /* MICROSOFT */
  { 245, "x-ms-cp932",                                      932,  no }, /* MICROSOFT */
  { 245, "x-sjis",                                          932,  no }, /* MICROSOFT */
  { 246, "dos-720",                                         720,  no }, /* MICROSOFT */
  { 247, "euc-cn",                                        51936,  no }, /* MICROSOFT */
  { 248, "ibm737",                                          737,  no }, /* MICROSOFT */
  { 249, "johab",                                          1361,  no }, /* MICROSOFT */
  { 250, "x-chinese-cns",                                 20000,  no }, /* MICROSOFT */
  { 251, "x-chinese-eten",                                20002,  no }, /* MICROSOFT */
  { 252, "x-ebcdic-cyrillicserbianbulgarian",             21025,  no }, /* MICROSOFT */
  { 253, "x-ebcdic-greekmodern",                            875,  no }, /* MICROSOFT */
  { 254, "x-ebcdic-japaneseandjapaneselatin",             50939,  no }, /* MICROSOFT */
  { 255, "x-ebcdic-japaneseandkana",                      50930,  no }, /* MICROSOFT */
  { 256, "x-ebcdic-japaneseanduscanada",                  50931,  no }, /* MICROSOFT */
  { 257, "x-ebcdic-koreanandkoreanextended",              50933,  no }, /* MICROSOFT */
  { 258, "x-ebcdic-koreanextended",                       20833,  no }, /* MICROSOFT */
  { 259, "x-ebcdic-simplifiedchinese",                    50935,  no }, /* MICROSOFT */
  { 260, "x-ebcdic-traditionalchinese",                   50937,  no }, /* MICROSOFT */
  { 261, "x-euc-cn",                                      51936,  no }, /* MICROSOFT */
  { 262, "x-europa",                                      29001,  no }, /* MICROSOFT */
  { 263, "x-iscii-as",                                    57006,  no }, /* MICROSOFT */
  { 264, "x-iscii-be",                                    57003,  no }, /* MICROSOFT */
  { 265, "x-iscii-de",                                    57002,  no }, /* MICROSOFT */
  { 266, "x-iscii-gu",                                    57010,  no }, /* MICROSOFT */
  { 267, "x-iscii-ka",                                    57008,  no }, /* MICROSOFT */
  { 268, "x-iscii-ma",                                    57009,  no }, /* MICROSOFT */
  { 269, "x-iscii-or",                                    57007,  no }, /* MICROSOFT */
  { 270, "x-iscii-pa",                                    57011,  no }, /* MICROSOFT */
  { 271, "x-iscii-ta",                                    57004,  no }, /* MICROSOFT */
  { 272, "x-iscii-te",                                    57005,  no }, /* MICROSOFT */
  { 273, "x-mac-arabic",                                  10004,  no }, /* MICROSOFT */
  { 274, "x-mac-ce",                                      10029,  no }, /* MICROSOFT */
  { 275, "x-mac-chinesesimp",                             10008,  no }, /* MICROSOFT */
  { 276, "x-mac-chinesetrad",                             10002,  no }, /* MICROSOFT */
  { 277, "x-mac-cyrillic",                                10007,  no }, /* MICROSOFT */
  { 278, "x-mac-greek",                                   10006,  no }, /* MICROSOFT */
  { 279, "x-mac-hebrew",                                  10005,  no }, /* MICROSOFT */
  { 280, "x-mac-icelandic",                               10079,  no }, /* MICROSOFT */
  { 281, "x-mac-japanese",                                10001,  no }, /* MICROSOFT */
  { 282, "x-mac-korean",                                  10003,  no }, /* MICROSOFT */
  { 283, "x-mac-turkish",                                 10081,  no }, /* MICROSOFT */

  /* final entry */
  {   0, NULL,                                                0,  no }
};

unsigned int TY_(GetEncodingIdFromName)(ctmbstr name)
{
    unsigned int i;

    for (i = 0; charsetInfo[i].id; ++i)
        if (TY_(tmbstrcasecmp)(name, charsetInfo[i].charset) == 0)
            return charsetInfo[i].id;

    return 0;
}

unsigned int TY_(GetEncodingIdFromCodePage)(unsigned int cp)
{
    unsigned int i;

    for (i = 0; charsetInfo[i].id; ++i)
        if (cp == charsetInfo[i].codepage)
            return charsetInfo[i].id;

    return 0;
}

unsigned int TY_(GetEncodingCodePageFromName)(ctmbstr name)
{
    unsigned int i;

    for (i = 0; charsetInfo[i].id; ++i)
        if (TY_(tmbstrcasecmp)(name, charsetInfo[i].charset) == 0)
            return charsetInfo[i].codepage;

    return 0;
}

unsigned int TY_(GetEncodingCodePageFromId)(unsigned int id)
{
    unsigned int i;

    for (i = 0; charsetInfo[i].id; ++i)
        if (id == charsetInfo[i].id)
            return charsetInfo[i].codepage;

    return 0;
}

ctmbstr TY_(GetEncodingNameFromId)(unsigned int id)
{
    unsigned int i;

    for (i = 0; charsetInfo[i].id; ++i)
        if (id == charsetInfo[i].id)
            return charsetInfo[i].charset;

    return NULL;
}

ctmbstr TY_(GetEncodingNameFromCodePage)(unsigned int cp)
{
    unsigned int i;

    for (i = 0; charsetInfo[i].id; ++i)
        if (cp == charsetInfo[i].codepage)
            return charsetInfo[i].charset;

    return NULL;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/*
  clean.c -- clean up misuse of presentation markup

  (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Filters from other formats such as Microsoft Word
  often make excessive use of presentation markup such
  as font tags, B, I, and the align attribute. By applying
  a set of production rules, it is straight forward to
  transform this to use CSS.

  Some rules replace some of the children of an element by
  style properties on the element, e.g.

  <p><b>...</b></p> -> <p style="font-weight: bold">...</p>

  Such rules are applied to the element's content and then
  to the element itself until none of the rules more apply.
  Having applied all the rules to an element, it will have
  a style attribute with one or more properties. 

  Other rules strip the element they apply to, replacing
  it by style properties on the contents, e.g.
  
  <dir><li><p>...</li></dir> -> <p style="margin-left 1em">...
      
  These rules are applied to an element before processing
  its content and replace the current element by the first
  element in the exposed content.

  After applying both sets of rules, you can replace the
  style attribute by a class value and style rule in the
  document head. To support this, an association of styles
  and class names is built.

  A naive approach is to rely on string matching to test
  when two property lists are the same. A better approach
  would be to first sort the properties before matching.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* #include "tidy-int.h" */
/* #include "clean.h" */
/* #include "lexer.h" */
/* #include "parser.h" */
/* #include "attrs.h" */
/* #include "message.h" */
/* #include "tmbstr.h" */
/* #include "utf8.h" */

static Node* CleanNode_clean_c( TidyDocImpl* doc, Node *node );

static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid )
{
    const Dict* dict = TY_(LookupTagDef)( tid );
    TidyDocFree( doc, node->element );
    node->element = TY_(tmbstrdup)( doc->allocator, dict->name );
    node->tag = dict;
}

static void FreeStyleProps(TidyDocImpl* doc, StyleProp *props)
{
    StyleProp *next;

    while (props)
    {
        next = props->next;
        TidyDocFree(doc, props->name);
        TidyDocFree(doc, props->value);
        TidyDocFree(doc, props);
        props = next;
    }
}

static StyleProp *InsertProperty( TidyDocImpl* doc, StyleProp* props, ctmbstr name, ctmbstr value )
{
    StyleProp *first, *prev, *prop;
    int cmp;

    prev = NULL;
    first = props;

    while (props)
    {
        cmp = TY_(tmbstrcmp)(props->name, name);

        if (cmp == 0)
        {
            /* this property is already defined, ignore new value */
            return first;
        }

        if (cmp > 0)
        {
            /* insert before this */

            prop = (StyleProp *)TidyDocAlloc(doc, sizeof(StyleProp));
            prop->name = TY_(tmbstrdup)(doc->allocator, name);
            prop->value = TY_(tmbstrdup)(doc->allocator, value);
            prop->next = props;

            if (prev)
                prev->next = prop;
            else
                first = prop;

            return first;
        }

        prev = props;
        props = props->next;
    }

    prop = (StyleProp *)TidyDocAlloc(doc, sizeof(StyleProp));
    prop->name = TY_(tmbstrdup)(doc->allocator, name);
    prop->value = TY_(tmbstrdup)(doc->allocator, value);
    prop->next = NULL;

    if (prev)
        prev->next = prop;
    else
        first = prop;

    return first;
}

/*
 Create sorted linked list of properties from style string
 It temporarily places nulls in place of ':' and ';' to
 delimit the strings for the property name and value.
 Some systems don't allow you to NULL literal strings,
 so to avoid this, a copy is made first.
*/
static StyleProp* CreateProps( TidyDocImpl* doc, StyleProp* prop, ctmbstr style )
{
    tmbstr name, value = NULL, name_end, value_end, line;
    Bool more;

    line = TY_(tmbstrdup)(doc->allocator, style);
    name = line;

    while (*name)
    {
        while (*name == ' ')
            ++name;

        name_end = name;

        while (*name_end)
        {
            if (*name_end == ':')
            {
                value = name_end + 1;
                break;
            }

            ++name_end;
        }

        if (*name_end != ':')
            break;

        while ( value && *value == ' ')
            ++value;

        value_end = value;
        more = no;

        while (*value_end)
        {
            if (*value_end == ';')
            {
                more = yes;
                break;
            }

            ++value_end;
        }

        *name_end = '\0';
        *value_end = '\0';

        prop = InsertProperty(doc, prop, name, value);
        *name_end = ':';

        if (more)
        {
            *value_end = ';';
            name = value_end + 1;
            continue;
        }

        break;
    }

    TidyDocFree(doc, line);  /* free temporary copy */
    return prop;
}

static tmbstr CreatePropString(TidyDocImpl* doc, StyleProp *props)
{
    tmbstr style, p, s;
    unsigned int len;
    StyleProp *prop;

    /* compute length */

    for (len = 0, prop = props; prop; prop = prop->next)
    {
        len += TY_(tmbstrlen)(prop->name) + 2;
        if (prop->value)
            len += TY_(tmbstrlen)(prop->value) + 2;
    }

    style = (tmbstr) TidyDocAlloc(doc, len+1);
    style[0] = '\0';

    for (p = style, prop = props; prop; prop = prop->next)
    {
        s = prop->name;

        while((*p++ = *s++))
            continue;

        if (prop->value)
        {
            *--p = ':';
            *++p = ' ';
            ++p;

            s = prop->value;
            while((*p++ = *s++))
                continue;
        }
        if (prop->next == NULL)
            break;

        *--p = ';';
        *++p = ' ';
        ++p;
    }

    return style;
}

/*
  create string with merged properties
static tmbstr AddProperty( ctmbstr style, ctmbstr property )
{
    tmbstr line;
    StyleProp *prop;

    prop = CreateProps(doc, NULL, style);
    prop = CreateProps(doc, prop, property);
    line = CreatePropString(doc, prop);
    FreeStyleProps(doc, prop);
    return line;
}
*/

void TY_(FreeStyles)( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    if ( lexer )
    {
        TagStyle *style, *next;
        for ( style = lexer->styles; style; style = next )
        {
            next = style->next;
            TidyDocFree( doc, style->tag );
            TidyDocFree( doc, style->tag_class );
            TidyDocFree( doc, style->properties );
            TidyDocFree( doc, style );
        }
    }
}

static tmbstr GensymClass( TidyDocImpl* doc )
{
    tmbchar buf[512];  /* CSSPrefix is limited to 256 characters */
    ctmbstr pfx = cfgStr(doc, TidyCSSPrefix);
    if ( pfx == NULL || *pfx == 0 )
      pfx = "c";

    TY_(tmbsnprintf)(buf, sizeof(buf), "%s%u", pfx, ++doc->nClassId );
    return TY_(tmbstrdup)(doc->allocator, buf);
}

static ctmbstr FindStyle( TidyDocImpl* doc, ctmbstr tag, ctmbstr properties )
{
    Lexer* lexer = doc->lexer;
    TagStyle* style;

    for (style = lexer->styles; style; style=style->next)
    {
        if (TY_(tmbstrcmp)(style->tag, tag) == 0 &&
            TY_(tmbstrcmp)(style->properties, properties) == 0)
            return style->tag_class;
    }

    style = (TagStyle *)TidyDocAlloc( doc, sizeof(TagStyle) );
    style->tag = TY_(tmbstrdup)(doc->allocator, tag);
    style->tag_class = GensymClass( doc );
    style->properties = TY_(tmbstrdup)( doc->allocator, properties );
    style->next = lexer->styles;
    lexer->styles = style;
    return style->tag_class;
}

/*
 Add class="foo" to node
*/
static void AddClass( TidyDocImpl* doc, Node* node, ctmbstr classname )
{
    AttVal *classattr = TY_(AttrGetById)(node, TidyAttr_CLASS);;

    /*
     if there already is a class attribute
     then append class name after a space.
    */
    if (classattr)
        TY_(AppendToClassAttr)( doc, classattr, classname );
    else /* create new class attribute */
        TY_(AddAttribute)( doc, node, "class", classname );
}

void TY_(AddStyleAsClass)( TidyDocImpl* doc, Node *node, ctmbstr stylevalue )
{
    ctmbstr classname;

    classname = FindStyle( doc, node->element, stylevalue );
    AddClass( doc, node, classname);
}

/*
 Find style attribute in node, and replace it
 by corresponding class attribute. Search for
 class in style dictionary otherwise gensym
 new class and add to dictionary.

 Assumes that node doesn't have a class attribute
*/
static void Style2Rule( TidyDocImpl* doc, Node *node)
{
    AttVal *styleattr, *classattr;
    ctmbstr classname;

    styleattr = TY_(AttrGetById)(node, TidyAttr_STYLE);

    if (styleattr)
    {
        /* fix for http://tidy.sf.net/bug/850215 */
        if (!styleattr->value)
        {
            TY_(RemoveAttribute)(doc, node, styleattr);
            return;
        }

        classname = FindStyle( doc, node->element, styleattr->value );
        classattr = TY_(AttrGetById)(node, TidyAttr_CLASS);

        /*
         if there already is a class attribute
         then append class name after an underscore
        */
        if (classattr)
        {
            TY_(AppendToClassAttr)( doc, classattr, classname );
            TY_(RemoveAttribute)( doc, node, styleattr );
        }
        else /* reuse style attribute for class attribute */
        {
            TidyDocFree(doc, styleattr->attribute);
            TidyDocFree(doc, styleattr->value);
            styleattr->attribute = TY_(tmbstrdup)(doc->allocator, "class");
            styleattr->value = TY_(tmbstrdup)(doc->allocator, classname);
        }
    }
}

static void AddColorRule( Lexer* lexer, ctmbstr selector, ctmbstr color )
{
    if ( selector && color )
    {
        TY_(AddStringLiteral)(lexer, selector);
        TY_(AddStringLiteral)(lexer, " { color: ");
        TY_(AddStringLiteral)(lexer, color);
        TY_(AddStringLiteral)(lexer, " }\n");
    }
}

/*
 move presentation attribs from body to style element

 background="foo" ->  body { background-image: url(foo) }
 bgcolor="foo"    ->  body { background-color: foo }
 text="foo"       ->  body { color: foo }
 link="foo"       ->  :link { color: foo }
 vlink="foo"      ->  :visited { color: foo }
 alink="foo"      ->  :active { color: foo }
*/
static void CleanBodyAttrs( TidyDocImpl* doc, Node* body )
{
    Lexer* lexer  = doc->lexer;
    tmbstr bgurl   = NULL;
    tmbstr bgcolor = NULL;
    tmbstr color   = NULL;
    AttVal* attr;
    
    if (NULL != (attr = TY_(AttrGetById)(body, TidyAttr_BACKGROUND)))
    {
        bgurl = attr->value;
        attr->value = NULL;
        TY_(RemoveAttribute)( doc, body, attr );
    }

    if (NULL != (attr = TY_(AttrGetById)(body, TidyAttr_BGCOLOR)))
    {
        bgcolor = attr->value;
        attr->value = NULL;
        TY_(RemoveAttribute)( doc, body, attr );
    }

    if (NULL != (attr = TY_(AttrGetById)(body, TidyAttr_TEXT)))
    {
        color = attr->value;
        attr->value = NULL;
        TY_(RemoveAttribute)( doc, body, attr );
    }

    if ( bgurl || bgcolor || color )
    {
        TY_(AddStringLiteral)(lexer, " body {\n");
        if (bgurl)
        {
            TY_(AddStringLiteral)(lexer, "  background-image: url(");
            TY_(AddStringLiteral)(lexer, bgurl);
            TY_(AddStringLiteral)(lexer, ");\n");
            TidyDocFree(doc, bgurl);
        }
        if (bgcolor)
        {
            TY_(AddStringLiteral)(lexer, "  background-color: ");
            TY_(AddStringLiteral)(lexer, bgcolor);
            TY_(AddStringLiteral)(lexer, ";\n");
            TidyDocFree(doc, bgcolor);
        }
        if (color)
        {
            TY_(AddStringLiteral)(lexer, "  color: ");
            TY_(AddStringLiteral)(lexer, color);
            TY_(AddStringLiteral)(lexer, ";\n");
            TidyDocFree(doc, color);
        }

        TY_(AddStringLiteral)(lexer, " }\n");
    }

    if (NULL != (attr = TY_(AttrGetById)(body, TidyAttr_LINK)))
    {
        AddColorRule(lexer, " :link", attr->value);
        TY_(RemoveAttribute)( doc, body, attr );
    }

    if (NULL != (attr = TY_(AttrGetById)(body, TidyAttr_VLINK)))
    {
        AddColorRule(lexer, " :visited", attr->value);
        TY_(RemoveAttribute)( doc, body, attr );
    }

    if (NULL != (attr = TY_(AttrGetById)(body, TidyAttr_ALINK)))
    {
        AddColorRule(lexer, " :active", attr->value);
        TY_(RemoveAttribute)( doc, body, attr );
    }
}

static Bool NiceBody( TidyDocImpl* doc )
{
    Node* node = TY_(FindBody)(doc);
    if (node)
    {
        if (TY_(AttrGetById)(node, TidyAttr_BACKGROUND) ||
            TY_(AttrGetById)(node, TidyAttr_BGCOLOR)    ||
            TY_(AttrGetById)(node, TidyAttr_TEXT)       ||
            TY_(AttrGetById)(node, TidyAttr_LINK)       ||
            TY_(AttrGetById)(node, TidyAttr_VLINK)      ||
            TY_(AttrGetById)(node, TidyAttr_ALINK))
        {
            doc->badLayout |= USING_BODY;
            return no;
        }
    }

    return yes;
}

/* create style element using rules from dictionary */
static void CreateStyleElement( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    Node *node, *head, *body;
    TagStyle *style;
    AttVal *av;

    if ( lexer->styles == NULL && NiceBody(doc) )
        return;

    node = TY_(NewNode)( doc->allocator, lexer );
    node->type = StartTag;
    node->implicit = yes;
    node->element = TY_(tmbstrdup)(doc->allocator, "style");
    TY_(FindTag)( doc, node );

    /* insert type attribute */
    av = TY_(NewAttributeEx)( doc, "type", "text/css", '"' );
    TY_(InsertAttributeAtStart)( node, av );

    body = TY_(FindBody)( doc );
    lexer->txtstart = lexer->lexsize;
    if ( body )
        CleanBodyAttrs( doc, body );

    for (style = lexer->styles; style; style = style->next)
    {
        TY_(AddCharToLexer)(lexer, ' ');
        TY_(AddStringLiteral)(lexer, style->tag);
        TY_(AddCharToLexer)(lexer, '.');
        TY_(AddStringLiteral)(lexer, style->tag_class);
        TY_(AddCharToLexer)(lexer, ' ');
        TY_(AddCharToLexer)(lexer, '{');
        TY_(AddStringLiteral)(lexer, style->properties);
        TY_(AddCharToLexer)(lexer, '}');
        TY_(AddCharToLexer)(lexer, '\n');
    }

    lexer->txtend = lexer->lexsize;

    TY_(InsertNodeAtEnd)( node, TY_(TextToken)(lexer) );

    /*
     now insert style element into document head

     doc is root node. search its children for html node
     the head node should be first child of html node
    */
    if ( NULL != (head = TY_(FindHEAD)( doc )) )
        TY_(InsertNodeAtEnd)( head, node );
}


/* ensure bidirectional links are consistent */
void TY_(FixNodeLinks)(Node *node)
{
    Node *child;

    if (node->prev)
        node->prev->next = node;
    else
        node->parent->content = node;

    if (node->next)
        node->next->prev = node;
    else
        node->parent->last = node;

    for (child = node->content; child; child = child->next)
        child->parent = node;
}

/*
 used to strip child of node when
 the node has one and only one child
*/
static void StripOnlyChild(TidyDocImpl* doc, Node *node)
{
    Node *child;

    child = node->content;
    node->content = child->content;
    node->last = child->last;
    child->content = NULL;
    TY_(FreeNode)(doc, child);

    for (child = node->content; child; child = child->next)
        child->parent = node;
}

/*
  used to strip font start and end tags.
  Extricate "element", replace it by its content and delete it.
*/
static void DiscardContainer_clean_c( TidyDocImpl* doc, Node *element, Node **pnode)
{
    if (element->content)
    {
        Node *node, *parent = element->parent;

        element->last->next = element->next;

        if (element->next)
        {
            element->next->prev = element->last;
        }
        else
            parent->last = element->last;

        if (element->prev)
        {
            element->content->prev = element->prev;
            element->prev->next = element->content;
        }
        else
            parent->content = element->content;

        for (node = element->content; node; node = node->next)
            node->parent = parent;

        *pnode = element->content;

        element->next = element->content = NULL;
        TY_(FreeNode)(doc, element);
    }
    else
    {
        *pnode = TY_(DiscardElement)(doc, element);
    }
}

/*
  Create new string that consists of the
  combined style properties in s1 and s2

  To merge property lists, we build a linked
  list of property/values and insert properties
  into the list in order, merging values for
  the same property name.
*/
static tmbstr MergeProperties( TidyDocImpl* doc, ctmbstr s1, ctmbstr s2 )
{
    tmbstr s;
    StyleProp *prop;

    prop = CreateProps(doc, NULL, s1);
    prop = CreateProps(doc, prop, s2);
    s = CreatePropString(doc, prop);
    FreeStyleProps(doc, prop);
    return s;
}

/*
 Add style property to element, creating style
 attribute as needed and adding ; delimiter
*/
void TY_(AddStyleProperty)(TidyDocImpl* doc, Node *node, ctmbstr property )
{
    AttVal *av = TY_(AttrGetById)(node, TidyAttr_STYLE);

    /* if style attribute already exists then insert property */

    if ( av )
    {
        if (av->value != NULL)
        {
            tmbstr s = MergeProperties( doc, av->value, property );
            TidyDocFree( doc, av->value );
            av->value = s;
        }
        else
        {
            av->value = TY_(tmbstrdup)( doc->allocator, property );
        }
    }
    else /* else create new style attribute */
    {
        av = TY_(NewAttributeEx)( doc, "style", property, '"' );
        TY_(InsertAttributeAtStart)( node, av );
    }
}

static void MergeClasses(TidyDocImpl* doc, Node *node, Node *child)
{
    AttVal *av;
    tmbstr s1, s2, names;

    for (s2 = NULL, av = child->attributes; av; av = av->next)
    {
        if (attrIsCLASS(av))
        {
            s2 = av->value;
            break;
        }
    }

    for (s1 = NULL, av = node->attributes; av; av = av->next)
    {
        if (attrIsCLASS(av))
        {
            s1 = av->value;
            break;
        }
    }

    if (s1)
    {
        if (s2)  /* merge class names from both */
        {
            unsigned int l1, l2;
            l1 = TY_(tmbstrlen)(s1);
            l2 = TY_(tmbstrlen)(s2);
            names = (tmbstr) TidyDocAlloc(doc, l1 + l2 + 2);
            TY_(tmbstrcpy)(names, s1);
            names[l1] = ' ';
            TY_(tmbstrcpy)(names+l1+1, s2);
            TidyDocFree(doc, av->value);
            av->value = names;
        }
    }
    else if (s2)  /* copy class names from child */
    {
        av = TY_(NewAttributeEx)( doc, "class", s2, '"' );
        TY_(InsertAttributeAtStart)( node, av );
    }
}

static void MergeStyles(TidyDocImpl* doc, Node *node, Node *child)
{
    AttVal *av;
    tmbstr s1, s2, style;

    /*
       the child may have a class attribute used
       for attaching styles, if so the class name
       needs to be copied to node's class
    */
    MergeClasses(doc, node, child);

    for (s2 = NULL, av = child->attributes; av; av = av->next)
    {
        if (attrIsSTYLE(av))
        {
            s2 = av->value;
            break;
        }
    }

    for (s1 = NULL, av = node->attributes; av; av = av->next)
    {
        if (attrIsSTYLE(av))
        {
            s1 = av->value;
            break;
        }
    }

    if (s1)
    {
        if (s2)  /* merge styles from both */
        {
            style = MergeProperties(doc, s1, s2);
            TidyDocFree(doc, av->value);
            av->value = style;
        }
    }
    else if (s2)  /* copy style of child */
    {
        av = TY_(NewAttributeEx)( doc, "style", s2, '"' );
        TY_(InsertAttributeAtStart)( node, av );
    }
}

static ctmbstr FontSize2Name(ctmbstr size)
{
    static const ctmbstr sizes[7] =
    {
        "60%", "70%", "80%", NULL,
        "120%", "150%", "200%"
    };

    /* increment of 0.8 */
    static const ctmbstr minussizes[] =
    {
        "100%", "80%", "64%", "51%",
        "40%", "32%", "26%"
    };

    /* increment of 1.2 */
    static const ctmbstr plussizes[] =
    {
        "100%", "120%", "144%", "172%",
        "207%", "248%", "298%"
    };

    if (size[0] == '\0')
        return NULL;

    if ('0' <= size[0] && size[0] <= '6')
    {
        int n = size[0] - '0';
        return sizes[n];
    }

    if (size[0] == '-')
    {
        if ('0' <= size[1] && size[1] <= '6')
        {
            int n = size[1] - '0';
            return minussizes[n];
        }
        return "smaller"; /*"70%"; */
    }

    if ('0' <= size[1] && size[1] <= '6')
    {
        int n = size[1] - '0';
        return plussizes[n];
    }

    return "larger"; /* "140%" */
}

static void AddFontFace( TidyDocImpl* doc, Node *node, ctmbstr face )
{
    tmbchar buf[256];
    TY_(tmbsnprintf)(buf, sizeof(buf), "font-family: %s", face );
    TY_(AddStyleProperty)( doc, node, buf );
}

static void AddFontSize( TidyDocImpl* doc, Node* node, ctmbstr size )
{
    ctmbstr value = NULL;

    if (nodeIsP(node))
    {
        if (TY_(tmbstrcmp)(size, "6") == 0)
            value = "h1";
        else if (TY_(tmbstrcmp)(size, "5") == 0)
            value = "h2";
        else if (TY_(tmbstrcmp)(size, "4") == 0)
            value = "h3";

        if (value)
        {
            TidyDocFree(doc, node->element);
            node->element = TY_(tmbstrdup)(doc->allocator, value);
            TY_(FindTag)(doc, node);
            return;
        }
    }

    value = FontSize2Name(size);

    if (value)
    {
        tmbchar buf[64];
        TY_(tmbsnprintf)(buf, sizeof(buf), "font-size: %s", value);
        TY_(AddStyleProperty)( doc, node, buf );
    }
}

static void AddFontColor( TidyDocImpl* doc, Node *node, ctmbstr color)
{
    tmbchar buf[128];
    TY_(tmbsnprintf)(buf, sizeof(buf), "color: %s", color);
    TY_(AddStyleProperty)( doc, node, buf );
}

/* force alignment value to lower case */
static void AddAlign( TidyDocImpl* doc, Node *node, ctmbstr align )
{
    unsigned int i;
    tmbchar buf[128];

    TY_(tmbstrcpy)( buf, "text-align: " );
    for ( i = 12; i < sizeof(buf)/sizeof(buf[0])-1; ++i )
    {
        if ( (buf[i] = (tmbchar)TY_(ToLower)(*align++)) == '\0' )
            break;
    }
    buf[i] = '\0';
    TY_(AddStyleProperty)( doc, node, buf );
}

/*
 add style properties to node corresponding to
 the font face, size and color attributes
*/
static void AddFontStyles( TidyDocImpl* doc, Node *node, AttVal *av)
{
    while (av)
    {
        if (AttrHasValue(av))
        {
            if (attrIsFACE(av))
                AddFontFace( doc, node, av->value );
            else if (attrIsSIZE(av))
                AddFontSize( doc, node, av->value );
            else if (attrIsCOLOR(av))
                AddFontColor( doc, node, av->value );
        }
        av = av->next;
    }
}

/*
    Symptom: <p align=center>
    Action: <p style="text-align: center">
*/
static void TextAlign( TidyDocImpl* doc, Node* node )
{
    AttVal *av, *prev;

    prev = NULL;

    for (av = node->attributes; av; av = av->next)
    {
        if (attrIsALIGN(av))
        {
            if (prev)
                prev->next = av->next;
            else
                node->attributes = av->next;

            if (av->value)
                AddAlign( doc, node, av->value );

            TY_(FreeAttribute)(doc, av);
            break;
        }

        prev = av;
    }
}

/*
    Symptom: <table bgcolor="red">
    Action: <table style="background-color: red">
*/
static void TableBgColor( TidyDocImpl* doc, Node* node )
{
    AttVal* attr;
    tmbchar buf[256];

    if (NULL != (attr = TY_(AttrGetById)(node, TidyAttr_BGCOLOR)))
    {
        TY_(tmbsnprintf)(buf, sizeof(buf), "background-color: %s", attr->value );
        TY_(RemoveAttribute)( doc, node, attr );
        TY_(AddStyleProperty)( doc, node, buf );
    }
}

/*
   The clean up rules use the pnode argument to return the
   next node when the original node has been deleted
*/

/*
    Symptom: <dir> <li> where <li> is only child
    Action: coerce <dir> <li> to <div> with indent.
*/

static Bool Dir2Div( TidyDocImpl* doc, Node *node, Node **ARG_UNUSED(pnode))
{
    Node *child;

    if ( nodeIsDIR(node) || nodeIsUL(node) || nodeIsOL(node) )
    {
        child = node->content;

        if (child == NULL)
            return no;

        /* check child has no peers */

        if (child->next)
            return no;

        if ( !nodeIsLI(child) )
            return no;

        if ( !child->implicit )
            return no;

        /* coerce dir to div */
        node->tag = TY_(LookupTagDef)( TidyTag_DIV );
        TidyDocFree( doc, node->element );
        node->element = TY_(tmbstrdup)(doc->allocator, "div");
        TY_(AddStyleProperty)( doc, node, "margin-left: 2em" );
        StripOnlyChild( doc, node );
        return yes;
    }

    return no;
}

/*
    Symptom: <center>
    Action: replace <center> by <div style="text-align: center">
*/

static Bool Center2Div( TidyDocImpl* doc, Node *node, Node **pnode)
{
    if ( nodeIsCENTER(node) )
    {
        RenameElem( doc, node, TidyTag_DIV );
        TY_(AddStyleProperty)( doc, node, "text-align: center" );
        return yes;
    }

    return no;
}

/* Copy child attributes to node. Duplicate attributes are overwritten.
   Unique attributes (such as ID) disable the action.
   Attributes style and class are not dealt with. A call to MergeStyles
   will do that.
*/
static Bool CopyAttrs( TidyDocImpl* doc, Node *node, Node *child)
{
    AttVal *av1, *av2;
    TidyAttrId id;

    /* Detect attributes that cannot be merged or overwritten. */
    if (TY_(AttrGetById)(child, TidyAttr_ID) != NULL
        && TY_(AttrGetById)(node, TidyAttr_ID) != NULL)
        return no;

    /* Move child attributes to node. Attributes in node
     can be overwritten or merged. */
    for (av2 = child->attributes; av2; )
    {
        /* Dealt by MergeStyles. */
        if (attrIsSTYLE(av2) || attrIsCLASS(av2))
        {
            av2 = av2->next;
            continue;
        }
        /* Avoid duplicates in node */
        if ((id=AttrId(av2)) != TidyAttr_UNKNOWN
            && (av1=TY_(AttrGetById)(node, id))!= NULL)
            TY_(RemoveAttribute)( doc, node, av1 );

        /* Move attribute from child to node */
        TY_(DetachAttribute)( child, av2 );
        av1 = av2;
        av2 = av2->next;
        av1->next = NULL;
        TY_(InsertAttributeAtEnd)( node, av1 );
    }

    return yes;
}

/*
    Symptom <XX><XX>...</XX></XX>
    Action: merge the two XXs

  For instance, this is useful after nested <dir>s used by Word
  for indenting have been converted to <div>s

  If state is "no", no merging.
  If state is "yes", inner element is discarded. Only Style and Class
  attributes are merged using MergeStyles().
  If state is "auto", atttibutes are merged as described in CopyAttrs().
  Style and Class attributes are merged using MergeStyles().
*/
static Bool MergeNestedElements( TidyDocImpl* doc,
                                 TidyTagId Id, TidyTriState state, Node *node,
                                 Node **ARG_UNUSED(pnode))
{
    Node *child;

    if ( state == TidyNoState
         || !TagIsId(node, Id) )
        return no;

    child = node->content;

    if ( child == NULL
         || child->next != NULL
         || !TagIsId(child, Id) )
        return no;

    if ( state == TidyAutoState
         && CopyAttrs(doc, node, child) == no )
        return no;

    MergeStyles( doc, node, child );
    StripOnlyChild( doc, node );
    return yes;
}

/*
    Symptom: <ul><li><ul>...</ul></li></ul>
    Action: discard outer list
*/

static Bool NestedList( TidyDocImpl* doc, Node *node, Node **pnode )
{
    Node *child, *list;

    if ( nodeIsUL(node) || nodeIsOL(node) )
    {
        child = node->content;

        if (child == NULL)
            return no;

        /* check child has no peers */

        if (child->next)
            return no;

        list = child->content;

        if (!list)
            return no;

        if (list->tag != node->tag)
            return no;

        /* check list has no peers */
        if (list->next)
            return no;

        *pnode = list;  /* Set node to resume iteration */

        /* move inner list node into position of outer node */
        list->prev = node->prev;
        list->next = node->next;
        list->parent = node->parent;
        TY_(FixNodeLinks)(list);

        /* get rid of outer ul and its li */
        child->content = NULL;
        TY_(FreeNode)( doc, child ); /* See test #427841. */
        child = NULL;
        node->content = NULL;
        node->next = NULL;
        TY_(FreeNode)( doc, node );
        node = NULL;

        /*
          If prev node was a list the chances are this node
          should be appended to that list. Word has no way of
          recognizing nested lists and just uses indents
        */

        if (list->prev)
        {
            if ( (nodeIsUL(list->prev) || nodeIsOL(list->prev))
                 && list->prev->last )
            {
                node = list;
                list = node->prev;

                child = list->last;  /* <li> */

                list->next = node->next;
                TY_(FixNodeLinks)(list);

                node->parent = child;
                node->next = NULL;
                node->prev = child->last;
                TY_(FixNodeLinks)(node);
                CleanNode_clean_c( doc, node );
            }
        }

        return yes;
    }

    return no;
}

/* Find CSS equivalent in a SPAN element */
static
Bool FindCSSSpanEq( Node *node, ctmbstr *s, Bool deprecatedOnly )
{
    struct
    {
        TidyTagId id;
        ctmbstr CSSeq;
        Bool deprecated;
    }
    const CSS_SpanEq[] =
        {
            { TidyTag_B, "font-weight: bold", no },
            { TidyTag_I, "font-style: italic", no },
            { TidyTag_S, "text-decoration: line-through", yes},
            { TidyTag_STRIKE, "text-decoration: line-through", yes},
            { TidyTag_U, "text-decoration: underline", yes},
            { TidyTag_UNKNOWN, NULL, no }
        };
    unsigned int i;

    for (i=0; CSS_SpanEq[i].CSSeq; ++i)
        if ( (!deprecatedOnly || CSS_SpanEq[i].deprecated)
             && TagIsId(node, CSS_SpanEq[i].id) )
        {
            *s = CSS_SpanEq[i].CSSeq;
            return yes;
        }
    return no; 
}

/* Necessary conditions to apply BlockStyle(). */
static Bool CanApplyBlockStyle( Node *node )
{
    if (TY_(nodeHasCM)(node,CM_BLOCK | CM_LIST | CM_DEFLIST | CM_TABLE)
        && !nodeIsDIV(node) && !nodeIsP(node)
        && !nodeIsTABLE(node) && !nodeIsTR(node) && !nodeIsLI(node) )
    {
        return yes;
    }
    return no;
}

/*
  Symptom: the only child of a block-level element is a
  presentation element such as B, I or FONT

  Action: add style "font-weight: bold" to the block and
  strip the <b> element, leaving its children.

  example:

    <p>
      <b><font face="Arial" size="6">Draft Recommended Practice</font></b>
    </p>

  becomes:

      <p style="font-weight: bold; font-family: Arial; font-size: 6">
        Draft Recommended Practice
      </p>

  This code also replaces the align attribute by a style attribute.
  However, to avoid CSS problems with Navigator 4, this isn't done
  for the elements: caption, tr and table
*/
static Bool BlockStyle( TidyDocImpl* doc, Node *node, Node **ARG_UNUSED(pnode) )
{
    Node *child;
    ctmbstr CSSeq;

    /* check for bgcolor */
    if (   nodeIsTABLE(node)
        || nodeIsTD(node) || nodeIsTH(node) || nodeIsTR( node ))
        TableBgColor( doc, node );

    if (CanApplyBlockStyle(node))
    {
        /* check for align attribute */
        if ( !nodeIsCAPTION(node) )
            TextAlign( doc, node );

        child = node->content;
        if (child == NULL)
            return no;

        /* check child has no peers */
        if (child->next)
            return no;

        if ( FindCSSSpanEq(child, &CSSeq, no) )
        {
            MergeStyles( doc, node, child );
            TY_(AddStyleProperty)( doc, node, CSSeq );
            StripOnlyChild( doc, node );
            return yes;
        }
        else if ( nodeIsFONT(child) )
        {
            MergeStyles( doc, node, child );
            AddFontStyles( doc, node, child->attributes );
            StripOnlyChild( doc, node );
            return yes;
        }
    }

    return no;
}

/* Necessary conditions to apply InlineStyle(). */
static Bool CanApplyInlineStyle( Node *node )
{
    return !nodeIsFONT(node) && TY_(nodeHasCM)(node, CM_INLINE|CM_ROW);
}

/* the only child of table cell or an inline element such as em */
static Bool InlineStyle( TidyDocImpl* doc, Node *node, Node **ARG_UNUSED(pnode) )
{
    Node *child;
    ctmbstr CSSeq;

    if ( CanApplyInlineStyle(node) )
    {
        child = node->content;

        if (child == NULL)
            return no;

        /* check child has no peers */

        if (child->next)
            return no;

        if ( FindCSSSpanEq(child, &CSSeq, no) )
        {
            MergeStyles( doc, node, child );
            TY_(AddStyleProperty)( doc, node, CSSeq );
            StripOnlyChild( doc, node );
            return yes;
        }
        else if ( nodeIsFONT(child) )
        {
            MergeStyles( doc, node, child );
            AddFontStyles( doc, node, child->attributes );
            StripOnlyChild( doc, node );
            return yes;
        }
    }

    return no;
}

/*
    Transform element to equivalent CSS
*/
static Bool InlineElementToCSS( TidyDocImpl* doc, Node* node,
                                Node **ARG_UNUSED(pnode)  )
{
    ctmbstr CSSeq;

    /* if node is the only child of parent element then leave alone
          Do so only if BlockStyle may be succesful. */
    if ( node->parent->content == node && node->next == NULL &&
         (CanApplyBlockStyle(node->parent)
          || CanApplyInlineStyle(node->parent)) )
        return no;

    if ( FindCSSSpanEq(node, &CSSeq, yes) )
    {
        RenameElem( doc, node, TidyTag_SPAN );
        TY_(AddStyleProperty)( doc, node, CSSeq );
        return yes;
    }
    return no;
} 

/*
  Replace font elements by span elements, deleting
  the font element's attributes and replacing them
  by a single style attribute.
*/
static Bool Font2Span( TidyDocImpl* doc, Node *node, Node **pnode )
{
    AttVal *av, *style, *next;

    if ( nodeIsFONT(node) )
    {
        /* if node is the only child of parent element then leave alone
          Do so only if BlockStyle may be succesful. */
        if ( node->parent->content == node && node->next == NULL &&
             CanApplyBlockStyle(node->parent) )
            return no;

        AddFontStyles( doc, node, node->attributes );

        /* extract style attribute and free the rest */
        av = node->attributes;
        style = NULL;

        while (av)
        {
            next = av->next;

            if (attrIsSTYLE(av))
            {
                av->next = NULL;
                style = av;
            }
            else
            {
                TY_(FreeAttribute)( doc, av );
            }
            av = next;
        }

        node->attributes = style;
        RenameElem( doc, node, TidyTag_SPAN );
        return yes;
    }

    return no;
}

/*
  Applies all matching rules to a node.
*/
Node* CleanNode_clean_c( TidyDocImpl* doc, Node *node )
{
    Node *next = NULL;
    TidyTriState mergeDivs = cfgAutoBool(doc, TidyMergeDivs);
    TidyTriState mergeSpans = cfgAutoBool(doc, TidyMergeSpans);

    for (next = node; TY_(nodeIsElement)(node); node = next)
    {
        if ( Dir2Div(doc, node, &next) )
            continue;

        /* Special case: true result means
        ** that arg node and its parent no longer exist.
        ** So we must jump back up the CreateStyleProperties()
        ** call stack until we have a valid node reference.
        */
        if ( NestedList(doc, node, &next) )
            return next;

        if ( Center2Div(doc, node, &next) )
            continue;

        if ( MergeNestedElements(doc, TidyTag_DIV, mergeDivs, node, &next) )
            continue;

        if ( MergeNestedElements(doc, TidyTag_SPAN, mergeSpans, node, &next) )
            continue;

        if ( BlockStyle(doc, node, &next) )
            continue;

        if ( InlineStyle(doc, node, &next) )
            continue;

        if ( InlineElementToCSS(doc, node, &next) )
            continue;

        if ( Font2Span(doc, node, &next) )
            continue;

        break;
    }

    return next;
}

/* Special case: if the current node is destroyed by
** CleanNode_clean_c() lower in the tree, this node and its parent
** no longer exist.  So we must jump back up the CleanTree()
** call stack until we have a valid node reference.
*/

static Node* CleanTree( TidyDocImpl* doc, Node *node )
{
    if (node->content)
    {
        Node *child;
        for (child = node->content; child != NULL; child = child->next)
        {
            child = CleanTree( doc, child );
            if ( !child )
                break;
        }
    }

    return CleanNode_clean_c( doc, node );
}

static void DefineStyleRules( TidyDocImpl* doc, Node *node )
{
    Node *child;

    if (node->content)
    {
        for (child = node->content;
                child != NULL; child = child->next)
        {
            DefineStyleRules( doc, child );
        }
    }

    Style2Rule( doc, node );
}

void TY_(CleanDocument)( TidyDocImpl* doc )
{
    /* placeholder.  CleanTree()/CleanNode_clean_c() will not
    ** zap root element 
    */
    CleanTree( doc, &doc->root );

    if ( cfgBool(doc, TidyMakeClean) )
    {
        DefineStyleRules( doc, &doc->root );
        CreateStyleElement( doc );
    }
}

/* simplifies <b><b> ... </b> ...</b> etc. */
void TY_(NestedEmphasis)( TidyDocImpl* doc, Node* node )
{
    Node *next;

    while (node)
    {
        next = node->next;

        if ( (nodeIsB(node) || nodeIsI(node))
             && node->parent && node->parent->tag == node->tag)
        {
            /* strip redundant inner element */
            DiscardContainer_clean_c( doc, node, &next );
            node = next;
            continue;
        }

        if ( node->content )
            TY_(NestedEmphasis)( doc, node->content );

        node = next;
    }
}



/* replace i by em and b by strong */
void TY_(EmFromI)( TidyDocImpl* doc, Node* node )
{
    while (node)
    {
        if ( nodeIsI(node) )
            RenameElem( doc, node, TidyTag_EM );
        else if ( nodeIsB(node) )
            RenameElem( doc, node, TidyTag_STRONG );

        if ( node->content )
            TY_(EmFromI)( doc, node->content );

        node = node->next;
    }
}

static Bool HasOneChild(Node *node)
{
    return (node->content && node->content->next == NULL);
}

/*
 Some people use dir or ul without an li
 to indent the content. The pattern to
 look for is a list with a single implicit
 li. This is recursively replaced by an
 implicit blockquote.
*/
void TY_(List2BQ)( TidyDocImpl* doc, Node* node )
{
    while (node)
    {
        if (node->content)
            TY_(List2BQ)( doc, node->content );

        if ( node->tag && node->tag->parser == TY_(ParseList) &&
             HasOneChild(node) && node->content->implicit )
        {
            StripOnlyChild( doc, node );
            RenameElem( doc, node, TidyTag_BLOCKQUOTE );
            node->implicit = yes;
        }

        node = node->next;
    }
}


/*
 Replace implicit blockquote by div with an indent
 taking care to reduce nested blockquotes to a single
 div with the indent set to match the nesting depth
*/
void TY_(BQ2Div)( TidyDocImpl* doc, Node *node )
{
    tmbchar indent_buf[ 32 ];
    unsigned int indent;

    while (node)
    {
        if ( nodeIsBLOCKQUOTE(node) && node->implicit )
        {
            indent = 1;

            while( HasOneChild(node) &&
                   nodeIsBLOCKQUOTE(node->content) &&
                   node->implicit)
            {
                ++indent;
                StripOnlyChild( doc, node );
            }

            if (node->content)
                TY_(BQ2Div)( doc, node->content );

            TY_(tmbsnprintf)(indent_buf, sizeof(indent_buf), "margin-left: %dem",
                             2*indent);

            RenameElem( doc, node, TidyTag_DIV );
            TY_(AddStyleProperty)(doc, node, indent_buf );
        }
        else if (node->content)
            TY_(BQ2Div)( doc, node->content );

        node = node->next;
    }
}


static Node* FindEnclosingCell( TidyDocImpl* ARG_UNUSED(doc), Node *node)
{
    Node *check;

    for ( check=node; check; check = check->parent )
    {
      if ( nodeIsTD(check) )
        return check;
    }
    return NULL;
}

/* node is <![if ...]> prune up to <![endif]> */
static Node* PruneSection( TidyDocImpl* doc, Node *node )
{
    Lexer* lexer = doc->lexer;

    for (;;)
    {
        ctmbstr lexbuf = lexer->lexbuf + node->start;
        if ( TY_(tmbstrncmp)(lexbuf, "if !supportEmptyParas", 21) == 0 )
        {
          Node* cell = FindEnclosingCell( doc, node );
          if ( cell )
          {
            /* Need to put &nbsp; into cell so it doesn't look weird
            */
            Node* nbsp = TY_(NewLiteralTextNode)( lexer, "\240" );
            assert( (byte)'\240' == (byte)160 );
            TY_(InsertNodeBeforeElement)( node, nbsp );
          }
        }

        /* discard node and returns next, unless it is a text node */
        if ( node->type == TextNode )
            node = node->next;
        else
            node = TY_(DiscardElement)( doc, node );

        if (node == NULL)
            return NULL;
        
        if (node->type == SectionTag)
        {
            if (TY_(tmbstrncmp)(lexer->lexbuf + node->start, "if", 2) == 0)
            {
                node = PruneSection( doc, node );
                continue;
            }

            if (TY_(tmbstrncmp)(lexer->lexbuf + node->start, "endif", 5) == 0)
            {
                node = TY_(DiscardElement)( doc, node );
                break;
            }
        }
    }

    return node;
}

void TY_(DropSections)( TidyDocImpl* doc, Node* node )
{
    Lexer* lexer = doc->lexer;
    while (node)
    {
        if (node->type == SectionTag)
        {
            /* prune up to matching endif */
            if ((TY_(tmbstrncmp)(lexer->lexbuf + node->start, "if", 2) == 0) &&
                (TY_(tmbstrncmp)(lexer->lexbuf + node->start, "if !vml", 7) != 0)) /* #444394 - fix 13 Sep 01 */
            {
                node = PruneSection( doc, node );
                continue;
            }

            /* discard others as well */
            node = TY_(DiscardElement)( doc, node );
            continue;
        }

        if (node->content)
            TY_(DropSections)( doc, node->content );

        node = node->next;
    }
}

static void PurgeWord2000Attributes( TidyDocImpl* doc, Node* node )
{
    AttVal *attr, *next, *prev = NULL;

    for ( attr = node->attributes; attr; attr = next )
    {
        next = attr->next;

        /* special check for class="Code" denoting pre text */
        /* Pass thru user defined styles as HTML class names */
        if (attrIsCLASS(attr))
        {
            if (AttrValueIs(attr, "Code") ||
                 TY_(tmbstrncmp)(attr->value, "Mso", 3) != 0 )
            {
                prev = attr;
                continue;
            }
        }

        if (attrIsCLASS(attr) ||
            attrIsSTYLE(attr) ||
            attrIsLANG(attr)  ||
             ( (attrIsHEIGHT(attr) || attrIsWIDTH(attr)) &&
               (nodeIsTD(node) || nodeIsTR(node) || nodeIsTH(node)) ) ||
             (attr->attribute && TY_(tmbstrncmp)(attr->attribute, "x:", 2) == 0) )
        {
            if (prev)
                prev->next = next;
            else
                node->attributes = next;

            TY_(FreeAttribute)( doc, attr );
        }
        else
            prev = attr;
    }
}

/* Word2000 uses span excessively, so we strip span out */
static Node* StripSpan( TidyDocImpl* doc, Node* span )
{
    Node *node, *prev = NULL, *content;

    /*
     deal with span elements that have content
     by splicing the content in place of the span
     after having processed it
    */

    TY_(CleanWord2000)( doc, span->content );
    content = span->content;

    if (span->prev)
        prev = span->prev;
    else if (content)
    {
        node = content;
        content = content->next;
        TY_(RemoveNode)(node);
        TY_(InsertNodeBeforeElement)(span, node);
        prev = node;
    }

    while (content)
    {
        node = content;
        content = content->next;
        TY_(RemoveNode)(node);
        TY_(InsertNodeAfterElement)(prev, node);
        prev = node;
    }

    if (span->next == NULL)
        span->parent->last = prev;

    node = span->next;
    span->content = NULL;
    TY_(DiscardElement)( doc, span );
    return node;
}

/* map non-breaking spaces to regular spaces */
void TY_(NormalizeSpaces)(Lexer *lexer, Node *node)
{
    while ( node )
    {
        if ( node->content )
            TY_(NormalizeSpaces)( lexer, node->content );

        if (TY_(nodeIsText)(node))
        {
            unsigned int i, c;
            tmbstr p = lexer->lexbuf + node->start;

            for (i = node->start; i < node->end; ++i)
            {
                c = (byte) lexer->lexbuf[i];

                /* look for UTF-8 multibyte character */
                if ( c > 0x7F )
                    i += TY_(GetUTF8)( lexer->lexbuf + i, &c );

                if ( c == 160 )
                    c = ' ';

                p = TY_(PutUTF8)(p, c);
            }
            node->end = p - lexer->lexbuf;
        }

        node = node->next;
    }
}

/* used to hunt for hidden preformatted sections */
static Bool NoMargins(Node *node)
{
    AttVal *attval = TY_(AttrGetById)(node, TidyAttr_STYLE);

    if ( !AttrHasValue(attval) )
        return no;

    /* search for substring "margin-top: 0" */
    if (!TY_(tmbsubstr)(attval->value, "margin-top: 0"))
        return no;

    /* search for substring "margin-bottom: 0" */
    if (!TY_(tmbsubstr)(attval->value, "margin-bottom: 0"))
        return no;

    return yes;
}

/* does element have a single space as its content? */
static Bool SingleSpace( Lexer* lexer, Node* node )
{
    if ( node->content )
    {
        node = node->content;

        if ( node->next != NULL )
            return no;

        if ( node->type != TextNode )
            return no;

        if ( (node->end - node->start) == 1 &&
             lexer->lexbuf[node->start] == ' ' )
            return yes;

        if ( (node->end - node->start) == 2 )
        {
            unsigned int c = 0;
            TY_(GetUTF8)( lexer->lexbuf + node->start, &c );
            if ( c == 160 )
                return yes;
        }
    }

    return no;
}

/*
 This is a major clean up to strip out all the extra stuff you get
 when you save as web page from Word 2000. It doesn't yet know what
 to do with VML tags, but these will appear as errors unless you
 declare them as new tags, such as o:p which needs to be declared
 as inline.
*/
void TY_(CleanWord2000)( TidyDocImpl* doc, Node *node)
{
    /* used to a list from a sequence of bulletted p's */
    Lexer* lexer = doc->lexer;
    Node* list = NULL;
    AttVal *next_attr, *attval;

    while ( node )
    {
        /* get rid of Word's xmlns attributes */
        if ( nodeIsHTML(node) )
        {
            /* check that it's a Word 2000 document */
            if ( !TY_(GetAttrByName)(node, "xmlns:o") &&
                 !cfgBool(doc, TidyMakeBare) )
                return;

            /* Output proprietary attributes to maintain errout compatability
             * with traditional Tidy. This is a result of moving all of the
             * proprietary checks to near the end of the cleanup process,
             * meaning this result would not ordinarily be displayed. 
             */
            attval = node->attributes;
            while ( attval ) {
                next_attr = attval->next;

                /* Issue #591 - take care of a NULL attribute, too. */
                if ( !attval->attribute || ( strcmp(attval->attribute, "xmlns") != 0 ))
                    TY_(ReportAttrError)(doc, node, attval, PROPRIETARY_ATTRIBUTE);
                attval = next_attr;
            }

            TY_(FreeAttrs)( doc, node );
        }

        /* fix up preformatted sections by looking for a
        ** sequence of paragraphs with zero top/bottom margin
        */
        if ( nodeIsP(node) )
        {
            if (NoMargins(node))
            {
                Node *pre, *next;
                TY_(CoerceNode)(doc, node, TidyTag_PRE, no, yes);

                PurgeWord2000Attributes( doc, node );

                if (node->content)
                    TY_(CleanWord2000)( doc, node->content );

                pre = node;
                node = node->next;

                /* continue to strip p's */

                while ( nodeIsP(node) && NoMargins(node) )
                {
                    next = node->next;
                    TY_(RemoveNode)(node);
                    TY_(InsertNodeAtEnd)(pre, TY_(NewLineNode)(lexer));
                    TY_(InsertNodeAtEnd)(pre, node);
                    StripSpan( doc, node );
                    node = next;
                }

                if (node == NULL)
                    break;
            }
        }

        if (node->tag && (node->tag->model & CM_BLOCK)
            && SingleSpace(lexer, node))
        {
            node = StripSpan( doc, node );
            continue;
        }
        /* discard Word's style verbiage */
        if ( nodeIsSTYLE(node) || nodeIsMETA(node) ||
             node->type == CommentTag )
        {
            node = TY_(DiscardElement)( doc, node );
            continue;
        }

        /* strip out all span and font tags Word scatters so liberally! */
        if ( nodeIsSPAN(node) || nodeIsFONT(node) )
        {
            node = StripSpan( doc, node );
            continue;
        }

        if ( nodeIsLINK(node) )
        {
            AttVal *attr = TY_(AttrGetById)(node, TidyAttr_REL);

            if (AttrValueIs(attr, "File-List"))
            {
                node = TY_(DiscardElement)( doc, node );
                continue;
            }
        }

        /* discards <o:p> which encodes the paragraph mark */
        if ( node->tag && TY_(tmbstrcmp)(node->tag->name,"o:p")==0)
        {
            /* Output proprietary elements to maintain errout compatability
             * with traditional Tidy. This is a result of moving all of the
             * proprietary checks to near the end of the cleanup process,
             * meaning this result would not ordinarily be displayed.
             */
            Node* next;
            TY_(Report)(doc, NULL, node, PROPRIETARY_ELEMENT);
            DiscardContainer_clean_c( doc, node, &next );
            node = next;
            continue;
        }

        /* discard empty paragraphs */

        if ( node->content == NULL && nodeIsP(node) )
        {
            /*  Use the existing function to ensure consistency */
            Node *next = TY_(TrimEmptyElement)( doc, node );
            node = next;
            continue;
        }

        if ( nodeIsP(node) )
        {
            AttVal *attr, *atrStyle;
            
            attr = TY_(AttrGetById)(node, TidyAttr_CLASS);
            atrStyle = TY_(AttrGetById)(node, TidyAttr_STYLE);
            /*
               (JES) Sometimes Word marks a list item with the following hokie syntax
               <p class="MsoNormal" style="...;mso-list:l1 level1 lfo1;
                translate these into <li>
            */
            /* map sequence of <p class="MsoListBullet"> to <ul>...</ul> */
            /* map <p class="MsoListNumber"> to <ol>...</ol> */
            if ( AttrValueIs(attr, "MsoListBullet") ||
                 AttrValueIs(attr, "MsoListNumber") ||
                 AttrContains(atrStyle, "mso-list:") )
            {
                TidyTagId listType = TidyTag_UL;
                if (AttrValueIs(attr, "MsoListNumber"))
                    listType = TidyTag_OL;

                TY_(CoerceNode)(doc, node, TidyTag_LI, no, yes);

                if ( !list || TagId(list) != listType )
                {
                    const Dict* tag = TY_(LookupTagDef)( listType );
                    list = TY_(InferredTag)(doc, tag->id);
                    TY_(InsertNodeBeforeElement)(node, list);
                }

                PurgeWord2000Attributes( doc, node );

                if ( node->content )
                    TY_(CleanWord2000)( doc, node->content );

                /* remove node and append to contents of list */
                TY_(RemoveNode)(node);
                TY_(InsertNodeAtEnd)(list, node);
                node = list;
            }
            /* map sequence of <p class="Code"> to <pre>...</pre> */
            else if (AttrValueIs(attr, "Code"))
            {
                Node *br = TY_(NewLineNode)(lexer);
                TY_(NormalizeSpaces)(lexer, node->content);

                if ( !list || TagId(list) != TidyTag_PRE )
                {
                    list = TY_(InferredTag)(doc, TidyTag_PRE);
                    TY_(InsertNodeBeforeElement)(node, list);
                }

                /* remove node and append to contents of list */
                TY_(RemoveNode)(node);
                TY_(InsertNodeAtEnd)(list, node);
                StripSpan( doc, node );
                TY_(InsertNodeAtEnd)(list, br);
                node = list->next;
            }
            else
                list = NULL;
        }
        else
            list = NULL;

        if (!node)
            return;

        /* strip out style and class attributes */
        if (TY_(nodeIsElement)(node))
            PurgeWord2000Attributes( doc, node );

        if (node->content)
            TY_(CleanWord2000)( doc, node->content );

        node = node->next;
    }
}

Bool TY_(IsWord2000)( TidyDocImpl* doc )
{
    AttVal *attval;
    Node *node, *head;
    Node *html = TY_(FindHTML)( doc );

    if (html && TY_(GetAttrByName)(html, "xmlns:o"))
        return yes;
    
    /* search for <meta name="GENERATOR" content="Microsoft ..."> */
    head = TY_(FindHEAD)( doc );

    if (head)
    {
        for (node = head->content; node; node = node->next)
        {
            if ( !nodeIsMETA(node) )
                continue;

            attval = TY_(AttrGetById)( node, TidyAttr_NAME );

            if ( !AttrValueIs(attval, "generator") )
                continue;

            attval =  TY_(AttrGetById)( node, TidyAttr_CONTENT );

            if ( AttrContains(attval, "Microsoft") )
                return yes;
        }
    }

    return no;
}

/* where appropriate move object elements from head to body */
void TY_(BumpObject)( TidyDocImpl* doc, Node *html )
{
    Node *node, *next, *head = NULL, *body = NULL;

    if (!html)
        return;

    for ( node = html->content; node != NULL; node = node->next )
    {
        if ( nodeIsHEAD(node) )
            head = node;

        if ( nodeIsBODY(node) )
            body = node;
    }

    if ( head != NULL && body != NULL )
    {
        for (node = head->content; node != NULL; node = next)
        {
            next = node->next;

            if ( nodeIsOBJECT(node) )
            {
                Node *child;
                Bool bump = no;

                for (child = node->content; child != NULL; child = child->next)
                {
                    /* bump to body unless content is param */
                    if ( (TY_(nodeIsText)(child) && !TY_(IsBlank)(doc->lexer, node))
                         || !nodeIsPARAM(child) )
                    {
                            bump = yes;
                            break;
                    }
                }

                if ( bump )
                {
                    TY_(RemoveNode)( node );
                    TY_(InsertNodeAtStart)( body, node );
                }
            }
        }
    }
}


/*\
*  Issue #456 - Check meta charset
*  1. if there is no meta charset, it adds one, according to doctype, no warning.
*  2. if there is a meta charset, it moves it to the top if HEAD. Not sure this required?
*  3. if it doesn't match the output encoding, and fix. Naybe no warning?
*  4. if there are duplicates, discard them, with warning.
\*/
Bool TY_(TidyMetaCharset)(TidyDocImpl* doc)
{
    AttVal *charsetAttr;
    AttVal *contentAttr;
    AttVal *httpEquivAttr;
    Bool charsetFound = no;
    unsigned int outenc = cfg(doc, TidyOutCharEncoding);
    ctmbstr enc = TY_(GetEncodingNameFromTidyId)(outenc);
    Node *currentNode;
    Node *head = TY_(FindHEAD)(doc);
    Node *metaTag;
    Node *prevNode;
    TidyBuffer buf;
    TidyBuffer charsetString;
    /* tmbstr httpEquivAttrValue; */
    /* tmbstr lcontent; */
    tmbstr newValue;
    Bool add_meta = cfgBool(doc, TidyMetaCharset);

    /* We can't do anything we don't have a head or encoding is NULL */
    if (!head || !enc || !TY_(tmbstrlen)(enc))
        return no;
    if (outenc == RAW)
        return no;
#ifndef NO_NATIVE_ISO2022_SUPPORT
    if (outenc == ISO2022)
        return no;
#endif
    if (cfgAutoBool(doc, TidyBodyOnly) == TidyYesState)
        return no; /* nothing to do here if showing body only */

    tidyBufInit(&charsetString);
    /* Set up the content test 'charset=value' */
    tidyBufClear(&charsetString);
    tidyBufAppend(&charsetString, "charset=", 8);
    tidyBufAppend(&charsetString, (char*)enc, TY_(tmbstrlen)(enc));
    tidyBufAppend(&charsetString, "\0", 1); /* zero terminate the buffer */
    /* process the children of the head */
    /* Issue #656 - guard against 'currentNode' being set NULL in loop */
    for (currentNode = head->content; currentNode; 
        currentNode = (currentNode ? currentNode->next : NULL))
    {
        if (!nodeIsMETA(currentNode))
            continue;   /* not a meta node */
        charsetAttr = attrGetCHARSET(currentNode);
        httpEquivAttr = attrGetHTTP_EQUIV(currentNode);
        if (!charsetAttr && !httpEquivAttr)
            continue;   /* has no charset attribute */
                        /*
                        Meta charset comes in quite a few flavors:
                        1. <meta charset="value"> - expected for (X)HTML5.
                        */
        if (charsetAttr && !httpEquivAttr)
        {
            /* we already found one, so remove the rest. */
            if (charsetFound || !charsetAttr->value)
            {
                prevNode = currentNode->prev;
                TY_(Report)(doc, head, currentNode, DISCARDING_UNEXPECTED);
                TY_(DiscardElement)(doc, currentNode);
                currentNode = prevNode;
                continue;
            }
            charsetFound = yes;
            /* Fix mismatched attribute value */
            if (TY_(tmbstrcasecmp)(charsetAttr->value, enc) != 0)
            {
                newValue = (tmbstr)TidyDocAlloc(doc, TY_(tmbstrlen)(enc) + 1);   /* allocate + 1 for 0 */
                TY_(tmbstrcpy)(newValue, enc);
                /* Note: previously http-equiv had been modified, without warning
                in void TY_(VerifyHTTPEquiv)(TidyDocImpl* doc, Node *head)
                */
                TY_(ReportAttrError)(doc, currentNode, charsetAttr, ATTRIBUTE_VALUE_REPLACED);
                TidyDocFree(doc, charsetAttr->value);   /* free current value */
                charsetAttr->value = newValue;
            }
            /* Make sure it's the first element. */
            if (currentNode != head->content->next) {
                TY_(RemoveNode)(currentNode);
                TY_(InsertNodeAtStart)(head, currentNode);
            }
            continue;
        }
        /*
        2. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        expected for HTML4. This is normally ok - but can clash.
        */
        if (httpEquivAttr && !charsetAttr)
        {
            contentAttr = TY_(AttrGetById)(currentNode, TidyAttr_CONTENT);
            if (!contentAttr)
                continue;   /* has no 'content' attribute */
            if (!httpEquivAttr->value)
            {
                prevNode = currentNode->prev;
                TY_(Report)(doc, head, currentNode, DISCARDING_UNEXPECTED);
                TY_(DiscardElement)(doc, currentNode);
                currentNode = prevNode;
                continue;
            }
            /* httpEquivAttrValue = TY_(tmbstrtolower)(httpEquivAttr->value); */
            if (TY_(tmbstrcasecmp)(httpEquivAttr->value, (tmbstr) "content-type") != 0)
                continue;   /* is not 'content-type' */
            if (!contentAttr->value)
            {
                continue; /* has no 'content' attribute has NO VALUE! */
            }
            /* check encoding matches
            If a miss-match found here, fix it. previous silently done
            in void TY_(VerifyHTTPEquiv)(TidyDocImpl* doc, Node *head)
            lcontent = TY_(tmbstrtolower)(contentAttr->value);
            */
            if (TY_(tmbstrcasecmp)(contentAttr->value, (ctmbstr)charsetString.bp) == 0)
            {
                /* we already found one, so remove the rest. */
                if (charsetFound)
                {
                    prevNode = currentNode->prev;
                    TY_(Report)(doc, head, currentNode, DISCARDING_UNEXPECTED);
                    TY_(DiscardElement)(doc, currentNode);
                    currentNode = prevNode;
                    continue;
                }
                charsetFound = yes;
            }
            else
            {
                /* fix a mis-match */
                if (charsetFound)
                {
                    prevNode = currentNode->prev;
                    TY_(Report)(doc, head, currentNode, DISCARDING_UNEXPECTED);
                    TY_(DiscardElement)(doc, currentNode);
                    currentNode = prevNode;
                }
                else
                {
                    /* correct the content */
                    newValue = (tmbstr)TidyDocAlloc(doc, 19 + TY_(tmbstrlen)(enc) + 1);
                    TY_(tmbstrcpy)(newValue, "text/html; charset=");
                    TY_(tmbstrcpy)(newValue + 19, enc);
                    if (cfgBool(doc, TidyShowMetaChange))   /* Issue #456 - backward compatibility only */
                        TY_(ReportAttrError)(doc, currentNode, contentAttr, ATTRIBUTE_VALUE_REPLACED);
                    TidyDocFree(doc, contentAttr->value);
                    contentAttr->value = newValue;
                    charsetFound = yes;
                }
            }
            continue;
        }
        /*
        3. <meta charset="utf-8" http-equiv="Content-Type" content="...">
        This is generally bad. Discard and warn.
        */
        if (httpEquivAttr && charsetAttr)
        {
            /* printf("WARN ABOUT HTTP EQUIV AND CHARSET ATTR! \n"); */
            prevNode = currentNode->prev;
            TY_(Report)(doc, head, currentNode, DISCARDING_UNEXPECTED);
            TY_(DiscardElement)(doc, currentNode);
            currentNode = prevNode;
        }
    }

    /* completed head scan - add appropriate meta - if 'yes' and none exists */
    if (add_meta && !charsetFound)
    {
        /* add appropriate meta charset tag - no warning */
        metaTag = TY_(InferredTag)(doc, TidyTag_META);
        switch (TY_(HTMLVersion)(doc))
        {
        case HT50:
        case XH50:
            TY_(AddAttribute)(doc, metaTag, "charset", enc);
            break;
        default:
            tidyBufInit(&buf);
            tidyBufAppend(&buf, "text/html; ", 11);
            tidyBufAppend(&buf, charsetString.bp, TY_(tmbstrlen)((ctmbstr)charsetString.bp));
            tidyBufAppend(&buf, "\0", 1);   /* zero terminate the buffer */
            TY_(AddAttribute)(doc, metaTag, "http-equiv", "Content-Type"); /* add 'http-equiv' const. */
            TY_(AddAttribute)(doc, metaTag, "content", (char*)buf.bp);  /* add 'content="<enc>"' */
            tidyBufFree(&buf);
        }
        TY_(InsertNodeAtStart)(head, metaTag);
        TY_(Report)(doc, metaTag, head, ADDED_MISSING_CHARSET); /* actually just 'Info:' */
    }
    tidyBufFree(&charsetString);
    return yes;
}


void TY_(DropComments)(TidyDocImpl* doc, Node* node)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (node->type == CommentTag)
        {
            TY_(RemoveNode)(node);
            TY_(FreeNode)(doc, node);
            node = next;
            continue;
        }

        if (node->content)
            TY_(DropComments)(doc, node->content);

        node = next;
    }
}

void TY_(DropFontElements)(TidyDocImpl* doc, Node* node, Node **ARG_UNUSED(pnode))
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (nodeIsFONT(node))
        {
            DiscardContainer_clean_c(doc, node, &next);
            node = next;
            continue;
        }

        if (node->content)
            TY_(DropFontElements)(doc, node->content, &next);

        node = next;
    }
}

void TY_(WbrToSpace)(TidyDocImpl* doc, Node* node)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (nodeIsWBR(node))
        {
            Node* text;
            text = TY_(NewLiteralTextNode)(doc->lexer, " ");
            TY_(InsertNodeAfterElement)(node, text);
            TY_(RemoveNode)(node);
            TY_(FreeNode)(doc, node);
            node = next;
            continue;
        }

        if (node->content)
            TY_(WbrToSpace)(doc, node->content);

        node = next;
   }
}

/*
  Filters from Word and PowerPoint often use smart
  quotes resulting in character codes between 128
  and 159. Unfortunately, the corresponding HTML 4.0
  entities for these are not widely supported. The
  following converts dashes and quotation marks to
  the nearest ASCII equivalent. My thanks to
  Andrzej Novosiolov for his help with this code.

  Note: The old code in the pretty printer applied
  this to all node types and attribute values while
  this routine applies it only to text nodes. First,
  Microsoft Office products rarely put the relevant
  characters into these tokens, second support for
  them is much better now and last but not least, it
  can be harmful to replace these characters since
  US-ASCII quote marks are often used as syntax
  characters, a simple

    <a onmouseover="alert('&#x2018;')">...</a>

  would be broken if the U+2018 is replaced by "'".
  The old code would neither take care whether the
  quote mark is already used as delimiter,

    <p title='&#x2018;'>...</p>

  got
  
    <p title='''>...</p>

  Since browser support is much better nowadays and
  high-quality typography is better than ASCII it'd
  be probably a good idea to drop the feature...
*/
void TY_(DowngradeTypography)(TidyDocImpl* doc, Node* node)
{
    Node* next;
    Lexer* lexer = doc->lexer;

    while (node)
    {
        next = node->next;

        if (TY_(nodeIsText)(node))
        {
            unsigned int i, c;
            tmbstr p = lexer->lexbuf + node->start;

            for (i = node->start; i < node->end; ++i)
            {
                c = (unsigned char) lexer->lexbuf[i];

                if (c > 0x7F)
                    i += TY_(GetUTF8)(lexer->lexbuf + i, &c);

                if (c >= 0x2013 && c <= 0x201E)
                {
                    switch (c)
                    {
                    case 0x2013: /* en dash */
                    case 0x2014: /* em dash */
                        c = '-';
                        break;
                    case 0x2018: /* left single  quotation mark */
                    case 0x2019: /* right single quotation mark */
                    case 0x201A: /* single low-9 quotation mark */
                        c = '\'';
                        break;
                    case 0x201C: /* left double  quotation mark */
                    case 0x201D: /* right double quotation mark */
                    case 0x201E: /* double low-9 quotation mark */
                        c = '"';
                        break;
                    }
                }

                p = TY_(PutUTF8)(p, c);
            }

            node->end = p - lexer->lexbuf;
        }

        if (node->content)
            TY_(DowngradeTypography)(doc, node->content);

        node = next;
    }
}

void TY_(ReplacePreformattedSpaces)(TidyDocImpl* doc, Node* node)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (node->tag && node->tag->parser == TY_(ParsePre))
        {
            TY_(NormalizeSpaces)(doc->lexer, node->content);
            node = next;
            continue;
        }

        if (node->content)
            TY_(ReplacePreformattedSpaces)(doc, node->content);

        node = next;
    }
}

void TY_(ConvertCDATANodes)(TidyDocImpl* doc, Node* node)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (node->type == CDATATag)
            node->type = TextNode;

        if (node->content)
            TY_(ConvertCDATANodes)(doc, node->content);

        node = next;
    }
}

/*
  FixLanguageInformation ensures that the document contains (only)
  the attributes for language information desired by the output
  document type. For example, for XHTML 1.0 documents both
  'xml:lang' and 'lang' are desired, for XHTML 1.1 only 'xml:lang'
  is desired and for HTML 4.01 only 'lang' is desired.
*/
void TY_(FixLanguageInformation)(TidyDocImpl* doc, Node* node, Bool wantXmlLang, Bool wantLang)
{
    Node* next;

    while (node)
    {
        next = node->next;

        /* todo: report modifications made here to the report system */

        if (TY_(nodeIsElement)(node))
        {
            AttVal* lang = TY_(AttrGetById)(node, TidyAttr_LANG);
            AttVal* xmlLang = TY_(AttrGetById)(node, TidyAttr_XML_LANG);

            if (lang && xmlLang)
            {
                /*
                  todo: check whether both attributes are in sync,
                  here or elsewhere, where elsewhere is probably
                  preferable.
                  AD - March 2005: not mandatory according the standards.
                */
            }
            else if (lang && wantXmlLang)
            {
                if (TY_(NodeAttributeVersions)( node, TidyAttr_XML_LANG )
                    & doc->lexer->versionEmitted)
                    TY_(RepairAttrValue)(doc, node, "xml:lang", lang->value);
            }
            else if (xmlLang && wantLang)
            {
                if (TY_(NodeAttributeVersions)( node, TidyAttr_LANG )
                    & doc->lexer->versionEmitted)
                    TY_(RepairAttrValue)(doc, node, "lang", xmlLang->value);
            }

            if (lang && !wantLang)
                TY_(RemoveAttribute)(doc, node, lang);
            
            if (xmlLang && !wantXmlLang)
                TY_(RemoveAttribute)(doc, node, xmlLang);
        }

        if (node->content)
            TY_(FixLanguageInformation)(doc, node->content, wantXmlLang, wantLang);

        node = next;
    }
}

/*
  Set/fix/remove <html xmlns='...'>
*/
void TY_(FixXhtmlNamespace)(TidyDocImpl* doc, Bool wantXmlns)
{
    Node* html = TY_(FindHTML)(doc);
    AttVal* xmlns;

    if (!html)
        return;

    xmlns = TY_(AttrGetById)(html, TidyAttr_XMLNS);

    if (wantXmlns)
    {
        if (!AttrValueIs(xmlns, XHTML_NAMESPACE))
            TY_(RepairAttrValue)(doc, html, "xmlns", XHTML_NAMESPACE);
    }
    else if (xmlns)
    {
        TY_(RemoveAttribute)(doc, html, xmlns);
    }
}

/*
  ...
*/
void TY_(FixAnchors)(TidyDocImpl* doc, Node *node, Bool wantName, Bool wantId)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (TY_(IsAnchorElement)(doc, node))
        {
            AttVal *name = TY_(AttrGetById)(node, TidyAttr_NAME);
            AttVal *id = TY_(AttrGetById)(node, TidyAttr_ID);
            Bool hadName = name!=NULL;
            Bool hadId = id!=NULL;
            Bool IdEmitted = no;
            Bool NameEmitted = no;

            /* todo: how are empty name/id attributes handled? */

            if (name && id)
            {
                Bool NameHasValue = AttrHasValue(name);
                Bool IdHasValue = AttrHasValue(id);
                if ( (NameHasValue != IdHasValue) ||
                     (NameHasValue && IdHasValue &&
                     TY_(tmbstrcmp)(name->value, id->value) != 0 ) )
                    TY_(ReportAttrError)( doc, node, name, ID_NAME_MISMATCH);
            }
            else if (name && wantId)
            {
                if (TY_(NodeAttributeVersions)( node, TidyAttr_ID )
                    & doc->lexer->versionEmitted)
                {
                    if (TY_(IsValidHTMLID)(name->value))
                    {
                        TY_(RepairAttrValue)(doc, node, "id", name->value);
                        IdEmitted = yes;
                    }
                    else
                        TY_(ReportAttrError)(doc, node, name, INVALID_XML_ID);
                 }
            }
            else if (id && wantName)
            {
                if (TY_(NodeAttributeVersions)( node, TidyAttr_NAME )
                    & doc->lexer->versionEmitted)
                {
                    /* todo: do not assume id is valid */
                    TY_(RepairAttrValue)(doc, node, "name", id->value);
                    NameEmitted = yes;
                }
            }

            if (id && !wantId
                /* make sure that Name has been emitted if requested */
                && (hadName || !wantName || NameEmitted) ) {
                if (!wantId && !wantName)
                    TY_(RemoveAnchorByNode)(doc, id->value, node);
                TY_(RemoveAttribute)(doc, node, id);
            }

            if (name && !wantName
                /* make sure that Id has been emitted if requested */
                && (hadId || !wantId || IdEmitted) ) {
                if (!wantId && !wantName)
                    TY_(RemoveAnchorByNode)(doc, name->value, node);
                TY_(RemoveAttribute)(doc, node, name);
            }
        }

        if (node->content)
            TY_(FixAnchors)(doc, node->content, wantName, wantId);

        node = next;
    }
}

/* Issue #567 - move style elements from body to head 
 * ==================================================
 */
static void StyleToHead(TidyDocImpl* doc, Node *head, Node *node, Bool fix, int indent)
{
	Node *next;
	while (node)
	{
		next = node->next;	/* get 'next' now , in case the node is moved */
		/* dbg_show_node(doc, node, 0, indent); */
		if (nodeIsSTYLE(node))
		{
			if (fix)
			{
				TY_(RemoveNode)(node); /* unhook style node from body */
				TY_(InsertNodeAtEnd)(head, node);   /* add to end of head */
				TY_(Report)(doc, node, head, MOVED_STYLE_TO_HEAD); /* report move */
			}
			else
			{
				TY_(Report)(doc, node, head, FOUND_STYLE_IN_BODY);
			}
		}
		else if (node->content)
		{
			StyleToHead(doc, head, node->content, fix, indent + 1);
		}
		node = next;	/* process the 'next', if any */
	}
}


void TY_(CleanStyle)(TidyDocImpl* doc, Node *html)
{
    Node *head = NULL, *body = NULL;
    Bool fix = cfgBool(doc, TidyStyleTags);

    if (!html)
        return; /* oops, not given a start node */

    head = TY_(FindHEAD)( doc );
    body = TY_(FindBody)( doc );

    if ((head != NULL) && (body != NULL))
    {
		StyleToHead(doc, head, body, fix, 0); /* found head and body */
    }
}
/* ==================================================
 */

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* config.c
 * Read configuration files and manage configuration properties.
 *
 * Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
 * Institute of Technology, European Research Consortium for Informatics
 * and Mathematics, Keio University) and HTACG.
 *
 * See tidy.h for the copyright notice.
 */

/* #include "config.h" */
/* #include "tidy-int.h" */
/* #include "message.h" */
/* #include "tmbstr.h" */
/* #include "tags.h" */

#ifdef WINDOWS_OS
#  include <io.h>
#else
#  ifdef DMALLOC
   /* macro for valloc() in dmalloc.h may conflict with declaration for valloc()
      in unistd.h - we don't need (debugging for) valloc() here. dmalloc.h should
      come last but it doesn't.*/
#    ifdef valloc
#      undef valloc
#    endif
#  endif
#  include <unistd.h>
#endif


/*****************************************************************************
 ** Picklist Configuration
 **
 ** Arrange so index can be cast to enum. Note that the value field in the
 ** following structures is not currently used in code; they're present for
 ** documentation purposes currently. The arrays must be populated in enum
 ** order.
 ******************************************************************************/

static PickListItems boolPicks = {
    { "no",  TidyNoState,  { "0", "n", "f", "no",  "false", NULL } },
    { "yes", TidyYesState, { "1", "y", "t", "yes", "true",  NULL } },
    { NULL }
};

static PickListItems autoBoolPicks = {
    { "no",   TidyNoState,   { "0", "n", "f", "no",  "false", NULL } },
    { "yes",  TidyYesState,  { "1", "y", "t", "yes", "true",  NULL } },
    { "auto", TidyAutoState, { "auto",                        NULL } },
    { NULL }
};

static PickListItems repeatAttrPicks = {
    { "keep-first", TidyNoState,  { "keep-first", NULL } },
    { "keep-last",  TidyYesState, { "keep-last",  NULL } },
    { NULL }
};

static PickListItems accessPicks = {
    { "0 (Tidy Classic)",      0, { "0", "0 (Tidy Classic)",      NULL } },
    { "1 (Priority 1 Checks)", 1, { "1", "1 (Priority 1 Checks)", NULL } },
    { "2 (Priority 2 Checks)", 2, { "2", "2 (Priority 2 Checks)", NULL } },
    { "3 (Priority 3 Checks)", 3, { "3", "3 (Priority 3 Checks)", NULL } },
    { NULL }
};

static PickListItems charEncPicks = {
    { "raw",      TidyEncRaw,      { "raw",      NULL } },
    { "ascii",    TidyEncAscii,    { "ascii",    NULL } },
    { "latin0",   TidyEncLatin0,   { "latin0",   NULL } },
    { "latin1",   TidyEncLatin1,   { "latin1",   NULL } },
    { "utf8",     TidyEncUtf8,     { "utf8",     NULL } },
#ifndef NO_NATIVE_ISO2022_SUPPORT
    { "iso2022",  TidyEncIso2022,  { "iso2022",  NULL } },
#endif
    { "mac",      TidyEncMac,      { "mac",      NULL } },
    { "win1252",  TidyEncWin1252,  { "win1252",  NULL } },
    { "ibm858",   TidyEncIbm858,   { "ibm858",   NULL } },
    { "utf16le",  TidyEncUtf16le,  { "utf16le",  NULL } },
    { "utf16be",  TidyEncUtf16be,  { "utf16be",  NULL } },
    { "utf16",    TidyEncUtf16,    { "utf16",    NULL } },
    { "big5",     TidyEncBig5,     { "big5",     NULL } },
    { "shiftjis", TidyEncShiftjis, { "shiftjis", NULL } },
    { NULL }
};

static PickListItems newlinePicks = {
    { "'\n'",   TidyLF,   { "lf",   NULL } },
    { "CRLF", TidyCRLF, { "crlf", NULL } },
    { "'\r'",   TidyCR,   { "cr",   NULL } },
    { NULL }
};

static PickListItems doctypePicks = {
    { "html5",        TidyDoctypeHtml5,  { "html5",                 NULL } },
    { "omit",         TidyDoctypeOmit,   { "omit",                  NULL } },
    { "auto",         TidyDoctypeAuto,   { "auto",                  NULL } },
    { "strict",       TidyDoctypeStrict, { "strict",                NULL } },
    { "transitional", TidyDoctypeLoose,  { "loose", "transitional", NULL } },
    { "user",         TidyDoctypeUser,   { "user",                  NULL } },
    { NULL }
};

static PickListItems sorterPicks = {
    { "none",  TidySortAttrNone,  { "none",  NULL } },
    { "alpha", TidySortAttrAlpha, { "alpha", NULL } },
    { NULL }
};

static PickListItems customTagsPicks = {
    {"no",         TidyCustomNo,         { "no", "n",            NULL } },
    {"blocklevel", TidyCustomBlocklevel, { "blocklevel",         NULL } },
    {"empty",      TidyCustomEmpty,      { "empty",              NULL } },
    {"inline",     TidyCustomInline,     { "inline", "y", "yes", NULL } },
    {"pre",        TidyCustomPre,        { "pre",                NULL } },
    { NULL }
};

static PickListItems attributeCasePicks = {
    { "no",       TidyUppercaseNo,       { "0", "n", "f", "no",  "false", NULL } },
    { "yes",      TidyUppercaseYes,      { "1", "y", "t", "yes", "true",  NULL } },
    { "preserve", TidyUppercasePreserve, { "preserve",                    NULL } },
    { NULL }
};


/*****************************************************************************
 ** Option Configuration
 ******************************************************************************/

#define DG TidyDiagnostics
#define DD TidyDisplay
#define DT TidyDocumentIO
#define CE TidyEncoding
#define IO TidyFileIO
#define MC TidyMarkupCleanup
#define ME TidyMarkupEntities
#define MR TidyMarkupRepair
#define MT TidyMarkupTeach
#define MX TidyMarkupXForm
#define PP TidyPrettyPrint
#define IR TidyInternalCategory

#define IN TidyInteger
#define BL TidyBoolean
#define ST TidyString

#define XX (TidyConfigCategory)-1
#define XY (TidyOptionType)-1

#define DLF DEFAULT_NL_CONFIG

/* forward declarations */
static ParseProperty ParseInt;
static ParseProperty ParseList;
static ParseProperty ParseName;
static ParseProperty ParseCSS1Selector;
static ParseProperty ParseString;
static ParseProperty ParseCharEnc;
static ParseProperty ParseDocType;
static ParseProperty ParseTabs;
static ParseProperty ParsePickList;

/*****************************************************************/
/* Ensure struct order is same order as tidyenum.h:TidyOptionId! */
/*****************************************************************/
static const TidyOptionImpl option_defs[] =
{
    { TidyUnknownOption,           IR, "unknown!",                    IN, 0,               NULL,              NULL                },
    { TidyAccessibilityCheckLevel, DG, "accessibility-check",         IN, 0,               ParsePickList,     &accessPicks        },
    { TidyAltText,                 MR, "alt-text",                    ST, 0,               ParseString,       NULL                },
    { TidyAnchorAsName,            MR, "anchor-as-name",              BL, yes,             ParsePickList,     &boolPicks          },
    { TidyAsciiChars,              ME, "ascii-chars",                 BL, no,              ParsePickList,     &boolPicks          },
    { TidyBlockTags,               MT, "new-blocklevel-tags",         ST, 0,               ParseList,         NULL                },
    { TidyBodyOnly,                DD, "show-body-only",              IN, no,              ParsePickList,     &autoBoolPicks      },
    { TidyBreakBeforeBR,           PP, "break-before-br",             BL, no,              ParsePickList,     &boolPicks          },
    { TidyCharEncoding,            CE, "char-encoding",               IN, UTF8,            ParseCharEnc,      &charEncPicks       },
    { TidyCoerceEndTags,           MR, "coerce-endtags",              BL, yes,             ParsePickList,     &boolPicks          },
    { TidyCSSPrefix,               MR, "css-prefix",                  ST, 0,               ParseCSS1Selector, NULL,           "c" },
    { TidyCustomTags,              IR, "new-custom-tags",             ST, 0,               ParseList,         NULL                }, /* 20170309 - Issue #119 */
    { TidyDecorateInferredUL,      MX, "decorate-inferred-ul",        BL, no,              ParsePickList,     &boolPicks          },
    { TidyDoctype,                 DT, "doctype",                     ST, TidyDoctypeAuto, ParseDocType,      &doctypePicks       },
#ifndef DOXYGEN_SHOULD_SKIP_THIS
    { TidyDoctypeMode,             IR, "doctype-mode",                IN, TidyDoctypeAuto, NULL,              &doctypePicks       },
#endif
    { TidyDropEmptyElems,          MC, "drop-empty-elements",         BL, yes,             ParsePickList,     &boolPicks          },
    { TidyDropEmptyParas,          MC, "drop-empty-paras",            BL, yes,             ParsePickList,     &boolPicks          },
    { TidyDropPropAttrs,           MC, "drop-proprietary-attributes", BL, no,              ParsePickList,     &boolPicks          },
    { TidyDuplicateAttrs,          MR, "repeated-attributes",         IN, TidyKeepLast,    ParsePickList,     &repeatAttrPicks    },
    { TidyEmacs,                   DD, "gnu-emacs",                   BL, no,              ParsePickList,     &boolPicks          },
#ifndef DOXYGEN_SHOULD_SKIP_THIS
    { TidyEmacsFile,               IR, "gnu-emacs-file",              ST, 0,               ParseString,       NULL                },
#endif
    { TidyEmptyTags,               MT, "new-empty-tags",              ST, 0,               ParseList,         NULL                },
    { TidyEncloseBlockText,        MR, "enclose-block-text",          BL, no,              ParsePickList,     &boolPicks          },
    { TidyEncloseBodyText,         MR, "enclose-text",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyErrFile,                 IO, "error-file",                  ST, 0,               ParseString,       NULL                },
    { TidyEscapeCdata,             MX, "escape-cdata",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyEscapeScripts,           MR, "escape-scripts",              BL, yes,             ParsePickList,     &boolPicks          }, /* 20160227 - Issue #348 */
    { TidyFixBackslash,            MR, "fix-backslash",               BL, yes,             ParsePickList,     &boolPicks          },
    { TidyFixComments,             MR, "fix-bad-comments",            IN, TidyAutoState,   ParsePickList,     &autoBoolPicks      },
    { TidyFixUri,                  MR, "fix-uri",                     BL, yes,             ParsePickList,     &boolPicks          },
    { TidyForceOutput,             DG, "force-output",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyGDocClean,               MC, "gdoc",                        BL, no,              ParsePickList,     &boolPicks          },
    { TidyHideComments,            MX, "hide-comments",               BL, no,              ParsePickList,     &boolPicks          },
    { TidyHtmlOut,                 DT, "output-html",                 BL, no,              ParsePickList,     &boolPicks          },
    { TidyInCharEncoding,          CE, "input-encoding",              IN, UTF8,            ParseCharEnc,      &charEncPicks       },
    { TidyIndentAttributes,        PP, "indent-attributes",           BL, no,              ParsePickList,     &boolPicks          },
    { TidyIndentCdata,             PP, "indent-cdata",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyIndentContent,           PP, "indent",                      IN, TidyNoState,     ParsePickList,     &autoBoolPicks      },
    { TidyIndentSpaces,            PP, "indent-spaces",               IN, 2,               ParseInt,          NULL                },
    { TidyInlineTags,              MT, "new-inline-tags",             ST, 0,               ParseList,         NULL                },
    { TidyJoinClasses,             MX, "join-classes",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyJoinStyles,              MX, "join-styles",                 BL, yes,             ParsePickList,     &boolPicks          },
    { TidyKeepFileTimes,           IO, "keep-time",                   BL, no,              ParsePickList,     &boolPicks          },
    { TidyKeepTabs,                PP, "keep-tabs",                   BL, no,              ParsePickList,     &boolPicks          }, /* 20171103 - Issue #403 */
    { TidyLiteralAttribs,          MR, "literal-attributes",          BL, no,              ParsePickList,     &boolPicks          },
    { TidyLogicalEmphasis,         MC, "logical-emphasis",            BL, no,              ParsePickList,     &boolPicks          },
    { TidyLowerLiterals,           MR, "lower-literals",              BL, yes,             ParsePickList,     &boolPicks          },
    { TidyMakeBare,                MC, "bare",                        BL, no,              ParsePickList,     &boolPicks          },
    { TidyMakeClean,               MC, "clean",                       BL, no,              ParsePickList,     &boolPicks          },
    { TidyMark,                    PP, "tidy-mark",                   BL, yes,             ParsePickList,     &boolPicks          },
    { TidyMergeDivs,               MC, "merge-divs",                  IN, TidyAutoState,   ParsePickList,     &autoBoolPicks      },
    { TidyMergeEmphasis,           MX, "merge-emphasis",              BL, yes,             ParsePickList,     &boolPicks          },
    { TidyMergeSpans,              MC, "merge-spans",                 IN, TidyAutoState,   ParsePickList,     &autoBoolPicks      },
    { TidyMetaCharset,             DT, "add-meta-charset",            BL, no,              ParsePickList,     &boolPicks          }, /* 20161004 - Issue #456 */
    { TidyMuteReports,             DD, "mute",                        ST, 0,               ParseList,         NULL                },
    { TidyMuteShow,                DD, "mute-id",                     BL, no,              ParsePickList,     &boolPicks          },
    { TidyNCR,                     ME, "ncr",                         BL, yes,             ParsePickList,     &boolPicks          },
    { TidyNewline,                 CE, "newline",                     IN, DLF,             ParsePickList,     &newlinePicks       },
    { TidyNumEntities,             ME, "numeric-entities",            BL, no,              ParsePickList,     &boolPicks          },
    { TidyOmitOptionalTags,        PP, "omit-optional-tags",          BL, no,              ParsePickList,     &boolPicks          },
    { TidyOutCharEncoding,         CE, "output-encoding",             IN, UTF8,            ParseCharEnc,      &charEncPicks       },
    { TidyOutFile,                 IO, "output-file",                 ST, 0,               ParseString,       NULL                },
    { TidyOutputBOM,               CE, "output-bom",                  IN, TidyAutoState,   ParsePickList,     &autoBoolPicks      },
    { TidyPPrintTabs,              PP, "indent-with-tabs",            BL, no,              ParseTabs,         &boolPicks          }, /* 20150515 - Issue #108 */
    { TidyPreserveEntities,        ME, "preserve-entities",           BL, no,              ParsePickList,     &boolPicks          },
    { TidyPreTags,                 MT, "new-pre-tags",                ST, 0,               ParseList,         NULL                },
    { TidyPriorityAttributes,      PP, "priority-attributes",         ST, 0,               ParseList,         NULL                },
    { TidyPunctWrap,               PP, "punctuation-wrap",            BL, no,              ParsePickList,     &boolPicks          },
    { TidyQuiet,                   DD, "quiet",                       BL, no,              ParsePickList,     &boolPicks          },
    { TidyQuoteAmpersand,          ME, "quote-ampersand",             BL, yes,             ParsePickList,     &boolPicks          },
    { TidyQuoteMarks,              ME, "quote-marks",                 BL, no,              ParsePickList,     &boolPicks          },
    { TidyQuoteNbsp,               ME, "quote-nbsp",                  BL, yes,             ParsePickList,     &boolPicks          },
    { TidyReplaceColor,            MX, "replace-color",               BL, no,              ParsePickList,     &boolPicks          },
    { TidyShowErrors,              DD, "show-errors",                 IN, 6,               ParseInt,          NULL                },
    { TidyShowFilename,            DD, "show-filename",               BL, no,              ParsePickList,     &boolPicks          },
    { TidyShowInfo,                DD, "show-info",                   BL, yes,             ParsePickList,     &boolPicks          },
    { TidyShowMarkup,              DD, "markup",                      BL, yes,             ParsePickList,     &boolPicks          },
    { TidyShowMetaChange,          DG, "show-meta-change",            BL, no,              ParsePickList,     &boolPicks          }, /* 20170609 - Issue #456 */
    { TidyShowWarnings,            DD, "show-warnings",               BL, yes,             ParsePickList,     &boolPicks          },
    { TidySkipNested,              MR, "skip-nested",                 BL, yes,             ParsePickList,     &boolPicks          }, /* 1642186 - Issue #65 */
    { TidySortAttributes,          PP, "sort-attributes",             IN, TidySortAttrNone,ParsePickList,     &sorterPicks        },
    { TidyStrictTagsAttr,          MR, "strict-tags-attributes",      BL, no,              ParsePickList,     &boolPicks          }, /* 20160209 - Issue #350 */
    { TidyStyleTags,               MR, "fix-style-tags",              BL, yes,             ParsePickList,     &boolPicks          },
    { TidyTabSize,                 PP, "tab-size",                    IN, 8,               ParseInt,          NULL                },
    { TidyUpperCaseAttrs,          MR, "uppercase-attributes",        IN, TidyUppercaseNo, ParsePickList,     &attributeCasePicks },
    { TidyUpperCaseTags,           MR, "uppercase-tags",              BL, no,              ParsePickList,     &boolPicks          },
    { TidyUseCustomTags,           MR, "custom-tags",                 IN, TidyCustomNo,    ParsePickList,     &customTagsPicks    }, /* 20170309 - Issue #119 */
    { TidyVertSpace,               PP, "vertical-space",              IN, no,              ParsePickList,     &autoBoolPicks      }, /* #228 - tri option */
    { TidyWarnPropAttrs,           DG, "warn-proprietary-attributes", BL, yes,             ParsePickList,     &boolPicks          },
    { TidyWord2000,                MC, "word-2000",                   BL, no,              ParsePickList,     &boolPicks          },
    { TidyWrapAsp,                 PP, "wrap-asp",                    BL, yes,             ParsePickList,     &boolPicks          },
    { TidyWrapAttVals,             PP, "wrap-attributes",             BL, no,              ParsePickList,     &boolPicks          },
    { TidyWrapJste,                PP, "wrap-jste",                   BL, yes,             ParsePickList,     &boolPicks          },
    { TidyWrapLen,                 PP, "wrap",                        IN, 68,              ParseInt,          NULL                },
    { TidyWrapPhp,                 PP, "wrap-php",                    BL, yes,             ParsePickList,     &boolPicks          },
    { TidyWrapScriptlets,          PP, "wrap-script-literals",        BL, no,              ParsePickList,     &boolPicks          },
    { TidyWrapSection,             PP, "wrap-sections",               BL, yes,             ParsePickList,     &boolPicks          },
    { TidyWriteBack,               IO, "write-back",                  BL, no,              ParsePickList,     &boolPicks          },
    { TidyXhtmlOut,                DT, "output-xhtml",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyXmlDecl,                 DT, "add-xml-decl",                BL, no,              ParsePickList,     &boolPicks          },
    { TidyXmlOut,                  DT, "output-xml",                  BL, no,              ParsePickList,     &boolPicks          },
    { TidyXmlPIs,                  MR, "assume-xml-procins",          BL, no,              ParsePickList,     &boolPicks          },
    { TidyXmlSpace,                DT, "add-xml-space",               BL, no,              ParsePickList,     &boolPicks          },
    { TidyXmlTags,                 DT, "input-xml",                   BL, no,              ParsePickList,     &boolPicks          },
    { N_TIDY_OPTIONS,              XX, NULL,                          XY, 0,               NULL,              NULL                }
};


/*****************************************************************************
 ** Deleted Options Configuration
 **
 ** Keep track of options that have been removed from Tidy, so that we can
 ** suggests a replacement. When a deleted option is used, client programs
 ** will have the opportunity to consume the option first via the callback,
 ** and if not handled by the callback, will be handled by Tidy, generally
 ** by setting an alternate or new option, in `subDeprecatedOption()`.
 ******************************************************************************/

static const struct {
    ctmbstr name;                /**< name of the deprecated option */
    TidyOptionId replacementId;  /**< Id of the replacement option, or 0 if none. */
} deprecatedOptions[] = {
/*    { "show-body-only", TidyBodyOnly }, */
    { NULL }
};


/*****************************************************************************
 ** Supporting Functions
 ******************************************************************************/


/* forward declarations */
static void AdjustConfig( TidyDocImpl* doc );
static Bool GetPickListValue( ctmbstr value, PickListItems* pickList, unsigned int *result );


void TY_(InitConfig)( TidyDocImpl* doc )
{
    TidyClearMemory( &doc->config, sizeof(TidyConfigImpl) );
    TY_(ResetConfigToDefault)( doc );
}


void TY_(FreeConfig)( TidyDocImpl* doc )
{
    doc->pConfigChangeCallback = NULL;
    TY_(ResetConfigToDefault)( doc );
    TY_(TakeConfigSnapshot)( doc );
}


/* Should only be called by options set by name
** thus, it is cheaper to do a few scans than set
** up every option in a hash table.
*/
const TidyOptionImpl* TY_(lookupOption)( ctmbstr s )
{
    const TidyOptionImpl* np = option_defs;
    for ( /**/; np < option_defs + N_TIDY_OPTIONS; ++np )
    {
        if ( TY_(tmbstrcasecmp)(s, np->name) == 0 )
            return np;
    }
    return NULL;
}


const TidyOptionImpl* TY_(getOption)( TidyOptionId optId )
{
  if ( optId < N_TIDY_OPTIONS )
      return option_defs + optId;
  return NULL;
}

const Bool TY_(getOptionIsList)( TidyOptionId optId )
{
    const TidyOptionImpl* option = TY_(getOption)( optId );
    return option->parser == ParseList;
}

static Bool OptionChangedValuesDiffer( ctmbstr a, ctmbstr b )
{
    if ( a != b )
    {
        if ( a == NULL || b == NULL ) /* can't both be null at this point. */
            return yes;
        else
            return TY_(tmbstrcmp)( a, b ) != 0;
    }

    return no;
}

static void PerformOptionChangedCallback( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    if ( doc->pConfigChangeCallback )
    {
        TidyDoc tdoc = tidyImplToDoc( doc );
        TidyOption opt = tidyImplToOption( option );
        doc->pConfigChangeCallback( tdoc, opt );
    }
}

static void FreeOptionValue( TidyDocImpl* doc, const TidyOptionImpl* option, TidyOptionValue* value )
{
    if ( option->type == TidyString && value->p && value->p != option->pdflt )
        TidyDocFree( doc, value->p );
}


static void CopyOptionValue( TidyDocImpl* doc, const TidyOptionImpl* option,
                             TidyOptionValue* oldval, const TidyOptionValue* newval )
{
    Bool fire_callback = no;
    assert( oldval != NULL );

    /* Compare the old and new values. */
    if ( doc->pConfigChangeCallback )
    {
        if ( option->type == TidyString )
            fire_callback = OptionChangedValuesDiffer( oldval->p, newval->p );
        else
            fire_callback = oldval->v != newval->v;
    }

    FreeOptionValue( doc, option, oldval );

    if ( option->type == TidyString )
    {
        if ( newval->p && newval->p != option->pdflt )
            oldval->p = TY_(tmbstrdup)( doc->allocator, newval->p );
        else
            oldval->p = newval->p;
    }
    else
        oldval->v = newval->v;

    if ( fire_callback )
        PerformOptionChangedCallback( doc, option );
}


static Bool SetOptionValue( TidyDocImpl* doc, TidyOptionId optId, ctmbstr val )
{
    const TidyOptionImpl* option = &option_defs[ optId ];
    Bool fire_callback = no;
    Bool status = ( optId < N_TIDY_OPTIONS );

    if ( status )
    {
        assert( option->id == optId && option->type == TidyString );

        /* Compare the old and new values. */
        if ( doc->pConfigChangeCallback )
        {
            TidyOptionValue* oldval = &(doc->config.value[ optId ]);
            fire_callback = OptionChangedValuesDiffer( oldval->p, val );
        }

        FreeOptionValue( doc, option, &doc->config.value[ optId ] );
        if ( TY_(tmbstrlen)(val)) /* Issue #218 - ONLY if it has LENGTH! */
            doc->config.value[ optId ].p = TY_(tmbstrdup)( doc->allocator, val );
        else
            doc->config.value[ optId ].p = 0; /* should already be zero, but to be sure... */
    }

    if ( fire_callback )
        PerformOptionChangedCallback( doc, option );

    return status;
}


ctmbstr TY_(GetPickListLabelForPick)( TidyOptionId optId, unsigned int pick )
{
    const TidyOptionImpl* option = TY_(getOption)( optId );

    if ( option && option->pickList )
    {
        unsigned int ix = 0;
        const PickListItem *item = NULL;

        /* Loop through the picklist until index matches the value. */
        while ( (item = &(*option->pickList)[ ix ]) && item->label && ix<pick )
        {
            ++ix;
        }
        if ( ix==pick && item->label )
            return item->label;
    }

    return NULL;
}


static void SetOptionInteger( TidyDocImpl* doc, TidyOptionId optId, unsigned int val )
{
    const TidyOptionImpl* option = &option_defs[ optId ];
    unsigned int* optVal = &(doc->config.value[ optId ].v);
    Bool fire_callback = doc->pConfigChangeCallback && *optVal != val;

    *optVal = val;

    if ( fire_callback )
        PerformOptionChangedCallback( doc, option );
}

Bool TY_(SetOptionInt)( TidyDocImpl* doc, TidyOptionId optId, unsigned int val )
{
    Bool status = ( optId < N_TIDY_OPTIONS );
    if ( status )
    {
        assert( option_defs[ optId ].type == TidyInteger );
        SetOptionInteger( doc, optId, val );
    }
    return status;
}


Bool TY_(SetOptionBool)( TidyDocImpl* doc, TidyOptionId optId, Bool val )
{
    Bool status = ( optId < N_TIDY_OPTIONS );
    if ( status )
    {
        assert( option_defs[ optId ].type == TidyBoolean );
        SetOptionInteger( doc, optId, (unsigned int)val );
    }
    return status;
}


static void GetOptionDefault( const TidyOptionImpl* option,
                              TidyOptionValue* dflt )
{
    if ( option->type == TidyString )
        dflt->p = (char*)option->pdflt;
    else
        dflt->v = option->dflt;
}


static Bool OptionValueEqDefault( const TidyOptionImpl* option,
                                  const TidyOptionValue* val )
{
    return ( option->type == TidyString ) ?
        val->p == option->pdflt :
        val->v == option->dflt;
}


Bool TY_(ResetOptionToDefault)( TidyDocImpl* doc, TidyOptionId optId )
{
    Bool status = ( optId > 0 && optId < N_TIDY_OPTIONS );
    if ( status )
    {
        TidyOptionValue dflt;
        const TidyOptionImpl* option = option_defs + optId;
        TidyOptionValue* value = &doc->config.value[ optId ];
        assert( optId == option->id );
        GetOptionDefault( option, &dflt );
        CopyOptionValue( doc, option, value, &dflt );
    }
    return status;
}


static void ReparseTagType( TidyDocImpl* doc, TidyOptionId optId )
{
    ctmbstr tagdecl = cfgStr( doc, optId );
    tmbstr dupdecl = TY_(tmbstrdup)( doc->allocator, tagdecl );
    TY_(ParseConfigValue)( doc, optId, dupdecl );
    TidyDocFree( doc, dupdecl );
}


static Bool OptionValueIdentical( const TidyOptionImpl* option,
                                  const TidyOptionValue* val1,
                                  const TidyOptionValue* val2 )
{
    if ( option->type == TidyString )
    {
        if ( val1->p == val2->p )
            return yes;
        if ( !val1->p || !val2->p )
            return no;
        return TY_(tmbstrcmp)( val1->p, val2->p ) == 0;
    }
    else
        return val1->v == val2->v;
}


static Bool NeedReparseTagDecls( TidyDocImpl* doc,
                                 const TidyOptionValue* current,
                                 const TidyOptionValue* new,
                                 unsigned int *changedUserTags )
{
    Bool ret = no;
    unsigned int ixVal;
    const TidyOptionImpl* option = option_defs;
    *changedUserTags = tagtype_null;

    for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
    {
        assert( ixVal == (unsigned int) option->id );
        switch (option->id)
        {
#define TEST_USERTAGS(USERTAGOPTION,USERTAGTYPE) \
        case USERTAGOPTION: \
            if (!OptionValueIdentical(option,&current[ixVal],&new[ixVal])) \
            { \
                *changedUserTags |= USERTAGTYPE; \
                ret = yes; \
            } \
            break
            TEST_USERTAGS(TidyInlineTags,tagtype_inline);
            TEST_USERTAGS(TidyBlockTags,tagtype_block);
            TEST_USERTAGS(TidyEmptyTags,tagtype_empty);
            TEST_USERTAGS(TidyPreTags,tagtype_pre);
        default:
            break;
        }
    }
    return ret;
}


static void ReparseTagDecls( TidyDocImpl* doc, unsigned int changedUserTags  )
{
#define REPARSE_USERTAGS(USERTAGOPTION,USERTAGTYPE) \
    if ( changedUserTags & USERTAGTYPE ) \
    { \
        TY_(FreeDeclaredTags)( doc, USERTAGTYPE ); \
        ReparseTagType( doc, USERTAGOPTION ); \
    }
    REPARSE_USERTAGS(TidyInlineTags,tagtype_inline);
    REPARSE_USERTAGS(TidyBlockTags,tagtype_block);
    REPARSE_USERTAGS(TidyEmptyTags,tagtype_empty);
    REPARSE_USERTAGS(TidyPreTags,tagtype_pre);
}


/*  Returns the option id of the replacement Tidy option for optName. Because
 ** an option might not have a replacement (0, TidyUnknownOption), a return
 ** value of N_TIDY_OPTIONS indicates an error, i.e., that the option isn't
 ** in the deprecated list.
 */
static TidyOptionId getOptionReplacement( ctmbstr optName )
{
    unsigned int i = 0;
    ctmbstr testName;
    while ( (testName = deprecatedOptions[i].name) )
    {
        if ( TY_(tmbstrcasecmp)( optName, testName ) == 0 )
            return deprecatedOptions[i].replacementId;

        i++;
    }
    return N_TIDY_OPTIONS;
}


/* Indicates whether or not optName is deprecated */
static Bool isOptionDeprecated( ctmbstr optName )
{
    return getOptionReplacement( optName ) != N_TIDY_OPTIONS;
}


/* Substitute the new option for the deprecated one. */
static Bool subDeprecatedOption( TidyDocImpl* doc, ctmbstr oldName, ctmbstr oldValue)
{
    TidyOptionId newOptId = getOptionReplacement( oldName );
    ctmbstr newName = TY_(getOption)( newOptId )->name;
    TidyDoc tdoc = tidyImplToDoc( doc );

    assert( isOptionDeprecated(oldName));

    if ( newOptId == TidyUnknownOption )
    {
        TY_(Report)( doc, NULL, NULL, OPTION_REMOVED, oldName );
        return no;
    }

    /********************/
    /* `show-body-only` */
    /********************/
    if ( TY_(tmbstrcasecmp)( oldName, "show-body-only" ) == 0 )
    {
        unsigned int value;

        /* `show-body-only` used to use the autoBoolPicks */
        if ( GetPickListValue( oldValue, &autoBoolPicks, &value ) )
        {
            if ( value == TidyNoState )
            {
                TY_(SetOptionInt)( doc, newOptId, value );
                TY_(Report)( doc, NULL, NULL, OPTION_REMOVED_UNAPPLIED, oldName, newName );
            }
            else
            {
                ctmbstr val;
                TY_(SetOptionInt)( doc, newOptId, value );
                val = tidyOptGetCurrPick( tdoc, newOptId );
                TY_(Report)( doc, NULL, NULL, OPTION_REMOVED_APPLIED, oldName, newName, val );
            }
        }
        else
        {
            TY_(ReportBadArgument)(doc, oldName);
        }
        return yes;
    }

    return no;
}


void TY_(ResetConfigToDefault)( TidyDocImpl* doc )
{
    unsigned int ixVal;
    const TidyOptionImpl* option = option_defs;
    TidyOptionValue* value = &doc->config.value[ 0 ];
    for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
    {
        TidyOptionValue dflt;
        assert( ixVal == (unsigned int) option->id );
        GetOptionDefault( option, &dflt );
        CopyOptionValue( doc, option, &value[ixVal], &dflt );
    }
    TY_(FreeDeclaredTags)( doc, tagtype_null );
}


void TY_(TakeConfigSnapshot)( TidyDocImpl* doc )
{
    unsigned int ixVal;
    const TidyOptionImpl* option = option_defs;
    const TidyOptionValue* value = &doc->config.value[ 0 ];
    TidyOptionValue* snap  = &doc->config.snapshot[ 0 ];

    AdjustConfig( doc );  /* Make sure it's consistent */
    for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
    {
        assert( ixVal == (unsigned int) option->id );
        CopyOptionValue( doc, option, &snap[ixVal], &value[ixVal] );
    }
}


void TY_(ResetConfigToSnapshot)( TidyDocImpl* doc )
{
    unsigned int ixVal;
    const TidyOptionImpl* option = option_defs;
    TidyOptionValue* value = &doc->config.value[ 0 ];
    const TidyOptionValue* snap  = &doc->config.snapshot[ 0 ];
    unsigned int changedUserTags;
    Bool needReparseTagsDecls = NeedReparseTagDecls( doc, value, snap,
                                                     &changedUserTags );
    
    for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
    {
        assert( ixVal == (unsigned int) option->id );
        CopyOptionValue( doc, option, &value[ixVal], &snap[ixVal] );
    }
    if ( needReparseTagsDecls )
        ReparseTagDecls( doc, changedUserTags );
}


void TY_(CopyConfig)( TidyDocImpl* docTo, TidyDocImpl* docFrom )
{
    if ( docTo != docFrom )
    {
        unsigned int ixVal;
        const TidyOptionImpl* option = option_defs;
        const TidyOptionValue* from = &docFrom->config.value[ 0 ];
        TidyOptionValue* to   = &docTo->config.value[ 0 ];
        unsigned int changedUserTags;
        Bool needReparseTagsDecls = NeedReparseTagDecls( docTo, to, from,
                                                         &changedUserTags );

        TY_(TakeConfigSnapshot)( docTo );
        for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
        {
            assert( ixVal == (unsigned int) option->id );
            CopyOptionValue( docTo, option, &to[ixVal], &from[ixVal] );
        }
        if ( needReparseTagsDecls )
            ReparseTagDecls( docTo, changedUserTags  );
        AdjustConfig( docTo );  /* Make sure it's consistent */
    }
}


#ifdef _DEBUG

/* Debug accessor functions will be type-safe and assert option type match */
unsigned int   TY_(_cfgGet)( TidyDocImpl* doc, TidyOptionId optId )
{
  assert( optId < N_TIDY_OPTIONS );
  return doc->config.value[ optId ].v;
}

Bool    TY_(_cfgGetBool)( TidyDocImpl* doc, TidyOptionId optId )
{
  unsigned int val = TY_(_cfgGet)( doc, optId );
  const TidyOptionImpl* opt = &option_defs[ optId ];
  assert( opt && opt->type == TidyBoolean );
  return (Bool) val;
}

TidyTriState    TY_(_cfgGetAutoBool)( TidyDocImpl* doc, TidyOptionId optId )
{
  unsigned int val = TY_(_cfgGet)( doc, optId );
  const TidyOptionImpl* opt = &option_defs[ optId ];
  assert( opt && opt->type == TidyInteger
          && opt->parser == ParsePickList );
  return (TidyTriState) val;
}

ctmbstr TY_(_cfgGetString)( TidyDocImpl* doc, TidyOptionId optId )
{
  const TidyOptionImpl* opt;

  assert( optId < N_TIDY_OPTIONS );
  opt = &option_defs[ optId ];
  assert( opt && opt->type == TidyString );
  return doc->config.value[ optId ].p;
}
#endif


static tchar GetC( TidyConfigImpl* config )
{
    if ( config->cfgIn )
        return TY_(ReadChar)( config->cfgIn );
    return EndOfStream;
}


static tchar FirstChar( TidyConfigImpl* config )
{
    config->c = GetC( config );
    return config->c;
}


static tchar AdvanceChar( TidyConfigImpl* config )
{
    if ( config->c != EndOfStream )
        config->c = GetC( config );
    return config->c;
}


static tchar SkipWhite( TidyConfigImpl* config )
{
    while ( TY_(IsWhite)(config->c) && !TY_(IsNewline)(config->c) )
        config->c = GetC( config );
    return config->c;
}


/* skip over line continuations to start of next property */
static unsigned int NextProperty( TidyConfigImpl* config )
{
    do
    {
        /* skip to end of line */
        while ( config->c != '\n' &&  config->c != '\r' &&  config->c != EndOfStream )
             config->c = GetC( config );

        /* treat  \r\n   \r  or  \n as line ends */
        if ( config->c == '\r' )
             config->c = GetC( config );

        if ( config->c == '\n' )
            config->c = GetC( config );
    }
    while ( TY_(IsWhite)(config->c) );  /* line continuation? */

    return config->c;
}


/*
 Todd Lewis contributed this code for expanding ~/foo or ~your/foo according
 to $HOME and your user name. This will work partially on any system which
 defines $HOME. Support for ~user/foo will work on systems that support
 getpwnam(userid), namely Unix/Linux.
*/
static ctmbstr ExpandTilde( TidyDocImpl* doc, ctmbstr filename )
{
    char *home_dir = NULL;

    if ( !filename )
        return NULL;

    if ( filename[0] != '~' )
        return filename;

    if (filename[1] == '/')
    {
        home_dir = getenv("HOME");
        if (home_dir) {
            ++filename;
        }
#ifdef _WIN32
        else if (strlen(filename) >= 3) {   /* at least '~/+1' */
            /* no HOME env in Windows - got for HOMEDRIVE=C: HOMEPATH=\Users\user */
            char * hd = getenv("HOMEDRIVE");
            char * hp = getenv("HOMEPATH");
            if (hd && hp) {
                ctmbstr s = TidyDocAlloc(doc, _MAX_PATH);
                strcpy(s, hd);
                strcat(s, hp);
                strcat(s, "\\");
                strcat(s, &filename[2]);
                return s;
            }

        }
#endif /* _WIN32 */

    }
#ifdef SUPPORT_GETPWNAM
    else
    {
        struct passwd *passwd = NULL;
        ctmbstr s = filename + 1;
        tmbstr t;

        while ( *s && *s != '/' )
            s++;

        if ( (t = TidyDocAlloc(doc, s - filename)) )
        {
            memcpy(t, filename+1, s-filename-1);
            t[s-filename-1] = 0;

            passwd = getpwnam(t);

            TidyDocFree(doc, t);
        }

        if ( passwd )
        {
            filename = s;
            home_dir = passwd->pw_dir;
        }
    }
#endif /* SUPPORT_GETPWNAM */

    if ( home_dir )
    {
        unsigned int len = TY_(tmbstrlen)(filename) + TY_(tmbstrlen)(home_dir) + 1;
        tmbstr p = (tmbstr)TidyDocAlloc( doc, len );
        TY_(tmbstrcpy)( p, home_dir );
        TY_(tmbstrcat)( p, filename );
        return (ctmbstr) p;
    }
    return (ctmbstr) filename;
}


Bool TIDY_CALL tidyFileExists( TidyDoc tdoc, ctmbstr filename )
{
  TidyDocImpl* doc = tidyDocToImpl( tdoc );
  ctmbstr fname = (tmbstr) ExpandTilde( doc, filename );
#ifndef NO_ACCESS_SUPPORT
  Bool exists = ( access(fname, 0) == 0 );
#else
  Bool exists;
  /* at present */
  FILE* fin = fopen(fname, "r");
  if (fin != NULL)
      fclose(fin);
  exists = ( fin != NULL );
#endif
  if ( fname != filename )
      TidyDocFree( doc, (tmbstr) fname );
  return exists;
}


int TY_(ParseConfigFile)( TidyDocImpl* doc, ctmbstr file )
{
    return TY_(ParseConfigFileEnc)( doc, file, "ascii" );
}

/* open the file and parse its contents
*/
int TY_(ParseConfigFileEnc)( TidyDocImpl* doc, ctmbstr file, ctmbstr charenc )
{
    enum { tidy_max_name = 64 };
    unsigned int opterrs = doc->optionErrors;
    tmbstr fname = (tmbstr) ExpandTilde( doc, file );
    TidyConfigImpl* cfg = &doc->config;
    FILE* fin = fopen( fname, "r" );
    int enc = TY_(CharEncodingId)( doc, charenc );

    if ( fin == NULL || enc < 0 )
    {
        TY_(ReportFileError)( doc, fname, FILE_CANT_OPEN_CFG );
        return -1;
    }
    else
    {
        tchar c;
        cfg->cfgIn = TY_(FileInput)( doc, fin, enc );
        c = FirstChar( cfg );
       
        for ( c = SkipWhite(cfg); c != EndOfStream; c = NextProperty(cfg) )
        {
            unsigned int ix = 0;
            tmbchar name[ tidy_max_name ] = {0};

            /* // or # start a comment */
            if ( c == '/' || c == '#' )
                continue;

            while ( ix < sizeof(name)-1 && c != '\n' && c != EndOfStream && c != ':' )
            {
                name[ ix++ ] = (tmbchar) c;  /* Option names all ASCII */
                c = AdvanceChar( cfg );
            }

            if ( c == ':' )
            {
                Bool isDeprecated = isOptionDeprecated( name );
                const TidyOptionImpl* option = TY_(lookupOption)( name );
                c = AdvanceChar( cfg );
                if ( option && !isDeprecated )
                    option->parser( doc, option );
                else
                {
                    if ( (NULL != doc->pOptCallback) || (NULL != doc->pConfigCallback) || isDeprecated )
                    {
                        TidyConfigImpl* cfg = &doc->config;
                        tmbchar buf[8192];
                        unsigned int i = 0;
                        tchar delim = 0;
                        Bool waswhite = yes;
                        Bool response = no;

                        tchar c = SkipWhite( cfg );

                        if ( c == '"' || c == '\'' )
                        {
                            delim = c;
                            c = AdvanceChar( cfg );
                        }

                        while ( i < sizeof(buf)-2 && c != EndOfStream && c != '\r' && c != '\n' )
                        {
                            if ( delim && c == delim )
                                break;

                            if ( TY_(IsWhite)(c) )
                            {
                                if ( waswhite )
                                {
                                    c = AdvanceChar( cfg );
                                    continue;
                                }
                                c = ' ';
                            }
                            else
                                waswhite = no;

                            buf[i++] = (tmbchar) c;
                            c = AdvanceChar( cfg );
                        }
                        buf[i] = '\0';
                        
                        if ( doc->pOptCallback )
                            response = (*doc->pOptCallback)( name, buf );

                        if ( doc->pConfigCallback )
                            response = response || (*doc->pConfigCallback)( tidyImplToDoc(doc), name, buf );

                        if ( !response && isDeprecated )
                            response = subDeprecatedOption( doc, name, buf);

                        if ( response == no )
                            TY_(ReportUnknownOption)( doc, name );
                    }
                    else
                        TY_(ReportUnknownOption)( doc, name );
                }
            }
        }

        TY_(freeFileSource)(&cfg->cfgIn->source, yes);
        TY_(freeStreamIn)( cfg->cfgIn );
        cfg->cfgIn = NULL;
    }

    if ( fname != (tmbstr) file )
        TidyDocFree( doc, fname );

    AdjustConfig( doc );

    /* any new config errors? If so, return warning status. */
    return (doc->optionErrors > opterrs ? 1 : 0); 
}


/* returns false if unknown option, missing parameter,
** or option doesn't use parameter
*/
Bool TY_(ParseConfigOption)( TidyDocImpl* doc, ctmbstr optnam, ctmbstr optval )
{
    const TidyOptionImpl* option = TY_(lookupOption)( optnam );
    Bool isDeprecated = isOptionDeprecated( optnam );
    Bool status = ( option != NULL ) && !isDeprecated;
    if ( !status )
    {
        /* Unknown or deprecated, so check to see if the user application
           wants to deal with it first. */
        if (NULL != doc->pOptCallback)
            status = (*doc->pOptCallback)( optnam, optval );
        if (NULL != doc->pConfigCallback )
            status = status || (*doc->pConfigCallback)( tidyImplToDoc(doc), optnam, optval );
        if (!status && isDeprecated)
            status = subDeprecatedOption( doc, optnam, optval);
        if (!status)
            TY_(ReportUnknownOption)( doc, optnam );
    }
    else
        status = TY_(ParseConfigValue)( doc, option->id, optval );

    return status;
}


/* returns false if unknown option, missing parameter,
** or option doesn't use parameter
*/
Bool TY_(ParseConfigValue)( TidyDocImpl* doc, TidyOptionId optId, ctmbstr optval )
{
    const TidyOptionImpl* option = NULL;
    /* #472: fail status if there is a NULL parser. @ralfjunker */
    Bool status = ( optId < N_TIDY_OPTIONS
                   && (option = option_defs + optId)->parser
                   && optval != NULL );

    if ( !status )
        if ( option )
            TY_(ReportBadArgument)(doc, option->name);
        else
        {
            /* If optId < N_TIDY_OPTIONS then option remains unassigned,
               and we have to fall back to an ugly error message. */
            enum { sizeBuf = 11 }; /* uint_max is 10 characters */
            char buffer[sizeBuf];
            TY_(tmbsnprintf(buffer, sizeBuf, "%u", optId));
            TY_(ReportUnknownOption(doc, buffer));
        }
    else
    {
        TidyBuffer inbuf;            /* Set up input source */
        tidyBufInitWithAllocator( &inbuf, doc->allocator );
        tidyBufAttach( &inbuf, (byte*)optval, TY_(tmbstrlen)(optval)+1 );
        if (optId == TidyOutFile)
            doc->config.cfgIn = TY_(BufferInput)( doc, &inbuf, RAW );
        else
            doc->config.cfgIn = TY_(BufferInput)( doc, &inbuf, RAW ); /* Issue #468 - Was ASCII! */
        doc->config.c = GetC( &doc->config );

        status = option->parser( doc, option );

        TY_(freeStreamIn)(doc->config.cfgIn);  /* Release input source */
        doc->config.cfgIn  = NULL;
        tidyBufDetach( &inbuf );
    }
    return status;
}


/* ensure that char encodings are self consistent */
Bool  TY_(AdjustCharEncoding)( TidyDocImpl* doc, int encoding )
{
    int outenc = -1;
    int inenc = -1;
    
    switch( encoding )
    {
    case MACROMAN:
        inenc = MACROMAN;
        outenc = ASCII;
        break;

    case WIN1252:
        inenc = WIN1252;
        outenc = ASCII;
        break;

    case IBM858:
        inenc = IBM858;
        outenc = ASCII;
        break;

    case ASCII:
        inenc = LATIN1;
        outenc = ASCII;
        break;

    case LATIN0:
        inenc = LATIN0;
        outenc = ASCII;
        break;

    case RAW:
    case LATIN1:
    case UTF8:
#ifndef NO_NATIVE_ISO2022_SUPPORT
    case ISO2022:
#endif

    case UTF16LE:
    case UTF16BE:
    case UTF16:
    case SHIFTJIS:
    case BIG5:
        inenc = outenc = encoding;
        break;
    }

    if ( inenc >= 0 )
    {
        TY_(SetOptionInt)( doc, TidyCharEncoding, encoding );
        TY_(SetOptionInt)( doc, TidyInCharEncoding, inenc );
        TY_(SetOptionInt)( doc, TidyOutCharEncoding, outenc );
        return yes;
    }
    return no;
}


/* ensure that config is self consistent */
static void AdjustConfig( TidyDocImpl* doc )
{
    if ( cfgBool(doc, TidyEncloseBlockText) )
        TY_(SetOptionBool)( doc, TidyEncloseBodyText, yes );

    if ( cfgAutoBool(doc, TidyIndentContent) == TidyNoState )
        TY_(SetOptionInt)( doc, TidyIndentSpaces, 0 );

    /* disable wrapping */
    if ( cfg(doc, TidyWrapLen) == 0 )
        TY_(SetOptionInt)( doc, TidyWrapLen, 0x7FFFFFFF );

    /* Word 2000 needs o:p to be declared as inline */
    if ( cfgBool(doc, TidyWord2000) )
    {
        doc->config.defined_tags |= tagtype_inline;
        TY_(DefineTag)( doc, tagtype_inline, "o:p" );
    }

    /* #480701 disable XHTML output flag if both output-xhtml and xml input are set */
    if ( cfgBool(doc, TidyXmlTags) )
        TY_(SetOptionBool)( doc, TidyXhtmlOut, no );

    /* XHTML is written in lower case */
    if ( cfgBool(doc, TidyXhtmlOut) )
    {
        TY_(SetOptionBool)( doc, TidyXmlOut, yes );
        TY_(SetOptionBool)( doc, TidyUpperCaseTags, no );
        TY_(SetOptionInt)( doc, TidyUpperCaseAttrs, no );
        /* TY_(SetOptionBool)( doc, TidyXmlPIs, yes ); */
    }

    /* if XML in, then XML out */
    if ( cfgBool(doc, TidyXmlTags) )
    {
        TY_(SetOptionBool)( doc, TidyXmlOut, yes );
        TY_(SetOptionBool)( doc, TidyXmlPIs, yes );
    }

    /* #427837 - fix by Dave Raggett 02 Jun 01
    ** generate <?xml version="1.0" encoding="iso-8859-1"?>
    ** if the output character encoding is Latin-1 etc.
    */
    if ( cfg(doc, TidyOutCharEncoding) != ASCII &&
         cfg(doc, TidyOutCharEncoding) != UTF8 &&
         cfg(doc, TidyOutCharEncoding) != UTF16 &&
         cfg(doc, TidyOutCharEncoding) != UTF16BE &&
         cfg(doc, TidyOutCharEncoding) != UTF16LE &&
         cfg(doc, TidyOutCharEncoding) != RAW &&
         cfgBool(doc, TidyXmlOut) )
    {
        TY_(SetOptionBool)( doc, TidyXmlDecl, yes );
    }

    /* XML requires end tags */
    if ( cfgBool(doc, TidyXmlOut) )
    {
        /* XML requires a BOM on output if using UTF-16 encoding */
        unsigned int enc = cfg( doc, TidyOutCharEncoding );
        if ( enc == UTF16LE || enc == UTF16BE || enc == UTF16 )
            TY_(SetOptionInt)( doc, TidyOutputBOM, yes );
        
        TY_(SetOptionBool)( doc, TidyQuoteAmpersand, yes );
        TY_(SetOptionBool)( doc, TidyOmitOptionalTags, no );
    }
}


/* A service to ParseList(), keeps option values nicely formatted and
   coordinates additions to the internal lists. Within Tidy, this function
   might be used to programmatically add individual values to items that use
   this service.
 */
void TY_(DeclareListItem)( TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name )
{
    ctmbstr prvval = cfgStr( doc, opt->id );
    tmbstr catval = NULL;
    ctmbstr theval = name;
    if ( prvval )
    {
        unsigned int len = TY_(tmbstrlen)(name) + TY_(tmbstrlen)(prvval) + 3;
        catval = TY_(tmbstrndup)( doc->allocator, prvval, len );
        TY_(tmbstrcat)( catval, ", " );
        TY_(tmbstrcat)( catval, name );
        theval = catval;
    }

    switch ( opt->id )
    {
        case TidyPriorityAttributes:
            TY_(DefinePriorityAttribute)( doc, name );
            break;

        case TidyMuteReports:
            TY_(DefineMutedMessage)( doc, opt, name );
            break;

        case TidyInlineTags:
        case TidyBlockTags:
        case TidyEmptyTags:
        case TidyPreTags:
        case TidyCustomTags:
            TY_(DeclareUserTag)( doc, opt, name );
            break;

        default:
            break;
    }

    SetOptionValue( doc, opt->id, theval );
    if ( catval )
        TidyDocFree( doc, catval );
}


/* a space or comma separated list of items */
Bool ParseList( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    TidyConfigImpl* cfg = &doc->config;
    tmbchar buf[1024];
    unsigned int i = 0, nItems = 0;
    unsigned int c;
    TidyConfigChangeCallback callback = doc->pConfigChangeCallback;
    tmbstr oldbuff = NULL;

    /* Handle comparing before and after for the config change callback.
       We have do handle this manually, because otherwise TY_(DeclareListItem)
       would fire a callback for EVERY list item being added. */
    doc->pConfigChangeCallback = NULL;
    if ( callback )
    {
        TidyOptionValue* oldval = &(doc->config.value[ option->id ]);
        oldbuff = TY_(tmbstrdup)( doc->allocator, oldval->p );
    }

    SetOptionValue( doc, option->id, NULL );

    /* Given an empty string, so signal success. */
    if ( cfg->c == EndOfStream )
        return yes;

    c = SkipWhite( cfg );

    do
    {
        if (c == ' ' || c == '\t' || c == ',')
        {
            c = AdvanceChar( cfg );
            continue;
        }

        if ( c == '\r' || c == '\n' )
        {
            unsigned int c2 = AdvanceChar( cfg );
            if ( c == '\r' && c2 == '\n' )
                c = AdvanceChar( cfg );
            else
                c = c2;

            if ( !TY_(IsWhite)(c) )
            {
                buf[i] = 0;
                TY_(UngetChar)( c, cfg->cfgIn );
                TY_(UngetChar)( '\n', cfg->cfgIn );
                break;
            }
        }

        while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) && c != ',' )
        {
            buf[i++] = (tmbchar) c;
            c = AdvanceChar( cfg );
        }

        buf[i] = '\0';
        if (i == 0)          /* Skip empty attribute definition. Possible when */
            continue;        /* there is a trailing space on the line. */

        /* add attribute to array */
        TY_(DeclareListItem)( doc, option, buf );

        i = 0;
        ++nItems;
    }
    while ( c != EndOfStream );

    if ( i > 0 )
        TY_(DeclareListItem)( doc, option, buf );

    /* If there's a callback, compare the old and new values, and fire
       the callback appropriately. */
    if ( callback )
    {
        TidyOptionValue* val = &(doc->config.value[ option->id ]);
        Bool fire_callback = OptionChangedValuesDiffer( val->p, oldbuff);

        doc->pConfigChangeCallback = callback;

        if ( oldbuff )
            TidyFree( doc->allocator, oldbuff );

        if ( fire_callback )
            PerformOptionChangedCallback( doc, option );
    }

    return ( nItems > 0 );
}


/* unsigned integers */
Bool ParseInt( TidyDocImpl* doc, const TidyOptionImpl* entry )
{
    unsigned int number = 0;
    Bool digits = no;
    TidyConfigImpl* cfg = &doc->config;
    tchar c = SkipWhite( cfg );

    while ( TY_(IsDigit)(c) )
    {
        number = c - '0' + (10 * number);
        digits = yes;
        c = AdvanceChar( cfg );
    }

    if ( !digits )
        TY_(ReportBadArgument)( doc, entry->name );
    else
        TY_(SetOptionInt)( doc, entry->id, number );
    return digits;
}


/* a string excluding whitespace */
Bool FUNC_UNUSED ParseName( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    tmbchar buf[ 1024 ] = {0};
    unsigned int i = 0;
    unsigned int c = SkipWhite( &doc->config );

    while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) )
    {
        buf[i++] = (tmbchar) c;
        c = AdvanceChar( &doc->config );
    }
    buf[i] = 0;

    if ( i == 0 )
        TY_(ReportBadArgument)( doc, option->name );
    else
        SetOptionValue( doc, option->id, buf );
    return ( i > 0 );
}


/* #508936 - CSS class naming for -clean option */
Bool ParseCSS1Selector( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    TidyConfigImpl* cfg = &doc->config;
    char buf[256] = {0};
    unsigned int i = 0;
    unsigned int c;

    /* Given an empty string, so signal success. */
    if ( cfg->c == EndOfStream )
    {
        SetOptionValue( doc, option->id, NULL );
        return yes;
    }

    c = SkipWhite( cfg );

    while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) )
    {
        buf[i++] = (tmbchar) c;
        c = AdvanceChar( &doc->config );
    }
    buf[i] = '\0';

    if ( i == 0 ) {
        return no;
    }
    else if ( !TY_(IsCSS1Selector)(buf) ) {
        TY_(ReportBadArgument)( doc, option->name );
        return no;
    }

    buf[i] = 0; /* Is #697 - Do *not* add '-' */
#if 0   /* Is #697 - Is this still required? KEEP HISTORY - DO NOT DELETE */
    buf[i++] = '-';  /* Make sure any escaped Unicode is terminated */
    buf[i] = 0;      /* so valid class names are generated after */
                     /* Tidy appends last digits. */
#endif /* Is #697 - Is this still required? */

    SetOptionValue( doc, option->id, buf );
    return yes;
}


/* Given a string, return the picklist value from an arbitrary picklist. */
static Bool GetPickListValue( ctmbstr value, PickListItems* pickList, unsigned int *result )
{
    const PickListItem *item = NULL;
    unsigned int ix = 0;

    while ( (item = &(*pickList)[ ix ]) && item->label )
    {
        ctmbstr input;
        unsigned int i = 0;
        while ( ( input = &(*item->inputs[i]) ) )
        {
            if (TY_(tmbstrcasecmp)(value, input) == 0 )
            {
                *result = ix;
                return yes;
            }
            ++i;
        }
        ++ix;
    }

    return no;
}


/* A general parser for anything using pick lists. This provides the engine to
   determine the proper option value, and can be used by parsers in addition to
   ParsePickList that require special handling.
 */
static Bool GetParsePickListValue( TidyDocImpl* doc, const TidyOptionImpl* entry, unsigned int *result )
{
    TidyConfigImpl* cfg = &doc->config;
    tchar c = SkipWhite( cfg );
    tmbchar work[ 16 ] = {0};
    tmbstr cp = work, end = work + sizeof(work);

    while ( c!=EndOfStream && cp < end && !TY_(IsWhite)(c) && c != '\r' && c != '\n' )
    {
        *cp++ = (tmbchar) c;
        c = AdvanceChar( cfg );
    }

    if ( GetPickListValue( work, entry->pickList, result ) != yes )
    {
        TY_(ReportBadArgument)( doc, entry->name );
        return no;
    }

    return yes;
}


/* A general parser for anything using pick lists that don't require special
   handling.
 */
Bool ParsePickList( TidyDocImpl* doc, const TidyOptionImpl* entry )
{
    unsigned int value;
    
    if ( GetParsePickListValue( doc, entry, &value ) )
    {
        if ( entry->type == TidyBoolean )
            TY_(SetOptionBool)( doc, entry->id, value );
        else if ( entry->type == TidyInteger )
            TY_(SetOptionInt)( doc, entry->id, value );
        return yes;
    }
  
    TY_(ReportBadArgument)( doc, entry->name );
    return no;
}


/*\
 * 20150515 - support using tabs instead of spaces - Issue #108
 * Sets the indent character to a tab if on, and set indent space count to 1
 * and sets indent character to a space if off.
 \*/
Bool ParseTabs( TidyDocImpl* doc, const TidyOptionImpl* entry )
{
    unsigned int flag = 0;
    Bool status = GetParsePickListValue( doc, entry, &flag );
    
    if ( status ) {
        Bool tabs = flag != 0 ? yes : no;
        TY_(SetOptionBool)( doc, entry->id, tabs );
        if (tabs) {
            TY_(SetOptionInt)( doc, TidyIndentSpaces, 1 );
        } else {
            /* optional - TY_(ResetOptionToDefault)( doc, TidyIndentSpaces ); */
        }
    }
    return status;
}


/* a string including whitespace */
/* munges whitespace sequences */
Bool ParseString( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    TidyConfigImpl* cfg = &doc->config;
    tmbchar buf[8192];
    unsigned int i = 0;
    tchar delim = 0;
    Bool waswhite = yes;

    tchar c = SkipWhite( cfg );

    if ( c == '"' || c == '\'' )
    {
        delim = c;
        c = AdvanceChar( cfg );
    }

    while ( i < sizeof(buf)-2 && c != EndOfStream && c != '\r' && c != '\n' )
    {
        if ( delim && c == delim )
            break;

        if ( TY_(IsWhite)(c) )
        {
            if ( waswhite )
            {
                c = AdvanceChar( cfg );
                continue;
            }
            c = ' ';
        }
        else
            waswhite = no;

        buf[i++] = (tmbchar) c;
        c = AdvanceChar( cfg );
    }
    buf[i] = '\0';

    SetOptionValue( doc, option->id, buf );
    return yes;
}


Bool ParseCharEnc( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    tmbchar buf[64] = {0};
    unsigned int i = 0;
    int enc = ASCII;
    Bool validEncoding = yes;
    tchar c = SkipWhite( &doc->config );

    while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) )
    {
        buf[i++] = (tmbchar) TY_(ToLower)( c );
        c = AdvanceChar( &doc->config );
    }
    buf[i] = 0;

    enc = TY_(CharEncodingId)( doc, buf );

    if ( enc < 0 )
    {
        validEncoding = no;
        TY_(ReportBadArgument)( doc, option->name );
    }
    else
        TY_(SetOptionInt)( doc, option->id, enc );

    if ( validEncoding && option->id == TidyCharEncoding )
        TY_(AdjustCharEncoding)( doc, enc );
    return validEncoding;
}


int TY_(CharEncodingId)( TidyDocImpl* ARG_UNUSED(doc), ctmbstr charenc )
{
    int enc = TY_(GetCharEncodingFromOptName)( charenc );
    return enc;
}


ctmbstr TY_(CharEncodingName)( int encoding )
{
    ctmbstr encodingName = TY_(GetEncodingNameFromTidyId)(encoding);

    if (!encodingName)
        encodingName = "unknown";

    return encodingName;
}


ctmbstr TY_(CharEncodingOptName)( int encoding )
{
    ctmbstr encodingName = TY_(GetEncodingOptNameFromTidyId)(encoding);

    if (!encodingName)
        encodingName = "unknown";

    return encodingName;
}


/*
   doctype: html5 | omit | auto | strict | loose | <fpi>

   where the fpi is a string similar to

      "-//ACME//DTD HTML 3.14159//EN"
*/
Bool ParseDocType( TidyDocImpl* doc, const TidyOptionImpl* option )
{
    Bool status = yes;
    unsigned int value;
    TidyConfigImpl* cfg = &doc->config;
    tchar c;

    /* Given an empty string, so signal success. */
    if ( cfg->c == EndOfStream )
    {
        SetOptionValue( doc, option->id, NULL );
        return yes;
    }

    c = SkipWhite( cfg );


    /* "-//ACME//DTD HTML 3.14159//EN" or similar */

    if ( c == '"' || c == '\''|| c == '-' || c == '+' )
    {
        status = ParseString(doc, option);
        if (status)
        {
            TY_(SetOptionInt)( doc, TidyDoctypeMode, TidyDoctypeUser );
        }
        return status;
    }
    
    if ( (status = GetParsePickListValue( doc, option, &value ) ) )
    {
        TY_(SetOptionInt)( doc, TidyDoctypeMode, value );
    }
    else
    {
        TY_(ReportBadArgument)( doc, option->name );
    }
    
    return status;
}


/* Use TidyOptionId as iterator.
** Send index of 1st option after TidyOptionUnknown as start of list.
*/
TidyIterator TY_(getOptionList)( TidyDocImpl* ARG_UNUSED(doc) )
{
    return (TidyIterator) (size_t)1;
}


/* Check if this item is last valid option.
** If so, zero out iterator.
*/
const TidyOptionImpl*  TY_(getNextOption)( TidyDocImpl* ARG_UNUSED(doc),
                                           TidyIterator* iter )
{
    const TidyOptionImpl* option = NULL;
    size_t optId;
    assert( iter != NULL );
    optId = (size_t) *iter;
    if ( optId > TidyUnknownOption && optId < N_TIDY_OPTIONS )
    {
        option = &option_defs[ optId ];
        optId++;
    }
    *iter = (TidyIterator) ( optId < N_TIDY_OPTIONS ? optId : (size_t)0 );
    return option;
}


/* Use a 1-based array index as iterator: 0 == end-of-list
*/
TidyIterator TY_(getOptionPickList)( const TidyOptionImpl* option )
{
    size_t ix = 0;
    if ( option && option->pickList )
        ix = 1;
    return (TidyIterator) ix;
}


ctmbstr      TY_(getNextOptionPick)( const TidyOptionImpl* option,
                                     TidyIterator* iter )
{
    size_t ix;
    ctmbstr val = NULL;
    const PickListItem *item= NULL;
    assert( option!=NULL && iter != NULL );

    ix = (size_t) *iter;
    
    if ( option->pickList )
    {
        if ( ix > 0 && ix < TIDY_PL_SIZE && option->pickList )
        {
            item = &(*option->pickList)[ ix-1 ];
            val = item->label;
        }
        item = &(*option->pickList)[ ix ];
        *iter = (TidyIterator) ( val && item->label ? ix + 1 : (size_t)0 );
    }
    
    return val;
}


static int  WriteOptionString( const TidyOptionImpl* option,
                               ctmbstr sval, StreamOut* out )
{
  ctmbstr cp = option->name;
  while ( *cp )
      TY_(WriteChar)( *cp++, out );
  TY_(WriteChar)( ':', out );
  TY_(WriteChar)( ' ', out );
  cp = sval;
  while ( *cp )
      TY_(WriteChar)( *cp++, out );
  TY_(WriteChar)( '\n', out );
  return 0;
}


static int  WriteOptionInt( const TidyOptionImpl* option, unsigned int ival, StreamOut* out )
{
  tmbchar sval[ 32 ] = {0};
  TY_(tmbsnprintf)(sval, sizeof(sval), "%u", ival );
  return WriteOptionString( option, sval, out );
}


static int  WriteOptionBool( const TidyOptionImpl* option, Bool bval, StreamOut* out )
{
  ctmbstr sval = bval ? "yes" : "no";
  return WriteOptionString( option, sval, out );
}


static int  WriteOptionPick( const TidyOptionImpl* option, unsigned int ival, StreamOut* out )
{
    unsigned int ix = 0;
    const PickListItem *item = NULL;
    
    if ( option-> pickList )
    {
        while ( (item = &(*option->pickList)[ ix ]) && item->label && ix<ival )
        {
            ++ix;
        }
        if ( ix==ival && item->label )
            return WriteOptionString( option, item->label, out );
    }
    
    return -1;
}


Bool  TY_(ConfigDiffThanSnapshot)( TidyDocImpl* doc )
{
  int diff = memcmp( &doc->config.value, &doc->config.snapshot,
                     N_TIDY_OPTIONS * sizeof(unsigned int) );
  return ( diff != 0 );
}


Bool  TY_(ConfigDiffThanDefault)( TidyDocImpl* doc )
{
  Bool diff = no;
  const TidyOptionImpl* option = option_defs + 1;
  const TidyOptionValue* val = doc->config.value + 1;
  for ( /**/; !diff && option && option->name; ++option, ++val )
  {
      diff = !OptionValueEqDefault( option, val );
  }
  return diff;
}


static int  SaveConfigToStream( TidyDocImpl* doc, StreamOut* out )
{
    int rc = 0;
    const TidyOptionImpl* option;
    for ( option=option_defs+1; 0==rc && option && option->name; ++option )
    {
        const TidyOptionValue* val = &doc->config.value[ option->id ];
        if ( option->parser == NULL )
            continue;
        if ( OptionValueEqDefault( option, val ) && option->id != TidyDoctype)
            continue;

        if ( option->id == TidyDoctype )  /* Special case */
        {
          unsigned int dtmode = cfg( doc, TidyDoctypeMode );
          if ( dtmode == TidyDoctypeUser )
          {
            tmbstr t;
            
            /* add 2 double quotes */
            if (( t = (tmbstr)TidyDocAlloc( doc, TY_(tmbstrlen)( val->p ) + 2 ) ))
            {
              t[0] = '\"'; t[1] = 0;
            
              TY_(tmbstrcat)( t, val->p );
              TY_(tmbstrcat)( t, "\"" );
              rc = WriteOptionString( option, t, out );
            
              TidyDocFree( doc, t );
            }
          }
          else if ( dtmode == option_defs[TidyDoctypeMode].dflt )
            continue;
          else
            rc = WriteOptionPick( option, dtmode, out );
        }
        else if ( option->pickList)
          rc = WriteOptionPick( option, val->v, out );
        else
        {
          switch ( option->type )
          {
          case TidyString:
            rc = WriteOptionString( option, val->p, out );
            break;
          case TidyInteger:
            rc = WriteOptionInt( option, val->v, out );
            break;
          case TidyBoolean:
            rc = WriteOptionBool( option, val->v ? yes : no, out );
            break;
          }
        }
    }
    return rc;
}


int  TY_(SaveConfigFile)( TidyDocImpl* doc, ctmbstr cfgfil )
{
    int status = -1;
    StreamOut* out = NULL;
    unsigned int outenc = cfg( doc, TidyOutCharEncoding );
    unsigned int nl = cfg( doc, TidyNewline );
    FILE* fout = fopen( cfgfil, "wb" );
    if ( fout )
    {
        out = TY_(FileOutput)( doc, fout, outenc, nl );
        status = SaveConfigToStream( doc, out );
        fclose( fout );
        TidyDocFree( doc, out );
    }
    return status;
}


int  TY_(SaveConfigSink)( TidyDocImpl* doc, TidyOutputSink* sink )
{
    unsigned int outenc = cfg( doc, TidyOutCharEncoding );
    unsigned int nl = cfg( doc, TidyNewline );
    StreamOut* out = TY_(UserOutput)( doc, sink, outenc, nl );
    int status = SaveConfigToStream( doc, out );
    TidyDocFree( doc, out );
    return status;
}

/* entities.c -- recognize HTML ISO entities

  (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Entity handling can be static because there are no config or
  document-specific values.  Lookup table is 100% defined at 
  compile time.

*/

#include <stdio.h>
/* #include "entities.h" */
/* #include "tidy-int.h" */
/* #include "tmbstr.h" */

struct _entity;
typedef struct _entity entity;

struct _entity
{
    ctmbstr name;
    unsigned int    versions;
    unsigned int    code;
};

#ifndef VERS_CHECK
#define VERS_CHECK VERS_HTML5
#endif

/*
** Issue #643 - list increased to
** 2032 known entities.
** Note also stuct /not/ padded to 
** keep source weight down, 79K vs 149K,
** and is strictly alphabetic to optimize 
** the searching.
** All new entities have been given VERS_CHECK
** This should be replaced if versioning can
** successfully be established.
*/

static const entity entities[] =
{
    { "AElig", VERS_ALL, 198 },
    { "AMP", VERS_CHECK, 38 },
    { "Aacute", VERS_ALL, 193 },
    { "Abreve", VERS_CHECK, 258 },
    { "Acirc", VERS_ALL, 194 },
    { "Acy", VERS_CHECK, 1040 },
    { "Afr", VERS_CHECK, 120068 },
    { "Agrave", VERS_ALL, 192 },
    { "Alpha", VERS_FROM40, 913 },
    { "Amacr", VERS_CHECK, 256 },
    { "And", VERS_CHECK, 10835 },
    { "Aogon", VERS_CHECK, 260 },
    { "Aopf", VERS_CHECK, 120120 },
    { "ApplyFunction", VERS_CHECK, 8289 },
    { "Aring", VERS_ALL, 197 },
    { "Ascr", VERS_CHECK, 119964 },
    { "Assign", VERS_CHECK, 8788 },
    { "Atilde", VERS_ALL, 195 },
    { "Auml", VERS_ALL, 196 },
    { "Backslash", VERS_CHECK, 8726 },
    { "Barv", VERS_CHECK, 10983 },
    { "Barwed", VERS_CHECK, 8966 },
    { "Bcy", VERS_CHECK, 1041 },
    { "Because", VERS_CHECK, 8757 },
    { "Bernoullis", VERS_CHECK, 8492 },
    { "Beta", VERS_FROM40, 914 },
    { "Bfr", VERS_CHECK, 120069 },
    { "Bopf", VERS_CHECK, 120121 },
    { "Breve", VERS_CHECK, 728 },
    { "Bscr", VERS_CHECK, 8492 },
    { "Bumpeq", VERS_CHECK, 8782 },
    { "CHcy", VERS_CHECK, 1063 },
    { "COPY", VERS_CHECK, 169 },
    { "Cacute", VERS_CHECK, 262 },
    { "Cap", VERS_CHECK, 8914 },
    { "CapitalDifferentialD", VERS_CHECK, 8517 },
    { "Cayleys", VERS_CHECK, 8493 },
    { "Ccaron", VERS_CHECK, 268 },
    { "Ccedil", VERS_ALL, 199 },
    { "Ccirc", VERS_CHECK, 264 },
    { "Cconint", VERS_CHECK, 8752 },
    { "Cdot", VERS_CHECK, 266 },
    { "Cedilla", VERS_CHECK, 184 },
    { "CenterDot", VERS_CHECK, 183 },
    { "Cfr", VERS_CHECK, 8493 },
    { "Chi", VERS_FROM40, 935 },
    { "CircleDot", VERS_CHECK, 8857 },
    { "CircleMinus", VERS_CHECK, 8854 },
    { "CirclePlus", VERS_CHECK, 8853 },
    { "CircleTimes", VERS_CHECK, 8855 },
    { "ClockwiseContourIntegral", VERS_CHECK, 8754 },
    { "CloseCurlyDoubleQuote", VERS_CHECK, 8221 },
    { "CloseCurlyQuote", VERS_CHECK, 8217 },
    { "Colon", VERS_CHECK, 8759 },
    { "Colone", VERS_CHECK, 10868 },
    { "Congruent", VERS_CHECK, 8801 },
    { "Conint", VERS_CHECK, 8751 },
    { "ContourIntegral", VERS_CHECK, 8750 },
    { "Copf", VERS_CHECK, 8450 },
    { "Coproduct", VERS_CHECK, 8720 },
    { "CounterClockwiseContourIntegral", VERS_CHECK, 8755 },
    { "Cross", VERS_CHECK, 10799 },
    { "Cscr", VERS_CHECK, 119966 },
    { "Cup", VERS_CHECK, 8915 },
    { "CupCap", VERS_CHECK, 8781 },
    { "DD", VERS_CHECK, 8517 },
    { "DDotrahd", VERS_CHECK, 10513 },
    { "DJcy", VERS_CHECK, 1026 },
    { "DScy", VERS_CHECK, 1029 },
    { "DZcy", VERS_CHECK, 1039 },
    { "Dagger", VERS_FROM40, 8225 },
    { "Darr", VERS_CHECK, 8609 },
    { "Dashv", VERS_CHECK, 10980 },
    { "Dcaron", VERS_CHECK, 270 },
    { "Dcy", VERS_CHECK, 1044 },
    { "Del", VERS_CHECK, 8711 },
    { "Delta", VERS_FROM40, 916 },
    { "Dfr", VERS_CHECK, 120071 },
    { "DiacriticalAcute", VERS_CHECK, 180 },
    { "DiacriticalDot", VERS_CHECK, 729 },
    { "DiacriticalDoubleAcute", VERS_CHECK, 733 },
    { "DiacriticalGrave", VERS_CHECK, 96 },
    { "DiacriticalTilde", VERS_CHECK, 732 },
    { "Diamond", VERS_CHECK, 8900 },
    { "DifferentialD", VERS_CHECK, 8518 },
    { "Dopf", VERS_CHECK, 120123 },
    { "Dot", VERS_CHECK, 168 },
    { "DotDot", VERS_CHECK, 8412 },
    { "DotEqual", VERS_CHECK, 8784 },
    { "DoubleContourIntegral", VERS_CHECK, 8751 },
    { "DoubleDot", VERS_CHECK, 168 },
    { "DoubleDownArrow", VERS_CHECK, 8659 },
    { "DoubleLeftArrow", VERS_CHECK, 8656 },
    { "DoubleLeftRightArrow", VERS_CHECK, 8660 },
    { "DoubleLeftTee", VERS_CHECK, 10980 },
    { "DoubleLongLeftArrow", VERS_CHECK, 10232 },
    { "DoubleLongLeftRightArrow", VERS_CHECK, 10234 },
    { "DoubleLongRightArrow", VERS_CHECK, 10233 },
    { "DoubleRightArrow", VERS_CHECK, 8658 },
    { "DoubleRightTee", VERS_CHECK, 8872 },
    { "DoubleUpArrow", VERS_CHECK, 8657 },
    { "DoubleUpDownArrow", VERS_CHECK, 8661 },
    { "DoubleVerticalBar", VERS_CHECK, 8741 },
    { "DownArrow", VERS_CHECK, 8595 },
    { "DownArrowBar", VERS_CHECK, 10515 },
    { "DownArrowUpArrow", VERS_CHECK, 8693 },
    { "DownBreve", VERS_CHECK, 785 },
    { "DownLeftRightVector", VERS_CHECK, 10576 },
    { "DownLeftTeeVector", VERS_CHECK, 10590 },
    { "DownLeftVector", VERS_CHECK, 8637 },
    { "DownLeftVectorBar", VERS_CHECK, 10582 },
    { "DownRightTeeVector", VERS_CHECK, 10591 },
    { "DownRightVector", VERS_CHECK, 8641 },
    { "DownRightVectorBar", VERS_CHECK, 10583 },
    { "DownTee", VERS_CHECK, 8868 },
    { "DownTeeArrow", VERS_CHECK, 8615 },
    { "Downarrow", VERS_CHECK, 8659 },
    { "Dscr", VERS_CHECK, 119967 },
    { "Dstrok", VERS_CHECK, 272 },
    { "ENG", VERS_CHECK, 330 },
    { "ETH", VERS_ALL, 208 },
    { "Eacute", VERS_ALL, 201 },
    { "Ecaron", VERS_CHECK, 282 },
    { "Ecirc", VERS_ALL, 202 },
    { "Ecy", VERS_CHECK, 1069 },
    { "Edot", VERS_CHECK, 278 },
    { "Efr", VERS_CHECK, 120072 },
    { "Egrave", VERS_ALL, 200 },
    { "Element", VERS_CHECK, 8712 },
    { "Emacr", VERS_CHECK, 274 },
    { "EmptySmallSquare", VERS_CHECK, 9723 },
    { "EmptyVerySmallSquare", VERS_CHECK, 9643 },
    { "Eogon", VERS_CHECK, 280 },
    { "Eopf", VERS_CHECK, 120124 },
    { "Epsilon", VERS_FROM40, 917 },
    { "Equal", VERS_CHECK, 10869 },
    { "EqualTilde", VERS_CHECK, 8770 },
    { "Equilibrium", VERS_CHECK, 8652 },
    { "Escr", VERS_CHECK, 8496 },
    { "Esim", VERS_CHECK, 10867 },
    { "Eta", VERS_FROM40, 919 },
    { "Euml", VERS_ALL, 203 },
    { "Exists", VERS_CHECK, 8707 },
    { "ExponentialE", VERS_CHECK, 8519 },
    { "Fcy", VERS_CHECK, 1060 },
    { "Ffr", VERS_CHECK, 120073 },
    { "FilledSmallSquare", VERS_CHECK, 9724 },
    { "FilledVerySmallSquare", VERS_CHECK, 9642 },
    { "Fopf", VERS_CHECK, 120125 },
    { "ForAll", VERS_CHECK, 8704 },
    { "Fouriertrf", VERS_CHECK, 8497 },
    { "Fscr", VERS_CHECK, 8497 },
    { "GJcy", VERS_CHECK, 1027 },
    { "GT", VERS_CHECK, 62 },
    { "Gamma", VERS_FROM40, 915 },
    { "Gammad", VERS_CHECK, 988 },
    { "Gbreve", VERS_CHECK, 286 },
    { "Gcedil", VERS_CHECK, 290 },
    { "Gcirc", VERS_CHECK, 284 },
    { "Gcy", VERS_CHECK, 1043 },
    { "Gdot", VERS_CHECK, 288 },
    { "Gfr", VERS_CHECK, 120074 },
    { "Gg", VERS_CHECK, 8921 },
    { "Gopf", VERS_CHECK, 120126 },
    { "GreaterEqual", VERS_CHECK, 8805 },
    { "GreaterEqualLess", VERS_CHECK, 8923 },
    { "GreaterFullEqual", VERS_CHECK, 8807 },
    { "GreaterGreater", VERS_CHECK, 10914 },
    { "GreaterLess", VERS_CHECK, 8823 },
    { "GreaterSlantEqual", VERS_CHECK, 10878 },
    { "GreaterTilde", VERS_CHECK, 8819 },
    { "Gscr", VERS_CHECK, 119970 },
    { "Gt", VERS_CHECK, 8811 },
    { "HARDcy", VERS_CHECK, 1066 },
    { "Hacek", VERS_CHECK, 711 },
    { "Hat", VERS_CHECK, 94 },
    { "Hcirc", VERS_CHECK, 292 },
    { "Hfr", VERS_CHECK, 8460 },
    { "HilbertSpace", VERS_CHECK, 8459 },
    { "Hopf", VERS_CHECK, 8461 },
    { "HorizontalLine", VERS_CHECK, 9472 },
    { "Hscr", VERS_CHECK, 8459 },
    { "Hstrok", VERS_CHECK, 294 },
    { "HumpDownHump", VERS_CHECK, 8782 },
    { "HumpEqual", VERS_CHECK, 8783 },
    { "IEcy", VERS_CHECK, 1045 },
    { "IJlig", VERS_CHECK, 306 },
    { "IOcy", VERS_CHECK, 1025 },
    { "Iacute", VERS_ALL, 205 },
    { "Icirc", VERS_ALL, 206 },
    { "Icy", VERS_CHECK, 1048 },
    { "Idot", VERS_CHECK, 304 },
    { "Ifr", VERS_CHECK, 8465 },
    { "Igrave", VERS_ALL, 204 },
    { "Im", VERS_CHECK, 8465 },
    { "Imacr", VERS_CHECK, 298 },
    { "ImaginaryI", VERS_CHECK, 8520 },
    { "Implies", VERS_CHECK, 8658 },
    { "Int", VERS_CHECK, 8748 },
    { "Integral", VERS_CHECK, 8747 },
    { "Intersection", VERS_CHECK, 8898 },
    { "InvisibleComma", VERS_CHECK, 8291 },
    { "InvisibleTimes", VERS_CHECK, 8290 },
    { "Iogon", VERS_CHECK, 302 },
    { "Iopf", VERS_CHECK, 120128 },
    { "Iota", VERS_FROM40, 921 },
    { "Iscr", VERS_CHECK, 8464 },
    { "Itilde", VERS_CHECK, 296 },
    { "Iukcy", VERS_CHECK, 1030 },
    { "Iuml", VERS_ALL, 207 },
    { "Jcirc", VERS_CHECK, 308 },
    { "Jcy", VERS_CHECK, 1049 },
    { "Jfr", VERS_CHECK, 120077 },
    { "Jopf", VERS_CHECK, 120129 },
    { "Jscr", VERS_CHECK, 119973 },
    { "Jsercy", VERS_CHECK, 1032 },
    { "Jukcy", VERS_CHECK, 1028 },
    { "KHcy", VERS_CHECK, 1061 },
    { "KJcy", VERS_CHECK, 1036 },
    { "Kappa", VERS_FROM40, 922 },
    { "Kcedil", VERS_CHECK, 310 },
    { "Kcy", VERS_CHECK, 1050 },
    { "Kfr", VERS_CHECK, 120078 },
    { "Kopf", VERS_CHECK, 120130 },
    { "Kscr", VERS_CHECK, 119974 },
    { "LJcy", VERS_CHECK, 1033 },
    { "LT", VERS_CHECK, 60 },
    { "Lacute", VERS_CHECK, 313 },
    { "Lambda", VERS_FROM40, 923 },
    { "Lang", VERS_CHECK, 10218 },
    { "Laplacetrf", VERS_CHECK, 8466 },
    { "Larr", VERS_CHECK, 8606 },
    { "Lcaron", VERS_CHECK, 317 },
    { "Lcedil", VERS_CHECK, 315 },
    { "Lcy", VERS_CHECK, 1051 },
    { "LeftAngleBracket", VERS_CHECK, 10216 },
    { "LeftArrow", VERS_CHECK, 8592 },
    { "LeftArrowBar", VERS_CHECK, 8676 },
    { "LeftArrowRightArrow", VERS_CHECK, 8646 },
    { "LeftCeiling", VERS_CHECK, 8968 },
    { "LeftDoubleBracket", VERS_CHECK, 10214 },
    { "LeftDownTeeVector", VERS_CHECK, 10593 },
    { "LeftDownVector", VERS_CHECK, 8643 },
    { "LeftDownVectorBar", VERS_CHECK, 10585 },
    { "LeftFloor", VERS_CHECK, 8970 },
    { "LeftRightArrow", VERS_CHECK, 8596 },
    { "LeftRightVector", VERS_CHECK, 10574 },
    { "LeftTee", VERS_CHECK, 8867 },
    { "LeftTeeArrow", VERS_CHECK, 8612 },
    { "LeftTeeVector", VERS_CHECK, 10586 },
    { "LeftTriangle", VERS_CHECK, 8882 },
    { "LeftTriangleBar", VERS_CHECK, 10703 },
    { "LeftTriangleEqual", VERS_CHECK, 8884 },
    { "LeftUpDownVector", VERS_CHECK, 10577 },
    { "LeftUpTeeVector", VERS_CHECK, 10592 },
    { "LeftUpVector", VERS_CHECK, 8639 },
    { "LeftUpVectorBar", VERS_CHECK, 10584 },
    { "LeftVector", VERS_CHECK, 8636 },
    { "LeftVectorBar", VERS_CHECK, 10578 },
    { "Leftarrow", VERS_CHECK, 8656 },
    { "Leftrightarrow", VERS_CHECK, 8660 },
    { "LessEqualGreater", VERS_CHECK, 8922 },
    { "LessFullEqual", VERS_CHECK, 8806 },
    { "LessGreater", VERS_CHECK, 8822 },
    { "LessLess", VERS_CHECK, 10913 },
    { "LessSlantEqual", VERS_CHECK, 10877 },
    { "LessTilde", VERS_CHECK, 8818 },
    { "Lfr", VERS_CHECK, 120079 },
    { "Ll", VERS_CHECK, 8920 },
    { "Lleftarrow", VERS_CHECK, 8666 },
    { "Lmidot", VERS_CHECK, 319 },
    { "LongLeftArrow", VERS_CHECK, 10229 },
    { "LongLeftRightArrow", VERS_CHECK, 10231 },
    { "LongRightArrow", VERS_CHECK, 10230 },
    { "Longleftarrow", VERS_CHECK, 10232 },
    { "Longleftrightarrow", VERS_CHECK, 10234 },
    { "Longrightarrow", VERS_CHECK, 10233 },
    { "Lopf", VERS_CHECK, 120131 },
    { "LowerLeftArrow", VERS_CHECK, 8601 },
    { "LowerRightArrow", VERS_CHECK, 8600 },
    { "Lscr", VERS_CHECK, 8466 },
    { "Lsh", VERS_CHECK, 8624 },
    { "Lstrok", VERS_CHECK, 321 },
    { "Lt", VERS_CHECK, 8810 },
    { "Map", VERS_CHECK, 10501 },
    { "Mcy", VERS_CHECK, 1052 },
    { "MediumSpace", VERS_CHECK, 8287 },
    { "Mellintrf", VERS_CHECK, 8499 },
    { "Mfr", VERS_CHECK, 120080 },
    { "MinusPlus", VERS_CHECK, 8723 },
    { "Mopf", VERS_CHECK, 120132 },
    { "Mscr", VERS_CHECK, 8499 },
    { "Mu", VERS_FROM40, 924 },
    { "NJcy", VERS_CHECK, 1034 },
    { "Nacute", VERS_CHECK, 323 },
    { "Ncaron", VERS_CHECK, 327 },
    { "Ncedil", VERS_CHECK, 325 },
    { "Ncy", VERS_CHECK, 1053 },
    { "NegativeMediumSpace", VERS_CHECK, 8203 },
    { "NegativeThickSpace", VERS_CHECK, 8203 },
    { "NegativeThinSpace", VERS_CHECK, 8203 },
    { "NegativeVeryThinSpace", VERS_CHECK, 8203 },
    { "NestedGreaterGreater", VERS_CHECK, 8811 },
    { "NestedLessLess", VERS_CHECK, 8810 },
    { "NewLine", VERS_CHECK, 10 },
    { "Nfr", VERS_CHECK, 120081 },
    { "NoBreak", VERS_CHECK, 8288 },
    { "NonBreakingSpace", VERS_CHECK, 160 },
    { "Nopf", VERS_CHECK, 8469 },
    { "Not", VERS_CHECK, 10988 },
    { "NotCongruent", VERS_CHECK, 8802 },
    { "NotCupCap", VERS_CHECK, 8813 },
    { "NotDoubleVerticalBar", VERS_CHECK, 8742 },
    { "NotElement", VERS_CHECK, 8713 },
    { "NotEqual", VERS_CHECK, 8800 },
    { "NotExists", VERS_CHECK, 8708 },
    { "NotGreater", VERS_CHECK, 8815 },
    { "NotGreaterEqual", VERS_CHECK, 8817 },
    { "NotGreaterLess", VERS_CHECK, 8825 },
    { "NotGreaterTilde", VERS_CHECK, 8821 },
    { "NotLeftTriangle", VERS_CHECK, 8938 },
    { "NotLeftTriangleEqual", VERS_CHECK, 8940 },
    { "NotLess", VERS_CHECK, 8814 },
    { "NotLessEqual", VERS_CHECK, 8816 },
    { "NotLessGreater", VERS_CHECK, 8824 },
    { "NotLessTilde", VERS_CHECK, 8820 },
    { "NotPrecedes", VERS_CHECK, 8832 },
    { "NotPrecedesSlantEqual", VERS_CHECK, 8928 },
    { "NotReverseElement", VERS_CHECK, 8716 },
    { "NotRightTriangle", VERS_CHECK, 8939 },
    { "NotRightTriangleEqual", VERS_CHECK, 8941 },
    { "NotSquareSubsetEqual", VERS_CHECK, 8930 },
    { "NotSquareSupersetEqual", VERS_CHECK, 8931 },
    { "NotSubsetEqual", VERS_CHECK, 8840 },
    { "NotSucceeds", VERS_CHECK, 8833 },
    { "NotSucceedsSlantEqual", VERS_CHECK, 8929 },
    { "NotSupersetEqual", VERS_CHECK, 8841 },
    { "NotTilde", VERS_CHECK, 8769 },
    { "NotTildeEqual", VERS_CHECK, 8772 },
    { "NotTildeFullEqual", VERS_CHECK, 8775 },
    { "NotTildeTilde", VERS_CHECK, 8777 },
    { "NotVerticalBar", VERS_CHECK, 8740 },
    { "Nscr", VERS_CHECK, 119977 },
    { "Ntilde", VERS_ALL, 209 },
    { "Nu", VERS_FROM40, 925 },
    { "OElig", VERS_FROM40, 338 },
    { "Oacute", VERS_ALL, 211 },
    { "Ocirc", VERS_ALL, 212 },
    { "Ocy", VERS_CHECK, 1054 },
    { "Odblac", VERS_CHECK, 336 },
    { "Ofr", VERS_CHECK, 120082 },
    { "Ograve", VERS_ALL, 210 },
    { "Omacr", VERS_CHECK, 332 },
    { "Omega", VERS_FROM40, 937 },
    { "Omicron", VERS_FROM40, 927 },
    { "Oopf", VERS_CHECK, 120134 },
    { "OpenCurlyDoubleQuote", VERS_CHECK, 8220 },
    { "OpenCurlyQuote", VERS_CHECK, 8216 },
    { "Or", VERS_CHECK, 10836 },
    { "Oscr", VERS_CHECK, 119978 },
    { "Oslash", VERS_ALL, 216 },
    { "Otilde", VERS_ALL, 213 },
    { "Otimes", VERS_CHECK, 10807 },
    { "Ouml", VERS_ALL, 214 },
    { "OverBar", VERS_CHECK, 8254 },
    { "OverBrace", VERS_CHECK, 9182 },
    { "OverBracket", VERS_CHECK, 9140 },
    { "OverParenthesis", VERS_CHECK, 9180 },
    { "PartialD", VERS_CHECK, 8706 },
    { "Pcy", VERS_CHECK, 1055 },
    { "Pfr", VERS_CHECK, 120083 },
    { "Phi", VERS_FROM40, 934 },
    { "Pi", VERS_FROM40, 928 },
    { "PlusMinus", VERS_CHECK, 177 },
    { "Poincareplane", VERS_CHECK, 8460 },
    { "Popf", VERS_CHECK, 8473 },
    { "Pr", VERS_CHECK, 10939 },
    { "Precedes", VERS_CHECK, 8826 },
    { "PrecedesEqual", VERS_CHECK, 10927 },
    { "PrecedesSlantEqual", VERS_CHECK, 8828 },
    { "PrecedesTilde", VERS_CHECK, 8830 },
    { "Prime", VERS_FROM40, 8243 },
    { "Product", VERS_CHECK, 8719 },
    { "Proportion", VERS_CHECK, 8759 },
    { "Proportional", VERS_CHECK, 8733 },
    { "Pscr", VERS_CHECK, 119979 },
    { "Psi", VERS_FROM40, 936 },
    { "QUOT", VERS_CHECK, 34 },
    { "Qfr", VERS_CHECK, 120084 },
    { "Qopf", VERS_CHECK, 8474 },
    { "Qscr", VERS_CHECK, 119980 },
    { "RBarr", VERS_CHECK, 10512 },
    { "REG", VERS_CHECK, 174 },
    { "Racute", VERS_CHECK, 340 },
    { "Rang", VERS_CHECK, 10219 },
    { "Rarr", VERS_CHECK, 8608 },
    { "Rarrtl", VERS_CHECK, 10518 },
    { "Rcaron", VERS_CHECK, 344 },
    { "Rcedil", VERS_CHECK, 342 },
    { "Rcy", VERS_CHECK, 1056 },
    { "Re", VERS_CHECK, 8476 },
    { "ReverseElement", VERS_CHECK, 8715 },
    { "ReverseEquilibrium", VERS_CHECK, 8651 },
    { "ReverseUpEquilibrium", VERS_CHECK, 10607 },
    { "Rfr", VERS_CHECK, 8476 },
    { "Rho", VERS_FROM40, 929 },
    { "RightAngleBracket", VERS_CHECK, 10217 },
    { "RightArrow", VERS_CHECK, 8594 },
    { "RightArrowBar", VERS_CHECK, 8677 },
    { "RightArrowLeftArrow", VERS_CHECK, 8644 },
    { "RightCeiling", VERS_CHECK, 8969 },
    { "RightDoubleBracket", VERS_CHECK, 10215 },
    { "RightDownTeeVector", VERS_CHECK, 10589 },
    { "RightDownVector", VERS_CHECK, 8642 },
    { "RightDownVectorBar", VERS_CHECK, 10581 },
    { "RightFloor", VERS_CHECK, 8971 },
    { "RightTee", VERS_CHECK, 8866 },
    { "RightTeeArrow", VERS_CHECK, 8614 },
    { "RightTeeVector", VERS_CHECK, 10587 },
    { "RightTriangle", VERS_CHECK, 8883 },
    { "RightTriangleBar", VERS_CHECK, 10704 },
    { "RightTriangleEqual", VERS_CHECK, 8885 },
    { "RightUpDownVector", VERS_CHECK, 10575 },
    { "RightUpTeeVector", VERS_CHECK, 10588 },
    { "RightUpVector", VERS_CHECK, 8638 },
    { "RightUpVectorBar", VERS_CHECK, 10580 },
    { "RightVector", VERS_CHECK, 8640 },
    { "RightVectorBar", VERS_CHECK, 10579 },
    { "Rightarrow", VERS_CHECK, 8658 },
    { "Ropf", VERS_CHECK, 8477 },
    { "RoundImplies", VERS_CHECK, 10608 },
    { "Rrightarrow", VERS_CHECK, 8667 },
    { "Rscr", VERS_CHECK, 8475 },
    { "Rsh", VERS_CHECK, 8625 },
    { "RuleDelayed", VERS_CHECK, 10740 },
    { "SHCHcy", VERS_CHECK, 1065 },
    { "SHcy", VERS_CHECK, 1064 },
    { "SOFTcy", VERS_CHECK, 1068 },
    { "Sacute", VERS_CHECK, 346 },
    { "Sc", VERS_CHECK, 10940 },
    { "Scaron", VERS_FROM40, 352 },
    { "Scedil", VERS_CHECK, 350 },
    { "Scirc", VERS_CHECK, 348 },
    { "Scy", VERS_CHECK, 1057 },
    { "Sfr", VERS_CHECK, 120086 },
    { "ShortDownArrow", VERS_CHECK, 8595 },
    { "ShortLeftArrow", VERS_CHECK, 8592 },
    { "ShortRightArrow", VERS_CHECK, 8594 },
    { "ShortUpArrow", VERS_CHECK, 8593 },
    { "Sigma", VERS_FROM40, 931 },
    { "SmallCircle", VERS_CHECK, 8728 },
    { "Sopf", VERS_CHECK, 120138 },
    { "Sqrt", VERS_CHECK, 8730 },
    { "Square", VERS_CHECK, 9633 },
    { "SquareIntersection", VERS_CHECK, 8851 },
    { "SquareSubset", VERS_CHECK, 8847 },
    { "SquareSubsetEqual", VERS_CHECK, 8849 },
    { "SquareSuperset", VERS_CHECK, 8848 },
    { "SquareSupersetEqual", VERS_CHECK, 8850 },
    { "SquareUnion", VERS_CHECK, 8852 },
    { "Sscr", VERS_CHECK, 119982 },
    { "Star", VERS_CHECK, 8902 },
    { "Sub", VERS_CHECK, 8912 },
    { "Subset", VERS_CHECK, 8912 },
    { "SubsetEqual", VERS_CHECK, 8838 },
    { "Succeeds", VERS_CHECK, 8827 },
    { "SucceedsEqual", VERS_CHECK, 10928 },
    { "SucceedsSlantEqual", VERS_CHECK, 8829 },
    { "SucceedsTilde", VERS_CHECK, 8831 },
    { "SuchThat", VERS_CHECK, 8715 },
    { "Sum", VERS_CHECK, 8721 },
    { "Sup", VERS_CHECK, 8913 },
    { "Superset", VERS_CHECK, 8835 },
    { "SupersetEqual", VERS_CHECK, 8839 },
    { "Supset", VERS_CHECK, 8913 },
    { "THORN", VERS_ALL, 222 },
    { "TRADE", VERS_CHECK, 8482 },
    { "TSHcy", VERS_CHECK, 1035 },
    { "TScy", VERS_CHECK, 1062 },
    { "Tab", VERS_CHECK, 9 },
    { "Tau", VERS_FROM40, 932 },
    { "Tcaron", VERS_CHECK, 356 },
    { "Tcedil", VERS_CHECK, 354 },
    { "Tcy", VERS_CHECK, 1058 },
    { "Tfr", VERS_CHECK, 120087 },
    { "Therefore", VERS_CHECK, 8756 },
    { "Theta", VERS_FROM40, 920 },
    { "ThinSpace", VERS_CHECK, 8201 },
    { "Tilde", VERS_CHECK, 8764 },
    { "TildeEqual", VERS_CHECK, 8771 },
    { "TildeFullEqual", VERS_CHECK, 8773 },
    { "TildeTilde", VERS_CHECK, 8776 },
    { "Topf", VERS_CHECK, 120139 },
    { "TripleDot", VERS_CHECK, 8411 },
    { "Tscr", VERS_CHECK, 119983 },
    { "Tstrok", VERS_CHECK, 358 },
    { "Uacute", VERS_ALL, 218 },
    { "Uarr", VERS_CHECK, 8607 },
    { "Uarrocir", VERS_CHECK, 10569 },
    { "Ubrcy", VERS_CHECK, 1038 },
    { "Ubreve", VERS_CHECK, 364 },
    { "Ucirc", VERS_ALL, 219 },
    { "Ucy", VERS_CHECK, 1059 },
    { "Udblac", VERS_CHECK, 368 },
    { "Ufr", VERS_CHECK, 120088 },
    { "Ugrave", VERS_ALL, 217 },
    { "Umacr", VERS_CHECK, 362 },
    { "UnderBar", VERS_CHECK, 95 },
    { "UnderBrace", VERS_CHECK, 9183 },
    { "UnderBracket", VERS_CHECK, 9141 },
    { "UnderParenthesis", VERS_CHECK, 9181 },
    { "Union", VERS_CHECK, 8899 },
    { "UnionPlus", VERS_CHECK, 8846 },
    { "Uogon", VERS_CHECK, 370 },
    { "Uopf", VERS_CHECK, 120140 },
    { "UpArrow", VERS_CHECK, 8593 },
    { "UpArrowBar", VERS_CHECK, 10514 },
    { "UpArrowDownArrow", VERS_CHECK, 8645 },
    { "UpDownArrow", VERS_CHECK, 8597 },
    { "UpEquilibrium", VERS_CHECK, 10606 },
    { "UpTee", VERS_CHECK, 8869 },
    { "UpTeeArrow", VERS_CHECK, 8613 },
    { "Uparrow", VERS_CHECK, 8657 },
    { "Updownarrow", VERS_CHECK, 8661 },
    { "UpperLeftArrow", VERS_CHECK, 8598 },
    { "UpperRightArrow", VERS_CHECK, 8599 },
    { "Upsi", VERS_CHECK, 978 },
    { "Upsilon", VERS_FROM40, 933 },
    { "Uring", VERS_CHECK, 366 },
    { "Uscr", VERS_CHECK, 119984 },
    { "Utilde", VERS_CHECK, 360 },
    { "Uuml", VERS_ALL, 220 },
    { "VDash", VERS_CHECK, 8875 },
    { "Vbar", VERS_CHECK, 10987 },
    { "Vcy", VERS_CHECK, 1042 },
    { "Vdash", VERS_CHECK, 8873 },
    { "Vdashl", VERS_CHECK, 10982 },
    { "Vee", VERS_CHECK, 8897 },
    { "Verbar", VERS_CHECK, 8214 },
    { "Vert", VERS_CHECK, 8214 },
    { "VerticalBar", VERS_CHECK, 8739 },
    { "VerticalLine", VERS_CHECK, 124 },
    { "VerticalSeparator", VERS_CHECK, 10072 },
    { "VerticalTilde", VERS_CHECK, 8768 },
    { "VeryThinSpace", VERS_CHECK, 8202 },
    { "Vfr", VERS_CHECK, 120089 },
    { "Vopf", VERS_CHECK, 120141 },
    { "Vscr", VERS_CHECK, 119985 },
    { "Vvdash", VERS_CHECK, 8874 },
    { "Wcirc", VERS_CHECK, 372 },
    { "Wedge", VERS_CHECK, 8896 },
    { "Wfr", VERS_CHECK, 120090 },
    { "Wopf", VERS_CHECK, 120142 },
    { "Wscr", VERS_CHECK, 119986 },
    { "Xfr", VERS_CHECK, 120091 },
    { "Xi", VERS_FROM40, 926 },
    { "Xopf", VERS_CHECK, 120143 },
    { "Xscr", VERS_CHECK, 119987 },
    { "YAcy", VERS_CHECK, 1071 },
    { "YIcy", VERS_CHECK, 1031 },
    { "YUcy", VERS_CHECK, 1070 },
    { "Yacute", VERS_ALL, 221 },
    { "Ycirc", VERS_CHECK, 374 },
    { "Ycy", VERS_CHECK, 1067 },
    { "Yfr", VERS_CHECK, 120092 },
    { "Yopf", VERS_CHECK, 120144 },
    { "Yscr", VERS_CHECK, 119988 },
    { "Yuml", VERS_FROM40, 376 },
    { "ZHcy", VERS_CHECK, 1046 },
    { "Zacute", VERS_CHECK, 377 },
    { "Zcaron", VERS_CHECK, 381 },
    { "Zcy", VERS_CHECK, 1047 },
    { "Zdot", VERS_CHECK, 379 },
    { "ZeroWidthSpace", VERS_CHECK, 8203 },
    { "Zeta", VERS_FROM40, 918 },
    { "Zfr", VERS_CHECK, 8488 },
    { "Zopf", VERS_CHECK, 8484 },
    { "Zscr", VERS_CHECK, 119989 },
    { "aacute", VERS_ALL, 225 },
    { "abreve", VERS_CHECK, 259 },
    { "ac", VERS_CHECK, 8766 },
    { "acd", VERS_CHECK, 8767 },
    { "acirc", VERS_ALL, 226 },
    { "acute", VERS_ALL, 180 },
    { "acy", VERS_CHECK, 1072 },
    { "aelig", VERS_ALL, 230 },
    { "af", VERS_CHECK, 8289 },
    { "afr", VERS_CHECK, 120094 },
    { "agrave", VERS_ALL, 224 },
    { "alefsym", VERS_FROM40, 8501 },
    { "aleph", VERS_CHECK, 8501 },
    { "alpha", VERS_FROM40, 945 },
    { "amacr", VERS_CHECK, 257 },
    { "amalg", VERS_CHECK, 10815 },
    { "amp", VERS_ALL | VERS_XML, 38 },
    { "and", VERS_FROM40, 8743 },
    { "andand", VERS_CHECK, 10837 },
    { "andd", VERS_CHECK, 10844 },
    { "andslope", VERS_CHECK, 10840 },
    { "andv", VERS_CHECK, 10842 },
    { "ang", VERS_FROM40, 8736 },
    { "ange", VERS_CHECK, 10660 },
    { "angle", VERS_CHECK, 8736 },
    { "angmsd", VERS_CHECK, 8737 },
    { "angmsdaa", VERS_CHECK, 10664 },
    { "angmsdab", VERS_CHECK, 10665 },
    { "angmsdac", VERS_CHECK, 10666 },
    { "angmsdad", VERS_CHECK, 10667 },
    { "angmsdae", VERS_CHECK, 10668 },
    { "angmsdaf", VERS_CHECK, 10669 },
    { "angmsdag", VERS_CHECK, 10670 },
    { "angmsdah", VERS_CHECK, 10671 },
    { "angrt", VERS_CHECK, 8735 },
    { "angrtvb", VERS_CHECK, 8894 },
    { "angrtvbd", VERS_CHECK, 10653 },
    { "angsph", VERS_CHECK, 8738 },
    { "angst", VERS_CHECK, 197 },
    { "angzarr", VERS_CHECK, 9084 },
    { "aogon", VERS_CHECK, 261 },
    { "aopf", VERS_CHECK, 120146 },
    { "ap", VERS_CHECK, 8776 },
    { "apE", VERS_CHECK, 10864 },
    { "apacir", VERS_CHECK, 10863 },
    { "ape", VERS_CHECK, 8778 },
    { "apid", VERS_CHECK, 8779 },
    { "apos", VERS_FROM40 | VERS_XML, 39 },
    { "approx", VERS_CHECK, 8776 },
    { "approxeq", VERS_CHECK, 8778 },
    { "aring", VERS_ALL, 229 },
    { "ascr", VERS_CHECK, 119990 },
    { "ast", VERS_CHECK, 42 },
    { "asymp", VERS_FROM40, 8776 },
    { "asympeq", VERS_CHECK, 8781 },
    { "atilde", VERS_ALL, 227 },
    { "auml", VERS_ALL, 228 },
    { "awconint", VERS_CHECK, 8755 },
    { "awint", VERS_CHECK, 10769 },
    { "bNot", VERS_CHECK, 10989 },
    { "backcong", VERS_CHECK, 8780 },
    { "backepsilon", VERS_CHECK, 1014 },
    { "backprime", VERS_CHECK, 8245 },
    { "backsim", VERS_CHECK, 8765 },
    { "backsimeq", VERS_CHECK, 8909 },
    { "barvee", VERS_CHECK, 8893 },
    { "barwed", VERS_CHECK, 8965 },
    { "barwedge", VERS_CHECK, 8965 },
    { "bbrk", VERS_CHECK, 9141 },
    { "bbrktbrk", VERS_CHECK, 9142 },
    { "bcong", VERS_CHECK, 8780 },
    { "bcy", VERS_CHECK, 1073 },
    { "bdquo", VERS_FROM40, 8222 },
    { "becaus", VERS_CHECK, 8757 },
    { "because", VERS_CHECK, 8757 },
    { "bemptyv", VERS_CHECK, 10672 },
    { "bepsi", VERS_CHECK, 1014 },
    { "bernou", VERS_CHECK, 8492 },
    { "beta", VERS_FROM40, 946 },
    { "beth", VERS_CHECK, 8502 },
    { "between", VERS_CHECK, 8812 },
    { "bfr", VERS_CHECK, 120095 },
    { "bigcap", VERS_CHECK, 8898 },
    { "bigcirc", VERS_CHECK, 9711 },
    { "bigcup", VERS_CHECK, 8899 },
    { "bigodot", VERS_CHECK, 10752 },
    { "bigoplus", VERS_CHECK, 10753 },
    { "bigotimes", VERS_CHECK, 10754 },
    { "bigsqcup", VERS_CHECK, 10758 },
    { "bigstar", VERS_CHECK, 9733 },
    { "bigtriangledown", VERS_CHECK, 9661 },
    { "bigtriangleup", VERS_CHECK, 9651 },
    { "biguplus", VERS_CHECK, 10756 },
    { "bigvee", VERS_CHECK, 8897 },
    { "bigwedge", VERS_CHECK, 8896 },
    { "bkarow", VERS_CHECK, 10509 },
    { "blacklozenge", VERS_CHECK, 10731 },
    { "blacksquare", VERS_CHECK, 9642 },
    { "blacktriangle", VERS_CHECK, 9652 },
    { "blacktriangledown", VERS_CHECK, 9662 },
    { "blacktriangleleft", VERS_CHECK, 9666 },
    { "blacktriangleright", VERS_CHECK, 9656 },
    { "blank", VERS_CHECK, 9251 },
    { "blk12", VERS_CHECK, 9618 },
    { "blk14", VERS_CHECK, 9617 },
    { "blk34", VERS_CHECK, 9619 },
    { "block", VERS_CHECK, 9608 },
    { "bnot", VERS_CHECK, 8976 },
    { "bopf", VERS_CHECK, 120147 },
    { "bot", VERS_CHECK, 8869 },
    { "bottom", VERS_CHECK, 8869 },
    { "bowtie", VERS_CHECK, 8904 },
    { "boxDL", VERS_CHECK, 9559 },
    { "boxDR", VERS_CHECK, 9556 },
    { "boxDl", VERS_CHECK, 9558 },
    { "boxDr", VERS_CHECK, 9555 },
    { "boxH", VERS_CHECK, 9552 },
    { "boxHD", VERS_CHECK, 9574 },
    { "boxHU", VERS_CHECK, 9577 },
    { "boxHd", VERS_CHECK, 9572 },
    { "boxHu", VERS_CHECK, 9575 },
    { "boxUL", VERS_CHECK, 9565 },
    { "boxUR", VERS_CHECK, 9562 },
    { "boxUl", VERS_CHECK, 9564 },
    { "boxUr", VERS_CHECK, 9561 },
    { "boxV", VERS_CHECK, 9553 },
    { "boxVH", VERS_CHECK, 9580 },
    { "boxVL", VERS_CHECK, 9571 },
    { "boxVR", VERS_CHECK, 9568 },
    { "boxVh", VERS_CHECK, 9579 },
    { "boxVl", VERS_CHECK, 9570 },
    { "boxVr", VERS_CHECK, 9567 },
    { "boxbox", VERS_CHECK, 10697 },
    { "boxdL", VERS_CHECK, 9557 },
    { "boxdR", VERS_CHECK, 9554 },
    { "boxdl", VERS_CHECK, 9488 },
    { "boxdr", VERS_CHECK, 9484 },
    { "boxh", VERS_CHECK, 9472 },
    { "boxhD", VERS_CHECK, 9573 },
    { "boxhU", VERS_CHECK, 9576 },
    { "boxhd", VERS_CHECK, 9516 },
    { "boxhu", VERS_CHECK, 9524 },
    { "boxminus", VERS_CHECK, 8863 },
    { "boxplus", VERS_CHECK, 8862 },
    { "boxtimes", VERS_CHECK, 8864 },
    { "boxuL", VERS_CHECK, 9563 },
    { "boxuR", VERS_CHECK, 9560 },
    { "boxul", VERS_CHECK, 9496 },
    { "boxur", VERS_CHECK, 9492 },
    { "boxv", VERS_CHECK, 9474 },
    { "boxvH", VERS_CHECK, 9578 },
    { "boxvL", VERS_CHECK, 9569 },
    { "boxvR", VERS_CHECK, 9566 },
    { "boxvh", VERS_CHECK, 9532 },
    { "boxvl", VERS_CHECK, 9508 },
    { "boxvr", VERS_CHECK, 9500 },
    { "bprime", VERS_CHECK, 8245 },
    { "breve", VERS_CHECK, 728 },
    { "brvbar", VERS_ALL, 166 },
    { "bscr", VERS_CHECK, 119991 },
    { "bsemi", VERS_CHECK, 8271 },
    { "bsim", VERS_CHECK, 8765 },
    { "bsime", VERS_CHECK, 8909 },
    { "bsol", VERS_CHECK, 92 },
    { "bsolb", VERS_CHECK, 10693 },
    { "bsolhsub", VERS_CHECK, 10184 },
    { "bull", VERS_FROM40, 8226 },
    { "bullet", VERS_CHECK, 8226 },
    { "bump", VERS_CHECK, 8782 },
    { "bumpE", VERS_CHECK, 10926 },
    { "bumpe", VERS_CHECK, 8783 },
    { "bumpeq", VERS_CHECK, 8783 },
    { "cacute", VERS_CHECK, 263 },
    { "cap", VERS_FROM40, 8745 },
    { "capand", VERS_CHECK, 10820 },
    { "capbrcup", VERS_CHECK, 10825 },
    { "capcap", VERS_CHECK, 10827 },
    { "capcup", VERS_CHECK, 10823 },
    { "capdot", VERS_CHECK, 10816 },
    { "caret", VERS_CHECK, 8257 },
    { "caron", VERS_CHECK, 711 },
    { "ccaps", VERS_CHECK, 10829 },
    { "ccaron", VERS_CHECK, 269 },
    { "ccedil", VERS_ALL, 231 },
    { "ccirc", VERS_CHECK, 265 },
    { "ccups", VERS_CHECK, 10828 },
    { "ccupssm", VERS_CHECK, 10832 },
    { "cdot", VERS_CHECK, 267 },
    { "cedil", VERS_ALL, 184 },
    { "cemptyv", VERS_CHECK, 10674 },
    { "cent", VERS_ALL, 162 },
    { "centerdot", VERS_CHECK, 183 },
    { "cfr", VERS_CHECK, 120096 },
    { "chcy", VERS_CHECK, 1095 },
    { "check", VERS_CHECK, 10003 },
    { "checkmark", VERS_CHECK, 10003 },
    { "chi", VERS_FROM40, 967 },
    { "cir", VERS_CHECK, 9675 },
    { "cirE", VERS_CHECK, 10691 },
    { "circ", VERS_FROM40, 710 },
    { "circeq", VERS_CHECK, 8791 },
    { "circlearrowleft", VERS_CHECK, 8634 },
    { "circlearrowright", VERS_CHECK, 8635 },
    { "circledR", VERS_CHECK, 174 },
    { "circledS", VERS_CHECK, 9416 },
    { "circledast", VERS_CHECK, 8859 },
    { "circledcirc", VERS_CHECK, 8858 },
    { "circleddash", VERS_CHECK, 8861 },
    { "cire", VERS_CHECK, 8791 },
    { "cirfnint", VERS_CHECK, 10768 },
    { "cirmid", VERS_CHECK, 10991 },
    { "cirscir", VERS_CHECK, 10690 },
    { "clubs", VERS_FROM40, 9827 },
    { "clubsuit", VERS_CHECK, 9827 },
    { "colon", VERS_CHECK, 58 },
    { "colone", VERS_CHECK, 8788 },
    { "coloneq", VERS_CHECK, 8788 },
    { "comma", VERS_CHECK, 44 },
    { "commat", VERS_CHECK, 64 },
    { "comp", VERS_CHECK, 8705 },
    { "compfn", VERS_CHECK, 8728 },
    { "complement", VERS_CHECK, 8705 },
    { "complexes", VERS_CHECK, 8450 },
    { "cong", VERS_FROM40, 8773 },
    { "congdot", VERS_CHECK, 10861 },
    { "conint", VERS_CHECK, 8750 },
    { "copf", VERS_CHECK, 120148 },
    { "coprod", VERS_CHECK, 8720 },
    { "copy", VERS_ALL, 169 },
    { "copysr", VERS_CHECK, 8471 },
    { "crarr", VERS_FROM40, 8629 },
    { "cross", VERS_CHECK, 10007 },
    { "cscr", VERS_CHECK, 119992 },
    { "csub", VERS_CHECK, 10959 },
    { "csube", VERS_CHECK, 10961 },
    { "csup", VERS_CHECK, 10960 },
    { "csupe", VERS_CHECK, 10962 },
    { "ctdot", VERS_CHECK, 8943 },
    { "cudarrl", VERS_CHECK, 10552 },
    { "cudarrr", VERS_CHECK, 10549 },
    { "cuepr", VERS_CHECK, 8926 },
    { "cuesc", VERS_CHECK, 8927 },
    { "cularr", VERS_CHECK, 8630 },
    { "cularrp", VERS_CHECK, 10557 },
    { "cup", VERS_FROM40, 8746 },
    { "cupbrcap", VERS_CHECK, 10824 },
    { "cupcap", VERS_CHECK, 10822 },
    { "cupcup", VERS_CHECK, 10826 },
    { "cupdot", VERS_CHECK, 8845 },
    { "cupor", VERS_CHECK, 10821 },
    { "curarr", VERS_CHECK, 8631 },
    { "curarrm", VERS_CHECK, 10556 },
    { "curlyeqprec", VERS_CHECK, 8926 },
    { "curlyeqsucc", VERS_CHECK, 8927 },
    { "curlyvee", VERS_CHECK, 8910 },
    { "curlywedge", VERS_CHECK, 8911 },
    { "curren", VERS_ALL, 164 },
    { "curvearrowleft", VERS_CHECK, 8630 },
    { "curvearrowright", VERS_CHECK, 8631 },
    { "cuvee", VERS_CHECK, 8910 },
    { "cuwed", VERS_CHECK, 8911 },
    { "cwconint", VERS_CHECK, 8754 },
    { "cwint", VERS_CHECK, 8753 },
    { "cylcty", VERS_CHECK, 9005 },
    { "dArr", VERS_FROM40, 8659 },
    { "dHar", VERS_CHECK, 10597 },
    { "dagger", VERS_FROM40, 8224 },
    { "daleth", VERS_CHECK, 8504 },
    { "darr", VERS_FROM40, 8595 },
    { "dash", VERS_CHECK, 8208 },
    { "dashv", VERS_CHECK, 8867 },
    { "dbkarow", VERS_CHECK, 10511 },
    { "dblac", VERS_CHECK, 733 },
    { "dcaron", VERS_CHECK, 271 },
    { "dcy", VERS_CHECK, 1076 },
    { "dd", VERS_CHECK, 8518 },
    { "ddagger", VERS_CHECK, 8225 },
    { "ddarr", VERS_CHECK, 8650 },
    { "ddotseq", VERS_CHECK, 10871 },
    { "deg", VERS_ALL, 176 },
    { "delta", VERS_FROM40, 948 },
    { "demptyv", VERS_CHECK, 10673 },
    { "dfisht", VERS_CHECK, 10623 },
    { "dfr", VERS_CHECK, 120097 },
    { "dharl", VERS_CHECK, 8643 },
    { "dharr", VERS_CHECK, 8642 },
    { "diam", VERS_CHECK, 8900 },
    { "diamond", VERS_CHECK, 8900 },
    { "diamondsuit", VERS_CHECK, 9830 },
    { "diams", VERS_FROM40, 9830 },
    { "die", VERS_CHECK, 168 },
    { "digamma", VERS_CHECK, 989 },
    { "disin", VERS_CHECK, 8946 },
    { "div", VERS_CHECK, 247 },
    { "divide", VERS_ALL, 247 },
    { "divideontimes", VERS_CHECK, 8903 },
    { "divonx", VERS_CHECK, 8903 },
    { "djcy", VERS_CHECK, 1106 },
    { "dlcorn", VERS_CHECK, 8990 },
    { "dlcrop", VERS_CHECK, 8973 },
    { "dollar", VERS_CHECK, 36 },
    { "dopf", VERS_CHECK, 120149 },
    { "dot", VERS_CHECK, 729 },
    { "doteq", VERS_CHECK, 8784 },
    { "doteqdot", VERS_CHECK, 8785 },
    { "dotminus", VERS_CHECK, 8760 },
    { "dotplus", VERS_CHECK, 8724 },
    { "dotsquare", VERS_CHECK, 8865 },
    { "doublebarwedge", VERS_CHECK, 8966 },
    { "downarrow", VERS_CHECK, 8595 },
    { "downdownarrows", VERS_CHECK, 8650 },
    { "downharpoonleft", VERS_CHECK, 8643 },
    { "downharpoonright", VERS_CHECK, 8642 },
    { "drbkarow", VERS_CHECK, 10512 },
    { "drcorn", VERS_CHECK, 8991 },
    { "drcrop", VERS_CHECK, 8972 },
    { "dscr", VERS_CHECK, 119993 },
    { "dscy", VERS_CHECK, 1109 },
    { "dsol", VERS_CHECK, 10742 },
    { "dstrok", VERS_CHECK, 273 },
    { "dtdot", VERS_CHECK, 8945 },
    { "dtri", VERS_CHECK, 9663 },
    { "dtrif", VERS_CHECK, 9662 },
    { "duarr", VERS_CHECK, 8693 },
    { "duhar", VERS_CHECK, 10607 },
    { "dwangle", VERS_CHECK, 10662 },
    { "dzcy", VERS_CHECK, 1119 },
    { "dzigrarr", VERS_CHECK, 10239 },
    { "eDDot", VERS_CHECK, 10871 },
    { "eDot", VERS_CHECK, 8785 },
    { "eacute", VERS_ALL, 233 },
    { "easter", VERS_CHECK, 10862 },
    { "ecaron", VERS_CHECK, 283 },
    { "ecir", VERS_CHECK, 8790 },
    { "ecirc", VERS_ALL, 234 },
    { "ecolon", VERS_CHECK, 8789 },
    { "ecy", VERS_CHECK, 1101 },
    { "edot", VERS_CHECK, 279 },
    { "ee", VERS_CHECK, 8519 },
    { "efDot", VERS_CHECK, 8786 },
    { "efr", VERS_CHECK, 120098 },
    { "eg", VERS_CHECK, 10906 },
    { "egrave", VERS_ALL, 232 },
    { "egs", VERS_CHECK, 10902 },
    { "egsdot", VERS_CHECK, 10904 },
    { "el", VERS_CHECK, 10905 },
    { "elinters", VERS_CHECK, 9191 },
    { "ell", VERS_CHECK, 8467 },
    { "els", VERS_CHECK, 10901 },
    { "elsdot", VERS_CHECK, 10903 },
    { "emacr", VERS_CHECK, 275 },
    { "empty", VERS_FROM40, 8709 },
    { "emptyset", VERS_CHECK, 8709 },
    { "emptyv", VERS_CHECK, 8709 },
    { "emsp", VERS_FROM40, 8195 },
    { "emsp13", VERS_CHECK, 8196 },
    { "emsp14", VERS_CHECK, 8197 },
    { "eng", VERS_CHECK, 331 },
    { "ensp", VERS_FROM40, 8194 },
    { "eogon", VERS_CHECK, 281 },
    { "eopf", VERS_CHECK, 120150 },
    { "epar", VERS_CHECK, 8917 },
    { "eparsl", VERS_CHECK, 10723 },
    { "eplus", VERS_CHECK, 10865 },
    { "epsi", VERS_CHECK, 949 },
    { "epsilon", VERS_FROM40, 949 },
    { "epsiv", VERS_CHECK, 1013 },
    { "eqcirc", VERS_CHECK, 8790 },
    { "eqcolon", VERS_CHECK, 8789 },
    { "eqsim", VERS_CHECK, 8770 },
    { "eqslantgtr", VERS_CHECK, 10902 },
    { "eqslantless", VERS_CHECK, 10901 },
    { "equals", VERS_CHECK, 61 },
    { "equest", VERS_CHECK, 8799 },
    { "equiv", VERS_FROM40, 8801 },
    { "equivDD", VERS_CHECK, 10872 },
    { "eqvparsl", VERS_CHECK, 10725 },
    { "erDot", VERS_CHECK, 8787 },
    { "erarr", VERS_CHECK, 10609 },
    { "escr", VERS_CHECK, 8495 },
    { "esdot", VERS_CHECK, 8784 },
    { "esim", VERS_CHECK, 8770 },
    { "eta", VERS_FROM40, 951 },
    { "eth", VERS_ALL, 240 },
    { "euml", VERS_ALL, 235 },
    { "euro", VERS_FROM40, 8364 },
    { "excl", VERS_CHECK, 33 },
    { "exist", VERS_FROM40, 8707 },
    { "expectation", VERS_CHECK, 8496 },
    { "exponentiale", VERS_CHECK, 8519 },
    { "fallingdotseq", VERS_CHECK, 8786 },
    { "fcy", VERS_CHECK, 1092 },
    { "female", VERS_CHECK, 9792 },
    { "ffilig", VERS_CHECK, 64259 },
    { "fflig", VERS_CHECK, 64256 },
    { "ffllig", VERS_CHECK, 64260 },
    { "ffr", VERS_CHECK, 120099 },
    { "filig", VERS_CHECK, 64257 },
    { "flat", VERS_CHECK, 9837 },
    { "fllig", VERS_CHECK, 64258 },
    { "fltns", VERS_CHECK, 9649 },
    { "fnof", VERS_FROM40, 402 },
    { "fopf", VERS_CHECK, 120151 },
    { "forall", VERS_FROM40, 8704 },
    { "fork", VERS_CHECK, 8916 },
    { "forkv", VERS_CHECK, 10969 },
    { "fpartint", VERS_CHECK, 10765 },
    { "frac12", VERS_ALL, 189 },
    { "frac13", VERS_CHECK, 8531 },
    { "frac14", VERS_ALL, 188 },
    { "frac15", VERS_CHECK, 8533 },
    { "frac16", VERS_CHECK, 8537 },
    { "frac18", VERS_CHECK, 8539 },
    { "frac23", VERS_CHECK, 8532 },
    { "frac25", VERS_CHECK, 8534 },
    { "frac34", VERS_ALL, 190 },
    { "frac35", VERS_CHECK, 8535 },
    { "frac38", VERS_CHECK, 8540 },
    { "frac45", VERS_CHECK, 8536 },
    { "frac56", VERS_CHECK, 8538 },
    { "frac58", VERS_CHECK, 8541 },
    { "frac78", VERS_CHECK, 8542 },
    { "frasl", VERS_FROM40, 8260 },
    { "frown", VERS_CHECK, 8994 },
    { "fscr", VERS_CHECK, 119995 },
    { "gE", VERS_CHECK, 8807 },
    { "gEl", VERS_CHECK, 10892 },
    { "gacute", VERS_CHECK, 501 },
    { "gamma", VERS_FROM40, 947 },
    { "gammad", VERS_CHECK, 989 },
    { "gap", VERS_CHECK, 10886 },
    { "gbreve", VERS_CHECK, 287 },
    { "gcirc", VERS_CHECK, 285 },
    { "gcy", VERS_CHECK, 1075 },
    { "gdot", VERS_CHECK, 289 },
    { "ge", VERS_FROM40, 8805 },
    { "gel", VERS_CHECK, 8923 },
    { "geq", VERS_CHECK, 8805 },
    { "geqq", VERS_CHECK, 8807 },
    { "geqslant", VERS_CHECK, 10878 },
    { "ges", VERS_CHECK, 10878 },
    { "gescc", VERS_CHECK, 10921 },
    { "gesdot", VERS_CHECK, 10880 },
    { "gesdoto", VERS_CHECK, 10882 },
    { "gesdotol", VERS_CHECK, 10884 },
    { "gesles", VERS_CHECK, 10900 },
    { "gfr", VERS_CHECK, 120100 },
    { "gg", VERS_CHECK, 8811 },
    { "ggg", VERS_CHECK, 8921 },
    { "gimel", VERS_CHECK, 8503 },
    { "gjcy", VERS_CHECK, 1107 },
    { "gl", VERS_CHECK, 8823 },
    { "glE", VERS_CHECK, 10898 },
    { "gla", VERS_CHECK, 10917 },
    { "glj", VERS_CHECK, 10916 },
    { "gnE", VERS_CHECK, 8809 },
    { "gnap", VERS_CHECK, 10890 },
    { "gnapprox", VERS_CHECK, 10890 },
    { "gne", VERS_CHECK, 10888 },
    { "gneq", VERS_CHECK, 10888 },
    { "gneqq", VERS_CHECK, 8809 },
    { "gnsim", VERS_CHECK, 8935 },
    { "gopf", VERS_CHECK, 120152 },
    { "grave", VERS_CHECK, 96 },
    { "gscr", VERS_CHECK, 8458 },
    { "gsim", VERS_CHECK, 8819 },
    { "gsime", VERS_CHECK, 10894 },
    { "gsiml", VERS_CHECK, 10896 },
    { "gt", VERS_ALL | VERS_XML, 62 },
    { "gtcc", VERS_CHECK, 10919 },
    { "gtcir", VERS_CHECK, 10874 },
    { "gtdot", VERS_CHECK, 8919 },
    { "gtlPar", VERS_CHECK, 10645 },
    { "gtquest", VERS_CHECK, 10876 },
    { "gtrapprox", VERS_CHECK, 10886 },
    { "gtrarr", VERS_CHECK, 10616 },
    { "gtrdot", VERS_CHECK, 8919 },
    { "gtreqless", VERS_CHECK, 8923 },
    { "gtreqqless", VERS_CHECK, 10892 },
    { "gtrless", VERS_CHECK, 8823 },
    { "gtrsim", VERS_CHECK, 8819 },
    { "hArr", VERS_FROM40, 8660 },
    { "hairsp", VERS_CHECK, 8202 },
    { "half", VERS_CHECK, 189 },
    { "hamilt", VERS_CHECK, 8459 },
    { "hardcy", VERS_CHECK, 1098 },
    { "harr", VERS_FROM40, 8596 },
    { "harrcir", VERS_CHECK, 10568 },
    { "harrw", VERS_CHECK, 8621 },
    { "hbar", VERS_CHECK, 8463 },
    { "hcirc", VERS_CHECK, 293 },
    { "hearts", VERS_FROM40, 9829 },
    { "heartsuit", VERS_CHECK, 9829 },
    { "hellip", VERS_FROM40, 8230 },
    { "hercon", VERS_CHECK, 8889 },
    { "hfr", VERS_CHECK, 120101 },
    { "hksearow", VERS_CHECK, 10533 },
    { "hkswarow", VERS_CHECK, 10534 },
    { "hoarr", VERS_CHECK, 8703 },
    { "homtht", VERS_CHECK, 8763 },
    { "hookleftarrow", VERS_CHECK, 8617 },
    { "hookrightarrow", VERS_CHECK, 8618 },
    { "hopf", VERS_CHECK, 120153 },
    { "horbar", VERS_CHECK, 8213 },
    { "hscr", VERS_CHECK, 119997 },
    { "hslash", VERS_CHECK, 8463 },
    { "hstrok", VERS_CHECK, 295 },
    { "hybull", VERS_CHECK, 8259 },
    { "hyphen", VERS_CHECK, 8208 },
    { "iacute", VERS_ALL, 237 },
    { "ic", VERS_CHECK, 8291 },
    { "icirc", VERS_ALL, 238 },
    { "icy", VERS_CHECK, 1080 },
    { "iecy", VERS_CHECK, 1077 },
    { "iexcl", VERS_ALL, 161 },
    { "iff", VERS_CHECK, 8660 },
    { "ifr", VERS_CHECK, 120102 },
    { "igrave", VERS_ALL, 236 },
    { "ii", VERS_CHECK, 8520 },
    { "iiiint", VERS_CHECK, 10764 },
    { "iiint", VERS_CHECK, 8749 },
    { "iinfin", VERS_CHECK, 10716 },
    { "iiota", VERS_CHECK, 8489 },
    { "ijlig", VERS_CHECK, 307 },
    { "imacr", VERS_CHECK, 299 },
    { "image", VERS_FROM40, 8465 },
    { "imagline", VERS_CHECK, 8464 },
    { "imagpart", VERS_CHECK, 8465 },
    { "imath", VERS_CHECK, 305 },
    { "imof", VERS_CHECK, 8887 },
    { "imped", VERS_CHECK, 437 },
    { "in", VERS_CHECK, 8712 },
    { "incare", VERS_CHECK, 8453 },
    { "infin", VERS_FROM40, 8734 },
    { "infintie", VERS_CHECK, 10717 },
    { "inodot", VERS_CHECK, 305 },
    { "int", VERS_FROM40, 8747 },
    { "intcal", VERS_CHECK, 8890 },
    { "integers", VERS_CHECK, 8484 },
    { "intercal", VERS_CHECK, 8890 },
    { "intlarhk", VERS_CHECK, 10775 },
    { "intprod", VERS_CHECK, 10812 },
    { "iocy", VERS_CHECK, 1105 },
    { "iogon", VERS_CHECK, 303 },
    { "iopf", VERS_CHECK, 120154 },
    { "iota", VERS_FROM40, 953 },
    { "iprod", VERS_CHECK, 10812 },
    { "iquest", VERS_ALL, 191 },
    { "iscr", VERS_CHECK, 119998 },
    { "isin", VERS_FROM40, 8712 },
    { "isinE", VERS_CHECK, 8953 },
    { "isindot", VERS_CHECK, 8949 },
    { "isins", VERS_CHECK, 8948 },
    { "isinsv", VERS_CHECK, 8947 },
    { "isinv", VERS_CHECK, 8712 },
    { "it", VERS_CHECK, 8290 },
    { "itilde", VERS_CHECK, 297 },
    { "iukcy", VERS_CHECK, 1110 },
    { "iuml", VERS_ALL, 239 },
    { "jcirc", VERS_CHECK, 309 },
    { "jcy", VERS_CHECK, 1081 },
    { "jfr", VERS_CHECK, 120103 },
    { "jmath", VERS_CHECK, 567 },
    { "jopf", VERS_CHECK, 120155 },
    { "jscr", VERS_CHECK, 119999 },
    { "jsercy", VERS_CHECK, 1112 },
    { "jukcy", VERS_CHECK, 1108 },
    { "kappa", VERS_FROM40, 954 },
    { "kappav", VERS_CHECK, 1008 },
    { "kcedil", VERS_CHECK, 311 },
    { "kcy", VERS_CHECK, 1082 },
    { "kfr", VERS_CHECK, 120104 },
    { "kgreen", VERS_CHECK, 312 },
    { "khcy", VERS_CHECK, 1093 },
    { "kjcy", VERS_CHECK, 1116 },
    { "kopf", VERS_CHECK, 120156 },
    { "kscr", VERS_CHECK, 120000 },
    { "lAarr", VERS_CHECK, 8666 },
    { "lArr", VERS_FROM40, 8656 },
    { "lAtail", VERS_CHECK, 10523 },
    { "lBarr", VERS_CHECK, 10510 },
    { "lE", VERS_CHECK, 8806 },
    { "lEg", VERS_CHECK, 10891 },
    { "lHar", VERS_CHECK, 10594 },
    { "lacute", VERS_CHECK, 314 },
    { "laemptyv", VERS_CHECK, 10676 },
    { "lagran", VERS_CHECK, 8466 },
    { "lambda", VERS_FROM40, 955 },
    { "lang", VERS_FROM40, 10216 },
    { "langd", VERS_CHECK, 10641 },
    { "langle", VERS_CHECK, 10216 },
    { "lap", VERS_CHECK, 10885 },
    { "laquo", VERS_ALL, 171 },
    { "larr", VERS_FROM40, 8592 },
    { "larrb", VERS_CHECK, 8676 },
    { "larrbfs", VERS_CHECK, 10527 },
    { "larrfs", VERS_CHECK, 10525 },
    { "larrhk", VERS_CHECK, 8617 },
    { "larrlp", VERS_CHECK, 8619 },
    { "larrpl", VERS_CHECK, 10553 },
    { "larrsim", VERS_CHECK, 10611 },
    { "larrtl", VERS_CHECK, 8610 },
    { "lat", VERS_CHECK, 10923 },
    { "latail", VERS_CHECK, 10521 },
    { "late", VERS_CHECK, 10925 },
    { "lbarr", VERS_CHECK, 10508 },
    { "lbbrk", VERS_CHECK, 10098 },
    { "lbrace", VERS_CHECK, 123 },
    { "lbrack", VERS_CHECK, 91 },
    { "lbrke", VERS_CHECK, 10635 },
    { "lbrksld", VERS_CHECK, 10639 },
    { "lbrkslu", VERS_CHECK, 10637 },
    { "lcaron", VERS_CHECK, 318 },
    { "lcedil", VERS_CHECK, 316 },
    { "lceil", VERS_FROM40, 8968 },
    { "lcub", VERS_CHECK, 123 },
    { "lcy", VERS_CHECK, 1083 },
    { "ldca", VERS_CHECK, 10550 },
    { "ldquo", VERS_FROM40, 8220 },
    { "ldquor", VERS_CHECK, 8222 },
    { "ldrdhar", VERS_CHECK, 10599 },
    { "ldrushar", VERS_CHECK, 10571 },
    { "ldsh", VERS_CHECK, 8626 },
    { "le", VERS_FROM40, 8804 },
    { "leftarrow", VERS_CHECK, 8592 },
    { "leftarrowtail", VERS_CHECK, 8610 },
    { "leftharpoondown", VERS_CHECK, 8637 },
    { "leftharpoonup", VERS_CHECK, 8636 },
    { "leftleftarrows", VERS_CHECK, 8647 },
    { "leftrightarrow", VERS_CHECK, 8596 },
    { "leftrightarrows", VERS_CHECK, 8646 },
    { "leftrightharpoons", VERS_CHECK, 8651 },
    { "leftrightsquigarrow", VERS_CHECK, 8621 },
    { "leftthreetimes", VERS_CHECK, 8907 },
    { "leg", VERS_CHECK, 8922 },
    { "leq", VERS_CHECK, 8804 },
    { "leqq", VERS_CHECK, 8806 },
    { "leqslant", VERS_CHECK, 10877 },
    { "les", VERS_CHECK, 10877 },
    { "lescc", VERS_CHECK, 10920 },
    { "lesdot", VERS_CHECK, 10879 },
    { "lesdoto", VERS_CHECK, 10881 },
    { "lesdotor", VERS_CHECK, 10883 },
    { "lesges", VERS_CHECK, 10899 },
    { "lessapprox", VERS_CHECK, 10885 },
    { "lessdot", VERS_CHECK, 8918 },
    { "lesseqgtr", VERS_CHECK, 8922 },
    { "lesseqqgtr", VERS_CHECK, 10891 },
    { "lessgtr", VERS_CHECK, 8822 },
    { "lesssim", VERS_CHECK, 8818 },
    { "lfisht", VERS_CHECK, 10620 },
    { "lfloor", VERS_FROM40, 8970 },
    { "lfr", VERS_CHECK, 120105 },
    { "lg", VERS_CHECK, 8822 },
    { "lgE", VERS_CHECK, 10897 },
    { "lhard", VERS_CHECK, 8637 },
    { "lharu", VERS_CHECK, 8636 },
    { "lharul", VERS_CHECK, 10602 },
    { "lhblk", VERS_CHECK, 9604 },
    { "ljcy", VERS_CHECK, 1113 },
    { "ll", VERS_CHECK, 8810 },
    { "llarr", VERS_CHECK, 8647 },
    { "llcorner", VERS_CHECK, 8990 },
    { "llhard", VERS_CHECK, 10603 },
    { "lltri", VERS_CHECK, 9722 },
    { "lmidot", VERS_CHECK, 320 },
    { "lmoust", VERS_CHECK, 9136 },
    { "lmoustache", VERS_CHECK, 9136 },
    { "lnE", VERS_CHECK, 8808 },
    { "lnap", VERS_CHECK, 10889 },
    { "lnapprox", VERS_CHECK, 10889 },
    { "lne", VERS_CHECK, 10887 },
    { "lneq", VERS_CHECK, 10887 },
    { "lneqq", VERS_CHECK, 8808 },
    { "lnsim", VERS_CHECK, 8934 },
    { "loang", VERS_CHECK, 10220 },
    { "loarr", VERS_CHECK, 8701 },
    { "lobrk", VERS_CHECK, 10214 },
    { "longleftarrow", VERS_CHECK, 10229 },
    { "longleftrightarrow", VERS_CHECK, 10231 },
    { "longmapsto", VERS_CHECK, 10236 },
    { "longrightarrow", VERS_CHECK, 10230 },
    { "looparrowleft", VERS_CHECK, 8619 },
    { "looparrowright", VERS_CHECK, 8620 },
    { "lopar", VERS_CHECK, 10629 },
    { "lopf", VERS_CHECK, 120157 },
    { "loplus", VERS_CHECK, 10797 },
    { "lotimes", VERS_CHECK, 10804 },
    { "lowast", VERS_FROM40, 8727 },
    { "lowbar", VERS_CHECK, 95 },
    { "loz", VERS_FROM40, 9674 },
    { "lozenge", VERS_CHECK, 9674 },
    { "lozf", VERS_CHECK, 10731 },
    { "lpar", VERS_CHECK, 40 },
    { "lparlt", VERS_CHECK, 10643 },
    { "lrarr", VERS_CHECK, 8646 },
    { "lrcorner", VERS_CHECK, 8991 },
    { "lrhar", VERS_CHECK, 8651 },
    { "lrhard", VERS_CHECK, 10605 },
    { "lrm", VERS_FROM40, 8206 },
    { "lrtri", VERS_CHECK, 8895 },
    { "lsaquo", VERS_FROM40, 8249 },
    { "lscr", VERS_CHECK, 120001 },
    { "lsh", VERS_CHECK, 8624 },
    { "lsim", VERS_CHECK, 8818 },
    { "lsime", VERS_CHECK, 10893 },
    { "lsimg", VERS_CHECK, 10895 },
    { "lsqb", VERS_CHECK, 91 },
    { "lsquo", VERS_FROM40, 8216 },
    { "lsquor", VERS_CHECK, 8218 },
    { "lstrok", VERS_CHECK, 322 },
    { "lt", VERS_ALL | VERS_XML, 60 },
    { "ltcc", VERS_CHECK, 10918 },
    { "ltcir", VERS_CHECK, 10873 },
    { "ltdot", VERS_CHECK, 8918 },
    { "lthree", VERS_CHECK, 8907 },
    { "ltimes", VERS_CHECK, 8905 },
    { "ltlarr", VERS_CHECK, 10614 },
    { "ltquest", VERS_CHECK, 10875 },
    { "ltrPar", VERS_CHECK, 10646 },
    { "ltri", VERS_CHECK, 9667 },
    { "ltrie", VERS_CHECK, 8884 },
    { "ltrif", VERS_CHECK, 9666 },
    { "lurdshar", VERS_CHECK, 10570 },
    { "luruhar", VERS_CHECK, 10598 },
    { "mDDot", VERS_CHECK, 8762 },
    { "macr", VERS_ALL, 175 },
    { "male", VERS_CHECK, 9794 },
    { "malt", VERS_CHECK, 10016 },
    { "maltese", VERS_CHECK, 10016 },
    { "map", VERS_CHECK, 8614 },
    { "mapsto", VERS_CHECK, 8614 },
    { "mapstodown", VERS_CHECK, 8615 },
    { "mapstoleft", VERS_CHECK, 8612 },
    { "mapstoup", VERS_CHECK, 8613 },
    { "marker", VERS_CHECK, 9646 },
    { "mcomma", VERS_CHECK, 10793 },
    { "mcy", VERS_CHECK, 1084 },
    { "mdash", VERS_FROM40, 8212 },
    { "measuredangle", VERS_CHECK, 8737 },
    { "mfr", VERS_CHECK, 120106 },
    { "mho", VERS_CHECK, 8487 },
    { "micro", VERS_ALL, 181 },
    { "mid", VERS_CHECK, 8739 },
    { "midast", VERS_CHECK, 42 },
    { "midcir", VERS_CHECK, 10992 },
    { "middot", VERS_ALL, 183 },
    { "minus", VERS_FROM40, 8722 },
    { "minusb", VERS_CHECK, 8863 },
    { "minusd", VERS_CHECK, 8760 },
    { "minusdu", VERS_CHECK, 10794 },
    { "mlcp", VERS_CHECK, 10971 },
    { "mldr", VERS_CHECK, 8230 },
    { "mnplus", VERS_CHECK, 8723 },
    { "models", VERS_CHECK, 8871 },
    { "mopf", VERS_CHECK, 120158 },
    { "mp", VERS_CHECK, 8723 },
    { "mscr", VERS_CHECK, 120002 },
    { "mstpos", VERS_CHECK, 8766 },
    { "mu", VERS_FROM40, 956 },
    { "multimap", VERS_CHECK, 8888 },
    { "mumap", VERS_CHECK, 8888 },
    { "nLeftarrow", VERS_CHECK, 8653 },
    { "nLeftrightarrow", VERS_CHECK, 8654 },
    { "nRightarrow", VERS_CHECK, 8655 },
    { "nVDash", VERS_CHECK, 8879 },
    { "nVdash", VERS_CHECK, 8878 },
    { "nabla", VERS_FROM40, 8711 },
    { "nacute", VERS_CHECK, 324 },
    { "nap", VERS_CHECK, 8777 },
    { "napos", VERS_CHECK, 329 },
    { "napprox", VERS_CHECK, 8777 },
    { "natur", VERS_CHECK, 9838 },
    { "natural", VERS_CHECK, 9838 },
    { "naturals", VERS_CHECK, 8469 },
    { "nbsp", VERS_ALL, 160 },
    { "ncap", VERS_CHECK, 10819 },
    { "ncaron", VERS_CHECK, 328 },
    { "ncedil", VERS_CHECK, 326 },
    { "ncong", VERS_CHECK, 8775 },
    { "ncup", VERS_CHECK, 10818 },
    { "ncy", VERS_CHECK, 1085 },
    { "ndash", VERS_FROM40, 8211 },
    { "ne", VERS_FROM40, 8800 },
    { "neArr", VERS_CHECK, 8663 },
    { "nearhk", VERS_CHECK, 10532 },
    { "nearr", VERS_CHECK, 8599 },
    { "nearrow", VERS_CHECK, 8599 },
    { "nequiv", VERS_CHECK, 8802 },
    { "nesear", VERS_CHECK, 10536 },
    { "nexist", VERS_CHECK, 8708 },
    { "nexists", VERS_CHECK, 8708 },
    { "nfr", VERS_CHECK, 120107 },
    { "nge", VERS_CHECK, 8817 },
    { "ngeq", VERS_CHECK, 8817 },
    { "ngsim", VERS_CHECK, 8821 },
    { "ngt", VERS_CHECK, 8815 },
    { "ngtr", VERS_CHECK, 8815 },
    { "nhArr", VERS_CHECK, 8654 },
    { "nharr", VERS_CHECK, 8622 },
    { "nhpar", VERS_CHECK, 10994 },
    { "ni", VERS_FROM40, 8715 },
    { "nis", VERS_CHECK, 8956 },
    { "nisd", VERS_CHECK, 8954 },
    { "niv", VERS_CHECK, 8715 },
    { "njcy", VERS_CHECK, 1114 },
    { "nlArr", VERS_CHECK, 8653 },
    { "nlarr", VERS_CHECK, 8602 },
    { "nldr", VERS_CHECK, 8229 },
    { "nle", VERS_CHECK, 8816 },
    { "nleftarrow", VERS_CHECK, 8602 },
    { "nleftrightarrow", VERS_CHECK, 8622 },
    { "nleq", VERS_CHECK, 8816 },
    { "nless", VERS_CHECK, 8814 },
    { "nlsim", VERS_CHECK, 8820 },
    { "nlt", VERS_CHECK, 8814 },
    { "nltri", VERS_CHECK, 8938 },
    { "nltrie", VERS_CHECK, 8940 },
    { "nmid", VERS_CHECK, 8740 },
    { "nopf", VERS_CHECK, 120159 },
    { "not", VERS_ALL, 172 },
    { "notin", VERS_FROM40, 8713 },
    { "notinva", VERS_CHECK, 8713 },
    { "notinvb", VERS_CHECK, 8951 },
    { "notinvc", VERS_CHECK, 8950 },
    { "notni", VERS_CHECK, 8716 },
    { "notniva", VERS_CHECK, 8716 },
    { "notnivb", VERS_CHECK, 8958 },
    { "notnivc", VERS_CHECK, 8957 },
    { "npar", VERS_CHECK, 8742 },
    { "nparallel", VERS_CHECK, 8742 },
    { "npolint", VERS_CHECK, 10772 },
    { "npr", VERS_CHECK, 8832 },
    { "nprcue", VERS_CHECK, 8928 },
    { "nprec", VERS_CHECK, 8832 },
    { "nrArr", VERS_CHECK, 8655 },
    { "nrarr", VERS_CHECK, 8603 },
    { "nrightarrow", VERS_CHECK, 8603 },
    { "nrtri", VERS_CHECK, 8939 },
    { "nrtrie", VERS_CHECK, 8941 },
    { "nsc", VERS_CHECK, 8833 },
    { "nsccue", VERS_CHECK, 8929 },
    { "nscr", VERS_CHECK, 120003 },
    { "nshortmid", VERS_CHECK, 8740 },
    { "nshortparallel", VERS_CHECK, 8742 },
    { "nsim", VERS_CHECK, 8769 },
    { "nsime", VERS_CHECK, 8772 },
    { "nsimeq", VERS_CHECK, 8772 },
    { "nsmid", VERS_CHECK, 8740 },
    { "nspar", VERS_CHECK, 8742 },
    { "nsqsube", VERS_CHECK, 8930 },
    { "nsqsupe", VERS_CHECK, 8931 },
    { "nsub", VERS_FROM40, 8836 },
    { "nsube", VERS_CHECK, 8840 },
    { "nsubseteq", VERS_CHECK, 8840 },
    { "nsucc", VERS_CHECK, 8833 },
    { "nsup", VERS_CHECK, 8837 },
    { "nsupe", VERS_CHECK, 8841 },
    { "nsupseteq", VERS_CHECK, 8841 },
    { "ntgl", VERS_CHECK, 8825 },
    { "ntilde", VERS_ALL, 241 },
    { "ntlg", VERS_CHECK, 8824 },
    { "ntriangleleft", VERS_CHECK, 8938 },
    { "ntrianglelefteq", VERS_CHECK, 8940 },
    { "ntriangleright", VERS_CHECK, 8939 },
    { "ntrianglerighteq", VERS_CHECK, 8941 },
    { "nu", VERS_FROM40, 957 },
    { "num", VERS_CHECK, 35 },
    { "numero", VERS_CHECK, 8470 },
    { "numsp", VERS_CHECK, 8199 },
    { "nvDash", VERS_CHECK, 8877 },
    { "nvHarr", VERS_CHECK, 10500 },
    { "nvdash", VERS_CHECK, 8876 },
    { "nvinfin", VERS_CHECK, 10718 },
    { "nvlArr", VERS_CHECK, 10498 },
    { "nvrArr", VERS_CHECK, 10499 },
    { "nwArr", VERS_CHECK, 8662 },
    { "nwarhk", VERS_CHECK, 10531 },
    { "nwarr", VERS_CHECK, 8598 },
    { "nwarrow", VERS_CHECK, 8598 },
    { "nwnear", VERS_CHECK, 10535 },
    { "oS", VERS_CHECK, 9416 },
    { "oacute", VERS_ALL, 243 },
    { "oast", VERS_CHECK, 8859 },
    { "ocir", VERS_CHECK, 8858 },
    { "ocirc", VERS_ALL, 244 },
    { "ocy", VERS_CHECK, 1086 },
    { "odash", VERS_CHECK, 8861 },
    { "odblac", VERS_CHECK, 337 },
    { "odiv", VERS_CHECK, 10808 },
    { "odot", VERS_CHECK, 8857 },
    { "odsold", VERS_CHECK, 10684 },
    { "oelig", VERS_FROM40, 339 },
    { "ofcir", VERS_CHECK, 10687 },
    { "ofr", VERS_CHECK, 120108 },
    { "ogon", VERS_CHECK, 731 },
    { "ograve", VERS_ALL, 242 },
    { "ogt", VERS_CHECK, 10689 },
    { "ohbar", VERS_CHECK, 10677 },
    { "ohm", VERS_CHECK, 937 },
    { "oint", VERS_CHECK, 8750 },
    { "olarr", VERS_CHECK, 8634 },
    { "olcir", VERS_CHECK, 10686 },
    { "olcross", VERS_CHECK, 10683 },
    { "oline", VERS_FROM40, 8254 },
    { "olt", VERS_CHECK, 10688 },
    { "omacr", VERS_CHECK, 333 },
    { "omega", VERS_FROM40, 969 },
    { "omicron", VERS_FROM40, 959 },
    { "omid", VERS_CHECK, 10678 },
    { "ominus", VERS_CHECK, 8854 },
    { "oopf", VERS_CHECK, 120160 },
    { "opar", VERS_CHECK, 10679 },
    { "operp", VERS_CHECK, 10681 },
    { "oplus", VERS_FROM40, 8853 },
    { "or", VERS_FROM40, 8744 },
    { "orarr", VERS_CHECK, 8635 },
    { "ord", VERS_CHECK, 10845 },
    { "order", VERS_CHECK, 8500 },
    { "orderof", VERS_CHECK, 8500 },
    { "ordf", VERS_ALL, 170 },
    { "ordm", VERS_ALL, 186 },
    { "origof", VERS_CHECK, 8886 },
    { "oror", VERS_CHECK, 10838 },
    { "orslope", VERS_CHECK, 10839 },
    { "orv", VERS_CHECK, 10843 },
    { "oscr", VERS_CHECK, 8500 },
    { "oslash", VERS_ALL, 248 },
    { "osol", VERS_CHECK, 8856 },
    { "otilde", VERS_ALL, 245 },
    { "otimes", VERS_FROM40, 8855 },
    { "otimesas", VERS_CHECK, 10806 },
    { "ouml", VERS_ALL, 246 },
    { "ovbar", VERS_CHECK, 9021 },
    { "par", VERS_CHECK, 8741 },
    { "para", VERS_ALL, 182 },
    { "parallel", VERS_CHECK, 8741 },
    { "parsim", VERS_CHECK, 10995 },
    { "parsl", VERS_CHECK, 11005 },
    { "part", VERS_FROM40, 8706 },
    { "pcy", VERS_CHECK, 1087 },
    { "percnt", VERS_CHECK, 37 },
    { "period", VERS_CHECK, 46 },
    { "permil", VERS_FROM40, 8240 },
    { "perp", VERS_FROM40, 8869 },
    { "pertenk", VERS_CHECK, 8241 },
    { "pfr", VERS_CHECK, 120109 },
    { "phi", VERS_FROM40, 966 },
    { "phiv", VERS_CHECK, 981 },
    { "phmmat", VERS_CHECK, 8499 },
    { "phone", VERS_CHECK, 9742 },
    { "pi", VERS_FROM40, 960 },
    { "pitchfork", VERS_CHECK, 8916 },
    { "piv", VERS_FROM40, 982 },
    { "planck", VERS_CHECK, 8463 },
    { "planckh", VERS_CHECK, 8462 },
    { "plankv", VERS_CHECK, 8463 },
    { "plus", VERS_CHECK, 43 },
    { "plusacir", VERS_CHECK, 10787 },
    { "plusb", VERS_CHECK, 8862 },
    { "pluscir", VERS_CHECK, 10786 },
    { "plusdo", VERS_CHECK, 8724 },
    { "plusdu", VERS_CHECK, 10789 },
    { "pluse", VERS_CHECK, 10866 },
    { "plusmn", VERS_ALL, 177 },
    { "plussim", VERS_CHECK, 10790 },
    { "plustwo", VERS_CHECK, 10791 },
    { "pm", VERS_CHECK, 177 },
    { "pointint", VERS_CHECK, 10773 },
    { "popf", VERS_CHECK, 120161 },
    { "pound", VERS_ALL, 163 },
    { "pr", VERS_CHECK, 8826 },
    { "prE", VERS_CHECK, 10931 },
    { "prap", VERS_CHECK, 10935 },
    { "prcue", VERS_CHECK, 8828 },
    { "pre", VERS_CHECK, 10927 },
    { "prec", VERS_CHECK, 8826 },
    { "precapprox", VERS_CHECK, 10935 },
    { "preccurlyeq", VERS_CHECK, 8828 },
    { "preceq", VERS_CHECK, 10927 },
    { "precnapprox", VERS_CHECK, 10937 },
    { "precneqq", VERS_CHECK, 10933 },
    { "precnsim", VERS_CHECK, 8936 },
    { "precsim", VERS_CHECK, 8830 },
    { "prime", VERS_FROM40, 8242 },
    { "primes", VERS_CHECK, 8473 },
    { "prnE", VERS_CHECK, 10933 },
    { "prnap", VERS_CHECK, 10937 },
    { "prnsim", VERS_CHECK, 8936 },
    { "prod", VERS_FROM40, 8719 },
    { "profalar", VERS_CHECK, 9006 },
    { "profline", VERS_CHECK, 8978 },
    { "profsurf", VERS_CHECK, 8979 },
    { "prop", VERS_FROM40, 8733 },
    { "propto", VERS_CHECK, 8733 },
    { "prsim", VERS_CHECK, 8830 },
    { "prurel", VERS_CHECK, 8880 },
    { "pscr", VERS_CHECK, 120005 },
    { "psi", VERS_FROM40, 968 },
    { "puncsp", VERS_CHECK, 8200 },
    { "qfr", VERS_CHECK, 120110 },
    { "qint", VERS_CHECK, 10764 },
    { "qopf", VERS_CHECK, 120162 },
    { "qprime", VERS_CHECK, 8279 },
    { "qscr", VERS_CHECK, 120006 },
    { "quaternions", VERS_CHECK, 8461 },
    { "quatint", VERS_CHECK, 10774 },
    { "quest", VERS_CHECK, 63 },
    { "questeq", VERS_CHECK, 8799 },
    { "quot", VERS_ALL | VERS_XML, 34 },
    { "rAarr", VERS_CHECK, 8667 },
    { "rArr", VERS_FROM40, 8658 },
    { "rAtail", VERS_CHECK, 10524 },
    { "rBarr", VERS_CHECK, 10511 },
    { "rHar", VERS_CHECK, 10596 },
    { "racute", VERS_CHECK, 341 },
    { "radic", VERS_FROM40, 8730 },
    { "raemptyv", VERS_CHECK, 10675 },
    { "rang", VERS_FROM40, 10217 },
    { "rangd", VERS_CHECK, 10642 },
    { "range", VERS_CHECK, 10661 },
    { "rangle", VERS_CHECK, 10217 },
    { "raquo", VERS_ALL, 187 },
    { "rarr", VERS_FROM40, 8594 },
    { "rarrap", VERS_CHECK, 10613 },
    { "rarrb", VERS_CHECK, 8677 },
    { "rarrbfs", VERS_CHECK, 10528 },
    { "rarrc", VERS_CHECK, 10547 },
    { "rarrfs", VERS_CHECK, 10526 },
    { "rarrhk", VERS_CHECK, 8618 },
    { "rarrlp", VERS_CHECK, 8620 },
    { "rarrpl", VERS_CHECK, 10565 },
    { "rarrsim", VERS_CHECK, 10612 },
    { "rarrtl", VERS_CHECK, 8611 },
    { "rarrw", VERS_CHECK, 8605 },
    { "ratail", VERS_CHECK, 10522 },
    { "ratio", VERS_CHECK, 8758 },
    { "rationals", VERS_CHECK, 8474 },
    { "rbarr", VERS_CHECK, 10509 },
    { "rbbrk", VERS_CHECK, 10099 },
    { "rbrace", VERS_CHECK, 125 },
    { "rbrack", VERS_CHECK, 93 },
    { "rbrke", VERS_CHECK, 10636 },
    { "rbrksld", VERS_CHECK, 10638 },
    { "rbrkslu", VERS_CHECK, 10640 },
    { "rcaron", VERS_CHECK, 345 },
    { "rcedil", VERS_CHECK, 343 },
    { "rceil", VERS_FROM40, 8969 },
    { "rcub", VERS_CHECK, 125 },
    { "rcy", VERS_CHECK, 1088 },
    { "rdca", VERS_CHECK, 10551 },
    { "rdldhar", VERS_CHECK, 10601 },
    { "rdquo", VERS_FROM40, 8221 },
    { "rdquor", VERS_CHECK, 8221 },
    { "rdsh", VERS_CHECK, 8627 },
    { "real", VERS_FROM40, 8476 },
    { "realine", VERS_CHECK, 8475 },
    { "realpart", VERS_CHECK, 8476 },
    { "reals", VERS_CHECK, 8477 },
    { "rect", VERS_CHECK, 9645 },
    { "reg", VERS_ALL, 174 },
    { "rfisht", VERS_CHECK, 10621 },
    { "rfloor", VERS_FROM40, 8971 },
    { "rfr", VERS_CHECK, 120111 },
    { "rhard", VERS_CHECK, 8641 },
    { "rharu", VERS_CHECK, 8640 },
    { "rharul", VERS_CHECK, 10604 },
    { "rho", VERS_FROM40, 961 },
    { "rhov", VERS_CHECK, 1009 },
    { "rightarrow", VERS_CHECK, 8594 },
    { "rightarrowtail", VERS_CHECK, 8611 },
    { "rightharpoondown", VERS_CHECK, 8641 },
    { "rightharpoonup", VERS_CHECK, 8640 },
    { "rightleftarrows", VERS_CHECK, 8644 },
    { "rightleftharpoons", VERS_CHECK, 8652 },
    { "rightrightarrows", VERS_CHECK, 8649 },
    { "rightsquigarrow", VERS_CHECK, 8605 },
    { "rightthreetimes", VERS_CHECK, 8908 },
    { "ring", VERS_CHECK, 730 },
    { "risingdotseq", VERS_CHECK, 8787 },
    { "rlarr", VERS_CHECK, 8644 },
    { "rlhar", VERS_CHECK, 8652 },
    { "rlm", VERS_FROM40, 8207 },
    { "rmoust", VERS_CHECK, 9137 },
    { "rmoustache", VERS_CHECK, 9137 },
    { "rnmid", VERS_CHECK, 10990 },
    { "roang", VERS_CHECK, 10221 },
    { "roarr", VERS_CHECK, 8702 },
    { "robrk", VERS_CHECK, 10215 },
    { "ropar", VERS_CHECK, 10630 },
    { "ropf", VERS_CHECK, 120163 },
    { "roplus", VERS_CHECK, 10798 },
    { "rotimes", VERS_CHECK, 10805 },
    { "rpar", VERS_CHECK, 41 },
    { "rpargt", VERS_CHECK, 10644 },
    { "rppolint", VERS_CHECK, 10770 },
    { "rrarr", VERS_CHECK, 8649 },
    { "rsaquo", VERS_FROM40, 8250 },
    { "rscr", VERS_CHECK, 120007 },
    { "rsh", VERS_CHECK, 8625 },
    { "rsqb", VERS_CHECK, 93 },
    { "rsquo", VERS_FROM40, 8217 },
    { "rsquor", VERS_CHECK, 8217 },
    { "rthree", VERS_CHECK, 8908 },
    { "rtimes", VERS_CHECK, 8906 },
    { "rtri", VERS_CHECK, 9657 },
    { "rtrie", VERS_CHECK, 8885 },
    { "rtrif", VERS_CHECK, 9656 },
    { "rtriltri", VERS_CHECK, 10702 },
    { "ruluhar", VERS_CHECK, 10600 },
    { "rx", VERS_CHECK, 8478 },
    { "sacute", VERS_CHECK, 347 },
    { "sbquo", VERS_FROM40, 8218 },
    { "sc", VERS_CHECK, 8827 },
    { "scE", VERS_CHECK, 10932 },
    { "scap", VERS_CHECK, 10936 },
    { "scaron", VERS_FROM40, 353 },
    { "sccue", VERS_CHECK, 8829 },
    { "sce", VERS_CHECK, 10928 },
    { "scedil", VERS_CHECK, 351 },
    { "scirc", VERS_CHECK, 349 },
    { "scnE", VERS_CHECK, 10934 },
    { "scnap", VERS_CHECK, 10938 },
    { "scnsim", VERS_CHECK, 8937 },
    { "scpolint", VERS_CHECK, 10771 },
    { "scsim", VERS_CHECK, 8831 },
    { "scy", VERS_CHECK, 1089 },
    { "sdot", VERS_FROM40, 8901 },
    { "sdotb", VERS_CHECK, 8865 },
    { "sdote", VERS_CHECK, 10854 },
    { "seArr", VERS_CHECK, 8664 },
    { "searhk", VERS_CHECK, 10533 },
    { "searr", VERS_CHECK, 8600 },
    { "searrow", VERS_CHECK, 8600 },
    { "sect", VERS_ALL, 167 },
    { "semi", VERS_CHECK, 59 },
    { "seswar", VERS_CHECK, 10537 },
    { "setminus", VERS_CHECK, 8726 },
    { "setmn", VERS_CHECK, 8726 },
    { "sext", VERS_CHECK, 10038 },
    { "sfr", VERS_CHECK, 120112 },
    { "sfrown", VERS_CHECK, 8994 },
    { "sharp", VERS_CHECK, 9839 },
    { "shchcy", VERS_CHECK, 1097 },
    { "shcy", VERS_CHECK, 1096 },
    { "shortmid", VERS_CHECK, 8739 },
    { "shortparallel", VERS_CHECK, 8741 },
    { "shy", VERS_ALL, 173 },
    { "sigma", VERS_FROM40, 963 },
    { "sigmaf", VERS_FROM40, 962 },
    { "sigmav", VERS_CHECK, 962 },
    { "sim", VERS_FROM40, 8764 },
    { "simdot", VERS_CHECK, 10858 },
    { "sime", VERS_CHECK, 8771 },
    { "simeq", VERS_CHECK, 8771 },
    { "simg", VERS_CHECK, 10910 },
    { "simgE", VERS_CHECK, 10912 },
    { "siml", VERS_CHECK, 10909 },
    { "simlE", VERS_CHECK, 10911 },
    { "simne", VERS_CHECK, 8774 },
    { "simplus", VERS_CHECK, 10788 },
    { "simrarr", VERS_CHECK, 10610 },
    { "slarr", VERS_CHECK, 8592 },
    { "smallsetminus", VERS_CHECK, 8726 },
    { "smashp", VERS_CHECK, 10803 },
    { "smeparsl", VERS_CHECK, 10724 },
    { "smid", VERS_CHECK, 8739 },
    { "smile", VERS_CHECK, 8995 },
    { "smt", VERS_CHECK, 10922 },
    { "smte", VERS_CHECK, 10924 },
    { "softcy", VERS_CHECK, 1100 },
    { "sol", VERS_CHECK, 47 },
    { "solb", VERS_CHECK, 10692 },
    { "solbar", VERS_CHECK, 9023 },
    { "sopf", VERS_CHECK, 120164 },
    { "spades", VERS_FROM40, 9824 },
    { "spadesuit", VERS_CHECK, 9824 },
    { "spar", VERS_CHECK, 8741 },
    { "sqcap", VERS_CHECK, 8851 },
    { "sqcup", VERS_CHECK, 8852 },
    { "sqsub", VERS_CHECK, 8847 },
    { "sqsube", VERS_CHECK, 8849 },
    { "sqsubset", VERS_CHECK, 8847 },
    { "sqsubseteq", VERS_CHECK, 8849 },
    { "sqsup", VERS_CHECK, 8848 },
    { "sqsupe", VERS_CHECK, 8850 },
    { "sqsupset", VERS_CHECK, 8848 },
    { "sqsupseteq", VERS_CHECK, 8850 },
    { "squ", VERS_CHECK, 9633 },
    { "square", VERS_CHECK, 9633 },
    { "squarf", VERS_CHECK, 9642 },
    { "squf", VERS_CHECK, 9642 },
    { "srarr", VERS_CHECK, 8594 },
    { "sscr", VERS_CHECK, 120008 },
    { "ssetmn", VERS_CHECK, 8726 },
    { "ssmile", VERS_CHECK, 8995 },
    { "sstarf", VERS_CHECK, 8902 },
    { "star", VERS_CHECK, 9734 },
    { "starf", VERS_CHECK, 9733 },
    { "straightepsilon", VERS_CHECK, 1013 },
    { "straightphi", VERS_CHECK, 981 },
    { "strns", VERS_CHECK, 175 },
    { "sub", VERS_FROM40, 8834 },
    { "subE", VERS_CHECK, 10949 },
    { "subdot", VERS_CHECK, 10941 },
    { "sube", VERS_FROM40, 8838 },
    { "subedot", VERS_CHECK, 10947 },
    { "submult", VERS_CHECK, 10945 },
    { "subnE", VERS_CHECK, 10955 },
    { "subne", VERS_CHECK, 8842 },
    { "subplus", VERS_CHECK, 10943 },
    { "subrarr", VERS_CHECK, 10617 },
    { "subset", VERS_CHECK, 8834 },
    { "subseteq", VERS_CHECK, 8838 },
    { "subseteqq", VERS_CHECK, 10949 },
    { "subsetneq", VERS_CHECK, 8842 },
    { "subsetneqq", VERS_CHECK, 10955 },
    { "subsim", VERS_CHECK, 10951 },
    { "subsub", VERS_CHECK, 10965 },
    { "subsup", VERS_CHECK, 10963 },
    { "succ", VERS_CHECK, 8827 },
    { "succapprox", VERS_CHECK, 10936 },
    { "succcurlyeq", VERS_CHECK, 8829 },
    { "succeq", VERS_CHECK, 10928 },
    { "succnapprox", VERS_CHECK, 10938 },
    { "succneqq", VERS_CHECK, 10934 },
    { "succnsim", VERS_CHECK, 8937 },
    { "succsim", VERS_CHECK, 8831 },
    { "sum", VERS_FROM40, 8721 },
    { "sung", VERS_CHECK, 9834 },
    { "sup", VERS_FROM40, 8835 },
    { "sup1", VERS_ALL, 185 },
    { "sup2", VERS_ALL, 178 },
    { "sup3", VERS_ALL, 179 },
    { "supE", VERS_CHECK, 10950 },
    { "supdot", VERS_CHECK, 10942 },
    { "supdsub", VERS_CHECK, 10968 },
    { "supe", VERS_FROM40, 8839 },
    { "supedot", VERS_CHECK, 10948 },
    { "suphsol", VERS_CHECK, 10185 },
    { "suphsub", VERS_CHECK, 10967 },
    { "suplarr", VERS_CHECK, 10619 },
    { "supmult", VERS_CHECK, 10946 },
    { "supnE", VERS_CHECK, 10956 },
    { "supne", VERS_CHECK, 8843 },
    { "supplus", VERS_CHECK, 10944 },
    { "supset", VERS_CHECK, 8835 },
    { "supseteq", VERS_CHECK, 8839 },
    { "supseteqq", VERS_CHECK, 10950 },
    { "supsetneq", VERS_CHECK, 8843 },
    { "supsetneqq", VERS_CHECK, 10956 },
    { "supsim", VERS_CHECK, 10952 },
    { "supsub", VERS_CHECK, 10964 },
    { "supsup", VERS_CHECK, 10966 },
    { "swArr", VERS_CHECK, 8665 },
    { "swarhk", VERS_CHECK, 10534 },
    { "swarr", VERS_CHECK, 8601 },
    { "swarrow", VERS_CHECK, 8601 },
    { "swnwar", VERS_CHECK, 10538 },
    { "szlig", VERS_ALL, 223 },
    { "target", VERS_CHECK, 8982 },
    { "tau", VERS_FROM40, 964 },
    { "tbrk", VERS_CHECK, 9140 },
    { "tcaron", VERS_CHECK, 357 },
    { "tcedil", VERS_CHECK, 355 },
    { "tcy", VERS_CHECK, 1090 },
    { "tdot", VERS_CHECK, 8411 },
    { "telrec", VERS_CHECK, 8981 },
    { "tfr", VERS_CHECK, 120113 },
    { "there4", VERS_FROM40, 8756 },
    { "therefore", VERS_CHECK, 8756 },
    { "theta", VERS_FROM40, 952 },
    { "thetasym", VERS_FROM40, 977 },
    { "thetav", VERS_CHECK, 977 },
    { "thickapprox", VERS_CHECK, 8776 },
    { "thicksim", VERS_CHECK, 8764 },
    { "thinsp", VERS_FROM40, 8201 },
    { "thkap", VERS_CHECK, 8776 },
    { "thksim", VERS_CHECK, 8764 },
    { "thorn", VERS_ALL, 254 },
    { "tilde", VERS_FROM40, 732 },
    { "times", VERS_ALL, 215 },
    { "timesb", VERS_CHECK, 8864 },
    { "timesbar", VERS_CHECK, 10801 },
    { "timesd", VERS_CHECK, 10800 },
    { "tint", VERS_CHECK, 8749 },
    { "toea", VERS_CHECK, 10536 },
    { "top", VERS_CHECK, 8868 },
    { "topbot", VERS_CHECK, 9014 },
    { "topcir", VERS_CHECK, 10993 },
    { "topf", VERS_CHECK, 120165 },
    { "topfork", VERS_CHECK, 10970 },
    { "tosa", VERS_CHECK, 10537 },
    { "tprime", VERS_CHECK, 8244 },
    { "trade", VERS_FROM40, 8482 },
    { "triangle", VERS_CHECK, 9653 },
    { "triangledown", VERS_CHECK, 9663 },
    { "triangleleft", VERS_CHECK, 9667 },
    { "trianglelefteq", VERS_CHECK, 8884 },
    { "triangleq", VERS_CHECK, 8796 },
    { "triangleright", VERS_CHECK, 9657 },
    { "trianglerighteq", VERS_CHECK, 8885 },
    { "tridot", VERS_CHECK, 9708 },
    { "trie", VERS_CHECK, 8796 },
    { "triminus", VERS_CHECK, 10810 },
    { "triplus", VERS_CHECK, 10809 },
    { "trisb", VERS_CHECK, 10701 },
    { "tritime", VERS_CHECK, 10811 },
    { "trpezium", VERS_CHECK, 9186 },
    { "tscr", VERS_CHECK, 120009 },
    { "tscy", VERS_CHECK, 1094 },
    { "tshcy", VERS_CHECK, 1115 },
    { "tstrok", VERS_CHECK, 359 },
    { "twixt", VERS_CHECK, 8812 },
    { "twoheadleftarrow", VERS_CHECK, 8606 },
    { "twoheadrightarrow", VERS_CHECK, 8608 },
    { "uArr", VERS_FROM40, 8657 },
    { "uHar", VERS_CHECK, 10595 },
    { "uacute", VERS_ALL, 250 },
    { "uarr", VERS_FROM40, 8593 },
    { "ubrcy", VERS_CHECK, 1118 },
    { "ubreve", VERS_CHECK, 365 },
    { "ucirc", VERS_ALL, 251 },
    { "ucy", VERS_CHECK, 1091 },
    { "udarr", VERS_CHECK, 8645 },
    { "udblac", VERS_CHECK, 369 },
    { "udhar", VERS_CHECK, 10606 },
    { "ufisht", VERS_CHECK, 10622 },
    { "ufr", VERS_CHECK, 120114 },
    { "ugrave", VERS_ALL, 249 },
    { "uharl", VERS_CHECK, 8639 },
    { "uharr", VERS_CHECK, 8638 },
    { "uhblk", VERS_CHECK, 9600 },
    { "ulcorn", VERS_CHECK, 8988 },
    { "ulcorner", VERS_CHECK, 8988 },
    { "ulcrop", VERS_CHECK, 8975 },
    { "ultri", VERS_CHECK, 9720 },
    { "umacr", VERS_CHECK, 363 },
    { "uml", VERS_ALL, 168 },
    { "uogon", VERS_CHECK, 371 },
    { "uopf", VERS_CHECK, 120166 },
    { "uparrow", VERS_CHECK, 8593 },
    { "updownarrow", VERS_CHECK, 8597 },
    { "upharpoonleft", VERS_CHECK, 8639 },
    { "upharpoonright", VERS_CHECK, 8638 },
    { "uplus", VERS_CHECK, 8846 },
    { "upsi", VERS_CHECK, 965 },
    { "upsih", VERS_FROM40, 978 },
    { "upsilon", VERS_FROM40, 965 },
    { "upuparrows", VERS_CHECK, 8648 },
    { "urcorn", VERS_CHECK, 8989 },
    { "urcorner", VERS_CHECK, 8989 },
    { "urcrop", VERS_CHECK, 8974 },
    { "uring", VERS_CHECK, 367 },
    { "urtri", VERS_CHECK, 9721 },
    { "uscr", VERS_CHECK, 120010 },
    { "utdot", VERS_CHECK, 8944 },
    { "utilde", VERS_CHECK, 361 },
    { "utri", VERS_CHECK, 9653 },
    { "utrif", VERS_CHECK, 9652 },
    { "uuarr", VERS_CHECK, 8648 },
    { "uuml", VERS_ALL, 252 },
    { "uwangle", VERS_CHECK, 10663 },
    { "vArr", VERS_CHECK, 8661 },
    { "vBar", VERS_CHECK, 10984 },
    { "vBarv", VERS_CHECK, 10985 },
    { "vDash", VERS_CHECK, 8872 },
    { "vangrt", VERS_CHECK, 10652 },
    { "varepsilon", VERS_CHECK, 1013 },
    { "varkappa", VERS_CHECK, 1008 },
    { "varnothing", VERS_CHECK, 8709 },
    { "varphi", VERS_CHECK, 981 },
    { "varpi", VERS_CHECK, 982 },
    { "varpropto", VERS_CHECK, 8733 },
    { "varr", VERS_CHECK, 8597 },
    { "varrho", VERS_CHECK, 1009 },
    { "varsigma", VERS_CHECK, 962 },
    { "vartheta", VERS_CHECK, 977 },
    { "vartriangleleft", VERS_CHECK, 8882 },
    { "vartriangleright", VERS_CHECK, 8883 },
    { "vcy", VERS_CHECK, 1074 },
    { "vdash", VERS_CHECK, 8866 },
    { "vee", VERS_CHECK, 8744 },
    { "veebar", VERS_CHECK, 8891 },
    { "veeeq", VERS_CHECK, 8794 },
    { "vellip", VERS_CHECK, 8942 },
    { "verbar", VERS_CHECK, 124 },
    { "vert", VERS_CHECK, 124 },
    { "vfr", VERS_CHECK, 120115 },
    { "vltri", VERS_CHECK, 8882 },
    { "vopf", VERS_CHECK, 120167 },
    { "vprop", VERS_CHECK, 8733 },
    { "vrtri", VERS_CHECK, 8883 },
    { "vscr", VERS_CHECK, 120011 },
    { "vzigzag", VERS_CHECK, 10650 },
    { "wcirc", VERS_CHECK, 373 },
    { "wedbar", VERS_CHECK, 10847 },
    { "wedge", VERS_CHECK, 8743 },
    { "wedgeq", VERS_CHECK, 8793 },
    { "weierp", VERS_FROM40, 8472 },
    { "wfr", VERS_CHECK, 120116 },
    { "wopf", VERS_CHECK, 120168 },
    { "wp", VERS_CHECK, 8472 },
    { "wr", VERS_CHECK, 8768 },
    { "wreath", VERS_CHECK, 8768 },
    { "wscr", VERS_CHECK, 120012 },
    { "xcap", VERS_CHECK, 8898 },
    { "xcirc", VERS_CHECK, 9711 },
    { "xcup", VERS_CHECK, 8899 },
    { "xdtri", VERS_CHECK, 9661 },
    { "xfr", VERS_CHECK, 120117 },
    { "xhArr", VERS_CHECK, 10234 },
    { "xharr", VERS_CHECK, 10231 },
    { "xi", VERS_FROM40, 958 },
    { "xlArr", VERS_CHECK, 10232 },
    { "xlarr", VERS_CHECK, 10229 },
    { "xmap", VERS_CHECK, 10236 },
    { "xnis", VERS_CHECK, 8955 },
    { "xodot", VERS_CHECK, 10752 },
    { "xopf", VERS_CHECK, 120169 },
    { "xoplus", VERS_CHECK, 10753 },
    { "xotime", VERS_CHECK, 10754 },
    { "xrArr", VERS_CHECK, 10233 },
    { "xrarr", VERS_CHECK, 10230 },
    { "xscr", VERS_CHECK, 120013 },
    { "xsqcup", VERS_CHECK, 10758 },
    { "xuplus", VERS_CHECK, 10756 },
    { "xutri", VERS_CHECK, 9651 },
    { "xvee", VERS_CHECK, 8897 },
    { "xwedge", VERS_CHECK, 8896 },
    { "yacute", VERS_ALL, 253 },
    { "yacy", VERS_CHECK, 1103 },
    { "ycirc", VERS_CHECK, 375 },
    { "ycy", VERS_CHECK, 1099 },
    { "yen", VERS_ALL, 165 },
    { "yfr", VERS_CHECK, 120118 },
    { "yicy", VERS_CHECK, 1111 },
    { "yopf", VERS_CHECK, 120170 },
    { "yscr", VERS_CHECK, 120014 },
    { "yucy", VERS_CHECK, 1102 },
    { "yuml", VERS_ALL, 255 },
    { "zacute", VERS_CHECK, 378 },
    { "zcaron", VERS_CHECK, 382 },
    { "zcy", VERS_CHECK, 1079 },
    { "zdot", VERS_CHECK, 380 },
    { "zeetrf", VERS_CHECK, 8488 },
    { "zeta", VERS_FROM40, 950 },
    { "zfr", VERS_CHECK, 120119 },
    { "zhcy", VERS_CHECK, 1078 },
    { "zigrarr", VERS_CHECK, 8669 },
    { "zopf", VERS_CHECK, 120171 },
    { "zscr", VERS_CHECK, 120015 },
    { "zwj", VERS_FROM40, 8205 },
    { "zwnj", VERS_FROM40, 8204 },
    { NULL, VERS_UNKNOWN, 0 },
};

/* 
** Pure static implementation.  Trades off lookup speed
** for faster setup time (well, none actually).
** Optimization of comparing 1st character buys enough
** speed that hash doesn't improve things without > 500
** items in list.
** Issue #643 - Keep list fully alphabetic for more 
** optimization, now that the list has grown to 2031
** entries. Perhaps hashing setup should be now considered.
**
*/
static const entity* entitiesLookup( ctmbstr s )
{
    tmbchar ch = (tmbchar)( s ? *s : 0 );
    const entity *np = entities;
    if (ch == 0)
        return NULL;
    while (np->name)
    {
        if (ch == *np->name)
            break;  /* stop when first letter matches */
        np++;
    }
    while (np->name)
    {
        if (ch != *np->name)
            break;  /* stop when first letter does not match */
        if (TY_(tmbstrcmp)(s, np->name) == 0)
            return np;
        np++;
    }
    return NULL;
}

Bool TY_(EntityInfo)( ctmbstr name, Bool isXml, unsigned int* code, unsigned int* versions )
{
    const entity* np;
    int res;
    assert( name && name[0] == '&' );
    assert( code != NULL );
    assert( versions != NULL );

    /* numeric entitity: name = "&#" followed by number */
    if ( name[1] == '#' )
    {
        unsigned int c = 0;  /* zero on missing/bad number */

        /* 'x' prefix denotes hexadecimal number format */
        if ( name[2] == 'x' || (!isXml && name[2] == 'X') )
            res = sscanf( name+3, "%x", &c );
        else
            res = sscanf( name+2, "%u", &c );

        /*  Issue #373 - Null Char in XML result doc - sf905 2009 */
        if ( res == 1 )
        {
            *code = c;
            *versions = VERS_ALL;
            return yes;
        }
        else
        {
            *code = 0;
            *versions = ( isXml ? VERS_XML : VERS_PROPRIETARY );
            return no;
        }
    }

    /* Named entity: name ="&" followed by a name */
    if ( NULL != (np = entitiesLookup(name+1)) )
    {
        *code = np->code;
        *versions = np->versions;
        return yes;
    }

    *code = 0;
    *versions = ( isXml ? VERS_XML : VERS_PROPRIETARY );
    return no;
}

/*
**
** Issue #643 - Now that the list has been enlarged to 
** 2031 entries, including multiple case entries for some
** like &amp; & &AMP;, the value can be repeated several
** time, so this lookup will now only return the first.
**
*/
ctmbstr TY_(EntityName)( unsigned int ch, unsigned int versions )
{
    ctmbstr entnam = NULL;
    const entity *ep;

    for ( ep = entities; ep->name != NULL; ++ep )
    {
        if ( ep->code == ch )
        {
            if (ep->versions & versions)
            {
                entnam = ep->name;
                break; /* Issue #643 - Found code and version. Stop search? */
            }
        }
    }
    return entnam;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* fileio.c -- does standard I/O

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Default implementations of Tidy input sources
  and output sinks based on standard C FILE*.

*/

#include <stdio.h>

/* #include "forward.h" */
/* #include "fileio.h" */
/* #include "tidy.h" */
/* #include "sprtf.h" */

typedef struct _fp_input_source
{
    FILE*        fp;
    TidyBuffer   unget;
} FileSource;

static int TIDY_CALL filesrc_getByte( void* sourceData )
{
  FileSource* fin = (FileSource*) sourceData;
  int bv;
  if ( fin->unget.size > 0 )
    bv = tidyBufPopByte( &fin->unget );
  else
    bv = fgetc( fin->fp );
  return bv;
}

static Bool TIDY_CALL filesrc_eof( void* sourceData )
{
  FileSource* fin = (FileSource*) sourceData;
  Bool isEOF = ( fin->unget.size == 0 );
  if ( isEOF )
    isEOF = feof( fin->fp ) != 0;
  return isEOF;
}

static void TIDY_CALL filesrc_ungetByte( void* sourceData, byte bv )
{
  FileSource* fin = (FileSource*) sourceData;
  tidyBufPutByte( &fin->unget, bv );
}

#if SUPPORT_POSIX_MAPPED_FILES
#  define initFileSource_fileio_c initStdIOFileSource
#  define freeFileSource_fileio_c freeStdIOFileSource
#endif
int TY_(initFileSource_fileio_c)( TidyAllocator *allocator, TidyInputSource* inp, FILE* fp )
{
  FileSource* fin = NULL;

  fin = (FileSource*) TidyAlloc( allocator, sizeof(FileSource) );
  if ( !fin )
      return -1;
  TidyClearMemory( fin, sizeof(FileSource) );
  fin->unget.allocator = allocator;
  fin->fp = fp;

  inp->getByte    = filesrc_getByte;
  inp->eof        = filesrc_eof;
  inp->ungetByte  = filesrc_ungetByte;
  inp->sourceData = fin;

  return 0;
}

void TY_(freeFileSource_fileio_c)( TidyInputSource* inp, Bool closeIt )
{
    FileSource* fin = (FileSource*) inp->sourceData;
    if ( closeIt && fin && fin->fp )
      fclose( fin->fp );
    tidyBufFree( &fin->unget );
    TidyFree( fin->unget.allocator, fin );
}

void TIDY_CALL TY_(filesink_putByte)( void* sinkData, byte bv )
{
  FILE* fout = (FILE*) sinkData;
  fputc( bv, fout );
#if defined(ENABLE_DEBUG_LOG)
  if (fileno(fout) != 2)
  {
      if (bv != 0x0d)
      {
          /*\
           * avoid duplicate newline - SPRTF will translate an 0x0d to CRLF,
           *  and do the same with the following 0x0a
          \*/
          SPRTF("%c",bv);
      }
  }
#endif
}

void TY_(initFileSink)( TidyOutputSink* outp, FILE* fp )
{
  outp->putByte  = TY_(filesink_putByte);
  outp->sinkData = fp;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/*
  clean.c -- clean up misuse of presentation markup

  (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Filters from other formats such as Microsoft Word
  often make excessive use of presentation markup such
  as font tags, B, I, and the align attribute. By applying
  a set of production rules, it is straight forward to
  transform this to use CSS.

  Some rules replace some of the children of an element by
  style properties on the element, e.g.

  <p><b>...</b></p> -> <p style="font-weight: bold">...</p>

  Such rules are applied to the element's content and then
  to the element itself until none of the rules more apply.
  Having applied all the rules to an element, it will have
  a style attribute with one or more properties. 

  Other rules strip the element they apply to, replacing
  it by style properties on the contents, e.g.
  
  <dir><li><p>...</li></dir> -> <p style="margin-left 1em">...
      
  These rules are applied to an element before processing
  its content and replace the current element by the first
  element in the exposed content.

  After applying both sets of rules, you can replace the
  style attribute by a class value and style rule in the
  document head. To support this, an association of styles
  and class names is built.

  A naive approach is to rely on string matching to test
  when two property lists are the same. A better approach
  would be to first sort the properties before matching.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* #include "tidy-int.h" */
/* #include "gdoc.h" */
/* #include "lexer.h" */
/* #include "parser.h" */
/* #include "tags.h" */
/* #include "attrs.h" */
/* #include "message.h" */
/* #include "tmbstr.h" */
/* #include "utf8.h" */

/*
  Extricate "element", replace it by its content and delete it.
*/
static void DiscardContainer_gdoc_c( TidyDocImpl* doc, Node *element, Node **pnode)
{
    if (element->content)
    {
        Node *node, *parent = element->parent;

        element->last->next = element->next;

        if (element->next)
        {
            element->next->prev = element->last;
        }
        else
            parent->last = element->last;

        if (element->prev)
        {
            element->content->prev = element->prev;
            element->prev->next = element->content;
        }
        else
            parent->content = element->content;

        for (node = element->content; node; node = node->next)
            node->parent = parent;

        *pnode = element->content;

        element->next = element->content = NULL;
        TY_(FreeNode)(doc, element);
    }
    else
    {
        *pnode = TY_(DiscardElement)(doc, element);
    }
}

static void CleanNode_gdoc_c( TidyDocImpl* doc, Node *node )
{
    Node *child, *next;

    if (node->content)
    {
        for (child = node->content; child != NULL; child = next)
        {
            next = child->next;

            if (TY_(nodeIsElement)(child))
            {
                if (nodeIsSTYLE(child))
                    TY_(DiscardElement)(doc, child);
                if (nodeIsP(child) && !child->content)
                    TY_(DiscardElement)(doc, child);
                else if (nodeIsSPAN(child))
                    DiscardContainer_gdoc_c( doc, child, &next);
                else if (nodeIsA(child) && !child->content)
                 {
                    AttVal *id = TY_(GetAttrByName)( child, "name" );
                    /* Recent Google Docs is using "id" instead of "name" in
                    ** the exported html.
                    */
                    if (!id)
                        id = TY_(GetAttrByName)( child, "id" );

                    if (id)
                        TY_(RepairAttrValue)( doc, child->parent, "id", id->value );

                    TY_(DiscardElement)(doc, child);
                }
                else
                {
                    if (child->attributes)
                        TY_(DropAttrByName)( doc, child, "class" );

                    CleanNode_gdoc_c(doc, child);
                }
            }
        }
    }
}

/* insert meta element to force browser to recognize doc as UTF8 */
static void SetUTF8( TidyDocImpl* doc )
{
    Node *head = TY_(FindHEAD)( doc );

    if (head)
    {
        Node *node = TY_(InferredTag)(doc, TidyTag_META);
        TY_(AddAttribute)( doc, node, "http-equiv", "Content-Type" );
        TY_(AddAttribute)( doc, node, "content", "text/html; charset=UTF-8" );
        TY_(InsertNodeAtStart)( head, node );
    }
}

/* clean html exported by Google Docs

    - strip the script element, as the style sheet is a mess
    - strip class attributes
    - strip span elements, leaving their content in place
    - replace <a name=...></a> by id on parent element
    - strip empty <p> elements
*/
void TY_(CleanGoogleDocument)( TidyDocImpl* doc )
{
    /* placeholder.  CleanTree()/CleanNode_gdoc_c() will not
    ** zap root element 
    */
    CleanNode_gdoc_c( doc, &doc->root );
    SetUTF8( doc );
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* istack.c -- inline stack for compatibility with Mosaic

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.
  
*/

/* #include "tidy-int.h" */
/* #include "lexer.h" */
/* #include "attrs.h" */
/* #include "streamio.h" */
/* #include "tmbstr.h" */

/* duplicate attributes */
AttVal *TY_(DupAttrs)( TidyDocImpl* doc, AttVal *attrs)
{
    AttVal *newattrs;

    if (attrs == NULL)
        return attrs;

    newattrs = TY_(NewAttribute)(doc);
    *newattrs = *attrs;
    newattrs->next = TY_(DupAttrs)( doc, attrs->next );
    newattrs->attribute = TY_(tmbstrdup)(doc->allocator, attrs->attribute);
    newattrs->value = TY_(tmbstrdup)(doc->allocator, attrs->value);
    newattrs->dict = TY_(FindAttribute)(doc, newattrs);
    newattrs->asp = attrs->asp ? TY_(CloneNode)(doc, attrs->asp) : NULL;
    newattrs->php = attrs->php ? TY_(CloneNode)(doc, attrs->php) : NULL;
    return newattrs;
}

static Bool IsNodePushable( Node *node )
{
    if (node->tag == NULL)
        return no;

    if (!(node->tag->model & CM_INLINE))
        return no;

    if (node->tag->model & CM_OBJECT)
        return no;

    /*\ Issue #92: OLD problem of ins and del which are marked as both
     *  inline and block, thus should NOT ever be 'inserted'
    \*/
    if (nodeIsINS(node) || nodeIsDEL(node))
        return no;

    return yes;
}

/*
  push a copy of an inline node onto stack
  but don't push if implicit or OBJECT or APPLET
  (implicit tags are ones generated from the istack)

  One issue arises with pushing inlines when
  the tag is already pushed. For instance:

      <p><em>text
      <p><em>more text

  Shouldn't be mapped to

      <p><em>text</em></p>
      <p><em><em>more text</em></em>
*/
void TY_(PushInline)( TidyDocImpl* doc, Node *node )
{
    Lexer* lexer = doc->lexer;
    IStack *istack;

    if (node->implicit)
        return;

    if ( !IsNodePushable(node) )
        return;

    if ( !nodeIsFONT(node) && TY_(IsPushed)(doc, node) )
        return;

    /* make sure there is enough space for the stack */
    if (lexer->istacksize + 1 > lexer->istacklength)
    {
        if (lexer->istacklength == 0)
            lexer->istacklength = 6;   /* this is perhaps excessive */

        lexer->istacklength = lexer->istacklength * 2;
        lexer->istack = (IStack *)TidyDocRealloc(doc, lexer->istack,
                            sizeof(IStack)*(lexer->istacklength));
    }

    istack = &(lexer->istack[lexer->istacksize]);
    istack->tag = node->tag;

    istack->element = TY_(tmbstrdup)(doc->allocator, node->element);
    istack->attributes = TY_(DupAttrs)( doc, node->attributes );
    ++(lexer->istacksize);
}

static void PopIStack( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    IStack *istack;
    AttVal *av;

    --(lexer->istacksize);
    istack = &(lexer->istack[lexer->istacksize]);

    while (istack->attributes)
    {
        av = istack->attributes;
        istack->attributes = av->next;
        TY_(FreeAttribute)( doc, av );
    }
    TidyDocFree(doc, istack->element);
    istack->element = NULL; /* remove the freed element */
}

static void PopIStackUntil( TidyDocImpl* doc, TidyTagId tid )
{
    Lexer* lexer = doc->lexer;
    IStack *istack;

    while (lexer->istacksize > 0)
    {
        PopIStack( doc );
        istack = &(lexer->istack[lexer->istacksize]);
        if ( istack->tag->id == tid )
            break;
    }
}

/* pop inline stack */
void TY_(PopInline)( TidyDocImpl* doc, Node *node )
{
    Lexer* lexer = doc->lexer;

    if (node)
    {
        if ( !IsNodePushable(node) )
            return;

        /* if node is </a> then pop until we find an <a> */
        if ( nodeIsA(node) )
        {
            PopIStackUntil( doc, TidyTag_A );
            return;
        }
    }

    if (lexer->istacksize > 0)
    {
        PopIStack( doc );

        /* #427822 - fix by Randy Waki 7 Aug 00 */
        if (lexer->insert >= lexer->istack + lexer->istacksize)
            lexer->insert = NULL;
    }
}

Bool TY_(IsPushed)( TidyDocImpl* doc, Node *node )
{
    Lexer* lexer = doc->lexer;
    int i;

    for (i = lexer->istacksize - 1; i >= 0; --i)
    {
        if (lexer->istack[i].tag == node->tag)
            return yes;
    }

    return no;
}

/*
   Test whether the last element on the stack has the same type than "node".
*/
Bool TY_(IsPushedLast)( TidyDocImpl* doc, Node *element, Node *node )
{
    Lexer* lexer = doc->lexer;

    if ( element && !IsNodePushable(element) )
        return no;

    if (lexer->istacksize > 0) {
        if (lexer->istack[lexer->istacksize - 1].tag == node->tag) {
            return yes;
        }
    }

    return no;
}

/*
  This has the effect of inserting "missing" inline
  elements around the contents of blocklevel elements
  such as P, TD, TH, DIV, PRE etc. This procedure is
  called at the start of ParseBlock. when the inline
  stack is not empty, as will be the case in:

    <i><h1>italic heading</h1></i>

  which is then treated as equivalent to

    <h1><i>italic heading</i></h1>

  This is implemented by setting the lexer into a mode
  where it gets tokens from the inline stack rather than
  from the input stream.
*/
int TY_(InlineDup)( TidyDocImpl* doc, Node* node )
{
    Lexer* lexer = doc->lexer;
    int n;

    if ((n = lexer->istacksize - lexer->istackbase) > 0)
    {
        lexer->insert = &(lexer->istack[lexer->istackbase]);
        lexer->inode = node;
    }

    return n;
}

/*
 defer duplicates when entering a table or other
 element where the inlines shouldn't be duplicated
*/
void TY_(DeferDup)( TidyDocImpl* doc )
{
    doc->lexer->insert = NULL;
    doc->lexer->inode = NULL;
}

Node *TY_(InsertedToken)( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    Node *node;
    IStack *istack;
    unsigned int n;

    /* this will only be NULL if inode != NULL */
    if (lexer->insert == NULL)
    {
        node = lexer->inode;
        lexer->inode = NULL;
        return node;
    }

    /*
      If this is the "latest" node then update
      the position, otherwise use current values
    */

    if (lexer->inode == NULL)
    {
        lexer->lines = doc->docIn->curline;
        lexer->columns = doc->docIn->curcol;
    }

    node = TY_(NewNode)(doc->allocator, lexer);
    node->type = StartTag;
    node->implicit = yes;
    node->start = lexer->txtstart;
    /* #431734 [JTidy bug #226261 (was 126261)] - fix by Gary Peskin 20 Dec 00 */ 
    node->end = lexer->txtend; /* was : lexer->txtstart; */
    istack = lexer->insert;

/* #if 0 && defined(_DEBUG) */
#if definedENABLE_DEBUG_LOG
    if ( lexer->istacksize == 0 )
    {
        SPRTF( "WARNING: ZERO sized istack!\n" );
    }
#endif

    node->element = TY_(tmbstrdup)(doc->allocator, istack->element);
    node->tag = istack->tag;
    node->attributes = TY_(DupAttrs)( doc, istack->attributes );

    /* advance lexer to next item on the stack */
    n = (unsigned int)(lexer->insert - &(lexer->istack[0]));

    /* and recover state if we have reached the end */
    if (++n < lexer->istacksize)
        lexer->insert = &(lexer->istack[n]);
    else
        lexer->insert = NULL;

    return node;
}


/*
   We have two CM_INLINE elements pushed ... the first is closing,
   but, like the browser, the second should be retained ...
   Like <b>bold <i>bold and italics</b> italics only</i>
   This function switches the tag positions on the stack,
   returning 'yes' if both were found in the expected order.
*/
Bool TY_(SwitchInline)( TidyDocImpl* doc, Node* element, Node* node )
{
    Lexer* lexer = doc->lexer;
    if ( lexer
         && element && element->tag
         && node && node->tag
         && TY_(IsPushed)( doc, element )
         && TY_(IsPushed)( doc, node ) 
         && ((lexer->istacksize - lexer->istackbase) >= 2) )
    {
        /* we have a chance of succeeding ... */
        int i;
        for (i = (lexer->istacksize - lexer->istackbase - 1); i >= 0; --i)
        {
            if (lexer->istack[i].tag == element->tag) {
                /* found the element tag - phew */
                IStack *istack1 = &lexer->istack[i];
                IStack *istack2 = NULL;
                --i; /* back one more, and continue */
                for ( ; i >= 0; --i)
                {
                    if (lexer->istack[i].tag == node->tag)
                    {
                        /* found the element tag - phew */
                        istack2 = &lexer->istack[i];
                        break;
                    }
                }
                if ( istack2 )
                {
                    /* perform the swap */
                    IStack tmp_istack = *istack2;
                    *istack2 = *istack1;
                    *istack1 = tmp_istack;
                    return yes;
                }
            }
        }
    }
    return no;
}

/*
  We want to push a specific a specific element on the stack,
  but it may not be the last element, which InlineDup()
  would handle. Return yes, if found and inserted.
*/
Bool TY_(InlineDup1)( TidyDocImpl* doc, Node* node, Node* element )
{
    Lexer* lexer = doc->lexer;
    int n, i;
    if ( element
         && (element->tag != NULL)
         && ((n = lexer->istacksize - lexer->istackbase) > 0) )
    {
        for ( i = n - 1; i >=0; --i ) {
            if (lexer->istack[i].tag == element->tag) {
                /* found our element tag - insert it */
                lexer->insert = &(lexer->istack[i]);
                lexer->inode = node;
                return yes;
            }
        }
    }
    return no;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* language.c -- localization support for HTML Tidy.

  Copyright 2015 HTACG
  See tidy.h for the copyright notice.

 */

/* #include "language.h" */
/* #include "language_en.h" */
/* #include "tmbstr.h" */
/* #include "locale.h" */

#if SUPPORT_LOCALIZATIONS
/* #include "language_en_gb.h" */
/* #include "language_es.h" */
/* #include "language_es_mx.h" */
/* #include "language_pt_br.h" */
/* #include "language_zh_cn.h" */
/* #include "language_fr.h" */
#endif


/**
 *  This structure type provides universal access to all of Tidy's strings.
 *  Note limit of 8, to be changed as more added...
 */
typedef struct {
    Bool manually_set;
    languageDefinition *currentLanguage;
    languageDefinition *fallbackLanguage;
    languageDefinition *languages[8];
} tidyLanguagesType;


/**
 *  This single structure contains all localizations. Note that we preset
 *  `.currentLanguage` to language_en, which is Tidy's default language.
 */
static tidyLanguagesType tidyLanguages = {
    no,           /* library language was NOT manually set */
    &language_en, /* current language */
    &language_en, /* first fallback language */
    {
        /* Required localization! */
        &language_en,
#if SUPPORT_LOCALIZATIONS
        /* These additional languages are installed. */
        &language_en_gb,
        &language_es,
        &language_es_mx,
        &language_pt_br,
        &language_zh_cn,
        &language_fr,
#endif
        NULL /* This array MUST be null terminated. */
    }
};


/**
 *  This structure maps old-fashioned Windows strings
 *  to proper POSIX names (modern Windows already uses
 *  POSIX names).
 */
static const tidyLocaleMapItemImpl localeMappings[] = {
    { "america",                "en_us" },
    { "american english",       "en_us" },
    { "american-english",       "en_us" },
    { "american",               "en_us" },
    { "aus",                    "en_au" },
    { "australia",              "en_au" },
    { "australian",             "en_au" },
    { "austria",                "de_at" },
    { "aut",                    "de_at" },
    { "bel",                    "nl_be" },
    { "belgian",                "nl_be" },
    { "belgium",                "nl_be" },
    { "bra",                    "pt-br" },
    { "brazil",                 "pt-br" },
    { "britain",                "en_gb" },
    { "can",                    "en_ca" },
    { "canada",                 "en_ca" },
    { "canadian",               "en_ca" },
    { "che",                    "de_ch" },
    { "china",                  "zh_cn" },
    { "chinese-simplified",     "zh"    },
    { "chinese-traditional",    "zh_tw" },
    { "chinese",                "zh"    },
    { "chn",                    "zh_cn" },
    { "chs",                    "zh"    },
    { "cht",                    "zh_tw" },
    { "csy",                    "cs"    },
    { "cze",                    "cs_cz" },
    { "czech",                  "cs_cz" },
    { "dan",                    "da"    },
    { "danish",                 "da"    },
    { "dea",                    "de_at" },
    { "denmark",                "da_dk" },
    { "des",                    "de_ch" },
    { "deu",                    "de"    },
    { "dnk",                    "da_dk" },
    { "dutch-belgian",          "nl_be" },
    { "dutch",                  "nl"    },
    { "ell",                    "el"    },
    { "ena",                    "en_au" },
    { "enc",                    "en_ca" },
    { "eng",                    "eb_gb" },
    { "england",                "en_gb" },
    { "english-american",       "en_us" },
    { "english-aus",            "en_au" },
    { "english-can",            "en_ca" },
    { "english-nz",             "en_nz" },
    { "english-uk",             "eb_gb" },
    { "english-us",             "en_us" },
    { "english-usa",            "en_us" },
    { "english",                "en"    },
    { "enu",                    "en_us" },
    { "enz",                    "en_nz" },
    { "esm",                    "es-mx" },
    { "esn",                    "es"    },
    { "esp",                    "es"    },
    { "fin",                    "fi"    },
    { "finland",                "fi_fi" },
    { "finnish",                "fi"    },
    { "fra",                    "fr"    },
    { "france",                 "fr_fr" },
    { "frb",                    "fr_be" },
    { "frc",                    "fr_ca" },
    { "french-belgian",         "fr_be" },
    { "french-canadian",        "fr_ca" },
    { "french-swiss",           "fr_ch" },
    { "french",                 "fr"    },
    { "frs",                    "fr_ch" },
    { "gbr",                    "en_gb" },
    { "german-austrian",        "de_at" },
    { "german-swiss",           "de_ch" },
    { "german",                 "de"    },
    { "germany",                "de_de" },
    { "grc",                    "el_gr" },
    { "great britain",          "en_gb" },
    { "greece",                 "el_gr" },
    { "greek",                  "el"    },
    { "hkg",                    "zh_hk" },
    { "holland",                "nl_nl" },
    { "hong kong",              "zh_hk" },
    { "hong-kong",              "zh_hk" },
    { "hun",                    "hu"    },
    { "hungarian",              "hu"    },
    { "hungary",                "hu_hu" },
    { "iceland",                "is_is" },
    { "icelandic",              "is"    },
    { "ireland",                "en_ie" },
    { "irl",                    "en_ie" },
    { "isl",                    "is"    },
    { "ita",                    "it"    },
    { "ita",                    "it_it" },
    { "italian-swiss",          "it_ch" },
    { "italian",                "it"    },
    { "italy",                  "it_it" },
    { "its",                    "it_ch" },
    { "japan",                  "ja_jp" },
    { "japanese",               "ja"    },
    { "jpn",                    "ja"    },
    { "kor",                    "ko"    },
    { "korea",                  "ko_kr" },
    { "korean",                 "ko"    },
    { "mex",                    "es-mx" },
    { "mexico",                 "es-mx" },
    { "netherlands",            "nl_nl" },
    { "new zealand",            "en_nz" },
    { "new-zealand",            "en_nz" },
    { "nlb",                    "nl_be" },
    { "nld",                    "nl"    },
    { "non",                    "nn"    },
    { "nor",                    "nb"    },
    { "norway",                 "no"    },
    { "norwegian-bokmal",       "nb"    },
    { "norwegian-nynorsk",      "nn"    },
    { "norwegian",              "no"    },
    { "nz",                     "en_nz" },
    { "nzl",                    "en_nz" },
    { "plk",                    "pl"    },
    { "pol",                    "pl-pl" },
    { "poland",                 "pl-pl" },
    { "polish",                 "pl"    },
    { "portugal",               "pt-pt" },
    { "portuguese-brazil",      "pt-br" },
    { "portuguese",             "pt"    },
    { "pr china",               "zh_cn" },
    { "pr-china",               "zh_cn" },
    { "prt",                    "pt-pt" },
    { "ptb",                    "pt-br" },
    { "ptg",                    "pt"    },
    { "rus",                    "ru"    },
    { "russia",                 "ru-ru" },
    { "russian",                "ru"    },
    { "sgp",                    "zh_sg" },
    { "singapore",              "zh_sg" },
    { "sky",                    "sk"    },
    { "slovak",                 "sk"    },
    { "spain",                  "es-es" },
    { "spanish-mexican",        "es-mx" },
    { "spanish-modern",         "es"    },
    { "spanish",                "es"    },
    { "sve",                    "sv"    },
    { "svk",                    "sk-sk" },
    { "swe",                    "sv-se" },
    { "sweden",                 "sv-se" },
    { "swedish",                "sv"    },
    { "swiss",                  "de_ch" },
    { "switzerland",            "de_ch" },
    { "taiwan",                 "zh_tw" },
    { "trk",                    "tr"    },
    { "tur",                    "tr-tr" },
    { "turkey",                 "tr-tr" },
    { "turkish",                "tr"    },
    { "twn",                    "zh_tw" },
    { "uk",                     "en_gb" },
    { "united kingdom",         "en_gb" },
    { "united states",          "en_us" },
    { "united-kingdom",         "en_gb" },
    { "united-states",          "en_us" },
    { "us",                     "en_us" },
    { "usa",                    "en_us" },
    
    /* MUST be last. */
    { NULL,                     NULL    }
};


/**
 *  The real string lookup function.
 */
static ctmbstr tidyLocalizedStringImpl( unsigned int messageType, languageDefinition *definition, unsigned int plural )
{
    int i;
    languageDictionary *dictionary = &definition->messages;
    unsigned int pluralForm = definition->whichPluralForm(plural);
    
    for (i = 0; (*dictionary)[i].value; ++i)
    {
        if ( (*dictionary)[i].key == messageType && (*dictionary)[i].pluralForm == pluralForm )
        {
            return (*dictionary)[i].value;
        }
    }
    return NULL;
}


/**
 *  Provides a string given `messageType` in the current
 *  localization, returning the correct plural form given
 *  `quantity`.
 *
 *  This isn't currently highly optimized; rewriting some
 *  of infrastructure to use hash lookups is a preferred
 *  future optimization.
 */
ctmbstr TY_(tidyLocalizedStringN)( unsigned int messageType, unsigned int quantity )
{
    ctmbstr result;
    
    result  = tidyLocalizedStringImpl( messageType, tidyLanguages.currentLanguage, quantity);
    
    if (!result && tidyLanguages.fallbackLanguage )
    {
        result = tidyLocalizedStringImpl( messageType, tidyLanguages.fallbackLanguage, quantity);
    }
    
    if (!result)
    {
        /* Fallback to en which is built in. */
        result = tidyLocalizedStringImpl( messageType, &language_en, quantity);
    }
    
    if (!result)
    {
        /* Last resort: Fallback to en singular which is built in. */
        result = tidyLocalizedStringImpl( messageType, &language_en, 1);
    }
    
    return result;
}


/**
 *  Provides a string given `messageType` in the current
 *  localization, in the non-plural form.
 *
 *  This isn't currently highly optimized; rewriting some
 *  of infrastructure to use hash lookups is a preferred
 *  future optimization.
 */
ctmbstr TY_(tidyLocalizedString)( unsigned int messageType )
{
    return TY_(tidyLocalizedStringN)( messageType, 1 );
}


/**
 *  Retrieves the POSIX name for a string. Result is a static char so please
 *  don't try to free it. If the name looks like a cc_ll identifier, we will
 *  return it if there's no other match.
 *  @note this routine uses default allocator, see tidySetMallocCall.
 */
tmbstr TY_(tidyNormalizedLocaleName)( ctmbstr locale )
{
    unsigned int i;
    unsigned int len;
    static char result[6] = "xx_yy";
    TidyAllocator * allocator = &TY_(g_default_allocator);

    tmbstr search = TY_(tmbstrdup)( allocator, locale );
    search = TY_(tmbstrtolower)(search);
    
    /* See if our string matches a Windows name. */
    for (i = 0; localeMappings[i].winName; ++i)
    {
        if ( strcmp( localeMappings[i].winName, search ) == 0 )
        {
            TidyFree( allocator, search );
            search = TY_(tmbstrdup)( allocator, localeMappings[i].POSIXName );
            break;
        }
    }
    
    /* We're going to be stupid about this and trust the user, and
     return just the first two characters if they exist and the
     4th and 5th if they exist. The worst that can happen is a
     junk language that doesn't exist and won't be set. */
    
    len = strlen( search );
    len = ( len <= 5 ? len : 5 );
    
    for ( i = 0; i < len; i++ )
    {
        if ( i == 2 )
        {
            /* Either terminate the string or ensure there's an underscore */
            if (len == 5) {
                result[i] = '_';
            }
            else {
                result[i] = '\0';
                break;      /* no need to copy after null */
            }
        }
        else
        {
            result[i] = tolower( search[i] );
        }
    }
    
    TidyFree( allocator, search );
    return result;
}


/**
 *  Returns the languageDefinition if the languageCode is installed in Tidy,
 *  otherwise return NULL
 */
languageDefinition *TY_(tidyTestLanguage)( ctmbstr languageCode )
{
    unsigned int i;
    languageDefinition *testLang;
    languageDictionary *testDict;
    ctmbstr testCode;
    
    for (i = 0; tidyLanguages.languages[i]; ++i)
    {
        testLang = tidyLanguages.languages[i];
        testDict = &testLang->messages;
        testCode = (*testDict)[0].value;
        
        if ( strcmp(testCode, languageCode) == 0 )
            return testLang;
    }
    
    return NULL;
}


/**
 *  Tells Tidy to use a different language for output.
 *  @param  languageCode A Windows or POSIX language code, and must match
 *          a TIDY_LANGUAGE for an installed language.
 *  @result Indicates that a setting was applied, but not necessarily the
 *          specific request, i.e., true indicates a language and/or region
 *          was applied. If es_mx is requested but not installed, and es is
 *          installed, then es will be selected and this function will return
 *          true. However the opposite is not true; if es is requested but
 *          not present, Tidy will not try to select from the es_XX variants.
 */
Bool TY_(tidySetLanguage)( ctmbstr languageCode )
{
    languageDefinition *dict1 = NULL;
    languageDefinition *dict2 = NULL;
    tmbstr wantCode = NULL;
    char lang[3] = "";
    
    if ( !languageCode || !(wantCode = TY_(tidyNormalizedLocaleName)( languageCode )) )
    {
        return no;
    }
    
    /* We want to use the specified language as the currentLanguage, and set
     fallback language as necessary. We have either a two or five digit code,
     either or both of which might be installed. Let's test both of them:
     */
    
    dict1 = TY_(tidyTestLanguage( wantCode ));  /* WANTED language */
    
    if ( strlen( wantCode ) > 2 )
    {
        strncpy(lang, wantCode, 2);
        lang[2] = '\0';
        dict2 = TY_(tidyTestLanguage( lang ) ); /* BACKUP language? */
    }
    
    if ( dict1 && dict2 )
    {
        tidyLanguages.currentLanguage = dict1;
        tidyLanguages.fallbackLanguage = dict2;
    }
    if ( dict1 && !dict2 )
    {
        tidyLanguages.currentLanguage = dict1;
        tidyLanguages.fallbackLanguage = NULL;
    }
    if ( !dict1 && dict2 )
    {
        tidyLanguages.currentLanguage = dict2;
        tidyLanguages.fallbackLanguage = NULL;
    }
    if ( !dict1 && !dict2 )
    {
        /* No change. */
    }
    
    return dict1 || dict2;
}


/**
 *  Gets the current language used by Tidy.
 */
ctmbstr TY_(tidyGetLanguage)()
{
    languageDefinition *langDef = tidyLanguages.currentLanguage;
    languageDictionary *langDict = &langDef->messages;
    return (*langDict)[0].value;
}


/**
 *  Indicates whether or not the current language was set by a
 *  LibTidy user (yes) or internally by the library (no).
 */
Bool TY_(tidyGetLanguageSetByUser)()
{
    return tidyLanguages.manually_set;
}


/**
 *  Specifies to LibTidy that the user (rather than the library)
 *  selected the current language.
 */
void TY_(tidySetLanguageSetByUser)( void )
{
    tidyLanguages.manually_set = yes;
}


/**
 *  Provides a string given `messageType` in the default
 *  localization (which is `en`), for single plural form.
 */
ctmbstr TY_(tidyDefaultString)( unsigned int messageType )
{
    return tidyLocalizedStringImpl( messageType, &language_en, 1);
}


/**
 *  Determines the true size of the `language_en` array indicating the
 *  number of items in the array, _not_ the highest index.
 */
static const unsigned int tidyStringKeyListSize()
{
    static unsigned int array_size = 0;
    
    if ( array_size == 0 )
    {
        while ( language_en.messages[array_size].value != NULL ) {
            array_size++;
        }
    }
    
    return array_size;
}


/*
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's list of localization string keys. Note that
 *  these are provided for documentation generation purposes
 *  and probably aren't useful for LibTidy implementors.
 */
TidyIterator TY_(getStringKeyList)()
{
    return (TidyIterator)(size_t)1;
}

/*
 *  Provides the next key value in Tidy's list of localized
 *  strings. Note that these are provided for documentation
 *  generation purposes and probably aren't useful to
 *  libtidy implementors.
 */
unsigned int TY_(getNextStringKey)( TidyIterator* iter )
{
    unsigned int item = 0;
    size_t itemIndex;
    assert( iter != NULL );
    
    itemIndex = (size_t)*iter;
    
    if ( itemIndex > 0 && itemIndex <= tidyStringKeyListSize() )
    {
        item = language_en.messages[ itemIndex - 1 ].key;
        itemIndex++;
    }
    
    *iter = (TidyIterator)( itemIndex <= tidyStringKeyListSize() ? itemIndex : (size_t)0 );
    return item;
}


/**
 *  Determines the true size of the `localeMappings` array indicating the
 *  number of items in the array, _not_ the highest index.
 */
static const unsigned int tidyLanguageListSize()
{
    static unsigned int array_size = 0;
    
    if ( array_size == 0 )
    {
        while ( localeMappings[array_size].winName ) {
            array_size++;
        }
    }
    
    return array_size;
}

/**
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's structure of Windows<->POSIX local mapping.
 *  Items can be retrieved with getNextWindowsLanguage();
 */
TidyIterator TY_(getWindowsLanguageList)()
{
    return (TidyIterator)(size_t)1;
}

/**
 *  Returns the next record of type `localeMapItem` in
 *  Tidy's structure of Windows<->POSIX local mapping.
 */
const tidyLocaleMapItemImpl *TY_(getNextWindowsLanguage)( TidyIterator *iter )
{
    const tidyLocaleMapItemImpl *item = NULL;
    size_t itemIndex;
    assert( iter != NULL );
    
    itemIndex = (size_t)*iter;
    
    if ( itemIndex > 0 && itemIndex <= tidyLanguageListSize() )
    {
        item = &localeMappings[ itemIndex -1 ];
        itemIndex++;
    }
    
    *iter = (TidyIterator)( itemIndex <= tidyLanguageListSize() ? itemIndex : (size_t)0 );
    return item;
}


/**
 *  Given a `tidyLocaleMapItemImpl, return the Windows name.
 */
ctmbstr TY_(TidyLangWindowsName)( const tidyLocaleMapItemImpl *item )
{
    return item->winName;
}


/**
 *  Given a `tidyLocaleMapItemImpl, return the POSIX name.
 */
ctmbstr TY_(TidyLangPosixName)( const tidyLocaleMapItemImpl *item )
{
    return item->POSIXName;
}


/**
 *  Determines the number of languages installed in Tidy.
 */
static const unsigned int tidyInstalledLanguageListSize()
{
    static unsigned int array_size = 0;
    
    if ( array_size == 0 )
    {
        while ( tidyLanguages.languages[array_size] ) {
            array_size++;
        }
    }
    
    return array_size;
}

/**
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's list of installed language codes.
 *  Items can be retrieved with getNextInstalledLanguage();
 */
TidyIterator TY_(getInstalledLanguageList)()
{
    return (TidyIterator)(size_t)1;
}

/**
 *  Returns the next installed language.
 */
ctmbstr TY_(getNextInstalledLanguage)( TidyIterator* iter )
{
    ctmbstr item = NULL;
    size_t itemIndex;
    assert( iter != NULL );
    
    itemIndex = (size_t)*iter;
    
    if ( itemIndex > 0 && itemIndex <= tidyInstalledLanguageListSize() )
    {
        item = tidyLanguages.languages[itemIndex - 1]->messages[0].value;
        itemIndex++;
    }
    
    *iter = (TidyIterator)( itemIndex <= tidyInstalledLanguageListSize() ? itemIndex : (size_t)0 );
    return item;
}
/* lexer.c -- Lexer for html parser
  
  (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/*
  Given a file stream fp it returns a sequence of tokens.

     GetToken(fp) gets the next token
     UngetToken(fp) provides one level undo

  The tags include an attribute list:

    - linked list of attribute/value nodes
    - each node has 2 NULL-terminated strings.
    - entities are replaced in attribute values

  white space is compacted if not in preformatted mode
  If not in preformatted mode then leading white space
  is discarded and subsequent white space sequences
  compacted to single space characters.

  If XmlTags is no then Tag names are folded to upper
  case and attribute names to lower case.

 Not yet done:
    -   Doctype subset and marked sections
*/

/* #include "tidy-int.h" */
/* #include "lexer.h" */
/* #include "parser.h" */
/* #include "entities.h" */
/* #include "streamio.h" */
/* #include "message.h" */
/* #include "tmbstr.h" */
/* #include "clean.h" */
/* #include "utf8.h" */
/* #include "streamio.h" */
/* #include "sprtf.h" */

#if defined(ENABLE_DEBUG_LOG)
/* #define DEBUG_ALLOCATION   special EXTRA allocation debug information - VERY NOISY */
static void check_me(char *name);
static Bool show_attrs = yes;
#define MX_TXT 8
static char buffer[(MX_TXT*4)+8]; /* NOTE extra for '...'\0 tail */
static tmbstr get_text_string(Lexer* lexer, Node *node)
{
    unsigned int len = node->end - node->start;
    tmbstr cp = lexer->lexbuf + node->start;
    tmbstr end = lexer->lexbuf + node->end;
    unsigned char c;
    unsigned int i = 0;
    Bool insp = no;
    if (len <= ((MX_TXT * 2) + 3)) {
        buffer[0] = 0;
        while (cp < end) {
            c = *cp;
            cp++;
            if (c == '\n') {
                buffer[i++] = '\\';
                buffer[i++] = 'n';
            } else if (c == '\t') {
                buffer[i++] = '\\';
                buffer[i++] = 't';
            } else if ( c == ' ' ) {
                if (!insp)
                    buffer[i++] = c;
                insp = yes;
            } else {
                buffer[i++] = c;
                insp = no;
            }
        }
    } else {
        char *end1 = cp + MX_TXT;
        char *bgn = cp + (len - MX_TXT);
        buffer[0] = 0;
        if (bgn < end1)
            bgn = end1;
        while (cp < end1) {
            c = *cp;
            cp++;
            if (c == '\n') {
                buffer[i++] = '\\';
                buffer[i++] = 'n';
            } else if (c == '\t') {
                buffer[i++] = '\\';
                buffer[i++] = 't';
            } else if ( c == ' ' ) {
                if (!insp)
                    buffer[i++] = c;
                insp = yes;
            } else {
                buffer[i++] = c;
                insp = no;
            }
            if (i >= MX_TXT)
                break;
        }
        c = '.';
        if ((i < len)&&(cp < bgn)) {
            buffer[i++] = c;
            cp++;
            if ((i < len)&&(cp < bgn)) {
                buffer[i++] = c;
                cp++;
                if ((i < len)&&(cp < bgn)) {
                    buffer[i++] = c;
                    cp++;
                }
            }
        }
        cp = bgn;
        insp = no;
        while (cp < end) {
            c = *cp;
            cp++;
            if (c == '\n') {
                buffer[i++] = '\\';
                buffer[i++] = 'n';
            } else if (c == '\t') {
                buffer[i++] = '\\';
                buffer[i++] = 't';
            } else if ( c == ' ' ) {
                if (!insp)
                    buffer[i++] = c;
                insp = yes;
            } else {
                buffer[i++] = c;
                insp = no;
            }
        }
    }
    buffer[i] = 0;
    return buffer;
}
static void Show_Node( TidyDocImpl* doc, const char *msg, Node *node )
{
    Lexer* lexer = doc->lexer;
    Bool lex = ((msg[0] == 'l')&&(msg[1] == 'e')) ? yes : no;
    int line = ( doc->lexer ? doc->lexer->lines : 0 );
    int col  = ( doc->lexer ? doc->lexer->columns : 0 );
    tmbstr src = lex ? "lexer" : "stream";
    SPRTF("R=%d C=%d: ", line, col );
    /* DEBUG: Be able to set a TRAP on a SPECIFIC row,col */
    if ((line == 3) && (col == 1)) {
        check_me("Show_Node"); /* just a debug trap */
    }
    if (lexer && lexer->token && 
        ((lexer->token->type == TextNode)||(node && (node->type == TextNode)))) {
        if (show_attrs) {
            unsigned int len = node ? node->end - node->start : 0;
            tmbstr cp = node ? get_text_string( lexer, node ) : "NULL";
            SPRTF("Returning %s TextNode [%s]%u %s\n", msg, cp, len, src );
        } else {
            SPRTF("Returning %s TextNode %p... %s\n", msg, node, src );
        }
    } else {
        tmbstr name = node ? node->element ? node->element : "blank" : "NULL";
        if (show_attrs) {
            AttVal* av;
            SPRTF("Returning %s node <%s", msg, name);
            if (node) {
                for (av = node->attributes; av; av = av->next) {
                    name = av->attribute;
                    if (name) {
                        SPRTF(" %s",name);
                        if (av->value) {
                            SPRTF("=\"%s\"", av->value);
                        }
                    }
                }
            }
            SPRTF("> %s\n", src);
        } else {
            SPRTF("Returning %s node %p <%s>... %s\n", msg, node,
                name, src );
        }
    }
}
#define GTDBG(a,b,c) Show_Node(a,b,c)
#else /* ENABLE_DEBUG_LOG */
#define GTDBG(a,b,c)
#endif /* defined(ENABLE_DEBUG_LOG) */

/* Forward references
*/
/* swallows closing '>' */
static AttVal *ParseAttrs( TidyDocImpl* doc, Bool *isempty );

static tmbstr ParseAttribute( TidyDocImpl* doc, Bool* isempty, 
                             Node **asp, Node **php );

static tmbstr ParseValue( TidyDocImpl* doc, ctmbstr name, Bool foldCase,
                         Bool *isempty, int *pdelim );

static Node *ParseDocTypeDecl(TidyDocImpl* doc);

static void AddAttrToList( AttVal** list, AttVal* av );

/* used to classify characters for lexical purposes */
#define MAP(c) ((unsigned)c < 128 ? lexmap[(unsigned)c] : 0)
static unsigned int lexmap[128];

#define IsValidXMLAttrName(name) TY_(IsValidXMLID)(name)
#define IsValidXMLElemName(name) TY_(IsValidXMLID)(name)

static struct _doctypes
{
    unsigned int score;
    unsigned int vers;
    unsigned int vers_out;
    Bool xhtml;
    ctmbstr name;
    ctmbstr fpi;
    ctmbstr si;
} const W3C_Doctypes[] =
{
  {  2, HT20, 200, no,  "HTML 2.0",               "-//IETF//DTD HTML 2.0//EN",              NULL,                                                       },
  {  2, HT20, 200, no,  "HTML 2.0",               "-//IETF//DTD HTML//EN",                  NULL,                                                       },
  {  2, HT20, 200, no,  "HTML 2.0",               "-//W3C//DTD HTML 2.0//EN",               NULL,                                                       },
  {  1, HT32, 320, no,  "HTML 3.2",               "-//W3C//DTD HTML 3.2//EN",               NULL,                                                       },
  {  1, HT32, 320, no,  "HTML 3.2",               "-//W3C//DTD HTML 3.2 Final//EN",         NULL,                                                       },
  {  1, HT32, 320, no,  "HTML 3.2",               "-//W3C//DTD HTML 3.2 Draft//EN",         NULL,                                                       },
  {  6, H40S, 400, no,  "HTML 4.0 Strict",        "-//W3C//DTD HTML 4.0//EN",               "http://www.w3.org/TR/REC-html40/strict.dtd"                },
  {  8, H40T, 400, no,  "HTML 4.0 Transitional",  "-//W3C//DTD HTML 4.0 Transitional//EN",  "http://www.w3.org/TR/REC-html40/loose.dtd"                 },
  {  7, H40F, 400, no,  "HTML 4.0 Frameset",      "-//W3C//DTD HTML 4.0 Frameset//EN",      "http://www.w3.org/TR/REC-html40/frameset.dtd"              },
  {  3, H41S, 401, no,  "HTML 4.01 Strict",       "-//W3C//DTD HTML 4.01//EN",              "http://www.w3.org/TR/html4/strict.dtd"                     },
  {  5, H41T, 401, no,  "HTML 4.01 Transitional", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd"                      },
  {  4, H41F, 401, no,  "HTML 4.01 Frameset",     "-//W3C//DTD HTML 4.01 Frameset//EN",     "http://www.w3.org/TR/html4/frameset.dtd"                   },
  {  9, X10S, 100, yes, "XHTML 1.0 Strict",       "-//W3C//DTD XHTML 1.0 Strict//EN",       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"         },
  { 11, X10T, 100, yes, "XHTML 1.0 Transitional", "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"   },
  { 10, X10F, 100, yes, "XHTML 1.0 Frameset",     "-//W3C//DTD XHTML 1.0 Frameset//EN",     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"       },
  { 12, XH11, 110, yes, "XHTML 1.1",              "-//W3C//DTD XHTML 1.1//EN",              "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"              },
  { 13, XB10, 100, yes, "XHTML Basic 1.0",        "-//W3C//DTD XHTML Basic 1.0//EN",        "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd"        },

  { 20, HT50, 500, no,  "HTML5",                  NULL,                                     NULL                                                        },
  { 21, XH50, 500, yes, "XHTML5",                 NULL,                                     NULL                                                        },

  /* final entry */
  {  0,    0, 0,  no,  NULL,                     NULL,                                     NULL                                                        }
};

/* 
 * Issue #643 - Since VERS_FROM40 was extended to include VERS_HTML5
 * to be used in the expanded entity table some 155 times,
 * need a special macro here to denote just HTML 4 plus XHTML,
 * which is actually the former define of VERS_FROM40
 */
#define VERS_HMTL40PX        (VERS_HTML40|VERS_XHTML11|VERS_BASIC)

int TY_(HTMLVersion)(TidyDocImpl* doc)
{
    unsigned int i;
    unsigned int j = 0;
    unsigned int score = 0;
    unsigned int vers = doc->lexer->versions;
    unsigned int dtver = doc->lexer->doctype;
    TidyDoctypeModes dtmode = (TidyDoctypeModes)cfg(doc, TidyDoctypeMode);
    Bool xhtml = (cfgBool(doc, TidyXmlOut) || doc->lexer->isvoyager) &&
                 !cfgBool(doc, TidyHtmlOut);
    Bool html4 = ((dtmode == TidyDoctypeStrict) || (dtmode == TidyDoctypeLoose) ||
                  (VERS_HMTL40PX & dtver) ? yes : no);
    Bool html5 = (!html4 && ((dtmode == TidyDoctypeAuto) ||
                  (dtmode == TidyDoctypeHtml5)) ? yes : no);

    if (xhtml && dtver == VERS_UNKNOWN) return XH50;
    if (dtver == VERS_UNKNOWN) return HT50;
    /* Issue #167 - if NOT XHTML, and doctype is default VERS_HTML5, then return HT50 */
    if (!xhtml && (dtver == VERS_HTML5)) return HT50;
    /* Issue #377 - If xhtml and (doctype == html5) and constrained vers contains XH50 return that,
       and really if tidy defaults to 'html5', then maybe 'auto' should also apply! */
    if (xhtml && html5 && ((vers & VERS_HTML5) == XH50)) return XH50;

    for (i = 0; W3C_Doctypes[i].name; ++i)
    {
        if ((xhtml && !(VERS_XHTML & W3C_Doctypes[i].vers)) ||
            (html4 && !(VERS_HMTL40PX & W3C_Doctypes[i].vers)))
            continue;

        if (vers & W3C_Doctypes[i].vers &&
            (W3C_Doctypes[i].score < score || !score))
        {
            score = W3C_Doctypes[i].score;
            j = i;
        }
    }

    if (score)
        return W3C_Doctypes[j].vers;

    return VERS_UNKNOWN;
}

static ctmbstr GetFPIFromVers(unsigned int vers)
{
    unsigned int i;

    for (i = 0; W3C_Doctypes[i].name; ++i)
        if (W3C_Doctypes[i].vers == vers)
            return W3C_Doctypes[i].fpi;

    return NULL;
}

static ctmbstr GetSIFromVers(unsigned int vers)
{
    unsigned int i;

    for (i = 0; W3C_Doctypes[i].name; ++i)
        if (W3C_Doctypes[i].vers == vers)
            return W3C_Doctypes[i].si;

    return NULL;
}

static ctmbstr GetNameFromVers(unsigned int vers)
{
    unsigned int i;

    for (i = 0; W3C_Doctypes[i].name; ++i)
        if (W3C_Doctypes[i].vers == vers)
            return W3C_Doctypes[i].name;

    return NULL;
}

static unsigned int GetVersFromFPI(ctmbstr fpi)
{
    unsigned int i;

    for (i = 0; W3C_Doctypes[i].name; ++i)
        if (W3C_Doctypes[i].fpi != NULL && TY_(tmbstrcasecmp)(W3C_Doctypes[i].fpi, fpi) == 0)
            return W3C_Doctypes[i].vers;

    return 0;
}

#ifdef ENABLE_DEBUG_LOG
#  ifndef EndBuf
#    define EndBuf(a)   ( a + strlen(a) )
#  endif

/* Issue #377 - Output diminishing version bits */
typedef struct tagV2S {
    unsigned int bit;
    ctmbstr val;
}V2S, *PV2S;

static V2S v2s[] = {
    { HT20, "HT20" },
    { HT32, "HT32" },
    { H40S, "H40S" },
    { H40T, "H40T" },
    { H40F, "H40F" },
    { H41S, "H41S" },
    { H41T, "H41T" },
    { H41F, "H41F" },
    { X10S, "X10S" },
    { X10T, "X10T" },
    { X10F, "X10F" },
    { XH11, "XH11" },
    { XB10, "XB10" }, /* 4096u */
    /* { VERS_SUN, "VSUN" }, */
    /* { VERS_NETSCAPE, "VNET" }, */
    /* { VERS_MICROSOFT, "VMIC" }, 32768u */
    { VERS_XML, "VXML" }, /* 65536u */
        /* HTML5 */
    { HT50, "HT50" }, /* 131072u */
    { XH50, "XH50" }, /* 262144u */
    { 0,     0  }
};

/* Process the above table, adding a bit name,
   or '----' when not present   */
static char *add_vers_string( tmbstr buf, unsigned int vers )
{
    PV2S pv2s = v2s;
    int len = (int)strlen(buf);
    while (pv2s->val) {
        if (vers & pv2s->bit) {
            if (len) {
                strcat(buf,"|");
                len++;
            }
            strcat(buf,pv2s->val);
            len += (int)strlen(pv2s->val);
            vers &= ~(pv2s->bit);
            if (!vers)
                break;
        } else {
            if (len) {
                strcat(buf,"|");
                len++;
            }
            strcat(buf,"----");
            len += 4;

        }
        pv2s++;
    }
    if (vers) { /* Should not have any here! */
        if (len)
            strcat(buf,"|");
        sprintf(EndBuf(buf),"%u",vers);
    }
    return buf;

}

/* Issue #377 - Show first Before: list, and then on any change
   Note the VERS_PROPRIETARY are exclude since they always remain */
void TY_(ConstrainVersion)(TidyDocImpl* doc, unsigned int vers)
{
    static char vcur[256];
    static Bool dnfirst = no;
    unsigned int curr = doc->lexer->versions; /* get current */
    doc->lexer->versions &= (vers | VERS_PROPRIETARY);
    if (curr != doc->lexer->versions) { /* only if different */
        if (!dnfirst) {
            dnfirst = yes;
            vcur[0] = 0;
            curr &= ~(VERS_PROPRIETARY);
            add_vers_string( vcur, curr );
            SPRTF("Before: %s\n", vcur);
        }
        vcur[0] = 0;
        curr = doc->lexer->versions;
        curr &= ~(VERS_PROPRIETARY);
        add_vers_string( vcur, curr );
        SPRTF("After : %s\n", vcur);
    }
}
#else /* !#if defined(ENABLE_DEBUG_LOG) */
/* everything is allowed in proprietary version of HTML */
/* this is handled here rather than in the tag/attr dicts */
void TY_(ConstrainVersion)(TidyDocImpl* doc, unsigned int vers)
{
    doc->lexer->versions &= (vers | VERS_PROPRIETARY);
}
#endif /* #if defined(ENABLE_DEBUG_LOG) y/n */

Bool TY_(IsWhite)(unsigned int c)
{
    unsigned int map = MAP(c);

    return (map & white)!=0;
}

Bool TY_(IsNewline)(unsigned int c)
{
    unsigned int map = MAP(c);
    return (map & newline)!=0;
}

Bool TY_(IsDigit)(unsigned int c)
{
    unsigned int map;

    map = MAP(c);

    return (map & digit)!=0;
}

static Bool IsDigitHex(unsigned int c)
{
    unsigned int map;

    map = MAP(c);

    return (map & digithex)!=0;
}

Bool TY_(IsLetter)(unsigned int c)
{
    unsigned int map;

    map = MAP(c);

    return (map & letter)!=0;
}

Bool TY_(IsHTMLSpace)(unsigned int c)
{
    return c == 0x020 || c == 0x009 || c == 0x00a || c == 0x00c || c == 0x00d;
}

Bool TY_(IsNamechar)(unsigned int c)
{
    unsigned int map = MAP(c);
    return (map & namechar)!=0;
}

Bool TY_(IsXMLLetter)(unsigned int c)
{
    return ((c >= 0x41 && c <= 0x5a) ||
        (c >= 0x61 && c <= 0x7a) ||
        (c >= 0xc0 && c <= 0xd6) ||
        (c >= 0xd8 && c <= 0xf6) ||
        (c >= 0xf8 && c <= 0xff) ||
        (c >= 0x100 && c <= 0x131) ||
        (c >= 0x134 && c <= 0x13e) ||
        (c >= 0x141 && c <= 0x148) ||
        (c >= 0x14a && c <= 0x17e) ||
        (c >= 0x180 && c <= 0x1c3) ||
        (c >= 0x1cd && c <= 0x1f0) ||
        (c >= 0x1f4 && c <= 0x1f5) ||
        (c >= 0x1fa && c <= 0x217) ||
        (c >= 0x250 && c <= 0x2a8) ||
        (c >= 0x2bb && c <= 0x2c1) ||
        c == 0x386 ||
        (c >= 0x388 && c <= 0x38a) ||
        c == 0x38c ||
        (c >= 0x38e && c <= 0x3a1) ||
        (c >= 0x3a3 && c <= 0x3ce) ||
        (c >= 0x3d0 && c <= 0x3d6) ||
        c == 0x3da ||
        c == 0x3dc ||
        c == 0x3de ||
        c == 0x3e0 ||
        (c >= 0x3e2 && c <= 0x3f3) ||
        (c >= 0x401 && c <= 0x40c) ||
        (c >= 0x40e && c <= 0x44f) ||
        (c >= 0x451 && c <= 0x45c) ||
        (c >= 0x45e && c <= 0x481) ||
        (c >= 0x490 && c <= 0x4c4) ||
        (c >= 0x4c7 && c <= 0x4c8) ||
        (c >= 0x4cb && c <= 0x4cc) ||
        (c >= 0x4d0 && c <= 0x4eb) ||
        (c >= 0x4ee && c <= 0x4f5) ||
        (c >= 0x4f8 && c <= 0x4f9) ||
        (c >= 0x531 && c <= 0x556) ||
        c == 0x559 ||
        (c >= 0x561 && c <= 0x586) ||
        (c >= 0x5d0 && c <= 0x5ea) ||
        (c >= 0x5f0 && c <= 0x5f2) ||
        (c >= 0x621 && c <= 0x63a) ||
        (c >= 0x641 && c <= 0x64a) ||
        (c >= 0x671 && c <= 0x6b7) ||
        (c >= 0x6ba && c <= 0x6be) ||
        (c >= 0x6c0 && c <= 0x6ce) ||
        (c >= 0x6d0 && c <= 0x6d3) ||
        c == 0x6d5 ||
        (c >= 0x6e5 && c <= 0x6e6) ||
        (c >= 0x905 && c <= 0x939) ||
        c == 0x93d ||
        (c >= 0x958 && c <= 0x961) ||
        (c >= 0x985 && c <= 0x98c) ||
        (c >= 0x98f && c <= 0x990) ||
        (c >= 0x993 && c <= 0x9a8) ||
        (c >= 0x9aa && c <= 0x9b0) ||
        c == 0x9b2 ||
        (c >= 0x9b6 && c <= 0x9b9) ||
        (c >= 0x9dc && c <= 0x9dd) ||
        (c >= 0x9df && c <= 0x9e1) ||
        (c >= 0x9f0 && c <= 0x9f1) ||
        (c >= 0xa05 && c <= 0xa0a) ||
        (c >= 0xa0f && c <= 0xa10) ||
        (c >= 0xa13 && c <= 0xa28) ||
        (c >= 0xa2a && c <= 0xa30) ||
        (c >= 0xa32 && c <= 0xa33) ||
        (c >= 0xa35 && c <= 0xa36) ||
        (c >= 0xa38 && c <= 0xa39) ||
        (c >= 0xa59 && c <= 0xa5c) ||
        c == 0xa5e ||
        (c >= 0xa72 && c <= 0xa74) ||
        (c >= 0xa85 && c <= 0xa8b) ||
        c == 0xa8d ||
        (c >= 0xa8f && c <= 0xa91) ||
        (c >= 0xa93 && c <= 0xaa8) ||
        (c >= 0xaaa && c <= 0xab0) ||
        (c >= 0xab2 && c <= 0xab3) ||
        (c >= 0xab5 && c <= 0xab9) ||
        c == 0xabd ||
        c == 0xae0 ||
        (c >= 0xb05 && c <= 0xb0c) ||
        (c >= 0xb0f && c <= 0xb10) ||
        (c >= 0xb13 && c <= 0xb28) ||
        (c >= 0xb2a && c <= 0xb30) ||
        (c >= 0xb32 && c <= 0xb33) ||
        (c >= 0xb36 && c <= 0xb39) ||
        c == 0xb3d ||
        (c >= 0xb5c && c <= 0xb5d) ||
        (c >= 0xb5f && c <= 0xb61) ||
        (c >= 0xb85 && c <= 0xb8a) ||
        (c >= 0xb8e && c <= 0xb90) ||
        (c >= 0xb92 && c <= 0xb95) ||
        (c >= 0xb99 && c <= 0xb9a) ||
        c == 0xb9c ||
        (c >= 0xb9e && c <= 0xb9f) ||
        (c >= 0xba3 && c <= 0xba4) ||
        (c >= 0xba8 && c <= 0xbaa) ||
        (c >= 0xbae && c <= 0xbb5) ||
        (c >= 0xbb7 && c <= 0xbb9) ||
        (c >= 0xc05 && c <= 0xc0c) ||
        (c >= 0xc0e && c <= 0xc10) ||
        (c >= 0xc12 && c <= 0xc28) ||
        (c >= 0xc2a && c <= 0xc33) ||
        (c >= 0xc35 && c <= 0xc39) ||
        (c >= 0xc60 && c <= 0xc61) ||
        (c >= 0xc85 && c <= 0xc8c) ||
        (c >= 0xc8e && c <= 0xc90) ||
        (c >= 0xc92 && c <= 0xca8) ||
        (c >= 0xcaa && c <= 0xcb3) ||
        (c >= 0xcb5 && c <= 0xcb9) ||
        c == 0xcde ||
        (c >= 0xce0 && c <= 0xce1) ||
        (c >= 0xd05 && c <= 0xd0c) ||
        (c >= 0xd0e && c <= 0xd10) ||
        (c >= 0xd12 && c <= 0xd28) ||
        (c >= 0xd2a && c <= 0xd39) ||
        (c >= 0xd60 && c <= 0xd61) ||
        (c >= 0xe01 && c <= 0xe2e) ||
        c == 0xe30 ||
        (c >= 0xe32 && c <= 0xe33) ||
        (c >= 0xe40 && c <= 0xe45) ||
        (c >= 0xe81 && c <= 0xe82) ||
        c == 0xe84 ||
        (c >= 0xe87 && c <= 0xe88) ||
        c == 0xe8a ||
        c == 0xe8d ||
        (c >= 0xe94 && c <= 0xe97) ||
        (c >= 0xe99 && c <= 0xe9f) ||
        (c >= 0xea1 && c <= 0xea3) ||
        c == 0xea5 ||
        c == 0xea7 ||
        (c >= 0xeaa && c <= 0xeab) ||
        (c >= 0xead && c <= 0xeae) ||
        c == 0xeb0 ||
        (c >= 0xeb2 && c <= 0xeb3) ||
        c == 0xebd ||
        (c >= 0xec0 && c <= 0xec4) ||
        (c >= 0xf40 && c <= 0xf47) ||
        (c >= 0xf49 && c <= 0xf69) ||
        (c >= 0x10a0 && c <= 0x10c5) ||
        (c >= 0x10d0 && c <= 0x10f6) ||
        c == 0x1100 ||
        (c >= 0x1102 && c <= 0x1103) ||
        (c >= 0x1105 && c <= 0x1107) ||
        c == 0x1109 ||
        (c >= 0x110b && c <= 0x110c) ||
        (c >= 0x110e && c <= 0x1112) ||
        c == 0x113c ||
        c == 0x113e ||
        c == 0x1140 ||
        c == 0x114c ||
        c == 0x114e ||
        c == 0x1150 ||
        (c >= 0x1154 && c <= 0x1155) ||
        c == 0x1159 ||
        (c >= 0x115f && c <= 0x1161) ||
        c == 0x1163 ||
        c == 0x1165 ||
        c == 0x1167 ||
        c == 0x1169 ||
        (c >= 0x116d && c <= 0x116e) ||
        (c >= 0x1172 && c <= 0x1173) ||
        c == 0x1175 ||
        c == 0x119e ||
        c == 0x11a8 ||
        c == 0x11ab ||
        (c >= 0x11ae && c <= 0x11af) ||
        (c >= 0x11b7 && c <= 0x11b8) ||
        c == 0x11ba ||
        (c >= 0x11bc && c <= 0x11c2) ||
        c == 0x11eb ||
        c == 0x11f0 ||
        c == 0x11f9 ||
        (c >= 0x1e00 && c <= 0x1e9b) ||
        (c >= 0x1ea0 && c <= 0x1ef9) ||
        (c >= 0x1f00 && c <= 0x1f15) ||
        (c >= 0x1f18 && c <= 0x1f1d) ||
        (c >= 0x1f20 && c <= 0x1f45) ||
        (c >= 0x1f48 && c <= 0x1f4d) ||
        (c >= 0x1f50 && c <= 0x1f57) ||
        c == 0x1f59 ||
        c == 0x1f5b ||
        c == 0x1f5d ||
        (c >= 0x1f5f && c <= 0x1f7d) ||
        (c >= 0x1f80 && c <= 0x1fb4) ||
        (c >= 0x1fb6 && c <= 0x1fbc) ||
        c == 0x1fbe ||
        (c >= 0x1fc2 && c <= 0x1fc4) ||
        (c >= 0x1fc6 && c <= 0x1fcc) ||
        (c >= 0x1fd0 && c <= 0x1fd3) ||
        (c >= 0x1fd6 && c <= 0x1fdb) ||
        (c >= 0x1fe0 && c <= 0x1fec) ||
        (c >= 0x1ff2 && c <= 0x1ff4) ||
        (c >= 0x1ff6 && c <= 0x1ffc) ||
        c == 0x2126 ||
        (c >= 0x212a && c <= 0x212b) ||
        c == 0x212e ||
        (c >= 0x2180 && c <= 0x2182) ||
        (c >= 0x3041 && c <= 0x3094) ||
        (c >= 0x30a1 && c <= 0x30fa) ||
        (c >= 0x3105 && c <= 0x312c) ||
        (c >= 0xac00 && c <= 0xd7a3) ||
        (c >= 0x4e00 && c <= 0x9fa5) ||
        c == 0x3007 ||
        (c >= 0x3021 && c <= 0x3029) ||
        (c >= 0x4e00 && c <= 0x9fa5) ||
        c == 0x3007 ||
        (c >= 0x3021 && c <= 0x3029));
}

Bool TY_(IsXMLNamechar)(unsigned int c)
{
    return (TY_(IsXMLLetter)(c) ||
        c == '.' || c == '_' ||
        c == ':' || c == '-' ||
        (c >= 0x300 && c <= 0x345) ||
        (c >= 0x360 && c <= 0x361) ||
        (c >= 0x483 && c <= 0x486) ||
        (c >= 0x591 && c <= 0x5a1) ||
        (c >= 0x5a3 && c <= 0x5b9) ||
        (c >= 0x5bb && c <= 0x5bd) ||
        c == 0x5bf ||
        (c >= 0x5c1 && c <= 0x5c2) ||
        c == 0x5c4 ||
        (c >= 0x64b && c <= 0x652) ||
        c == 0x670 ||
        (c >= 0x6d6 && c <= 0x6dc) ||
        (c >= 0x6dd && c <= 0x6df) ||
        (c >= 0x6e0 && c <= 0x6e4) ||
        (c >= 0x6e7 && c <= 0x6e8) ||
        (c >= 0x6ea && c <= 0x6ed) ||
        (c >= 0x901 && c <= 0x903) ||
        c == 0x93c ||
        (c >= 0x93e && c <= 0x94c) ||
        c == 0x94d ||
        (c >= 0x951 && c <= 0x954) ||
        (c >= 0x962 && c <= 0x963) ||
        (c >= 0x981 && c <= 0x983) ||
        c == 0x9bc ||
        c == 0x9be ||
        c == 0x9bf ||
        (c >= 0x9c0 && c <= 0x9c4) ||
        (c >= 0x9c7 && c <= 0x9c8) ||
        (c >= 0x9cb && c <= 0x9cd) ||
        c == 0x9d7 ||
        (c >= 0x9e2 && c <= 0x9e3) ||
        c == 0xa02 ||
        c == 0xa3c ||
        c == 0xa3e ||
        c == 0xa3f ||
        (c >= 0xa40 && c <= 0xa42) ||
        (c >= 0xa47 && c <= 0xa48) ||
        (c >= 0xa4b && c <= 0xa4d) ||
        (c >= 0xa70 && c <= 0xa71) ||
        (c >= 0xa81 && c <= 0xa83) ||
        c == 0xabc ||
        (c >= 0xabe && c <= 0xac5) ||
        (c >= 0xac7 && c <= 0xac9) ||
        (c >= 0xacb && c <= 0xacd) ||
        (c >= 0xb01 && c <= 0xb03) ||
        c == 0xb3c ||
        (c >= 0xb3e && c <= 0xb43) ||
        (c >= 0xb47 && c <= 0xb48) ||
        (c >= 0xb4b && c <= 0xb4d) ||
        (c >= 0xb56 && c <= 0xb57) ||
        (c >= 0xb82 && c <= 0xb83) ||
        (c >= 0xbbe && c <= 0xbc2) ||
        (c >= 0xbc6 && c <= 0xbc8) ||
        (c >= 0xbca && c <= 0xbcd) ||
        c == 0xbd7 ||
        (c >= 0xc01 && c <= 0xc03) ||
        (c >= 0xc3e && c <= 0xc44) ||
        (c >= 0xc46 && c <= 0xc48) ||
        (c >= 0xc4a && c <= 0xc4d) ||
        (c >= 0xc55 && c <= 0xc56) ||
        (c >= 0xc82 && c <= 0xc83) ||
        (c >= 0xcbe && c <= 0xcc4) ||
        (c >= 0xcc6 && c <= 0xcc8) ||
        (c >= 0xcca && c <= 0xccd) ||
        (c >= 0xcd5 && c <= 0xcd6) ||
        (c >= 0xd02 && c <= 0xd03) ||
        (c >= 0xd3e && c <= 0xd43) ||
        (c >= 0xd46 && c <= 0xd48) ||
        (c >= 0xd4a && c <= 0xd4d) ||
        c == 0xd57 ||
        c == 0xe31 ||
        (c >= 0xe34 && c <= 0xe3a) ||
        (c >= 0xe47 && c <= 0xe4e) ||
        c == 0xeb1 ||
        (c >= 0xeb4 && c <= 0xeb9) ||
        (c >= 0xebb && c <= 0xebc) ||
        (c >= 0xec8 && c <= 0xecd) ||
        (c >= 0xf18 && c <= 0xf19) ||
        c == 0xf35 ||
        c == 0xf37 ||
        c == 0xf39 ||
        c == 0xf3e ||
        c == 0xf3f ||
        (c >= 0xf71 && c <= 0xf84) ||
        (c >= 0xf86 && c <= 0xf8b) ||
        (c >= 0xf90 && c <= 0xf95) ||
        c == 0xf97 ||
        (c >= 0xf99 && c <= 0xfad) ||
        (c >= 0xfb1 && c <= 0xfb7) ||
        c == 0xfb9 ||
        (c >= 0x20d0 && c <= 0x20dc) ||
        c == 0x20e1 ||
        (c >= 0x302a && c <= 0x302f) ||
        c == 0x3099 ||
        c == 0x309a ||
        (c >= 0x30 && c <= 0x39) ||
        (c >= 0x660 && c <= 0x669) ||
        (c >= 0x6f0 && c <= 0x6f9) ||
        (c >= 0x966 && c <= 0x96f) ||
        (c >= 0x9e6 && c <= 0x9ef) ||
        (c >= 0xa66 && c <= 0xa6f) ||
        (c >= 0xae6 && c <= 0xaef) ||
        (c >= 0xb66 && c <= 0xb6f) ||
        (c >= 0xbe7 && c <= 0xbef) ||
        (c >= 0xc66 && c <= 0xc6f) ||
        (c >= 0xce6 && c <= 0xcef) ||
        (c >= 0xd66 && c <= 0xd6f) ||
        (c >= 0xe50 && c <= 0xe59) ||
        (c >= 0xed0 && c <= 0xed9) ||
        (c >= 0xf20 && c <= 0xf29) ||
        c == 0xb7 ||
        c == 0x2d0 ||
        c == 0x2d1 ||
        c == 0x387 ||
        c == 0x640 ||
        c == 0xe46 ||
        c == 0xec6 ||
        c == 0x3005 ||
        (c >= 0x3031 && c <= 0x3035) ||
        (c >= 0x309d && c <= 0x309e) ||
        (c >= 0x30fc && c <= 0x30fe));
}

Bool TY_(IsUpper)(unsigned int c)
{
    unsigned int map = MAP(c);

    return (map & uppercase)!=0;
}

unsigned int TY_(ToLower)(unsigned int c)
{
    unsigned int map = MAP(c);

    if (map & uppercase)
        c += 'a' - 'A';

    return c;
}

unsigned int TY_(ToUpper)(unsigned int c)
{
    unsigned int map = MAP(c);

    if (map & lowercase)
        c += (unsigned int) ('A' - 'a' );

    return c;
}

/*
 return last character in string
 this is useful when trailing quotemark
 is missing on an attribute
*/
static tmbchar LastChar( tmbstr str )
{
    if ( str && *str )
    {
        int n = TY_(tmbstrlen)(str);
        return str[n-1];
    }
    return 0;
}

/*
   node->type is one of these:

    #define TextNode    1
    #define StartTag    2
    #define EndTag      3
    #define StartEndTag 4
*/

Lexer* TY_(NewLexer)( TidyDocImpl* doc )
{
    Lexer* lexer = (Lexer*) TidyDocAlloc( doc, sizeof(Lexer) );

    if ( lexer != NULL )
    {
        TidyClearMemory( lexer, sizeof(Lexer) );

        lexer->allocator = doc->allocator;
        lexer->lines = 1;
        lexer->columns = 1;
        lexer->state = LEX_CONTENT;

        lexer->versions = (VERS_ALL|VERS_PROPRIETARY);
        lexer->doctype = VERS_UNKNOWN;
        lexer->root = &doc->root;
    }
    return lexer;
}

static Bool EndOfInput( TidyDocImpl* doc )
{
    assert( doc->docIn != NULL );
    return ( !doc->docIn->pushed && TY_(IsEOF)(doc->docIn) );
}

void TY_(FreeLexer)( TidyDocImpl* doc )
{
    Lexer *lexer = doc->lexer;
    if ( lexer )
    {
        TY_(FreeStyles)( doc );

        /* See GetToken() */
        if ( lexer->pushed || lexer->itoken )
        {
            if (lexer->pushed)
                TY_(FreeNode)( doc, lexer->itoken );
            TY_(FreeNode)( doc, lexer->token );
        }

        while ( lexer->istacksize > 0 )
            TY_(PopInline)( doc, NULL );

        TidyDocFree( doc, lexer->istack );
        TidyDocFree( doc, lexer->lexbuf );
        TidyDocFree( doc, lexer );
        doc->lexer = NULL;
    }
}

/* Lexer uses bigger memory chunks than pprint as
** it must hold the entire input document. not just
** the last line or three.
*/
static void AddByte( Lexer *lexer, tmbchar ch )
{
    if ( lexer->lexsize + 2 >= lexer->lexlength )
    {
        tmbstr buf = NULL;
        unsigned int allocAmt = lexer->lexlength;
        while ( lexer->lexsize + 2 >= allocAmt )
        {
            if ( allocAmt == 0 )
                allocAmt = 8192;
            else
                allocAmt *= 2;
        }
        buf = (tmbstr) TidyRealloc( lexer->allocator, lexer->lexbuf, allocAmt );
        if ( buf )
        {
          TidyClearMemory( buf + lexer->lexlength, 
                           allocAmt - lexer->lexlength );
          lexer->lexbuf = buf;
          lexer->lexlength = allocAmt;
        }
    }

    lexer->lexbuf[ lexer->lexsize++ ] = ch;
    lexer->lexbuf[ lexer->lexsize ]   = '\0';  /* debug */
}

static void ChangeChar( Lexer *lexer, tmbchar c )
{
    if ( lexer->lexsize > 0 )
    {
        lexer->lexbuf[ lexer->lexsize-1 ] = c;
    }
}

/* store character c as UTF-8 encoded byte stream */
void TY_(AddCharToLexer)( Lexer *lexer, unsigned int c )
{
    int i, err, count = 0;
    tmbchar buf[10] = {0};
    
    err = TY_(EncodeCharToUTF8Bytes)( c, buf, NULL, &count );
    if (err)
    {
        /* replacement character 0xFFFD encoded as UTF-8 */
        buf[0] = (byte) 0xEF;
        buf[1] = (byte) 0xBF;
        buf[2] = (byte) 0xBD;
        count = 3;
    }
    
    for ( i = 0; i < count; ++i )
        AddByte( lexer, buf[i] );
}

static void AddStringToLexer( Lexer *lexer, ctmbstr str )
{
    unsigned int c;

    /*  Many (all?) compilers will sign-extend signed chars (the default) when
    **  converting them to unsigned integer values.  We must cast our char to
    **  unsigned char before assigning it to prevent this from happening.
    */
    while( 0 != (c = (unsigned char) *str++ ))
        TY_(AddCharToLexer)( lexer, c );
}


static void SetLexerLocus( TidyDocImpl* doc, Lexer *lexer )
{
    lexer->lines = doc->docIn->curline;
    lexer->columns = doc->docIn->curcol;
}

/*
    Issue #483
    Have detected the first of a surrogate pair...
    Try to find, decode the second...
    Already have '&' start...
*/

typedef enum {
    SP_ok,
    SP_failed,
    SP_error
}SPStatus;

static SPStatus GetSurrogatePair(TidyDocImpl* doc, Bool isXml, unsigned int *pch)
{
    Lexer* lexer = doc->lexer;
    unsigned int bufSize = 32;
    unsigned int c, ch, offset = 0;
    tmbstr buf = 0;
    SPStatus status = SP_error;  /* assume failed */
    int type = 0;   /* assume numeric */
    unsigned int fch = *pch;
    int i;  /* has to be signed due to for i >= 0 */
    if (!lexer)
        return status;
    buf = (tmbstr)TidyRealloc(lexer->allocator, buf, bufSize);
    if (!buf)
        return status;
    while ((c = TY_(ReadChar)(doc->docIn)) != EndOfStream )
    {
        if (c == ';')
        {
            break;  /* reached end of entity */
        }
        if ((offset + 2) > bufSize)
        {
            bufSize *= 2;
            buf = (tmbstr)TidyRealloc(lexer->allocator, buf, bufSize);
            if (!buf)
            {
                break;
            }
        }
        buf[offset++] = c;  /* add char to buffer */
        if (offset == 1)
        {
            if (c != '#')   /* is a numeric entity */
                break;
        }
        else if (offset == 2 && ((c == 'x') || (!isXml && c == 'X')))
        {
            type = 1;   /* set hex digits */
        }
        else
        {
            if (type)   /* if hex digits */
            {
                if (!IsDigitHex(c))
                    break;
            }
            else    /* if numeric */
            {
                if (!TY_(IsDigit)(c))
                    break;
            }
        }
    }

    if (c == ';')
    {
        buf[offset] = 0;
        if (type)
            sscanf(buf + 2, "%x", &ch);
        else
            sscanf(buf + 1, "%d", &ch);

        if (TY_(IsHighSurrogate)(ch))
        {
            ch = TY_(CombineSurrogatePair)(ch, fch);
            if (TY_(IsValidCombinedChar)(ch))
            {
                *pch = ch;  /* return combined pair value */
                status = SP_ok; /* full success - pair used */
            }
            else
            {
                status = SP_failed; /* is one of the 32 out-of-range pairs */
                *pch = 0xFFFD;  /* return substitute character */
                TY_(ReportSurrogateError)(doc, BAD_SURROGATE_PAIR, fch, ch); /* SP WARNING: -  */
            }
        }
    }

    if (status == SP_error)
    {
        /* Error condition - can only put back all the chars */
        if (c == ';') /* if last, not added to buffer */
            TY_(UngetChar)(c, doc->docIn);
        if (buf && offset)
        {
            /* correct the order for unget - last first */
            for (i = offset - 1; i >= 0; i--)
            {
                c = buf[i];
                TY_(UngetChar)(c, doc->docIn);
            }
        }
    }

    if (buf)
        TidyFree(lexer->allocator, buf);

    return status;
}

/*
  No longer attempts to insert missing ';' for unknown
  enitities unless one was present already, since this
  gives unexpected results.

  For example:   <a href="something.htm?foo&bar&fred">
  was tidied to: <a href="something.htm?foo&amp;bar;&amp;fred;">
  rather than:   <a href="something.htm?foo&amp;bar&amp;fred">

  My thanks for Maurice Buxton for spotting this.

  Also Randy Waki pointed out the following case for the
  04 Aug 00 version (bug #433012):
  
  For example:   <a href="something.htm?id=1&lang=en">
  was tidied to: <a href="something.htm?id=1&lang;=en">
  rather than:   <a href="something.htm?id=1&amp;lang=en">
  
  where "lang" is a known entity (#9001), but browsers would
  misinterpret "&lang;" because it had a value > 256.
  
  So the case of an apparently known entity with a value > 256 and
  missing a semicolon is handled specially.
  
  "ParseEntity" is also a bit of a misnomer - it handles entities and
  numeric character references. Invalid NCR's are now reported.
*/
static void ParseEntity( TidyDocImpl* doc, GetTokenMode mode )
{
    typedef enum
    {
        ENT_default,
        ENT_numdec,
        ENT_numhex
    } ENTState;
    
    typedef Bool (*ENTfn)(unsigned int);
    const ENTfn entFn[] = {
        TY_(IsNamechar),
        TY_(IsDigit),
        IsDigitHex
    };
    unsigned int start;
    ENTState entState = ENT_default;
    unsigned int charRead = 0;
    Bool semicolon = no, found = no;
    Bool isXml = cfgBool( doc, TidyXmlTags );
    Bool preserveEntities = cfgBool( doc, TidyPreserveEntities );
    unsigned int c, ch, startcol, entver = 0;
    Lexer* lexer = doc->lexer;

    start = lexer->lexsize - 1;  /* to start at "&" */
    startcol = doc->docIn->curcol - 1;

    while ( (c = TY_(ReadChar)(doc->docIn)) != EndOfStream )
    {
        if ( c == ';' )
        {
            semicolon = yes;
            break;
        }
        ++charRead;

        if (charRead == 1 && c == '#')
        {
            if ( !cfgBool(doc, TidyNCR) ||
                 cfg(doc, TidyInCharEncoding) == BIG5 ||
                 cfg(doc, TidyInCharEncoding) == SHIFTJIS )
            {
                TY_(UngetChar)('#', doc->docIn);
                return;
            }

            TY_(AddCharToLexer)( lexer, c );
            entState = ENT_numdec;
            continue;
        }
        else if (charRead == 2 && entState == ENT_numdec
                 && (c == 'x' || (!isXml && c == 'X')) )
        {
            TY_(AddCharToLexer)( lexer, c );
            entState = ENT_numhex;
            continue;
        }

        if ( entFn[entState](c) )
        {
            TY_(AddCharToLexer)( lexer, c );
            continue;
        }

        /* otherwise put it back */
        TY_(UngetChar)( c, doc->docIn );
        break;
    }

    /* make sure entity is NULL terminated */
    lexer->lexbuf[lexer->lexsize] = '\0';

    /* Should contrain version to XML/XHTML if &apos; 
    ** is encountered.  But this is not possible with
    ** Tidy's content model bit mask.
    */
    if ( TY_(tmbstrcmp)(lexer->lexbuf+start, "&apos") == 0
         && !cfgBool(doc, TidyXmlOut)
         && !lexer->isvoyager
         && !cfgBool(doc, TidyXhtmlOut)
         && !(TY_(HTMLVersion)(doc) == HT50) ) /* Issue #239 - no warning if in HTML5++ mode */
        TY_(ReportEntityError)( doc, APOS_UNDEFINED, lexer->lexbuf+start, 39 );

    if (( mode == OtherNamespace ) && ( c == ';' ))
    {
        /* #130 MathML attr and entity fix! */
        found = yes;
        ch = 255;
        entver = XH50|HT50;
        preserveEntities = yes;
    }
    else
    {
        /* Lookup entity code and version
        */
        found = TY_(EntityInfo)( lexer->lexbuf+start, isXml, &ch, &entver );
    }

    /* Issue #483 - Deal with 'surrogate pairs' */
    /* TODO: Maybe warning/error, like found a leading surrogate
       but no following surrogate! Maybe should avoid outputting
       invalid utf-8 for this entity - maybe substitute?  */
    if (!preserveEntities && found && TY_(IsLowSurrogate)(ch))
    {
        unsigned int c1;
        if ((c1 = TY_(ReadChar)(doc->docIn)) == '&')
        {
            SPStatus status;
            /* Have a following entity, 
               so there is a chance of having a valid surrogate pair */
            c1 = ch;    /* keep first value, in case of error */
            status = GetSurrogatePair(doc, isXml, &ch);
            if (status == SP_error)
            {
                TY_(ReportSurrogateError)(doc, BAD_SURROGATE_TAIL, c1, 0); /* SP WARNING: - using substitute character */
                TY_(UngetChar)('&', doc->docIn);  /* otherwise put it back */
            }
        }
        else
        {
            /* put this non-entity lead char back */
            TY_(UngetChar)(c1, doc->docIn);
            /* Have leading surrogate pair, with no tail */
            TY_(ReportSurrogateError)(doc, BAD_SURROGATE_TAIL, ch, 0); /* SP WARNING: - using substitute character */
            ch = 0xFFFD;
        }
    } 
    else if (!preserveEntities && found && TY_(IsHighSurrogate)(ch))
    {
        /* Have trailing surrogate pair, with no lead */
        TY_(ReportSurrogateError)(doc, BAD_SURROGATE_LEAD, ch, 0); /* SP WARNING: - using substitute character */
        ch = 0xFFFD;
    }

    /* deal with unrecognized or invalid entities */
    /* #433012 - fix by Randy Waki 17 Feb 01 */
    /* report invalid NCR's - Terry Teague 01 Sep 01 */
    if ( !found || (ch >= 128 && ch <= 159) || (ch >= 256 && c != ';') )
    {
        /* set error position just before offending character */
        SetLexerLocus( doc, lexer );
        lexer->columns = startcol;

        if (lexer->lexsize > start + 1)
        {
            if (ch >= 128 && ch <= 159)
            {
                /* invalid numeric character reference */
                
                unsigned int c1 = 0;
                int replaceMode = DISCARDED_CHAR;
            
                /* Always assume Win1252 in this circumstance. */
                c1 = TY_(DecodeWin1252)( ch );

                if ( c1 )
                    replaceMode = REPLACED_CHAR;
                
                if ( c != ';' )  /* issue warning if not terminated by ';' */
                    TY_(ReportEntityError)( doc, MISSING_SEMICOLON_NCR,
                                            lexer->lexbuf+start, c );
 
                TY_(ReportEncodingError)(doc, INVALID_NCR, ch, replaceMode == DISCARDED_CHAR);
                
                if ( c1 )
                {
                    /* make the replacement */
                    lexer->lexsize = start;
                    TY_(AddCharToLexer)( lexer, c1 );
                    semicolon = no;
                }
                else
                {
                    /* discard */
                    lexer->lexsize = start;
                    semicolon = no;
               }
               
            }
            else
                TY_(ReportEntityError)( doc, UNKNOWN_ENTITY,
                                        lexer->lexbuf+start, ch );

            if (semicolon)
                TY_(AddCharToLexer)( lexer, ';' );
        }
        else
        {
            /*\ 
             *  Issue #207 - A naked & is allowed in HTML5, as an unambiguous ampersand!
            \*/
            if (TY_(HTMLVersion)(doc) != HT50) 
            {
                TY_(ReportEntityError)( doc, UNESCAPED_AMPERSAND,
                                    lexer->lexbuf+start, ch );
            }
        }
    }
    else
    {
        if ( c != ';' )    /* issue warning if not terminated by ';' */
        {
            /* set error position just before offending chararcter */
            SetLexerLocus( doc, lexer );
            lexer->columns = startcol;
            TY_(ReportEntityError)( doc, MISSING_SEMICOLON, lexer->lexbuf+start, c );
        }

        if (preserveEntities)
            TY_(AddCharToLexer)( lexer, ';' );
        else
        {
            lexer->lexsize = start;
            if ( ch == 160 && (mode == Preformatted) )
                ch = ' ';
            TY_(AddCharToLexer)( lexer, ch );

            if ( ch == '&' && !cfgBool(doc, TidyQuoteAmpersand) )
                AddStringToLexer( lexer, "amp;" );
        }

        /* Detect extended vs. basic entities */
        TY_(ConstrainVersion)( doc, entver );
    }
}

static tmbchar ParseTagName( TidyDocImpl* doc )
{
    Lexer *lexer = doc->lexer;
    unsigned int c = lexer->lexbuf[ lexer->txtstart ];
    Bool xml = cfgBool(doc, TidyXmlTags);

    /* fold case of first character in buffer */
    if (!xml && TY_(IsUpper)(c))
        lexer->lexbuf[lexer->txtstart] = (tmbchar) TY_(ToLower)(c);

    while ((c = TY_(ReadChar)(doc->docIn)) != EndOfStream)
    {
        if ((!xml && !TY_(IsNamechar)(c)) ||
            (xml && !TY_(IsXMLNamechar)(c)))
            break;

        /* fold case of subsequent characters */
        if (!xml && TY_(IsUpper)(c))
             c = TY_(ToLower)(c);

        TY_(AddCharToLexer)(lexer, c);
    }

    lexer->txtend = lexer->lexsize;
    return (tmbchar) c;
}

/*
  Used for elements and text nodes
  element name is NULL for text nodes
  start and end are offsets into lexbuf
  which contains the textual content of
  all elements in the parse tree.

  parent and content allow traversal
  of the parse tree in any direction.
  attributes are represented as a linked
  list of AttVal nodes which hold the
  strings for attribute/value pairs.
*/


Node *TY_(NewNode)(TidyAllocator* allocator, Lexer *lexer)
{
    Node* node = (Node*) TidyAlloc( allocator, sizeof(Node) );
    TidyClearMemory( node, sizeof(Node) );
    if ( lexer )
    {
        node->line = lexer->lines;
        node->column = lexer->columns;
    }
    node->type = TextNode;
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_ALLOCATION)
    SPRTF("Allocated node %p\n", node );
#endif
    return node;
}

/* used to clone heading nodes when split by an <HR> */
Node *TY_(CloneNode)( TidyDocImpl* doc, Node *element )
{
    Lexer* lexer = doc->lexer;
    Node *node = TY_(NewNode)( lexer->allocator, lexer );

    node->start = lexer->lexsize;
    node->end   = lexer->lexsize;

    if ( element )
    {
        node->parent     = element->parent;
        node->type       = element->type;
        node->closed     = element->closed;
        node->implicit   = element->implicit;
        node->tag        = element->tag;
        node->element    = TY_(tmbstrdup)( doc->allocator, element->element );
        node->attributes = TY_(DupAttrs)( doc, element->attributes );
    }
    return node;
}

/* free node's attributes */
void TY_(FreeAttrs)( TidyDocImpl* doc, Node *node )
{
    while ( node->attributes )
    {
        AttVal *av = node->attributes;

        if ( av->attribute )
        {
            if ( (attrIsID(av) || attrIsNAME(av)) &&
                 TY_(IsAnchorElement)(doc, node) )
            {
                TY_(RemoveAnchorByNode)( doc, av->value, node );
            }
        }

        node->attributes = av->next;
        TY_(FreeAttribute)( doc, av );
    }
}

/* doesn't repair attribute list linkage */
void TY_(FreeAttribute)( TidyDocImpl* doc, AttVal *av )
{
    TY_(FreeNode)( doc, av->asp );
    TY_(FreeNode)( doc, av->php );
    TidyDocFree( doc, av->attribute );
    TidyDocFree( doc, av->value );
    TidyDocFree( doc, av );
}

/* detach attribute from node
*/
void TY_(DetachAttribute)( Node *node, AttVal *attr )
{
    AttVal *av, *prev = NULL;

    for ( av = node->attributes; av; av = av->next )
    {
        if ( av == attr )
        {
            if ( prev )
                prev->next = attr->next;
            else
                node->attributes = attr->next;
            break;
        }
        prev = av;
    }
}

/* detach attribute from node then free it
*/
void TY_(RemoveAttribute)( TidyDocImpl* doc, Node *node, AttVal *attr )
{
    TY_(DetachAttribute)( node, attr );
    TY_(FreeAttribute)( doc, attr );
}

/*
  Free document nodes by iterating through peers and recursing
  through children. Set next to NULL before calling TY_(FreeNode)()
  to avoid freeing peer nodes. Doesn't patch up prev/next links.
 */
void TY_(FreeNode)( TidyDocImpl* doc, Node *node )
{
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_ALLOCATION)
    /* avoid showing free of root node! */
    if (node) {
        if (RootNode != node->type) {
            SPRTF("Free node %p\n", node);
        }
        else {
            SPRTF("Root node %p\n", node);
        }
    }
#endif
    /* this is no good ;=((
    if (node && doc && doc->lexer) {
        if (node == doc->lexer->token) {
            doc->lexer->token = NULL; // TY_(NewNode)( doc->lexer->allocator, doc->lexer );
        }
    }
      ----------------- */
    while ( node )
    {
        Node* next = node->next;

        TY_(FreeAttrs)( doc, node );
        TY_(FreeNode)( doc, node->content );
        TidyDocFree( doc, node->element );
        if (RootNode != node->type)
            TidyDocFree( doc, node );
        else
            node->content = NULL;

        node = next;
    }
}

Node* TY_(TextToken)( Lexer *lexer )
{
    Node *node = TY_(NewNode)( lexer->allocator, lexer );
    node->start = lexer->txtstart;
    node->end = lexer->txtend;
    return node;
}

/* used for creating preformatted text from Word2000 */
Node *TY_(NewLineNode)( Lexer *lexer )
{
    Node *node = TY_(NewNode)( lexer->allocator, lexer );
    node->start = lexer->lexsize;
    TY_(AddCharToLexer)( lexer, (unsigned int)'\n' );
    node->end = lexer->lexsize;
    return node;
}

/* used for adding a &nbsp; for Word2000 */
Node* TY_(NewLiteralTextNode)( Lexer *lexer, ctmbstr txt )
{
    Node *node = TY_(NewNode)( lexer->allocator, lexer );
    node->start = lexer->lexsize;
    AddStringToLexer( lexer, txt );
    node->end = lexer->lexsize;
    return node;
}

static Node* TagToken( TidyDocImpl* doc, NodeType type )
{
    Lexer* lexer = doc->lexer;
    Node* node = TY_(NewNode)( lexer->allocator, lexer );
    node->type = type;
    node->element = TY_(tmbstrndup)( doc->allocator,
                                     lexer->lexbuf + lexer->txtstart,
                                     lexer->txtend - lexer->txtstart );
    node->start = lexer->txtstart;
    node->end = lexer->txtstart;

    if ( type == StartTag || type == StartEndTag || type == EndTag )
        TY_(FindTag)(doc, node);

    return node;
}

static Node* NewToken(TidyDocImpl* doc, NodeType type)
{
    Lexer* lexer = doc->lexer;
    Node* node = TY_(NewNode)(lexer->allocator, lexer);
    node->type = type;
    node->start = lexer->txtstart;
    node->end = lexer->txtend;
    return node;
}

#define CommentToken(doc) NewToken(doc, CommentTag)
#define DocTypeToken(doc) NewToken(doc, DocTypeTag)
#define PIToken(doc)      NewToken(doc, ProcInsTag)
#define AspToken(doc)     NewToken(doc, AspTag)
#define JsteToken(doc)    NewToken(doc, JsteTag)
#define PhpToken(doc)     NewToken(doc, PhpTag)
#define XmlDeclToken(doc) NewToken(doc, XmlDecl)
#define SectionToken(doc) NewToken(doc, SectionTag)
#define CDATAToken(doc)   NewToken(doc, CDATATag)

void TY_(AddStringLiteral)( Lexer* lexer, ctmbstr str )
{
    byte c;
    while(0 != (c = *str++) ) {
        /*\
         *  Issue #286
         *  Previously this used TY_(AddCharToLexer)( lexer, c );
         *  which uses err = TY_(EncodeCharToUTF8Bytes)( c, buf, NULL, &count );
         *  But this is transferring already 'translated' data from an
         *  internal location to the lexer, so should use AddByte()
        \*/
        AddByte( lexer, c );
    }
}

/*
void AddStringLiteralLen( Lexer* lexer, ctmbstr str, int len )
{
    byte c;
    int ix;

    for ( ix=0; ix < len && (c = *str++); ++ix )
        TY_(AddCharToLexer)(lexer, c);
}
*/

/* find doctype element */
Node *TY_(FindDocType)( TidyDocImpl* doc )
{
    Node* node;
    for ( node = (doc ? doc->root.content : NULL);
          node && node->type != DocTypeTag; 
          node = node->next )
        /**/;
    return node;
}

/* find parent container element */
Node* TY_(FindContainer)( Node* node )
{
    for ( node = (node ? node->parent : NULL);
          node && TY_(nodeHasCM)(node, CM_INLINE);
          node = node->parent )
        /**/;

    return node;
}


/* find html element */
Node *TY_(FindHTML)( TidyDocImpl* doc )
{
    Node *node;
    for ( node = (doc ? doc->root.content : NULL);
          node && !nodeIsHTML(node); 
          node = node->next )
        /**/;

    return node;
}

/* find XML Declaration */
Node *TY_(FindXmlDecl)(TidyDocImpl* doc)
{
    Node *node;
    for ( node = (doc ? doc->root.content : NULL);
          node && !(node->type == XmlDecl);
          node = node->next )
        /**/;

    return node;
}


Node *TY_(FindHEAD)( TidyDocImpl* doc )
{
    Node *node = TY_(FindHTML)( doc );

    if ( node )
    {
        for ( node = node->content;
              node && !nodeIsHEAD(node); 
              node = node->next )
            /**/;
    }

    return node;
}

Node *TY_(FindTITLE)(TidyDocImpl* doc)
{
    Node *node = TY_(FindHEAD)(doc);

    if (node)
        for (node = node->content;
             node && !nodeIsTITLE(node);
             node = node->next) {}

    return node;
}

Node *TY_(FindBody)( TidyDocImpl* doc )
{
    Node *node = ( doc ? doc->root.content : NULL );

    while ( node && !nodeIsHTML(node) )
        node = node->next;

    if (node == NULL)
        return NULL;

    node = node->content;
    while ( node && !nodeIsBODY(node) && !nodeIsFRAMESET(node) )
        node = node->next;

    if ( node && nodeIsFRAMESET(node) )
    {
        node = node->content;
        while ( node && !nodeIsNOFRAMES(node) )
            node = node->next;

        if ( node )
        {
            node = node->content;
            while ( node && !nodeIsBODY(node) )
                node = node->next;
        }
    }

    return node;
}

/* add meta element for Tidy */
Bool TY_(AddGenerator)( TidyDocImpl* doc )
{
    AttVal *attval;
    Node *node;
    Node *head = TY_(FindHEAD)( doc );
    tmbchar buf[256];
    
    if (head)
    {
#ifdef PLATFORM_NAME
        TY_(tmbsnprintf)(buf, sizeof(buf), "HTML Tidy for HTML5 for "PLATFORM_NAME" version %s",
                         tidyLibraryVersion());
#else
        TY_(tmbsnprintf)(buf, sizeof(buf), "HTML Tidy for HTML5 version %s", tidyLibraryVersion());
#endif

        for ( node = head->content; node; node = node->next )
        {
            if ( nodeIsMETA(node) )
            {
                attval = TY_(AttrGetById)(node, TidyAttr_NAME);

                if (AttrValueIs(attval, "generator"))
                {
                    attval = TY_(AttrGetById)(node, TidyAttr_CONTENT);

                    if (AttrHasValue(attval) &&
                        TY_(tmbstrncasecmp)(attval->value, "HTML Tidy", 9) == 0)
                    {
                        /* update the existing content to reflect the */
                        /* actual version of Tidy currently being used */
                        
                        TidyDocFree(doc, attval->value);
                        attval->value = TY_(tmbstrdup)(doc->allocator, buf);
                        return no;
                    }
                }
            }
        }

        if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
        {
            node = TY_(InferredTag)(doc, TidyTag_META);
            TY_(AddAttribute)( doc, node, "name", "generator" );
            TY_(AddAttribute)( doc, node, "content", buf );
            TY_(InsertNodeAtStart)( head, node );
            return yes;
        }
    }

    return no;
}

/*\ examine <!DOCTYPE ...> to identify version 
 *  Issue #167 and #169
 *   If HTML5
 *        <!DOCTYPE html>
 *       <!DOCTYPE html SYSTEM "about:legacy-compat">
 *   else others
\*/
static unsigned int FindGivenVersion( TidyDocImpl* doc, Node* doctype )
{
    AttVal * fpi = TY_(GetAttrByName)(doctype, "PUBLIC");
    unsigned int vers;

    if (!fpi || !fpi->value) 
    {
        if (doctype->element && (TY_(tmbstrcmp)(doctype->element,"html") == 0))
        {
            return VERS_HTML5;  /* TODO: do we need to check MORE? */
        }
        /* TODO: Consider warning, error message */
        return VERS_UNKNOWN;
    }
    vers = GetVersFromFPI(fpi->value);

    if (VERS_XHTML & vers)
    {
        TY_(SetOptionBool)(doc, TidyXmlOut, yes);
        TY_(SetOptionBool)(doc, TidyXhtmlOut, yes);
        doc->lexer->isvoyager = yes;
    }

    /* todo: add a warning if case does not match? */
    TidyDocFree(doc, fpi->value);
    fpi->value = TY_(tmbstrdup)(doc->allocator, GetFPIFromVers(vers));

    return vers;
}

/* return guessed version */
unsigned int TY_(ApparentVersion)( TidyDocImpl* doc )
{
    if ((doc->lexer->doctype == XH11 ||
         doc->lexer->doctype == XB10) &&
        (doc->lexer->versions & doc->lexer->doctype))
        return doc->lexer->doctype;
    else
        return TY_(HTMLVersion)(doc);
}

ctmbstr TY_(HTMLVersionNameFromCode)( unsigned int vers, Bool ARG_UNUSED(isXhtml) )
{
    ctmbstr name = GetNameFromVers(vers);
    return name;
}

unsigned int TY_(HTMLVersionNumberFromCode)( unsigned int vers )
{
    unsigned int i;

    for (i = 0; W3C_Doctypes[i].name; ++i)
        if (W3C_Doctypes[i].vers == vers)
            return W3C_Doctypes[i].vers_out;

    return VERS_UNKNOWN;
}

Bool TY_(WarnMissingSIInEmittedDocType)( TidyDocImpl* doc )
{
    Bool isXhtml = doc->lexer->isvoyager;
    Node* doctype;
    
    /* Do not warn in XHTML mode */
    if ( isXhtml )
        return no;

    /* Do not warn if emitted doctype is proprietary */
    if ( TY_(HTMLVersionNameFromCode)(doc->lexer->versionEmitted, isXhtml ) == NULL )
        return no;

    /* Do not warn if no SI is possible */
    if ( GetSIFromVers(doc->lexer->versionEmitted) == NULL )
        return no;

    if ( (doctype = TY_(FindDocType)( doc )) != NULL
         && TY_(GetAttrByName)(doctype, "SYSTEM") == NULL )
        return yes;

    return no;
}


/* Put DOCTYPE declaration between the
** <?xml version "1.0" ... ?> declaration, if any,
** and the <html> tag.  Should also work for any comments, 
** etc. that may precede the <html> tag.
*/

static Node* NewDocTypeNode( TidyDocImpl* doc )
{
    Node* doctype = NULL;
    Node* html = TY_(FindHTML)( doc );

    if ( !html )
        return NULL;

    doctype = TY_(NewNode)( doc->allocator, NULL );
    doctype->type = DocTypeTag;
    TY_(InsertNodeBeforeElement)(html, doctype);
    return doctype;
}

Bool TY_(SetXHTMLDocType)( TidyDocImpl* doc )
{
    Lexer *lexer = doc->lexer;
    Node *doctype = TY_(FindDocType)( doc );
    TidyDoctypeModes dtmode = (TidyDoctypeModes)cfg(doc, TidyDoctypeMode);
    ctmbstr pub = "PUBLIC";
    ctmbstr sys = "SYSTEM";

    lexer->versionEmitted = TY_(ApparentVersion)( doc );

    if (dtmode == TidyDoctypeOmit)
    {
        if (doctype)
            TY_(DiscardElement)(doc, doctype);
        return yes;
    }

    if (dtmode == TidyDoctypeUser && !cfgStr(doc, TidyDoctype))
        return no;

    if (!doctype)
    {
        doctype = NewDocTypeNode(doc);
        doctype->element = TY_(tmbstrdup)(doc->allocator, "html");
    }
    else
    {
        doctype->element = TY_(tmbstrtolower)(doctype->element);
    }

    switch(dtmode)
    {
    case TidyDoctypeHtml5:
        /* HTML5 */
        TY_(RepairAttrValue)(doc, doctype, pub, NULL);
        TY_(RepairAttrValue)(doc, doctype, sys, NULL);
        lexer->versionEmitted = XH50;
        break;
    case TidyDoctypeStrict:
        /* XHTML 1.0 Strict */
        TY_(RepairAttrValue)(doc, doctype, pub, GetFPIFromVers(X10S));
        TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(X10S));
        lexer->versionEmitted = X10S;
        break;
    case TidyDoctypeLoose:
        /* XHTML 1.0 Transitional */
        TY_(RepairAttrValue)(doc, doctype, pub, GetFPIFromVers(X10T));
        TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(X10T));
        lexer->versionEmitted = X10T;
        break;
    case TidyDoctypeUser:
        /* user defined document type declaration */
        TY_(RepairAttrValue)(doc, doctype, pub, cfgStr(doc, TidyDoctype));
        TY_(RepairAttrValue)(doc, doctype, sys, "");
        break;
    case TidyDoctypeAuto:
        if (lexer->doctype == VERS_UNKNOWN || lexer->doctype == VERS_HTML5) {
          lexer->versionEmitted = XH50;
          return yes;
        }
        else if (lexer->versions & XH11 && lexer->doctype == XH11)
        {
            if (!TY_(GetAttrByName)(doctype, sys))
                TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(XH11));
            lexer->versionEmitted = XH11;
            return yes;
        }
        else if (lexer->versions & XH11 && !(lexer->versions & VERS_HTML40))
        {
            TY_(RepairAttrValue)(doc, doctype, pub, GetFPIFromVers(XH11));
            TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(XH11));
            lexer->versionEmitted = XH11;
        }
        else if (lexer->versions & XB10 && lexer->doctype == XB10)
        {
            if (!TY_(GetAttrByName)(doctype, sys))
                TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(XB10));
            lexer->versionEmitted = XB10;
            return yes;
        }
        else if (lexer->versions & VERS_HTML40_STRICT)
        {
            TY_(RepairAttrValue)(doc, doctype, pub, GetFPIFromVers(X10S));
            TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(X10S));
            lexer->versionEmitted = X10S;
        }
        else if (lexer->versions & VERS_FRAMESET)
        {
            TY_(RepairAttrValue)(doc, doctype, pub, GetFPIFromVers(X10F));
            TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(X10F));
            lexer->versionEmitted = X10F;
        }
        else if (lexer->versions & VERS_LOOSE)
        {
            TY_(RepairAttrValue)(doc, doctype, pub, GetFPIFromVers(X10T));
            TY_(RepairAttrValue)(doc, doctype, sys, GetSIFromVers(X10T));
            lexer->versionEmitted = X10T;
        }
        else if (lexer->versions & VERS_HTML5)
        {
            /*\
             *  Issue #273 - If still a html5/xhtml5 bit
             *  existing, that is the 'ConstrainVersion' has
             *  not eliminated all HTML5, then nothing to do here.
             *  Certainly do **not** delete the DocType node!
             *  see: http://www.w3.org/QA/Tips/Doctype
            \*/
        }
        else
        {
            if (doctype)
                TY_(DiscardElement)(doc, doctype);
            return no;
        }
        break;
    case TidyDoctypeOmit:
        assert(0);
        break;
    }

    return no;
}

/* fixup doctype if missing */
Bool TY_(FixDocType)( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    Node* doctype = TY_(FindDocType)( doc );
    unsigned int dtmode = cfg( doc, TidyDoctypeMode );
    unsigned int guessed = VERS_UNKNOWN;
    Bool hadSI = no;

    /* Issue #167 - found doctype, and doctype is default VERS_HTML5, set VERS_HTML5 and return yes */
    if (doctype && (dtmode == TidyDoctypeAuto) &&
        (lexer->doctype == VERS_HTML5) )
    {
        /* The version emitted cannot be a composite value! */
        lexer->versionEmitted = HT50;
        return yes;
    }
    if (dtmode == TidyDoctypeAuto &&
        lexer->versions & lexer->doctype &&
        !(VERS_XHTML & lexer->doctype && !lexer->isvoyager)
        && TY_(FindDocType)(doc))
    {
        lexer->versionEmitted = lexer->doctype;
        return yes;
    }

    if (dtmode == TidyDoctypeOmit)
    {
        if (doctype)
            TY_(DiscardElement)( doc, doctype );
        lexer->versionEmitted = TY_(ApparentVersion)( doc );
        return yes;
    }

    if (cfgBool(doc, TidyXmlOut))
        return yes;

    if (doctype)
        hadSI = TY_(GetAttrByName)(doctype, "SYSTEM") != NULL;

    if ((dtmode == TidyDoctypeStrict ||
         dtmode == TidyDoctypeLoose) && doctype)
    {
        TY_(DiscardElement)(doc, doctype);
        doctype = NULL;
    }

    switch (dtmode)
    {
    case TidyDoctypeHtml5:
        guessed = HT50;
        break;
    case TidyDoctypeStrict:
        guessed = H41S;
        break;
    case TidyDoctypeLoose:
        guessed = H41T;
        break;
    case TidyDoctypeAuto:
        guessed = TY_(HTMLVersion)(doc);
        break;
    }

    lexer->versionEmitted = guessed;
    if (guessed == VERS_UNKNOWN)
        return no;

    if (doctype)
    {
        doctype->element = TY_(tmbstrtolower)(doctype->element);
    }
    else
    {
        doctype = NewDocTypeNode(doc);
        doctype->element = TY_(tmbstrdup)(doc->allocator, "html");
    }

    TY_(RepairAttrValue)(doc, doctype, "PUBLIC", GetFPIFromVers(guessed));

    if (hadSI)
        TY_(RepairAttrValue)(doc, doctype, "SYSTEM", GetSIFromVers(guessed));

    return yes;
}

/* ensure XML document starts with <?xml version="1.0"?> */
/* add encoding attribute if not using ASCII or UTF-8 output */
Bool TY_(FixXmlDecl)( TidyDocImpl* doc )
{
    Node* xml;
    AttVal *version, *encoding;
    Lexer*lexer = doc->lexer;
    Node* root = &doc->root;

    if ( root->content && root->content->type == XmlDecl )
    {
        xml = root->content;
    }
    else
    {
        xml = TY_(NewNode)(lexer->allocator, lexer);
        xml->type = XmlDecl;
        if ( root->content )
            TY_(InsertNodeBeforeElement)(root->content, xml);
        else
            root->content = xml;
    }

    version = TY_(GetAttrByName)(xml, "version");
    encoding = TY_(GetAttrByName)(xml, "encoding");

    /*
      We need to insert a check if declared encoding 
      and output encoding mismatch and fix the XML
      declaration accordingly!!!
    */

    if ( encoding == NULL && cfg(doc, TidyOutCharEncoding) != UTF8 )
    {
        ctmbstr enc = TY_(GetEncodingNameFromTidyId)(cfg(doc, TidyOutCharEncoding));
        if ( enc )
            TY_(AddAttribute)( doc, xml, "encoding", enc );
    }

    if ( version == NULL )
        TY_(AddAttribute)( doc, xml, "version", "1.0" );
    return yes;
}

Node* TY_(InferredTag)(TidyDocImpl* doc, TidyTagId id)
{
    Lexer *lexer = doc->lexer;
    Node *node = TY_(NewNode)( lexer->allocator, lexer );
    const Dict* dict = TY_(LookupTagDef)(id);

    assert( dict != NULL );

    node->type = StartTag;
    node->implicit = yes;
    node->element = TY_(tmbstrdup)(doc->allocator, dict->name);
    node->tag = dict;
    node->start = lexer->txtstart;
    node->end = lexer->txtend;

    return node;
}

static Bool ExpectsContent(Node *node)
{
    if (node->type != StartTag)
        return no;

    /* unknown element? */
    if (node->tag == NULL)
        return yes;

    if (node->tag->model & CM_EMPTY)
        return no;

    return yes;
}

/*
  create a text node for the contents of
  a CDATA element like style or script
  which ends with </foo> for some foo.
*/

typedef enum
{
    CDATA_INTERMEDIATE,
    CDATA_STARTTAG,
    CDATA_ENDTAG
} CDATAState;

static Node *GetCDATA( TidyDocImpl* doc, Node *container )
{
    Lexer* lexer = doc->lexer;
    unsigned int start = 0;
    int nested = 0;
    CDATAState state = CDATA_INTERMEDIATE;
    unsigned int i;
    Bool isEmpty = yes;
    Bool matches = no;
    unsigned int c;
    Bool hasSrc = (TY_(AttrGetById)(container, TidyAttr_SRC) != NULL) ? yes : no;
    /*\ Issue #65 (1642186) and #280 - is script or style, and the option on
     *  If yes, then avoid incrementing nested...
    \*/
    Bool nonested = ((nodeIsSCRIPT(container) || (nodeIsSTYLE(container))) && 
        cfgBool(doc, TidySkipNested)) ? yes : no;

    SetLexerLocus( doc, lexer );
    lexer->waswhite = no;
    lexer->txtstart = lexer->txtend = lexer->lexsize;

    /* seen start tag, look for matching end tag */
    while ((c = TY_(ReadChar)(doc->docIn)) != EndOfStream)
    {
        TY_(AddCharToLexer)(lexer, c);
        lexer->txtend = lexer->lexsize;

        if (state == CDATA_INTERMEDIATE)
        {
            if (c != '<')
            {
                if (isEmpty && !TY_(IsWhite)(c))
                    isEmpty = no;
                continue;
            }

            c = TY_(ReadChar)(doc->docIn);

            if (TY_(IsLetter)(c))
            {
                /* <head><script src=foo><meta name=foo content=bar>*/
                if (hasSrc && isEmpty && nodeIsSCRIPT(container))
                {
                    /* ReportError(doc, container, NULL, MISSING_ENDTAG_FOR); */
                    lexer->lexsize = lexer->txtstart;
                    TY_(UngetChar)(c, doc->docIn);
                    TY_(UngetChar)('<', doc->docIn);
                    return NULL;
                }
                TY_(AddCharToLexer)(lexer, c);
                start = lexer->lexsize - 1;
                state = CDATA_STARTTAG;
            }
            else if (c == '/')
            {
                TY_(AddCharToLexer)(lexer, c);

                c = TY_(ReadChar)(doc->docIn);
                
                if (!TY_(IsLetter)(c))
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }
                TY_(UngetChar)(c, doc->docIn);

                start = lexer->lexsize;
                state = CDATA_ENDTAG;
            }
            else if (c == '\\')
            {
                /* recognize document.write("<script><\/script>") */
                TY_(AddCharToLexer)(lexer, c);

                c = TY_(ReadChar)(doc->docIn);

                if (c != '/')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }

                TY_(AddCharToLexer)(lexer, c);

                if (nonested) {
                    /*\ 
                     *  Issue #65 - for version 5.1.14.EXP2
                     *  If the nonested option is ON then the <script> 
                     *  tag did not bump nested, so no need to treat this as 
                     *  an end tag just to decrease nested, just continue!
                    \*/
                    continue;
                }

                c = TY_(ReadChar)(doc->docIn);
                
                if (!TY_(IsLetter)(c))
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }
                TY_(UngetChar)(c, doc->docIn);

                start = lexer->lexsize;
                state = CDATA_ENDTAG;
            }
            else
            {
                TY_(UngetChar)(c, doc->docIn);
            }
        }
        /* '<' + Letter found */
        else if (state == CDATA_STARTTAG)
        {
            if (TY_(IsLetter)(c))
                continue;

            matches = TY_(tmbstrncasecmp)(container->element, lexer->lexbuf + start,
                                          TY_(tmbstrlen)(container->element)) == 0;
            if (matches && !nonested)
                nested++;

            state = CDATA_INTERMEDIATE;
        }
        /* '<' + '/' + Letter found */
        else if (state == CDATA_ENDTAG)
        {
            if (TY_(IsLetter)(c))
                continue;

            matches = TY_(tmbstrncasecmp)(container->element, lexer->lexbuf + start,
                                          TY_(tmbstrlen)(container->element)) == 0;

            if (isEmpty && !matches)
            {
                /* ReportError(doc, container, NULL, MISSING_ENDTAG_FOR); */

                for (i = lexer->lexsize - 1; i >= start; --i)
                    TY_(UngetChar)((unsigned int)lexer->lexbuf[i], doc->docIn);
                TY_(UngetChar)('/', doc->docIn);
                TY_(UngetChar)('<', doc->docIn);
                break;
            }

            if (matches && nested-- <= 0)
            {
                for (i = lexer->lexsize - 1; i >= start; --i)
                    TY_(UngetChar)((unsigned int)lexer->lexbuf[i], doc->docIn);
                TY_(UngetChar)('/', doc->docIn);
                TY_(UngetChar)('<', doc->docIn);
                lexer->lexsize -= (lexer->lexsize - start) + 2;
                break;
            }
            else if (lexer->lexbuf[start - 2] != '\\')
            {
                /* if the end tag is not already escaped using backslash */
                SetLexerLocus( doc, lexer );
                lexer->columns -= 3;

                /*\ if javascript insert backslash before / 
                 *  Issue #348 - Add option, escape-scripts, to skip
                \*/
                if ((TY_(IsJavaScript)(container)) && cfgBool(doc, TidyEscapeScripts) &&
                    !TY_(IsHTML5Mode)(doc) )    /* Is #700 - This only applies to legacy html4 mode */
                {
                    /* Issue #281 - only warn if adding the escape! */
                    TY_(Report)(doc, NULL, NULL, BAD_CDATA_CONTENT);

                    for (i = lexer->lexsize; i > start-1; --i)
                        lexer->lexbuf[i] = lexer->lexbuf[i-1];

                    lexer->lexbuf[start-1] = '\\';
                    lexer->lexsize++;
                }
            }
            state = CDATA_INTERMEDIATE;
        }
    }
    if (isEmpty)
        lexer->lexsize = lexer->txtstart = lexer->txtend;
    else
        lexer->txtend = lexer->lexsize;

    if (c == EndOfStream)
        TY_(Report)(doc, container, NULL, MISSING_ENDTAG_FOR );

    return TY_(TextToken)(lexer);
}

void TY_(UngetToken)( TidyDocImpl* doc )
{
    doc->lexer->pushed = yes;
}

#if defined(ENABLE_DEBUG_LOG)
#  define CondReturnTextNode(doc, skip) \
            if (lexer->txtend > lexer->txtstart) { \
                Node *_node = TY_(TextToken)(lexer); \
                lexer->token = _node; \
                GTDBG(doc,"text_node",_node); \
                return _node; \
            }

#else
#  define CondReturnTextNode(doc, skip) \
            if (lexer->txtend > lexer->txtstart) \
            { \
                lexer->token = TY_(TextToken)(lexer); \
                return lexer->token; \
            }
#endif

/*
  modes for GetToken()

  MixedContent   -- for elements which don't accept PCDATA
  Preformatted   -- white space preserved as is
  IgnoreMarkup   -- for CDATA elements such as script, style
*/
static Node* GetTokenFromStream( TidyDocImpl* doc, GetTokenMode mode );

Node* TY_(GetToken)( TidyDocImpl* doc, GetTokenMode mode )
{
    Node *node;
    Lexer* lexer = doc->lexer;

    if (lexer->pushed || lexer->itoken)
    {
        /* Deal with previously returned duplicate inline token */
        if (lexer->itoken)
        {
            /* itoken rejected */
            if (lexer->pushed)
            {
                lexer->pushed = no;
                node = lexer->itoken;
                GTDBG(doc,"lex-itoken", node);
                return node;
            }
            /* itoken has been accepted */
            lexer->itoken = NULL;
        }
            
        /* duplicate inlines in preference to pushed text nodes when appropriate */
        lexer->pushed = no;
        if (lexer->token->type != TextNode
            || !(lexer->insert || lexer->inode)) {
            node = lexer->token;
            GTDBG(doc,"lex-token", node);
            return node;
        }
        lexer->itoken = TY_(InsertedToken)( doc );
        node = lexer->itoken;
        GTDBG(doc,"lex-inserted", node);
        return node;
    }

    assert( !(lexer->pushed || lexer->itoken) );

    /* at start of block elements, unclosed inline
       elements are inserted into the token stream 
       Issue #341 - Can NOT insert a token if NO istacksize  
     */
    if ((lexer->insert || lexer->inode) && lexer->istacksize)
    {
        /*\ Issue #92: could fix by the following, but instead chose not to stack these 2
         *  if ( !(lexer->insert && (nodeIsINS(lexer->insert) || nodeIsDEL(lexer->insert))) ) {
        \*/
        lexer->token = TY_(InsertedToken)( doc );
        node = lexer->token;
        GTDBG(doc,"lex-inserted2", node);
        return node;
    }

    if (mode == CdataContent)
    {
        assert( lexer->parent != NULL );
        node = GetCDATA(doc, lexer->parent);
        GTDBG(doc,"lex-cdata", node);
        return node;
    }

    return GetTokenFromStream( doc, mode );
}

#if defined(ENABLE_DEBUG_LOG)
static void check_me(char *name)
{
    SPRTF("Have node %s\n", name);
}
#endif

static Node* GetTokenFromStream( TidyDocImpl* doc, GetTokenMode mode )
{
    Lexer* lexer = doc->lexer;
    unsigned int c, lexdump, badcomment = 0;
    Bool isempty = no;
    AttVal *attributes = NULL;
    Node *node;
    Bool fixComments;
    
    switch ( cfgAutoBool(doc, TidyFixComments) )
    {
        case TidyYesState:
            fixComments = yes;
            break;

        case TidyNoState:
            fixComments = no;
            break;

        default:
            fixComments = (TY_(HTMLVersion)(doc) & HT50) == 0;
            break;
    }

    /* Lexer->token must be set on return. Nullify it for safety. */
    lexer->token = NULL;

    SetLexerLocus( doc, lexer );
    lexer->waswhite = no;

    lexer->txtstart = lexer->txtend = lexer->lexsize;

    while ((c = TY_(ReadChar)(doc->docIn)) != EndOfStream)
    {
        if (lexer->insertspace)
        {
            TY_(AddCharToLexer)(lexer, ' ');
            lexer->waswhite = yes;
            lexer->insertspace = no;
        }

        if (c == 160 && (mode == Preformatted))
            c = ' ';

        TY_(AddCharToLexer)(lexer, c);

        switch (lexer->state)
        {
            case LEX_CONTENT:  /* element content */

                /*
                 Discard white space if appropriate. Its cheaper
                 to do this here rather than in parser methods
                 for elements that don't have mixed content.
                */
                if (TY_(IsWhite)(c) && (mode == IgnoreWhitespace) 
                      && lexer->lexsize == lexer->txtstart + 1)
                {
                    --(lexer->lexsize);
                    lexer->waswhite = no;
                    SetLexerLocus( doc, lexer );
                    continue;
                }

                if (c == '<')
                {
                    lexer->state = LEX_GT;
                    continue;
                }

                if (TY_(IsWhite)(c))
                {
                    /* was previous character white? */
                    if (lexer->waswhite)
                    {
                        if (mode != Preformatted && mode != IgnoreMarkup)
                        {
                            --(lexer->lexsize);
                            SetLexerLocus( doc, lexer );
                        }
                    }
                    else /* prev character wasn't white */
                    {
                        lexer->waswhite = yes;

                        if (mode != Preformatted && mode != IgnoreMarkup && c != ' ')
                            ChangeChar(lexer, ' ');
                    }

                    continue;
                }
                else if (c == '&' && mode != IgnoreMarkup)
                    ParseEntity( doc, mode );

                /* this is needed to avoid trimming trailing whitespace */
                if (mode == IgnoreWhitespace)
                    mode = MixedContent;

                lexer->waswhite = no;
                continue;

            case LEX_GT:  /* < */

                /* check for endtag */
                if (c == '/')
                {
                    if ((c = TY_(ReadChar)(doc->docIn)) == EndOfStream)
                    {
                        TY_(UngetChar)(c, doc->docIn);
                        continue;
                    }

                    TY_(AddCharToLexer)(lexer, c);

                    if (TY_(IsLetter)(c) || (cfgBool(doc, TidyXmlTags) && TY_(IsXMLNamechar)(c)))
                    {
                        lexer->lexsize -= 3;
                        lexer->txtend = lexer->lexsize;
                        TY_(UngetChar)(c, doc->docIn);
                        lexer->state = LEX_ENDTAG;
                        lexer->lexbuf[lexer->lexsize] = '\0';  /* debug */
                        doc->docIn->curcol -= 2;

                        /* if some text before the </ return it now */
                        if (lexer->txtend > lexer->txtstart)
                        {
                            /* trim space character before end tag */
                            if (mode == IgnoreWhitespace && lexer->lexbuf[lexer->lexsize - 1] == ' ')
                            {
                                lexer->lexsize -= 1;
                                lexer->txtend = lexer->lexsize;
                            }
                            lexer->token = TY_(TextToken)(lexer);
                            node = lexer->token;
                            GTDBG(doc,"text", node);
                            return node;
                        }

                        continue;       /* no text so keep going */
                    }

                    /* otherwise treat as CDATA */
                    lexer->waswhite = no;
                    lexer->state = LEX_CONTENT;
                    continue;
                }

                if (mode == IgnoreMarkup)
                {
                    /* otherwise treat as CDATA */
                    lexer->waswhite = no;
                    lexer->state = LEX_CONTENT;
                    continue;
                }

                /*
                   look out for comments, doctype or marked sections
                   this isn't quite right, but its getting there ...
                */
                if (c == '!')
                {
                    c = TY_(ReadChar)(doc->docIn);

                    if (c == '-')
                    {
                        c = TY_(ReadChar)(doc->docIn);

                        if (c == '-')
                        {
                            lexer->state = LEX_COMMENT;  /* comment */
                            lexer->lexsize -= 2;
                            lexer->txtend = lexer->lexsize;

                            CondReturnTextNode(doc, 4)

                            lexer->txtstart = lexer->lexsize;
                            continue;
                        }

                        /*
                           We only print this message if there's a missing
                           starting hyphen; this comment will be dropped.
                         */
                        TY_(Report)(doc, NULL, NULL, MALFORMED_COMMENT_DROPPING );
                    }
                    else if (c == 'd' || c == 'D')
                    {
                        /* todo: check for complete "<!DOCTYPE" not just <!D */

                        unsigned int skip = 0;

                        lexer->state = LEX_DOCTYPE; /* doctype */
                        lexer->lexsize -= 2;
                        lexer->txtend = lexer->lexsize;
                        mode = IgnoreWhitespace;

                        /* skip until white space or '>' */

                        for (;;)
                        {
                            c = TY_(ReadChar)(doc->docIn);
                            ++skip;

                            if (c == EndOfStream || c == '>')
                            {
                                TY_(UngetChar)(c, doc->docIn);
                                break;
                            }


                            if (!TY_(IsWhite)(c))
                                continue;

                            /* and skip to end of whitespace */

                            for (;;)
                            {
                                c = TY_(ReadChar)(doc->docIn);
                                ++skip;

                                if (c == EndOfStream || c == '>')
                                {
                                    TY_(UngetChar)(c, doc->docIn);
                                    break;
                                }


                                if (TY_(IsWhite)(c))
                                    continue;

                                TY_(UngetChar)(c, doc->docIn);
                                break;
                            }

                            break;
                        }

                        CondReturnTextNode(doc, (skip + 3))

                        lexer->txtstart = lexer->lexsize;
                        continue;
                    }
                    else if (c == '[')
                    {
                        /* Word 2000 embeds <![if ...]> ... <![endif]> sequences */
                        lexer->lexsize -= 2;
                        lexer->state = LEX_SECTION;
                        lexer->txtend = lexer->lexsize;

                        CondReturnTextNode(doc, 2)

                        lexer->txtstart = lexer->lexsize;
                        continue;
                    }



                    /* else swallow characters up to and including next '>' */
                    while ((c = TY_(ReadChar)(doc->docIn)) != '>')
                    {
                        if (c == EndOfStream)
                        {
                            TY_(UngetChar)(c, doc->docIn);
                            break;
                        }
                    }

                    lexer->lexsize -= 2;
                    lexer->lexbuf[lexer->lexsize] = '\0';
                    lexer->state = LEX_CONTENT;
                    continue;
                }

                /*
                   processing instructions
                */

                if (c == '?')
                {
                    lexer->lexsize -= 2;
                    lexer->state = LEX_PROCINSTR;
                    lexer->txtend = lexer->lexsize;

                    CondReturnTextNode(doc, 2)

                    lexer->txtstart = lexer->lexsize;
                    continue;
                }

                /* Microsoft ASP's e.g. <% ... server-code ... %> */
                if (c == '%')
                {
                    lexer->lexsize -= 2;
                    lexer->state = LEX_ASP;
                    lexer->txtend = lexer->lexsize;

                    CondReturnTextNode(doc, 2)

                    lexer->txtstart = lexer->lexsize;
                    continue;
                }

                /* Netscapes JSTE e.g. <# ... server-code ... #> */
                if (c == '#')
                {
                    lexer->lexsize -= 2;
                    lexer->state = LEX_JSTE;
                    lexer->txtend = lexer->lexsize;

                    CondReturnTextNode(doc, 2)

                    lexer->txtstart = lexer->lexsize;
                    continue;
                }

                /* check for start tag */
                if (TY_(IsLetter)(c) || (cfgBool(doc, TidyXmlTags) && TY_(IsXMLNamechar)(c)))
                {
                    TY_(UngetChar)(c, doc->docIn);     /* push back letter */
                    TY_(UngetChar)('<', doc->docIn);
                    lexer->lexsize -= 2;      /* discard "<" + letter */
                    lexer->txtend = lexer->lexsize;
                    lexer->state = LEX_STARTTAG;         /* ready to read tag name */

                    CondReturnTextNode(doc, 2)

                    /* lexer->txtstart = lexer->lexsize; missing here? */
                    continue;       /* no text so keep going */
                }

                /* otherwise treat as CDATA */
                /* fix for bug 762102 (486) */
                /* Issue #384 - Fix skipping parsing character, particularly '<<' */
                TY_(UngetChar)(c, doc->docIn);
                lexer->lexsize -= 1;
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                continue;

            case LEX_ENDTAG:  /* </letter */
                lexer->txtstart = lexer->lexsize - 1;
                doc->docIn->curcol += 2;
                c = ParseTagName( doc );
                lexer->token = TagToken( doc, EndTag );  /* create endtag token */
                lexer->lexsize = lexer->txtend = lexer->txtstart;

                /* skip to '>' */
                while ( c != '>' && c != EndOfStream )
                {
                    c = TY_(ReadChar)(doc->docIn);
                }

                if (c == EndOfStream)
                {
                    TY_(FreeNode)( doc, lexer->token );
                    continue;
                }

                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                node = lexer->token;
                GTDBG(doc,"endtag", node);
                return node;  /* the endtag token */

            case LEX_STARTTAG: /* first letter of tagname */
                c = TY_(ReadChar)(doc->docIn);
                ChangeChar(lexer, (tmbchar)c);
                lexer->txtstart = lexer->lexsize - 1; /* set txtstart to first letter */
                c = ParseTagName( doc );
                isempty = no;
                attributes = NULL;
                lexer->token = TagToken( doc, StartTag ); /* [i_a]2 'isempty' is always false, thanks to code 2 lines above */

                /* parse attributes, consuming closing ">" */
                if (c != '>')
                {
                    if (c == '/')
                        TY_(UngetChar)(c, doc->docIn);

                    attributes = ParseAttrs( doc, &isempty );
                }

                if (isempty)
                    lexer->token->type = StartEndTag;

                lexer->token->attributes = attributes;
                lexer->lexsize = lexer->txtend = lexer->txtstart;

                /* swallow newline following start tag */
                /* special check needed for CRLF sequence */
                /* this doesn't apply to empty elements */
                /* nor to preformatted content that needs escaping */
                /*\
                 * Issue #230: Need to KEEP this user newline character in certain 
                 * circumstances, certainly for <pre>, <script>, <style>...
                 * Any others?
                 * Issue #238: maybe **ONLY** for <pre>
                \*/
                if ( nodeIsPRE(lexer->token) )
                {
                    mode = Preformatted;
                }

                if ((mode != Preformatted && ExpectsContent(lexer->token))
                    || nodeIsBR(lexer->token) || nodeIsHR(lexer->token))
                {
                    c = TY_(ReadChar)(doc->docIn);

                    if ((c == '\n') && (mode != IgnoreWhitespace)) /* Issue #329 - Can NOT afford to lose this newline */
                        TY_(UngetChar)(c, doc->docIn);  /* Issue #329 - make sure the newline is maintained for now */
                    else if (c != '\n' && c != '\f')
                        TY_(UngetChar)(c, doc->docIn);

                    lexer->waswhite = yes;  /* to swallow leading whitespace */
                }
                else
                    lexer->waswhite = no;

                lexer->state = LEX_CONTENT;
                if (lexer->token->tag == NULL) 
                {
                    if (mode != OtherNamespace) /* [i_a]2 only issue warning if NOT 'OtherNamespace', and tag null */
                    {
                        /* Special case for HTML5 unknown tags: if it looks 
                           like an autonomous custom tag, then emit a variation
                           of the standard message. We don't want to do this
                           for older HTML, because it's not truly supported
                           by the standard, although Tidy will allow it. */
                        if ( (doc->lexer->doctype & VERS_HTML5) > 0 && TY_(elementIsAutonomousCustomFormat)( lexer->token->element ) )
                            TY_(Report)( doc, NULL, lexer->token, UNKNOWN_ELEMENT_LOOKS_CUSTOM );
                        else
                            TY_(Report)( doc, NULL, lexer->token, UNKNOWN_ELEMENT );
                    }
                }
                else if ( !cfgBool(doc, TidyXmlTags) )
                {
                    TY_(ConstrainVersion)( doc, lexer->token->tag->versions );
                    TY_(RepairDuplicateAttributes)( doc, lexer->token, no );
                } else 
                    TY_(RepairDuplicateAttributes)( doc, lexer->token, yes );
                node = lexer->token;
                GTDBG(doc,"starttag", node);
                return node;  /* return start tag */

            case LEX_COMMENT:  /* seen <!-- so look for --> */

                if (c != '-')
                    continue;

                c = TY_(ReadChar)(doc->docIn);

                /* Fix hyphens at beginning of tag */
                if ( c != '-' && fixComments && lexer->lexsize - lexer->txtstart == 1 )
                {
                    lexer->lexbuf[lexer->lexsize - 1] = '=';
                }

                TY_(AddCharToLexer)(lexer, c);

                if (c != '-')
                    continue;

            end_comment:
                c = TY_(ReadChar)(doc->docIn);

                if (c == '>')
                {
                    if (badcomment)
                    {
                        /*
                           We've got bad comments that we either fixed or
                           ignored; provide proper user feedback based on
                           doctype and whether or not we fixed them.
                         */
                        if ( (TY_(HTMLVersion)(doc) & HT50) )
                        {
                            if ( fixComments )
                                TY_(Report)(doc, NULL, NULL, MALFORMED_COMMENT );
                            /* Otherwise for HTML5, it's safe to ignore. */
                        }
                        else
                        {
                            if ( fixComments )
                                TY_(Report)(doc, NULL, NULL, MALFORMED_COMMENT );
                            else
                                TY_(Report)(doc, NULL, NULL, MALFORMED_COMMENT_WARN );
                        }
                    }

                    /* do not store closing -- in lexbuf */
                    lexer->lexsize -= 2;
                    lexer->txtend = lexer->lexsize;
                    lexer->lexbuf[lexer->lexsize] = '\0';
                    lexer->state = LEX_CONTENT;
                    lexer->waswhite = no;
                    lexer->token = CommentToken(doc);

                    /* now look for a line break */

                    c = TY_(ReadChar)(doc->docIn);

                    if (c == '\n')
                        lexer->token->linebreak = yes;
                    else
                        TY_(UngetChar)(c, doc->docIn);

                    node = lexer->token;
                    GTDBG(doc,"comment", node);
                    return node;
                }

                /* note position of first such error in the comment */
                if (!badcomment)
                {
                    SetLexerLocus( doc, lexer );
                    lexer->columns -= 3;
                }

                badcomment++;

                /* fix hyphens in the middle */
                if ( fixComments )
                    lexer->lexbuf[lexer->lexsize - 2] = '=';

                /* if '-' then look for '>' to end the comment */
                if (c == '-')
                {
                    TY_(AddCharToLexer)(lexer, c);
                    goto end_comment;
                }

                /* fix hyphens end, and continue to look for --> */
                if ( fixComments )
                    lexer->lexbuf[lexer->lexsize - 1] = '=';

                /* http://tidy.sf.net/bug/1266647 */
                TY_(AddCharToLexer)(lexer, c);

                continue; 

            case LEX_DOCTYPE:  /* seen <!d so look for '>' munging whitespace */

                /* use ParseDocTypeDecl() to tokenize doctype declaration */
                TY_(UngetChar)(c, doc->docIn);
                lexer->lexsize -= 1;
                lexer->token = ParseDocTypeDecl(doc);

                lexer->txtend = lexer->lexsize;
                lexer->lexbuf[lexer->lexsize] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;

                /* make a note of the version named by the 1st doctype */
                if (lexer->doctype == VERS_UNKNOWN && lexer->token && !cfgBool(doc, TidyXmlTags))
                {
                    lexer->doctype = FindGivenVersion(doc, lexer->token);
                    if (lexer->doctype != VERS_HTML5)
                    {
                        /*\
                         *  Back to legacy HTML4 mode for -
                         *  Issue #167 & #169 - TidyTag_A
                         *  Issue #196        - TidyTag_CAPTION
                         *  others?
                        \*/ 
                        TY_(AdjustTags)(doc); /* Dynamically modify the tags table  */
                    }
                }
                node = lexer->token;
                GTDBG(doc,"doctype", node);
                return node;

            case LEX_PROCINSTR:  /* seen <? so look for '>' */
                /* check for PHP preprocessor instructions <?php ... ?> */

                if  (lexer->lexsize - lexer->txtstart == 3)
                {
                    if (TY_(tmbstrncmp)(lexer->lexbuf + lexer->txtstart, "php", 3) == 0)
                    {
                        lexer->state = LEX_PHP;
                        continue;
                    }
                }

                if  (lexer->lexsize - lexer->txtstart == 4)
                {
                    if (TY_(tmbstrncmp)(lexer->lexbuf + lexer->txtstart, "xml", 3) == 0 &&
                        TY_(IsWhite)(lexer->lexbuf[lexer->txtstart + 3]))
                    {
                        lexer->state = LEX_XMLDECL;
                        attributes = NULL;
                        continue;
                    }
                }

                if (cfgBool(doc, TidyXmlPIs) || lexer->isvoyager) /* insist on ?> as terminator */
                {
                    if (c != '?')
                        continue;

                    /* now look for '>' */
                    c = TY_(ReadChar)(doc->docIn);

                    if (c == EndOfStream)
                    {
                        TY_(Report)(doc, NULL, NULL, UNEXPECTED_END_OF_FILE );
                        TY_(UngetChar)(c, doc->docIn);
                        continue;
                    }

                    TY_(AddCharToLexer)(lexer, c);
                }


                if (c != '>')
                    continue;

                lexer->lexsize -= 1;

                if (lexer->lexsize)
                {
                    unsigned int i;
                    Bool closed;

                    for (i = 0; i < lexer->lexsize - lexer->txtstart &&
                        !TY_(IsWhite)(lexer->lexbuf[i + lexer->txtstart]); ++i)
                        /**/;

                    closed = lexer->lexbuf[lexer->lexsize - 1] == '?';

                    if (closed)
                        lexer->lexsize -= 1;

                    lexer->txtstart += i;
                    lexer->txtend = lexer->lexsize;
                    lexer->lexbuf[lexer->lexsize] = '\0';

                    lexer->token = PIToken(doc);
                    lexer->token->closed = closed;
                    lexer->token->element = TY_(tmbstrndup)(doc->allocator,
                                                            lexer->lexbuf +
                                                            lexer->txtstart - i, i);
                }
                else
                {
                    lexer->txtend = lexer->lexsize;
                    lexer->lexbuf[lexer->lexsize] = '\0';
                    lexer->token = PIToken(doc);
                }

                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                node = lexer->token;
                GTDBG(doc,"procinstr", node);
                return node;

            case LEX_ASP:  /* seen <% so look for "%>" */
                if (c != '%')
                    continue;

                /* now look for '>' */
                c = TY_(ReadChar)(doc->docIn);


                if (c != '>')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }

                lexer->lexsize -= 1;
                lexer->txtend = lexer->lexsize;
                lexer->lexbuf[lexer->lexsize] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                lexer->token = AspToken(doc);
                node = lexer->token;
                GTDBG(doc,"ASP", node);
                return node;  /* the endtag token */



            case LEX_JSTE:  /* seen <# so look for "#>" */
                if (c != '#')
                    continue;

                /* now look for '>' */
                c = TY_(ReadChar)(doc->docIn);


                if (c != '>')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }

                lexer->lexsize -= 1;
                lexer->txtend = lexer->lexsize;
                lexer->lexbuf[lexer->lexsize] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                lexer->token = JsteToken(doc);
                node = lexer->token;
                GTDBG(doc,"JSTE", node);
                return node;  /* the JSTE token */


            case LEX_PHP: /* seen "<?php" so look for "?>" */
                if (c != '?')
                    continue;

                /* now look for '>' */
                c = TY_(ReadChar)(doc->docIn);

                if (c != '>')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }

                lexer->lexsize -= 1;
                lexer->txtend = lexer->lexsize;
                lexer->lexbuf[lexer->lexsize] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                lexer->token = PhpToken(doc);
                node = lexer->token;
                GTDBG(doc,"PHP", node);
                return node;  /* the PHP token */

            case LEX_XMLDECL: /* seen "<?xml" so look for "?>" */

                if (TY_(IsWhite)(c) && c != '?')
                    continue;

                /* get pseudo-attribute */
                if (c != '?')
                {
                    tmbstr name;
                    Node *asp, *php;
                    AttVal *av = NULL;
                    int pdelim = 0;
                    isempty = no;

                    TY_(UngetChar)(c, doc->docIn);

                    name = ParseAttribute( doc, &isempty, &asp, &php );

                    if (!name)
                    {
                        /* fix for http://tidy.sf.net/bug/788031 */
                        lexer->lexsize -= 1;
                        lexer->txtend = lexer->txtstart;
                        lexer->lexbuf[lexer->txtend] = '\0';
                        lexer->state = LEX_CONTENT;
                        lexer->waswhite = no;
                        lexer->token = XmlDeclToken(doc);
                        lexer->token->attributes = attributes;
                        node = lexer->token;
                        GTDBG(doc,"xml", node);
                        return node;  /* the xml token */
                    }

                    av = TY_(NewAttribute)(doc);
                    av->attribute = name;
                    av->value = ParseValue( doc, name, yes, &isempty, &pdelim );
                    av->delim = pdelim;
                    av->dict = TY_(FindAttribute)( doc, av );

                    AddAttrToList( &attributes, av );
                    /* continue; */
                }

                /* now look for '>' */
                c = TY_(ReadChar)(doc->docIn);

                if (c != '>')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }
                lexer->lexsize -= 1;
                lexer->txtend = lexer->txtstart;
                lexer->lexbuf[lexer->txtend] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                lexer->token = XmlDeclToken(doc);
                lexer->token->attributes = attributes;
                node = lexer->token;
                GTDBG(doc,"XML", node);
                return node;  /* the XML token */

            case LEX_SECTION: /* seen "<![" so look for "]>" */
                if (c == '[')
                {
                    if (lexer->lexsize == (lexer->txtstart + 6) &&
                        TY_(tmbstrncmp)(lexer->lexbuf+lexer->txtstart, "CDATA[", 6) == 0)
                    {
                        lexer->state = LEX_CDATA;
                        lexer->lexsize -= 6;
                        continue;
                    }
                }

                if (c != ']')
                    continue;

                /* now look for '>' */
                c = TY_(ReadChar)(doc->docIn);

                lexdump = 1;
                if (c != '>')
                {
                    /* Issue #153 - can also be ]'-->' */
                    if (c == '-') 
                    {
                        c = TY_(ReadChar)(doc->docIn);
                        if (c == '-')
                        {
                            c = TY_(ReadChar)(doc->docIn);
                            if (c != '>')
                            {
                                TY_(UngetChar)(c, doc->docIn);
                                TY_(UngetChar)('-', doc->docIn);
                                TY_(UngetChar)('-', doc->docIn);
                                continue;
                            }
                            /* this failed!
                               TY_(AddCharToLexer)(lexer, '-'); TY_(AddCharToLexer)(lexer, '-'); lexdump = 0; 
                               got output <![endif]--]> - needs furhter fix in pprint section output 
                             */
                        }
                        else
                        {
                            TY_(UngetChar)(c, doc->docIn);
                            TY_(UngetChar)('-', doc->docIn);
                            continue;
                        }
                    } 
                    else 
                    {
                        TY_(UngetChar)(c, doc->docIn);
                        continue;
                    }
                }
 
                lexer->lexsize -= lexdump;
                lexer->txtend = lexer->lexsize;
                lexer->lexbuf[lexer->lexsize] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                lexer->token = SectionToken(doc);
                node = lexer->token;
                GTDBG(doc,"SECTION", node);
                return node;  /* the SECTION token */

            case LEX_CDATA: /* seen "<![CDATA[" so look for "]]>" */
                if (c != ']')
                    continue;

                /* now look for ']' */
                c = TY_(ReadChar)(doc->docIn);

                if (c != ']')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    continue;
                }

                /* now look for '>' */
                c = TY_(ReadChar)(doc->docIn);

                if (c != '>')
                {
                    TY_(UngetChar)(c, doc->docIn);
                    TY_(UngetChar)(']', doc->docIn);
                    continue;
                }

                lexer->lexsize -= 1;
                lexer->txtend = lexer->lexsize;
                lexer->lexbuf[lexer->lexsize] = '\0';
                lexer->state = LEX_CONTENT;
                lexer->waswhite = no;
                lexer->token = CDATAToken(doc);
                node = lexer->token;
                GTDBG(doc,"CDATA", node);
                return node;  /* the CDATA token */
        }
    }

    if (lexer->state == LEX_CONTENT)  /* text string */
    {
        lexer->txtend = lexer->lexsize;

        if (lexer->txtend > lexer->txtstart)
        {
            TY_(UngetChar)(c, doc->docIn);

            if (lexer->lexbuf[lexer->lexsize - 1] == ' ')
            {
                lexer->lexsize -= 1;
                lexer->txtend = lexer->lexsize;
            }
            lexer->token = TY_(TextToken)(lexer);
            node = lexer->token;
            GTDBG(doc,"textstring", node);
            return node;  /* the textstring token */
        }
    }
    else if (lexer->state == LEX_COMMENT) /* comment */
    {
        if (c == EndOfStream)
        {
            /* We print this if we reached end of the stream mid-comment. */
            TY_(Report)(doc, NULL, NULL, MALFORMED_COMMENT_EOS );
        }

        lexer->txtend = lexer->lexsize;
        lexer->lexbuf[lexer->lexsize] = '\0';
        lexer->state = LEX_CONTENT;
        lexer->waswhite = no;
        lexer->token = CommentToken(doc);
        node = lexer->token;
        GTDBG(doc,"COMMENT", node);
        return node;  /* the COMMENT token */
    }

    DEBUG_LOG(SPRTF("Returning NULL...\n"));
    return NULL;
}

static void MapStr( ctmbstr str, unsigned int code )
{
    while ( *str )
    {
        unsigned int i = (byte) *str++;
        lexmap[i] |= code;
    }
}

void TY_(InitMap)(void)
{
    MapStr("\r\n\f", newline|white);
    MapStr(" \t", white);
    MapStr("-.:_", namechar);
    MapStr("0123456789", digit|digithex|namechar);
    MapStr("abcdefghijklmnopqrstuvwxyz", lowercase|letter|namechar);
    MapStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", uppercase|letter|namechar);
    MapStr("abcdefABCDEF", digithex);
}

/*
 parser for ASP within start tags

 Some people use ASP for to customize attributes
 Tidy isn't really well suited to dealing with ASP
 This is a workaround for attributes, but won't
 deal with the case where the ASP is used to tailor
 the attribute value. Here is an example of a work
 around for using ASP in attribute values:

  href='<%=rsSchool.Fields("ID").Value%>'

 where the ASP that generates the attribute value
 is masked from Tidy by the quotemarks.

*/

static Node *ParseAsp( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    unsigned int c;
    Node *asp = NULL;

    lexer->txtstart = lexer->lexsize;

    for (;;)
    {
        if ((c = TY_(ReadChar)(doc->docIn)) == EndOfStream)
            break;

        TY_(AddCharToLexer)(lexer, c);


        if (c != '%')
            continue;

        if ((c = TY_(ReadChar)(doc->docIn)) == EndOfStream)
            break;

        TY_(AddCharToLexer)(lexer, c);

        if (c == '>')
        {
            lexer->lexsize -= 2;
            break;
        }
    }

    lexer->txtend = lexer->lexsize;
    if (lexer->txtend > lexer->txtstart)
        asp = AspToken(doc);

    lexer->txtstart = lexer->txtend;
    return asp;
}   
 

/*
 PHP is like ASP but is based upon XML
 processing instructions, e.g. <?php ... ?>
*/
static Node *ParsePhp( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    unsigned int c;
    Node *php = NULL;

    lexer->txtstart = lexer->lexsize;

    for (;;)
    {
        if ((c = TY_(ReadChar)(doc->docIn)) == EndOfStream)
            break;

        TY_(AddCharToLexer)(lexer, c);


        if (c != '?')
            continue;

        if ((c = TY_(ReadChar)(doc->docIn)) == EndOfStream)
            break;

        TY_(AddCharToLexer)(lexer, c);

        if (c == '>')
        {
            lexer->lexsize -= 2;
            break;
        }
    }

    lexer->txtend = lexer->lexsize;
    if (lexer->txtend > lexer->txtstart)
        php = PhpToken(doc);

    lexer->txtstart = lexer->txtend;
    return php;
}   

/* consumes the '>' terminating start tags */
/* @TODO: float the errors back to the calling method */
static tmbstr  ParseAttribute( TidyDocImpl* doc, Bool *isempty,
                              Node **asp, Node **php )
{
    Lexer* lexer = doc->lexer;
    int start, len = 0;
    tmbstr attr = NULL;
    unsigned int c, lastc;

    *asp = NULL;  /* clear asp pointer */
    *php = NULL;  /* clear php pointer */

 /* skip white space before the attribute */

    for (;;)
    {
        c = TY_(ReadChar)( doc->docIn );


        if (c == '/')
        {
            c = TY_(ReadChar)( doc->docIn );

            if (c == '>')
            {
                *isempty = yes;
                return NULL;
            }

            TY_(UngetChar)(c, doc->docIn);
            c = '/';
            break;
        }

        if (c == '>')
            return NULL;

        if (c =='<')
        {
            c = TY_(ReadChar)(doc->docIn);

            if (c == '%')
            {
                *asp = ParseAsp( doc );
                return NULL;
            }
            else if (c == '?')
            {
                *php = ParsePhp( doc );
                return NULL;
            }

            TY_(UngetChar)(c, doc->docIn);
            TY_(UngetChar)('<', doc->docIn);
            TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_GT );
            return NULL;
        }

        if (c == '=')
        {
            TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_EQUALSIGN );
            continue;
        }

        if (c == '"' || c == '\'')
        {
            TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_QUOTEMARK );
            continue;
        }

        if (c == EndOfStream)
        {
            TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_END_OF_FILE_ATTR );
            TY_(UngetChar)(c, doc->docIn);
            return NULL;
        }


        if (!TY_(IsWhite)(c))
           break;
    }

    start = lexer->lexsize;
    lastc = c;

    for (;;)
    {
     /* but push back '=' for parseValue() */
        if (c == '=' || c == '>')
        {
            TY_(UngetChar)(c, doc->docIn);
            break;
        }

        if (c == '<' || c == EndOfStream)
        {
            TY_(UngetChar)(c, doc->docIn);
            break;
        }

        if (lastc == '-' && (c == '"' || c == '\''))
        {
            lexer->lexsize--;
            --len;
            TY_(UngetChar)(c, doc->docIn);
            break;
        }

        if (TY_(IsWhite)(c))
            break;

        if (c == '/') /* Issue #395 - potential self closing tag */
        {
            c = TY_(ReadChar)(doc->docIn);  /* read next */
            if (c == '>')
            {
                /* got a self closing tag - put is back and continue... */
                TY_(UngetChar)(c, doc->docIn);
                break;
            }
            else
            {
                /* Not '/>' - put it back */
                TY_(UngetChar)(c, doc->docIn);
                c = '/';  /* retore original char */
            }
        }

        /* what should be done about non-namechar characters? */
        /* currently these are incorporated into the attr name */

        if ( cfg(doc, TidyUpperCaseAttrs) != TidyUppercasePreserve )
        {
            if ( !cfgBool(doc, TidyXmlTags) && TY_(IsUpper)(c) )
                c = TY_(ToLower)(c);
        }

        TY_(AddCharToLexer)( lexer, c );
        lastc = c;
        c = TY_(ReadChar)(doc->docIn);
    }

    /* handle attribute names with multibyte chars */
    len = lexer->lexsize - start;
    attr = (len > 0 ? TY_(tmbstrndup)(doc->allocator,
                                      lexer->lexbuf+start, len) : NULL);
    lexer->lexsize = start;
    return attr;
}

/*
 invoked when < is seen in place of attribute value
 but terminates on whitespace if not ASP, PHP or Tango
 this routine recognizes ' and " quoted strings
*/
static int ParseServerInstruction( TidyDocImpl* doc )
{
    Lexer* lexer = doc->lexer;
    unsigned int c;
    int delim = '"';
    Bool isrule = no;

    c = TY_(ReadChar)(doc->docIn);
    TY_(AddCharToLexer)(lexer, c);

    /* check for ASP, PHP or Tango */
    if (c == '%' || c == '?' || c == '@')
        isrule = yes;

    for (;;)
    {
        c = TY_(ReadChar)(doc->docIn);

        if (c == EndOfStream)
            break;

        if (c == '>')
        {
            if (isrule)
                TY_(AddCharToLexer)(lexer, c);
            else
                TY_(UngetChar)(c, doc->docIn);

            break;
        }

        /* if not recognized as ASP, PHP or Tango */
        /* then also finish value on whitespace */
        if (!isrule)
        {
            if (TY_(IsWhite)(c))
                break;
        }

        TY_(AddCharToLexer)(lexer, c);

        if (c == '"')
        {
            do
            {
                c = TY_(ReadChar)(doc->docIn);
                if (c == EndOfStream) /* #427840 - fix by Terry Teague 30 Jun 01 */
                {
                    TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_END_OF_FILE_ATTR );
                    TY_(UngetChar)(c, doc->docIn);
                    return 0;
                }
                if (c == '>') /* #427840 - fix by Terry Teague 30 Jun 01 */
                {
                    TY_(UngetChar)(c, doc->docIn);
                    TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_GT );
                    return 0;
                }
                TY_(AddCharToLexer)(lexer, c);
            }
            while (c != '"');
            delim = '\'';
            continue;
        }

        if (c == '\'')
        {
            do
            {
                c = TY_(ReadChar)(doc->docIn);
                if (c == EndOfStream) /* #427840 - fix by Terry Teague 30 Jun 01 */
                {
                    TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_END_OF_FILE_ATTR );
                    TY_(UngetChar)(c, doc->docIn);
                    return 0;
                }
                if (c == '>') /* #427840 - fix by Terry Teague 30 Jun 01 */
                {
                    TY_(UngetChar)(c, doc->docIn);
                    TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_GT );
                    return 0;
                }
                TY_(AddCharToLexer)(lexer, c);
            }
            while (c != '\'');
        }
    }

    return delim;
}

/* values start with "=" or " = " etc. */
/* doesn't consume the ">" at end of start tag */

static tmbstr ParseValue( TidyDocImpl* doc, ctmbstr name,
                          Bool foldCase, Bool *isempty, int *pdelim)
{
    Lexer* lexer = doc->lexer;
    int len = 0, start;
    Bool seen_gt = no;
    Bool munge = yes;
    unsigned int c, lastc, delim, quotewarning;
    tmbstr value;

    delim = (tmbchar) 0;
    *pdelim = '"';

    /*
     Henry Zrepa reports that some folk are using the
     embed element with script attributes where newlines
     are significant and must be preserved
    */
    if ( cfgBool(doc, TidyLiteralAttribs) )
        munge = no;

 /* skip white space before the '=' */

    for (;;)
    {
        c = TY_(ReadChar)(doc->docIn);

        if (c == EndOfStream)
        {
            TY_(UngetChar)(c, doc->docIn);
            break;
        }

        if (!TY_(IsWhite)(c))
           break;
    }

/*
  c should be '=' if there is a value
  other legal possibilities are white
  space, '/' and '>'
*/

    if (c != '=' && c != '"' && c != '\'')
    {
        TY_(UngetChar)(c, doc->docIn);
        return NULL;
    }

 /* skip white space after '=' */

    for (;;)
    {
        c = TY_(ReadChar)(doc->docIn);

        if (c == EndOfStream)
        {
            TY_(UngetChar)(c, doc->docIn);
            break;
        }

        if (!TY_(IsWhite)(c))
           break;
    }

 /* check for quote marks */

    if (c == '"' || c == '\'')
        delim = c;
    else if (c == '<')
    {
        start = lexer->lexsize;
        TY_(AddCharToLexer)(lexer, c);
        *pdelim = ParseServerInstruction( doc );
        len = lexer->lexsize - start;
        lexer->lexsize = start;
        return (len > 0 ? TY_(tmbstrndup)(doc->allocator,
                                          lexer->lexbuf+start, len) : NULL);
    }
    else
        TY_(UngetChar)(c, doc->docIn);

 /*
   and read the value string
   check for quote mark if needed
 */

    quotewarning = 0;
    start = lexer->lexsize;
    c = '\0';

    for (;;)
    {
        lastc = c;  /* track last character */
        c = TY_(ReadChar)(doc->docIn);

        if (c == EndOfStream)
        {
            TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_END_OF_FILE_ATTR );
            TY_(UngetChar)(c, doc->docIn);
            break;
        }

        if (delim == (tmbchar)0)
        {
            if (c == '>')
            {
                TY_(UngetChar)(c, doc->docIn);
                break;
            }

            if (c == '"' || c == '\'')
            {
                unsigned int q = c;

                /* handle <input onclick=s("btn1")> and <a title=foo""">...</a> */
                /* this doesn't handle <a title=foo"/> which browsers treat as  */
                /* 'foo"/' nor  <a title=foo" /> which browser treat as 'foo"'  */
                
                c = TY_(ReadChar)(doc->docIn);
                if (c == '>')
                {
                    TY_(AddCharToLexer)(lexer, q);
                    TY_(UngetChar)(c, doc->docIn);
                    break;
                }
                else
                {
                    TY_(UngetChar)(c, doc->docIn);
                    c = q;
                }
            }

            if (c == '<')
            {
                TY_(UngetChar)(c, doc->docIn);
                c = '>';
                TY_(UngetChar)(c, doc->docIn);
                TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_GT );
                break;
            }

            /*
             For cases like <br clear=all/> need to avoid treating /> as
             part of the attribute value, however care is needed to avoid
             so treating <a href=http://www.acme.com/> in this way, which
             would map the <a> tag to <a href="http://www.acme.com"/>
            */
            if (c == '/')
            {
                /* peek ahead in case of /> */
                c = TY_(ReadChar)(doc->docIn);

                if ( c == '>' && !TY_(IsUrl)(doc, name) )
                {
                    *isempty = yes;
                    TY_(UngetChar)(c, doc->docIn);
                    break;
                }

                /* unget peeked character */
                TY_(UngetChar)(c, doc->docIn);
                c = '/';
            }
        }
        else  /* delim is '\'' or '"' */
        {
            if (c == delim)
                break;

            if (c == '\n' || c == '<' || c == '>')
                ++quotewarning;

            if (c == '>')
                seen_gt = yes;
        }

        if (c == '&')
        {
            TY_(AddCharToLexer)(lexer, c);
            ParseEntity( doc, IgnoreWhitespace );
            if (lexer->lexbuf[lexer->lexsize - 1] == '\n' && munge)
                ChangeChar(lexer, ' ');
            continue;
        }

        /*
         kludge for JavaScript attribute values
         with line continuations in string literals
        */
        if (c == '\\')
        {
            c = TY_(ReadChar)(doc->docIn);

            if (c != '\n')
            {
                TY_(UngetChar)(c, doc->docIn);
                c = '\\';
            }
        }

        if (TY_(IsWhite)(c))
        {
            if ( delim == 0 )
                break;

            if (munge)
            {
                /* discard line breaks in quoted URLs */ 
                /* #438650 - fix by Randy Waki */
                if ( c == '\n' && TY_(IsUrl)(doc, name) )
                {
                    /* warn that we discard this newline */
                    TY_(ReportAttrError)( doc, lexer->token, NULL, NEWLINE_IN_URI);
                    continue;
                }
                
                c = ' ';

                if (lastc == ' ')
                {
                    if (TY_(IsUrl)(doc, name) )
                        TY_(ReportAttrError)( doc, lexer->token, NULL, WHITE_IN_URI);
                    continue;
                }
            }
        }
        else if (foldCase && TY_(IsUpper)(c))
            c = TY_(ToLower)(c);

        TY_(AddCharToLexer)(lexer, c);
    }

    if (quotewarning > 10 && seen_gt && munge)
    {
        /*
           there is almost certainly a missing trailing quote mark
           as we have see too many newlines, < or > characters.

           an exception is made for Javascript attributes and the
           javascript URL scheme which may legitimately include < and >,
           and for attributes starting with "<xml " as generated by
           Microsoft Office.
        */
        if ( !TY_(IsScript)(doc, name) &&
             !(TY_(IsUrl)(doc, name) && TY_(tmbstrncmp)(lexer->lexbuf+start, "javascript:", 11) == 0) &&
             !(TY_(tmbstrncmp)(lexer->lexbuf+start, "<xml ", 5) == 0)
           )
            TY_(Report)( doc, NULL, NULL, SUSPECTED_MISSING_QUOTE ); 
    }

    len = lexer->lexsize - start;
    lexer->lexsize = start;


    if (len > 0 || delim)
    {
        /* ignore leading and trailing white space for all but title, alt, value */
        /* and prompts attributes unless --literal-attributes is set to yes      */
        /* #994841 - Whitespace is removed from value attributes                 */

        /* Issue #217 - Also only if/while (len > 0) - MUST NEVER GO NEGATIVE! */
        if ((len > 0) && munge &&
            TY_(tmbstrcasecmp)(name, "alt") &&
            TY_(tmbstrcasecmp)(name, "title") &&
            TY_(tmbstrcasecmp)(name, "value") &&
            TY_(tmbstrcasecmp)(name, "prompt"))
        {
            while (TY_(IsWhite)(lexer->lexbuf[start+len-1]) && (len > 0))
                --len;

            /* Issue #497 - Fix leading space trimming */
            while (TY_(IsWhite)(lexer->lexbuf[start]) && (len > 0))
            {
                ++start;
                --len;
            }
        }

        value = TY_(tmbstrndup)(doc->allocator, lexer->lexbuf + start, len);
    }
    else
        value = NULL;

    /* note delimiter if given */
    *pdelim = delim;

    return value;
}

/* attr must be non-NULL */
static Bool IsValidAttrName( ctmbstr attr )
{
    unsigned int i, c = attr[0];

    /* first character should be a letter */
    if (!TY_(IsLetter)(c))
        return no;

    /* remaining characters should be namechars */
    for( i = 1; i < TY_(tmbstrlen)(attr); i++)
    {
        c = attr[i];

        if (TY_(IsNamechar)(c))
            continue;

        return no;
    }

    return yes;
}

/* create a new attribute */
AttVal *TY_(NewAttribute)( TidyDocImpl* doc )
{
    AttVal *av = (AttVal*) TidyDocAlloc( doc, sizeof(AttVal) );
    TidyClearMemory( av, sizeof(AttVal) );
    return av;
}

/* create a new attribute with given name and value */
AttVal* TY_(NewAttributeEx)( TidyDocImpl* doc, ctmbstr name, ctmbstr value,
                             int delim )
{
    AttVal *av = TY_(NewAttribute)(doc);
    av->attribute = TY_(tmbstrdup)(doc->allocator, name);
    av->value = TY_(tmbstrdup)(doc->allocator, value);
    av->delim = delim;
    av->dict = TY_(FindAttribute)( doc, av );
    return av;
}

static void AddAttrToList( AttVal** list, AttVal* av )
{
  if ( *list == NULL )
    *list = av;
  else
  {
    AttVal* here = *list;
    while ( here->next )
      here = here->next;
    here->next = av;
  }
}

void TY_(InsertAttributeAtEnd)( Node *node, AttVal *av )
{
    AddAttrToList(&node->attributes, av);
}

void TY_(InsertAttributeAtStart)( Node *node, AttVal *av )
{
    av->next = node->attributes;
    node->attributes = av;
}

/* swallows closing '>' */

static AttVal* ParseAttrs( TidyDocImpl* doc, Bool *isempty )
{
    Lexer* lexer = doc->lexer;
    AttVal *av, *list;
    tmbstr value;
    int delim;
    Node *asp, *php;

    list = NULL;

    while ( !EndOfInput(doc) )
    {
        tmbstr attribute = ParseAttribute( doc, isempty, &asp, &php );

        if (attribute == NULL)
        {
            /* check if attributes are created by ASP markup */
            if (asp)
            {
                av = TY_(NewAttribute)(doc);
                av->asp = asp;
                AddAttrToList( &list, av ); 
                continue;
            }

            /* check if attributes are created by PHP markup */
            if (php)
            {
                av = TY_(NewAttribute)(doc);
                av->php = php;
                AddAttrToList( &list, av ); 
                continue;
            }

            break;
        }

        value = ParseValue( doc, attribute, no, isempty, &delim );

        if (attribute && (IsValidAttrName(attribute) ||
            (cfgBool(doc, TidyXmlTags) && IsValidXMLAttrName(attribute))))
        {
            av = TY_(NewAttribute)(doc);
            av->delim = delim ? delim : '"';
            av->attribute = attribute;
            av->value = value;
            av->dict = TY_(FindAttribute)( doc, av );
            AddAttrToList( &list, av );
            if ( !delim && value )
                TY_(ReportAttrError)( doc, lexer->token, av, MISSING_QUOTEMARK_OPEN);
        }
        else
        {
            av = TY_(NewAttribute)(doc);
            av->attribute = attribute;
            av->value = value;

            if (LastChar(attribute) == '"')
                TY_(ReportAttrError)( doc, lexer->token, av, MISSING_QUOTEMARK);
            else if (value == NULL)
                TY_(ReportAttrError)(doc, lexer->token, av, MISSING_ATTR_VALUE);
            else
                TY_(ReportAttrError)(doc, lexer->token, av, INVALID_ATTRIBUTE);

            TY_(FreeAttribute)( doc, av );
        }
    }

    return list;
}

/*
  Returns document type declarations like

  <!DOCTYPE foo PUBLIC "fpi" "sysid">
  <!DOCTYPE bar SYSTEM "sysid">
  <!DOCTYPE baz [ <!ENTITY ouml "&#246"> ]>

  as

  <foo PUBLIC="fpi" SYSTEM="sysid" />
  <bar SYSTEM="sysid" />
  <baz> &lt;!ENTITY ouml &quot;&amp;#246&quot;&gt; </baz>
*/
static Node *ParseDocTypeDecl(TidyDocImpl* doc)
{
    Lexer *lexer = doc->lexer;
    int start = lexer->lexsize;
    ParseDocTypeDeclState state = DT_DOCTYPENAME;
    unsigned int c;
    unsigned int delim = 0;
    Bool hasfpi = yes;

    Node* node = TY_(NewNode)(lexer->allocator, lexer);
    node->type = DocTypeTag;
    node->start = lexer->txtstart;
    node->end = lexer->txtend;

    lexer->waswhite = no;

    /* todo: reset lexer->lexsize when appropriate to avoid wasting memory */

    while ((c = TY_(ReadChar)(doc->docIn)) != EndOfStream)
    {
        /* convert newlines to spaces */
        if (state != DT_INTSUBSET)
            c = c == '\n' ? ' ' : c;

        /* convert white-space sequences to single space character */
        if (TY_(IsWhite)(c) && state != DT_INTSUBSET)
        {
            if (!lexer->waswhite)
            {
                TY_(AddCharToLexer)(lexer, c);
                lexer->waswhite = yes;
            }
            else
            {
                /* discard space */
                continue;
            }
        }
        else
        {
            TY_(AddCharToLexer)(lexer, c);
            lexer->waswhite = no;
        }

        switch(state)
        {
        case DT_INTERMEDIATE:
            /* determine what's next */
            if (TY_(ToUpper)(c) == 'P' || TY_(ToUpper)(c) == 'S')
            {
                start = lexer->lexsize - 1;
                state = DT_PUBLICSYSTEM;
                continue;
            }
            else if (c == '[')
            {
                start = lexer->lexsize;
                state = DT_INTSUBSET;
                continue;
            }
            else if (c == '\'' || c == '"')
            {
                start = lexer->lexsize;
                delim = c;
                state = DT_QUOTEDSTRING;
                continue;
            }
            else if (c == '>')
            {
                AttVal* si;

                node->end = --(lexer->lexsize);

                si = TY_(GetAttrByName)(node, "SYSTEM");
                if (si)
                    TY_(CheckUrl)(doc, node, si);

                if (!node->element || !IsValidXMLElemName(node->element))
                {
                    TY_(Report)(doc, NULL, NULL, MALFORMED_DOCTYPE);
                    TY_(FreeNode)(doc, node);
                    return NULL;
                }
                return node;
            }
            else
            {
                /* error */
            }
            break;
        case DT_DOCTYPENAME:
            /* read document type name */
            if (TY_(IsWhite)(c) || c == '>' || c == '[')
            {
                node->element = TY_(tmbstrndup)(doc->allocator,
                                                lexer->lexbuf + start,
                                                lexer->lexsize - start - 1);
                if (c == '>' || c == '[')
                {
                    --(lexer->lexsize);
                    TY_(UngetChar)(c, doc->docIn);
                }

                state = DT_INTERMEDIATE;
                continue;
            }
            break;
        case DT_PUBLICSYSTEM:
            /* read PUBLIC/SYSTEM */
            if (TY_(IsWhite)(c) || c == '>')
            {
                char *attname = TY_(tmbstrndup)(doc->allocator,
                                                lexer->lexbuf + start,
                                                lexer->lexsize - start - 1);
                hasfpi = !(TY_(tmbstrcasecmp)(attname, "SYSTEM") == 0);

                TidyDocFree(doc, attname);

                /* todo: report an error if SYSTEM/PUBLIC not uppercase */

                if (c == '>')
                {
                    --(lexer->lexsize);
                    TY_(UngetChar)(c, doc->docIn);
                }

                state = DT_INTERMEDIATE;
                continue;
            }
            break;
        case DT_QUOTEDSTRING:
            /* read quoted string */
            if (c == delim)
            {
                char *value = TY_(tmbstrndup)(doc->allocator,
                                              lexer->lexbuf + start,
                                              lexer->lexsize - start - 1);
                AttVal* att = TY_(AddAttribute)(doc, node, hasfpi ? "PUBLIC" : "SYSTEM", value);
                TidyDocFree(doc, value);
                att->delim = delim;
                hasfpi = no;
                state = DT_INTERMEDIATE;
                delim = 0;
                continue;
            }
            break;
        case DT_INTSUBSET:
            /* read internal subset */
            if (c == ']')
            {
                Node* subset;
                lexer->txtstart = start;
                lexer->txtend = lexer->lexsize - 1;
                subset = TY_(TextToken)(lexer);
                TY_(InsertNodeAtEnd)(node, subset);
                state = DT_INTERMEDIATE;
            }
            break;
        }
    }

    /* document type declaration not finished */
    TY_(Report)(doc, NULL, NULL, MALFORMED_DOCTYPE);
    TY_(FreeNode)(doc, node);
    return NULL;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* Interface to mmap style I/O

   (c) 2006-2008 (W3C) MIT, ERCIM, Keio University
   See tidy.h for the copyright notice.

   Originally contributed by Cory Nelson and Nuno Lopes

*/

/* keep these here to keep file non-empty */
/* #include "forward.h" */
/* #include "mappedio.h" */

#if SUPPORT_POSIX_MAPPED_FILES

/* #include "fileio.h" */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

#include <sys/mman.h>


typedef struct
{
    TidyAllocator *allocator;
    const byte *base;
    size_t pos, size;
} MappedFileSource;

static int TIDY_CALL mapped_getByte( void* sourceData )
{
    MappedFileSource* fin = (MappedFileSource*) sourceData;
    return fin->base[fin->pos++];
}

static Bool TIDY_CALL mapped_eof( void* sourceData )
{
    MappedFileSource* fin = (MappedFileSource*) sourceData;
    return (fin->pos >= fin->size);
}

static void TIDY_CALL mapped_ungetByte( void* sourceData, byte ARG_UNUSED(bv) )
{
    MappedFileSource* fin = (MappedFileSource*) sourceData;
    fin->pos--;
}

int TY_(initFileSource)( TidyAllocator *allocator, TidyInputSource* inp, FILE* fp )
{
    MappedFileSource* fin;
    struct stat sbuf;
    int fd;

    fin = (MappedFileSource*) TidyAlloc( allocator, sizeof(MappedFileSource) );
    if ( !fin )
        return -1;

    fd = fileno(fp);
    if ( fstat(fd, &sbuf) == -1
         || sbuf.st_size == 0
         || (fin->base = mmap(0, fin->size = sbuf.st_size, PROT_READ,
                              MAP_SHARED, fd, 0)) == MAP_FAILED)
    {
        TidyFree( allocator, fin );
        /* Fallback on standard I/O */
        return TY_(initStdIOFileSource)( allocator, inp, fp );
    }

    fin->pos = 0;
    fin->allocator = allocator;
    fclose(fp);

    inp->getByte    = mapped_getByte;
    inp->eof        = mapped_eof;
    inp->ungetByte  = mapped_ungetByte;
    inp->sourceData = fin;

    return 0;
}

void TY_(freeFileSource)( TidyInputSource* inp, Bool closeIt )
{
    if ( inp->getByte == mapped_getByte )
    {
        MappedFileSource* fin = (MappedFileSource*) inp->sourceData;
        munmap( (void*)fin->base, fin->size );
        TidyFree( fin->allocator, fin );
    }
    else
        TY_(freeStdIOFileSource)( inp, closeIt );
}

#endif /* SUPPORT_POSIX_MAPPED_FILES */


#if defined(_WIN32)
#  if defined(_MSC_VER) && (_MSC_VER < 1300)  /* less than msvc++ 7.0 */
#    pragma warning(disable:4115) /* named type definition in parentheses in windows headers */
#  endif
#  include <windows.h>
#  include <errno.h>
/* #  include "streamio.h" */
/* #  include "tidy-int.h" */
/* #  include "message.h" */

typedef struct _fp_input_mapped_source
{
    TidyAllocator *allocator;
    LONGLONG size, pos;
    HANDLE file, map;
    byte *view, *iter, *end;
    unsigned int gran;
} MappedFileSource;

static int mapped_openView( MappedFileSource *data )
{
    DWORD numb = ( ( data->size - data->pos ) > data->gran ) ?
        data->gran : (DWORD)( data->size - data->pos );

    if ( data->view )
    {
        UnmapViewOfFile( data->view );
        data->view = NULL;
    }

    data->view = MapViewOfFile( data->map, FILE_MAP_READ,
                                (DWORD)( data->pos >> 32 ),
                                (DWORD)data->pos, numb );

    if ( !data->view ) return -1;

    data->iter = data->view;
    data->end = data->iter + numb;

    return 0;
}

static int TIDY_CALL mapped_getByte( void *sourceData )
{
    MappedFileSource *data = sourceData;

    if ( !data->view || data->iter >= data->end )
    {
        data->pos += data->gran;

        if ( data->pos >= data->size || mapped_openView(data) != 0 )
            return EndOfStream;
    }

    return *( data->iter++ );
}

static Bool TIDY_CALL mapped_eof( void *sourceData )
{
    MappedFileSource *data = sourceData;
    return ( data->pos >= data->size );
}

static void TIDY_CALL mapped_ungetByte( void *sourceData, byte ARG_UNUSED(bt) )
{
    MappedFileSource *data = sourceData;

    if ( data->iter >= data->view )
    {
        --data->iter;
        return;
    }

    if ( data->pos < data->gran )
    {
        assert(0);
        return;
    }

    data->pos -= data->gran;
    mapped_openView( data );
}

static int initMappedFileSource( TidyAllocator *allocator, TidyInputSource* inp, HANDLE fp )
{
    MappedFileSource* fin = NULL;

    inp->getByte    = mapped_getByte;
    inp->eof        = mapped_eof;
    inp->ungetByte  = mapped_ungetByte;

    fin = (MappedFileSource*) TidyAlloc( allocator, sizeof(MappedFileSource) );
    if ( !fin )
        return -1;

#  if defined(__MINGW32__)
    {
        DWORD lowVal, highVal;
        lowVal = GetFileSize(fp, &highVal);
        if ((lowVal == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
        {
            TidyFree(allocator, fin);
            return -1;
        }
        fin->size = highVal;
        fin->size = (fin->size << 32);
        fin->size += lowVal;
    }
#  else /* NOT a MinGW build */
#    if defined(_MSC_VER) && (_MSC_VER < 1300)  /* less than msvc++ 7.0 */
    {
        LARGE_INTEGER* pli = (LARGE_INTEGER *)&fin->size;
        (DWORD)pli->LowPart = GetFileSize( fp, (DWORD *)&pli->HighPart );
        if ( GetLastError() != NO_ERROR || fin->size <= 0 )
        {
            TidyFree(allocator, fin);
            return -1;
        }
    }
#    else
    if ( !GetFileSizeEx( fp, (LARGE_INTEGER*)&fin->size )
         || fin->size <= 0 )
    {
        TidyFree(allocator, fin);
        return -1;
    }
#    endif
#  endif /* MinGW y/n */

    fin->map = CreateFileMapping( fp, NULL, PAGE_READONLY, 0, 0, NULL );

    if ( !fin->map )
    {
        TidyFree(allocator, fin);
        return -1;
    }

    {
        SYSTEM_INFO info;
        GetSystemInfo( &info );
        fin->gran = info.dwAllocationGranularity;
    }

    fin->allocator = allocator;
    fin->pos    = 0;
    fin->view   = NULL;
    fin->iter   = NULL;
    fin->end    = NULL;

    if ( mapped_openView( fin ) != 0 )
    {
        CloseHandle( fin->map );
        TidyFree( allocator, fin );
        return -1;
    }

    fin->file = fp;
    inp->sourceData = fin;

    return 0;
}

static void freeMappedFileSource( TidyInputSource* inp, Bool closeIt )
{
    MappedFileSource* fin = (MappedFileSource*) inp->sourceData;
    if ( closeIt && fin && fin->file != INVALID_HANDLE_VALUE )
    {
        if ( fin->view )
            UnmapViewOfFile( fin->view );

        CloseHandle( fin->map );
        CloseHandle( fin->file );
    }
    TidyFree( fin->allocator, fin );
}

StreamIn* MappedFileInput ( TidyDocImpl* doc, HANDLE fp, int encoding )
{
    StreamIn *in = TY_(initStreamIn)( doc, encoding );
    if ( initMappedFileSource( doc->allocator, &in->source, fp ) != 0 )
    {
        TY_(freeStreamIn)( in );
        return NULL;
    }
    in->iotype = FileIO;
    return in;
}


int TY_(DocParseFileWithMappedFile)( TidyDocImpl* doc, ctmbstr filnam ) {
    int status = -ENOENT;
    HANDLE fin = CreateFileA( filnam, GENERIC_READ, FILE_SHARE_READ, NULL,
                              OPEN_EXISTING, 0, NULL );

#  if PRESERVE_FILE_TIMES
    LONGLONG actime, modtime;
    TidyClearMemory( &doc->filetimes, sizeof(doc->filetimes) );

    if ( fin != INVALID_HANDLE_VALUE && cfgBool(doc,TidyKeepFileTimes) &&
         GetFileTime(fin, NULL, (FILETIME*)&actime, (FILETIME*)&modtime) )
    {
#    define TY_I64(str) TYDYAPPEND(str,LL)
#    if _MSC_VER < 1300  && !defined(__GNUC__) /* less than msvc++ 7.0 */
#      undef TY_I64
#      define TY_I64(str) TYDYAPPEND(str,i64)
#    endif
        doc->filetimes.actime =
            (time_t)( ( actime  - TY_I64(116444736000000000)) / 10000000 );

        doc->filetimes.modtime =
            (time_t)( ( modtime - TY_I64(116444736000000000)) / 10000000 );
    }
#  endif /* PRESERVE_FILE_TIMES */

    if ( fin != INVALID_HANDLE_VALUE )
    {
        StreamIn* in = MappedFileInput( doc, fin,
                                        cfg( doc, TidyInCharEncoding ) );
        if ( !in )
        {
            CloseHandle( fin );
            return -ENOMEM;
        }

        status = TY_(DocParseStream)( doc, in );
        freeMappedFileSource( &in->source, yes );
        TY_(freeStreamIn)( in );
    }
    else /* Error message! */
        TY_(ReportFileError)( doc, filnam, FILE_CANT_OPEN );
    return status;
}

#endif /* defined(_WIN32) */

/* message.c -- General Message Writing Routines

  (c) 1998-2017 (W3C) MIT, ERCIM, Keio University, University of
  Toronto, HTACG
  See tidy.h for the copyright notice.

*/

/* #include "message.h" */
/* #include "messageobj.h" */
/* #include "limits.h" */
/* #include "tidy-int.h" */
/* #include "lexer.h" */
/* #include "streamio.h" */
/* #include "tmbstr.h" */
/* #include "utf8.h" */
/* #include "version.h" */


/*********************************************************************
 * Release Information
 *********************************************************************/

ctmbstr TY_(ReleaseDate)(void)
{
  return TY_(release_date);
}


ctmbstr TY_(tidyLibraryVersion)(void)
{
  return TY_(library_version);
}


/*********************************************************************
 * General Message Utility Functions
 *********************************************************************/

/* Returns the given node's tag as a string. */
static char* TagToString(Node* tag, char* buf, size_t count)
{
    *buf = 0;
    if (tag)
    {
        if (TY_(nodeIsElement)(tag))
            TY_(tmbsnprintf)(buf, count, "<%s>", tag->element);
        else if (tag->type == EndTag)
            TY_(tmbsnprintf)(buf, count, "</%s>", tag->element);
        else if (tag->type == DocTypeTag)
            TY_(tmbsnprintf)(buf, count, "<!DOCTYPE>");
        else if (tag->type == TextNode)
            TY_(tmbsnprintf)(buf, count, "%s", tidyLocalizedString(STRING_PLAIN_TEXT));
        else if (tag->type == XmlDecl)
            TY_(tmbsnprintf)(buf, count, "%s", tidyLocalizedString(STRING_XML_DECLARATION));
        else if (tag->element)
            TY_(tmbsnprintf)(buf, count, "%s", tag->element);
    }
    return buf + TY_(tmbstrlen)(buf);
}


/* Convert an integer to a string. */
static void NtoS(int n, tmbstr str)
{
    tmbchar buf[40];
    int i;
    
    for (i = 0;; ++i)
    {
        buf[i] = (tmbchar)( (n % 10) + '0' );
        
        n = n / 10;
        
        if (n == 0)
            break;
    }
    
    n = i;
    
    while (i >= 0)
    {
        str[n-i] = buf[i];
        --i;
    }
    
    str[n+1] = '\0';
}


/* Get an HTML version string */
static ctmbstr HTMLVersion( TidyDocImpl* doc )
{
    unsigned int versionEmitted = doc->lexer->versionEmitted;
    unsigned int declared = doc->lexer->doctype;
    unsigned int version = versionEmitted == 0 ? declared : versionEmitted;
    ctmbstr result = TY_(HTMLVersionNameFromCode)(version, 0);
    if (!result)
        result = tidyLocalizedString(STRING_HTML_PROPRIETARY);
    return result;
}


/*********************************************************************
 * Message Writing Functions
 * These funtions provide final, formatted output to the output sink.
 *********************************************************************/


/* Writes messages to the output sink unless they are suppressed by one of the
** message callback filters, or suppressed by the configuration settings.
** Report messages are messages that are included in the "error table," and
** dialogue messages are any other output that Tidy traditionally emits.
*/
static void messageOut( TidyMessageImpl *message )
{
    TidyDocImpl *doc;
    Bool go = yes;

    if ( !message )
        return;

    doc = message->tidyDoc;

    /* The filter has had a chance to suppress *any* message from output. */
    go = message->allowMessage;

    /* Update the count of each report type. */
    switch ( message->level )
    {
        case TidyInfo:
            doc->infoMessages++;
            break;
        case TidyWarning:
            doc->warnings++;
            break;
        case TidyConfig:
            doc->optionErrors++;
            break;
        case TidyAccess:
            doc->accessErrors++;
            break;
        case TidyError:
            doc->errors++;
            break;
        case TidyBadDocument:
            doc->docErrors++;
            break;
        case TidyFatal:
            /* Ack! */
            break;
        default:
            break;
    }

    /* Suppress report messages if they've been muted. */
    go = go & !message->muted;

    /* Suppress report messages if we've already reached the reporting limit. */
    if ( message->level <= TidyFatal )
    {
        go = go & ( doc->errors < cfg(doc, TidyShowErrors) );
    }

    /* Let TidyQuiet silence a lot of things. */
    if ( cfgBool( doc, TidyQuiet ) == yes )
    {
        go = go && message->code != STRING_DOCTYPE_GIVEN;
        go = go && message->code != STRING_CONTENT_LOOKS;
        go = go && message->code != STRING_NO_SYSID;
        go = go && message->level != TidyDialogueInfo;
        go = go && message->level != TidyConfig;
        go = go && message->level != TidyInfo;
        go = go && !(message->level >= TidyDialogueSummary &&
                            message->code != STRING_NEEDS_INTERVENTION);
    }

    /* Let !TidyShowInfo silence some things. */
    if ( cfgBool( doc, TidyShowInfo ) == no )
    {
        go = go && message->level != TidyInfo;

        /* Temporary; TidyShowInfo shouldn't affect TidyDialogueInfo, but
           right now such messages are hidden until we granularize the
           output controls. */
        go = go && message->level != TidyDialogueInfo;
    }

    /* Let !TidyShowWarnings silence some things. */
    if ( cfgBool( doc, TidyShowWarnings ) == no )
    {
        go = go && message->level != TidyWarning;
    }

    /* Output the message if applicable. */
    if ( go )
    {
        TidyOutputSink *outp = &doc->errout->sink;
        ctmbstr cp;
        byte b = '\0';
        for ( cp = message->messageOutput; *cp; ++cp )
        {
            b = (*cp & 0xff);
            if (b == (byte)'\n')
                TY_(WriteChar)( b, doc->errout );   /* for EOL translation */
            else
                outp->putByte( outp->sinkData, b ); /* #383 - no encoding */
        }

        /* Always add a trailing newline. Reports require this, and dialogue
           messages will be better spaced out without having to fill the
           language file with superflous newlines. */
        TY_(WriteChar)( '\n', doc->errout );
    }

    TY_(tidyMessageRelease)(message);
}


/*********************************************************************
 * Report Formatting
 * In order to provide a single, predictable reporting system, Tidy
 * provides an extensible messaging system that provides most of the
 * basic requirements for most reports, while permitting simple
 * implementation of new reports in a flexible manner. By adding
 * additional formatters, new messages can be added easily while
 * maintaining Tidy's internal organization.
 *********************************************************************/


/* Functions of this type will create new instances of TidyMessage specific to
** the type of report being emitted. Many messages share the same fomatter for
** messages, but new ones can be written as required. Please have a look at
** the existing formatters in order to determine if an existing signature is
** compatible with the report you wish to output before adding a new formatter.
** In particular, if an existing formatter provides most of the local variables
** required to populate your format string, try to use it.
*/
typedef TidyMessageImpl*(messageFormatter)(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, unsigned int level, va_list args);


/* Forward declarations of messageFormatter functions. */
static messageFormatter formatAccessReport;
static messageFormatter formatAttributeReport;
static messageFormatter formatEncodingReport;
static messageFormatter formatStandard;
static messageFormatter formatStandardDynamic;


/* This structure ties together for each report Code the default 
** TidyReportLevel, the Formatter to be used to construct the message, and the
** next code to output, if applicable. Assuming an existing formatter can,
** this it makes it simple to output new reports, or to change report level by
** modifying this array.
*/
static struct _dispatchTable {
    unsigned int code;                 /**< The message code. */
    TidyReportLevel level;     /**< The default TidyReportLevel of the message. */
    messageFormatter *handler; /**< The formatter for the report. */
    unsigned int next;                 /**< If multiple codes should be displayed, which is next? */
} dispatchTable[] = {
    { ADDED_MISSING_CHARSET,        TidyInfo,        formatStandard          },
    { ANCHOR_NOT_UNIQUE,            TidyWarning,     formatAttributeReport   },
    { ANCHOR_DUPLICATED,            TidyWarning,     formatAttributeReport   },
    { APOS_UNDEFINED,               TidyWarning,     formatStandard          },
    { ATTR_VALUE_NOT_LCASE,         TidyWarning,     formatAttributeReport   },
    { ATTRIBUTE_VALUE_REPLACED,     TidyInfo,        formatAttributeReport   },
    { ATTRIBUTE_IS_NOT_ALLOWED,     TidyWarning,     formatAttributeReport   },
    { BACKSLASH_IN_URI,             TidyWarning,     formatAttributeReport   },
    { BAD_ATTRIBUTE_VALUE_REPLACED, TidyWarning,     formatAttributeReport   },
    { BAD_ATTRIBUTE_VALUE,          TidyWarning,     formatAttributeReport   },
    { BAD_CDATA_CONTENT,            TidyWarning,     formatStandard          },
    { BAD_SUMMARY_HTML5,            TidyWarning,     formatStandard          },
    { BAD_SURROGATE_LEAD,           TidyWarning,     formatStandard          },
    { BAD_SURROGATE_PAIR,           TidyWarning,     formatStandard          },
    { BAD_SURROGATE_TAIL,           TidyWarning,     formatStandard          },
    { CANT_BE_NESTED,               TidyWarning,     formatStandard          },
    { COERCE_TO_ENDTAG,             TidyWarning,     formatStandard          },
    { CONTENT_AFTER_BODY,           TidyWarning,     formatStandard          },
    { CUSTOM_TAG_DETECTED,          TidyInfo,        formatStandard          },
    { DISCARDING_UNEXPECTED,        0,               formatStandardDynamic   },
    { DOCTYPE_AFTER_TAGS,           TidyWarning,     formatStandard          },
    { DUPLICATE_FRAMESET,           TidyError,       formatStandard          },
    { ELEMENT_NOT_EMPTY,            TidyWarning,     formatStandard          },
    { ELEMENT_VERS_MISMATCH_ERROR,  TidyError,       formatStandard          },
    { ELEMENT_VERS_MISMATCH_WARN,   TidyWarning,     formatStandard          },
    { ENCODING_MISMATCH,            TidyWarning,     formatEncodingReport    },
    { ESCAPED_ILLEGAL_URI,          TidyWarning,     formatAttributeReport   },
    { FILE_CANT_OPEN,               TidyBadDocument, formatStandard          },
    { FILE_CANT_OPEN_CFG,           TidyBadDocument, formatStandard          },
    { FILE_NOT_FILE,                TidyBadDocument, formatStandard          },
    { FIXED_BACKSLASH,              TidyWarning,     formatAttributeReport   },
    { FOUND_STYLE_IN_BODY,          TidyWarning,     formatStandard          },
    { ID_NAME_MISMATCH,             TidyWarning,     formatAttributeReport   },
    { ILLEGAL_NESTING,              TidyWarning,     formatStandard          },
    { ILLEGAL_URI_CODEPOINT,        TidyWarning,     formatAttributeReport   },
    { ILLEGAL_URI_REFERENCE,        TidyWarning,     formatAttributeReport   },
    { INSERTING_AUTO_ATTRIBUTE,     TidyWarning,     formatAttributeReport   },
    { INSERTING_TAG,                TidyWarning,     formatStandard          },
    { INVALID_ATTRIBUTE,            TidyWarning,     formatAttributeReport   },
    { INVALID_NCR,                  TidyWarning,     formatEncodingReport    },
    { INVALID_SGML_CHARS,           TidyWarning,     formatEncodingReport    },
    { INVALID_UTF8,                 TidyWarning,     formatEncodingReport    },
    { INVALID_UTF16,                TidyWarning,     formatEncodingReport    },
    { INVALID_XML_ID,               TidyWarning,     formatAttributeReport   },
    { JOINING_ATTRIBUTE,            TidyWarning,     formatAttributeReport   },
    { MALFORMED_COMMENT,            TidyInfo,        formatStandard          },
    { MALFORMED_COMMENT_EOS,        TidyError,       formatStandard          },
    { MALFORMED_COMMENT_DROPPING,   TidyWarning,     formatStandard          },
    { MALFORMED_COMMENT_WARN,       TidyWarning,     formatStandard          },
    { MALFORMED_DOCTYPE,            TidyWarning,     formatStandard          },
    { MISMATCHED_ATTRIBUTE_ERROR,   TidyError,       formatAttributeReport   },
    { MISMATCHED_ATTRIBUTE_WARN,    TidyWarning,     formatAttributeReport   },
    { MISSING_ATTR_VALUE,           TidyWarning,     formatAttributeReport   },
    { MISSING_ATTRIBUTE,            TidyWarning,     formatStandard          },
    { MISSING_DOCTYPE,              TidyWarning,     formatStandard          },
    { MISSING_ENDTAG_BEFORE,        TidyWarning,     formatStandard          },
    { MISSING_ENDTAG_FOR,           TidyWarning,     formatStandard          },
    { MISSING_ENDTAG_OPTIONAL,      TidyInfo,        formatStandard          },
    { MISSING_IMAGEMAP,             TidyWarning,     formatAttributeReport   },
    { MISSING_QUOTEMARK,            TidyWarning,     formatAttributeReport   },
    { MISSING_QUOTEMARK_OPEN,       TidyInfo,        formatAttributeReport   },
    { MISSING_SEMICOLON_NCR,        TidyWarning,     formatStandard          },
    { MISSING_SEMICOLON,            TidyWarning,     formatStandard          },
    { MISSING_STARTTAG,             TidyWarning,     formatStandard          },
    { MISSING_TITLE_ELEMENT,        TidyWarning,     formatStandard          },
    { MOVED_STYLE_TO_HEAD,          TidyWarning,     formatStandard          },
    { NESTED_EMPHASIS,              TidyWarning,     formatStandard          },
    { NESTED_QUOTATION,             TidyWarning,     formatStandard          },
    { NEWLINE_IN_URI,               TidyWarning,     formatAttributeReport   },
    { NOFRAMES_CONTENT,             TidyWarning,     formatStandard          },
    { NON_MATCHING_ENDTAG,          TidyWarning,     formatStandard          },
    { OBSOLETE_ELEMENT,             TidyWarning,     formatStandard          },
    { OPTION_REMOVED,               TidyConfig,      formatStandard          },
    { OPTION_REMOVED_APPLIED,       TidyConfig,      formatStandard          },
    { OPTION_REMOVED_UNAPPLIED,     TidyConfig,      formatStandard          },
    { PREVIOUS_LOCATION,            TidyInfo,        formatStandard          },
    { PROPRIETARY_ATTR_VALUE,       TidyWarning,     formatAttributeReport   },
    { PROPRIETARY_ATTRIBUTE,        TidyWarning,     formatAttributeReport   },
    { PROPRIETARY_ELEMENT,          TidyWarning,     formatStandard          },
    { REMOVED_HTML5,                TidyWarning,     formatStandard          },
    { REPEATED_ATTRIBUTE,           TidyWarning,     formatAttributeReport   },
    { REPLACING_ELEMENT,            TidyWarning,     formatStandard          },
    { REPLACING_UNEX_ELEMENT,       TidyWarning,     formatStandard          },
    { SPACE_PRECEDING_XMLDECL,      TidyWarning,     formatStandard          },
    { STRING_ARGUMENT_BAD,          TidyConfig,      formatStandard          },
    { STRING_CONTENT_LOOKS,         TidyInfo,        formatStandard          }, /* reportMarkupVersion() */
    { STRING_DOCTYPE_GIVEN,         TidyInfo,        formatStandard          }, /* reportMarkupVersion() */
    { STRING_MISSING_MALFORMED,     TidyConfig,      formatStandard          },
    { STRING_MUTING_TYPE,           TidyInfo,        formatStandard          },
    { STRING_NO_SYSID,              TidyInfo,        formatStandard          }, /* reportMarkupVersion() */
    { STRING_UNKNOWN_OPTION,        TidyConfig,      formatStandard          },
    { SUSPECTED_MISSING_QUOTE,      TidyWarning,     formatStandard          },
    { TAG_NOT_ALLOWED_IN,           TidyWarning,     formatStandard, PREVIOUS_LOCATION },
    { TOO_MANY_ELEMENTS_IN,         TidyWarning,     formatStandard, PREVIOUS_LOCATION },
    { TOO_MANY_ELEMENTS,            TidyWarning,     formatStandard          },
    { TRIM_EMPTY_ELEMENT,           TidyWarning,     formatStandard          },
    { UNESCAPED_AMPERSAND,          TidyWarning,     formatStandard          },
    { UNEXPECTED_END_OF_FILE_ATTR,  TidyWarning,     formatAttributeReport   },
    { UNEXPECTED_END_OF_FILE,       TidyWarning,     formatStandard          },
    { UNEXPECTED_ENDTAG_IN,         TidyError,       formatStandard          },
    { UNEXPECTED_ENDTAG,            TidyWarning,     formatStandard          },
    { UNEXPECTED_ENDTAG_ERR,        TidyError,       formatStandard          },
    { UNEXPECTED_EQUALSIGN,         TidyWarning,     formatAttributeReport   },
    { UNEXPECTED_GT,                TidyWarning,     formatAttributeReport   },
    { UNEXPECTED_QUOTEMARK,         TidyWarning,     formatAttributeReport   },
    { UNKNOWN_ELEMENT_LOOKS_CUSTOM, TidyError,       formatStandard          },
    { UNKNOWN_ELEMENT,              TidyError,       formatStandard          },
    { UNKNOWN_ENTITY,               TidyWarning,     formatStandard          },
    { USING_BR_INPLACE_OF,          TidyWarning,     formatStandard          },
    { VENDOR_SPECIFIC_CHARS,        TidyWarning,     formatEncodingReport    },
    { WHITE_IN_URI,                 TidyWarning,     formatAttributeReport   },
    { XML_DECLARATION_DETECTED,     TidyWarning,     formatStandard          },
    { XML_ID_SYNTAX,                TidyWarning,     formatAttributeReport   },

    { APPLET_MISSING_ALT,                            TidyAccess, formatAccessReport },
    { AREA_MISSING_ALT,                              TidyAccess, formatAccessReport },
    { ASCII_REQUIRES_DESCRIPTION,                    TidyAccess, formatAccessReport },
    { ASSOCIATE_LABELS_EXPLICITLY,                   TidyAccess, formatAccessReport },
    { ASSOCIATE_LABELS_EXPLICITLY_FOR,               TidyAccess, formatAccessReport },
    { ASSOCIATE_LABELS_EXPLICITLY_ID,                TidyAccess, formatAccessReport },
    { AUDIO_MISSING_TEXT_AIFF,                       TidyAccess, formatAccessReport },
    { AUDIO_MISSING_TEXT_AU,                         TidyAccess, formatAccessReport },
    { AUDIO_MISSING_TEXT_RA,                         TidyAccess, formatAccessReport },
    { AUDIO_MISSING_TEXT_RM,                         TidyAccess, formatAccessReport },
    { AUDIO_MISSING_TEXT_SND,                        TidyAccess, formatAccessReport },
    { AUDIO_MISSING_TEXT_WAV,                        TidyAccess, formatAccessReport },
    { COLOR_CONTRAST_ACTIVE_LINK,                    TidyAccess, formatAccessReport },
    { COLOR_CONTRAST_LINK,                           TidyAccess, formatAccessReport },
    { COLOR_CONTRAST_TEXT,                           TidyAccess, formatAccessReport },
    { COLOR_CONTRAST_VISITED_LINK,                   TidyAccess, formatAccessReport },
    { DATA_TABLE_MISSING_HEADERS,                    TidyAccess, formatAccessReport },
    { DATA_TABLE_MISSING_HEADERS_COLUMN,             TidyAccess, formatAccessReport },
    { DATA_TABLE_MISSING_HEADERS_ROW,                TidyAccess, formatAccessReport },
    { DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS,      TidyAccess, formatAccessReport },
    { DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS,         TidyAccess, formatAccessReport },
    { DOCTYPE_MISSING,                               TidyAccess, formatAccessReport },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET, TidyAccess, formatAccessReport },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED,  TidyAccess, formatAccessReport },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT, TidyAccess, formatAccessReport },
    { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT, TidyAccess, formatAccessReport },
    { FRAME_MISSING_LONGDESC,                        TidyAccess, formatAccessReport },
    { FRAME_MISSING_NOFRAMES,                        TidyAccess, formatAccessReport },
    { FRAME_MISSING_TITLE,                           TidyAccess, formatAccessReport },
    { FRAME_SRC_INVALID,                             TidyAccess, formatAccessReport },
    { FRAME_TITLE_INVALID_NULL,                      TidyAccess, formatAccessReport },
    { FRAME_TITLE_INVALID_SPACES,                    TidyAccess, formatAccessReport },
    { HEADER_USED_FORMAT_TEXT,                       TidyAccess, formatAccessReport },
    { HEADERS_IMPROPERLY_NESTED,                     TidyAccess, formatAccessReport },
    { IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION,     TidyAccess, formatAccessReport },
    { IMG_ALT_SUSPICIOUS_FILE_SIZE,                  TidyAccess, formatAccessReport },
    { IMG_ALT_SUSPICIOUS_FILENAME,                   TidyAccess, formatAccessReport },
    { IMG_ALT_SUSPICIOUS_PLACEHOLDER,                TidyAccess, formatAccessReport },
    { IMG_ALT_SUSPICIOUS_TOO_LONG,                   TidyAccess, formatAccessReport },
    { IMG_BUTTON_MISSING_ALT,                        TidyAccess, formatAccessReport },
    { IMG_MAP_CLIENT_MISSING_TEXT_LINKS,             TidyAccess, formatAccessReport },
    { IMG_MAP_SERVER_REQUIRES_TEXT_LINKS,            TidyAccess, formatAccessReport },
    { IMG_MISSING_ALT,                               TidyAccess, formatAccessReport },
    { IMG_MISSING_DLINK,                             TidyAccess, formatAccessReport },
    { IMG_MISSING_LONGDESC,                          TidyAccess, formatAccessReport },
    { IMG_MISSING_LONGDESC_DLINK,                    TidyAccess, formatAccessReport },
    { INFORMATION_NOT_CONVEYED_APPLET,               TidyAccess, formatAccessReport },
    { INFORMATION_NOT_CONVEYED_IMAGE,                TidyAccess, formatAccessReport },
    { INFORMATION_NOT_CONVEYED_INPUT,                TidyAccess, formatAccessReport },
    { INFORMATION_NOT_CONVEYED_OBJECT,               TidyAccess, formatAccessReport },
    { INFORMATION_NOT_CONVEYED_SCRIPT,               TidyAccess, formatAccessReport },
    { LANGUAGE_INVALID,                              TidyAccess, formatAccessReport },
    { LANGUAGE_NOT_IDENTIFIED,                       TidyAccess, formatAccessReport },
    { LAYOUT_TABLE_INVALID_MARKUP,                   TidyAccess, formatAccessReport },
    { LAYOUT_TABLES_LINEARIZE_PROPERLY,              TidyAccess, formatAccessReport },
    { LINK_TEXT_MISSING,                             TidyAccess, formatAccessReport },
    { LINK_TEXT_NOT_MEANINGFUL,                      TidyAccess, formatAccessReport },
    { LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE,           TidyAccess, formatAccessReport },
    { LINK_TEXT_TOO_LONG,                            TidyAccess, formatAccessReport },
    { LIST_USAGE_INVALID_LI,                         TidyAccess, formatAccessReport },
    { LIST_USAGE_INVALID_OL,                         TidyAccess, formatAccessReport },
    { LIST_USAGE_INVALID_UL,                         TidyAccess, formatAccessReport },
    { METADATA_MISSING,                              TidyAccess, formatAccessReport },
    { METADATA_MISSING_REDIRECT_AUTOREFRESH,         TidyAccess, formatAccessReport },
    { MULTIMEDIA_REQUIRES_TEXT,                      TidyAccess, formatAccessReport },
    { NEW_WINDOWS_REQUIRE_WARNING_BLANK,             TidyAccess, formatAccessReport },
    { NEW_WINDOWS_REQUIRE_WARNING_NEW,               TidyAccess, formatAccessReport },
    { NOFRAMES_INVALID_CONTENT,                      TidyAccess, formatAccessReport },
    { NOFRAMES_INVALID_LINK,                         TidyAccess, formatAccessReport },
    { NOFRAMES_INVALID_NO_VALUE,                     TidyAccess, formatAccessReport },
    { OBJECT_MISSING_ALT,                            TidyAccess, formatAccessReport },
    { POTENTIAL_HEADER_BOLD,                         TidyAccess, formatAccessReport },
    { POTENTIAL_HEADER_ITALICS,                      TidyAccess, formatAccessReport },
    { POTENTIAL_HEADER_UNDERLINE,                    TidyAccess, formatAccessReport },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET,   TidyAccess, formatAccessReport },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED,    TidyAccess, formatAccessReport },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT,   TidyAccess, formatAccessReport },
    { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT,   TidyAccess, formatAccessReport },
    { REMOVE_AUTO_REDIRECT,                          TidyAccess, formatAccessReport },
    { REMOVE_AUTO_REFRESH,                           TidyAccess, formatAccessReport },
    { REMOVE_BLINK_MARQUEE,                          TidyAccess, formatAccessReport },
    { REMOVE_FLICKER_ANIMATED_GIF,                   TidyAccess, formatAccessReport },
    { REMOVE_FLICKER_APPLET,                         TidyAccess, formatAccessReport },
    { REMOVE_FLICKER_EMBED,                          TidyAccess, formatAccessReport },
    { REMOVE_FLICKER_OBJECT,                         TidyAccess, formatAccessReport },
    { REMOVE_FLICKER_SCRIPT,                         TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_APPLET,                TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_BASEFONT,              TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_CENTER,                TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_DIR,                   TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_FONT,                  TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_ISINDEX,               TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_MENU,                  TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_S,                     TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_STRIKE,                TidyAccess, formatAccessReport },
    { REPLACE_DEPRECATED_HTML_U,                     TidyAccess, formatAccessReport },
    { SCRIPT_MISSING_NOSCRIPT,                       TidyAccess, formatAccessReport },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK,       TidyAccess, formatAccessReport },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN,  TidyAccess, formatAccessReport },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE,  TidyAccess, formatAccessReport },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT,   TidyAccess, formatAccessReport },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER,  TidyAccess, formatAccessReport },
    { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP,    TidyAccess, formatAccessReport },
    { SKIPOVER_ASCII_ART,                            TidyAccess, formatAccessReport },
    { STYLE_SHEET_CONTROL_PRESENTATION,              TidyAccess, formatAccessReport },
    { STYLESHEETS_REQUIRE_TESTING_LINK,              TidyAccess, formatAccessReport },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR,        TidyAccess, formatAccessReport },
    { STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT,     TidyAccess, formatAccessReport },
    { TABLE_MAY_REQUIRE_HEADER_ABBR,                 TidyAccess, formatAccessReport },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_NULL,            TidyAccess, formatAccessReport },
    { TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES,          TidyAccess, formatAccessReport },
    { TABLE_MISSING_CAPTION,                         TidyAccess, formatAccessReport },
    { TABLE_MISSING_SUMMARY,                         TidyAccess, formatAccessReport },
    { TABLE_SUMMARY_INVALID_NULL,                    TidyAccess, formatAccessReport },
    { TABLE_SUMMARY_INVALID_PLACEHOLDER,             TidyAccess, formatAccessReport },
    { TABLE_SUMMARY_INVALID_SPACES,                  TidyAccess, formatAccessReport },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET,      TidyAccess, formatAccessReport },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT,      TidyAccess, formatAccessReport },
    { TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT,      TidyAccess, formatAccessReport },

    { 0, 0, NULL }
};


/*********************************************************************
 * Message Formatting
 * These individual message formatters populate messages with the
 * correct, pertinent data.
 *********************************************************************/


/* Provides formatting for the Attribute-related reports. This formatter
** should be reserved for messages generated by Tidy's accessibility module,
** even if the signature matches some unrelated report that you wish to
** generate.
*/
TidyMessageImpl *formatAccessReport(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, unsigned int level, va_list args)
{
    doc->badAccess |= BA_WAI;

    /* Currently *all* cases are handled in the default, but maintain this
       structure for possible future cases. */
    switch (code)
    {
        default:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level );
    }

    return NULL;
}

/* Provides formatting for the Attribute-related reports. This formatter
** provides local variables that are used principally in the formats used for
** the attribute related reports.
*/
TidyMessageImpl *formatAttributeReport(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, unsigned int level, va_list args)
{
    AttVal *av = NULL;
    char const *name = "NULL";
    char const *value = "NULL";
    char tagdesc[64];

    TagToString(node, tagdesc, sizeof(tagdesc));

    if ( ( av = va_arg(args, AttVal*) ) )
    {
        if (av->attribute)
            name = av->attribute;
        if (av->value)
            value = av->value;
    }

    switch (code)
    {
        case MISSING_QUOTEMARK_OPEN:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, name );
		
        case BACKSLASH_IN_URI:
        case ESCAPED_ILLEGAL_URI:
        case FIXED_BACKSLASH:
        case ID_NAME_MISMATCH:
        case ILLEGAL_URI_CODEPOINT:
        case ILLEGAL_URI_REFERENCE:
        case INVALID_XML_ID:
        case MISSING_IMAGEMAP:
        case MISSING_QUOTEMARK:
        case NEWLINE_IN_URI:
        case UNEXPECTED_EQUALSIGN:
        case UNEXPECTED_GT:
        case UNEXPECTED_QUOTEMARK:
        case WHITE_IN_URI:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, tagdesc );

        case ATTRIBUTE_IS_NOT_ALLOWED:
        case JOINING_ATTRIBUTE:
        case MISSING_ATTR_VALUE:
        case PROPRIETARY_ATTRIBUTE:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, tagdesc, name );

        case ATTRIBUTE_VALUE_REPLACED:
        case BAD_ATTRIBUTE_VALUE:
        case BAD_ATTRIBUTE_VALUE_REPLACED:
        case INSERTING_AUTO_ATTRIBUTE:
        case INVALID_ATTRIBUTE:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, tagdesc, name, value );

        case MISMATCHED_ATTRIBUTE_ERROR:
        case MISMATCHED_ATTRIBUTE_WARN:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, tagdesc, name, HTMLVersion(doc));

        case ANCHOR_NOT_UNIQUE:
        case ANCHOR_DUPLICATED:
        case ATTR_VALUE_NOT_LCASE:
        case PROPRIETARY_ATTR_VALUE:
        case XML_ID_SYNTAX:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, tagdesc, value );

        case REPEATED_ATTRIBUTE:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, tagdesc, value, name );

        case UNEXPECTED_END_OF_FILE_ATTR:
            /* on end of file adjust reported position to end of input */
            doc->lexer->lines   = doc->docIn->curline;
            doc->lexer->columns = doc->docIn->curcol;
            return TY_(tidyMessageCreateWithLexer)(doc, code, level, tagdesc );
    }

    return NULL;
}


/* Provides report formatting *and* additional status settings for Tidy's
** encoding reports. Provides the local variables typically used for this type
** of report.
** @todo: These status changes probably SHOULD be made in the calling code;
**   however these states are captured to generate future output, which may be
**   useful here in the long run.
*/
TidyMessageImpl *formatEncodingReport(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, unsigned int level, va_list args)
{
    char buf[ 32 ] = {'\0'};
    unsigned int c = va_arg( args, unsigned int );
    Bool discarded = va_arg( args, Bool );
    ctmbstr action = tidyLocalizedString(discarded ? STRING_DISCARDING : STRING_REPLACING);

    switch (code)
    {
        case INVALID_NCR:
            NtoS(c, buf);
            doc->badChars |= BC_INVALID_NCR;
            break;

        case INVALID_SGML_CHARS:
            NtoS(c, buf);
            doc->badChars |= BC_INVALID_SGML_CHARS;
            break;

        case INVALID_UTF8:
            TY_(tmbsnprintf)(buf, sizeof(buf), "U+%04X", c);
            doc->badChars |= BC_INVALID_UTF8;
            break;

        case INVALID_UTF16:
            TY_(tmbsnprintf)(buf, sizeof(buf), "U+%04X", c);
            doc->badChars |= BC_INVALID_UTF16;
            break;

        case VENDOR_SPECIFIC_CHARS:
            NtoS(c, buf);
            doc->badChars |= BC_VENDOR_SPECIFIC_CHARS;
            break;

        case ENCODING_MISMATCH:
            doc->badChars |= BC_ENCODING_MISMATCH;
            return TY_(tidyMessageCreateWithLexer)(doc,
                                                   code,
                                                   level,
                                                   TY_(CharEncodingName)(doc->docIn->encoding),
                                                   TY_(CharEncodingName)(c));
            break;
    }

    return TY_(tidyMessageCreateWithLexer)(doc, code, level, action, buf );

}


/* Provides general formatting for the majority of Tidy's reports. Because most
** reports use the same basic data derived from the element and node, this
** formatter covers the vast majority of Tidy's report messages. Note that this
** formatter guarantees the values of TidyReportLevel in the dispatchTable[].
** Some of the cases in this formatter start new contexts from the va_list
** when the required data is simple. For complex local variable needs, it may
** be preferred to write a new formatter.
*/
TidyMessageImpl *formatStandard(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, unsigned int level, va_list args)
{
    char nodedesc[ 256 ] = {0};
    char elemdesc[ 256 ] = {0};
    Node* rpt = ( element ? element : node );

    TagToString(node, nodedesc, sizeof(nodedesc));

    if ( element )
        TagToString(element, elemdesc, sizeof(elemdesc));

    switch ( code )
    {
        case CUSTOM_TAG_DETECTED:
        {
            ctmbstr tagtype;
            switch ( cfg( doc, TidyUseCustomTags ) )
            {
                case TidyCustomBlocklevel:
                    tagtype = tidyLocalizedString( TIDYCUSTOMBLOCKLEVEL_STRING );
                    break;
                case TidyCustomEmpty:
                    tagtype = tidyLocalizedString( TIDYCUSTOMEMPTY_STRING );
                    break;
                case TidyCustomInline:
                    tagtype = tidyLocalizedString( TIDYCUSTOMINLINE_STRING );
                    break;
                case TidyCustomPre:
                default:
                    tagtype = tidyLocalizedString( TIDYCUSTOMPRE_STRING );
                    break;
            }
            return TY_(tidyMessageCreateWithNode)(doc, element, code, level, elemdesc, tagtype );
        }

        case STRING_NO_SYSID:
            return TY_(tidyMessageCreate)( doc, code, level );
            
        case FILE_CANT_OPEN:
        case FILE_CANT_OPEN_CFG:
        case FILE_NOT_FILE:
        case STRING_CONTENT_LOOKS:
        case STRING_DOCTYPE_GIVEN:
        case STRING_MISSING_MALFORMED:
        case STRING_MUTING_TYPE:
        {
            ctmbstr str;
            if ( (str = va_arg( args, ctmbstr)) )
                return TY_(tidyMessageCreate)( doc, code, level, str );

        } break;

        case APOS_UNDEFINED:
        case MISSING_SEMICOLON_NCR:
        case MISSING_SEMICOLON:
        case UNESCAPED_AMPERSAND:
        case UNKNOWN_ENTITY:
        {
            ctmbstr entityname;
            if ( !(entityname = va_arg( args, ctmbstr)) )
            {
                entityname = "NULL";
            }
            return TY_(tidyMessageCreateWithLexer)(doc, code, level, entityname);
        }

        case MISSING_ATTRIBUTE:
        {
            ctmbstr name;
            if ( (name = va_arg( args, ctmbstr)) )
                return TY_(tidyMessageCreateWithNode)(doc, node, code, level, nodedesc, name );
        } break;

        case STRING_UNKNOWN_OPTION:
        case OPTION_REMOVED:
        {
            ctmbstr str;
            if ( (str = va_arg( args, ctmbstr)) )
                return TY_(tidyMessageCreateWithLexer)(doc, code, level, str);
        } break;

        case OPTION_REMOVED_UNAPPLIED:
        case STRING_ARGUMENT_BAD:
        {
            ctmbstr s1 = va_arg( args, ctmbstr );
            ctmbstr s2 = va_arg( args, ctmbstr );
            return TY_(tidyMessageCreateWithLexer)(doc, code, level, s1, s2);
        }

        case OPTION_REMOVED_APPLIED:
        {
            ctmbstr s1 = va_arg( args, ctmbstr );
            ctmbstr s2 = va_arg( args, ctmbstr );
            ctmbstr s3 = va_arg( args, ctmbstr );
            return TY_(tidyMessageCreateWithLexer)(doc, code, level, s1, s2, s3);
        }


        case BAD_SURROGATE_LEAD:
        case BAD_SURROGATE_PAIR:
        case BAD_SURROGATE_TAIL:
        {
            unsigned int c1 = va_arg( args, unsigned int );
            unsigned int c2 = va_arg( args, unsigned int );
            return TY_(tidyMessageCreateWithLexer)(doc, code, level, c1, c2);
        }

        case SPACE_PRECEDING_XMLDECL:
            /* @TODO: Should this be a TidyInfo "silent" fix? */
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level );

        case CANT_BE_NESTED:
        case NOFRAMES_CONTENT:
        case USING_BR_INPLACE_OF:
            /* Can we use `rpt` here? No; `element` has a value in every case. */
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, nodedesc );

        case ELEMENT_VERS_MISMATCH_ERROR:
        case ELEMENT_VERS_MISMATCH_WARN:
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, nodedesc, HTMLVersion(doc) );

        case TAG_NOT_ALLOWED_IN:
            /* Can we use `rpt` here? No; `element` has a value in every case. */
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, nodedesc, element->element );

        case INSERTING_TAG:
        case MISSING_STARTTAG:
        case TOO_MANY_ELEMENTS:
        case UNEXPECTED_ENDTAG:
        case UNEXPECTED_ENDTAG_ERR:  /* generated by XML docs */
            /* Can we use `rpt` here? No; `element` has a value in every case. */
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, node->element );

        case UNEXPECTED_ENDTAG_IN:
            /* Can we use `rpt` here? No; `element` has a value in every case. */
            return TY_(tidyMessageCreateWithNode)(doc, node, code, level, node->element, element->element );

        case BAD_CDATA_CONTENT:
        case CONTENT_AFTER_BODY:
        case DOCTYPE_AFTER_TAGS:
        case DUPLICATE_FRAMESET:
        case MALFORMED_COMMENT:
        case MALFORMED_COMMENT_DROPPING:
        case MALFORMED_COMMENT_EOS:
        case MALFORMED_COMMENT_WARN:
        case MALFORMED_DOCTYPE:
        case MISSING_DOCTYPE:
        case MISSING_TITLE_ELEMENT:
        case NESTED_QUOTATION:
        case SUSPECTED_MISSING_QUOTE:
        case XML_DECLARATION_DETECTED:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level );

        case ELEMENT_NOT_EMPTY:
        case FOUND_STYLE_IN_BODY:
        case ILLEGAL_NESTING:
        case MOVED_STYLE_TO_HEAD:
        case TRIM_EMPTY_ELEMENT:
        case UNEXPECTED_END_OF_FILE:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level, elemdesc );

        case OBSOLETE_ELEMENT:
        case REPLACING_ELEMENT:
        case REPLACING_UNEX_ELEMENT:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level, elemdesc, nodedesc );

        case ADDED_MISSING_CHARSET:
        case BAD_SUMMARY_HTML5:
        case NESTED_EMPHASIS:
        case PROPRIETARY_ELEMENT:
        case REMOVED_HTML5:
        case UNKNOWN_ELEMENT:
        case UNKNOWN_ELEMENT_LOOKS_CUSTOM:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level, nodedesc );

        case MISSING_ENDTAG_FOR:
        case MISSING_ENDTAG_OPTIONAL:
        case PREVIOUS_LOCATION:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level, element->element );

        case MISSING_ENDTAG_BEFORE:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level, element->element, nodedesc );

        case COERCE_TO_ENDTAG:
        case NON_MATCHING_ENDTAG:
        case TOO_MANY_ELEMENTS_IN:
            return TY_(tidyMessageCreateWithNode)(doc, rpt, code, level, node->element, node->element );
    }

    return NULL;
}


/* Provides general formatting as formatStandard, except TidyReportLevel is set
** dynamically for these items as it cannot be predicted except at runtime.
 */
TidyMessageImpl *formatStandardDynamic(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, unsigned int level, va_list args)
{
    char nodedesc[ 256 ] = {0};

    TagToString(node, nodedesc, sizeof(nodedesc));

    switch (code)
    {
        case DISCARDING_UNEXPECTED:
            /* Force error if in a bad form, or Issue #166 - repeated <main> element. */
            /* Can we use `rpt` here? No; `element` has a value in every case. */
            return TY_(tidyMessageCreateWithNode)(doc, node, code, doc->badForm ? TidyError : TidyWarning, nodedesc );
            break;
    }

    return NULL;
}


/*********************************************************************
 * High Level Message Writing Functions
 * When adding new reports to LibTidy, preference should be given
 * to one of the existing, general pupose message writing functions
 * above, if possible, otherwise try to use one of these, or as a
 * last resort add a new one in this section.
 *********************************************************************/


/* This function performs the heavy lifting for TY_(Report)(). Critically we
** can accept the va_list needed for recursion.
*/
static void vReport(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, va_list args)
{
    int i = 0;
    va_list args_copy;

    while ( dispatchTable[i].code != 0 )
    {
        if ( dispatchTable[i].code == code )
        {
            TidyMessageImpl *message;
            messageFormatter *handler = dispatchTable[i].handler;
            TidyReportLevel level = dispatchTable[i].level;

            va_copy(args_copy, args);
            message = handler( doc, element, node, code, level, args_copy );
            va_end(args_copy);

            messageOut( message );

            if ( dispatchTable[i].next )
            {
                va_copy(args_copy, args);
                vReport(doc, element, node, dispatchTable[i].next, args_copy);
                va_end(args_copy);
            }
            break;
        }
        i++;
    }
}


/* This single Report output function uses the correct formatter with all
** possible, relevant data that can be reported. The only real drawbacks are
** having to pass NULL when some of the values aren't used, and the lack of
** type safety by using the variable arguments. To counter this some convenience
** report output functions exist, too. Any new reports you wish to create must
** be able to use this function signature, although convenience functions should
** be added to abstract the full fuction signature and to preserve type safety.
*/
void TY_(Report)(TidyDocImpl* doc, Node *element, Node *node, unsigned int code, ...)
{
    va_list args;
    va_start(args, code);
    vReport(doc, element, node, code, args);
    va_end(args);
}


/*********************************************************************
 * Convenience Reporting Functions
 * Functions that don't require the full signature of TY_(Report),
 * and help protect type safety by avoiding variable arguments in the
 * rest of Tidy's code.
 *********************************************************************/

void TY_(ReportAccessError)( TidyDocImpl* doc, Node* node, unsigned int code )
{
    TY_(Report)( doc, NULL, node, code );
}


void TY_(ReportAttrError)(TidyDocImpl* doc, Node *node, AttVal *av, unsigned int code)
{
    TY_(Report)( doc, NULL, node, code, av );
}


void TY_(ReportBadArgument)( TidyDocImpl* doc, ctmbstr option )
{
    assert( option != NULL );
    TY_(Report)( doc, NULL, NULL, STRING_MISSING_MALFORMED, option );
}


void TY_(ReportEntityError)( TidyDocImpl* doc, unsigned int code, ctmbstr entity, int ARG_UNUSED(c) )
{
    /* Note that the report formatter currently doesn't use argument c */
    TY_(Report)( doc, NULL, NULL, code, entity, c );
}


void TY_(ReportFileError)( TidyDocImpl* doc, ctmbstr file, unsigned int code )
{
    TY_(Report)( doc, NULL, NULL, code, file );
}


void TY_(ReportEncodingError)(TidyDocImpl* doc, unsigned int code, unsigned int c, Bool discarded)
{
    TY_(Report)( doc, NULL, NULL, code, c, discarded );
}

void TY_(ReportEncodingWarning)(TidyDocImpl* doc, unsigned int code, unsigned int encoding)
{
    /* va_list in formatter expects trailing `no` argument */
    TY_(Report)( doc, NULL, NULL, code, encoding, no );
}


void TY_(ReportMissingAttr)( TidyDocImpl* doc, Node* node, ctmbstr name )
{
    TY_(Report)( doc, NULL, node, MISSING_ATTRIBUTE, name );
}


void TY_(ReportSurrogateError)(TidyDocImpl* doc, unsigned int code, unsigned int c1, unsigned int c2)
{
    TY_(Report)( doc, NULL, NULL, code, c1,c2 );
}


void TY_(ReportUnknownOption)( TidyDocImpl* doc, ctmbstr option )
{
    /* lexer is not defined when this is called */
    TY_(Report)( doc, NULL, NULL, STRING_UNKNOWN_OPTION, option );
}


/*********************************************************************
 * Dialogue Output Functions
 * As for issuing reports, Tidy manages all dialogue output from a
 * single source in order to manage message categories in a simple
 * an consistent manner.
 *********************************************************************/


/* This structure ties together for each dialogue Code the default
** TidyReportLevel. This it makes it simple to output new dialogue
** messages, or to change report level by modifying this array.
*/
static struct _dialogueDispatchTable {
    unsigned int code;                 /**< The message code. */
    TidyReportLevel level;     /**< The default TidyReportLevel of the message. */
} dialogueDispatchTable[] = {
    { STRING_HELLO_ACCESS,         TidyDialogueInfo     }, /* AccessibilityChecks() */
    { TEXT_GENERAL_INFO,           TidyDialogueInfo     }, /* tidyGeneralInfo() */
    { TEXT_GENERAL_INFO_PLEA,      TidyDialogueInfo     }, /* tidyGeneralInfo() */
    
    { STRING_NEEDS_INTERVENTION,   TidyDialogueSummary  }, /* tidyDocRunDiagnostics() */
    { STRING_ERROR_COUNT,          TidyDialogueSummary  }, /* ReportNumWarnings() */
    { STRING_NO_ERRORS,            TidyDialogueSummary  }, /* ReportNumWarnings() */
    { STRING_NOT_ALL_SHOWN,        TidyDialogueSummary  }, /* ReportNumWarnings() */
    
    { FOOTNOTE_TRIM_EMPTY_ELEMENT, TidyDialogueFootnote },
    { TEXT_ACCESS_ADVICE1,         TidyDialogueFootnote }, /* errorSummary() */
    { TEXT_ACCESS_ADVICE2,         TidyDialogueFootnote },
    { TEXT_BAD_FORM,               TidyDialogueFootnote },
    { TEXT_BAD_MAIN,               TidyDialogueFootnote },
    { TEXT_HTML_T_ALGORITHM,       TidyDialogueFootnote },
    { TEXT_INVALID_URI,            TidyDialogueFootnote },
    { TEXT_INVALID_UTF8,           TidyDialogueFootnote },
    { TEXT_INVALID_UTF16,          TidyDialogueFootnote },
    { TEXT_M_IMAGE_ALT,            TidyDialogueFootnote },
    { TEXT_M_IMAGE_MAP,            TidyDialogueFootnote },
    { TEXT_M_LINK_ALT,             TidyDialogueFootnote },
    { TEXT_M_SUMMARY,              TidyDialogueFootnote },
    { TEXT_SGML_CHARS,             TidyDialogueFootnote },
    { TEXT_USING_BODY,             TidyDialogueFootnote },
    { TEXT_USING_FONT,             TidyDialogueFootnote },
    { TEXT_USING_FRAMES,           TidyDialogueFootnote },
    { TEXT_USING_LAYER,            TidyDialogueFootnote },
    { TEXT_USING_NOBR,             TidyDialogueFootnote },
    { TEXT_USING_SPACER,           TidyDialogueFootnote },
    { TEXT_VENDOR_CHARS,           TidyDialogueFootnote },
    
    { 0, 0 }
};


/* This message formatter for dialogue messages should be capable of formatting
** every message, because they're not all the complex and there aren't that
** many.
*/
TidyMessageImpl *formatDialogue( TidyDocImpl* doc, unsigned int code, TidyReportLevel level, va_list args )
{
    switch (code)
    {
        case TEXT_SGML_CHARS:
        case TEXT_VENDOR_CHARS:
        {
            ctmbstr str = va_arg(args, ctmbstr);
            return TY_(tidyMessageCreate)( doc, code, level, str );
        }
            
        case STRING_ERROR_COUNT:
        case STRING_NOT_ALL_SHOWN:
            return TY_(tidyMessageCreate)( doc, code, level,
                                           doc->warnings, tidyLocalizedStringN( STRING_ERROR_COUNT_WARNING, doc->warnings ),
                                           doc->errors, tidyLocalizedStringN( STRING_ERROR_COUNT_ERROR, doc->errors ) );

        case FOOTNOTE_TRIM_EMPTY_ELEMENT:
        case STRING_HELLO_ACCESS:
        case STRING_NEEDS_INTERVENTION:
        case STRING_NO_ERRORS:
        case TEXT_ACCESS_ADVICE1:
        case TEXT_ACCESS_ADVICE2:
        case TEXT_BAD_FORM:
        case TEXT_BAD_MAIN:
        case TEXT_GENERAL_INFO:
        case TEXT_GENERAL_INFO_PLEA:
        case TEXT_HTML_T_ALGORITHM:
        case TEXT_INVALID_URI:
        case TEXT_INVALID_UTF8:
        case TEXT_INVALID_UTF16:
        case TEXT_M_IMAGE_ALT:
        case TEXT_M_IMAGE_MAP:
        case TEXT_M_LINK_ALT:
        case TEXT_M_SUMMARY:
        case TEXT_USING_BODY:
        case TEXT_USING_FONT:
        case TEXT_USING_FRAMES:
        case TEXT_USING_LAYER:
        case TEXT_USING_NOBR:
        case TEXT_USING_SPACER:
        default:
            return TY_(tidyMessageCreate)( doc, code, level );
    }
    
    return NULL;
}


/* This single Dialogue output function determines the correct message level
** and formats the message with the appropriate formatter, and then outputs it.
** This one dialogue function should be sufficient for every use case.
*/
void TY_(Dialogue)(TidyDocImpl* doc, unsigned int code, ...)
{
    int i = 0;
    va_list args;

    while ( dialogueDispatchTable[i].code != 0 )
    {
        if ( dialogueDispatchTable[i].code == code )
        {
            TidyMessageImpl *message;
            TidyReportLevel level = dialogueDispatchTable[i].level;
            va_start(args, code);
            message = formatDialogue( doc, code, level, args );
            va_end(args);
            messageOut( message );
            break;
        }
        i++;
    }
}


/*********************************************************************
 * Output Dialogue Information
 * In addition to reports that are added to the table, Tidy emits
 * various dialogue type information. Most of these are specific to
 * exact circumstances, although `TY_(Dialogue)` should be used
 * instead of adding a new function, if possible.
 *********************************************************************/


/* Outputs the footnotes and other dialogue information after document cleanup
** is complete. LibTidy users might consider capturing these individually in
** the message callback rather than capturing this entire buffer.
** Called by tidyErrorSummary(), in console.
** @todo: This name is a bit misleading and should probably be renamed to
** indicate its focus on printing footnotes.
*/
void TY_(ErrorSummary)( TidyDocImpl* doc )
{
    ctmbstr encnam = tidyLocalizedString(STRING_SPECIFIED);
    int charenc = cfg( doc, TidyCharEncoding ); 
    if ( charenc == WIN1252 ) 
        encnam = "Windows-1252";
    else if ( charenc == MACROMAN )
        encnam = "MacRoman";
    else if ( charenc == IBM858 )
        encnam = "ibm858";
    else if ( charenc == LATIN0 )
        encnam = "latin0";

    /* adjust badAccess to that it is 0 if frames are ok */
    if ( doc->badAccess & (BA_USING_FRAMES | BA_USING_NOFRAMES) )
    {
        if (!((doc->badAccess & BA_USING_FRAMES) && !(doc->badAccess & BA_USING_NOFRAMES)))
        {
            doc->badAccess &= ~(BA_USING_FRAMES | BA_USING_NOFRAMES);
        }
    }

    if (doc->badChars)
    {
        if (doc->badChars & BC_VENDOR_SPECIFIC_CHARS)
            TY_(Dialogue)( doc, TEXT_VENDOR_CHARS, encnam );

        if ((doc->badChars & BC_INVALID_SGML_CHARS) || (doc->badChars & BC_INVALID_NCR))
            TY_(Dialogue)( doc, TEXT_SGML_CHARS, encnam );

        if (doc->badChars & BC_INVALID_UTF8)
            TY_(Dialogue)( doc, TEXT_INVALID_UTF8 );

        if (doc->badChars & BC_INVALID_UTF16)
            TY_(Dialogue)( doc, TEXT_INVALID_UTF16 );

        if (doc->badChars & BC_INVALID_URI)
            TY_(Dialogue)( doc, TEXT_INVALID_URI );
    }
    
    if (doc->badForm)
    {
        if (doc->badForm & flg_BadForm) /* Issue #166 - changed to BIT flag to support other errors */
            TY_(Dialogue)( doc, TEXT_BAD_FORM );

        if (doc->badForm & flg_BadMain) /* Issue #166 - repeated <main> element */
            TY_(Dialogue)( doc, TEXT_BAD_MAIN );
    }

    if (doc->badAccess)
    {
        /* Tidy "classic" accessibility tests */
        if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
        {
            if (doc->badAccess & BA_MISSING_SUMMARY)
                TY_(Dialogue)( doc, TEXT_M_SUMMARY );

            if (doc->badAccess & BA_MISSING_IMAGE_ALT)
                TY_(Dialogue)( doc, TEXT_M_IMAGE_ALT );

            if (doc->badAccess & BA_MISSING_IMAGE_MAP)
                TY_(Dialogue)( doc, TEXT_M_IMAGE_MAP );

            if (doc->badAccess & BA_MISSING_LINK_ALT)
                TY_(Dialogue)( doc, TEXT_M_LINK_ALT );

            if ((doc->badAccess & BA_USING_FRAMES) && !(doc->badAccess & BA_USING_NOFRAMES))
                TY_(Dialogue)( doc, TEXT_USING_FRAMES );
        }

        if ( cfg(doc, TidyAccessibilityCheckLevel) > 0 )
            TY_(Dialogue)( doc, TEXT_ACCESS_ADVICE2 );
        else
            TY_(Dialogue)( doc, TEXT_ACCESS_ADVICE1 );
    }

    if (doc->badLayout)
    {
        if (doc->badLayout & USING_LAYER)
            TY_(Dialogue)( doc, TEXT_USING_LAYER );

        if (doc->badLayout & USING_SPACER)
            TY_(Dialogue)( doc, TEXT_USING_SPACER );

        if (doc->badLayout & USING_FONT)
            TY_(Dialogue)( doc, TEXT_USING_FONT );

        if (doc->badLayout & USING_NOBR)
            TY_(Dialogue)( doc, TEXT_USING_NOBR );
        
        if (doc->badLayout & USING_BODY)
            TY_(Dialogue)( doc, TEXT_USING_BODY );
    }
    
    if (doc->footnotes)
    {
        if (doc->footnotes & FN_TRIM_EMPTY_ELEMENT)
            TY_(Dialogue)( doc, FOOTNOTE_TRIM_EMPTY_ELEMENT );
    }
}


/* Outputs document HTML version and version-related information. 
** Called by tidyRunDiagnostics(), from console.
** Called by tidyDocReportDoctype(), currently unused.
*/
void TY_(ReportMarkupVersion)( TidyDocImpl* doc )
{
    if ( doc->givenDoctype )
        TY_(Report)( doc, NULL, NULL, STRING_DOCTYPE_GIVEN, doc->givenDoctype );

    if ( ! cfgBool(doc, TidyXmlTags) )
    {
        Bool isXhtml = doc->lexer->isvoyager;
        unsigned int apparentVers = TY_(ApparentVersion)( doc );
        ctmbstr vers = TY_(HTMLVersionNameFromCode)( apparentVers, isXhtml );

        if ( !vers )
            vers = tidyLocalizedString(STRING_HTML_PROPRIETARY);

        TY_(Report)( doc, NULL, NULL, STRING_CONTENT_LOOKS, vers );

        /* Warn about missing sytem identifier (SI) in emitted doctype */
        if ( TY_(WarnMissingSIInEmittedDocType)( doc ) )
            TY_(Report)( doc, NULL, NULL, STRING_NO_SYSID );
    }
}


/* Reports the number of warnings and errors found in the document. 
** Called by tidyRunDiagnostics(), from console.
*/
void TY_(ReportNumWarnings)( TidyDocImpl* doc )
{
    if ( doc->warnings > 0 || doc->errors > 0 )
    {
        if ( doc->errors > cfg(doc, TidyShowErrors) || !cfgBool(doc, TidyShowWarnings) )
        {
            TY_(Dialogue)( doc, STRING_NOT_ALL_SHOWN );
        }
        else
        {
            TY_(Dialogue)( doc, STRING_ERROR_COUNT );
        }

    }
    else
    {
        TY_(Dialogue)( doc, STRING_NO_ERRORS );
    }
}


/*********************************************************************
 * Message Muting
 *********************************************************************/


void TY_(FreeMutedMessageList)( TidyDocImpl* doc )
{
    TidyMutedMessages *list = &(doc->muted);

    if ( list->list )
        TidyFree( doc->allocator, list->list );
}


void TY_(DefineMutedMessage)(TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name)
{
    enum { capacity = 10 };
    TidyMutedMessages *list = &(doc->muted);
    tidyStrings message = TY_(tidyErrorCodeFromKey)( name );

    if ( message <= REPORT_MESSAGE_FIRST || message >= REPORT_MESSAGE_LAST)
    {
        TY_(Report)( doc, NULL, NULL, STRING_ARGUMENT_BAD, opt->name, name );
        return;
    }

    if ( !list->list )
    {
        list->list = TidyAlloc(doc->allocator, sizeof(tidyStrings) * capacity );
        list->list[0] = 0;
        list->capacity = capacity;
        list->count = 0;
    }

    if ( list->count >= list->capacity )
    {
        list->capacity = list->capacity * 2;
        list->list = TidyRealloc(doc->allocator, list->list, sizeof(tidyStrings) * list->capacity + 1 );
    }

    list->list[list->count] = message;
    list->count++;
    list->list[list->count] = 0;

    /* Must come *after* adding to the list, in case it's muted, too. */
    TY_(Report)( doc, NULL, NULL, STRING_MUTING_TYPE, name );
}


TidyIterator TY_(getMutedMessageList)( TidyDocImpl* doc )
{
    TidyMutedMessages *list = &(doc->muted);
    size_t result = list->count > 0 ? 1 : 0;

    return (TidyIterator) result;
}


ctmbstr TY_(getNextMutedMessage)( TidyDocImpl* doc, TidyIterator* iter )
{
    TidyMutedMessages *list = &(doc->muted);
    size_t index;
    ctmbstr result = NULL;
    assert( iter != NULL );
    index = (size_t)*iter;

    if ( index > 0 && index <= list->count )
    {
        result = TY_(tidyErrorCodeAsKey)(list->list[index-1]);
        index++;
    }
    *iter = (TidyIterator) ( index <= list->count ? index : (size_t)0 );

    return result;
}


/*********************************************************************
 * Key Discovery
 *********************************************************************/


/*********************************************************************
 * LibTidy users may want to to enable their own localization lookup
 * lookup methods. Because Tidy's errors codes are enums, the actual
 * values can change over time. This table will the LibTidy users
 * always have a static value available for use.
 *
 * For macro documentation, refer to the comments in `tidyenum.h`.
 *********************************************************************/

typedef struct tidyStringsKeyItem {
    ctmbstr key;
    int value;
} tidyStringsKeyItem;

static const tidyStringsKeyItem tidyStringsKeys[] = {
    FOREACH_TIDYCONFIGCATEGORY(MAKE_STRUCT)
    FOREACH_MSG_MISC(MAKE_STRUCT)
    FOREACH_FOOTNOTE_MSG(MAKE_STRUCT)
    FOREACH_DIALOG_MSG(MAKE_STRUCT)
    FOREACH_REPORT_MSG(MAKE_STRUCT)
    FOREACH_ACCESS_MSG(MAKE_STRUCT)
#if SUPPORT_CONSOLE_APP
    FOREACH_MSG_CONSOLE(MAKE_STRUCT)
#endif
    { "TIDYSTRINGS_FIRST",                        TIDYSTRINGS_FIRST },
    { "TIDYSTRINGS_LAST",                         TIDYSTRINGS_LAST  },
    { NULL,                                       0                 },
};


/**
 *  Given an error code, return the string associated with it.
 */
ctmbstr TY_(tidyErrorCodeAsKey)(unsigned int code)
{
    unsigned int i = 0;
    while (tidyStringsKeys[i].key) {
        if ( tidyStringsKeys[i].value == code )
            return tidyStringsKeys[i].key;
        i++;
    }
    return "UNDEFINED";
}


/**
 *  Given an error code string, return its unsigned int.
 */
unsigned int TY_(tidyErrorCodeFromKey)(ctmbstr code)
{
    unsigned int i = 0;
    while (tidyStringsKeys[i].key) {
        if ( strcmp(tidyStringsKeys[i].key, code) == 0 )
            return tidyStringsKeys[i].value;
        i++;
    }
    return UINT_MAX;
}


/**
 *  Determines the number of error codes used by Tidy.
 */
static const unsigned int tidyErrorCodeListSize()
{
    static unsigned int array_size = 0;
    
    if ( array_size == 0 )
    {
        while ( tidyStringsKeys[array_size].key ) {
            array_size++;
        }
    }
    
    return array_size;
}

/**
 *  Initializes the TidyIterator to point to the first item
 *  in Tidy's list of error codes. Individual items must be
 *  retrieved with getNextErrorCode();
 */
TidyIterator TY_(getErrorCodeList)()
{
    return (TidyIterator)(size_t)1;
}

/**
 *  Returns the next error code.
 */
unsigned int TY_(getNextErrorCode)( TidyIterator* iter )
{
    const tidyStringsKeyItem *item = NULL;
    size_t itemIndex;
    assert( iter != NULL );
    
    itemIndex = (size_t)*iter;
    
    if ( itemIndex > 0 && itemIndex <= tidyErrorCodeListSize() )
    {
        item = &tidyStringsKeys[itemIndex - 1];
        itemIndex++;
    }
    
    *iter = (TidyIterator)( itemIndex <= tidyErrorCodeListSize() ? itemIndex : (size_t)0 );
    return item->value;
}


/*********************************************************************
 * Documentation of configuration options
 *
 * Although most of the strings now come from the language module,
 * generating the documentation by the console application requires a
 * series of cross-references that are generated in this messaging
 * module.
 *********************************************************************/


#if SUPPORT_CONSOLE_APP
/* Cross-references definitions.
 * Note that each list must be terminated with `TidyUnknownOption`.
 */
static const TidyOptionId TidyAsciiCharsLinks[] =      { TidyMakeClean, TidyUnknownOption };
static const TidyOptionId TidyBlockTagsLinks[] =       { TidyEmptyTags, TidyInlineTags, TidyPreTags, TidyUseCustomTags, TidyUnknownOption };
static const TidyOptionId TidyCharEncodingLinks[] =    { TidyInCharEncoding, TidyOutCharEncoding, TidyUnknownOption };
static const TidyOptionId TidyDuplicateAttrsLinks[] =  { TidyJoinClasses, TidyJoinStyles, TidyUnknownOption };
static const TidyOptionId TidyEmacsLinks[] =           { TidyShowFilename, TidyUnknownOption };
static const TidyOptionId TidyEmptyTagsLinks[] =       { TidyBlockTags, TidyInlineTags, TidyPreTags, TidyUseCustomTags, TidyUnknownOption };
static const TidyOptionId TidyErrFileLinks[] =         { TidyOutFile, TidyUnknownOption };
static const TidyOptionId TidyInCharEncodingLinks[] =  { TidyCharEncoding, TidyUnknownOption };
static const TidyOptionId TidyIndentContentLinks[] =   { TidyIndentSpaces, TidyUnknownOption };
static const TidyOptionId TidyIndentSpacesLinks[] =    { TidyIndentContent, TidyUnknownOption };
static const TidyOptionId TidyInlineTagsLinks[] =      { TidyBlockTags, TidyEmptyTags, TidyPreTags, TidyUseCustomTags, TidyUnknownOption };
static const TidyOptionId TidyMergeDivsLinks[] =       { TidyMakeClean, TidyMergeSpans, TidyUnknownOption };
static const TidyOptionId TidyMergeSpansLinks[] =      { TidyMakeClean, TidyMergeDivs, TidyUnknownOption };
static const TidyOptionId TidyMuteLinks[] =            { TidyMuteShow, TidyUnknownOption };
static const TidyOptionId TidyMuteShowLinks[] =        { TidyMuteReports, TidyUnknownOption };
static const TidyOptionId TidyNumEntitiesLinks[] =     { TidyDoctype, TidyPreserveEntities, TidyUnknownOption };
static const TidyOptionId TidyOutCharEncodingLinks[] = { TidyCharEncoding, TidyUnknownOption };
static const TidyOptionId TidyOutFileLinks[] =         { TidyErrFile, TidyUnknownOption };
static const TidyOptionId TidyPreTagsLinks[] =         { TidyBlockTags, TidyEmptyTags, TidyInlineTags, TidyUseCustomTags, TidyUnknownOption };
static const TidyOptionId TidyShowFilenameLinks[] =    { TidyEmacs, TidyUnknownOption };
static const TidyOptionId TidySortAttributesLinks[] =  { TidyPriorityAttributes, TidyUnknownOption };
static const TidyOptionId TidyUseCustomTagsLinks[] =   { TidyBlockTags, TidyEmptyTags, TidyInlineTags, TidyPreTags, TidyUnknownOption };
static const TidyOptionId TidyWrapAttValsLinks[] =     { TidyWrapScriptlets, TidyLiteralAttribs, TidyUnknownOption };
static const TidyOptionId TidyWrapScriptletsLinks[] =  { TidyWrapAttVals, TidyUnknownOption };
static const TidyOptionId TidyXmlDeclLinks[] =         { TidyCharEncoding, TidyOutCharEncoding, TidyUnknownOption };

/* Cross-reference assignments. 
 * We can't build a complex array at compile time and we're not counting on
 * any type of initialization, so this two-stage building process is required.
 */
static const TidyOptionDoc docs_xrefs[] =
{
    { TidyAsciiChars,      TidyAsciiCharsLinks      },
    { TidyBlockTags,       TidyBlockTagsLinks       },
    { TidyCharEncoding,    TidyCharEncodingLinks    },
    { TidyDuplicateAttrs,  TidyDuplicateAttrsLinks  },
    { TidyEmacs,           TidyEmacsLinks           },
    { TidyEmptyTags,       TidyEmptyTagsLinks       },
    { TidyErrFile,         TidyErrFileLinks         },
    { TidyInCharEncoding,  TidyInCharEncodingLinks  },
    { TidyIndentContent,   TidyIndentContentLinks   },
    { TidyIndentSpaces,    TidyIndentSpacesLinks    },
    { TidyInlineTags,      TidyInlineTagsLinks      },
    { TidyMergeDivs,       TidyMergeDivsLinks       },
    { TidyMergeSpans,      TidyMergeSpansLinks      },
    { TidyMuteShow,        TidyMuteShowLinks        },
    { TidyNumEntities,     TidyNumEntitiesLinks     },
    { TidyOutCharEncoding, TidyOutCharEncodingLinks },
    { TidyOutFile,         TidyOutFileLinks         },
    { TidyPreTags,         TidyPreTagsLinks         },
    { TidyShowFilename,    TidyShowFilenameLinks    },
    { TidySortAttributes,  TidySortAttributesLinks  },
    { TidyMuteReports,     TidyMuteLinks            },
    { TidyUseCustomTags,   TidyUseCustomTagsLinks   },
    { TidyWrapAttVals,     TidyWrapAttValsLinks     },
    { TidyWrapScriptlets,  TidyWrapScriptletsLinks  },
    { TidyXmlDecl,         TidyXmlDeclLinks         },
    { N_TIDY_OPTIONS                                }
};


/* Cross-reference retrieval. */
const TidyOptionDoc* TY_(OptGetDocDesc)( TidyOptionId optId )
{
    unsigned int i = 0;

    while( docs_xrefs[i].opt != N_TIDY_OPTIONS )
    {
        if ( docs_xrefs[i].opt == optId )
            return &docs_xrefs[i];
        ++i;
    }
    return NULL;
}

#endif /* SUPPORT_CONSOLE_APP */


/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* messageobj.c
 * Provides an external, extensible API for message reporting.
 *
 * (c) 2017 HTACG
 * See tidy.h for the copyright notice.
 */

/* #include "messageobj.h" */
/* #include "message.h" */
/* #include "tidy-int.h" */
/* #include "limits.h" */
/* #include "tmbstr.h" */


/*********************************************************************
 * BuildArgArray Support - declarations and forward declarations
 *********************************************************************/


/** A record of a single argument and its type. An array these
**  represents the arguments supplied to a format string, ordered
**  in the same position as they occur in the format string. Because
**  older versions of Windows don't support positional arguments,
**  Tidy doesn't either.
*/

#define FORMAT_LENGTH 21

struct printfArg {
    TidyFormatParameterType type;  /* type of the argument    */
    int formatStart;               /* where the format starts */
    int formatLength;              /* length of the format    */
    char format[FORMAT_LENGTH];    /* buffer for the format   */
    union {                        /* the argument            */
        int i;
        unsigned int ui;
        double d;
        const char *s;
    } u;
};



/** Returns a pointer to an allocated array of `printfArg` given a format
 ** string and a va_list, or NULL if not successful or no parameters were
 ** given. Parameter `rv` will return with the count of zero or more
 ** parameters if successful, else -1.
 **
 */
static struct printfArg *BuildArgArray( TidyDocImpl *doc, ctmbstr fmt, va_list ap, int *rv );


/*********************************************************************
 * Tidy Message Object Support
 *********************************************************************/


/** Create an internal representation of a Tidy message with all of
 ** the information that that we know about the message.
 **
 ** The function signature doesn't have to stay static and is a good
 ** place to add instantiation if expanding the API.
 **
 ** We currently know the doc, node, code, line, column, level, and
 ** args, will pre-calculate all of the other members upon creation.
 ** This ensures that we can use members directly, immediately,
 ** without having to use accessors internally.
 **
 ** If any message callback filters are setup by API clients, they
 ** will be called here.
 **
 ** This version serves as the designated initializer and as such
 ** requires every known parameter.
 */
static TidyMessageImpl *tidyMessageCreateInitV( TidyDocImpl *doc,
                                                Node *node,
                                                unsigned int code,
                                                int line,
                                                int column,
                                                TidyReportLevel level,
                                                va_list args )
{
    TidyMessageImpl *result = TidyDocAlloc(doc, sizeof(TidyMessageImpl));
    TidyDoc tdoc = tidyImplToDoc(doc);
    va_list args_copy;
    enum { sizeMessageBuf=2048 };
    ctmbstr pattern;
    unsigned int i = 0;


    /* Things we know... */

    result->tidyDoc = doc;
    result->tidyNode = node;
    result->code = code;
    result->line = line;
    result->column = column;
    result->level = level;
    /* Is #719 - set 'muted' before any callbacks. */
    result->muted = no;
    i = 0;
    while ((doc->muted.list) && (doc->muted.list[i] != 0))
    {
        if (doc->muted.list[i] == code)
        {
            result->muted = yes;
            break;
        }
        i++;
    }

    /* Things we create... */

    va_copy(args_copy, args);
    result->arguments = BuildArgArray(doc, tidyDefaultString(code), args_copy, &result->argcount);
    va_end(args_copy);

    result->messageKey = TY_(tidyErrorCodeAsKey)(code);

    result->messageFormatDefault = tidyDefaultString(code);
    result->messageFormat = tidyLocalizedString(code);

    result->messageDefault = TidyDocAlloc(doc, sizeMessageBuf);
    va_copy(args_copy, args);
    TY_(tmbvsnprintf)(result->messageDefault, sizeMessageBuf, result->messageFormatDefault, args_copy);
    va_end(args_copy);

    result->message = TidyDocAlloc(doc, sizeMessageBuf);
    va_copy(args_copy, args);
    TY_(tmbvsnprintf)(result->message, sizeMessageBuf, result->messageFormat, args_copy);
    va_end(args_copy);

    result->messagePosDefault = TidyDocAlloc(doc, sizeMessageBuf);
    result->messagePos = TidyDocAlloc(doc, sizeMessageBuf);

    if ( cfgBool(doc, TidyEmacs) && cfgStr(doc, TidyEmacsFile) )
    {
        /* Change formatting to be parsable by GNU Emacs */
        TY_(tmbsnprintf)(result->messagePosDefault, sizeMessageBuf, "%s:%d:%d: ", cfgStr(doc, TidyEmacsFile), line, column);
        TY_(tmbsnprintf)(result->messagePos, sizeMessageBuf, "%s:%d:%d: ", cfgStr(doc, TidyEmacsFile), line, column);
    }
    else if ( cfgBool(doc, TidyShowFilename) && cfgStr(doc, TidyEmacsFile) )
    {
        /* Include filename in output */
        TY_(tmbsnprintf)(result->messagePosDefault, sizeMessageBuf, tidyDefaultString(FN_LINE_COLUMN_STRING),
            cfgStr(doc, TidyEmacsFile), line, column);
        TY_(tmbsnprintf)(result->messagePos, sizeMessageBuf, tidyLocalizedString(FN_LINE_COLUMN_STRING),
            cfgStr(doc, TidyEmacsFile), line, column);
    }
    else
    {
        /* traditional format */
        TY_(tmbsnprintf)(result->messagePosDefault, sizeMessageBuf, tidyDefaultString(LINE_COLUMN_STRING), line, column);
        TY_(tmbsnprintf)(result->messagePos, sizeMessageBuf, tidyLocalizedString(LINE_COLUMN_STRING), line, column);
    }

    result->messagePrefixDefault = tidyDefaultString(level);

    result->messagePrefix = tidyLocalizedString(level);

    if ( line > 0 && column > 0 )
        pattern = "%s%s%s";      /* pattern if there's location information */
    else
        pattern = "%.0s%s%s";    /* otherwise if there isn't */

    if ( level > TidyFatal )
        pattern = "%.0s%.0s%s";  /* dialog doesn't have pos or prefix */

    result->messageOutputDefault = TidyDocAlloc(doc, sizeMessageBuf);
    TY_(tmbsnprintf)(result->messageOutputDefault, sizeMessageBuf, pattern,
                     result->messagePosDefault, result->messagePrefixDefault,
                     result->messageDefault);

    result->messageOutput = TidyDocAlloc(doc, sizeMessageBuf);
    TY_(tmbsnprintf)(result->messageOutput, sizeMessageBuf, pattern,
                     result->messagePos, result->messagePrefix,
                     result->message);

    if ( ( cfgBool(doc, TidyMuteShow) == yes ) && level <= TidyFatal )
    {
        /*\ Issue #655 - Unsafe to use output buffer as one of the va_list
         *  input parameters in some snprintf implmentations.
        \*/
        ctmbstr pc = TY_(tidyErrorCodeAsKey)(code);
        i = TY_(tmbstrlen)(result->messageOutputDefault);
        if (i < sizeMessageBuf)
            TY_(tmbsnprintf)(result->messageOutputDefault + i, sizeMessageBuf - i, " (%s)", pc );
        i = TY_(tmbstrlen)(result->messageOutput);
        if (i < sizeMessageBuf)
            TY_(tmbsnprintf)(result->messageOutput + i, sizeMessageBuf - i, " (%s)", pc );
        i = 0;
    }

    result->allowMessage = yes;

    /* reportFilter is a simple error filter that provides minimal information
       to callback functions, and includes the message buffer in LibTidy's
       configured localization. As it's a "legacy" API, it does not receive
       TidyDialogue messages.*/
    if ( (result->level <= TidyFatal) && doc->reportFilter )
    {
        result->allowMessage = result->allowMessage & doc->reportFilter( tdoc, result->level, result->line, result->column, result->messageOutput );
    }

    /* reportCallback is intended to allow LibTidy users to localize messages
       via their own means by providing a key and the parameters to fill it. 
       As it's a "legacy" API, it does not receive TidyDialogue messages. */
    if ( (result->level <= TidyFatal) && doc->reportCallback )
    {
        TidyDoc tdoc = tidyImplToDoc( doc );
        va_copy(args_copy, args);
        result->allowMessage = result->allowMessage & doc->reportCallback( tdoc, result->level, result->line, result->column, result->messageKey, args_copy );
        va_end(args_copy);
    }

    /* messageCallback is the newest interface to interrogate Tidy's
       emitted messages. */
    if ( doc->messageCallback )
    {
        result->allowMessage = result->allowMessage & doc->messageCallback( tidyImplToMessage(result) );
    }

    return result;
}


TidyMessageImpl *TY_(tidyMessageCreate)( TidyDocImpl *doc,
                                         unsigned int code,
                                         TidyReportLevel level,
                                         ... )
{
    TidyMessageImpl *result;
    va_list args;
    va_start(args, level);
    result = tidyMessageCreateInitV(doc, NULL, code, 0, 0, level, args);
    va_end(args);
    
    return result;
}


TidyMessageImpl *TY_(tidyMessageCreateWithNode)( TidyDocImpl *doc,
                                                 Node *node,
                                                 unsigned int code,
                                                 TidyReportLevel level,
                                                 ... )
{
    TidyMessageImpl *result;
    va_list args_copy;
    int line = ( node ? node->line :
                ( doc->lexer ? doc->lexer->lines : 0 ) );
    int col  = ( node ? node->column :
                ( doc->lexer ? doc->lexer->columns : 0 ) );
    
    va_start(args_copy, level);
    result = tidyMessageCreateInitV(doc, node, code, line, col, level, args_copy);
    va_end(args_copy);
    
    return result;
}


TidyMessageImpl *TY_(tidyMessageCreateWithLexer)( TidyDocImpl *doc,
                                                  unsigned int code,
                                                  TidyReportLevel level,
                                                  ... )
{
    TidyMessageImpl *result;
    va_list args_copy;
    int line = ( doc->lexer ? doc->lexer->lines : 0 );
    int col  = ( doc->lexer ? doc->lexer->columns : 0 );
    
    va_start(args_copy, level);
    result = tidyMessageCreateInitV(doc, NULL, code, line, col, level, args_copy);
    va_end(args_copy);
    
    return result;
}


void TY_(tidyMessageRelease)( TidyMessageImpl *message )
{
    if ( !message )
        return;
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->arguments );
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messageDefault );
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->message );
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messagePosDefault );
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messagePos );
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messageOutputDefault );
    TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messageOutput );
    TidyDocFree(tidyDocToImpl(message->tidyDoc), message); /* Issue #597 - and discard the message structure */
}


/*********************************************************************
 * Modern Message Callback Functions
 *********************************************************************/


TidyDocImpl* TY_(getMessageDoc)( TidyMessageImpl message )
{
    return message.tidyDoc;
}

unsigned int TY_(getMessageCode)( TidyMessageImpl message )
{
    return message.code;
}

ctmbstr TY_(getMessageKey)( TidyMessageImpl message )
{
    return message.messageKey;
}

int TY_(getMessageLine)( TidyMessageImpl message )
{
    return message.line;
}

int TY_(getMessageColumn)( TidyMessageImpl message )
{
    return message.column;
}

TidyReportLevel TY_(getMessageLevel)( TidyMessageImpl message )
{
    return message.level;
}

Bool TY_(getMessageIsMuted)( TidyMessageImpl message )
{
    return message.muted;
}

ctmbstr TY_(getMessageFormatDefault)( TidyMessageImpl message )
{
    return message.messageFormatDefault;
}

ctmbstr TY_(getMessageFormat)( TidyMessageImpl message )
{
    return message.messageFormat;
}

ctmbstr TY_(getMessageDefault)( TidyMessageImpl message )
{
    return message.messageDefault;
}

ctmbstr TY_(getMessage)( TidyMessageImpl message )
{
    return message.message;
}

ctmbstr TY_(getMessagePosDefault)( TidyMessageImpl message )
{
    return message.messagePosDefault;
}

ctmbstr TY_(getMessagePos)( TidyMessageImpl message )
{
    return message.messagePos;
}

ctmbstr TY_(getMessagePrefixDefault)( TidyMessageImpl message )
{
    return message.messagePrefixDefault;
}

ctmbstr TY_(getMessagePrefix)( TidyMessageImpl message )
{
    return message.messagePrefix;
}


ctmbstr TY_(getMessageOutputDefault)( TidyMessageImpl message )
{
    return message.messageOutputDefault;
}

ctmbstr TY_(getMessageOutput)( TidyMessageImpl message )
{
    return message.messageOutput;
}


/*********************************************************************
 * Message Argument Interrogation
 *********************************************************************/


TidyIterator TY_(getMessageArguments)( TidyMessageImpl message )
{
    if (message.argcount > 0)
        return (TidyIterator) (size_t)1;
    else
        return (TidyIterator) (size_t)0;
}

TidyMessageArgument TY_(getNextMessageArgument)( TidyMessageImpl message, TidyIterator* iter )
{
    size_t item = 0;
    size_t itemIndex;
    assert( iter != NULL );
    
    itemIndex = (size_t)*iter;
    
    if ( itemIndex >= 1 && itemIndex <= (size_t)message.argcount )
    {
        item = itemIndex;
        itemIndex++;
    }
    
    /* Just as TidyIterator is really just a dumb, one-based index, the
       TidyMessageArgument is really just a dumb, zero-based index; however
       this type of iterator and opaque interrogation is simply how Tidy
       does things. */
    *iter = (TidyIterator)( itemIndex <= (size_t)message.argcount ? itemIndex : (size_t)0 );
    return (TidyMessageArgument)item;
}


TidyFormatParameterType TY_(getArgType)( TidyMessageImpl message, TidyMessageArgument* arg )
{
    int argNum = (int)(size_t)*arg - 1;
    assert( argNum <= message.argcount );
    
    return message.arguments[argNum].type;
}


ctmbstr TY_(getArgFormat)( TidyMessageImpl message, TidyMessageArgument* arg )
{
    int argNum = (int)(size_t)*arg - 1;
    assert( argNum <= message.argcount );
    
    return message.arguments[argNum].format;
}


ctmbstr TY_(getArgValueString)( TidyMessageImpl message, TidyMessageArgument* arg )
{
    int argNum = (int)(size_t)*arg - 1;
    assert( argNum <= message.argcount );
    assert( message.arguments[argNum].type == tidyFormatType_STRING);
    
    return message.arguments[argNum].u.s;
}


unsigned int TY_(getArgValueUInt)( TidyMessageImpl message, TidyMessageArgument* arg )
{
    int argNum = (int)(size_t)*arg - 1;
    assert( argNum <= message.argcount );
    assert( message.arguments[argNum].type == tidyFormatType_UINT);

    return message.arguments[argNum].u.ui;
}


int TY_(getArgValueInt)( TidyMessageImpl message, TidyMessageArgument* arg )
{
    int argNum = (int)(size_t)*arg - 1;
    assert( argNum <= message.argcount );
    assert( message.arguments[argNum].type == tidyFormatType_INT);

    return message.arguments[argNum].u.i;
}


double TY_(getArgValueDouble)( TidyMessageImpl message, TidyMessageArgument* arg )
{
    int argNum = (int)(size_t)*arg - 1;
    assert( argNum <= message.argcount );
    assert( message.arguments[argNum].type == tidyFormatType_DOUBLE);
    
    return message.arguments[argNum].u.d;
}



/*********************************************************************
 * BuildArgArray support
 * Adapted loosely from Mozilla `prprf.c`, Mozilla Public License:
 *   - https://www.mozilla.org/en-US/MPL/2.0/
 *********************************************************************/


/** Returns a pointer to an allocated array of `printfArg` given a format
 ** string and a va_list, or NULL if not successful or no parameters were
 ** given. Parameter `rv` will return with the count of zero or more
 ** parameters if successful, else -1.
 **
 ** We'll also be sure to use the document's allocator if specified, thus
 ** the requirement to pass in a TidyDocImpl.
 **
 ** Currently Tidy only uses %c, %d, %s, %u, %X, although doubles are
 ** supported as well. Unsupported arguments will result in failure as
 ** described above.
 */
static struct printfArg* BuildArgArray( TidyDocImpl *doc, ctmbstr fmt, va_list ap, int* rv )
{
    int number = 0; /* the quantity of valid arguments found; returned as rv. */
    int cn = -1;    /* keeps track of which parameter index is current. */
    int i = 0;      /* typical index. */
    int pos = -1;   /* starting position of current argument. */
    const char* p;  /* current position in format string. */
    char c;         /* current character. */
    struct printfArg* nas;
    
    /* first pass: determine number of valid % to allocate space. */
    
    p = fmt;
    *rv = 0;
    
    while( ( c = *p++ ) != 0 )
    {
        if( c != '%' )
            continue;
        
        if( ( c = *p++ ) == '%' )	/* skip %% case */
            continue;
        else
            number++;
    }
        

    if( number == 0 )
        return NULL;

    
    nas = (struct printfArg*)TidyDocAlloc( doc, number * sizeof( struct printfArg ) );
    if( !nas )
    {
        *rv = -1;
        return NULL;
    }


    for( i = 0; i < number; i++ )
    {
        nas[i].type = tidyFormatType_UNKNOWN;
    }
    
    
    /* second pass: set nas[].type and location. */
    
    p = fmt;
    while( ( c = *p++ ) != 0 )
    {
        if( c != '%' )
            continue;
        
        if( ( c = *p++ ) == '%' )
            continue; /* skip %% case */

        pos = p - fmt - 2; /* p already incremented twice */

        /* width -- width via parameter */
        if (c == '*')
        {
            /* not supported feature */
            *rv = -1;
            break;
        }
        
        /* width field -- skip */
        while ((c >= '0') && (c <= '9'))
        {
            c = *p++;
        }
        
        /* precision */
        if (c == '.')
        {
            c = *p++;
            if (c == '*') {
                /* not supported feature */
                *rv = -1;
                break;
            }
            
            while ((c >= '0') && (c <= '9'))
            {
                c = *p++;
            }
        }
        
        
        cn++;
        
        /* size and format */
        nas[cn].type = tidyFormatType_UINT;
        switch (c)
        {
            case 'c': /* unsigned int (char) */
            case 'u': /* unsigned int */
            case 'X': /* unsigned int as hex */
            case 'x': /* unsigned int as hex */
            case 'o': /* octal */
                nas[cn].u.ui = va_arg( ap, unsigned int );
                break;

            case 'd': /* signed int */
            case 'i': /* signed int */
                nas[cn].type = tidyFormatType_INT;
                nas[cn].u.i = va_arg( ap, int );
                break;


            case 's': /* string */
                nas[cn].type = tidyFormatType_STRING;
                nas[cn].u.s = va_arg( ap, char* );
                break;

            case 'e': /* double */
            case 'E': /* double */
            case 'f': /* double */
            case 'F': /* double */
            case 'g': /* double */
            case 'G': /* double */
                nas[cn].type = tidyFormatType_DOUBLE;
                nas[cn].u.d = va_arg( ap, double );
                break;

            default:
                nas[cn].type = tidyFormatType_UNKNOWN;
                *rv = -1;
                break;
        }

        /* position and format */
        nas[cn].formatStart = pos;
        nas[cn].formatLength = (p - fmt) - pos;
        
        /* the format string exceeds the buffer length */
        if ( nas[cn].formatLength >= FORMAT_LENGTH )
        {
            *rv = -1;
            break;
        }
        else
        {
            strncpy(nas[cn].format, fmt + nas[cn].formatStart, nas[cn].formatLength);
        }
        

        /* Something's not right. */
        if( nas[cn].type == tidyFormatType_UNKNOWN )
        {
            *rv = -1;
            break;
        }
    }
    
    
    /* third pass: fill the nas[cn].ap */
    
    if( *rv < 0 )
    {
        TidyDocFree( doc, nas );;
        return NULL;
    }

    *rv = number;
    return nas;
}

/* parser.c -- HTML Parser

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "tidy-int.h" */
/* #include "lexer.h" */
/* #include "parser.h" */
/* #include "message.h" */
/* #include "clean.h" */
/* #include "tags.h" */
/* #include "tmbstr.h" */
/* #include "sprtf.h" */

/*
  Issue #72 - Need to know to avoid error-reporting - no warning only if --show-body-only yes
  Issue #132 - likewise avoid warning if showing body only
 */
#define showingBodyOnly(doc) (cfgAutoBool(doc,TidyBodyOnly) == TidyYesState) ? yes : no


Bool TY_(CheckNodeIntegrity)(Node *node)
{
#ifndef NO_NODE_INTEGRITY_CHECK
    Node *child;

    if (node->prev)
    {
        if (node->prev->next != node)
            return no;
    }

    if (node->next)
    {
        if (node->next == node || node->next->prev != node)
            return no;
    }

    if (node->parent)
    {
        if (node->prev == NULL && node->parent->content != node)
            return no;

        if (node->next == NULL && node->parent->last != node)
            return no;
    }

    for (child = node->content; child; child = child->next)
        if ( child->parent != node || !TY_(CheckNodeIntegrity)(child) )
            return no;

#endif
    return yes;
}

/*
 used to determine how attributes
 without values should be printed
 this was introduced to deal with
 user defined tags e.g. ColdFusion
*/
Bool TY_(IsNewNode)(Node *node)
{
    if (node && node->tag)
    {
        return (node->tag->model & CM_NEW);
    }
    return yes;
}

void TY_(CoerceNode)(TidyDocImpl* doc, Node *node, TidyTagId tid, Bool obsolete, Bool unexpected)
{
    const Dict* tag = TY_(LookupTagDef)(tid);
    Node* tmp = TY_(InferredTag)(doc, tag->id);

    if (obsolete)
        TY_(Report)(doc, node, tmp, OBSOLETE_ELEMENT);
    else if (unexpected)
        TY_(Report)(doc, node, tmp, REPLACING_UNEX_ELEMENT);
    else
        TY_(Report)(doc, node, tmp, REPLACING_ELEMENT);

    TidyDocFree(doc, tmp->element);
    TidyDocFree(doc, tmp);

    node->was = node->tag;
    node->tag = tag;
    node->type = StartTag;
    node->implicit = yes;
    TidyDocFree(doc, node->element);
    node->element = TY_(tmbstrdup)(doc->allocator, tag->name);
}

/* extract a node and its children from a markup tree */
Node *TY_(RemoveNode)(Node *node)
{
    if (node->prev)
        node->prev->next = node->next;

    if (node->next)
        node->next->prev = node->prev;

    if (node->parent)
    {
        if (node->parent->content == node)
            node->parent->content = node->next;

        if (node->parent->last == node)
            node->parent->last = node->prev;
    }

    node->parent = node->prev = node->next = NULL;
    return node;
}

/* remove node from markup tree and discard it */
Node *TY_(DiscardElement)( TidyDocImpl* doc, Node *element )
{
    Node *next = NULL;

    if (element)
    {
        next = element->next;
        TY_(RemoveNode)(element);
        TY_(FreeNode)( doc, element);
    }

    return next;
}

/*
 insert "node" into markup tree as the firt element
 of content of "element"
*/
void TY_(InsertNodeAtStart)(Node *element, Node *node)
{
    node->parent = element;

    if (element->content == NULL)
        element->last = node;
    else
        element->content->prev = node;

    node->next = element->content;
    node->prev = NULL;
    element->content = node;
}

/*
 insert "node" into markup tree as the last element
 of content of "element"
*/
void TY_(InsertNodeAtEnd)(Node *element, Node *node)
{
    node->parent = element;
    node->prev = element->last;

    if (element->last != NULL)
        element->last->next = node;
    else
        element->content = node;

    element->last = node;
}

/*
 insert "node" into markup tree in place of "element"
 which is moved to become the child of the node
*/
static void InsertNodeAsParent(Node *element, Node *node)
{
    node->content = element;
    node->last = element;
    node->parent = element->parent;
    element->parent = node;

    if (node->parent->content == element)
        node->parent->content = node;

    if (node->parent->last == element)
        node->parent->last = node;

    node->prev = element->prev;
    element->prev = NULL;

    if (node->prev)
        node->prev->next = node;

    node->next = element->next;
    element->next = NULL;

    if (node->next)
        node->next->prev = node;
}

/* insert "node" into markup tree before "element" */
void TY_(InsertNodeBeforeElement)(Node *element, Node *node)
{
    Node *parent;

    parent = element->parent;
    node->parent = parent;
    node->next = element;
    node->prev = element->prev;
    element->prev = node;

    if (node->prev)
        node->prev->next = node;

    if (parent->content == element)
        parent->content = node;
}

/* insert "node" into markup tree after "element" */
void TY_(InsertNodeAfterElement)(Node *element, Node *node)
{
    Node *parent;

    parent = element->parent;
    node->parent = parent;

    /* AQ - 13 Jan 2000 fix for parent == NULL */
    if (parent != NULL && parent->last == element)
        parent->last = node;
    else
    {
        node->next = element->next;
        /* AQ - 13 Jan 2000 fix for node->next == NULL */
        if (node->next != NULL)
            node->next->prev = node;
    }

    element->next = node;
    node->prev = element;
}

static Bool CanPrune( TidyDocImpl* doc, Node *element )
{
    if ( !cfgBool(doc, TidyDropEmptyElems) )
        return no;

    if ( TY_(nodeIsText)(element) )
        return yes;

    if ( element->content )
        return no;

    if ( element->tag == NULL )
        return no;

    if ( element->tag->model & CM_BLOCK && element->attributes != NULL )
        return no;

    if ( nodeIsA(element) && element->attributes != NULL )
        return no;

    if ( nodeIsP(element) && !cfgBool(doc, TidyDropEmptyParas) )
        return no;

    if ( element->tag->model & CM_ROW )
        return no;

    if ( element->tag->model & CM_EMPTY )
        return no;

    if ( nodeIsAPPLET(element) )
        return no;

    if ( nodeIsOBJECT(element) )
        return no;

    if ( nodeIsSCRIPT(element) && attrGetSRC(element) )
        return no;

    if ( nodeIsTITLE(element) )
        return no;

    /* #433359 - fix by Randy Waki 12 Mar 01 */
    if ( nodeIsIFRAME(element) )
        return no;

    /* fix for bug 770297 */
    if (nodeIsTEXTAREA(element))
        return no;

    /* fix for ISSUE #7 https://github.com/w3c/tidy-html5/issues/7 */
    if (nodeIsCANVAS(element))
        return no;
    
    if (nodeIsPROGRESS(element))
        return no;

    if ( attrGetID(element) || attrGetNAME(element) )
        return no;

    /* fix for bug 695408; a better fix would look for unknown and    */
    /* known proprietary attributes that make the element significant */
    if (attrGetDATAFLD(element))
        return no;

    /* fix for bug 723772, don't trim new-...-tags */
    if (element->tag->id == TidyTag_UNKNOWN)
        return no;

    if (nodeIsBODY(element))
        return no;

    if (nodeIsCOLGROUP(element))
        return no;

    /* HTML5 - do NOT drop empty option if it has attributes */
    if ( nodeIsOPTION(element) && element->attributes != NULL )
        return no;

    /* fix for #103 - don't drop empty dd tags lest document not validate */
    if (nodeIsDD(element))
        return no;

    return yes;
}

/* return next element */
Node *TY_(TrimEmptyElement)( TidyDocImpl* doc, Node *element )
{
    if ( CanPrune(doc, element) )
    {
        if (element->type != TextNode)
        {
            doc->footnotes |= FN_TRIM_EMPTY_ELEMENT;
            TY_(Report)(doc, element, NULL, TRIM_EMPTY_ELEMENT);
        }
        
        return TY_(DiscardElement)(doc, element);
    }
    return element->next;
}

Node* TY_(DropEmptyElements)(TidyDocImpl* doc, Node* node)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (node->content)
            TY_(DropEmptyElements)(doc, node->content);

        if (!TY_(nodeIsElement)(node) &&
            !(TY_(nodeIsText)(node) && !(node->start < node->end)))
        {
            node = next;
            continue;
        }

        next = TY_(TrimEmptyElement)(doc, node);
        node = next;
    }

    return node;
}

/* 
  errors in positioning of form start or end tags
  generally require human intervention to fix
  Issue #166 - repeated <main> element also uses this flag
  to indicate duplicates, discarded
*/
static void BadForm( TidyDocImpl* doc )
{
    doc->badForm |= flg_BadForm;
    /* doc->errors++; */
}

/*
  This maps 
       <em>hello </em><strong>world</strong>
  to
       <em>hello</em> <strong>world</strong>

  If last child of element is a text node
  then trim trailing white space character
  moving it to after element's end tag.
*/
static void TrimTrailingSpace( TidyDocImpl* doc, Node *element, Node *last )
{
    Lexer* lexer = doc->lexer;
    byte c;

    if (TY_(nodeIsText)(last))
    {
        if (last->end > last->start)
        {
            c = (byte) lexer->lexbuf[ last->end - 1 ];

            if ( c == ' ' )
            {
                last->end -= 1;
                if ( (element->tag->model & CM_INLINE) &&
                     !(element->tag->model & CM_FIELD) )
                    lexer->insertspace = yes;
            }
        }
    }
}

/* Only true for text nodes. */
Bool TY_(IsBlank)(Lexer *lexer, Node *node)
{
    Bool isBlank = TY_(nodeIsText)(node);
    if ( isBlank )
        isBlank = ( node->end == node->start ||       /* Zero length */
                    ( node->end == node->start+1      /* or one blank. */
                      && lexer->lexbuf[node->start] == ' ' ) );
    return isBlank;
}

/*
  This maps 
       <p>hello<em> world</em>
  to
       <p>hello <em>world</em>

  Trims initial space, by moving it before the
  start tag, or if this element is the first in
  parent's content, then by discarding the space
*/
static void TrimInitialSpace( TidyDocImpl* doc, Node *element, Node *text )
{
    Lexer* lexer = doc->lexer;
    Node *prev, *node;

    if ( TY_(nodeIsText)(text) && 
         lexer->lexbuf[text->start] == ' ' && 
         text->start < text->end )
    {
        if ( (element->tag->model & CM_INLINE) &&
             !(element->tag->model & CM_FIELD) )
        {
            prev = element->prev;

            if (TY_(nodeIsText)(prev))
            {
                if (prev->end == 0 || lexer->lexbuf[prev->end - 1] != ' ')
                    lexer->lexbuf[(prev->end)++] = ' ';

                ++(element->start);
            }
            else /* create new node */
            {
                node = TY_(NewNode)(lexer->allocator, lexer);
                node->start = (element->start)++;
                node->end = element->start;
                lexer->lexbuf[node->start] = ' ';
                TY_(InsertNodeBeforeElement)(element ,node);
                DEBUG_LOG(SPRTF("TrimInitialSpace: Created text node, inserted before <%s>\n",
                    (element->element ? element->element : "unknown")));
            }
        }

        /* discard the space in current node */
        ++(text->start);
    }
}

static Bool IsPreDescendant(Node* node)
{
    Node *parent = node->parent;

    while (parent)
    {
        if (parent->tag && parent->tag->parser == TY_(ParsePre))
            return yes;

        parent = parent->parent;
    }

    return no;
}

static Bool CleanTrailingWhitespace(TidyDocImpl* doc, Node* node)
{
    Node* next;

    if (!TY_(nodeIsText)(node))
        return no;

    if (node->parent->type == DocTypeTag)
        return no;

    if (IsPreDescendant(node))
        return no;

    if (node->parent->tag && node->parent->tag->parser == TY_(ParseScript))
        return no;

    next = node->next;

    /* <p>... </p> */
    if (!next && !TY_(nodeHasCM)(node->parent, CM_INLINE))
        return yes;

    /* <div><small>... </small><h3>...</h3></div> */
    if (!next && node->parent->next && !TY_(nodeHasCM)(node->parent->next, CM_INLINE))
        return yes;

    if (!next)
        return no;

    if (nodeIsBR(next))
        return yes;

    if (TY_(nodeHasCM)(next, CM_INLINE))
        return no;

    /* <a href='/'>...</a> <p>...</p> */
    if (next->type == StartTag)
        return yes;

    /* <strong>...</strong> <hr /> */
    if (next->type == StartEndTag)
        return yes;

    /* evil adjacent text nodes, Tidy should not generate these :-( */
    if (TY_(nodeIsText)(next) && next->start < next->end
        && TY_(IsWhite)(doc->lexer->lexbuf[next->start]))
        return yes;

    return no;
}

static Bool CleanLeadingWhitespace(TidyDocImpl* ARG_UNUSED(doc), Node* node)
{
    if (!TY_(nodeIsText)(node))
        return no;

    if (node->parent->type == DocTypeTag)
        return no;

    if (IsPreDescendant(node))
        return no;

    if (node->parent->tag && node->parent->tag->parser == TY_(ParseScript))
        return no;

    /* <p>...<br> <em>...</em>...</p> */
    if (nodeIsBR(node->prev))
        return yes;

    /* <p> ...</p> */
    if (node->prev == NULL && !TY_(nodeHasCM)(node->parent, CM_INLINE))
        return yes;

    /* <h4>...</h4> <em>...</em> */
    if (node->prev && !TY_(nodeHasCM)(node->prev, CM_INLINE) &&
        TY_(nodeIsElement)(node->prev))
        return yes;

    /* <p><span> ...</span></p> */
    if (!node->prev && !node->parent->prev && !TY_(nodeHasCM)(node->parent->parent, CM_INLINE))
        return yes;

    return no;
}

static void CleanSpaces(TidyDocImpl* doc, Node* node)
{
    Node* next;

    while (node)
    {
        next = node->next;

        if (TY_(nodeIsText)(node) && CleanLeadingWhitespace(doc, node))
            while (node->start < node->end && TY_(IsWhite)(doc->lexer->lexbuf[node->start]))
                ++(node->start);

        if (TY_(nodeIsText)(node) && CleanTrailingWhitespace(doc, node))
            while (node->end > node->start && TY_(IsWhite)(doc->lexer->lexbuf[node->end - 1]))
                --(node->end);

        if (TY_(nodeIsText)(node) && !(node->start < node->end))
        {
            TY_(RemoveNode)(node);
            TY_(FreeNode)(doc, node);
            node = next;

            continue;
        }

        if (node->content)
            CleanSpaces(doc, node->content);

        node = next;
    }
}

/* 
  Move initial and trailing space out.
  This routine maps:

       hello<em> world</em>
  to
       hello <em>world</em>
  and
       <em>hello </em><strong>world</strong>
  to
       <em>hello</em> <strong>world</strong>
*/
static void TrimSpaces( TidyDocImpl* doc, Node *element)
{
    Node* text = element->content;

    if (nodeIsPRE(element) || IsPreDescendant(element))
        return;

    if (TY_(nodeIsText)(text))
        TrimInitialSpace(doc, element, text);

    text = element->last;

    if (TY_(nodeIsText)(text))
        TrimTrailingSpace(doc, element, text);
}

static Bool DescendantOf( Node *element, TidyTagId tid )
{
    Node *parent;
    for ( parent = element->parent;
          parent != NULL;
          parent = parent->parent )
    {
        if ( TagIsId(parent, tid) )
            return yes;
    }
    return no;
}

static Bool InsertMisc(Node *element, Node *node)
{
    if (node->type == CommentTag ||
        node->type == ProcInsTag ||
        node->type == CDATATag ||
        node->type == SectionTag ||
        node->type == AspTag ||
        node->type == JsteTag ||
        node->type == PhpTag )
    {
        TY_(InsertNodeAtEnd)(element, node);
        return yes;
    }

    if ( node->type == XmlDecl )
    {
        Node* root = element;
        while ( root && root->parent )
            root = root->parent;
        if ( root && !(root->content && root->content->type == XmlDecl))
        {
          TY_(InsertNodeAtStart)( root, node );
          return yes;
        }
    }

    /* Declared empty tags seem to be slipping through
    ** the cracks.  This is an experiment to figure out
    ** a decent place to pick them up.
    */
    if ( node->tag &&
         TY_(nodeIsElement)(node) &&
         TY_(nodeCMIsEmpty)(node) && TagId(node) == TidyTag_UNKNOWN &&
         (node->tag->versions & VERS_PROPRIETARY) != 0 )
    {
        TY_(InsertNodeAtEnd)(element, node);
        return yes;
    }

    return no;
}


static void ParseTag( TidyDocImpl* doc, Node *node, GetTokenMode mode )
{
    Lexer* lexer = doc->lexer;

    if (node->tag == NULL) /* [i_a]2 prevent crash for active content (php, asp) docs */
        return;

    /*
       Fix by GLP 2000-12-21.  Need to reset insertspace if this 
       is both a non-inline and empty tag (base, link, meta, isindex, hr, area).
    */
    if (node->tag->model & CM_EMPTY)
    {
        lexer->waswhite = no;
        if (node->tag->parser == NULL)
            return;
    }
    else if (!(node->tag->model & CM_INLINE))
        lexer->insertspace = no;

    if (node->tag->parser == NULL)
        return;

    if (node->type == StartEndTag)
        return;

    lexer->parent = node; /* [i_a]2 added this - not sure why - CHECKME: */

    (*node->tag->parser)( doc, node, mode );
}

/*
 the doctype has been found after other tags,
 and needs moving to before the html element
*/
static void InsertDocType( TidyDocImpl* doc, Node *element, Node *doctype )
{
    Node* existing = TY_(FindDocType)( doc );
    if ( existing )
    {
        TY_(Report)(doc, element, doctype, DISCARDING_UNEXPECTED );
        TY_(FreeNode)( doc, doctype );
    }
    else
    {
        TY_(Report)(doc, element, doctype, DOCTYPE_AFTER_TAGS );
        while ( !nodeIsHTML(element) )
            element = element->parent;
        TY_(InsertNodeBeforeElement)( element, doctype );
    }
}

/*
 move node to the head, where element is used as starting
 point in hunt for head. normally called during parsing
*/
static void MoveToHead( TidyDocImpl* doc, Node *element, Node *node )
{
    Node *head;

    TY_(RemoveNode)( node );  /* make sure that node is isolated */

    if ( TY_(nodeIsElement)(node) )
    {
        TY_(Report)(doc, element, node, TAG_NOT_ALLOWED_IN );

        head = TY_(FindHEAD)(doc);
        assert(head != NULL);

        TY_(InsertNodeAtEnd)(head, node);

        if ( node->tag->parser )
            ParseTag( doc, node, IgnoreWhitespace );
    }
    else
    {
        TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node );
    }
}

/* moves given node to end of body element */
static void MoveNodeToBody( TidyDocImpl* doc, Node* node )
{
    Node* body = TY_(FindBody)( doc );
    if ( body )
    {
        TY_(RemoveNode)( node );
        TY_(InsertNodeAtEnd)( body, node );
    }
}

static void AddClassNoIndent( TidyDocImpl* doc, Node *node )
{
    ctmbstr sprop =
        "padding-left: 2ex; margin-left: 0ex"
        "; margin-top: 0ex; margin-bottom: 0ex";
    if ( !cfgBool(doc, TidyDecorateInferredUL) )
        return;
    if ( cfgBool(doc, TidyMakeClean) )
        TY_(AddStyleAsClass)( doc, node, sprop );
    else
        TY_(AddStyleProperty)( doc, node, sprop );
}

/*
   element is node created by the lexer
   upon seeing the start tag, or by the
   parser when the start tag is inferred
*/
void TY_(ParseBlock)( TidyDocImpl* doc, Node *element, GetTokenMode mode)
{
#if defined(ENABLE_DEBUG_LOG)
    static int in_parse_block = 0;
    static int parse_block_cnt = 0;
#endif
    Lexer* lexer = doc->lexer;
    Node *node;
    Bool checkstack = yes;
    unsigned int istackbase = 0;
#if defined(ENABLE_DEBUG_LOG)
    in_parse_block++;
    parse_block_cnt++;
    SPRTF("Entering ParseBlock %d... %d %s\n",in_parse_block,parse_block_cnt,
        ((element && element->element) ? element->element : ""));
#endif

    if ( element->tag->model & CM_EMPTY ) {
#if defined(ENABLE_DEBUG_LOG)
        in_parse_block--;
        SPRTF("Exit ParseBlockL 1 %d...\n",in_parse_block);
#endif
        return;
    }

    if ( nodeIsFORM(element) && 
         DescendantOf(element, TidyTag_FORM) )
        TY_(Report)(doc, element, NULL, ILLEGAL_NESTING );

    /*
     InlineDup() asks the lexer to insert inline emphasis tags
     currently pushed on the istack, but take care to avoid
     propagating inline emphasis inside OBJECT or APPLET.
     For these elements a fresh inline stack context is created
     and disposed of upon reaching the end of the element.
     They thus behave like table cells in this respect.
    */
    if (element->tag->model & CM_OBJECT)
    {
        istackbase = lexer->istackbase;
        lexer->istackbase = lexer->istacksize;
    }

    if (!(element->tag->model & CM_MIXED))
        TY_(InlineDup)( doc, NULL );

    /*\
     *  Issue #212 - If it is likely that it may be necessary
     *  to move a leading space into a text node before this
     *  element, then keep the mode MixedContent to keep any
     *  leading space
    \*/
    if ( !(element->tag->model & CM_INLINE) ||
          (element->tag->model & CM_FIELD ) )
    {
        mode = IgnoreWhitespace;
    }
    else if (mode == IgnoreWhitespace)
    {
        /* Issue #212 - Further fix in case ParseBlock() is called with 'IgnoreWhitespace'
           when such a leading space may need to be inserted before this element to 
           preverve the browser view */
        mode = MixedContent;
    }

    while ((node = TY_(GetToken)(doc, mode /*MixedContent*/)) != NULL)
    {
        /* end tag for this element */
        if (node->type == EndTag && node->tag &&
            (node->tag == element->tag || element->was == node->tag))
        {
            TY_(FreeNode)( doc, node );

            if (element->tag->model & CM_OBJECT)
            {
                /* pop inline stack */
                while (lexer->istacksize > lexer->istackbase)
                    TY_(PopInline)( doc, NULL );
                lexer->istackbase = istackbase;
            }

            element->closed = yes;
            TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
            in_parse_block--;
            SPRTF("Exit ParseBlock 2 %d...\n",in_parse_block);
#endif
            return;
        }

        if ( nodeIsHTML(node) || nodeIsHEAD(node) || nodeIsBODY(node) )
        {
            if ( TY_(nodeIsElement)(node) )
                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
            TY_(FreeNode)( doc, node );
            continue;
        }


        if (node->type == EndTag)
        {
            if (node->tag == NULL)
            {
                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
                TY_(FreeNode)( doc, node );
                continue;
            }
            else if ( nodeIsBR(node) )
                node->type = StartTag;
            else if ( nodeIsP(node) )
            {
                /* Cannot have a block inside a paragraph, so no checking
                   for an ancestor is necessary -- but we _can_ have
                   paragraphs inside a block, so change it to an implicit
                   empty paragraph, to be dealt with according to the user's
                   options
                */
                node->type = StartEndTag;
                node->implicit = yes;
            }
            else if (DescendantOf( element, node->tag->id ))
            {
                /* 
                  if this is the end tag for an ancestor element
                  then infer end tag for this element
                */
                TY_(UngetToken)( doc );
                break;
            }
            else
            {
                /* special case </tr> etc. for stuff moved in front of table */
                if ( lexer->exiled
                     && (TY_(nodeHasCM)(node, CM_TABLE) || nodeIsTABLE(node)) )
                {
                    TY_(UngetToken)( doc );
                    TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_block--;
                    SPRTF("Exit ParseBlock 2 %d...\n",in_parse_block);
#endif
                    return;
                }
            }
        }

        /* mixed content model permits text */
        if (TY_(nodeIsText)(node))
        {
            if ( checkstack )
            {
                checkstack = no;
                if (!(element->tag->model & CM_MIXED))
                {
                    if ( TY_(InlineDup)(doc, node) > 0 )
                        continue;
                }
            }

            TY_(InsertNodeAtEnd)(element, node);
            mode = MixedContent;

            /*
              HTML4 strict doesn't allow mixed content for
              elements with %block; as their content model
            */
            /*
              But only body, map, blockquote, form and
              noscript have content model %block;
            */
            if ( nodeIsBODY(element)       ||
                 nodeIsMAP(element)        ||
                 nodeIsBLOCKQUOTE(element) ||
                 nodeIsFORM(element)       ||
                 nodeIsNOSCRIPT(element) )
                TY_(ConstrainVersion)( doc, ~VERS_HTML40_STRICT );
            continue;
        }

        if ( InsertMisc(element, node) )
            continue;

        /* allow PARAM elements? */
        if ( nodeIsPARAM(node) )
        {
            if ( TY_(nodeHasCM)(element, CM_PARAM) && TY_(nodeIsElement)(node) )
            {
                TY_(InsertNodeAtEnd)(element, node);
                continue;
            }

            /* otherwise discard it */
            TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
            TY_(FreeNode)( doc, node );
            continue;
        }

        /* allow AREA elements? */
        if ( nodeIsAREA(node) )
        {
            if ( nodeIsMAP(element) && TY_(nodeIsElement)(node) )
            {
                TY_(InsertNodeAtEnd)(element, node);
                continue;
            }

            /* otherwise discard it */
            TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
            TY_(FreeNode)( doc, node );
            continue;
        }

        /* ignore unknown start/end tags */
        if ( node->tag == NULL )
        {
            TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
            TY_(FreeNode)( doc, node );
            continue;
        }

        /*
          Allow CM_INLINE elements here.

          Allow CM_BLOCK elements here unless
          lexer->excludeBlocks is yes.

          LI and DD are special cased.

          Otherwise infer end tag for this element.
        */

        if ( !TY_(nodeHasCM)(node, CM_INLINE) )
        {
            if ( !TY_(nodeIsElement)(node) )
            {
                if ( nodeIsFORM(node) )
                    BadForm( doc );

                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
                TY_(FreeNode)( doc, node );
                continue;
            }

            /* #427671 - Fix by Randy Waki - 10 Aug 00 */
            /*
             If an LI contains an illegal FRAME, FRAMESET, OPTGROUP, or OPTION
             start tag, discard the start tag and let the subsequent content get
             parsed as content of the enclosing LI.  This seems to mimic IE and
             Netscape, and avoids an infinite loop: without this check,
             ParseBlock (which is parsing the LI's content) and ParseList (which
             is parsing the LI's parent's content) repeatedly defer to each
             other to parse the illegal start tag, each time inferring a missing
             </li> or <li> respectively.

             NOTE: This check is a bit fragile.  It specifically checks for the
             four tags that happen to weave their way through the current series
             of tests performed by ParseBlock and ParseList to trigger the
             infinite loop.
            */
            if ( nodeIsLI(element) )
            {
                if ( nodeIsFRAME(node)    ||
                     nodeIsFRAMESET(node) ||
                     nodeIsOPTGROUP(node) ||
                     nodeIsOPTION(node) )
                {
                    TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
                    TY_(FreeNode)( doc, node );  /* DSR - 27Apr02 avoid memory leak */
                    continue;
                }
            }

            if ( nodeIsTD(element) || nodeIsTH(element) )
            {
                /* if parent is a table cell, avoid inferring the end of the cell */

                if ( TY_(nodeHasCM)(node, CM_HEAD) )
                {
                    MoveToHead( doc, element, node );
                    continue;
                }

                if ( TY_(nodeHasCM)(node, CM_LIST) )
                {
                    TY_(UngetToken)( doc );
                    node = TY_(InferredTag)(doc, TidyTag_UL);
                    AddClassNoIndent(doc, node);
                    lexer->excludeBlocks = yes;
                }
                else if ( TY_(nodeHasCM)(node, CM_DEFLIST) )
                {
                    TY_(UngetToken)( doc );
                    node = TY_(InferredTag)(doc, TidyTag_DL);
                    lexer->excludeBlocks = yes;
                }

                /* infer end of current table cell */
                if ( !TY_(nodeHasCM)(node, CM_BLOCK) )
                {
                    TY_(UngetToken)( doc );
                    TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_block--;
                    SPRTF("Exit ParseBlock 3 %d...\n",in_parse_block);
#endif
                    return;
                }
            }
            else if ( TY_(nodeHasCM)(node, CM_BLOCK) )
            {
                if ( lexer->excludeBlocks )
                {
                    if ( !TY_(nodeHasCM)(element, CM_OPT) )
                        TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE );

                    TY_(UngetToken)( doc );

                    if ( TY_(nodeHasCM)(element, CM_OBJECT) )
                        lexer->istackbase = istackbase;

                    TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_block--;
                    SPRTF("Exit ParseBlock 4 %d...\n",in_parse_block);
#endif
                    return;
                }
            }
            else /* things like list items */
            {
                if (node->tag->model & CM_HEAD)
                {
                    MoveToHead( doc, element, node );
                    continue;
                }

                /*
                 special case where a form start tag
                 occurs in a tr and is followed by td or th
                */

                if ( nodeIsFORM(element) &&
                     nodeIsTD(element->parent) &&
                     element->parent->implicit )
                {
                    if ( nodeIsTD(node) )
                    {
                        TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
                        TY_(FreeNode)( doc, node );
                        continue;
                    }

                    if ( nodeIsTH(node) )
                    {
                        TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
                        TY_(FreeNode)( doc, node );
                        node = element->parent;
                        TidyDocFree(doc, node->element);
                        node->element = TY_(tmbstrdup)(doc->allocator, "th");
                        node->tag = TY_(LookupTagDef)( TidyTag_TH );
                        continue;
                    }
                }

                if ( !TY_(nodeHasCM)(element, CM_OPT) && !element->implicit )
                    TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE );
                
                /* #521, warn on missing optional end-tags if not omitting them. */
                if ( cfgBool( doc, TidyOmitOptionalTags ) == no && TY_(nodeHasCM)(element, CM_OPT) )
                    TY_(Report)(doc, element, node, MISSING_ENDTAG_OPTIONAL );


                TY_(UngetToken)( doc );

                if ( TY_(nodeHasCM)(node, CM_LIST) )
                {
                    if ( element->parent && element->parent->tag &&
                         element->parent->tag->parser == TY_(ParseList) )
                    {
                        TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                        in_parse_block--;
                        SPRTF("Exit ParseBlock 5 %d...\n",in_parse_block);
#endif
                        return;
                    }

                    node = TY_(InferredTag)(doc, TidyTag_UL);
                    AddClassNoIndent(doc, node);
                }
                else if ( TY_(nodeHasCM)(node, CM_DEFLIST) )
                {
                    if ( nodeIsDL(element->parent) )
                    {
                        TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                        in_parse_block--;
                        SPRTF("Exit ParseBlock 6 %d...\n",in_parse_block);
#endif
                        return;
                    }

                    node = TY_(InferredTag)(doc, TidyTag_DL);
                }
                else if ( TY_(nodeHasCM)(node, CM_TABLE) || TY_(nodeHasCM)(node, CM_ROW) )
                {
                    /* http://tidy.sf.net/issue/1316307 */
                    /* In exiled mode, return so table processing can 
                       continue. */
                    if (lexer->exiled) {
#if defined(ENABLE_DEBUG_LOG)
                        in_parse_block--;
                        SPRTF("Exit ParseBlock 7 %d...\n",in_parse_block);
#endif
                        return;
                    }
                    node = TY_(InferredTag)(doc, TidyTag_TABLE);
                }
                else if ( TY_(nodeHasCM)(element, CM_OBJECT) )
                {
                    /* pop inline stack */
                    while ( lexer->istacksize > lexer->istackbase )
                        TY_(PopInline)( doc, NULL );
                    lexer->istackbase = istackbase;
                    TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_block--;
                    SPRTF("Exit ParseBlock 8 %d...\n",in_parse_block);
#endif
                    return;

                }
                else
                {
                    TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_block--;
                    SPRTF("Exit ParseBlock 9 %d...\n",in_parse_block);
#endif
                    return;
                }
            }
        }

        /*\
         *  Issue #307 - an <A> tag to ends any open <A> element
         *  Like #427827 - fixed by Randy Waki and Bjoern Hoehrmann 23 Aug 00
         *  in ParseInline(), fix copied HERE to ParseBlock()
         *  href: http://www.w3.org/TR/html-markup/a.html
         *  The interactive element a must not appear as a descendant of the a element.
        \*/
        if ( nodeIsA(node) && !node->implicit && 
             (nodeIsA(element) || DescendantOf(element, TidyTag_A)) )
        {
            if (node->type != EndTag && node->attributes == NULL
                && cfgBool(doc, TidyCoerceEndTags) )
            {
                node->type = EndTag;
                TY_(Report)(doc, element, node, COERCE_TO_ENDTAG);
                TY_(UngetToken)( doc );
                continue;
            }

            if (nodeIsA(element))
            {
                TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE);
                TY_(UngetToken)( doc );
            }
            else
            {
                /* Issue #597 - if we not 'UngetToken' then it is being discarded.
                   Add message, and 'FreeNode' - thanks @ralfjunker */
                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)(doc, node);
            }

            if (!(mode & Preformatted))
                TrimSpaces(doc, element);

#if defined(ENABLE_DEBUG_LOG)
            in_parse_block--;
            SPRTF("Exit ParseBlock 9b %d...\n",in_parse_block);
#endif
            return;
        }

        /* parse known element */
        if (TY_(nodeIsElement)(node))
        {
            if (node->tag->model & CM_INLINE)
            {
                if (checkstack && !node->implicit)
                {
                    checkstack = no;

                    if (!(element->tag->model & CM_MIXED)) /* #431731 - fix by Randy Waki 25 Dec 00 */
                    {
                        if ( TY_(InlineDup)(doc, node) > 0 )
                            continue;
                    }
                }

                mode = MixedContent;
            }
            else
            {
                checkstack = yes;
                mode = IgnoreWhitespace;
            }

            /* trim white space before <br> */
            if ( nodeIsBR(node) )
                TrimSpaces( doc, element );

            TY_(InsertNodeAtEnd)(element, node);
            
            if (node->implicit)
                TY_(Report)(doc, element, node, INSERTING_TAG );

            /* Issue #212 - WHY is this hard coded to 'IgnoreWhitespace' while an 
               effort has been made above to set a 'MixedContent' mode in some cases?
               WHY IS THE 'mode' VARIABLE NOT USED HERE???? */
            ParseTag( doc, node, IgnoreWhitespace /*MixedContent*/ );
            continue;
        }

        /* discard unexpected tags */
        if (node->type == EndTag)
            TY_(PopInline)( doc, node );  /* if inline end tag */

        TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
        TY_(FreeNode)( doc, node );
        continue;
    }

    if (!(element->tag->model & CM_OPT))
        TY_(Report)(doc, element, node, MISSING_ENDTAG_FOR);

    if (element->tag->model & CM_OBJECT)
    {
        /* pop inline stack */
        while ( lexer->istacksize > lexer->istackbase )
            TY_(PopInline)( doc, NULL );
        lexer->istackbase = istackbase;
    }

    TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
    in_parse_block--;
    SPRTF("Exit ParseBlock 10 %d...\n",in_parse_block);
#endif
}

/* [i_a] svg / math */

struct MatchingDescendantData
{
    Node *found_node;
    Bool *passed_marker_node;

    /* input: */
    TidyTagId matching_tagId;
    Node *node_to_find;
    Node *marker_node;
};

static NodeTraversalSignal FindDescendant_cb(TidyDocImpl* ARG_UNUSED(doc), Node* node, void *propagate)
{
    struct MatchingDescendantData *cb_data = (struct MatchingDescendantData *)propagate;

    if (TagId(node) == cb_data->matching_tagId)
    {
        /* make sure we match up 'unknown' tags exactly! */
        if (cb_data->matching_tagId != TidyTag_UNKNOWN ||
            (node->element != NULL &&
            cb_data->node_to_find != NULL &&
            cb_data->node_to_find->element != NULL &&
            0 == TY_(tmbstrcmp)(cb_data->node_to_find->element, node->element)))
        {
            cb_data->found_node = node;
            return ExitTraversal;
        }
    }

    if (cb_data->passed_marker_node && node == cb_data->marker_node)
        *cb_data->passed_marker_node = yes;

    return VisitParent;
}

/*
Search the parent chain (from 'parent' upwards up to the root) for a node matching the
given 'node'.

When the search passes beyond the 'marker_node' (which is assumed to sit in the
parent chain), this will be flagged by setting the boolean referenced by
'is_parent_of_marker' to yes.

'is_parent_of_marker' and 'marker_node' are optional parameters and may be NULL.
*/
static Node *FindMatchingDescendant( Node *parent, Node *node, Node *marker_node, Bool *is_parent_of_marker )
{
    struct MatchingDescendantData cb_data = { 0 };
    cb_data.matching_tagId = TagId(node);
    cb_data.node_to_find = node;
    cb_data.marker_node = marker_node;

    assert(node);

    if (is_parent_of_marker)
        *is_parent_of_marker = no;

    TY_(TraverseNodeTree)(NULL, parent, FindDescendant_cb, &cb_data);
    return cb_data.found_node;
}

/*
   Act as a generic XML (sub)tree parser: collect each node and add it to the DOM, without any further validation.
   TODO : add schema- or other-hierarchy-definition-based validation of the subtree here...
*/
void TY_(ParseNamespace)(TidyDocImpl* doc, Node *basenode, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    Node *node;
    Node *parent = basenode;
    unsigned int istackbase;
    AttVal* av; /* #130 MathML attr and entity fix! */

    /* a la <table>: defer popping elements off the inline stack */
    TY_(DeferDup)( doc );
    istackbase = lexer->istackbase;
    lexer->istackbase = lexer->istacksize;

    mode = OtherNamespace; /* Preformatted; IgnoreWhitespace; */

    while ((node = TY_(GetToken)(doc, mode)) != NULL)
    {
        /*
        fix check to skip action in InsertMisc for regular/empty
        nodes, which we don't want here...

        The way we do it here is by checking and processing everything
        and only what remains goes into InsertMisc()
        */

        /* is this a close tag? And does it match the current parent node? */
        if (node->type == EndTag)
        {
            /*
            to prevent end tags flowing from one 'alternate namespace' we
            check this in two phases: first we check if the tag is a
            descendant of the current node, and when it is, we check whether
            it is the end tag for a node /within/ or /outside/ the basenode.
            */
            Bool outside;
            Node *mp = FindMatchingDescendant(parent, node, basenode, &outside);

            if (mp != NULL)
            {
                /*
                when mp != parent as we might expect,
                infer end tags until we 'hit' the matched
                parent or the basenode
                */
                Node *n;

                for (n = parent;
                     n != NULL && n != basenode->parent && n != mp;
                     n = n->parent)
                {
                    /* n->implicit = yes; */
                    n->closed = yes;
                    TY_(Report)(doc, n->parent, n, MISSING_ENDTAG_BEFORE);
                }

                /* Issue #369 - Since 'assert' is DEBUG only, and there are
                   simple cases where these can be fired, removing them
                   pending feedback from the original author!
                   assert(outside == no ? n == mp : 1);
                   assert(outside == yes ? n == basenode->parent : 1);
                   =================================================== */

                if (outside == no)
                {
                    /* EndTag for a node within the basenode subtree. Roll on... */
                    n->closed = yes;
                    TY_(FreeNode)(doc, node);

                    node = n;
                    parent = node->parent;
                }
                else
                {
                    /* EndTag for a node outside the basenode subtree: let the caller handle that. */
                    TY_(UngetToken)( doc );
                    node = basenode;
                    parent = node->parent;
                }

                /* when we've arrived at the end-node for the base node, it's quitting time */
                if (node == basenode)
                {
                    lexer->istackbase = istackbase;
                    assert(basenode->closed == yes);
                    return;
                }
            }
            else
            {
                /* unmatched close tag: report an error and discard */
                /* TY_(Report)(doc, parent, node, NON_MATCHING_ENDTAG); Issue #308 - Seems wrong warning! */
                TY_(Report)(doc, parent, node, DISCARDING_UNEXPECTED);
                assert(parent);
                /* assert(parent->tag != node->tag); Issue #308 - Seems would always be true! */
                TY_(FreeNode)( doc, node); /* Issue #308 - Discard unexpected end tag memory */
            }
        }
        else if (node->type == StartTag)
        {
            /* #130 MathML attr and entity fix! 
               care if it has attributes, and 'accidently' any of those attributes match known */
            for ( av = node->attributes; av; av = av->next )
            {
                av->dict = 0; /* does something need to be freed? */
            }
            /* add another child to the current parent */
            TY_(InsertNodeAtEnd)(parent, node);
            parent = node;
        }
        else
        {
            /* #130 MathML attr and entity fix! 
               care if it has attributes, and 'accidently' any of those attributes match known */
            for ( av = node->attributes; av; av = av->next )
            {
                av->dict = 0; /* does something need to be freed? */
            }
            TY_(InsertNodeAtEnd)(parent, node);
        }
    }

    TY_(Report)(doc, basenode->parent, basenode, MISSING_ENDTAG_FOR);
}


void TY_(ParseInline)( TidyDocImpl* doc, Node *element, GetTokenMode mode )
{
#if defined(ENABLE_DEBUG_LOG)
    static int in_parse_inline = 0;
#endif
    Lexer* lexer = doc->lexer;
    Node *node, *parent;
#if defined(ENABLE_DEBUG_LOG)
    in_parse_inline++;
    SPRTF("Entering ParseInline %d...\n",in_parse_inline);
#endif

    if (element->tag->model & CM_EMPTY) {
#if defined(ENABLE_DEBUG_LOG)
        in_parse_inline--;
        SPRTF("Exit ParseInline 1 %d...\n",in_parse_inline);
#endif
        return;
    }

    /*
     ParseInline is used for some block level elements like H1 to H6
     For such elements we need to insert inline emphasis tags currently
     on the inline stack. For Inline elements, we normally push them
     onto the inline stack provided they aren't implicit or OBJECT/APPLET.
     This test is carried out in PushInline and PopInline, see istack.c

     InlineDup(...) is not called for elements with a CM_MIXED (inline and
     block) content model, e.g. <del> or <ins>, otherwise constructs like 

       <p>111<a name='foo'>222<del>333</del>444</a>555</p>
       <p>111<span>222<del>333</del>444</span>555</p>
       <p>111<em>222<del>333</del>444</em>555</p>

     will get corrupted.
    */
    if ((TY_(nodeHasCM)(element, CM_BLOCK) || nodeIsDT(element)) &&
        !TY_(nodeHasCM)(element, CM_MIXED))
        TY_(InlineDup)(doc, NULL);
    else if (TY_(nodeHasCM)(element, CM_INLINE))
        TY_(PushInline)(doc, element);

    if ( nodeIsNOBR(element) )
        doc->badLayout |= USING_NOBR;
    else if ( nodeIsFONT(element) )
        doc->badLayout |= USING_FONT;

    /* Inline elements may or may not be within a preformatted element */
    if (mode != Preformatted)
        mode = MixedContent;

    while ((node = TY_(GetToken)(doc, mode)) != NULL)
    {
        /* end tag for current element */
        if (node->tag == element->tag && node->type == EndTag)
        {
            if (element->tag->model & CM_INLINE)
                TY_(PopInline)( doc, node );

            TY_(FreeNode)( doc, node );

            if (!(mode & Preformatted))
                TrimSpaces(doc, element);

            /*
             if a font element wraps an anchor and nothing else
             then move the font element inside the anchor since
             otherwise it won't alter the anchor text color
            */
            if ( nodeIsFONT(element) && 
                 element->content && element->content == element->last )
            {
                Node *child = element->content;

                if ( nodeIsA(child) )
                {
                    child->parent = element->parent;
                    child->next = element->next;
                    child->prev = element->prev;

                    element->next = NULL;
                    element->prev = NULL;
                    element->parent = child;

                    element->content = child->content;
                    element->last = child->last;
                    child->content = element;

                    TY_(FixNodeLinks)(child);
                    TY_(FixNodeLinks)(element);
                }
            }

            element->closed = yes;
            TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
            in_parse_inline--;
            SPRTF("Exit ParseInline 2 %d...\n",in_parse_inline);
#endif
            return;
        }

        /* <u>...<u>  map 2nd <u> to </u> if 1st is explicit */
        /* (see additional conditions below) */
        /* otherwise emphasis nesting is probably unintentional */
        /* big, small, sub, sup have cumulative effect to leave them alone */
        if ( node->type == StartTag
             && node->tag == element->tag
             && TY_(IsPushed)( doc, node )
             && !node->implicit
             && !element->implicit
             && node->tag && (node->tag->model & CM_INLINE)
             && !nodeIsA(node)
             && !nodeIsFONT(node)
             && !nodeIsBIG(node)
             && !nodeIsSMALL(node)
             && !nodeIsSUB(node)
             && !nodeIsSUP(node)
             && !nodeIsQ(node)
             && !nodeIsSPAN(node)
             && cfgBool(doc, TidyCoerceEndTags)
           )
        {
            /* proceeds only if "node" does not have any attribute and
               follows a text node not finishing with a space */
            if (element->content != NULL && node->attributes == NULL
                && TY_(nodeIsText)(element->last)
                && !TY_(TextNodeEndWithSpace)(doc->lexer, element->last) )
            {
                TY_(Report)(doc, element, node, COERCE_TO_ENDTAG);
                node->type = EndTag;
                TY_(UngetToken)(doc);
                continue;
            }

            if (node->attributes == NULL || element->attributes == NULL)
                TY_(Report)(doc, element, node, NESTED_EMPHASIS);
        }
        else if ( TY_(IsPushed)(doc, node) && node->type == StartTag && 
                  nodeIsQ(node) )
        {
            /*\
             * Issue #215 - such nested quotes are NOT a problem if HTML5, so
             * only issue this warning if NOT HTML5 mode.
            \*/
            if (TY_(HTMLVersion)(doc) != HT50) 
            {
                TY_(Report)(doc, element, node, NESTED_QUOTATION);
            }
        }

        if ( TY_(nodeIsText)(node) )
        {
            /* only called for 1st child */
            if ( element->content == NULL && !(mode & Preformatted) )
                TrimSpaces( doc, element );

            if ( node->start >= node->end )
            {
                TY_(FreeNode)( doc, node );
                continue;
            }

            TY_(InsertNodeAtEnd)(element, node);
            continue;
        }

        /* mixed content model so allow text */
        if (InsertMisc(element, node))
            continue;

        /* deal with HTML tags */
        if ( nodeIsHTML(node) )
        {
            if ( TY_(nodeIsElement)(node) )
            {
                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED );
                TY_(FreeNode)( doc, node );
                continue;
            }

            /* otherwise infer end of inline element */
            TY_(UngetToken)( doc );

            if (!(mode & Preformatted))
                TrimSpaces(doc, element);
#if defined(ENABLE_DEBUG_LOG)
            in_parse_inline--;
            SPRTF("Exit ParseInline 3 %d...\n",in_parse_inline);
#endif
            return;
        }

        /* within <dt> or <pre> map <p> to <br> */
        if ( nodeIsP(node) &&
             node->type == StartTag &&
             ( (mode & Preformatted) ||
               nodeIsDT(element) || 
               DescendantOf(element, TidyTag_DT )
             )
           )
        {
            node->tag = TY_(LookupTagDef)( TidyTag_BR );
            TidyDocFree(doc, node->element);
            node->element = TY_(tmbstrdup)(doc->allocator, "br");
            TrimSpaces(doc, element);
            TY_(InsertNodeAtEnd)(element, node);
            continue;
        }

        /* <p> allowed within <address> in HTML 4.01 Transitional */
        if ( nodeIsP(node) &&
             node->type == StartTag &&
             nodeIsADDRESS(element) )
        {
            TY_(ConstrainVersion)( doc, ~VERS_HTML40_STRICT );
            TY_(InsertNodeAtEnd)(element, node);
            (*node->tag->parser)( doc, node, mode );
            continue;
        }

        /* ignore unknown and PARAM tags */
        if ( node->tag == NULL || nodeIsPARAM(node) )
        {
            TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node );
            continue;
        }

        if ( nodeIsBR(node) && node->type == EndTag )
            node->type = StartTag;

        if ( node->type == EndTag )
        {
           /* coerce </br> to <br> */
           if ( nodeIsBR(node) )
                node->type = StartTag;
           else if ( nodeIsP(node) )
           {
               /* coerce unmatched </p> to <br><br> */
                if ( !DescendantOf(element, TidyTag_P) )
                {
                    TY_(CoerceNode)(doc, node, TidyTag_BR, no, no);
                    TrimSpaces( doc, element );
                    TY_(InsertNodeAtEnd)( element, node );
                    node = TY_(InferredTag)(doc, TidyTag_BR);
                    TY_(InsertNodeAtEnd)( element, node ); /* todo: check this */
                    continue;
                }
           }
           else if ( TY_(nodeHasCM)(node, CM_INLINE)
                     && !nodeIsA(node)
                     && !TY_(nodeHasCM)(node, CM_OBJECT)
                     && TY_(nodeHasCM)(element, CM_INLINE) )
            {
                /* allow any inline end tag to end current element */

                /* http://tidy.sf.net/issue/1426419 */
                /* but, like the browser, retain an earlier inline element.
                   This is implemented by setting the lexer into a mode
                   where it gets tokens from the inline stack rather than
                   from the input stream. Check if the scenerio fits. */
                if ( !nodeIsA(element)
                     && (node->tag != element->tag)
                     && TY_(IsPushed)( doc, node )
                     && TY_(IsPushed)( doc, element ) )
                {
                    /* we have something like
                       <b>bold <i>bold and italic</b> italics</i> */
                    if ( TY_(SwitchInline)( doc, element, node ) )
                    {
                        TY_(Report)(doc, element, node, NON_MATCHING_ENDTAG);
                        TY_(UngetToken)( doc ); /* put this back */
                        TY_(InlineDup1)( doc, NULL, element ); /* dupe the <i>, after </b> */
                        if (!(mode & Preformatted))
                            TrimSpaces( doc, element );
#if defined(ENABLE_DEBUG_LOG)
                        in_parse_inline--;
                        SPRTF("Exit ParseInline 4 %d...\n",in_parse_inline);
#endif
                        return; /* close <i>, but will re-open it, after </b> */
                    }
                }
                TY_(PopInline)( doc, element );

                if ( !nodeIsA(element) )
                {
                    if ( nodeIsA(node) && node->tag != element->tag )
                    {
                       TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE );
                       TY_(UngetToken)( doc );
                    }
                    else
                    {
                        TY_(Report)(doc, element, node, NON_MATCHING_ENDTAG);
                        TY_(FreeNode)( doc, node);
                    }

                    if (!(mode & Preformatted))
                        TrimSpaces(doc, element);
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_inline--;
                    SPRTF("Exit ParseInline 5 %d...\n",in_parse_inline);
#endif
                    return;
                }

                /* if parent is <a> then discard unexpected inline end tag */
                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }  /* special case </tr> etc. for stuff moved in front of table */
            else if ( lexer->exiled
                     && (TY_(nodeHasCM)(node, CM_TABLE) || nodeIsTABLE(node)) )
            {
                TY_(UngetToken)( doc );
                TrimSpaces(doc, element);
#if defined(ENABLE_DEBUG_LOG)
                in_parse_inline--;
                SPRTF("Exit ParseInline 6 %d...\n",in_parse_inline);
#endif
                return;
            }
        }

        /* allow any header tag to end current header */
        if ( TY_(nodeHasCM)(node, CM_HEADING) && TY_(nodeHasCM)(element, CM_HEADING) )
        {

            if ( node->tag == element->tag )
            {
                TY_(Report)(doc, element, node, NON_MATCHING_ENDTAG );
                TY_(FreeNode)( doc, node);
            }
            else
            {
                TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE );
                TY_(UngetToken)( doc );
            }

            if (!(mode & Preformatted))
                TrimSpaces(doc, element);

#if defined(ENABLE_DEBUG_LOG)
            in_parse_inline--;
            SPRTF("Exit ParseInline 7 %d...\n",in_parse_inline);
#endif
            return;
        }

        /*
           an <A> tag to ends any open <A> element
           but <A href=...> is mapped to </A><A href=...>
        */
        /* #427827 - fix by Randy Waki and Bjoern Hoehrmann 23 Aug 00 */
        /* if (node->tag == doc->tags.tag_a && !node->implicit && TY_(IsPushed)(doc, node)) */
        if ( nodeIsA(node) && !node->implicit && 
             (nodeIsA(element) || DescendantOf(element, TidyTag_A)) )
        {
            /* coerce <a> to </a> unless it has some attributes */
            /* #427827 - fix by Randy Waki and Bjoern Hoehrmann 23 Aug 00 */
            /* other fixes by Dave Raggett */
            /* if (node->attributes == NULL) */
            if (node->type != EndTag && node->attributes == NULL
                && cfgBool(doc, TidyCoerceEndTags) )
            {
                node->type = EndTag;
                TY_(Report)(doc, element, node, COERCE_TO_ENDTAG);
                /* TY_(PopInline)( doc, node ); */
                TY_(UngetToken)( doc );
                continue;
            }

            TY_(UngetToken)( doc );
            TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE);
            /* TY_(PopInline)( doc, element ); */

            if (!(mode & Preformatted))
                TrimSpaces(doc, element);

#if defined(ENABLE_DEBUG_LOG)
            in_parse_inline--;
            SPRTF("Exit ParseInline 8 %d...\n",in_parse_inline);
#endif
            return;
        }

        if (element->tag->model & CM_HEADING)
        {
            if ( nodeIsCENTER(node) || nodeIsDIV(node) )
            {
                if (!TY_(nodeIsElement)(node))
                {
                    TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
                    TY_(FreeNode)( doc, node);
                    continue;
                }

                TY_(Report)(doc, element, node, TAG_NOT_ALLOWED_IN);

                /* insert center as parent if heading is empty */
                if (element->content == NULL)
                {
                    InsertNodeAsParent(element, node);
                    continue;
                }

                /* split heading and make center parent of 2nd part */
                TY_(InsertNodeAfterElement)(element, node);

                if (!(mode & Preformatted))
                    TrimSpaces(doc, element);

                element = TY_(CloneNode)( doc, element );
                TY_(InsertNodeAtEnd)(node, element);
                continue;
            }

            if ( nodeIsHR(node) )
            {
                if ( !TY_(nodeIsElement)(node) )
                {
                    TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
                    TY_(FreeNode)( doc, node);
                    continue;
                }

                TY_(Report)(doc, element, node, TAG_NOT_ALLOWED_IN);

                /* insert hr before heading if heading is empty */
                if (element->content == NULL)
                {
                    TY_(InsertNodeBeforeElement)(element, node);
                    continue;
                }

                /* split heading and insert hr before 2nd part */
                TY_(InsertNodeAfterElement)(element, node);

                if (!(mode & Preformatted))
                    TrimSpaces(doc, element);

                element = TY_(CloneNode)( doc, element );
                TY_(InsertNodeAfterElement)(node, element);
                continue;
            }
        }

        if ( nodeIsDT(element) )
        {
            if ( nodeIsHR(node) )
            {
                Node *dd;
                if ( !TY_(nodeIsElement)(node) )
                {
                    TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
                    TY_(FreeNode)( doc, node);
                    continue;
                }

                TY_(Report)(doc, element, node, TAG_NOT_ALLOWED_IN);
                dd = TY_(InferredTag)(doc, TidyTag_DD);

                /* insert hr within dd before dt if dt is empty */
                if (element->content == NULL)
                {
                    TY_(InsertNodeBeforeElement)(element, dd);
                    TY_(InsertNodeAtEnd)(dd, node);
                    continue;
                }

                /* split dt and insert hr within dd before 2nd part */
                TY_(InsertNodeAfterElement)(element, dd);
                TY_(InsertNodeAtEnd)(dd, node);

                if (!(mode & Preformatted))
                    TrimSpaces(doc, element);

                element = TY_(CloneNode)( doc, element );
                TY_(InsertNodeAfterElement)(dd, element);
                continue;
            }
        }


        /* 
          if this is the end tag for an ancestor element
          then infer end tag for this element
        */
        if (node->type == EndTag)
        {
            for (parent = element->parent;
                    parent != NULL; parent = parent->parent)
            {
                if (node->tag == parent->tag)
                {
                    if (!(element->tag->model & CM_OPT) && !element->implicit)
                        TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE);

                    if( TY_(IsPushedLast)( doc, element, node ) ) 
                        TY_(PopInline)( doc, element );
                    TY_(UngetToken)( doc );

                    if (!(mode & Preformatted))
                        TrimSpaces(doc, element);

#if defined(ENABLE_DEBUG_LOG)
                    in_parse_inline--;
                    SPRTF("Exit ParseInline 9 %d...\n",in_parse_inline);
#endif
                    return;
                }
            }
        }

        /*\
         *  block level tags end this element 
         *  Issue #333 - There seems an exception if the element is a 'span',
         *  and the node just collected is a 'meta'. The 'meta' can not have
         *  CM_INLINE added, nor can the 'span' have CM_MIXED added without
         *  big consequences.
         *  There may be other exceptions to be added...
        \*/
        if (!(node->tag->model & CM_INLINE) &&
            !(element->tag->model & CM_MIXED) &&
            !(nodeIsSPAN(element) && nodeIsMETA(node)) )
        {
            if ( !TY_(nodeIsElement)(node) )
            {
                TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }
            /* HTML5 */
            if (nodeIsDATALIST(element)) {
                TY_(ConstrainVersion)( doc, ~VERS_HTML5 );
            } else
            if (!(element->tag->model & CM_OPT))
                TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE);

            if (node->tag->model & CM_HEAD && !(node->tag->model & CM_BLOCK))
            {
                MoveToHead(doc, element, node);
                continue;
            }

            /*
               prevent anchors from propagating into block tags
               except for headings h1 to h6
            */
            if ( nodeIsA(element) )
            {
                if (node->tag && !(node->tag->model & CM_HEADING))
                    TY_(PopInline)( doc, element );
                else if (!(element->content))
                {
                    TY_(DiscardElement)( doc, element );
                    TY_(UngetToken)( doc );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_inline--;
                    SPRTF("Exit ParseInline 10 %d...\n",in_parse_inline);
#endif
                    return;
                }
            }

            TY_(UngetToken)( doc );

            if (!(mode & Preformatted))
                TrimSpaces(doc, element);

#if defined(ENABLE_DEBUG_LOG)
            in_parse_inline--;
            SPRTF("Exit ParseInline 11 %d...\n",in_parse_inline);
#endif
            return;
        }

        /* parse inline element */
        if (TY_(nodeIsElement)(node))
        {
            if (node->implicit)
                TY_(Report)(doc, element, node, INSERTING_TAG);

            /* trim white space before <br> */
            if ( nodeIsBR(node) )
                TrimSpaces(doc, element);
            
            TY_(InsertNodeAtEnd)(element, node);
            ParseTag(doc, node, mode);
            continue;
        }

        /* discard unexpected tags */
        TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node );
        continue;
    }

    if (!(element->tag->model & CM_OPT))
        TY_(Report)(doc, element, node, MISSING_ENDTAG_FOR);

#if defined(ENABLE_DEBUG_LOG)
    in_parse_inline--;
    SPRTF("Exit ParseInline 12 %d...\n",in_parse_inline);
#endif
}

void TY_(ParseEmpty)(TidyDocImpl* doc, Node *element, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    if ( lexer->isvoyager )
    {
        Node *node = TY_(GetToken)( doc, mode);
        if ( node )
        {
            if ( !(node->type == EndTag && node->tag == element->tag) )
            {
                /* TY_(Report)(doc, element, node, ELEMENT_NOT_EMPTY); */
                TY_(UngetToken)( doc );
            }
            else
            {
                TY_(FreeNode)( doc, node );
            }
        }
    }
}

void TY_(ParseDefList)(TidyDocImpl* doc, Node *list, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    Node *node, *parent;

    if (list->tag->model & CM_EMPTY)
        return;

    lexer->insert = NULL;  /* defer implicit inline start tags */

    while ((node = TY_(GetToken)( doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == list->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            list->closed = yes;
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(list, node))
            continue;

        if (TY_(nodeIsText)(node))
        {
            TY_(UngetToken)( doc );
            node = TY_(InferredTag)(doc, TidyTag_DT);
            TY_(Report)(doc, list, node, MISSING_STARTTAG);
        }

        if (node->tag == NULL)
        {
            TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* 
          if this is the end tag for an ancestor element
          then infer end tag for this element
        */
        if (node->type == EndTag)
        {
            Bool discardIt = no;
            if ( nodeIsFORM(node) )
            {
                BadForm( doc );
                TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node );
                continue;
            }

            for (parent = list->parent;
                    parent != NULL; parent = parent->parent)
            {
               /* Do not match across BODY to avoid infinite loop
                  between ParseBody and this parser,
                  See http://tidy.sf.net/bug/1098012. */
                if (nodeIsBODY(parent))
                {
                    discardIt = yes;
                    break;
                }
                if (node->tag == parent->tag)
                {
                    TY_(Report)(doc, list, node, MISSING_ENDTAG_BEFORE);

                    TY_(UngetToken)( doc );
                    return;
                }
            }
            if (discardIt)
            {
                TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }
        }

        /* center in a dt or a dl breaks the dl list in two */
        if ( nodeIsCENTER(node) )
        {
            if (list->content)
                TY_(InsertNodeAfterElement)(list, node);
            else /* trim empty dl list */
            {
                TY_(InsertNodeBeforeElement)(list, node);
            }

            /* #426885 - fix by Glenn Carroll 19 Apr 00, and
                         Gary Dechaines 11 Aug 00 */
            /* ParseTag can destroy node, if it finds that
             * this <center> is followed immediately by </center>.
             * It's awkward but necessary to determine if this
             * has happened.
             */
            parent = node->parent;

            /* and parse contents of center */
            lexer->excludeBlocks = no;
            ParseTag( doc, node, mode);
            lexer->excludeBlocks = yes;

            /* now create a new dl element,
             * unless node has been blown away because the
             * center was empty, as above.
             */
            if (parent->last == node)
            {
                list = TY_(InferredTag)(doc, TidyTag_DL);
                TY_(InsertNodeAfterElement)(node, list);
            }
            continue;
        }

        if ( !(nodeIsDT(node) || nodeIsDD(node)) )
        {
            TY_(UngetToken)( doc );

            if (!(node->tag->model & (CM_BLOCK | CM_INLINE)))
            {
                TY_(Report)(doc, list, node, TAG_NOT_ALLOWED_IN);
                return;
            }

            /* if DD appeared directly in BODY then exclude blocks */
            if (!(node->tag->model & CM_INLINE) && lexer->excludeBlocks)
                return;

            node = TY_(InferredTag)(doc, TidyTag_DD);
            TY_(Report)(doc, list, node, MISSING_STARTTAG);
        }

        if (node->type == EndTag)
        {
            TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }
        
        /* node should be <DT> or <DD>*/
        TY_(InsertNodeAtEnd)(list, node);
        ParseTag( doc, node, IgnoreWhitespace);
    }

    TY_(Report)(doc, list, node, MISSING_ENDTAG_FOR);
}

static Bool FindLastLI( Node *list, Node **lastli )
{
    Node *node;

    *lastli = NULL;
    for ( node = list->content; node ; node = node->next )
        if ( nodeIsLI(node) && node->type == StartTag )
            *lastli=node;
    return *lastli ? yes:no;
}

void TY_(ParseList)(TidyDocImpl* doc, Node *list, GetTokenMode ARG_UNUSED(mode))
{
#if defined(ENABLE_DEBUG_LOG)
    static int in_parse_list = 0;
#endif
    Lexer* lexer = doc->lexer;
    Node *node, *parent, *lastli;
    Bool wasblock;
    Bool nodeisOL = nodeIsOL(list);

#if defined(ENABLE_DEBUG_LOG)
    in_parse_list++;
    SPRTF("Entering ParseList %d...\n",in_parse_list);
#endif
    if (list->tag->model & CM_EMPTY)
    {
#if defined(ENABLE_DEBUG_LOG)
        in_parse_list--;
        SPRTF("Exit ParseList 1 %d... CM_EMPTY\n",in_parse_list);
#endif
        return;
    }
    lexer->insert = NULL;  /* defer implicit inline start tags */

    while ((node = TY_(GetToken)( doc, IgnoreWhitespace)) != NULL)
    {
        Bool foundLI = no;
        if (node->tag == list->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            list->closed = yes;
#if defined(ENABLE_DEBUG_LOG)
            in_parse_list--;
            SPRTF("Exit ParseList 2 %d... Endtag\n",in_parse_list);
#endif
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(list, node))
            continue;

        if (node->type != TextNode && node->tag == NULL)
        {
            TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }
        if (lexer && (node->type == TextNode))
        {
            unsigned int ch, ix = node->start;
            /* Issue #572 - Skip whitespace. */
            while (ix < node->end && (ch = (lexer->lexbuf[ix] & 0xff))
                && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'))
                ++ix;
            if (ix >= node->end)
            {
                /* Issue #572 - Discard if ALL whitespace. */
                TY_(FreeNode)(doc, node);
                continue;
            }
        }


        /* 
          if this is the end tag for an ancestor element
          then infer end tag for this element
        */
        if (node->type == EndTag)
        {
            if ( nodeIsFORM(node) )
            {
                BadForm( doc );
                TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node );
                continue;
            }

            if (TY_(nodeHasCM)(node,CM_INLINE))
            {
                TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
                TY_(PopInline)( doc, node );
                TY_(FreeNode)( doc, node);
                continue;
            }

            for ( parent = list->parent;
                  parent != NULL; parent = parent->parent )
            {
               /* Do not match across BODY to avoid infinite loop
                  between ParseBody and this parser,
                  See http://tidy.sf.net/bug/1053626. */
                if (nodeIsBODY(parent))
                    break;
                if (node->tag == parent->tag)
                {
                    TY_(Report)(doc, list, node, MISSING_ENDTAG_BEFORE);
                    TY_(UngetToken)( doc );
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_list--;
                    SPRTF("Exit ParseList 3 %d... No End Tag\n",in_parse_list);
#endif
                    return;
                }
            }

            TY_(Report)(doc, list, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        if ( !nodeIsLI(node) && nodeisOL )
        {
            /* Issue #572 - A <ol><li> can have nested <ol> elements */
            foundLI = FindLastLI(list, &lastli); /* find last <li> */
        }

        if ( nodeIsLI(node) || (TY_(IsHTML5Mode)(doc) && !foundLI) )
        {
            /* node is <LI> OR
               Issue #396 - A <ul> can have Zero or more <li> elements
             */
            TY_(InsertNodeAtEnd)(list,node);
        }
        else
        {
            TY_(UngetToken)( doc );

            if (TY_(nodeHasCM)(node,CM_BLOCK) && lexer->excludeBlocks)
            {
                TY_(Report)(doc, list, node, MISSING_ENDTAG_BEFORE);
#if defined(ENABLE_DEBUG_LOG)
                in_parse_list--;
                SPRTF("Exit ParseList 4 %d... No End Tag\n",in_parse_list);
#endif
                return;
            }
            /* http://tidy.sf.net/issue/1316307 */
            /* In exiled mode, return so table processing can continue. */
            else if ( lexer->exiled
                      && (TY_(nodeHasCM)(node, CM_TABLE|CM_ROWGRP|CM_ROW)
                          || nodeIsTABLE(node)) )
            {
#if defined(ENABLE_DEBUG_LOG)
                in_parse_list--;
                SPRTF("Exit ParseList 5 %d... exiled\n",in_parse_list);
#endif
                return;
            }
            /* http://tidy.sf.net/issue/836462
               If "list" is an unordered list, insert the next tag within 
               the last <li> to preserve the numbering to match the visual 
               rendering of most browsers. */    
            if ( nodeIsOL(list) && FindLastLI(list, &lastli) )
            {
                /* Create a node for error reporting */
                node = TY_(InferredTag)(doc, TidyTag_LI);
                TY_(Report)(doc, list, node, MISSING_STARTTAG );
                TY_(FreeNode)( doc, node);
                node = lastli;
            }
            else
            {
                /* Add an inferred <li> */
                wasblock = TY_(nodeHasCM)(node,CM_BLOCK);
                node = TY_(InferredTag)(doc, TidyTag_LI);
                /* Add "display: inline" to avoid a blank line after <li> with 
                   Internet Explorer. See http://tidy.sf.net/issue/836462 */
                TY_(AddStyleProperty)( doc, node,
                                       wasblock
                                       ? "list-style: none; display: inline"
                                       : "list-style: none" 
                                       );
                TY_(Report)(doc, list, node, MISSING_STARTTAG );
                TY_(InsertNodeAtEnd)(list,node);
            }
        }

        ParseTag( doc, node, IgnoreWhitespace);
    }

    TY_(Report)(doc, list, node, MISSING_ENDTAG_FOR);
#if defined(ENABLE_DEBUG_LOG)
    in_parse_list--;
    SPRTF("Exit ParseList 6 %d... missing end tag\n",in_parse_list);
#endif
}

/*
 unexpected content in table row is moved to just before
 the table in accordance with Netscape and IE. This code
 assumes that node hasn't been inserted into the row.
*/
static void MoveBeforeTable( TidyDocImpl* ARG_UNUSED(doc), Node *row,
                             Node *node )
{
    Node *table;

    /* first find the table element */
    for (table = row->parent; table; table = table->parent)
    {
        if ( nodeIsTABLE(table) )
        {
            TY_(InsertNodeBeforeElement)( table, node );
            return;
        }
    }
    /* No table element */
    TY_(InsertNodeBeforeElement)( row->parent, node );
}

/*
 if a table row is empty then insert an empty cell
 this practice is consistent with browser behavior
 and avoids potential problems with row spanning cells
*/
static void FixEmptyRow(TidyDocImpl* doc, Node *row)
{
    Node *cell;

    if (row->content == NULL)
    {
        cell = TY_(InferredTag)(doc, TidyTag_TD);
        TY_(InsertNodeAtEnd)(row, cell);
        TY_(Report)(doc, row, cell, MISSING_STARTTAG);
    }
}

void TY_(ParseRow)(TidyDocImpl* doc, Node *row, GetTokenMode ARG_UNUSED(mode))
{
    Lexer* lexer = doc->lexer;
    Node *node;
    Bool exclude_state;

    if (row->tag->model & CM_EMPTY)
        return;

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == row->tag)
        {
            if (node->type == EndTag)
            {
                TY_(FreeNode)( doc, node);
                row->closed = yes;
                FixEmptyRow( doc, row);
                return;
            }

            /* New row start implies end of current row */
            TY_(UngetToken)( doc );
            FixEmptyRow( doc, row);
            return;
        }

        /* 
          if this is the end tag for an ancestor element
          then infer end tag for this element
        */
        if ( node->type == EndTag )
        {
            if ( (TY_(nodeHasCM)(node, CM_HTML|CM_TABLE) || nodeIsTABLE(node))
                 && DescendantOf(row, TagId(node)) )
            {
                TY_(UngetToken)( doc );
                return;
            }

            if ( nodeIsFORM(node) || TY_(nodeHasCM)(node, CM_BLOCK|CM_INLINE) )
            {
                if ( nodeIsFORM(node) )
                    BadForm( doc );

                TY_(Report)(doc, row, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            if ( nodeIsTD(node) || nodeIsTH(node) )
            {
                TY_(Report)(doc, row, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }
        }

        /* deal with comments etc. */
        if (InsertMisc(row, node))
            continue;

        /* discard unknown tags */
        if (node->tag == NULL && node->type != TextNode)
        {
            TY_(Report)(doc, row, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* discard unexpected <table> element */
        if ( nodeIsTABLE(node) )
        {
            TY_(Report)(doc, row, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* THEAD, TFOOT or TBODY */
        if ( TY_(nodeHasCM)(node, CM_ROWGRP) )
        {
            TY_(UngetToken)( doc );
            return;
        }

        if (node->type == EndTag)
        {
            TY_(Report)(doc, row, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /*
          if text or inline or block move before table
          if head content move to head
        */

        if (node->type != EndTag)
        {
            if ( nodeIsFORM(node) )
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_TD);
                TY_(Report)(doc, row, node, MISSING_STARTTAG);
            }
            else if ( TY_(nodeIsText)(node)
                      || TY_(nodeHasCM)(node, CM_BLOCK | CM_INLINE) )
            {
                MoveBeforeTable( doc, row, node );
                TY_(Report)(doc, row, node, TAG_NOT_ALLOWED_IN);
                lexer->exiled = yes;
                exclude_state = lexer->excludeBlocks;
                lexer->excludeBlocks = no;

                if (node->type != TextNode)
                    ParseTag( doc, node, IgnoreWhitespace);

                lexer->exiled = no;
                lexer->excludeBlocks = exclude_state;
                continue;
            }
            else if (node->tag->model & CM_HEAD)
            {
                TY_(Report)(doc, row, node, TAG_NOT_ALLOWED_IN);
                MoveToHead( doc, row, node);
                continue;
            }
        }

        if ( !(nodeIsTD(node) || nodeIsTH(node)) )
        {
            TY_(Report)(doc, row, node, TAG_NOT_ALLOWED_IN);
            TY_(FreeNode)( doc, node);
            continue;
        }
        
        /* node should be <TD> or <TH> */
        TY_(InsertNodeAtEnd)(row, node);
        exclude_state = lexer->excludeBlocks;
        lexer->excludeBlocks = no;
        ParseTag( doc, node, IgnoreWhitespace);
        lexer->excludeBlocks = exclude_state;

        /* pop inline stack */

        while ( lexer->istacksize > lexer->istackbase )
            TY_(PopInline)( doc, NULL );
    }

}

void TY_(ParseRowGroup)(TidyDocImpl* doc, Node *rowgroup, GetTokenMode ARG_UNUSED(mode))
{
    Lexer* lexer = doc->lexer;
    Node *node, *parent;

    if (rowgroup->tag->model & CM_EMPTY)
        return;

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == rowgroup->tag)
        {
            if (node->type == EndTag)
            {
                rowgroup->closed = yes;
                TY_(FreeNode)( doc, node);
                return;
            }

            TY_(UngetToken)( doc );
            return;
        }

        /* if </table> infer end tag */
        if ( nodeIsTABLE(node) && node->type == EndTag )
        {
            TY_(UngetToken)( doc );
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(rowgroup, node))
            continue;

        /* discard unknown tags */
        if (node->tag == NULL && node->type != TextNode)
        {
            TY_(Report)(doc, rowgroup, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /*
          if TD or TH then infer <TR>
          if text or inline or block move before table
          if head content move to head
        */

        if (node->type != EndTag)
        {
            if ( nodeIsTD(node) || nodeIsTH(node) )
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_TR);
                TY_(Report)(doc, rowgroup, node, MISSING_STARTTAG);
            }
            else if ( TY_(nodeIsText)(node)
                      || TY_(nodeHasCM)(node, CM_BLOCK|CM_INLINE) )
            {
                MoveBeforeTable( doc, rowgroup, node );
                TY_(Report)(doc, rowgroup, node, TAG_NOT_ALLOWED_IN);
                lexer->exiled = yes;

                if (node->type != TextNode)
                    ParseTag(doc, node, IgnoreWhitespace);

                lexer->exiled = no;
                continue;
            }
            else if (node->tag->model & CM_HEAD)
            {
                TY_(Report)(doc, rowgroup, node, TAG_NOT_ALLOWED_IN);
                MoveToHead(doc, rowgroup, node);
                continue;
            }
        }

        /* 
          if this is the end tag for ancestor element
          then infer end tag for this element
        */
        if (node->type == EndTag)
        {
            if ( nodeIsFORM(node) || TY_(nodeHasCM)(node, CM_BLOCK|CM_INLINE) )
            {
                if ( nodeIsFORM(node) )
                    BadForm( doc );

                TY_(Report)(doc, rowgroup, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            if ( nodeIsTR(node) || nodeIsTD(node) || nodeIsTH(node) )
            {
                TY_(Report)(doc, rowgroup, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            for ( parent = rowgroup->parent;
                  parent != NULL;
                  parent = parent->parent )
            {
                if (node->tag == parent->tag)
                {
                    TY_(UngetToken)( doc );
                    return;
                }
            }
        }

        /*
          if THEAD, TFOOT or TBODY then implied end tag

        */
        if (node->tag->model & CM_ROWGRP)
        {
            if (node->type != EndTag)
            {
                TY_(UngetToken)( doc );
                return;
            }
        }

        if (node->type == EndTag)
        {
            TY_(Report)(doc, rowgroup, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }
        
        if ( !nodeIsTR(node) )
        {
            node = TY_(InferredTag)(doc, TidyTag_TR);
            TY_(Report)(doc, rowgroup, node, MISSING_STARTTAG);
            TY_(UngetToken)( doc );
        }

       /* node should be <TR> */
        TY_(InsertNodeAtEnd)(rowgroup, node);
        ParseTag(doc, node, IgnoreWhitespace);
    }

}

void TY_(ParseColGroup)(TidyDocImpl* doc, Node *colgroup, GetTokenMode ARG_UNUSED(mode))
{
    Node *node, *parent;

    if (colgroup->tag->model & CM_EMPTY)
        return;

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == colgroup->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            colgroup->closed = yes;
            return;
        }

        /* 
          if this is the end tag for an ancestor element
          then infer end tag for this element
        */
        if (node->type == EndTag)
        {
            if ( nodeIsFORM(node) )
            {
                BadForm( doc );
                TY_(Report)(doc, colgroup, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            for ( parent = colgroup->parent;
                  parent != NULL;
                  parent = parent->parent )
            {
                if (node->tag == parent->tag)
                {
                    TY_(UngetToken)( doc );
                    return;
                }
            }
        }

        if (TY_(nodeIsText)(node))
        {
            TY_(UngetToken)( doc );
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(colgroup, node))
            continue;

        /* discard unknown tags */
        if (node->tag == NULL)
        {
            TY_(Report)(doc, colgroup, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        if ( !nodeIsCOL(node) )
        {
            TY_(UngetToken)( doc );
            return;
        }

        if (node->type == EndTag)
        {
            TY_(Report)(doc, colgroup, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }
        
        /* node should be <COL> */
        TY_(InsertNodeAtEnd)(colgroup, node);
        ParseTag(doc, node, IgnoreWhitespace);
    }
}

void TY_(ParseTableTag)(TidyDocImpl* doc, Node *table, GetTokenMode ARG_UNUSED(mode))
{
#if defined(ENABLE_DEBUG_LOG)
    static int in_parse_table = 0;
#endif
    Lexer* lexer = doc->lexer;
    Node *node, *parent;
    unsigned int istackbase;

    TY_(DeferDup)( doc );
    istackbase = lexer->istackbase;
    lexer->istackbase = lexer->istacksize;
#if defined(ENABLE_DEBUG_LOG)
    in_parse_table++;
    SPRTF("Entering ParseTableTag %d...\n",in_parse_table);
#endif
    
    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == table->tag )
        {
            if (node->type == EndTag)
            {
                TY_(FreeNode)(doc, node);
            }
            else
            {
                /* Issue #498 - If a <table> in a <table>
                 * just close the current table, and issue a 
                 * warning. The previous action was to discard
                 * this second <table>
                 */
                TY_(UngetToken)(doc);
                TY_(Report)(doc, table, node, TAG_NOT_ALLOWED_IN);
            }
            lexer->istackbase = istackbase;
            table->closed = yes;
#if defined(ENABLE_DEBUG_LOG)
            in_parse_table--;
            SPRTF("Exit ParseTableTag 1 %d... EndTag\n",in_parse_table);
#endif
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(table, node))
            continue;

        /* discard unknown tags */
        if (node->tag == NULL && node->type != TextNode)
        {
            TY_(Report)(doc, table, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* if TD or TH or text or inline or block then infer <TR> */

        if (node->type != EndTag)
        {
            if ( nodeIsTD(node) || nodeIsTH(node) || nodeIsTABLE(node) )
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_TR);
                TY_(Report)(doc, table, node, MISSING_STARTTAG);
            }
            else if ( TY_(nodeIsText)(node) ||TY_(nodeHasCM)(node,CM_BLOCK|CM_INLINE) )
            {
                TY_(InsertNodeBeforeElement)(table, node);
                TY_(Report)(doc, table, node, TAG_NOT_ALLOWED_IN);
                lexer->exiled = yes;

                if (node->type != TextNode) 
                    ParseTag(doc, node, IgnoreWhitespace);

                lexer->exiled = no;
                continue;
            }
            else if (node->tag->model & CM_HEAD)
            {
                MoveToHead(doc, table, node);
                continue;
            }
        }

        /* 
          if this is the end tag for an ancestor element
          then infer end tag for this element
        */
        if (node->type == EndTag)
        {
            if ( nodeIsFORM(node) )
            {
                BadForm( doc );
                TY_(Report)(doc, table, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            /* best to discard unexpected block/inline end tags */
            if ( TY_(nodeHasCM)(node, CM_TABLE|CM_ROW) ||
                 TY_(nodeHasCM)(node, CM_BLOCK|CM_INLINE) )
            {
                TY_(Report)(doc, table, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            for ( parent = table->parent;
                  parent != NULL;
                  parent = parent->parent )
            {
                if (node->tag == parent->tag)
                {
                    TY_(Report)(doc, table, node, MISSING_ENDTAG_BEFORE );
                    TY_(UngetToken)( doc );
                    lexer->istackbase = istackbase;
#if defined(ENABLE_DEBUG_LOG)
                    in_parse_table--;
                    SPRTF("Exit ParseTableTag 2 %d... missing EndTag\n",in_parse_table);
#endif
                    return;
                }
            }
        }

        if (!(node->tag->model & CM_TABLE))
        {
            TY_(UngetToken)( doc );
            TY_(Report)(doc, table, node, TAG_NOT_ALLOWED_IN);
            lexer->istackbase = istackbase;
#if defined(ENABLE_DEBUG_LOG)
            in_parse_table--;
            SPRTF("Exit ParseTableTag 3 %d... CM_TABLE\n",in_parse_table);
#endif
            return;
        }

        if (TY_(nodeIsElement)(node))
        {
            TY_(InsertNodeAtEnd)(table, node);
            ParseTag(doc, node, IgnoreWhitespace);
            continue;
        }

        /* discard unexpected text nodes and end tags */
        TY_(Report)(doc, table, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    TY_(Report)(doc, table, node, MISSING_ENDTAG_FOR);
    lexer->istackbase = istackbase;
#if defined(ENABLE_DEBUG_LOG)
    in_parse_table--;
    SPRTF("Exit ParseTableTag 4 %d... missing end\n",in_parse_table);
#endif
}

/* acceptable content for pre elements */
static Bool PreContent( TidyDocImpl* ARG_UNUSED(doc), Node* node )
{
    /* p is coerced to br's, Text OK too */
    if ( nodeIsP(node) || TY_(nodeIsText)(node) )
        return yes;

    if ( node->tag == NULL ||
         nodeIsPARAM(node) ||
         !TY_(nodeHasCM)(node, CM_INLINE|CM_NEW) )
        return no;

    return yes;
}

void TY_(ParsePre)( TidyDocImpl* doc, Node *pre, GetTokenMode ARG_UNUSED(mode) )
{
    Node *node;

    if (pre->tag->model & CM_EMPTY)
        return;

    TY_(InlineDup)( doc, NULL ); /* tell lexer to insert inlines if needed */

    while ((node = TY_(GetToken)(doc, Preformatted)) != NULL)
    {
        if ( node->type == EndTag && 
             (node->tag == pre->tag || DescendantOf(pre, TagId(node))) )
        {
            if (nodeIsBODY(node) || nodeIsHTML(node))
            {
                TY_(Report)(doc, pre, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)(doc, node);
                continue;
            }
            if (node->tag == pre->tag)
            {
                TY_(FreeNode)(doc, node);
            }
            else
            {
                TY_(Report)(doc, pre, node, MISSING_ENDTAG_BEFORE );
                TY_(UngetToken)( doc );
            }
            pre->closed = yes;
            TrimSpaces(doc, pre);
            return;
        }

        if (TY_(nodeIsText)(node))
        {
            TY_(InsertNodeAtEnd)(pre, node);
            continue;
        }

        /* deal with comments etc. */
        if (InsertMisc(pre, node))
            continue;

        if (node->tag == NULL)
        {
            TY_(Report)(doc, pre, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)(doc, node);
            continue;
        }

        /* strip unexpected tags */
        if ( !PreContent(doc, node) )
        {
            Node *newnode;

            /* fix for http://tidy.sf.net/bug/772205 */
            if (node->type == EndTag)
            {
                /* http://tidy.sf.net/issue/1590220 */ 
               if ( doc->lexer->exiled
                   && (TY_(nodeHasCM)(node, CM_TABLE) || nodeIsTABLE(node)) )
               {
                  TY_(UngetToken)(doc);
                  TrimSpaces(doc, pre);
                  return;
               }

               TY_(Report)(doc, pre, node, DISCARDING_UNEXPECTED);
               TY_(FreeNode)(doc, node);
               continue;
            }
            /* http://tidy.sf.net/issue/1590220 */
            else if (TY_(nodeHasCM)(node, CM_TABLE|CM_ROW)
                     || nodeIsTABLE(node) )
            {
                if (!doc->lexer->exiled)
                    /* No missing close warning if exiled. */
                    TY_(Report)(doc, pre, node, MISSING_ENDTAG_BEFORE);

                TY_(UngetToken)(doc);
                return;
            }

            /*
              This is basically what Tidy 04 August 2000 did and far more accurate
              with respect to browser behaivour than the code commented out above.
              Tidy could try to propagate the <pre> into each disallowed child where
              <pre> is allowed in order to replicate some browsers behaivour, but
              there are a lot of exceptions, e.g. Internet Explorer does not propagate
              <pre> into table cells while Mozilla does. Opera 6 never propagates
              <pre> into blocklevel elements while Opera 7 behaves much like Mozilla.

              Tidy behaves thus mostly like Opera 6 except for nested <pre> elements
              which are handled like Mozilla takes them (Opera6 closes all <pre> after
              the first </pre>).

              There are similar issues like replacing <p> in <pre> with <br>, for
              example

                <pre>...<p>...</pre>                 (Input)
                <pre>...<br>...</pre>                (Tidy)
                <pre>...<br>...</pre>                (Opera 7 and Internet Explorer)
                <pre>...<br><br>...</pre>            (Opera 6 and Mozilla)

                <pre>...<p>...</p>...</pre>          (Input)
                <pre>...<br>......</pre>             (Tidy, BUG!)
                <pre>...<br>...<br>...</pre>         (Internet Explorer)
                <pre>...<br><br>...<br><br>...</pre> (Mozilla, Opera 6)
                <pre>...<br>...<br><br>...</pre>     (Opera 7)
                
              or something similar, they could also be closing the <pre> and propagate
              the <pre> into the newly opened <p>.

              Todo: IMG, OBJECT, APPLET, BIG, SMALL, SUB, SUP, FONT, and BASEFONT are
              dissallowed in <pre>, Tidy neither detects this nor does it perform any
              cleanup operation. Tidy should at least issue a warning if it encounters
              such constructs.

              Todo: discarding </p> is abviously a bug, it should be replaced by <br>.
            */
            TY_(InsertNodeAfterElement)(pre, node);
            TY_(Report)(doc, pre, node, MISSING_ENDTAG_BEFORE);
            ParseTag(doc, node, IgnoreWhitespace);

            newnode = TY_(InferredTag)(doc, TidyTag_PRE);
            TY_(Report)(doc, pre, newnode, INSERTING_TAG);
            pre = newnode;
            TY_(InsertNodeAfterElement)(node, pre);

            continue;
        }

        if ( nodeIsP(node) )
        {
            if (node->type == StartTag)
            {
                TY_(Report)(doc, pre, node, USING_BR_INPLACE_OF);

                /* trim white space before <p> in <pre>*/
                TrimSpaces(doc, pre);
            
                /* coerce both <p> and </p> to <br> */
                TY_(CoerceNode)(doc, node, TidyTag_BR, no, no);
                TY_(FreeAttrs)( doc, node ); /* discard align attribute etc. */
                TY_(InsertNodeAtEnd)( pre, node );
            }
            else
            {
                TY_(Report)(doc, pre, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
            }
            continue;
        }

        if ( TY_(nodeIsElement)(node) )
        {
            /* trim white space before <br> */
            if ( nodeIsBR(node) )
                TrimSpaces(doc, pre);
            
            TY_(InsertNodeAtEnd)(pre, node);
            ParseTag(doc, node, Preformatted);
            continue;
        }

        /* discard unexpected tags */
        TY_(Report)(doc, pre, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    TY_(Report)(doc, pre, node, MISSING_ENDTAG_FOR);
}

void TY_(ParseOptGroup)(TidyDocImpl* doc, Node *field, GetTokenMode ARG_UNUSED(mode))
{
    Lexer* lexer = doc->lexer;
    Node *node;

    lexer->insert = NULL;  /* defer implicit inline start tags */

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == field->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            field->closed = yes;
            TrimSpaces(doc, field);
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(field, node))
            continue;

        if ( node->type == StartTag && 
             (nodeIsOPTION(node) || nodeIsOPTGROUP(node)) )
        {
            if ( nodeIsOPTGROUP(node) )
                TY_(Report)(doc, field, node, CANT_BE_NESTED);

            TY_(InsertNodeAtEnd)(field, node);
            ParseTag(doc, node, MixedContent);
            continue;
        }

        /* discard unexpected tags */
        TY_(Report)(doc, field, node, DISCARDING_UNEXPECTED );
        TY_(FreeNode)( doc, node);
    }
}


void TY_(ParseSelect)(TidyDocImpl* doc, Node *field, GetTokenMode ARG_UNUSED(mode))
{
#if defined(ENABLE_DEBUG_LOG)
    static int in_parse_select = 0;
#endif
    Lexer* lexer = doc->lexer;
    Node *node;

    lexer->insert = NULL;  /* defer implicit inline start tags */
#if defined(ENABLE_DEBUG_LOG)
    in_parse_select++;
    SPRTF("Entering ParseSelect %d...\n",in_parse_select);
#endif

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == field->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            field->closed = yes;
            TrimSpaces(doc, field);
#if defined(ENABLE_DEBUG_LOG)
            in_parse_select--;
            SPRTF("Exit ParseSelect 1 %d...\n",in_parse_select);
#endif
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(field, node))
            continue;

        if ( node->type == StartTag && 
             ( nodeIsOPTION(node)   ||
               nodeIsOPTGROUP(node) ||
               nodeIsDATALIST(node) ||
               nodeIsSCRIPT(node)) 
           )
        {
            TY_(InsertNodeAtEnd)(field, node);
            ParseTag(doc, node, IgnoreWhitespace);
            continue;
        }

        /* discard unexpected tags */
        TY_(Report)(doc, field, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    TY_(Report)(doc, field, node, MISSING_ENDTAG_FOR);
#if defined(ENABLE_DEBUG_LOG)
    in_parse_select--;
    SPRTF("Exit ParseSelect 2 %d...\n",in_parse_select);
#endif
}

/* HTML5 */
void TY_(ParseDatalist)(TidyDocImpl* doc, Node *field, GetTokenMode ARG_UNUSED(mode))
{
#if defined(ENABLE_DEBUG_LOG)
    static int in_parse_datalist = 0;
#endif
    Lexer* lexer = doc->lexer;
    Node *node;

    lexer->insert = NULL;  /* defer implicit inline start tags */
#if defined(ENABLE_DEBUG_LOG)
    in_parse_datalist++;
    SPRTF("Entering ParseDatalist %d...\n",in_parse_datalist);
#endif

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == field->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            field->closed = yes;
            TrimSpaces(doc, field);
#if defined(ENABLE_DEBUG_LOG)
            in_parse_datalist--;
            SPRTF("Exit ParseDatalist 1 %d...\n",in_parse_datalist);
#endif
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(field, node))
            continue;

        if ( node->type == StartTag && 
             ( nodeIsOPTION(node)   ||
               nodeIsOPTGROUP(node) ||
               nodeIsDATALIST(node) ||
               nodeIsSCRIPT(node)) 
           )
        {
            TY_(InsertNodeAtEnd)(field, node);
            ParseTag(doc, node, IgnoreWhitespace);
            continue;
        }

        /* discard unexpected tags */
        TY_(Report)(doc, field, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    TY_(Report)(doc, field, node, MISSING_ENDTAG_FOR);
#if defined(ENABLE_DEBUG_LOG)
    in_parse_datalist--;
    SPRTF("Exit ParseDatalist 2 %d...\n",in_parse_datalist);
#endif
}




void TY_(ParseText)(TidyDocImpl* doc, Node *field, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    Node *node;

    lexer->insert = NULL;  /* defer implicit inline start tags */

    if ( nodeIsTEXTAREA(field) )
        mode = Preformatted;
    else
        mode = MixedContent;  /* kludge for font tags */

    while ((node = TY_(GetToken)(doc, mode)) != NULL)
    {
        if (node->tag == field->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            field->closed = yes;
            TrimSpaces(doc, field);
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(field, node))
            continue;

        if (TY_(nodeIsText)(node))
        {
            /* only called for 1st child */
            if (field->content == NULL && !(mode & Preformatted))
                TrimSpaces(doc, field);

            if (node->start >= node->end)
            {
                TY_(FreeNode)( doc, node);
                continue;
            }

            TY_(InsertNodeAtEnd)(field, node);
            continue;
        }

        /* for textarea should all cases of < and & be escaped? */

        /* discard inline tags e.g. font */
        if (   node->tag 
            && node->tag->model & CM_INLINE
            && !(node->tag->model & CM_FIELD)) /* #487283 - fix by Lee Passey 25 Jan 02 */
        {
            TY_(Report)(doc, field, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* terminate element on other tags */
        if (!(field->tag->model & CM_OPT))
            TY_(Report)(doc, field, node, MISSING_ENDTAG_BEFORE);

        TY_(UngetToken)( doc );
        TrimSpaces(doc, field);
        return;
    }

    if (!(field->tag->model & CM_OPT))
        TY_(Report)(doc, field, node, MISSING_ENDTAG_FOR);
}


void TY_(ParseTitle)(TidyDocImpl* doc, Node *title, GetTokenMode ARG_UNUSED(mode))
{
    Node *node;
    while ((node = TY_(GetToken)(doc, MixedContent)) != NULL)
    {
        if (node->tag == title->tag && node->type == StartTag
            && cfgBool(doc, TidyCoerceEndTags) )
        {
            TY_(Report)(doc, title, node, COERCE_TO_ENDTAG);
            node->type = EndTag;
            TY_(UngetToken)( doc );
            continue;
        }
        else if (node->tag == title->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            title->closed = yes;
            TrimSpaces(doc, title);
            return;
        }

        if (TY_(nodeIsText)(node))
        {
            /* only called for 1st child */
            if (title->content == NULL)
                TrimInitialSpace(doc, title, node);

            if (node->start >= node->end)
            {
                TY_(FreeNode)( doc, node);
                continue;
            }

            TY_(InsertNodeAtEnd)(title, node);
            continue;
        }

        /* deal with comments etc. */
        if (InsertMisc(title, node))
            continue;

        /* discard unknown tags */
        if (node->tag == NULL)
        {
            TY_(Report)(doc, title, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* pushback unexpected tokens */
        TY_(Report)(doc, title, node, MISSING_ENDTAG_BEFORE);
        TY_(UngetToken)( doc );
        TrimSpaces(doc, title);
        return;
    }

    TY_(Report)(doc, title, node, MISSING_ENDTAG_FOR);
}

/*
  This isn't quite right for CDATA content as it recognises
  tags within the content and parses them accordingly.
  This will unfortunately screw up scripts which include
  < + letter,  < + !, < + ?  or  < + / + letter
*/

void TY_(ParseScript)(TidyDocImpl* doc, Node *script, GetTokenMode ARG_UNUSED(mode))
{
    Node *node;
    
    doc->lexer->parent = script;
    node = TY_(GetToken)(doc, CdataContent);
    doc->lexer->parent = NULL;

    if (node)
    {
        TY_(InsertNodeAtEnd)(script, node);
    }
    else
    {
        /* handle e.g. a document like "<script>" */
        TY_(Report)(doc, script, NULL, MISSING_ENDTAG_FOR);
        return;
    }

    node = TY_(GetToken)(doc, IgnoreWhitespace);

    if (!(node && node->type == EndTag && node->tag &&
        node->tag->id == script->tag->id))
    {
        TY_(Report)(doc, script, node, MISSING_ENDTAG_FOR);

        if (node)
            TY_(UngetToken)(doc);
    }
    else
    {
        TY_(FreeNode)(doc, node);
    }
}

Bool TY_(IsJavaScript)(Node *node)
{
    Bool result = no;
    AttVal *attr;

    if (node->attributes == NULL)
        return yes;

    for (attr = node->attributes; attr; attr = attr->next)
    {
        if ( (attrIsLANGUAGE(attr) || attrIsTYPE(attr))
             && AttrContains(attr, "javascript") )
        {
            result = yes;
            break;
        }
    }

    return result;
}

void TY_(ParseHead)(TidyDocImpl* doc, Node *head, GetTokenMode ARG_UNUSED(mode))
{
    Lexer* lexer = doc->lexer;
    Node *node;
    int HasTitle = 0;
    int HasBase = 0;

    DEBUG_LOG(SPRTF("Enter ParseHead...\n"));
    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == head->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            head->closed = yes;
            break;
        }

        /* find and discard multiple <head> elements */
        /* find and discard <html> in <head> elements */
        if ((node->tag == head->tag || nodeIsHTML(node)) && node->type == StartTag)
        {
            TY_(Report)(doc, head, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)(doc, node);
            continue;
        }

        if (TY_(nodeIsText)(node))
        {
            /*\ Issue #132 - avoid warning for missing body tag,
             *  if configured to --omit-otpional-tags yes
             *  Issue #314 - and if --show-body-only
            \*/
            if (!cfgBool( doc, TidyOmitOptionalTags ) &&
                !showingBodyOnly(doc) )
            {
                TY_(Report)(doc, head, node, TAG_NOT_ALLOWED_IN);
            }
            TY_(UngetToken)( doc );
            break;
        }

        if (node->type == ProcInsTag && node->element &&
            TY_(tmbstrcmp)(node->element, "xml-stylesheet") == 0)
        {
            TY_(Report)(doc, head, node, TAG_NOT_ALLOWED_IN);
            TY_(InsertNodeBeforeElement)(TY_(FindHTML)(doc), node);
            continue;
        }

        /* deal with comments etc. */
        if (InsertMisc(head, node))
            continue;

        if (node->type == DocTypeTag)
        {
            InsertDocType(doc, head, node);
            continue;
        }

        /* discard unknown tags */
        if (node->tag == NULL)
        {
            TY_(Report)(doc, head, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }
        
        /*
         if it doesn't belong in the head then
         treat as implicit end of head and deal
         with as part of the body
        */
        if (!(node->tag->model & CM_HEAD))
        {
            /* #545067 Implicit closing of head broken - warn only for XHTML input */
            if ( lexer->isvoyager )
                TY_(Report)(doc, head, node, TAG_NOT_ALLOWED_IN );
            TY_(UngetToken)( doc );
            break;
        }

        if (TY_(nodeIsElement)(node))
        {
            if ( nodeIsTITLE(node) )
            {
                ++HasTitle;

                if (HasTitle > 1)
                    TY_(Report)(doc, head, node,
                                     head ?
                                     TOO_MANY_ELEMENTS_IN : TOO_MANY_ELEMENTS);
            }
            else if ( nodeIsBASE(node) )
            {
                ++HasBase;

                if (HasBase > 1)
                    TY_(Report)(doc, head, node,
                                     head ?
                                     TOO_MANY_ELEMENTS_IN : TOO_MANY_ELEMENTS);
            }

            TY_(InsertNodeAtEnd)(head, node);
            ParseTag(doc, node, IgnoreWhitespace);
            continue;
        }

        /* discard unexpected text nodes and end tags */
        TY_(Report)(doc, head, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }
    DEBUG_LOG(SPRTF("Exit ParseHead 1...\n"));
}

/*\ 
 *  Issue #166 - repeated <main> element
 *  But this service is generalised to check for other duplicate elements
\*/
Bool TY_(FindNodeWithId)( Node *node, TidyTagId tid )
{
    Node *content;
    while (node)
    {
        if (TagIsId(node,tid))
            return yes;
        /*\ 
         *   Issue #459 - Under certain circumstances, with many node this use of
         *   'for (content = node->content; content; content = content->content)'
         *   would produce a **forever** circle, or at least a very extended loop...
         *   It is sufficient to test the content, if it exists,
         *   to quickly iterate all nodes. Now all nodes are tested only once.
        \*/ 
        content = node->content;
        if (content)
        {
            if (TY_(FindNodeWithId)(content,tid))
                return yes;
        }
        node = node->next;
    }
    return no;
}


/*\ 
 *  Issue #166 - repeated <main> element
 *  Do a global search for an element
\*/
Bool TY_(FindNodeById)( TidyDocImpl* doc, TidyTagId tid )
{
    Node *node = (doc ? doc->root.content : NULL);
    return TY_(FindNodeWithId)(node,tid);
}


void TY_(ParseBody)(TidyDocImpl* doc, Node *body, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    Node *node;
    Bool checkstack, iswhitenode;

    mode = IgnoreWhitespace;
    checkstack = yes;

    TY_(BumpObject)( doc, body->parent );

    DEBUG_LOG(SPRTF("Enter ParseBody...\n"));
    while ((node = TY_(GetToken)(doc, mode)) != NULL)
    {
        /* find and discard multiple <body> elements */
        if (node->tag == body->tag && node->type == StartTag)
        {
            TY_(Report)(doc, body, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)(doc, node);
            continue;
        }

        /* #538536 Extra endtags not detected */
        if ( nodeIsHTML(node) )
        {
            if (TY_(nodeIsElement)(node) || lexer->seenEndHtml) 
                TY_(Report)(doc, body, node, DISCARDING_UNEXPECTED);
            else
                lexer->seenEndHtml = 1;

            TY_(FreeNode)( doc, node);
            continue;
        }

        if ( lexer->seenEndBody && 
             ( node->type == StartTag ||
               node->type == EndTag   ||
               node->type == StartEndTag ) )
        {
            TY_(Report)(doc, body, node, CONTENT_AFTER_BODY );
        }

        if ( node->tag == body->tag && node->type == EndTag )
        {
            body->closed = yes;
            TrimSpaces(doc, body);
            TY_(FreeNode)( doc, node);
            lexer->seenEndBody = 1;
            mode = IgnoreWhitespace;

            if ( nodeIsNOFRAMES(body->parent) )
                break;

            continue;
        }

        if ( nodeIsNOFRAMES(node) )
        {
            if (node->type == StartTag)
            {
                TY_(InsertNodeAtEnd)(body, node);
                TY_(ParseBlock)(doc, node, mode);
                continue;
            }

            if (node->type == EndTag && nodeIsNOFRAMES(body->parent) )
            {
                TrimSpaces(doc, body);
                TY_(UngetToken)( doc );
                break;
            }
        }

        if ( (nodeIsFRAME(node) || nodeIsFRAMESET(node))
             && nodeIsNOFRAMES(body->parent) )
        {
            TrimSpaces(doc, body);
            TY_(UngetToken)( doc );
            break;
        }
        
        iswhitenode = no;

        if ( TY_(nodeIsText)(node) &&
             node->end <= node->start + 1 &&
             lexer->lexbuf[node->start] == ' ' )
            iswhitenode = yes;

        /* deal with comments etc. */
        if (InsertMisc(body, node))
            continue;

        /* mixed content model permits text */
        if (TY_(nodeIsText)(node))
        {
            if (iswhitenode && mode == IgnoreWhitespace)
            {
                TY_(FreeNode)( doc, node);
                continue;
            }

            /* HTML 2 and HTML4 strict don't allow text here */
            TY_(ConstrainVersion)(doc, ~(VERS_HTML40_STRICT | VERS_HTML20));

            if (checkstack)
            {
                checkstack = no;

                if ( TY_(InlineDup)(doc, node) > 0 )
                    continue;
            }

            TY_(InsertNodeAtEnd)(body, node);
            mode = MixedContent;
            continue;
        }

        if (node->type == DocTypeTag)
        {
            InsertDocType(doc, body, node);
            continue;
        }
        /* discard unknown  and PARAM tags */
        if ( node->tag == NULL || nodeIsPARAM(node) )
        {
            TY_(Report)(doc, body, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /*
          Netscape allows LI and DD directly in BODY
          We infer UL or DL respectively and use this
          Bool to exclude block-level elements so as
          to match Netscape's observed behaviour.
        */
        lexer->excludeBlocks = no;
        
        if (( nodeIsINPUT(node) ||
             (!TY_(nodeHasCM)(node, CM_BLOCK) && !TY_(nodeHasCM)(node, CM_INLINE))
           ) && !TY_(IsHTML5Mode)(doc) )
        {
            /* avoid this error message being issued twice */
            if (!(node->tag->model & CM_HEAD))
                TY_(Report)(doc, body, node, TAG_NOT_ALLOWED_IN);

            if (node->tag->model & CM_HTML)
            {
                /* copy body attributes if current body was inferred */
                if ( nodeIsBODY(node) && body->implicit 
                     && body->attributes == NULL )
                {
                    body->attributes = node->attributes;
                    node->attributes = NULL;
                }

                TY_(FreeNode)( doc, node);
                continue;
            }

            if (node->tag->model & CM_HEAD)
            {
                MoveToHead(doc, body, node);
                continue;
            }

            if (node->tag->model & CM_LIST)
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_UL);
                AddClassNoIndent(doc, node);
                lexer->excludeBlocks = yes;
            }
            else if (node->tag->model & CM_DEFLIST)
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_DL);
                lexer->excludeBlocks = yes;
            }
            else if (node->tag->model & (CM_TABLE | CM_ROWGRP | CM_ROW))
            {
                /* http://tidy.sf.net/issue/2855621 */
                if (node->type != EndTag) {
                    TY_(UngetToken)( doc );
                    node = TY_(InferredTag)(doc, TidyTag_TABLE);
                }
                lexer->excludeBlocks = yes;
            }
            else if ( nodeIsINPUT(node) )
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_FORM);
                lexer->excludeBlocks = yes;
            }
            else
            {
                if ( !TY_(nodeHasCM)(node, CM_ROW | CM_FIELD) )
                {
                    TY_(UngetToken)( doc );
                    return;
                }

                /* ignore </td> </th> <option> etc. */
                TY_(FreeNode)( doc, node );
                continue;
            }
        }

        if (node->type == EndTag)
        {
            if ( nodeIsBR(node) )
                node->type = StartTag;
            else if ( nodeIsP(node) )
            {
                node->type = StartEndTag;
                node->implicit = yes;
            }
            else if ( TY_(nodeHasCM)(node, CM_INLINE) )
                TY_(PopInline)( doc, node );
        }

        if (TY_(nodeIsElement)(node))
        {
            if (nodeIsMAIN(node)) {
                /*\ Issue #166 - repeated <main> element
                 *  How to efficiently search for a previous main element?
                \*/
                if ( TY_(FindNodeById)(doc, TidyTag_MAIN) )
                {
                    doc->badForm |= flg_BadMain; /* this is an ERROR in format */
                    TY_(Report)(doc, body, node, DISCARDING_UNEXPECTED);
                    TY_(FreeNode)( doc, node);
                    continue;
                }
            }
            /* Issue #20 - merging from Ger Hobbelt fork put back CM_MIXED, which had been
               removed to fix this issue - reverting to fix 880221e
             */
            if ( TY_(nodeHasCM)(node, CM_INLINE) )
            {
                /* HTML4 strict doesn't allow inline content here */
                /* but HTML2 does allow img elements as children of body */
                if ( nodeIsIMG(node) )
                    TY_(ConstrainVersion)(doc, ~VERS_HTML40_STRICT);
                else
                    TY_(ConstrainVersion)(doc, ~(VERS_HTML40_STRICT|VERS_HTML20));

                if (checkstack && !node->implicit)
                {
                    checkstack = no;

                    if ( TY_(InlineDup)(doc, node) > 0 )
                        continue;
                }

                mode = MixedContent;
            }
            else
            {
                checkstack = yes;
                mode = IgnoreWhitespace;
            }

            if (node->implicit)
                TY_(Report)(doc, body, node, INSERTING_TAG);

            TY_(InsertNodeAtEnd)(body, node);
            ParseTag(doc, node, mode);
            continue;
        }

        /* discard unexpected tags */
        TY_(Report)(doc, body, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }
    DEBUG_LOG(SPRTF("Exit ParseBody 1...\n"));
}

void TY_(ParseNoFrames)(TidyDocImpl* doc, Node *noframes, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    Node *node;

    if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
    {
        doc->badAccess |=  BA_USING_NOFRAMES;
    }
    mode = IgnoreWhitespace;

    while ( (node = TY_(GetToken)(doc, mode)) != NULL )
    {
        if ( node->tag == noframes->tag && node->type == EndTag )
        {
            TY_(FreeNode)( doc, node);
            noframes->closed = yes;
            TrimSpaces(doc, noframes);
            return;
        }

        if ( nodeIsFRAME(node) || nodeIsFRAMESET(node) )
        {
            TrimSpaces(doc, noframes);
            if (node->type == EndTag)
            {
                TY_(Report)(doc, noframes, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);       /* Throw it away */
            }
            else
            {
                TY_(Report)(doc, noframes, node, MISSING_ENDTAG_BEFORE);
                TY_(UngetToken)( doc );
            }
            return;
        }

        if ( nodeIsHTML(node) )
        {
            if (TY_(nodeIsElement)(node))
                TY_(Report)(doc, noframes, node, DISCARDING_UNEXPECTED);

            TY_(FreeNode)( doc, node);
            continue;
        }

        /* deal with comments etc. */
        if (InsertMisc(noframes, node))
            continue;

        if ( nodeIsBODY(node) && node->type == StartTag )
        {
            Bool seen_body = lexer->seenEndBody;
            TY_(InsertNodeAtEnd)(noframes, node);
            ParseTag(doc, node, IgnoreWhitespace /*MixedContent*/);

            /* fix for bug http://tidy.sf.net/bug/887259 */
            if (seen_body && TY_(FindBody)(doc) != node)
            {
                TY_(CoerceNode)(doc, node, TidyTag_DIV, no, no);
                MoveNodeToBody(doc, node);
            }
            continue;
        }

        /* implicit body element inferred */
        if (TY_(nodeIsText)(node) || (node->tag && node->type != EndTag))
        {
            Node *body = TY_(FindBody)( doc );
            if ( body || lexer->seenEndBody )
            {
                if ( body == NULL )
                {
                    TY_(Report)(doc, noframes, node, DISCARDING_UNEXPECTED);
                    TY_(FreeNode)( doc, node);
                    continue;
                }
                if ( TY_(nodeIsText)(node) )
                {
                    TY_(UngetToken)( doc );
                    node = TY_(InferredTag)(doc, TidyTag_P);
                    TY_(Report)(doc, noframes, node, CONTENT_AFTER_BODY );
                }
                TY_(InsertNodeAtEnd)( body, node );
            }
            else
            {
                TY_(UngetToken)( doc );
                node = TY_(InferredTag)(doc, TidyTag_BODY);
                if ( cfgBool(doc, TidyXmlOut) )
                    TY_(Report)(doc, noframes, node, INSERTING_TAG);
                TY_(InsertNodeAtEnd)( noframes, node );
            }

            ParseTag( doc, node, IgnoreWhitespace /*MixedContent*/ );
            continue;
        }

        /* discard unexpected end tags */
        TY_(Report)(doc, noframes, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    TY_(Report)(doc, noframes, node, MISSING_ENDTAG_FOR);
}

void TY_(ParseFrameSet)(TidyDocImpl* doc, Node *frameset, GetTokenMode ARG_UNUSED(mode))
{
    Lexer* lexer = doc->lexer;
    Node *node;

    if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
    {
        doc->badAccess |= BA_USING_FRAMES;
    }
    
    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->tag == frameset->tag && node->type == EndTag)
        {
            TY_(FreeNode)( doc, node);
            frameset->closed = yes;
            TrimSpaces(doc, frameset);
            return;
        }

        /* deal with comments etc. */
        if (InsertMisc(frameset, node))
            continue;

        if (node->tag == NULL)
        {
            TY_(Report)(doc, frameset, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue; 
        }

        if (TY_(nodeIsElement)(node))
        {
            if (node->tag && node->tag->model & CM_HEAD)
            {
                MoveToHead(doc, frameset, node);
                continue;
            }
        }

        if ( nodeIsBODY(node) )
        {
            TY_(UngetToken)( doc );
            node = TY_(InferredTag)(doc, TidyTag_NOFRAMES);
            TY_(Report)(doc, frameset, node, INSERTING_TAG);
        }

        if (node->type == StartTag && (node->tag->model & CM_FRAMES))
        {
            TY_(InsertNodeAtEnd)(frameset, node);
            lexer->excludeBlocks = no;
            ParseTag(doc, node, MixedContent);
            continue;
        }
        else if (node->type == StartEndTag && (node->tag->model & CM_FRAMES))
        {
            TY_(InsertNodeAtEnd)(frameset, node);
            continue;
        }

        /* discard unexpected tags */
        /* WAI [6.5.1.4] link is being discarded outside of NOFRAME */
        if ( nodeIsA(node) )
           doc->badAccess |= BA_INVALID_LINK_NOFRAMES;

        TY_(Report)(doc, frameset, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    TY_(Report)(doc, frameset, node, MISSING_ENDTAG_FOR);
}

void TY_(ParseHTML)(TidyDocImpl* doc, Node *html, GetTokenMode mode)
{
    Node *node, *head;
    Node *frameset = NULL;
    Node *noframes = NULL;

    DEBUG_LOG(SPRTF("Entering ParseHTML...\n"));
    TY_(SetOptionBool)( doc, TidyXmlTags, no );

    for (;;)
    {
        node = TY_(GetToken)(doc, IgnoreWhitespace);

        if (node == NULL)
        {
            node = TY_(InferredTag)(doc, TidyTag_HEAD);
            break;
        }

        if ( nodeIsHEAD(node) )
            break;

        if (node->tag == html->tag && node->type == EndTag)
        {
            TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        /* find and discard multiple <html> elements */
        if (node->tag == html->tag && node->type == StartTag)
        {
            TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)(doc, node);
            continue;
        }

        /* deal with comments etc. */
        if (InsertMisc(html, node))
            continue;

        TY_(UngetToken)( doc );
        node = TY_(InferredTag)(doc, TidyTag_HEAD);
        break;
    }

    head = node;
    TY_(InsertNodeAtEnd)(html, head);
    TY_(ParseHead)(doc, head, mode);

    for (;;)
    {
        node = TY_(GetToken)(doc, IgnoreWhitespace);

        if (node == NULL)
        {
            if (frameset == NULL) /* implied body */
            {
                node = TY_(InferredTag)(doc, TidyTag_BODY);
                TY_(InsertNodeAtEnd)(html, node);
                TY_(ParseBody)(doc, node, mode);
            }

            DEBUG_LOG(SPRTF("Exit ParseHTML 1...\n"));
            return;
        }

        /* robustly handle html tags */
        if (node->tag == html->tag)
        {
            if (node->type != StartTag && frameset == NULL)
                TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);

            TY_(FreeNode)( doc, node);
            continue;
        }

        /* deal with comments etc. */
        if (InsertMisc(html, node))
            continue;

        /* if frameset document coerce <body> to <noframes> */
        if ( nodeIsBODY(node) )
        {
            if (node->type != StartTag)
            {
                TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
            {
                if (frameset != NULL)
                {
                    TY_(UngetToken)( doc );

                    if (noframes == NULL)
                    {
                        noframes = TY_(InferredTag)(doc, TidyTag_NOFRAMES);
                        TY_(InsertNodeAtEnd)(frameset, noframes);
                        TY_(Report)(doc, html, noframes, INSERTING_TAG);
                    }
                    else
                    {
                        if (noframes->type == StartEndTag)
                            noframes->type = StartTag;
                    }

                    ParseTag(doc, noframes, mode);
                    continue;
                }
            }

            TY_(ConstrainVersion)(doc, ~VERS_FRAMESET);
            break;  /* to parse body */
        }

        /* flag an error if we see more than one frameset */
        if ( nodeIsFRAMESET(node) )
        {
            if (node->type != StartTag)
            {
                TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            if (frameset != NULL)
                TY_(Report)(doc, html, node, DUPLICATE_FRAMESET);
            else
                frameset = node;

            TY_(InsertNodeAtEnd)(html, node);
            ParseTag(doc, node, mode);

            /*
              see if it includes a noframes element so
              that we can merge subsequent noframes elements
            */

            for (node = frameset->content; node; node = node->next)
            {
                if ( nodeIsNOFRAMES(node) )
                    noframes = node;
            }
            continue;
        }

        /* if not a frameset document coerce <noframes> to <body> */
        if ( nodeIsNOFRAMES(node) )
        {
            if (node->type != StartTag)
            {
                TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                continue;
            }

            if (frameset == NULL)
            {
                TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
                node = TY_(InferredTag)(doc, TidyTag_BODY);
                break;
            }

            if (noframes == NULL)
            {
                noframes = node;
                TY_(InsertNodeAtEnd)(frameset, noframes);
            }
            else
                TY_(FreeNode)( doc, node);

            ParseTag(doc, noframes, mode);
            continue;
        }

        if (TY_(nodeIsElement)(node))
        {
            if (node->tag && node->tag->model & CM_HEAD)
            {
                MoveToHead(doc, html, node);
                continue;
            }

            /* discard illegal frame element following a frameset */
            if ( frameset != NULL && nodeIsFRAME(node) )
            {
                TY_(Report)(doc, html, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)(doc, node);
                continue;
            }
        }

        TY_(UngetToken)( doc );

        /* insert other content into noframes element */

        if (frameset)
        {
            if (noframes == NULL)
            {
                noframes = TY_(InferredTag)(doc, TidyTag_NOFRAMES);
                TY_(InsertNodeAtEnd)(frameset, noframes);
            }
            else
            {
                TY_(Report)(doc, html, node, NOFRAMES_CONTENT);
                if (noframes->type == StartEndTag)
                    noframes->type = StartTag;
            }

            TY_(ConstrainVersion)(doc, VERS_FRAMESET);
            ParseTag(doc, noframes, mode);
            continue;
        }

        node = TY_(InferredTag)(doc, TidyTag_BODY);
        /* Issue #132 - disable inserting BODY tag warning
           BUT only if NOT --show-body-only yes */
        if (!showingBodyOnly(doc))
            TY_(Report)(doc, html, node, INSERTING_TAG );
        TY_(ConstrainVersion)(doc, ~VERS_FRAMESET);
        break;
    }

    /* node must be body */

    TY_(InsertNodeAtEnd)(html, node);
    ParseTag(doc, node, mode);
    DEBUG_LOG(SPRTF("Exit ParseHTML 2...\n"));
}

static Bool nodeCMIsOnlyInline( Node* node )
{
    return TY_(nodeHasCM)( node, CM_INLINE ) && !TY_(nodeHasCM)( node, CM_BLOCK );
}

static void EncloseBodyText(TidyDocImpl* doc)
{
    Node* node;
    Node* body = TY_(FindBody)(doc);

    if (!body)
        return;

    node = body->content;

    while (node)
    {
        if ((TY_(nodeIsText)(node) && !TY_(IsBlank)(doc->lexer, node)) ||
            (TY_(nodeIsElement)(node) && nodeCMIsOnlyInline(node)))
        {
            Node* p = TY_(InferredTag)(doc, TidyTag_P);
            TY_(InsertNodeBeforeElement)(node, p);
            while (node && (!TY_(nodeIsElement)(node) || nodeCMIsOnlyInline(node)))
            {
                Node* next = node->next;
                TY_(RemoveNode)(node);
                TY_(InsertNodeAtEnd)(p, node);
                node = next;
            }
            TrimSpaces(doc, p);
            continue;
        }
        node = node->next;
    }
}

/* <form>, <blockquote> and <noscript> do not allow #PCDATA in
   HTML 4.01 Strict (%block; model instead of %flow;).
  When requested, text nodes in these elements are wrapped in <p>. */
static void EncloseBlockText(TidyDocImpl* doc, Node* node)
{
    Node *next;
    Node *block;

    while (node)
    {
        next = node->next;

        if (node->content)
            EncloseBlockText(doc, node->content);

        if (!(nodeIsFORM(node) || nodeIsNOSCRIPT(node) ||
              nodeIsBLOCKQUOTE(node))
            || !node->content)
        {
            node = next;
            continue;
        }

        block = node->content;

        if ((TY_(nodeIsText)(block) && !TY_(IsBlank)(doc->lexer, block)) ||
            (TY_(nodeIsElement)(block) && nodeCMIsOnlyInline(block)))
        {
            Node* p = TY_(InferredTag)(doc, TidyTag_P);
            TY_(InsertNodeBeforeElement)(block, p);
            while (block &&
                   (!TY_(nodeIsElement)(block) || nodeCMIsOnlyInline(block)))
            {
                Node* tempNext = block->next;
                TY_(RemoveNode)(block);
                TY_(InsertNodeAtEnd)(p, block);
                block = tempNext;
            }
            TrimSpaces(doc, p);
            continue;
        }

        node = next;
    }
}

static void ReplaceObsoleteElements(TidyDocImpl* doc, Node* node)
{
    Node *next;

    while (node)
    {
        next = node->next;

        /* if (nodeIsDIR(node) || nodeIsMENU(node)) */
        /* HTML5 - <menu ... > is no longer obsolete */
        if (nodeIsDIR(node))
            TY_(CoerceNode)(doc, node, TidyTag_UL, yes, yes);

        if (nodeIsXMP(node) || nodeIsLISTING(node) ||
            (node->tag && node->tag->id == TidyTag_PLAINTEXT))
            TY_(CoerceNode)(doc, node, TidyTag_PRE, yes, yes);

        if (node->content)
            ReplaceObsoleteElements(doc, node->content);

        node = next;
    }
}

static void AttributeChecks(TidyDocImpl* doc, Node* node)
{
    Node *next;

    while (node)
    {
        next = node->next;

        if (TY_(nodeIsElement)(node))
        {
            if (node->tag && node->tag->chkattrs) /* [i_a]2 fix crash after adding SVG support with alt/unknown tag subtree insertion there */
                node->tag->chkattrs(doc, node);
            else
                TY_(CheckAttributes)(doc, node);
        }

        if (node->content)
            AttributeChecks(doc, node->content);

        assert( next != node ); /* http://tidy.sf.net/issue/1603538 */
        node = next;
    }
}

/*
  HTML is the top level element
*/
void TY_(ParseDocument)(TidyDocImpl* doc)
{
    Node *node, *html, *doctype = NULL;

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        if (node->type == XmlDecl)
        {
            doc->xmlDetected = yes;

            if (TY_(FindXmlDecl)(doc) && doc->root.content)
            {
                TY_(Report)(doc, &doc->root, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)(doc, node);
                continue;
            }
            if (node->line > 1 || node->column != 1)
            {
                TY_(Report)(doc, &doc->root, node, SPACE_PRECEDING_XMLDECL);
            }
        }

        /* deal with comments etc. */
        if (InsertMisc( &doc->root, node ))
            continue;

        if (node->type == DocTypeTag)
        {
            if (doctype == NULL)
            {
                TY_(InsertNodeAtEnd)( &doc->root, node);
                doctype = node;
            }
            else
            {
                TY_(Report)(doc, &doc->root, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
            }
            continue;
        }

        if (node->type == EndTag)
        {
            TY_(Report)(doc, &doc->root, node, DISCARDING_UNEXPECTED);
            TY_(FreeNode)( doc, node);
            continue;
        }

        if (node->type == StartTag && nodeIsHTML(node))
        {
            AttVal *xmlns;

            xmlns = TY_(AttrGetById)(node, TidyAttr_XMLNS);

            if (AttrValueIs(xmlns, XHTML_NAMESPACE))
            {
                Bool htmlOut = cfgBool( doc, TidyHtmlOut );
                doc->lexer->isvoyager = yes;                  /* Unless plain HTML */
                TY_(SetOptionBool)( doc, TidyXhtmlOut, !htmlOut ); /* is specified, output*/
                TY_(SetOptionBool)( doc, TidyXmlOut, !htmlOut );   /* will be XHTML. */

                /* adjust other config options, just as in config.c */
                if ( !htmlOut )
                {
                    TY_(SetOptionBool)( doc, TidyUpperCaseTags, no );
                    TY_(SetOptionInt)( doc, TidyUpperCaseAttrs, no );
                }
            }
        }

        if ( node->type != StartTag || !nodeIsHTML(node) )
        {
            TY_(UngetToken)( doc );
            html = TY_(InferredTag)(doc, TidyTag_HTML);
        }
        else
            html = node;

        /*\
         *  #72, avoid MISSING_DOCTYPE if show-body-only. 
         *  #191, also if --doctype omit, that is TidyDoctypeOmit
         *  #342, adjust tags to html4-- if not 'auto' or 'html5'
        \*/
        if (!TY_(FindDocType)(doc)) 
        {
            unsigned int dtmode = cfg( doc, TidyDoctypeMode );
            if ((dtmode != TidyDoctypeOmit) && !showingBodyOnly(doc))
                TY_(Report)(doc, NULL, NULL, MISSING_DOCTYPE);
            if ((dtmode != TidyDoctypeAuto) && (dtmode != TidyDoctypeHtml5))
            {
                /*\
                 *  Issue #342 - if not doctype 'auto', or 'html5'
                 *  then reset mode htm4-- parsing
                \*/
                TY_(AdjustTags)(doc); /* Dynamically modify the tags table to html4-- mode */
            }
        }
        TY_(InsertNodeAtEnd)( &doc->root, html);
        TY_(ParseHTML)( doc, html, IgnoreWhitespace );
        break;
    }

    /* do this before any more document fixes */
    if ( cfg( doc, TidyAccessibilityCheckLevel ) > 0 )
        TY_(AccessibilityChecks)( doc );

    if (!TY_(FindHTML)(doc))
    {
        /* a later check should complain if <body> is empty */
        html = TY_(InferredTag)(doc, TidyTag_HTML);
        TY_(InsertNodeAtEnd)( &doc->root, html);
        TY_(ParseHTML)(doc, html, IgnoreWhitespace);
    }

    if (!TY_(FindTITLE)(doc))
    {
        Node* head = TY_(FindHEAD)(doc);
        /* #72, avoid MISSING_TITLE_ELEMENT if show-body-only (but allow InsertNodeAtEnd to avoid new warning) */
        if (!showingBodyOnly(doc))
        {
            TY_(Report)(doc, head, NULL, MISSING_TITLE_ELEMENT);
        }
        TY_(InsertNodeAtEnd)(head, TY_(InferredTag)(doc, TidyTag_TITLE));
    }

    AttributeChecks(doc, &doc->root);
    ReplaceObsoleteElements(doc, &doc->root);
    TY_(DropEmptyElements)(doc, &doc->root);
    CleanSpaces(doc, &doc->root);

    if (cfgBool(doc, TidyEncloseBodyText))
        EncloseBodyText(doc);
    if (cfgBool(doc, TidyEncloseBlockText))
        EncloseBlockText(doc, &doc->root);
}

Bool TY_(XMLPreserveWhiteSpace)( TidyDocImpl* doc, Node *element)
{
    AttVal *attribute;

    /* search attributes for xml:space */
    for (attribute = element->attributes; attribute; attribute = attribute->next)
    {
        if (attrIsXML_SPACE(attribute))
        {
            if (AttrValueIs(attribute, "preserve"))
                return yes;

            return no;
        }
    }

    if (element->element == NULL)
        return no;
        
    /* kludge for html docs without explicit xml:space attribute */
    if (nodeIsPRE(element)    ||
        nodeIsSCRIPT(element) ||
        nodeIsSTYLE(element)  ||
        TY_(FindParser)(doc, element) == TY_(ParsePre))
        return yes;

    /* kludge for XSL docs */
    if ( TY_(tmbstrcasecmp)(element->element, "xsl:text") == 0 )
        return yes;

    return no;
}

/*
  XML documents
*/
static void ParseXMLElement(TidyDocImpl* doc, Node *element, GetTokenMode mode)
{
    Lexer* lexer = doc->lexer;
    Node *node;

    /* if node is pre or has xml:space="preserve" then do so */

    if ( TY_(XMLPreserveWhiteSpace)(doc, element) )
        mode = Preformatted;

    while ((node = TY_(GetToken)(doc, mode)) != NULL)
    {
        if (node->type == EndTag &&
           node->element && element->element &&
           TY_(tmbstrcmp)(node->element, element->element) == 0)
        {
            TY_(FreeNode)( doc, node);
            element->closed = yes;
            break;
        }

        /* discard unexpected end tags */
        if (node->type == EndTag)
        {
            if (element)
                TY_(Report)(doc, element, node, UNEXPECTED_ENDTAG_IN);
            else
                TY_(Report)(doc, element, node, UNEXPECTED_ENDTAG_ERR);

            TY_(FreeNode)( doc, node);
            continue;
        }

        /* parse content on seeing start tag */
        if (node->type == StartTag)
            ParseXMLElement( doc, node, mode );

        TY_(InsertNodeAtEnd)(element, node);
    }

    /*
     if first child is text then trim initial space and
     delete text node if it is empty.
    */

    node = element->content;

    if (TY_(nodeIsText)(node) && mode != Preformatted)
    {
        if ( lexer->lexbuf[node->start] == ' ' )
        {
            node->start++;

            if (node->start >= node->end)
                TY_(DiscardElement)( doc, node );
        }
    }

    /*
     if last child is text then trim final space and
     delete the text node if it is empty
    */

    node = element->last;

    if (TY_(nodeIsText)(node) && mode != Preformatted)
    {
        if ( lexer->lexbuf[node->end - 1] == ' ' )
        {
            node->end--;

            if (node->start >= node->end)
                TY_(DiscardElement)( doc, node );
        }
    }
}

void TY_(ParseXMLDocument)(TidyDocImpl* doc)
{
    Node *node, *doctype = NULL;

    TY_(SetOptionBool)( doc, TidyXmlTags, yes );

    doc->xmlDetected = yes;

    while ((node = TY_(GetToken)(doc, IgnoreWhitespace)) != NULL)
    {
        /* discard unexpected end tags */
        if (node->type == EndTag)
        {
            TY_(Report)(doc, NULL, node, UNEXPECTED_ENDTAG);
            TY_(FreeNode)( doc, node);
            continue;
        }

         /* deal with comments etc. */
        if (InsertMisc( &doc->root, node))
            continue;

        if (node->type == DocTypeTag)
        {
            if (doctype == NULL)
            {
                TY_(InsertNodeAtEnd)( &doc->root, node);
                doctype = node;
            }
            else
            {
                TY_(Report)(doc, &doc->root, node, DISCARDING_UNEXPECTED);
                TY_(FreeNode)( doc, node);
            }
            continue;
        }

        if (node->type == StartEndTag)
        {
            TY_(InsertNodeAtEnd)( &doc->root, node);
            continue;
        }

       /* if start tag then parse element's content */
        if (node->type == StartTag)
        {
            TY_(InsertNodeAtEnd)( &doc->root, node );
            ParseXMLElement( doc, node, IgnoreWhitespace );
            continue;
        }

        TY_(Report)(doc, &doc->root, node, DISCARDING_UNEXPECTED);
        TY_(FreeNode)( doc, node);
    }

    /* ensure presence of initial <?xml version="1.0"?> */
    if ( cfgBool(doc, TidyXmlDecl) )
        TY_(FixXmlDecl)( doc );
}


/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/*
  pprint.c -- pretty print parse tree  
  
  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* #include "pprint.h" */
/* #include "tidy-int.h" */
/* #include "parser.h" */
/* #include "entities.h" */
/* #include "tmbstr.h" */
/* #include "utf8.h" */

/* *** FOR DEBUG ONLY *** */
/* #define DEBUG_PPRINT */
/* #define DEBUG_INDENT */
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_PPRINT)
extern void dbg_show_node( TidyDocImpl* doc, Node *node, int caller, int indent );
#endif

/*
  Block-level and unknown elements are printed on
  new lines and their contents indented 2 spaces

  Inline elements are printed inline.

  Inline content is wrapped on spaces (except in
  attribute values or preformatted text, after
  start tags and before end tags
*/

static void PPrintAsp( TidyDocImpl* doc, unsigned int indent, Node* node );
static void PPrintJste( TidyDocImpl* doc, unsigned int indent, Node* node );
static void PPrintPhp( TidyDocImpl* doc, unsigned int indent, Node* node );
static int  TextEndsWithNewline( Lexer *lexer, Node *node, unsigned int mode );
static int  TextStartsWithWhitespace( Lexer *lexer, Node *node, unsigned int start, unsigned int mode );
static Bool InsideHead( TidyDocImpl* doc, Node *node );
static Bool ShouldIndent( TidyDocImpl* doc, Node *node );

/*\
 * Issue #228 20150715 - macros to access --vertical-space tri state configuration parameter
\*/
#define TidyClassicVS ((cfgAutoBool( doc, TidyVertSpace ) == TidyYesState) ? yes : no)
#define TidyAddVS ((cfgAutoBool( doc, TidyVertSpace ) == TidyAutoState) ? no : yes )

/*\
 * 20150515 - support using tabs instead of spaces - Issue #108
 * GH: https://github.com/htacg/tidy-html5/issues/108 - Keep indent with tabs #108
 * SF: https://sourceforge.net/p/tidy/feature-requests/3/ - #3 tabs in place of spaces
\*/
static unsigned int indent_char = ' ';
void TY_(PPrintTabs)(void)
{
    indent_char = '\t';
}
void TY_(PPrintSpaces)(void)
{
    indent_char = ' ';
}

/* #431953 - start RJ Wraplen adjusted for smooth international ride */

typedef enum
{
  UC00, /* None                       */
  UCPC, /* Punctuation, Connector     */
  UCPD, /* Punctuation, Dash          */
  UCPE, /* Punctuation, Close         */
  UCPS, /* Punctuation, Open          */
  UCPI, /* Punctuation, Initial quote */
  UCPF, /* Punctuation, Final quote   */
  UCPO, /* Punctuation, Other         */
  UCZS, /* Separator, Space           */
  UCZL, /* Separator, Line            */
  UCZP  /* Separator, Paragraph       */
} UnicodeCategory;

/*
  From the original code, the following characters are removed:

    U+2011 (non-breaking hyphen)
    U+202F (narrow non-break space)
    U+2044 (fraction slash) 
    U+200B (zero width space)
    ...... (bidi formatting control characters)

  U+2011 and U+202F are non-breaking, U+2044 is a Sm character,
  U+200B is a non-visible space, wrapping after it would make
  this space visible, bidi should be done using HTML features
  and the characters are neither Px or Zx.

  The following Unicode 3.0 punctuation characters are added:

    U+2048 (question exclamation mark)
    U+2049 (exclamation question mark)
    U+204A (tironian sign et)
    U+204B (reversed pilcrow sign)
    U+204C (black leftwards bullet)
    U+204D (black rightwards bullet)
    U+3030 (wavy dash)
    U+30FB (katakana middle dot)
    U+FE63 (small hyphen-minus)
    U+FE68 (small reverse solidus)
    U+FF3F (fullwidth low line)
    U+FF5B (fullwidth left curly bracket)
    U+FF5D (fullwidth right curly bracket)

  Other additional characters were not included in Unicode 3.0.
  The table is based on Unicode 4.0. It must include only those
  characters marking a wrapping point, "before" if the general
  category is UCPS or UCPI, otherwise "after".
*/
static struct _unicode4cat
{
  unsigned long code;
  UnicodeCategory category;
} const unicode4cat[] =
{
  { 0x2000, UCZS }, { 0x2001, UCZS }, { 0x2002, UCZS }, { 0x2003, UCZS },
  { 0x2004, UCZS }, { 0x2005, UCZS }, { 0x2006, UCZS }, { 0x2008, UCZS },
  { 0x2009, UCZS }, { 0x200A, UCZS }, { 0x2010, UCPD }, { 0x2012, UCPD },
  { 0x2013, UCPD }, { 0x2014, UCPD }, { 0x2015, UCPD }, { 0x2016, UCPO },
  { 0x2017, UCPO }, { 0x2018, UCPI }, { 0x2019, UCPF }, { 0x201A, UCPS },
  { 0x201B, UCPI }, { 0x201C, UCPI }, { 0x201D, UCPF }, { 0x201E, UCPS },
  { 0x201F, UCPI }, { 0x2020, UCPO }, { 0x2021, UCPO }, { 0x2022, UCPO },
  { 0x2023, UCPO }, { 0x2024, UCPO }, { 0x2025, UCPO }, { 0x2026, UCPO },
  { 0x2027, UCPO }, { 0x2028, UCZL }, { 0x2029, UCZP }, { 0x2030, UCPO },
  { 0x2031, UCPO }, { 0x2032, UCPO }, { 0x2033, UCPO }, { 0x2034, UCPO },
  { 0x2035, UCPO }, { 0x2036, UCPO }, { 0x2037, UCPO }, { 0x2038, UCPO },
  { 0x2039, UCPI }, { 0x203A, UCPF }, { 0x203B, UCPO }, { 0x203C, UCPO },
  { 0x203D, UCPO }, { 0x203E, UCPO }, { 0x203F, UCPC }, { 0x2040, UCPC },
  { 0x2041, UCPO }, { 0x2042, UCPO }, { 0x2043, UCPO }, { 0x2045, UCPS },
  { 0x2046, UCPE }, { 0x2047, UCPO }, { 0x2048, UCPO }, { 0x2049, UCPO },
  { 0x204A, UCPO }, { 0x204B, UCPO }, { 0x204C, UCPO }, { 0x204D, UCPO },
  { 0x204E, UCPO }, { 0x204F, UCPO }, { 0x2050, UCPO }, { 0x2051, UCPO },
  { 0x2053, UCPO }, { 0x2054, UCPC }, { 0x2057, UCPO }, { 0x205F, UCZS },
  { 0x207D, UCPS }, { 0x207E, UCPE }, { 0x208D, UCPS }, { 0x208E, UCPE },
  { 0x2329, UCPS }, { 0x232A, UCPE }, { 0x23B4, UCPS }, { 0x23B5, UCPE },
  { 0x23B6, UCPO }, { 0x2768, UCPS }, { 0x2769, UCPE }, { 0x276A, UCPS },
  { 0x276B, UCPE }, { 0x276C, UCPS }, { 0x276D, UCPE }, { 0x276E, UCPS },
  { 0x276F, UCPE }, { 0x2770, UCPS }, { 0x2771, UCPE }, { 0x2772, UCPS },
  { 0x2773, UCPE }, { 0x2774, UCPS }, { 0x2775, UCPE }, { 0x27E6, UCPS },
  { 0x27E7, UCPE }, { 0x27E8, UCPS }, { 0x27E9, UCPE }, { 0x27EA, UCPS },
  { 0x27EB, UCPE }, { 0x2983, UCPS }, { 0x2984, UCPE }, { 0x2985, UCPS },
  { 0x2986, UCPE }, { 0x2987, UCPS }, { 0x2988, UCPE }, { 0x2989, UCPS },
  { 0x298A, UCPE }, { 0x298B, UCPS }, { 0x298C, UCPE }, { 0x298D, UCPS },
  { 0x298E, UCPE }, { 0x298F, UCPS }, { 0x2990, UCPE }, { 0x2991, UCPS },
  { 0x2992, UCPE }, { 0x2993, UCPS }, { 0x2994, UCPE }, { 0x2995, UCPS },
  { 0x2996, UCPE }, { 0x2997, UCPS }, { 0x2998, UCPE }, { 0x29D8, UCPS },
  { 0x29D9, UCPE }, { 0x29DA, UCPS }, { 0x29DB, UCPE }, { 0x29FC, UCPS },
  { 0x29FD, UCPE }, { 0x3001, UCPO }, { 0x3002, UCPO }, { 0x3003, UCPO },
  { 0x3008, UCPS }, { 0x3009, UCPE }, { 0x300A, UCPS }, { 0x300B, UCPE },
  { 0x300C, UCPS }, { 0x300D, UCPE }, { 0x300E, UCPS }, { 0x300F, UCPE },
  { 0x3010, UCPS }, { 0x3011, UCPE }, { 0x3014, UCPS }, { 0x3015, UCPE },
  { 0x3016, UCPS }, { 0x3017, UCPE }, { 0x3018, UCPS }, { 0x3019, UCPE },
  { 0x301A, UCPS }, { 0x301B, UCPE }, { 0x301C, UCPD }, { 0x301D, UCPS },
  { 0x301E, UCPE }, { 0x301F, UCPE }, { 0x3030, UCPD }, { 0x303D, UCPO },
  { 0x30A0, UCPD }, { 0x30FB, UCPC }, { 0xFD3E, UCPS }, { 0xFD3F, UCPE },
  { 0xFE30, UCPO }, { 0xFE31, UCPD }, { 0xFE32, UCPD }, { 0xFE33, UCPC },
  { 0xFE34, UCPC }, { 0xFE35, UCPS }, { 0xFE36, UCPE }, { 0xFE37, UCPS },
  { 0xFE38, UCPE }, { 0xFE39, UCPS }, { 0xFE3A, UCPE }, { 0xFE3B, UCPS },
  { 0xFE3C, UCPE }, { 0xFE3D, UCPS }, { 0xFE3E, UCPE }, { 0xFE3F, UCPS },
  { 0xFE40, UCPE }, { 0xFE41, UCPS }, { 0xFE42, UCPE }, { 0xFE43, UCPS },
  { 0xFE44, UCPE }, { 0xFE45, UCPO }, { 0xFE46, UCPO }, { 0xFE47, UCPS },
  { 0xFE48, UCPE }, { 0xFE49, UCPO }, { 0xFE4A, UCPO }, { 0xFE4B, UCPO },
  { 0xFE4C, UCPO }, { 0xFE4D, UCPC }, { 0xFE4E, UCPC }, { 0xFE4F, UCPC },
  { 0xFE50, UCPO }, { 0xFE51, UCPO }, { 0xFE52, UCPO }, { 0xFE54, UCPO },
  { 0xFE55, UCPO }, { 0xFE56, UCPO }, { 0xFE57, UCPO }, { 0xFE58, UCPD },
  { 0xFE59, UCPS }, { 0xFE5A, UCPE }, { 0xFE5B, UCPS }, { 0xFE5C, UCPE },
  { 0xFE5D, UCPS }, { 0xFE5E, UCPE }, { 0xFE5F, UCPO }, { 0xFE60, UCPO },
  { 0xFE61, UCPO }, { 0xFE63, UCPD }, { 0xFE68, UCPO }, { 0xFE6A, UCPO },
  { 0xFE6B, UCPO }, { 0xFF01, UCPO }, { 0xFF02, UCPO }, { 0xFF03, UCPO },
  { 0xFF05, UCPO }, { 0xFF06, UCPO }, { 0xFF07, UCPO }, { 0xFF08, UCPS },
  { 0xFF09, UCPE }, { 0xFF0A, UCPO }, { 0xFF0C, UCPO }, { 0xFF0D, UCPD },
  { 0xFF0E, UCPO }, { 0xFF0F, UCPO }, { 0xFF1A, UCPO }, { 0xFF1B, UCPO },
  { 0xFF1F, UCPO }, { 0xFF20, UCPO }, { 0xFF3B, UCPS }, { 0xFF3C, UCPO },
  { 0xFF3D, UCPE }, { 0xFF3F, UCPC }, { 0xFF5B, UCPS }, { 0xFF5D, UCPE },
  { 0xFF5F, UCPS }, { 0xFF60, UCPE }, { 0xFF61, UCPO }, { 0xFF62, UCPS },
  { 0xFF63, UCPE }, { 0xFF64, UCPO }, { 0xFF65, UCPC }, { 0x10100,UCPO },
  { 0x10101,UCPO }, { 0x1039F,UCPO },

  /* final entry */
  { 0x0000, UC00 }
};

typedef enum
{
    NoWrapPoint,
    WrapBefore,
    WrapAfter
} WrapPoint;

/*
  If long lines of text have no white space as defined in HTML 4
  (U+0009, U+000A, U+000D, U+000C, U+0020) other characters could
  be used to determine a wrap point. Since user agents would
  normalize the inserted newline character to a space character,
  this wrapping behaviour would insert visual whitespace into the
  document.

  Characters of the General Category Pi and Ps in the Unicode
  character database (opening punctuation and intial quote
  characters) mark a wrapping point before the character, other
  punctuation characters (Pc, Pd, Pe, Pf, and Po), breakable
  space characters (Zs), and paragraph and line separators
  (Zl, Zp) mark a wrap point after the character. Using this
  function Tidy can for example pretty print

    <p>....................&ldquo;...quote...&rdquo;...</p>
  as
    <p>....................\n&ldquo;...quote...&rdquo;...</p>
  or
    <p>....................&ldquo;...quote...&rdquo;\n...</p>

  if the next normal wrapping point would exceed the user
  chosen wrapping column.
*/
static WrapPoint CharacterWrapPoint(tchar c)
{
    int i;
    for (i = 0; unicode4cat[i].code && unicode4cat[i].code <= c; ++i)
        if (unicode4cat[i].code == c)
        {
            /* wrapping before opening punctuation and initial quotes */
            if (unicode4cat[i].category == UCPS ||
                unicode4cat[i].category == UCPI)
                return WrapBefore;
            /* else wrapping after this character */
            else
                return WrapAfter;
        }
    /* character has no effect on line wrapping */
    return NoWrapPoint;
}

static WrapPoint Big5WrapPoint(tchar c)
{
    if ((c & 0xFF00) == 0xA100)
    { 
        /* opening brackets have odd codes: break before them */ 
        if ( c > 0xA15C && c < 0xA1AD && (c & 1) == 1 ) 
            return WrapBefore;
        return WrapAfter;
    }
    return NoWrapPoint;
}


static void InitIndent( TidyIndent* ind )
{
    ind->spaces = -1;
    ind->attrValStart = -1;
    ind->attrStringStart = -1;
}

void TY_(InitPrintBuf)( TidyDocImpl* doc )
{
    TidyClearMemory( &doc->pprint, sizeof(TidyPrintImpl) );
    InitIndent( &doc->pprint.indent[0] );
    InitIndent( &doc->pprint.indent[1] );
    doc->pprint.allocator = doc->allocator;
    doc->pprint.line = 0;
}

void TY_(FreePrintBuf)( TidyDocImpl* doc )
{
    TidyDocFree( doc, doc->pprint.linebuf );
    TY_(InitPrintBuf)( doc );
}

static void expand( TidyPrintImpl* pprint, unsigned int len )
{
    unsigned int* ip;
    unsigned int buflen = pprint->lbufsize;

    if ( buflen == 0 )
        buflen = 256;
    while ( len >= buflen )
        buflen *= 2;

    ip = (unsigned int*) TidyRealloc( pprint->allocator, pprint->linebuf, buflen*sizeof(unsigned int) );
    if ( ip )
    {
      TidyClearMemory( ip+pprint->lbufsize, 
                       (buflen-pprint->lbufsize)*sizeof(unsigned int) );
      pprint->lbufsize = buflen;
      pprint->linebuf = ip;
    }
}

static unsigned int GetSpaces( TidyPrintImpl* pprint )
{
    int spaces = pprint->indent[ 0 ].spaces;
    return ( spaces < 0 ? 0U : (unsigned int) spaces );
}
static int ClearInString( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + pprint->ixInd;
    return ind->attrStringStart = -1;
}
static int ToggleInString( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + pprint->ixInd;
    Bool inString = ( ind->attrStringStart >= 0 );
    return ind->attrStringStart = ( inString ? -1 : (int) pprint->linelen );
}
static Bool IsInString( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + 0; /* Always 1st */
    return ( ind->attrStringStart >= 0 && 
             ind->attrStringStart < (int) pprint->linelen );
}
static Bool IsWrapInString( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + 0; /* Always 1st */
    int wrap = (int) pprint->wraphere;
    return ( ind->attrStringStart == 0 ||
             (ind->attrStringStart > 0 && ind->attrStringStart < wrap) );
}

static Bool HasMixedContent (Node *element)
{
    Node * node;

    if (!element)
        return no;

    for (node = element->content; node; node = node->next)
        if ( TY_(nodeIsText)(node) )
             return yes;

    return no;
}

static void ClearInAttrVal( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + pprint->ixInd;
    ind->attrValStart = -1;
}
static int SetInAttrVal( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + pprint->ixInd;
    return ind->attrValStart = (int) pprint->linelen;
}
static Bool IsWrapInAttrVal( TidyPrintImpl* pprint )
{
    TidyIndent *ind = pprint->indent + 0; /* Always 1st */
    int wrap = (int) pprint->wraphere;
    return ( ind->attrValStart == 0 ||
             (ind->attrValStart > 0 && ind->attrValStart < wrap) );
}

static Bool WantIndent( TidyDocImpl* doc )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool wantIt = GetSpaces(pprint) > 0;
    if ( wantIt )
    {
        Bool indentAttrs = cfgBool( doc, TidyIndentAttributes );
        wantIt = ( ( !IsWrapInAttrVal(pprint) || indentAttrs ) &&
                   !IsWrapInString(pprint) );
    }
    return wantIt;
}


static unsigned int  WrapOff( TidyDocImpl* doc )
{
    unsigned int saveWrap = cfg( doc, TidyWrapLen );
    TY_(SetOptionInt)( doc, TidyWrapLen, 0xFFFFFFFF );  /* very large number */
    return saveWrap;
}

static void  WrapOn( TidyDocImpl* doc, unsigned int saveWrap )
{
    TY_(SetOptionInt)( doc, TidyWrapLen, saveWrap );
}

static unsigned int  WrapOffCond( TidyDocImpl* doc, Bool onoff )
{
    if ( onoff )
        return WrapOff( doc );
    return cfg( doc, TidyWrapLen );
}


static void AddC( TidyPrintImpl* pprint, unsigned int c, unsigned int string_index)
{
    if ( string_index + 1 >= pprint->lbufsize )
        expand( pprint, string_index + 1 );
    pprint->linebuf[string_index] = c;
}

static unsigned int AddChar( TidyPrintImpl* pprint, unsigned int c )
{
    AddC( pprint, c, pprint->linelen );
    return ++pprint->linelen;
}

static unsigned int AddAsciiString( TidyPrintImpl* pprint, ctmbstr str, unsigned int string_index )
{
    unsigned int ix, len = TY_(tmbstrlen)( str );
    if ( string_index + len >= pprint->lbufsize )
        expand( pprint, string_index + len );

    for ( ix=0; ix<len; ++ix )
        pprint->linebuf[string_index + ix] = str[ ix ];
    return string_index + len;
}

static unsigned int AddString( TidyPrintImpl* pprint, ctmbstr str )
{
   return pprint->linelen = AddAsciiString( pprint, str, pprint->linelen );
}

/* Saves current output point as the wrap point,
** but only if indentation would NOT overflow 
** the current line.  Otherwise keep previous wrap point.
*/
static Bool SetWrap( TidyDocImpl* doc, unsigned int indent )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool wrap = ( indent + pprint->linelen < cfg(doc, TidyWrapLen) );
    if ( wrap )
    {
        if ( pprint->indent[0].spaces < 0 )
            pprint->indent[0].spaces = indent;
        pprint->wraphere = pprint->linelen;
    }
    else if ( pprint->ixInd == 0 )
    {
        /* Save indent 1st time we pass the the wrap line */
        pprint->indent[ 1 ].spaces = indent;
        pprint->ixInd = 1;
    }
    return wrap;
}

static void CarryOver( int* valTo, int* valFrom, unsigned int wrapPoint )
{
  if ( *valFrom > (int) wrapPoint )
  {
    *valTo = *valFrom - wrapPoint;
    *valFrom = -1;
  }
}


static Bool SetWrapAttr( TidyDocImpl* doc,
                         unsigned int indent, int attrStart, int strStart )
{
    TidyPrintImpl* pprint = &doc->pprint;
    TidyIndent *ind = pprint->indent + 0;

    Bool wrap = ( indent + pprint->linelen < cfg(doc, TidyWrapLen) );
    if ( wrap )
    {
        if ( ind[0].spaces < 0 )
            ind[0].spaces = indent;
        pprint->wraphere = pprint->linelen;
    }
    else if ( pprint->ixInd == 0 )
    {
        /* Save indent 1st time we pass the the wrap line */
        pprint->indent[ 1 ].spaces = indent;
        pprint->ixInd = 1;

        /* Carry over string state */
        CarryOver( &ind[1].attrStringStart, &ind[0].attrStringStart, pprint->wraphere );
        CarryOver( &ind[1].attrValStart, &ind[0].attrValStart, pprint->wraphere );
    }
    ind += doc->pprint.ixInd;
    ind->attrValStart = attrStart;
    ind->attrStringStart = strStart;
    return wrap;
}


/* Reset indent state after flushing a new line
*/
static void ResetLine( TidyPrintImpl* pprint )
{
    TidyIndent* ind = pprint->indent + 0;
    if ( pprint->ixInd > 0 )
    {
        ind[0] = ind[1];
        InitIndent( &ind[1] );
    }

    if ( pprint->wraphere > 0 )
    {
        int wrap = (int) pprint->wraphere;
        if ( ind[0].attrStringStart > wrap )
            ind[0].attrStringStart -= wrap;
        if ( ind[0].attrValStart > wrap )
            ind[0].attrValStart -= wrap;
    }
    else
    {
        if ( ind[0].attrStringStart > 0 )
            ind[0].attrStringStart = 0;
        if ( ind[0].attrValStart > 0 )
            ind[0].attrValStart = 0;
    }
    pprint->wraphere = pprint->ixInd = 0;
}

/* Shift text after wrap point to
** beginning of next line.
*/
static void ResetLineAfterWrap( TidyPrintImpl* pprint )
{
    if ( pprint->linelen > pprint->wraphere )
    {
        unsigned int *p = pprint->linebuf;
        unsigned int *q = p + pprint->wraphere;
        unsigned int *end = p + pprint->linelen;

        if ( ! IsWrapInAttrVal(pprint) )
        {
            while ( q < end && *q == ' ' )
                ++q, ++pprint->wraphere;
        }

        while ( q < end )
            *p++ = *q++;

        pprint->linelen -= pprint->wraphere;
    }
    else
    {
        pprint->linelen = 0;
    }

    ResetLine( pprint );
}

/*\
 *  Write the 'indent' char to output
 *  Issue #335 - The GetSpaces() returns the number of spaces to be
 *  used for the indent. This is fine if ouputting spaces.
 *  However, if outputting 'tab' chars, then the number of tabs 
 *  output should euivalent to spaces divided by 'tab-size'
\*/
static void WriteIndentChar(TidyDocImpl* doc )
{
    TidyPrintImpl* pprint = &doc->pprint;
    unsigned int i;
    unsigned int spaces = GetSpaces(pprint);
    unsigned int tabsize = cfg(doc, TidyTabSize);
    if (spaces && (indent_char == '\t') && tabsize)
    {
        spaces /= tabsize;  // set number of tabs to output
        if (spaces == 0)    // with a minimum of one
            spaces = 1;
    }
    for (i = 0; i < spaces; i++)
        TY_(WriteChar)(indent_char, doc->docOut); /* 20150515 - Issue #108 */

}

/* Goes ahead with writing current line up to
** previously saved wrap point.  Shifts unwritten
** text in output buffer to beginning of next line.
*/
static void WrapLine( TidyDocImpl* doc )
{
    TidyPrintImpl* pprint = &doc->pprint;
    unsigned int i;

    if ( pprint->wraphere == 0 )
        return;

    if ( WantIndent(doc) )
        WriteIndentChar(doc);

    for ( i = 0; i < pprint->wraphere; ++i )
        TY_(WriteChar)( pprint->linebuf[i], doc->docOut );

    if ( IsWrapInString(pprint) )
        TY_(WriteChar)( '\\', doc->docOut );

    TY_(WriteChar)( '\n', doc->docOut );
    pprint->line++;
    ResetLineAfterWrap( pprint );
}

/* Checks current output line length along with current indent.
** If combined they overflow output line length, go ahead
** and flush output up to the current wrap point.
*/
static Bool CheckWrapLine( TidyDocImpl* doc )
{
    TidyPrintImpl* pprint = &doc->pprint;
    if ( GetSpaces(pprint) + pprint->linelen >= cfg(doc, TidyWrapLen) )
    {
        WrapLine( doc );
        return yes;
    }
    return no;
}

static Bool CheckWrapIndent( TidyDocImpl* doc, unsigned int indent )
{
    TidyPrintImpl* pprint = &doc->pprint;
    if ( GetSpaces(pprint) + pprint->linelen >= cfg(doc, TidyWrapLen) )
    {
        WrapLine( doc );
        if ( pprint->indent[ 0 ].spaces < 0 )
        {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
            SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
            pprint->indent[ 0 ].spaces = indent;
        }
        return yes;
    }
    return no;
}

static void WrapAttrVal( TidyDocImpl* doc )
{
    TidyPrintImpl* pprint = &doc->pprint;
    unsigned int i;

    /* assert( IsWrapInAttrVal(pprint) ); */
    if ( WantIndent(doc) )
        WriteIndentChar(doc);

    for ( i = 0; i < pprint->wraphere; ++i )
        TY_(WriteChar)( pprint->linebuf[i], doc->docOut );

    if ( IsWrapInString(pprint) )
        TY_(WriteChar)( '\\', doc->docOut );
    else
        TY_(WriteChar)( ' ', doc->docOut );

    TY_(WriteChar)( '\n', doc->docOut );
    pprint->line++;
    ResetLineAfterWrap( pprint );
}

static void PFlushLineImpl( TidyDocImpl* doc )
{
    TidyPrintImpl* pprint = &doc->pprint;

    unsigned int i;

    CheckWrapLine( doc );

    if ( WantIndent(doc) )
        WriteIndentChar(doc);

    for ( i = 0; i < pprint->linelen; ++i )
        TY_(WriteChar)( pprint->linebuf[i], doc->docOut );

    if ( IsInString(pprint) )
        TY_(WriteChar)( '\\', doc->docOut );
    ResetLine( pprint );
    pprint->linelen = 0;
}

void TY_(PFlushLine)( TidyDocImpl* doc, unsigned int indent )
{
    TidyPrintImpl* pprint = &doc->pprint;

    if ( pprint->linelen > 0 )
        PFlushLineImpl( doc );

    TY_(WriteChar)( '\n', doc->docOut );
    pprint->line++;

    if (pprint->indent[ 0 ].spaces != (int)indent )
    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
        SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
        pprint->indent[ 0 ].spaces = indent;
    }
}

static void PCondFlushLine( TidyDocImpl* doc, unsigned int indent )
{
    TidyPrintImpl* pprint = &doc->pprint;

    if ( pprint->linelen > 0 )
    {
         PFlushLineImpl( doc );

         TY_(WriteChar)( '\n', doc->docOut );
         pprint->line++;
    }

    /* Issue #390 - Whether chars to flush or not, set new indent */
    if ( pprint->indent[ 0 ].spaces != (int)indent )
    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
        SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
         pprint->indent[ 0 ].spaces = indent;
    }
}

/**
 * Two additional "smart" flush line functions which only
 * write a newline if `vertical-space no`. See issues #163 and #227.
 * These need to be used in the right place. In same cases `PFlushLine`
 * and `PCondFlushLine` should still be used.
 */
void TY_(PFlushLineSmart)( TidyDocImpl* doc, unsigned int indent )
{
    TidyPrintImpl* pprint = &doc->pprint;

    if ( pprint->linelen > 0 )
        PFlushLineImpl( doc );

    /* Issue #228 - cfgBool( doc, TidyVertSpace ); */
    if(TidyAddVS) {
        TY_(WriteChar)( '\n', doc->docOut );
        pprint->line++;
    }

    if ( pprint->indent[ 0 ].spaces != (int)indent )
    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
        SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
        pprint->indent[ 0 ].spaces = indent;
    }
}

static void PCondFlushLineSmart( TidyDocImpl* doc, unsigned int indent )
{
    TidyPrintImpl* pprint = &doc->pprint;

    if ( pprint->linelen > 0 )
    {
         PFlushLineImpl( doc );

         /* Issue #228 - cfgBool( doc, TidyVertSpace ); */
         if(TidyAddVS) {
            TY_(WriteChar)( '\n', doc->docOut );
            pprint->line++;
         }
    }

    /*\
     *  Issue #390 - Must still deal with fixing indent!
     *  If TidyOmitOptionalTags, then in cerain circumstances no PrintEndTag
     *  will be done, so linelen will be 0...
    \*/
    if (pprint->indent[ 0 ].spaces != (int)indent)
    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
        SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
        pprint->indent[ 0 ].spaces = indent;
    }
}

static void PPrintChar( TidyDocImpl* doc, unsigned int c, unsigned int mode )
{
    tmbchar entity[128];
    ctmbstr p;
    TidyPrintImpl* pprint  = &doc->pprint;
    unsigned int outenc = cfg( doc, TidyOutCharEncoding );
    Bool qmark = cfgBool( doc, TidyQuoteMarks );

    if ( c == ' ' && !(mode & (PREFORMATTED | COMMENT | ATTRIBVALUE | CDATA)))
    {
        /* coerce a space character to a non-breaking space */
        if (mode & NOWRAP)
        {
            ctmbstr ent = "&nbsp;";
            /* by default XML doesn't define &nbsp; */
            if ( cfgBool(doc, TidyNumEntities) || cfgBool(doc, TidyXmlTags) )
                ent = "&#160;";
            AddString( pprint, ent );
            return;
        }
        else
            pprint->wraphere = pprint->linelen;
    }

    /* comment characters are passed raw */
    if ( mode & (COMMENT | CDATA) )
    {
        AddChar( pprint, c );
        return;
    }

    /* except in CDATA map < to &lt; etc. */
    if ( !(mode & CDATA) )
    {
        if ( c == '<')
        {
            AddString( pprint, "&lt;" );
            return;
        }
            
        if ( c == '>')
        {
            AddString( pprint, "&gt;" );
            return;
        }

        /*
          naked '&' chars can be left alone or
          quoted as &amp; The latter is required
          for XML where naked '&' are illegal.
        */
        if ( c == '&' && cfgBool(doc, TidyQuoteAmpersand)
             && !cfgBool(doc, TidyPreserveEntities)
             && ( mode != OtherNamespace) ) /* #130 MathML attr and entity fix! */
        {
            AddString( pprint, "&amp;" );
            return;
        }

        if ( c == '"' && qmark )
        {
            AddString( pprint, "&quot;" );
            return;
        }

        if ( c == '\'' && qmark )
        {
            AddString( pprint, "&#39;" );
            return;
        }

        if ( c == 160 && outenc != RAW )
        {
            if ( cfgBool(doc, TidyQuoteNbsp) )
            {
                if ( cfgBool(doc, TidyNumEntities) ||
                     cfgBool(doc, TidyXmlTags) )
                    AddString( pprint, "&#160;" );
                else
                    AddString( pprint, "&nbsp;" );
            }
            else
                AddChar( pprint, c );
            return;
        }
    }

    /* #431953 - start RJ */
    /* Handle encoding-specific issues */
    switch ( outenc )
    {
    case UTF8:
    case UTF16:
    case UTF16LE:
    case UTF16BE:
        if (!(mode & PREFORMATTED) && cfg(doc, TidyPunctWrap))
        {
            WrapPoint wp = CharacterWrapPoint(c);
            if (wp == WrapBefore)
                pprint->wraphere = pprint->linelen;
            else if (wp == WrapAfter)
                pprint->wraphere = pprint->linelen + 1;
        }
        break;

    case BIG5:
        /* Allow linebreak at Chinese punctuation characters */
        /* There are not many spaces in Chinese */
        AddChar( pprint, c );
        if (!(mode & PREFORMATTED)  && cfg(doc, TidyPunctWrap))
        {
            WrapPoint wp = Big5WrapPoint(c);
            if (wp == WrapBefore)
                pprint->wraphere = pprint->linelen;
            else if (wp == WrapAfter)
                pprint->wraphere = pprint->linelen + 1;
        }
        return;

    case SHIFTJIS:
#ifndef NO_NATIVE_ISO2022_SUPPORT
    case ISO2022: /* ISO 2022 characters are passed raw */
#endif
    case RAW:
        AddChar( pprint, c );
        return;
    }

    /* don't map latin-1 chars to entities */
    if ( outenc == LATIN1 )
    {
        if (c > 255)  /* multi byte chars */
        {
            unsigned int vers = TY_(HTMLVersion)( doc );
            if ( !cfgBool(doc, TidyNumEntities) && (p = TY_(EntityName)(c, vers)) )
                TY_(tmbsnprintf)(entity, sizeof(entity), "&%s;", p);
            else
                TY_(tmbsnprintf)(entity, sizeof(entity), "&#%u;", c);

            AddString( pprint, entity );
            return;
        }

        if (c > 126 && c < 160)
        {
            TY_(tmbsnprintf)(entity, sizeof(entity), "&#%u;", c);
            AddString( pprint, entity );
            return;
        }

        AddChar( pprint, c );
        return;
    }

    /* don't map UTF-8 chars to entities */
    if ( outenc == UTF8 )
    {
        AddChar( pprint, c );
        return;
    }

    /* don't map UTF-16 chars to entities */
    if ( outenc == UTF16 || outenc == UTF16LE || outenc == UTF16BE )
    {
        AddChar( pprint, c );
        return;
    }

    /* use numeric entities only  for XML */
    if ( cfgBool(doc, TidyXmlTags) )
    {
        /* if ASCII use numeric entities for chars > 127 */
        if ( c > 127 && outenc == ASCII )
        {
            TY_(tmbsnprintf)(entity, sizeof(entity), "&#%u;", c);
            AddString( pprint, entity );
            return;
        }

        /* otherwise output char raw */
        AddChar( pprint, c );
        return;
    }

    /* default treatment for ASCII */
    if ( outenc == ASCII && (c > 126 || (c < ' ' && c != '\t')) )
    {
        unsigned int vers = TY_(HTMLVersion)( doc );
        if (!cfgBool(doc, TidyNumEntities) && (p = TY_(EntityName)(c, vers)) )
            TY_(tmbsnprintf)(entity, sizeof(entity), "&%s;", p);
        else
            TY_(tmbsnprintf)(entity, sizeof(entity), "&#%u;", c);

        AddString( pprint, entity );
        return;
    }

    AddChar( pprint, c );
}

static unsigned int IncrWS( unsigned int start, unsigned int end, unsigned int indent, int ixWS )
{
  if ( ixWS > 0 )
  {
    unsigned int st = start + MIN( (unsigned int)ixWS, indent );
    start = MIN( st, end );
  }
  return start;
}
/* 
  The line buffer is unsigned int not char so we can
  hold Unicode values unencoded. The translation
  to UTF-8 is deferred to the TY_(WriteChar)() routine called
  to flush the line buffer.
*/
static void PPrintText( TidyDocImpl* doc, unsigned int mode, unsigned int indent,
                        Node* node  )
{
    unsigned int start = node->start;
    unsigned int end = node->end;
    unsigned int ix, c = 0;
    int  ixNL = TextEndsWithNewline( doc->lexer, node, mode );
    int  ixWS = TextStartsWithWhitespace( doc->lexer, node, start, mode );
    if ( ixNL > 0 )
      end -= ixNL;
    start = IncrWS( start, end, indent, ixWS );

    for ( ix = start; ix < end; ++ix )
    {
        CheckWrapIndent( doc, indent );
        /*
        if ( CheckWrapIndent(doc, indent) )
        {
            ixWS = TextStartsWithWhitespace( doc->lexer, node, ix );
            ix = IncrWS( ix, end, indent, ixWS );
        }
        */
        c = (byte) doc->lexer->lexbuf[ix];

        /* look for UTF-8 multibyte character */
        if ( c > 0x7F )
             ix += TY_(GetUTF8)( doc->lexer->lexbuf + ix, &c );

        if ( c == '\n' )
        {
            TY_(PFlushLine)( doc, indent );
            ixWS = TextStartsWithWhitespace( doc->lexer, node, ix+1, mode );
            ix = IncrWS( ix, end, indent, ixWS );
        }
        else if (( c == '&' ) && (TY_(HTMLVersion)(doc) == HT50) &&
            (((ix + 1) == end) || (((ix + 1) < end) && (isspace(doc->lexer->lexbuf[ix+1] & 0xff)))) )
        {
            /*\
             * Issue #207 - This is an unambiguous ampersand need not be 'quoted' in HTML5
             * Issue #379 - Ensure only 0 to 255 passed to 'isspace' to avoid debug assert
            \*/
            PPrintChar( doc, c, (mode | CDATA) );
        }
        else
        {
            PPrintChar( doc, c, mode );
        }
    }
}


static void PPrintAttrValue( TidyDocImpl* doc, unsigned int indent,
                             ctmbstr value, unsigned int delim, Bool wrappable, Bool scriptAttr )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool scriptlets = cfgBool(doc, TidyWrapScriptlets);

    unsigned int mode = PREFORMATTED | ATTRIBVALUE;
    if ( wrappable )
        mode = NORMAL | ATTRIBVALUE;

    /* look for ASP, Tango or PHP instructions for computed attribute value */
    if ( value && value[0] == '<' )
    {
        if ( value[1] == '%' || value[1] == '@'||
             TY_(tmbstrncmp)(value, "<?php", 5) == 0 )
            mode |= CDATA;
    }

    if ( delim == 0 )
        delim = '"';

    AddChar( pprint, '=' );

    /* don't wrap after "=" for xml documents */
    if ( !cfgBool(doc, TidyXmlOut) || cfgBool(doc, TidyXhtmlOut) )
    {
        SetWrap( doc, indent );
        CheckWrapIndent( doc, indent );
        /*
        if ( !SetWrap(doc, indent) )
            PCondFlushLine( doc, indent );
        */
    }

    AddChar( pprint, delim );

    if ( value )
    {
        unsigned int wraplen = cfg( doc, TidyWrapLen );
        int attrStart = SetInAttrVal( pprint );
        int strStart = ClearInString( pprint );

        while (*value != '\0')
        {
            unsigned int c = *value;

            if ( wrappable && c == ' ' )
                SetWrapAttr( doc, indent, attrStart, strStart );

            if ( wrappable && pprint->wraphere > 0 &&
                 GetSpaces(pprint) + pprint->linelen >= wraplen )
                WrapAttrVal( doc );

            if ( c == delim )
            {
                ctmbstr entity = (c == '"' ? "&quot;" : "&#39;");
                AddString( pprint, entity );
                ++value;
                continue;
            }
            else if (c == '"')
            {
                if ( cfgBool(doc, TidyQuoteMarks) )
                    AddString( pprint, "&quot;" );
                else
                    AddChar( pprint, c );

                if ( delim == '\'' && scriptAttr && scriptlets )
                    strStart = ToggleInString( pprint );

                ++value;
                continue;
            }
            else if ( c == '\'' )
            {
                if ( cfgBool(doc, TidyQuoteMarks) )
                    AddString( pprint, "&#39;" );
                else
                    AddChar( pprint, c );

                if ( delim == '"' && scriptAttr && scriptlets )
                    strStart = ToggleInString( pprint );

                ++value;
                continue;
            }

            /* look for UTF-8 multibyte character */
            if ( c > 0x7F )
                 value += TY_(GetUTF8)( value, &c );
            ++value;

            if ( c == '\n' )
            {
                /* No indent inside Javascript literals */
                TY_(PFlushLine)( doc, (strStart < 0
                                       && !cfgBool(doc, TidyLiteralAttribs) ?
                                       indent : 0) );
                continue;
            }
            PPrintChar( doc, c, mode );
        }
        ClearInAttrVal( pprint );
        ClearInString( pprint );
    }
    AddChar( pprint, delim );
}

static unsigned int AttrIndent( TidyDocImpl* doc, Node* node, AttVal* ARG_UNUSED(attr) )
{
  unsigned int spaces = cfg( doc, TidyIndentSpaces );
  unsigned int xtra = 2;  /* 1 for the '<', another for the ' ' */
  if ( node->element == NULL )
    return spaces;

  if ( !TY_(nodeHasCM)(node, CM_INLINE) ||
       !ShouldIndent(doc, node->parent ? node->parent: node) )
    return xtra + TY_(tmbstrlen)( node->element );

  if ( NULL != (node = TY_(FindContainer)(node)) )
    return xtra + TY_(tmbstrlen)( node->element );
  return spaces;
}

static Bool AttrNoIndentFirst( /*TidyDocImpl* doc,*/ Node* node, AttVal* attr )
{
  return ( attr==node->attributes );
  
  /*&& 
           ( InsideHead(doc, node) ||
             !TY_(nodeHasCM)(node, CM_INLINE) ) );
             */
}

static void PPrintAttribute( TidyDocImpl* doc, unsigned int indent,
                             Node *node, AttVal *attr )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool xmlOut    = cfgBool( doc, TidyXmlOut );
    Bool xhtmlOut  = cfgBool( doc, TidyXhtmlOut );
    Bool wrapAttrs = cfgBool( doc, TidyWrapAttVals );
    unsigned int ucAttrs   = cfg( doc, TidyUpperCaseAttrs );
    Bool indAttrs  = cfgBool( doc, TidyIndentAttributes );
    unsigned int xtra      = AttrIndent( doc, node, attr );
    Bool first     = AttrNoIndentFirst( /*doc,*/ node, attr );
    tmbstr name    = attr->attribute;
    Bool wrappable = no;
    tchar c;

    /* fix for odd attribute indentation bug triggered by long values */
    if (!indAttrs)
      xtra = 0;

    if ( indAttrs )
    {
        if ( TY_(nodeIsElement)(node) && !first )
        {
            indent += xtra;
            PCondFlushLineSmart( doc, indent );
        }
        else
          indAttrs = no;
    }

    CheckWrapIndent( doc, indent );

    if ( !xmlOut && !xhtmlOut && attr->dict )
    {
        if ( TY_(IsScript)(doc, name) )
            wrappable = cfgBool( doc, TidyWrapScriptlets );
        else if (!(attrIsCONTENT(attr) || attrIsVALUE(attr) || attrIsALT(attr) || attrIsTITLE(attr)) && wrapAttrs )
            wrappable = yes;
    }

    if ( !first && !SetWrap(doc, indent) )
    {
        TY_(PFlushLine)( doc, indent+xtra );  /* Put it on next line */
    }
    else if ( pprint->linelen > 0 )
    {
        AddChar( pprint, ' ' );
    }

    /* Attribute name */
    while (*name)
    {
        c = (unsigned char)*name;

        if (c > 0x7F)
            name += TY_(GetUTF8)(name, &c);
        else if (ucAttrs == TidyUppercaseYes)
            c = TY_(ToUpper)(c);

        AddChar(pprint, c);
        ++name;
    }

    CheckWrapIndent( doc, indent );
 
    if ( attr->value == NULL )
    {
        Bool isB = TY_(IsBoolAttribute)(attr);
        Bool scriptAttr = TY_(attrIsEvent)(attr);

        if ( xmlOut )
            PPrintAttrValue( doc, indent, isB ? attr->attribute : NULLSTR,
                             attr->delim, no, scriptAttr );

        else if ( !isB && !TY_(IsNewNode)(node) )
            PPrintAttrValue( doc, indent, "", attr->delim, yes, scriptAttr );

        else 
            SetWrap( doc, indent );
    }
    else
        PPrintAttrValue( doc, indent, attr->value, attr->delim, wrappable, no );
}

static void PPrintAttrs( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    AttVal* av;

    /* add xml:space attribute to pre and other elements */
    if ( cfgBool(doc, TidyXmlOut) && cfgBool(doc, TidyXmlSpace) &&
         !TY_(GetAttrByName)(node, "xml:space") &&
         TY_(XMLPreserveWhiteSpace)(doc, node) )
    {
        TY_(AddAttribute)( doc, node, "xml:space", "preserve" );
    }

    for ( av = node->attributes; av; av = av->next )
    {
        if ( av->attribute != NULL )
        {
            PPrintAttribute( doc, indent, node, av );
        }
        else if ( av->asp != NULL )
        {
            AddChar( pprint, ' ' );
            PPrintAsp( doc, indent, av->asp );
        }
        else if ( av->php != NULL )
        {
            AddChar( pprint, ' ' );
            PPrintPhp( doc, indent, av->php );
        }
    }
}

Bool TY_(TextNodeEndWithSpace)( Lexer *lexer, Node *node )
{
    if (TY_(nodeIsText)(node) && node->end > node->start)
    {
        unsigned int i, c = '\0'; /* initialised to avoid warnings */
        for (i = node->start; i < node->end; ++i)
        {
            c = (byte) lexer->lexbuf[i];
            if ( c > 0x7F )
                i += TY_(GetUTF8)( lexer->lexbuf + i, &c );
        }

        if ( c == ' ' || c == '\n' )
            return yes;
    }
    return no;
}

/*
 Line can be wrapped immediately after inline start tag provided
 if follows a text node ending in a space, or it follows a <br>,
 or its parent is an inline element that that rule applies to.
 This behaviour was reverse engineered from Netscape 3.0.

 Line wrapping can occur if an element is not empty and before a block
 level. For instance:
 <p><span>
 x</span>y</p>
 will display properly. Whereas
 <p><img />
 x</p> won't.
*/
static Bool AfterSpaceImp(Lexer *lexer, Node *node, Bool isEmpty)
{
    Node *prev;

    if ( !TY_(nodeCMIsInline)(node) )
        return yes;

    prev = node->prev;
    if (prev)
    {
        if (TY_(nodeIsText)(prev))
            return TY_(TextNodeEndWithSpace)( lexer, prev );
        else if (nodeIsBR(prev))
            return yes;

        return no;
    }

    if ( isEmpty && !TY_(nodeCMIsInline)(node->parent) )
        return no;

    return AfterSpaceImp(lexer, node->parent, isEmpty);
}

static Bool AfterSpace(Lexer *lexer, Node *node)
{
    return AfterSpaceImp(lexer, node, TY_(nodeCMIsEmpty)(node));
}

static void PPrintEndTag( TidyDocImpl* doc, unsigned int ARG_UNUSED(mode),
                          unsigned int ARG_UNUSED(indent), Node *node );

/*\
 *  See Issue #162 - void elements also get a closing tag, like img, br, ...
 *
 *  from : http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
 *  A complete list of the void elements in HTML:
 *  area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr
 *
 *  This could be sped up by NOT using the macro nodeIsXXXX, since this repeatedly checks the node,
 *  and then the node->tag, which here are checked at the beginning...
 *
 *  Some have already been done... at least where no macro yet exists.
 *
 *  And maybe a switch(id) case would be faster.
\*/

static Bool TY_(isVoidElement)( Node *node )
{
    TidyTagId id;
    if ( !node )
        return no;
    if ( !node->tag )
        return no;
    id = node->tag->id;
    if (nodeIsAREA(node))
        return yes;
    if (nodeIsBASE(node))
        return yes;
    if (nodeIsBR(node))
        return yes;
    if (nodeIsCOL(node))
        return yes;
    /* if (nodeIsCOMMAND(node)) */
    if (id == TidyTag_COMMAND)
        return yes;
    if (nodeIsEMBED(node))
        return yes;
    if (nodeIsHR(node))
        return yes;
    if (nodeIsIMG(node))
        return yes;
    if (nodeIsINPUT(node))
        return yes;
    /* if (nodeIsKEYGEN(node)) */
    if (id == TidyTag_KEYGEN )
        return yes;
    if (nodeIsLINK(node))
        return yes;
    if (nodeIsMETA(node))
        return yes;
    if (nodeIsPARAM(node))
        return yes;
    /* if (nodeIsSOURCE(node)) */
    if (id == TidyTag_SOURCE )
        return yes;
    /* if (nodeIsTRACK(node)) */
    if (id == TidyTag_TRACK )
        return yes;
    if (nodeIsWBR(node))
        return yes;

    return no;
}

static void PPrintTag( TidyDocImpl* doc,
                       unsigned int mode, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool uc = cfgBool( doc, TidyUpperCaseTags );
    Bool xhtmlOut = cfgBool( doc, TidyXhtmlOut );
    Bool xmlOut = cfgBool( doc, TidyXmlOut );
    tchar c;
    tmbstr s = node->element;

    AddChar( pprint, '<' );

    if ( node->type == EndTag )
        AddChar( pprint, '/' );

    if (s)
    {
        while (*s)
        {
            c = (unsigned char)*s;

            if (c > 0x7F)
                s += TY_(GetUTF8)(s, &c);
            else if (uc)
                c = TY_(ToUpper)(c);

            AddChar(pprint, c);
            ++s;
        }
    }

    PPrintAttrs( doc, indent, node );

    if ( (xmlOut || xhtmlOut) &&
         (node->type == StartEndTag || TY_(nodeCMIsEmpty)(node)) )
    {
        AddChar( pprint, ' ' );   /* Space is NS compatibility hack <br /> */
        AddChar( pprint, '/' );   /* Required end tag marker */
    }

    AddChar( pprint, '>' );

    /*\
     *  Appears this was added for Issue #111, #112, #113, but will now add an end tag
     *  for elements like <img ...> which do NOT have an EndTag, even in html5
     *  See Issue #162 - void elements also get a closing tag, like img, br, ...
     *  A complete list of the void elements in HTML:
     *  area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr
    \*/
    if ((node->type == StartEndTag && TY_(HTMLVersion)(doc) == HT50) && !TY_(isVoidElement)(node) )
    {
        PPrintEndTag( doc, mode, indent, node );
    }

    if ( (node->type != StartEndTag || xhtmlOut || (node->type == StartEndTag && TY_(HTMLVersion)(doc) == HT50)) && !(mode & PREFORMATTED) )
    {
        unsigned int wraplen = cfg( doc, TidyWrapLen );
        CheckWrapIndent( doc, indent );

        if ( indent + pprint->linelen < wraplen )
        {
            /* wrap after start tag if is <br/> or if it's not inline.
               Technically, it would be safe to call only AfterSpace.
               However, it would disrupt the existing algorithm. So let's
               leave as is. Note that AfterSpace returns true for non inline
               elements but can still be false for some <br>. So it has to
               stay as well. */
            if (!(mode & NOWRAP)
                && (!TY_(nodeCMIsInline)(node) || nodeIsBR(node))
                && AfterSpace(doc->lexer, node))
            {
                pprint->wraphere = pprint->linelen;
            }
        }
        /* flush the current buffer only if it is known to be safe,
           i.e. it will not introduce some spurious white spaces.
           See bug #996484 */
        else if ( mode & NOWRAP ||
                  nodeIsBR(node) || AfterSpace(doc->lexer, node))
            PCondFlushLineSmart( doc, indent );
    }
}

static void PPrintEndTag( TidyDocImpl* doc, unsigned int ARG_UNUSED(mode),
                          unsigned int ARG_UNUSED(indent), Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool uc = cfgBool( doc, TidyUpperCaseTags );
    tmbstr s = node->element;
    tchar c;

    AddString( pprint, "</" );

    if (s)
    {
        while (*s)
        {
             c = (unsigned char)*s;

             if (c > 0x7F)
                 s += TY_(GetUTF8)(s, &c);
             else if (uc)
                 c = TY_(ToUpper)(c);

             AddChar(pprint, c);
             ++s;
        }
    }

    AddChar( pprint, '>' );
}

static void PPrintComment( TidyDocImpl* doc, unsigned int indent, Node* node )
{
    TidyPrintImpl* pprint = &doc->pprint;

    SetWrap( doc, indent );
    AddString( pprint, "<!--" );

    PPrintText(doc, COMMENT, 0, node);

    AddString(pprint, "--");
    AddChar( pprint, '>' );
    if ( node->linebreak && node->next )
        TY_(PFlushLineSmart)( doc, indent );
}

static void PPrintDocType( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    unsigned int wraplen = cfg( doc, TidyWrapLen );
    unsigned int spaces = cfg( doc, TidyIndentSpaces );
    AttVal* fpi = TY_(GetAttrByName)(node, "PUBLIC");
    AttVal* sys = TY_(GetAttrByName)(node, "SYSTEM");

    /* todo: handle non-ASCII characters in FPI / SI / node->element */

    SetWrap( doc, indent );
    PCondFlushLineSmart( doc, indent );

    AddString( pprint, "<!DOCTYPE " );
    SetWrap( doc, indent );
    if (node->element)
    {
        AddString(pprint, node->element);
    }

    if (fpi && fpi->value)
    {
        AddString(pprint, " PUBLIC ");
        AddChar(pprint, fpi->delim);
        AddString(pprint, fpi->value);
        AddChar(pprint, fpi->delim);
    }

    if (fpi && fpi->value && sys && sys->value)
    {
        unsigned int i = pprint->linelen - (TY_(tmbstrlen)(sys->value) + 2) - 1;
        if (!(i>0&&TY_(tmbstrlen)(sys->value)+2+i<wraplen&&i<=(spaces?spaces:2)*2))
            i = 0;

        PCondFlushLineSmart(doc, i);
        if (pprint->linelen)
            AddChar(pprint, ' ');
    }
    else if (sys && sys->value)
    {
        AddString(pprint, " SYSTEM ");
    }

    if (sys && sys->value)
    {
        AddChar(pprint, sys->delim);
        AddString(pprint, sys->value);
        AddChar(pprint, sys->delim);
    }

    if (node->content)
    {
        PCondFlushLineSmart(doc, indent);
        AddChar(pprint, '[');
        PPrintText(doc, CDATA, 0, node->content);
        AddChar(pprint, ']');
    }

    SetWrap( doc, 0 );
    AddChar( pprint, '>' );
    PCondFlushLineSmart( doc, indent );
}

static void PPrintPI( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    tchar c;
    tmbstr s;

    SetWrap( doc, indent );
    AddString( pprint, "<?" );

    s = node->element;

    while (s && *s)
    {
        c = (unsigned char)*s;
        if (c > 0x7F)
            s += TY_(GetUTF8)(s, &c);
        AddChar(pprint, c);
        ++s;
    }

    /* set CDATA to pass < and > unescaped */
    PPrintText( doc, CDATA, indent, node );

    if (cfgBool(doc, TidyXmlOut) ||
        cfgBool(doc, TidyXhtmlOut) || node->closed)
        AddChar( pprint, '?' );

    AddChar( pprint, '>' );
    PCondFlushLine( doc, indent );
}

static void PPrintXmlDecl( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    AttVal* att;
    unsigned int saveWrap;
    TidyPrintImpl* pprint = &doc->pprint;
    Bool ucAttrs;
    SetWrap( doc, indent );
    saveWrap = WrapOff( doc );

    /* no case translation for XML declaration pseudo attributes */
    ucAttrs = cfg(doc, TidyUpperCaseAttrs);
    TY_(SetOptionInt)(doc, TidyUpperCaseAttrs, no);

    AddString( pprint, "<?xml" );

    /* Force order of XML declaration attributes */
    /* PPrintAttrs( doc, indent, node ); */
    if ( NULL != (att = TY_(AttrGetById)(node, TidyAttr_VERSION)) )
      PPrintAttribute( doc, indent, node, att );
    if ( NULL != (att = TY_(AttrGetById)(node, TidyAttr_ENCODING)) )
      PPrintAttribute( doc, indent, node, att );
    if ( NULL != (att = TY_(GetAttrByName)(node, "standalone")) )
      PPrintAttribute( doc, indent, node, att );

    /* restore old config value */
    TY_(SetOptionInt)(doc, TidyUpperCaseAttrs, ucAttrs);

    if ( node->end <= 0 || doc->lexer->lexbuf[node->end - 1] != '?' )
        AddChar( pprint, '?' );
    AddChar( pprint, '>' );
    WrapOn( doc, saveWrap );
    TY_(PFlushLineSmart)( doc, indent );
}

/* note ASP and JSTE share <% ... %> syntax */
static void PPrintAsp( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool wrapAsp  = cfgBool( doc, TidyWrapAsp );
    Bool wrapJste = cfgBool( doc, TidyWrapJste );
    unsigned int saveWrap = WrapOffCond( doc, !wrapAsp || !wrapJste );

    AddString( pprint, "<%" );
    PPrintText( doc, (wrapAsp ? CDATA : COMMENT), indent, node );
    AddString( pprint, "%>" );

    /* PCondFlushLine( doc, indent ); */
    WrapOn( doc, saveWrap );
}

/* JSTE also supports <# ... #> syntax */
static void PPrintJste( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool wrapAsp = cfgBool( doc, TidyWrapAsp );
    unsigned int saveWrap = WrapOffCond( doc, !wrapAsp  );

    AddString( pprint, "<#" );
    PPrintText( doc, (cfgBool(doc, TidyWrapJste) ? CDATA : COMMENT),
                indent, node );
    AddString( pprint, "#>" );

    /* PCondFlushLine( doc, indent ); */
    WrapOn( doc, saveWrap );
}

/* PHP is based on XML processing instructions */
static void PPrintPhp( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool wrapPhp = cfgBool( doc, TidyWrapPhp );
    unsigned int saveWrap = WrapOffCond( doc, !wrapPhp  );

    AddString( pprint, "<?" );
    PPrintText( doc, (wrapPhp ? CDATA : COMMENT),
                indent, node );
    AddString( pprint, "?>" );

    /* PCondFlushLine( doc, indent ); */
    WrapOn( doc, saveWrap );
}

static void PPrintCDATA( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    unsigned int saveWrap;
    TidyPrintImpl* pprint = &doc->pprint;
    Bool indentCData = cfgBool( doc, TidyIndentCdata );
    if ( !indentCData )
        indent = 0;

    PCondFlushLineSmart( doc, indent );
    saveWrap = WrapOff( doc );        /* disable wrapping */

    AddString( pprint, "<![CDATA[" );
    PPrintText( doc, COMMENT, indent, node );
    AddString( pprint, "]]>" );

    PCondFlushLineSmart( doc, indent );
    WrapOn( doc, saveWrap );          /* restore wrapping */
}

static void PPrintSection( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Bool wrapSect = cfgBool( doc, TidyWrapSection );
    unsigned int saveWrap = WrapOffCond( doc, !wrapSect  );

    AddString( pprint, "<![" );
    PPrintText( doc, (wrapSect ? CDATA : COMMENT),
                indent, node );
    AddString( pprint, "]>" );

    /* PCondFlushLine( doc, indent ); */
    WrapOn( doc, saveWrap );
}


static ctmbstr CDATA_START           = "<![CDATA[";
static ctmbstr CDATA_END             = "]]>";
static ctmbstr JS_COMMENT_START      = "//";
static ctmbstr JS_COMMENT_END        = "";
static ctmbstr VB_COMMENT_START      = "\'";
static ctmbstr VB_COMMENT_END        = "";
static ctmbstr CSS_COMMENT_START     = "/*";
static ctmbstr CSS_COMMENT_END       = "*/";
static ctmbstr DEFAULT_COMMENT_START = "";
static ctmbstr DEFAULT_COMMENT_END   = "";

static Bool InsideHead( TidyDocImpl* doc, Node *node )
{
  if ( nodeIsHEAD(node) )
    return yes;

  if ( node->parent != NULL )
    return InsideHead( doc, node->parent );

  return no;
}

/* Is text node and already ends w/ a newline?
 
   Used to pretty print CDATA/PRE text content.
   If it already ends on a newline, it is not
   necessary to print another before printing end tag.
*/
static int TextEndsWithNewline(Lexer *lexer, Node *node, unsigned int mode )
{
    if ( (mode & (CDATA|COMMENT)) && TY_(nodeIsText)(node) && node->end > node->start )
    {
        unsigned int ch, ix = node->end - 1;
        /*\
         *  Skip non-newline whitespace. 
         *  Issue #379 - Only if ix is GT start can it be decremented!
        \*/
        while ( ix > node->start && (ch = (lexer->lexbuf[ix] & 0xff))
                 && ( ch == ' ' || ch == '\t' || ch == '\r' ) )
            --ix;

        if ( lexer->lexbuf[ ix ] == '\n' )
          return node->end - ix - 1; /* #543262 tidy eats all memory */
    }
    return -1;
}

/*\
 * Issue #133 - creeping indent - a very OLD bug - 2nd tidy run increases the indent!
 * If the node is text, then remove any white space equal to the indent,
 * but this also applies to the AspTag, which is text like...
 * And may apply to other text like nodes as well.
 *
 * Here the total white space is returned, and then a sister service, IncrWS() 
 * will advance the start of the lexer output by the amount of the indent.
\*/
static Bool TY_(nodeIsTextLike)( Node *node )
{
    if ( TY_(nodeIsText)(node) )
        return yes;
    if ( node->type == AspTag )
        return yes;
    if (node->type == PhpTag)
        return yes; /* Issue #392 */
    /* add other text like nodes... */
    return no;
}

static int TextStartsWithWhitespace( Lexer *lexer, Node *node, unsigned int start, unsigned int mode )
{
    assert( node != NULL );
    if ( (mode & (CDATA|COMMENT)) && TY_(nodeIsTextLike)(node) && node->end > node->start && start >= node->start )
    {
        unsigned int ch, ix = start;
        /* Skip whitespace. */
        while ( ix < node->end && (ch = (lexer->lexbuf[ix] & 0xff))
                && ( ch==' ' || ch=='\t' || ch=='\r' ) )
            ++ix;

        if ( ix > start )
          return ix - start;
    }
    return -1;
}

static Bool HasCDATA( Lexer* lexer, Node* node )
{
    /* Scan forward through the textarray. Since the characters we're
    ** looking for are < 0x7f, we don't have to do any UTF-8 decoding.
    */
    ctmbstr start = lexer->lexbuf + node->start;
    int len = node->end - node->start + 1;

    if ( node->type != TextNode )
        return no;

    return ( NULL != TY_(tmbsubstrn)( start, len, CDATA_START ));
}


static
void PPrintScriptStyle( TidyDocImpl* doc, unsigned int mode, unsigned int indent, Node *node )
{
    TidyPrintImpl* pprint = &doc->pprint;
    Node*   content;
    ctmbstr commentStart = DEFAULT_COMMENT_START;
    ctmbstr commentEnd = DEFAULT_COMMENT_END;
    Bool    hasCData = no;
    int     contentIndent = -1;
    Bool    xhtmlOut = cfgBool( doc, TidyXhtmlOut );

    if ( InsideHead(doc, node) )
      TY_(PFlushLineSmart)( doc, indent );

    PCondFlushLineSmart( doc, indent );  /* Issue #56 - long oustanding bug - flush any existing closing tag */

    PPrintTag( doc, mode, indent, node );

    /* SCRIPT may have no content such as when loading code via its SRC attribute.
       In this case we don't want to flush the line, preferring to keep the required
       closing SCRIPT tag on the same line. */
    if ( node->content != NULL )
        TY_(PFlushLineSmart)(doc, indent);

    if ( xhtmlOut && node->content != NULL )
    {
        AttVal* type = attrGetTYPE(node);

        if (AttrValueIs(type, "text/javascript"))
        {
            commentStart = JS_COMMENT_START;
            commentEnd = JS_COMMENT_END;
        }
        else if (AttrValueIs(type, "text/css"))
        {
            commentStart = CSS_COMMENT_START;
            commentEnd = CSS_COMMENT_END;
        }
        else if (AttrValueIs(type, "text/vbscript"))
        {
            commentStart = VB_COMMENT_START;
            commentEnd = VB_COMMENT_END;
        }

        hasCData = HasCDATA(doc->lexer, node->content);

        if (!hasCData)
        {
            unsigned int saveWrap = WrapOff( doc );

            AddString( pprint, commentStart );
            AddString( pprint, CDATA_START );
            AddString( pprint, commentEnd );
            PCondFlushLineSmart( doc, indent );

            WrapOn( doc, saveWrap );
        }
    }

    for ( content = node->content;
          content != NULL;
          content = content->next )
    {
        /*
          This is a bit odd, with the current code there can only
          be one child and the only caller of this function defines
          all these modes already...
        */
        TY_(PPrintTree)( doc, (mode | PREFORMATTED | NOWRAP | CDATA), 
                         indent, content );

        if ( content == node->last )
            contentIndent = TextEndsWithNewline( doc->lexer, content, CDATA );
    }

    /* Only flush the line if these was content present so that the closing
       SCRIPT tag will stay on the same line. */
    if ( contentIndent < 0 && node->content != NULL )
    {
        PCondFlushLineSmart( doc, indent );
        contentIndent = 0;
    }

    if ( xhtmlOut && node->content != NULL )
    {
        if ( ! hasCData )
        {
            unsigned int saveWrap = WrapOff( doc );

            AddString( pprint, commentStart );
            AddString( pprint, CDATA_END );
            AddString( pprint, commentEnd );

            WrapOn( doc, saveWrap );
            PCondFlushLineSmart( doc, indent );
        }
    }

    if ( node->content && pprint->indent[ 0 ].spaces != (int)indent )
    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
        SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
        pprint->indent[ 0 ].spaces = indent;
    }
    PPrintEndTag( doc, mode, indent, node );
    if ( cfgAutoBool(doc, TidyIndentContent) == TidyNoState
         && node->next != NULL &&
         !( TY_(nodeHasCM)(node, CM_INLINE) || TY_(nodeIsText)(node) ) )
        TY_(PFlushLineSmart)( doc, indent );
}



static Bool ShouldIndent( TidyDocImpl* doc, Node *node )
{
    TidyTriState indentContent = cfgAutoBool( doc, TidyIndentContent );
    if ( indentContent == TidyNoState )
        return no;

    if ( nodeIsTEXTAREA(node) )
        return no;

    if ( indentContent == TidyAutoState )
    {
        if ( node->content && TY_(nodeHasCM)(node, CM_NO_INDENT) )
        {
            for ( node = node->content; node; node = node->next )
                if ( TY_(nodeHasCM)(node, CM_BLOCK) )
                    return yes;
            return no;
        }

        if ( TY_(nodeHasCM)(node, CM_HEADING) )
            return no;

        if ( nodeIsHTML(node) )
            return no;

        if ( nodeIsP(node) )
            return no;

        if ( nodeIsTITLE(node) )
            return no;

        /* http://tidy.sf.net/issue/1610888
           Indenting <div><img /></div> produces spurious lines with IE 6.x */
        if ( nodeIsDIV(node) && node->last && nodeIsIMG(node->last) )
            return no;
    }

    if ( TY_(nodeHasCM)(node, CM_FIELD | CM_OBJECT) )
        return yes;

    if ( nodeIsMAP(node) )
        return yes;

    return ( !TY_(nodeHasCM)( node, CM_INLINE ) && node->content );
}

/*
 Feature request #434940 - fix by Dave Raggett/Ignacio Vazquez-Abrams 21 Jun 01
 print just the content of the body element.
 useful when you want to reuse material from
 other documents.

 -- Sebastiano Vigna <vigna@dsi.unimi.it>
*/
void TY_(PrintBody)( TidyDocImpl* doc )
{
    Node *node = TY_(FindBody)( doc );

    if ( node )
    {
        for ( node = node->content; node != NULL; node = node->next )
            TY_(PPrintTree)( doc, NORMAL, 0, node );
    }
}

/* #130 MathML attr and entity fix! 
   Support MathML namepsace */
static void PPrintMathML( TidyDocImpl* doc, unsigned int indent, Node *node )
{
    Node *content;
    unsigned int mode = OtherNamespace;

    PPrintTag( doc, mode, indent, node );

    for ( content = node->content; content; content = content->next )
           TY_(PPrintTree)( doc, mode, indent, content );

    PPrintEndTag( doc, mode, indent, node );
}

void TY_(PPrintTree)( TidyDocImpl* doc, unsigned int mode, unsigned int indent, Node *node )
{
    Node *content, *last;
    unsigned int spaces = cfg( doc, TidyIndentSpaces );
    Bool xhtml = cfgBool( doc, TidyXhtmlOut );

    if ( node == NULL )
        return;

    if (doc->progressCallback)
    {
        doc->progressCallback( tidyImplToDoc(doc), node->line, node->column, doc->pprint.line + 1 );
    }

#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_PPRINT)
    dbg_show_node( doc, node, 4, GetSpaces( &doc->pprint ) );
#endif

    if (node->type == TextNode)
    {
        PPrintText( doc, mode, indent, node );
    }
    else if ( node->type == CommentTag )
    {
        PPrintComment( doc, indent, node );
    }
    else if ( node->type == RootNode )
    {
        for ( content = node->content; content; content = content->next )
           TY_(PPrintTree)( doc, mode, indent, content );
    }
    else if ( node->type == DocTypeTag )
        PPrintDocType( doc, indent, node );
    else if ( node->type == ProcInsTag)
        PPrintPI( doc, indent, node );
    else if ( node->type == XmlDecl)
        PPrintXmlDecl( doc, indent, node );
    else if ( node->type == CDATATag)
        PPrintCDATA( doc, indent, node );
    else if ( node->type == SectionTag)
        PPrintSection( doc, indent, node );
    else if ( node->type == AspTag)
        PPrintAsp( doc, indent, node );
    else if ( node->type == JsteTag)
        PPrintJste( doc, indent, node );
    else if ( node->type == PhpTag)
        PPrintPhp( doc, indent, node );
    else if ( nodeIsMATHML(node) )
        PPrintMathML( doc, indent, node ); /* #130 MathML attr and entity fix! */
    else if ( TY_(nodeCMIsEmpty)(node) ||
              (node->type == StartEndTag && !xhtml) )
    {
        /* Issue #8 - flush to new line? 
           maybe use if ( TY_(nodeHasCM)(node, CM_BLOCK) ) instead
           or remove the CM_INLINE from the tag
         */
        if ( ! TY_(nodeHasCM)(node, CM_INLINE) )
            PCondFlushLineSmart( doc, indent );

        if ( nodeIsBR(node) && node->prev &&
             !(nodeIsBR(node->prev) || (mode & PREFORMATTED)) &&
             cfgBool(doc, TidyBreakBeforeBR) )
            TY_(PFlushLineSmart)( doc, indent );

        if ( nodeIsHR(node) )
        {
            /* insert extra newline for classic formatting */
            Bool classic = TidyClassicVS; /* #228 - cfgBool( doc, TidyVertSpace ); */
            if (classic && node->parent && node->parent->content != node)
            {
                TY_(PFlushLineSmart)( doc, indent );
            }
        }

        PPrintTag( doc, mode, indent, node );

        if (node->next)
        {
          if (nodeIsPARAM(node) || nodeIsAREA(node))
              PCondFlushLineSmart(doc, indent);
          else if ((nodeIsBR(node) && !(mode & PREFORMATTED))
                   || nodeIsHR(node))
              TY_(PFlushLineSmart)(doc, indent);
        }
    }
    else /* some kind of container element */
    {
        if ( node->type == StartEndTag )
            node->type = StartTag;

        if ( node->tag && 
             (node->tag->parser == TY_(ParsePre) || nodeIsTEXTAREA(node)) )
        {
            Bool classic  = TidyClassicVS; /* #228 - cfgBool( doc, TidyVertSpace ); */
            unsigned int indprev = indent;

            PCondFlushLineSmart( doc, indent ); /* about to add <pre> tag - clear any previous */

            /* insert extra newline for classic formatting */
            if (classic && node->parent && node->parent->content != node)
            {
                TY_(PFlushLineSmart)( doc, indent );
            }

            /* Issue #697 - Add NOWRAP to the mode */
            PPrintTag( doc, (mode | NOWRAP), indent, node );   /* add <pre> or <textarea> tag */

            indent = 0;
            /* @camoy Fix #158 - remove inserted newlines in pre - TY_(PFlushLineSmart)( doc, indent ); */

            for ( content = node->content; content; content = content->next )
            {
                TY_(PPrintTree)( doc, (mode | PREFORMATTED | NOWRAP),
                                 indent, content );
            }

            /* @camoy Fix #158 - remove inserted newlines in pre - PCondFlushLineSmart( doc, indent ); */
            indent = indprev;
            PPrintEndTag( doc, mode, indent, node );

            if ( cfgAutoBool(doc, TidyIndentContent) == TidyNoState
                 && node->next != NULL )
                TY_(PFlushLineSmart)( doc, indent );
        }
        else if ( nodeIsSTYLE(node) || nodeIsSCRIPT(node) )
        {
            PPrintScriptStyle( doc, (mode | PREFORMATTED | NOWRAP | CDATA),
                               indent, node );
        }
        else if ( TY_(nodeCMIsInline)(node) )
        {
            if ( cfgBool(doc, TidyMakeClean) )
            {
                /* replace <nobr>...</nobr> by &nbsp; or &#160; etc. */
                if ( nodeIsNOBR(node) )
                {
                    for ( content = node->content;
                          content != NULL;
                          content = content->next)
                        TY_(PPrintTree)( doc, mode|NOWRAP, indent, content );
                    return;
                }
            }

            /* otherwise a normal inline element */
            PPrintTag( doc, mode, indent, node );

            /* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */
            if ( ShouldIndent(doc, node) )
            {
                indent += spaces;
                PCondFlushLineSmart( doc, indent );

                for ( content = node->content;
                      content != NULL;
                      content = content->next )
                    TY_(PPrintTree)( doc, mode, indent, content );

                indent -= spaces;
                PCondFlushLineSmart( doc, indent );
                /* PCondFlushLine( doc, indent ); */
            }
            else
            {
                for ( content = node->content;
                      content != NULL;
                      content = content->next )
                    TY_(PPrintTree)( doc, mode, indent, content );
            }
            PPrintEndTag( doc, mode, indent, node );
        }
        else /* other tags */
        {
            Bool indcont  = ( cfgAutoBool(doc, TidyIndentContent) != TidyNoState );
            /* Issue #582 - Seems this is no longer used
               Bool indsmart = ( cfgAutoBool(doc, TidyIndentContent) == TidyAutoState ); */
            Bool hideend  = cfgBool( doc, TidyOmitOptionalTags );
            Bool classic  = TidyClassicVS; /* #228 - cfgBool( doc, TidyVertSpace ); */
            unsigned int contentIndent = indent;

            /* insert extra newline for classic formatting */
            if (classic && node->parent && node->parent->content != node && !nodeIsHTML(node))
            {
                TY_(PFlushLineSmart)( doc, indent );
            }

            if ( ShouldIndent(doc, node) )
                contentIndent += spaces;

            PCondFlushLineSmart( doc, indent );

            /*\
             *  Issue #180 - with the above PCondFlushLine, 
             *  this adds an uneccessary additional line!
             *  Maybe only if 'classic' ie --vertical-space yes 
             *  Issue #582 - maybe this is no longer needed!
             *  It adds a 3rd newline if indent: auto...
             *  if ( indsmart && node->prev != NULL && classic)
             *   TY_(PFlushLineSmart)( doc, indent );
            \*/

            /* do not omit elements with attributes */
            if ( !hideend || !TY_(nodeHasCM)(node, CM_OMITST) ||
                 node->attributes != NULL )
            {
                PPrintTag( doc, mode, indent, node );

                if ( ShouldIndent(doc, node) )
                {
                    /* fix for bug 530791, don't wrap after */
                    /* <li> if first child is text node     */
                    if (!(nodeIsLI(node) && TY_(nodeIsText)(node->content)))
                        PCondFlushLineSmart( doc, contentIndent );
                }
                else if ( TY_(nodeHasCM)(node, CM_HTML) || nodeIsNOFRAMES(node) ||
                          (TY_(nodeHasCM)(node, CM_HEAD) && !nodeIsTITLE(node)) )
                    TY_(PFlushLineSmart)( doc, contentIndent );
            }
            else if ( ShouldIndent(doc, node) )
            {
                /*\
                 * Issue #180 - If the tag was NOT printed due to the -omit option,
                 * then reduce the bumped indent under the same ShouldIndent(doc, node) 
                 * conditions that caused the indent to be bumped.
                \*/
                contentIndent -= spaces;
            }

            last = NULL;
            for ( content = node->content; content; content = content->next )
            {
                /* kludge for naked text before block level tag */
                if ( last && !indcont && TY_(nodeIsText)(last) &&
                     content->tag && !TY_(nodeHasCM)(content, CM_INLINE) )
                {
                    /* TY_(PFlushLine)(fout, indent); */
                    TY_(PFlushLineSmart)( doc, contentIndent );
                }

                TY_(PPrintTree)( doc, mode, contentIndent, content );
                last = content;
            }

            /* don't flush line for td and th */
            if ( ShouldIndent(doc, node) ||
                 ( !hideend &&
                   ( TY_(nodeHasCM)(node, CM_HTML) || 
                     nodeIsNOFRAMES(node) ||
                     (TY_(nodeHasCM)(node, CM_HEAD) && !nodeIsTITLE(node))
                   )
                 )
               )
            {
                PCondFlushLineSmart( doc, indent );
                if ( !hideend || !TY_(nodeHasCM)(node, CM_OPT) )
                {
                    PPrintEndTag( doc, mode, indent, node );
                    /* TY_(PFlushLine)( doc, indent ); */
                }
            }
            else
            {
                if ( !hideend || !TY_(nodeHasCM)(node, CM_OPT) )
                {
                    /* newline before endtag for classic formatting */
                    if ( classic && !HasMixedContent(node) )
                        TY_(PFlushLineSmart)( doc, indent );
                    PPrintEndTag( doc, mode, indent, node );
                }
                else if (hideend)
                {
                    /* Issue #390  - must still deal with adjusting indent */
                    TidyPrintImpl* pprint = &doc->pprint;
                    if (pprint->indent[ 0 ].spaces != (int)indent)
                    {
#if defined(ENABLE_DEBUG_LOG) && defined(DEBUG_INDENT)
                        SPRTF("%s Indent from %d to %d\n", __FUNCTION__, pprint->indent[ 0 ].spaces, indent );
#endif  
                        pprint->indent[ 0 ].spaces = indent;
                    }
                }
            }

            if (!indcont && !hideend && !nodeIsHTML(node) && !classic)
                TY_(PFlushLineSmart)( doc, indent );
            else if (classic && node->next != NULL && TY_(nodeHasCM)(node, CM_LIST|CM_DEFLIST|CM_TABLE|CM_BLOCK/*|CM_HEADING*/))
                TY_(PFlushLineSmart)( doc, indent );
        }
    }
}

void TY_(PPrintXMLTree)( TidyDocImpl* doc, unsigned int mode, unsigned int indent, Node *node )
{
    Bool xhtmlOut = cfgBool( doc, TidyXhtmlOut );
    if (node == NULL)
        return;

    if (doc->progressCallback)
    {
        doc->progressCallback( tidyImplToDoc(doc), node->line, node->column, doc->pprint.line + 1 );
    }
    
    if ( node->type == TextNode)
    {
        PPrintText( doc, mode, indent, node );
    }
    else if ( node->type == CommentTag )
    {
        PCondFlushLineSmart( doc, indent );
        PPrintComment( doc, indent, node);
        /* PCondFlushLine( doc, 0 ); */
    }
    else if ( node->type == RootNode )
    {
        Node *content;
        for ( content = node->content;
              content != NULL;
              content = content->next )
           TY_(PPrintXMLTree)( doc, mode, indent, content );
    }
    else if ( node->type == DocTypeTag )
        PPrintDocType( doc, indent, node );
    else if ( node->type == ProcInsTag )
        PPrintPI( doc, indent, node );
    else if ( node->type == XmlDecl )
        PPrintXmlDecl( doc, indent, node );
    else if ( node->type == CDATATag )
        PPrintCDATA( doc, indent, node );
    else if ( node->type == SectionTag )
        PPrintSection( doc, indent, node );
    else if ( node->type == AspTag )
        PPrintAsp( doc, indent, node );
    else if ( node->type == JsteTag)
        PPrintJste( doc, indent, node );
    else if ( node->type == PhpTag)
        PPrintPhp( doc, indent, node );
    else if ( TY_(nodeHasCM)(node, CM_EMPTY) ||
              (node->type == StartEndTag && !xhtmlOut) )
    {
        PCondFlushLineSmart( doc, indent );
        PPrintTag( doc, mode, indent, node );
        /* TY_(PFlushLine)( doc, indent ); */
    }
    else /* some kind of container element */
    {
        unsigned int spaces = cfg( doc, TidyIndentSpaces );
        Node *content;
        Bool mixed = no;
        unsigned int cindent;

        for ( content = node->content; content; content = content->next )
        {
            if ( TY_(nodeIsText)(content) )
            {
                mixed = yes;
                break;
            }
        }

        PCondFlushLineSmart( doc, indent );

        if ( TY_(XMLPreserveWhiteSpace)(doc, node) )
        {
            indent = 0;
            mixed = no;
            cindent = 0;
        }
        else if (mixed)
            cindent = indent;
        else
            cindent = indent + spaces;

        PPrintTag( doc, mode, indent, node );
        if ( !mixed && node->content )
            TY_(PFlushLineSmart)( doc, cindent );
 
        for ( content = node->content; content; content = content->next )
            TY_(PPrintXMLTree)( doc, mode, cindent, content );

        if ( !mixed && node->content )
            PCondFlushLineSmart( doc, indent );

        PPrintEndTag( doc, mode, indent, node );
        /* PCondFlushLine( doc, indent ); */
    }
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* sprtf.c
 * SPRTF - Log output utility - part of the HTML Tidy project
 *
 * Copyright (c) 1998-2017 Geoff R. McLane and HTACG
 *
 * See tidy.h for the copyright notice.
 */

#ifdef _MSC_VER
#  pragma warning( disable : 4995 )
#endif

#include <stdio.h>  /* fopen()... */
#include <string.h> /* strcpy */
#include <stdarg.h> /* va_start, va_end, ... */

#ifdef _MSC_VER
#  include <WinSock2.h>
#  include <sys/timeb.h>
#  if (defined(UNICODE) || defined(_UNICODE))
#    include <Strsafe.h>
#  endif
#else /* !_MSC_VER */
#  include <sys/time.h> /* gettimeoday(), struct timeval,... */
#endif /* _MSC_VER y/n */

#include <time.h>
#include <stdlib.h> /* for exit() in unix */
/* #include "sprtf.h" */

#ifdef ENABLE_DEBUG_LOG

#ifdef _MSC_VER
#  ifndef _CRT_SECURE_NO_DEPRECATE
#    define _CRT_SECURE_NO_DEPRECATE
#  endif /* #ifndef _CRT_SECURE_NO_DEPRECATE */
#  pragma warning( disable:4996 )
#else
#  define strcmpi strcasecmp
#endif 

#ifndef MX_ONE_BUF
#  define MX_ONE_BUF 1024
#endif
#ifndef MX_BUFFERS
#  define MX_BUFFERS 1024
#endif

static char _s_strbufs[MX_ONE_BUF * MX_BUFFERS];
static int iNextBuf = 0;

char *GetNxtBuf()
{
   iNextBuf++;
   if(iNextBuf >= MX_BUFFERS)
      iNextBuf = 0;
   return &_s_strbufs[MX_ONE_BUF * iNextBuf];
}

#define  MXIO     512

static char def_log[] = "temptidy.txt"; /* use local log */
static char logfile[264] = "\0";
static FILE * outfile = NULL;
static int addsystime = 0;
static int addsysdate = 0;
static int addstdout = 1;
static int addflush = 1;
static int add2screen = 0;
static int add2listview = 0;
static int append_to_log = 0;

#ifndef VFP
#  define VFP(a) ( a && ( a != (FILE *)-1 ) )
#endif

int   add_list_out( int val )
{
   int i = add2listview;
   add2listview = val;
   return i;
}

int   add_std_out( int val )
{
   int i = addstdout;
   addstdout = val;
   return i;
}

int   add_screen_out( int val )
{
   int i = add2screen;
   add2screen = val;
   return i;
}


int   add_sys_time( int val )
{
   int   i = addsystime;
   addsystime = val;
   return i;
}

int   add_sys_date( int val )
{
   int   i = addsysdate;
   addsysdate = val;
   return i;
}


int   add_append_log( int val )
{
   int   i = append_to_log;
   append_to_log = val;
   return i;
}


#ifdef _MSC_VER
static const char *mode = "wb"; /* in window sprtf looks after the line endings */
#else
static const char *mode = "w";
#endif

int   open_log_file( void )
{
   if (logfile[0] == 0)
      strcpy(logfile,def_log);
   if (append_to_log) {
#ifdef _MSC_VER
        mode = "ab"; /* in window sprtf looks after the line endings */
#else
        mode = "a";
#endif
   }
   outfile = fopen(logfile, mode);
   if( outfile == 0 ) {
      outfile = (FILE *)-1;
      sprtf("ERROR: Failed to open log file [%s] ...\n", logfile);
      /* exit(1); failed */
      return 0;   /* failed */
   }
   return 1; /* success */
}

void close_log_file( void )
{
   if( VFP(outfile) ) {
      fclose(outfile);
   }
   outfile = NULL;
}

char * get_log_file( void )
{
   if (logfile[0] == 0)
      strcpy(logfile,def_log);
   if (outfile == (FILE *)-1) /* disable the log file */
       return (char *)"none";
   return logfile;
}

void   set_log_file( char * nf, int open )
{
   if (logfile[0] == 0)
      strcpy(logfile,def_log);
   if ( nf && *nf && strcmpi(nf,logfile) ) {
      close_log_file(); /* remove any previous */
      strcpy(logfile,nf); /* set new name */
      if (strcmp(logfile,"none") == 0) { /* if equal 'none' */
          outfile = (FILE *)-1; /* disable the log file */
      } else if (open) {
          open_log_file();  /* and open it ... anything previous written is 'lost' */
      } else
          outfile = 0; /* else set 0 to open on first write */
   }
}

#ifdef _MSC_VER
int gettimeofday(struct timeval *tp, void *tzp)
{
#ifdef WIN32
    struct _timeb timebuffer;
    _ftime(&timebuffer);
    tp->tv_sec = (long)timebuffer.time;
    tp->tv_usec = timebuffer.millitm * 1000;
#else
    tp->tv_sec = time(NULL);
    tp->tv_usec = 0;
#endif
    return 0;
}

#endif /* _MSC_VER */

void add_date_stg( char *ps, struct timeval *ptv )
{
    time_t curtime;
    struct tm * ptm;
    curtime = (ptv->tv_sec & 0xffffffff);
    ptm = localtime(&curtime);
    if (ptm) {
        strftime(EndBuf(ps),128,"%Y/%m/%d",ptm);
    }
}

void add_time_stg( char *ps, struct timeval *ptv )
{
    time_t curtime;
    struct tm * ptm;
    curtime = (ptv->tv_sec & 0xffffffff);
    ptm = localtime(&curtime);
    if (ptm) {
        strftime(EndBuf(ps),128,"%H:%M:%S",ptm);
    }
}

char *get_date_stg()
{
    char *ps;
    struct timeval tv;
    gettimeofday( (struct timeval *)&tv, (struct timezone *)0 );
    ps = GetNxtBuf();
    *ps = 0;
    add_date_stg( ps, &tv );
    return ps;
}

char *get_time_stg()
{
    char *ps;
    struct timeval tv;
    gettimeofday( (struct timeval *)&tv, (struct timezone *)0 );
    ps = GetNxtBuf();
    *ps = 0;
    add_time_stg( ps, &tv );
    return ps;
}

char *get_date_time_stg()
{
    char *ps;
    struct timeval tv;
    gettimeofday( (struct timeval *)&tv, (struct timezone *)0 );
    ps = GetNxtBuf();
    *ps = 0;
    add_date_stg( ps, &tv );
    strcat(ps," ");
    add_time_stg( ps, &tv );
    return ps;
}

static void oi( char * psin )
{
    int len, w;
    char * ps = psin;
    if (!ps)
        return;

   len = (int)strlen(ps);
   if (len) {

      if( outfile == 0 ) {
         open_log_file();
      }
      if( VFP(outfile) ) {
          char *tb;
          if (addsysdate) {
              tb = GetNxtBuf();
              len = sprintf( tb, "%s - %s", get_date_time_stg(), ps );
              ps = tb;
          } else if( addsystime ) {
              tb = GetNxtBuf();
              len = sprintf( tb, "%s - %s", get_time_stg(), ps );
              ps = tb;
          }

         w = (int)fwrite( ps, 1, len, outfile );
         if( w != len ) {
            fclose(outfile);
            outfile = (FILE *)-1;
            sprtf("WARNING: Failed write to log file [%s] ...\n", logfile);
            exit(1);
         } else if (addflush) {
            fflush( outfile );
         }
      }

      if( addstdout ) {
         fwrite( ps, 1, len, stderr );  /* 20170917 - Switch to using 'stderr' in place of 'stdout' */
      }
#ifdef ADD_LISTVIEW
       if (add2listview) {
           LVInsertItem(ps);
       } 
#endif /* ADD_LISTVIEW */
#ifdef ADD_SCREENOUT
       if (add2screen) {
          Add_String(ps);    /* add string to screen list */
       }
#endif /* #ifdef ADD_SCREENOUT */
   }
}

#ifdef _MSC_VER
/* service to ensure line endings in windows only */
static void prt( char * ps )
{
    static char _s_buf[1024];
    char * pb = _s_buf;
    size_t i, j, k;
    char   c, d;
    i = strlen(ps);
    k = 0;
    d = 0;
    if(i) {
        k = 0;
        d = 0;
        for( j = 0; j < i; j++ ) {
            c = ps[j];
            if( c == 0x0d ) {
                if( (j+1) < i ) {
                    if( ps[j+1] != 0x0a ) {
                        pb[k++] = c;
                        c = 0x0a;
                    }
            } else {
                    pb[k++] = c;
                    c = 0x0a;
                }
            } else if( c == 0x0a ) {
                if( d != 0x0d ) {
                    pb[k++] = 0x0d;
                }
            }
            pb[k++] = c;
            d = c;
            if( k >= MXIO ) {
                pb[k] = 0;
                oi(pb);
                k = 0;
            }
        }   /* for length of string */
        if( k ) {
            pb[k] = 0;
            oi( pb );
        }
    }
}
#endif /* #ifdef _MSC_VER */

int direct_out_it( char *cp )
{
#ifdef _MSC_VER
    prt(cp);
#else
    oi(cp);
#endif
    return (int)strlen(cp);
}

/* STDAPI StringCchVPrintf( OUT LPTSTR  pszDest,
 *   IN  size_t  cchDest, IN  LPCTSTR pszFormat, IN  va_list argList ); */
int MCDECL sprtf( const char *pf, ... )
{
   static char _s_sprtfbuf[M_MAX_SPRTF+4];
   char * pb = _s_sprtfbuf;
   int   i;
   va_list arglist;
   va_start(arglist, pf);
   i = vsnprintf( pb, M_MAX_SPRTF, pf, arglist );
   va_end(arglist);
#ifdef _MSC_VER
   prt(pb); /* ensure '\r'/'\n' */
#else
   oi(pb);
#endif
   return i;
}

#ifdef UNICODE
/* WIDE VARIETY */
static void wprt( PTSTR ps )
{
   static char _s_woibuf[1024];
   char * cp = _s_woibuf;
   int len = (int)lstrlen(ps);
   if(len) {
      int ret = WideCharToMultiByte( CP_ACP, /* UINT CodePage, // code page */
         0, /* DWORD dwFlags,            // performance and mapping flags */
         ps,   /* LPCWSTR lpWideCharStr,    // wide-character string */
         len,     /* int cchWideChar,          // number of chars in string. */
         cp,      /* LPSTR lpMultiByteStr,     // buffer for new string */
         1024,    /* int cbMultiByte,          // size of buffer */
         NULL,    /* LPCSTR lpDefaultChar,     // default for unmappable chars */
         NULL );  /* LPBOOL lpUsedDefaultChar  // set when default char used */
      /* oi(cp); */
      prt(cp);
   }
}

int MCDECL wsprtf( PTSTR pf, ... )
{
   static WCHAR _s_sprtfwbuf[1024];
   PWSTR pb = _s_sprtfwbuf;
   int   i = 1;
   va_list arglist;
   va_start(arglist, pf);
   *pb = 0;
   StringCchVPrintf(pb,1024,pf,arglist);
   va_end(arglist);
   wprt(pb);
   return i;
}

#endif /* #ifdef UNICODE */

#endif /* #ifdef ENABLE_DEBUG_LOG */
/* eof - sprtf.c */
/* streamio.c -- handles character stream I/O

  (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Wrapper around Tidy input source and output sink
  that calls appropriate interfaces, and applies
  necessary char encoding transformations: to/from
  ISO-10646 and/or UTF-8.

*/

#include <stdio.h>
#include <errno.h>

/* #include "streamio.h" */
/* #include "tidy-int.h" */
/* #include "lexer.h" */
/* #include "message.h" */
/* #include "utf8.h" */
/* #include "tmbstr.h" */


/************************
** Forward Declarations
************************/

static unsigned int ReadCharFromStream( StreamIn* in );

static unsigned int ReadByte( StreamIn* in );
static void UngetByte( StreamIn* in, unsigned int byteValue );

static void PutByte( unsigned int byteValue, StreamOut* out );

static void EncodeWin1252( unsigned int c, StreamOut* out );
static void EncodeMacRoman( unsigned int c, StreamOut* out );
static void EncodeIbm858( unsigned int c, StreamOut* out );
static void EncodeLatin0( unsigned int c, StreamOut* out );

static unsigned int DecodeIbm850(unsigned int c);
static unsigned int DecodeLatin0(unsigned int c);

static unsigned int PopChar( StreamIn *in );

/******************************
** Static (duration) Globals
******************************/

static StreamOut stderrStreamOut = 
{
    ASCII,
    FSM_ASCII,
    DEFAULT_NL_CONFIG,
    FileIO,
    { 0, TY_(filesink_putByte) }
};

static StreamOut stdoutStreamOut = 
{
    ASCII,
    FSM_ASCII,
    DEFAULT_NL_CONFIG,
    FileIO,
    { 0, TY_(filesink_putByte) }
};

StreamOut* TY_(StdErrOutput)(void)
{
  if ( stderrStreamOut.sink.sinkData == 0 )
      stderrStreamOut.sink.sinkData = stderr;
  return &stderrStreamOut;
}

void  TY_(ReleaseStreamOut)( TidyDocImpl *doc,  StreamOut* out )
{
    if ( out && out != &stderrStreamOut && out != &stdoutStreamOut )
    {
        if ( out->iotype == FileIO )
            fclose( (FILE*) out->sink.sinkData );
        TidyDocFree( doc, out );
    }
}

/************************
** Source
************************/

static void InitLastPos( StreamIn *in );

StreamIn* TY_(initStreamIn)( TidyDocImpl* doc, int encoding )
{
    StreamIn *in = (StreamIn*) TidyDocAlloc( doc, sizeof(StreamIn) );

    TidyClearMemory( in, sizeof(StreamIn) );
    in->curline = 1;
    in->curcol = 1;
    in->encoding = encoding;
    in->state = FSM_ASCII;
    in->doc = doc;
    in->bufsize = CHARBUF_SIZE;
    in->allocator = doc->allocator;
    in->charbuf = (tchar*)TidyDocAlloc(doc, sizeof(tchar) * in->bufsize);
    InitLastPos( in );
    return in;
}

void TY_(freeStreamIn)(StreamIn* in)
{
    TidyFree(in->allocator, in->charbuf);
    TidyFree(in->allocator, in);
}

StreamIn* TY_(FileInput)( TidyDocImpl* doc, FILE *fp, int encoding )
{
    StreamIn *in = TY_(initStreamIn)( doc, encoding );
    if ( TY_(initFileSource)( doc->allocator, &in->source, fp ) != 0 )
    {
        TY_(freeStreamIn)( in );
        return NULL;
    }
    in->iotype = FileIO;
    return in;
}

StreamIn* TY_(BufferInput)( TidyDocImpl* doc, TidyBuffer* buf, int encoding )
{
    StreamIn *in = TY_(initStreamIn)( doc, encoding );
    tidyInitInputBuffer( &in->source, buf );
    in->iotype = BufferIO;
    return in;
}

StreamIn* TY_(UserInput)( TidyDocImpl* doc, TidyInputSource* source, int encoding )
{
    StreamIn *in = TY_(initStreamIn)( doc, encoding );
    memcpy( &in->source, source, sizeof(TidyInputSource) );
    in->iotype = UserIO;
    return in;
}

int TY_(ReadBOMEncoding)(StreamIn *in)
{
    unsigned int c, c1;
    unsigned int bom;

    c = ReadByte(in);
    if (c == EndOfStream)
        return -1;

    c1 = ReadByte( in );
    if (c1 == EndOfStream)
    {
        UngetByte(in, c);
        return -1;
    }

    /* todo: dont warn about mismatch for auto input encoding */
    /* todo: let the user override the encoding found here */

    bom = (c << 8) + c1;

    if ( bom == UNICODE_BOM_BE )
    {
        /* big-endian UTF-16 */
        if ( in->encoding != UTF16 && in->encoding != UTF16BE )
            TY_(ReportEncodingWarning)(in->doc, ENCODING_MISMATCH, UTF16BE);

        return UTF16BE; /* return decoded BOM */
    }
    else if (bom == UNICODE_BOM_LE)
    {
        /* little-endian UTF-16 */
        if (in->encoding != UTF16 && in->encoding != UTF16LE)
            TY_(ReportEncodingWarning)(in->doc, ENCODING_MISMATCH, UTF16LE);

        return UTF16LE; /* return decoded BOM */
    }
    else
    {
        unsigned int c2 = ReadByte(in);

        if (c2 == EndOfStream)
        {
            UngetByte(in, c1);
            UngetByte(in, c);
            return -1;
        }

        if (((c << 16) + (c1 << 8) + c2) == UNICODE_BOM_UTF8)
        {
            /* UTF-8 */
            if (in->encoding != UTF8)
                TY_(ReportEncodingWarning)(in->doc, ENCODING_MISMATCH, UTF8);

            return UTF8;
        }
        else
            UngetByte( in, c2 );
    }

    UngetByte(in, c1);
    UngetByte(in, c);

    return -1;
}

static void InitLastPos( StreamIn *in )
{
    in->curlastpos = 0;
    in->firstlastpos = 0;
}

static void PopLastPos( StreamIn *in )
{
    in->curlastpos = (in->curlastpos+1)%LASTPOS_SIZE;
    if ( in->curlastpos == in->firstlastpos )
        in->firstlastpos = (in->firstlastpos+1)%LASTPOS_SIZE;
}

static void SaveLastPos( StreamIn *in )
{
    PopLastPos( in );
    in->lastcols[in->curlastpos] = in->curcol;
}

static void RestoreLastPos( StreamIn *in )
{
    if ( in->firstlastpos == in->curlastpos )
        in->curcol = 0;
    else
    {
        in->curcol = in->lastcols[in->curlastpos];
        if ( in->curlastpos == 0 )
            in->curlastpos = LASTPOS_SIZE;
        in->curlastpos--;
    }
}

unsigned int TY_(ReadChar)( StreamIn *in )
{
    unsigned int c = EndOfStream;

    if ( in->pushed )
        return PopChar( in );

    SaveLastPos( in );

    if ( in->tabs > 0 )
    {
        in->curcol++;
        in->tabs--;
        return ' ';
    }
    
    for (;;)
    {
        c = ReadCharFromStream(in);

        if ( EndOfStream == c )
            return EndOfStream;

        if (c == '\n')
        {
            in->curcol = 1;
            in->curline++;
            break;
        }

        if (c == '\t')
        {
            Bool keeptabs = cfg( in->doc, TidyKeepTabs );
            if (!keeptabs) {
                unsigned int tabsize = cfg(in->doc, TidyTabSize);
                in->tabs = tabsize > 0 ?
                    tabsize - ((in->curcol - 1) % tabsize) - 1
                    : 0;
                c = ' ';
            }
            in->curcol++;
            break;
        }

        /* #427663 - map '\r' to '\n' - Andy Quick 11 Aug 00 */
        if (c == '\r')
        {
            c = ReadCharFromStream(in);
            if (c != '\n')
            {
                TY_(UngetChar)( c, in );
                c = '\n';
            }
            else
            {
            }
            in->curcol = 1;
            in->curline++;
            break;
        }

#ifndef NO_NATIVE_ISO2022_SUPPORT
        /* strip control characters, except for Esc */
        if (c == '\033')
            break;
#endif

        /* Form Feed is allowed in HTML */
        if ( c == '\015' && !cfgBool(in->doc, TidyXmlTags) )
            break;
            
        if ( c < 32 )
            continue; /* discard control char */

        /* watch out for chars that have already been decoded such as */
        /* IS02022, UTF-8 etc, that don't require further decoding */

        if (
            in->encoding == RAW
#ifndef NO_NATIVE_ISO2022_SUPPORT
         || in->encoding == ISO2022
#endif
         || in->encoding == UTF8
         || in->encoding == SHIFTJIS /* #431953 - RJ */
         || in->encoding == BIG5     /* #431953 - RJ */
           )
        {
            in->curcol++;
            break;
        }

        /* handle surrogate pairs */
        if ( in->encoding == UTF16LE ||
             in->encoding == UTF16   ||
             in->encoding == UTF16BE )
        {
            if ( !TY_(IsValidUTF16FromUCS4)(c) )
            {
                /* invalid UTF-16 value */
                TY_(ReportEncodingError)(in->doc, INVALID_UTF16, c, yes);
                c = 0;
            }
            else if ( TY_(IsLowSurrogate)(c) )
            {
                unsigned int n = c;
                unsigned int m = ReadCharFromStream( in );
                if ( m == EndOfStream )
                   return EndOfStream;

                c = 0;
                if ( TY_(IsHighSurrogate)(m) )
                {
                    n = TY_(CombineSurrogatePair)( m, n );
                    if ( TY_(IsValidCombinedChar)(n) )
                        c = n;
                }
                /* not a valid pair */
                if ( 0 == c )
                    TY_(ReportEncodingError)( in->doc, INVALID_UTF16, c, yes );
            }
        }

        /* Do first: acts on range 128 - 255 */
        switch ( in->encoding )
        {
        case MACROMAN:
            c = TY_(DecodeMacRoman)( c );
            break;
        case IBM858:
            c = DecodeIbm850( c );
            break;
        case LATIN0:
            c = DecodeLatin0( c );
            break;
        }

        /* produced e.g. as a side-effect of smart quotes in Word */
        /* but can't happen if using MACROMAN encoding */
        if ( 127 < c && c < 160 )
        {
            unsigned int c1 = 0, replMode = DISCARDED_CHAR;
            Bool isVendorChar = ( in->encoding == WIN1252 ||
                                  in->encoding == MACROMAN );
            Bool isMacChar    = ( in->encoding == MACROMAN );
            
            /* set error position just before offending character */
            if (in->doc->lexer)
            {
                in->doc->lexer->lines = in->curline;
                in->doc->lexer->columns = in->curcol;
            }
                
            if ( isMacChar )
                c1 = TY_(DecodeMacRoman)( c );
            else
                c1 = TY_(DecodeWin1252)( c );
            if ( c1 )
                replMode = REPLACED_CHAR;
                
            if ( c1 == 0 && isVendorChar )
                TY_(ReportEncodingError)(in->doc, VENDOR_SPECIFIC_CHARS, c, replMode == DISCARDED_CHAR);
            else if ( ! isVendorChar )
                TY_(ReportEncodingError)(in->doc, INVALID_SGML_CHARS, c, replMode == DISCARDED_CHAR);
                
            c = c1;
        }

        if ( c == 0 )
            continue; /* illegal char is discarded */
        
        in->curcol++;
        break;
    }

    return c;
}

static unsigned int PopChar( StreamIn *in )
{
    unsigned int c = EndOfStream;
    if ( in->pushed )
    {
        assert( in->bufpos > 0 );
        c = in->charbuf[ --in->bufpos ];
        if ( in->bufpos == 0 )
            in->pushed = no;

        if ( c == '\n' )
        {
            in->curcol = 1;
            in->curline++;
            PopLastPos( in );
            return c;
        }
        in->curcol++;
        PopLastPos( in );
    }
    return c;
}

void TY_(UngetChar)( unsigned int c, StreamIn *in )
{
    if (c == EndOfStream)
    {
        /* fprintf(stderr, "Attempt to UngetChar EOF\n"); */
        return;
    }
    
    in->pushed = yes;

    if (in->bufpos + 1 >= in->bufsize)
        in->charbuf = (tchar*)TidyRealloc(in->allocator, in->charbuf, sizeof(tchar) * ++(in->bufsize));

    in->charbuf[(in->bufpos)++] = c;

    if (c == '\n')
        --(in->curline);

    RestoreLastPos( in );
}



/************************
** Sink
************************/

static StreamOut* initStreamOut( TidyDocImpl* doc, int encoding, unsigned int nl )
{
    StreamOut* out = (StreamOut*) TidyDocAlloc( doc, sizeof(StreamOut) );
    TidyClearMemory( out, sizeof(StreamOut) );
    out->encoding = encoding;
    out->state = FSM_ASCII;
    out->nl = nl;
    return out;
}

StreamOut* TY_(FileOutput)( TidyDocImpl *doc, FILE* fp, int encoding, unsigned int nl )
{
    StreamOut* out = initStreamOut( doc, encoding, nl );
    TY_(initFileSink)( &out->sink, fp );
    out->iotype = FileIO;
    return out;
}
StreamOut* TY_(BufferOutput)( TidyDocImpl *doc, TidyBuffer* buf, int encoding, unsigned int nl )
{
    StreamOut* out = initStreamOut( doc, encoding, nl );
    tidyInitOutputBuffer( &out->sink, buf );
    out->iotype = BufferIO;
    return out;
}
StreamOut* TY_(UserOutput)( TidyDocImpl *doc, TidyOutputSink* sink, int encoding, unsigned int nl )
{
    StreamOut* out = initStreamOut( doc, encoding, nl );
    memcpy( &out->sink, sink, sizeof(TidyOutputSink) );
    out->iotype = UserIO;
    return out;
}

void TY_(WriteChar)( unsigned int c, StreamOut* out )
{
    /* Translate outgoing newlines */
    if ( '\n' == c )
    {
      if ( out->nl == TidyCRLF )
          TY_(WriteChar)( '\r', out );
      else if ( out->nl == TidyCR )
          c = '\r';
    }

    if (out->encoding == MACROMAN)
    {
        EncodeMacRoman( c, out );
    }
    else if (out->encoding == WIN1252)
    {
        EncodeWin1252( c, out );
    }
    else if (out->encoding == IBM858)
    {
        EncodeIbm858( c, out );
    }
    else if (out->encoding == LATIN0)
    {
        EncodeLatin0( c, out );
    }

    else if (out->encoding == UTF8)
    {
        int count = 0;
        
        TY_(EncodeCharToUTF8Bytes)( c, NULL, &out->sink, &count );
        if (count <= 0)
        {
            /* replacement char 0xFFFD encoded as UTF-8 */
            PutByte(0xEF, out); PutByte(0xBF, out); PutByte(0xBF, out);
        }
    }
#ifndef NO_NATIVE_ISO2022_SUPPORT
    else if (out->encoding == ISO2022)
    {
        if (c == 0x1b)  /* ESC */
            out->state = FSM_ESC;
        else
        {
            switch (out->state)
            {
            case FSM_ESC:
                if (c == '$')
                    out->state = FSM_ESCD;
                else if (c == '(')
                    out->state = FSM_ESCP;
                else
                    out->state = FSM_ASCII;
                break;

            case FSM_ESCD:
                if (c == '(')
                    out->state = FSM_ESCDP;
                else
                    out->state = FSM_NONASCII;
                break;

            case FSM_ESCDP:
                out->state = FSM_NONASCII;
                break;

            case FSM_ESCP:
                out->state = FSM_ASCII;
                break;

            case FSM_NONASCII:
                c &= 0x7F;
                break;

            case FSM_ASCII:
                break;
            }
        }

        PutByte(c, out);
    }
#endif /* NO_NATIVE_ISO2022_SUPPORT */

    else if ( out->encoding == UTF16LE ||
              out->encoding == UTF16BE ||
              out->encoding == UTF16 )
    {
        int i, numChars = 1;
        unsigned int theChars[2];
        
        if ( !TY_(IsValidUTF16FromUCS4)(c) )
        {
            /* invalid UTF-16 value */
            c = 0;
            numChars = 0;
        }
        else if ( TY_(IsCombinedChar)(c) )
        {
            /* output both, unless something goes wrong */
            numChars = 2;
            if ( !TY_(SplitSurrogatePair)(c, &theChars[0], &theChars[1]) )
            {
                c = 0;
                numChars = 0;
            }
        }
        else
        {
            /* just put the char out */
            theChars[0] = c;
        }
        
        for (i = 0; i < numChars; i++)
        {
            c = theChars[i];
            
            if (out->encoding == UTF16LE)
            {
                unsigned int ch = c & 0xFF; PutByte(ch, out); 
                ch = (c >> 8) & 0xFF; PutByte(ch, out); 
            }
    
            else if (out->encoding == UTF16BE || out->encoding == UTF16)
            {
                unsigned int ch = (c >> 8) & 0xFF; PutByte(ch, out); 
                ch = c & 0xFF; PutByte(ch, out); 
            }
        }
    }
    else if (out->encoding == BIG5 || out->encoding == SHIFTJIS)
    {
        if (c < 128)
            PutByte(c, out);
        else
        {
            unsigned int ch = (c >> 8) & 0xFF; PutByte(ch, out); 
            ch = c & 0xFF; PutByte(ch, out); 
        }
    }
    else
        PutByte( c, out );
}



/****************************
** Miscellaneous / Helpers
****************************/

/* Mapping for Windows Western character set CP 1252
** (chars 128-159/U+0080-U+009F) to Unicode.
*/
static const unsigned int Win2Unicode[32] =
{
    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
    0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
    0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178
};

/* Function for conversion from Windows-1252 to Unicode */
unsigned int TY_(DecodeWin1252)(unsigned int c)
{
    if (127 < c && c < 160)
        c = Win2Unicode[c - 128];
        
    return c;
}

static void EncodeWin1252( unsigned int c, StreamOut* out )
{
    if (c < 128 || (c > 159 && c < 256))
        PutByte(c, out);
    else
    {
        int i;

        for (i = 128; i < 160; i++)
            if (Win2Unicode[i - 128] == c)
            {
                PutByte(i, out);
                break;
            }
    }
}

/*
   John Love-Jensen contributed this table for mapping MacRoman
   character set to Unicode
*/

/* modified to only need chars 128-255/U+0080-U+00FF - Terry Teague 19 Aug 01 */
static const unsigned int Mac2Unicode[128] = 
{
    /* x7F = DEL */
    
    0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
    0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,

    0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
    0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,

    0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
    0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,

    0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
                                            /* =BD U+2126 OHM SIGN */
    0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,

    0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
    0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,

    0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
                            /* =DB U+00A4 CURRENCY SIGN */
    0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,

    0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
    0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
    /* xF0 = Apple Logo */
    /* =F0 U+2665 BLACK HEART SUIT */
    0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
    0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
};

/* Function to convert from MacRoman to Unicode */
unsigned int TY_(DecodeMacRoman)(unsigned int c)
{
    if (127 < c)
        c = Mac2Unicode[c - 128];
    return c;
}

static void EncodeMacRoman( unsigned int c, StreamOut* out )
{
        if (c < 128)
            PutByte(c, out);
        else
        {
            /* For mac users, map Unicode back to MacRoman. */
            int i;
            for (i = 128; i < 256; i++)
            {
                if (Mac2Unicode[i - 128] == c)
                {
                    PutByte(i, out);
                    break;
                }
            }
        }
}

/* Mapping for OS/2 Western character set CP 850
** (chars 128-255) to Unicode.
*/
static const unsigned int IBM2Unicode[128] =
{
    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
    0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
    0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
    0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x20AC, 0x00cd, 0x00ce,
    0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,
    0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe,
    0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4,
    0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8,
    0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0
};

/* Function for conversion from OS/2-850 to Unicode */
static unsigned int DecodeIbm850(unsigned int c)
{
    if (127 < c && c < 256)
        c = IBM2Unicode[c - 128];

    return c;
}

/* For OS/2,Java users, map Unicode back to IBM858 (IBM850+Euro). */
static void EncodeIbm858( unsigned int c, StreamOut* out )
{
    if (c < 128)
        PutByte(c, out);
    else
    {
        int i;
        for (i = 128; i < 256; i++)
        {
            if (IBM2Unicode[i - 128] == c)
            {
                PutByte(i, out);
                break;
            }
        }
    }
}


/* Convert from Latin0 (aka Latin9, ISO-8859-15) to Unicode */
static unsigned int DecodeLatin0(unsigned int c)
{
    if (159 < c && c < 191)
    {
        switch (c)
        {
        case 0xA4: c = 0x20AC; break;
        case 0xA6: c = 0x0160; break;
        case 0xA8: c = 0x0161; break;
        case 0xB4: c = 0x017D; break;
        case 0xB8: c = 0x017E; break;
        case 0xBC: c = 0x0152; break;
        case 0xBD: c = 0x0153; break;
        case 0xBE: c = 0x0178; break;
        }
    }
    return c;
}

/* Map Unicode back to ISO-8859-15. */
static void EncodeLatin0( unsigned int c, StreamOut* out )
{
    switch (c)
    {
    case 0x20AC: c = 0xA4; break;
    case 0x0160: c = 0xA6; break;
    case 0x0161: c = 0xA8; break;
    case 0x017D: c = 0xB4; break;
    case 0x017E: c = 0xB8; break;
    case 0x0152: c = 0xBC; break;
    case 0x0153: c = 0xBD; break;
    case 0x0178: c = 0xBE; break;
    }
    PutByte(c, out);
}

/* Facilitates user defined source by providing
** an entry point to marshal pointers-to-functions.
** Needed by .NET and possibly other language bindings.
*/
Bool TIDY_CALL tidyInitSource( TidyInputSource*  source,
                               void*             srcData,
                               TidyGetByteFunc   gbFunc,
                               TidyUngetByteFunc ugbFunc,
                               TidyEOFFunc       endFunc )
{
  Bool status = ( source && srcData && gbFunc && ugbFunc && endFunc );

  if ( status )
  {
    source->sourceData = srcData;
    source->getByte    = gbFunc;
    source->ungetByte  = ugbFunc;
    source->eof        = endFunc;
  }

  return status;
}

Bool TIDY_CALL tidyInitSink( TidyOutputSink* sink,
                             void*           snkData,
                             TidyPutByteFunc pbFunc )
{
  Bool status = ( sink && snkData && pbFunc );
  if ( status )
  {
    sink->sinkData = snkData;
    sink->putByte  = pbFunc;
  }
  return status;
}

/* GetByte must return a byte value in a signed
** integer so that a negative value can signal EOF
** without interfering w/ 0-255 legitimate byte values.
*/
unsigned int TIDY_CALL tidyGetByte( TidyInputSource* source )
{
  int bv = source->getByte( source->sourceData );
  return (unsigned int) bv;
}
Bool TIDY_CALL tidyIsEOF( TidyInputSource* source )
{
  return source->eof( source->sourceData );
}
void TIDY_CALL tidyUngetByte( TidyInputSource* source, unsigned int ch )
{
    source->ungetByte( source->sourceData, (byte) ch );
}
void TIDY_CALL tidyPutByte( TidyOutputSink* sink, unsigned int ch )
{
    sink->putByte( sink->sinkData, (byte) ch );
}

static unsigned int ReadByte( StreamIn* in )
{
    return tidyGetByte( &in->source );
}
Bool TY_(IsEOF)( StreamIn* in )
{
    return tidyIsEOF( &in->source );
}
static void UngetByte( StreamIn* in, unsigned int byteValue )
{
    tidyUngetByte( &in->source, byteValue );
}
static void PutByte( unsigned int byteValue, StreamOut* out )
{
    tidyPutByte( &out->sink, byteValue );
}

/* read char from stream */
static unsigned int ReadCharFromStream( StreamIn* in )
{
    unsigned int c, n;

    if ( TY_(IsEOF)(in) )
        return EndOfStream;
    
    c = ReadByte( in );

    if (c == EndOfStream)
        return c;

#ifndef NO_NATIVE_ISO2022_SUPPORT
    /*
       A document in ISO-2022 based encoding uses some ESC sequences
       called "designator" to switch character sets. The designators
       defined and used in ISO-2022-JP are:

        "ESC" + "(" + ?     for ISO646 variants

        "ESC" + "$" + ?     and
        "ESC" + "$" + "(" + ?   for multibyte character sets

       Where ? stands for a single character used to indicate the
       character set for multibyte characters.

       Tidy handles this by preserving the escape sequence and
       setting the top bit of each byte for non-ascii chars. This
       bit is then cleared on output. The input stream keeps track
       of the state to determine when to set/clear the bit.
    */

    if (in->encoding == ISO2022)
    {
        if (c == 0x1b)  /* ESC */
        {
            in->state = FSM_ESC;
            return c;
        }

        switch (in->state)
        {
        case FSM_ESC:
            if (c == '$')
                in->state = FSM_ESCD;
            else if (c == '(')
                in->state = FSM_ESCP;
            else
                in->state = FSM_ASCII;
            break;

        case FSM_ESCD:
            if (c == '(')
                in->state = FSM_ESCDP;
            else
                in->state = FSM_NONASCII;
            break;

        case FSM_ESCDP:
            in->state = FSM_NONASCII;
            break;

        case FSM_ESCP:
            in->state = FSM_ASCII;
            break;

        case FSM_NONASCII:
            c |= 0x80;
            break;

        case FSM_ASCII:
            break;
        }

        return c;
    }
#endif /* NO_NATIVE_ISO2022_SUPPORT */

    if ( in->encoding == UTF16LE )
    {
        unsigned int c1 = ReadByte( in );
        if ( EndOfStream == c1 )
            return EndOfStream;
        n = (c1 << 8) + c;
        return n;
    }

    if ((in->encoding == UTF16) || (in->encoding == UTF16BE)) /* UTF-16 is big-endian by default */
    {
        unsigned int c1 = ReadByte( in );
        if ( EndOfStream == c1 )
            return EndOfStream;
        n = (c << 8) + c1;
        return n;
    }

    if ( in->encoding == UTF8 )
    {
        /* deal with UTF-8 encoded char */

        int err, count = 0;
        
        /* first byte "c" is passed in separately */
        err = TY_(DecodeUTF8BytesToChar)( &n, c, NULL, &in->source, &count );
        if (!err && (n == (unsigned int)EndOfStream) && (count == 1)) /* EOF */
            return EndOfStream;
        else if (err)
        {
            /* set error position just before offending character */
            in->doc->lexer->lines = in->curline;
            in->doc->lexer->columns = in->curcol;

            TY_(ReportEncodingError)(in->doc, INVALID_UTF8, n, no);
            n = 0xFFFD; /* replacement char */
        }
        
        return n;
    }
    
    /*
       This section is suitable for any "multibyte" variable-width 
       character encoding in which a one-byte code is less than
       128, and the first byte of a two-byte code is greater or
       equal to 128. Note that Big5 and ShiftJIS fit into this
       kind, even though their second byte may be less than 128
    */
    if ((in->encoding == BIG5) || (in->encoding == SHIFTJIS))
    {
        if (c < 128)
            return c;
        else if ((in->encoding == SHIFTJIS) && (c >= 0xa1 && c <= 0xdf)) /* 461643 - fix suggested by Rick Cameron 14 Sep 01 */
        {
            /*
              Rick Cameron pointed out that for Shift_JIS, the values from
              0xa1 through 0xdf represent singe-byte characters
              (U+FF61 to U+FF9F - half-shift Katakana)
            */
            return c;
        }
        else
        {
            unsigned int c1 = ReadByte( in );
            if ( EndOfStream == c1 )
                return EndOfStream;
            n = (c << 8) + c1;
            return n;
        }
    }
    else
        n = c;
        
    return n;
}

/* Output a Byte Order Mark if required */
void TY_(outBOM)( StreamOut *out )
{
    if ( out->encoding == UTF8
         || out->encoding == UTF16LE
         || out->encoding == UTF16BE
         || out->encoding == UTF16
       )
    {
        /* this will take care of encoding the BOM correctly */
        TY_(WriteChar)( UNICODE_BOM, out );
    }
}

/* this is in intermediate fix for various problems in the */
/* long term code and data in charsets.c should be used    */
static struct _enc2iana
{
    unsigned int id;
    ctmbstr name;
    ctmbstr tidyOptName;
} const enc2iana[] =
{
  { ASCII,    "us-ascii",     "ascii"   },
  { LATIN0,   "iso-8859-15",  "latin0"  },
  { LATIN1,   "iso-8859-1",   "latin1"  },
  { UTF8,     "utf-8",        "utf8"   },
  { MACROMAN, "macintosh",    "mac"     },
  { WIN1252,  "windows-1252", "win1252" },
  { IBM858,   "ibm00858",     "ibm858"  },
  { UTF16LE,  "utf-16",       "utf16le" },
  { UTF16BE,  "utf-16",       "utf16be" },
  { UTF16,    "utf-16",       "utf16"   },
  { BIG5,     "big5",         "big5"    },
  { SHIFTJIS, "shift_jis",    "shiftjis"},
#ifndef NO_NATIVE_ISO2022_SUPPORT
  { ISO2022,  NULL,           "iso2022" },
#endif
  { RAW,      NULL,           "raw"     }
};

ctmbstr TY_(GetEncodingNameFromTidyId)(unsigned int id)
{
    unsigned int i;

    for (i = 0; enc2iana[i].name; ++i)
        if (enc2iana[i].id == id)
            return enc2iana[i].name;

    return NULL;
}

ctmbstr TY_(GetEncodingOptNameFromTidyId)(unsigned int id)
{
    unsigned int i;

    for (i = 0; i < sizeof(enc2iana)/sizeof(enc2iana[0]); ++i)
        if (enc2iana[i].id == id)
            return enc2iana[i].tidyOptName;

    return NULL;
}

int TY_(GetCharEncodingFromOptName)( ctmbstr charenc )
{
    unsigned int i;

    for (i = 0; i < sizeof(enc2iana)/sizeof(enc2iana[0]); ++i)
        if (TY_(tmbstrcasecmp)(charenc, enc2iana[i].tidyOptName) == 0 )
            return enc2iana[i].id;

    return -1;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* tags.c
 * Recognize HTML tags.
 *
 * Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
 * Institute of Technology, European Research Consortium for Informatics
 * and Mathematics, Keio University) and HTACG.
 *
 * See tidy.h for the copyright notice.
 */

/* #include "tidy-int.h" */
/* #include "message.h" */
/* #include "tmbstr.h" */
/* #include "sprtf.h" */

/* Attribute checking methods */
static CheckAttribs CheckIMG;
static CheckAttribs CheckLINK;
static CheckAttribs CheckAREA;
static CheckAttribs CheckTABLE;
static CheckAttribs CheckCaption;
static CheckAttribs CheckHTML;

#define VERS_ELEM_A          (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_ABBR       (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_ACRONYM    (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|xxxx|xxxx)
#define VERS_ELEM_ADDRESS    (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_APPLET     (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_AREA       (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_B          (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_BASE       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_BASEFONT   (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_BDO        (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_BIG        (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx)
#define VERS_ELEM_BLOCKQUOTE (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_BODY       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_BR         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_BUTTON     (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_CAPTION    (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_CENTER     (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_CITE       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_CODE       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_COL        (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_COLGROUP   (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_DD         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_DEL        (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_DFN        (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_DIR        (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_DIV        (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_DL         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_DT         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_EM         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_FIELDSET   (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_FONT       (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_FORM       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_FRAME      (xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_FRAMESET   (xxxx|xxxx|xxxx|xxxx|xxxx|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_H1         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_H2         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_H3         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_H4         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_H5         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_H6         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_HEAD       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_HR         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_HTML       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_I          (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_IFRAME     (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_IMG        (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_INPUT      (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_INS        (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_ISINDEX    (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_KBD        (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_LABEL      (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_LEGEND     (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_LI         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_LINK       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_LISTING    (HT20|HT32|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_MAP        (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_MATHML     (xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50) /* [i_a]2 */
#define VERS_ELEM_MENU       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_META       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_NEXTID     (HT20|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_NOFRAMES   (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_NOSCRIPT   (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_OBJECT     (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_OL         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_OPTGROUP   (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_OPTION     (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_P          (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_PARAM      (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_PICTURE    (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_PLAINTEXT  (HT20|HT32|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_PRE        (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_Q          (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_RB         (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx)
#define VERS_ELEM_RBC        (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx)
#define VERS_ELEM_RP         (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_RT         (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_RTC        (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|xxxx|xxxx)
#define VERS_ELEM_RUBY       (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_S          (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_SAMP       (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_SCRIPT     (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_SELECT     (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_SMALL      (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_SPAN       (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_STRIKE     (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)
#define VERS_ELEM_STRONG     (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_STYLE      (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_SUB        (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_SUP        (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_SVG        (xxxx|xxxx|xxxx|H41T|X10T|xxxx|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_TABLE      (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_TBODY      (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_TD         (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_TEXTAREA   (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_TFOOT      (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_TH         (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_THEAD      (xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|HT50|XH50)
#define VERS_ELEM_TITLE      (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_TR         (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_TT         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|xxxx|xxxx|xxxx)
#define VERS_ELEM_U          (xxxx|HT32|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_UL         (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_VAR        (HT20|HT32|H40T|H41T|X10T|H40F|H41F|X10F|H40S|H41S|X10S|XH11|XB10|HT50|XH50)
#define VERS_ELEM_XMP        (HT20|HT32|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx)

#define VERS_ELEM_ARTICLE    (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_ASIDE      (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_AUDIO      (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_BDI        (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_CANVAS     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_COMMAND    (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_DATALIST   (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_DATA       (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_DETAILS    (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_DIALOG     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_EMBED      (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_FIGCAPTION (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_FIGURE     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_FOOTER     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_HEADER     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_HGROUP     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_KEYGEN     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_MAIN       (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_MARK       (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_MENUITEM   (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_KEYGEN     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_METER      (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_NAV        (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_OUTPUT     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_PROGRESS   (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_SECTION    (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_SOURCE     (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_SUMMARY    (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_TEMPLATE   (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_TIME       (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_TRACK      (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_VIDEO      (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)
#define VERS_ELEM_WBR        (xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|HT50|XH50)

/*\ 
 * Issue #167 & #169 & #232
 * Tidy defaults to HTML5 mode
 * but allow this table to be ADJUSTED if NOT HTML5
 * was static const Dict tag_defs[] = 
\*/
static Dict tag_defs[] =
{
  { TidyTag_UNKNOWN,    "unknown!",   VERS_UNKNOWN,         NULL,                       (0),                                           NULL,          NULL           },

  /* W3C defined elements */
  { TidyTag_A,          "a",          VERS_ELEM_A,          &TY_(W3CAttrsFor_A)[0],          (CM_INLINE|CM_BLOCK|CM_MIXED),                 TY_(ParseBlock),    NULL           }, /* Issue #167 & #169 - default HTML5 */
  { TidyTag_ABBR,       "abbr",       VERS_ELEM_ABBR,       &TY_(W3CAttrsFor_ABBR)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_ACRONYM,    "acronym",    VERS_ELEM_ACRONYM,    &TY_(W3CAttrsFor_ACRONYM)[0],    (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_ADDRESS,    "address",    VERS_ELEM_ADDRESS,    &TY_(W3CAttrsFor_ADDRESS)[0],    (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_APPLET,     "applet",     VERS_ELEM_APPLET,     &TY_(W3CAttrsFor_APPLET)[0],     (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM),         TY_(ParseBlock),    NULL           },
  { TidyTag_AREA,       "area",       VERS_ELEM_AREA,       &TY_(W3CAttrsFor_AREA)[0],       (CM_BLOCK|CM_EMPTY),                           TY_(ParseEmpty),    CheckAREA      },
  { TidyTag_B,          "b",          VERS_ELEM_B,          &TY_(W3CAttrsFor_B)[0],          (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_BASE,       "base",       VERS_ELEM_BASE,       &TY_(W3CAttrsFor_BASE)[0],       (CM_HEAD|CM_EMPTY),                            TY_(ParseEmpty),    NULL           },
  { TidyTag_BASEFONT,   "basefont",   VERS_ELEM_BASEFONT,   &TY_(W3CAttrsFor_BASEFONT)[0],   (CM_INLINE|CM_EMPTY),                          TY_(ParseEmpty),    NULL           },
  { TidyTag_BDO,        "bdo",        VERS_ELEM_BDO,        &TY_(W3CAttrsFor_BDO)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_BIG,        "big",        VERS_ELEM_BIG,        &TY_(W3CAttrsFor_BIG)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_BLOCKQUOTE, "blockquote", VERS_ELEM_BLOCKQUOTE, &TY_(W3CAttrsFor_BLOCKQUOTE)[0], (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_BODY,       "body",       VERS_ELEM_BODY,       &TY_(W3CAttrsFor_BODY)[0],       (CM_HTML|CM_OPT|CM_OMITST),                    TY_(ParseBody),     NULL           },
  { TidyTag_BR,         "br",         VERS_ELEM_BR,         &TY_(W3CAttrsFor_BR)[0],         (CM_INLINE|CM_EMPTY),                          TY_(ParseEmpty),    NULL           },
  { TidyTag_BUTTON,     "button",     VERS_ELEM_BUTTON,     &TY_(W3CAttrsFor_BUTTON)[0],     (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_CAPTION,    "caption",    VERS_ELEM_CAPTION,    &TY_(W3CAttrsFor_CAPTION)[0],    (CM_TABLE),                                    TY_(ParseBlock),    CheckCaption   },
  { TidyTag_CENTER,     "center",     VERS_ELEM_CENTER,     &TY_(W3CAttrsFor_CENTER)[0],     (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_CITE,       "cite",       VERS_ELEM_CITE,       &TY_(W3CAttrsFor_CITE)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_CODE,       "code",       VERS_ELEM_CODE,       &TY_(W3CAttrsFor_CODE)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_COL,        "col",        VERS_ELEM_COL,        &TY_(W3CAttrsFor_COL)[0],        (CM_TABLE|CM_EMPTY),                           TY_(ParseEmpty),    NULL           },
  { TidyTag_COLGROUP,   "colgroup",   VERS_ELEM_COLGROUP,   &TY_(W3CAttrsFor_COLGROUP)[0],   (CM_TABLE|CM_OPT),                             TY_(ParseColGroup), NULL           },
  { TidyTag_DD,         "dd",         VERS_ELEM_DD,         &TY_(W3CAttrsFor_DD)[0],         (CM_DEFLIST|CM_OPT|CM_NO_INDENT),              TY_(ParseBlock),    NULL           },
  { TidyTag_DEL,        "del",        VERS_ELEM_DEL,        &TY_(W3CAttrsFor_DEL)[0],        (CM_INLINE|CM_BLOCK|CM_MIXED),                 TY_(ParseInline),   NULL           },
  { TidyTag_DFN,        "dfn",        VERS_ELEM_DFN,        &TY_(W3CAttrsFor_DFN)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_DIR,        "dir",        VERS_ELEM_DIR,        &TY_(W3CAttrsFor_DIR)[0],        (CM_BLOCK|CM_OBSOLETE),                        TY_(ParseList),     NULL           },
  { TidyTag_DIV,        "div",        VERS_ELEM_DIV,        &TY_(W3CAttrsFor_DIV)[0],        (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_DL,         "dl",         VERS_ELEM_DL,         &TY_(W3CAttrsFor_DL)[0],         (CM_BLOCK),                                    TY_(ParseDefList),  NULL           },
  { TidyTag_DT,         "dt",         VERS_ELEM_DT,         &TY_(W3CAttrsFor_DT)[0],         (CM_DEFLIST|CM_OPT|CM_NO_INDENT),              TY_(ParseInline),   NULL           },
  { TidyTag_EM,         "em",         VERS_ELEM_EM,         &TY_(W3CAttrsFor_EM)[0],         (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_FIELDSET,   "fieldset",   VERS_ELEM_FIELDSET,   &TY_(W3CAttrsFor_FIELDSET)[0],   (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_FONT,       "font",       VERS_ELEM_FONT,       &TY_(W3CAttrsFor_FONT)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  /* HTML5 Form Elements has several new elements and attributes - datalist keygen output */
  { TidyTag_FORM,       "form",       VERS_ELEM_FORM,       &TY_(W3CAttrsFor_FORM)[0],       (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_FRAME,      "frame",      VERS_ELEM_FRAME,      &TY_(W3CAttrsFor_FRAME)[0],      (CM_FRAMES|CM_EMPTY),                          TY_(ParseEmpty),    NULL           },
  { TidyTag_FRAMESET,   "frameset",   VERS_ELEM_FRAMESET,   &TY_(W3CAttrsFor_FRAMESET)[0],   (CM_HTML|CM_FRAMES),                           TY_(ParseFrameSet), NULL           },
  { TidyTag_H1,         "h1",         VERS_ELEM_H1,         &TY_(W3CAttrsFor_H1)[0],         (CM_BLOCK|CM_HEADING),                         TY_(ParseInline),   NULL           },
  { TidyTag_H2,         "h2",         VERS_ELEM_H2,         &TY_(W3CAttrsFor_H2)[0],         (CM_BLOCK|CM_HEADING),                         TY_(ParseInline),   NULL           },
  { TidyTag_H3,         "h3",         VERS_ELEM_H3,         &TY_(W3CAttrsFor_H3)[0],         (CM_BLOCK|CM_HEADING),                         TY_(ParseInline),   NULL           },
  { TidyTag_H4,         "h4",         VERS_ELEM_H4,         &TY_(W3CAttrsFor_H4)[0],         (CM_BLOCK|CM_HEADING),                         TY_(ParseInline),   NULL           },
  { TidyTag_H5,         "h5",         VERS_ELEM_H5,         &TY_(W3CAttrsFor_H5)[0],         (CM_BLOCK|CM_HEADING),                         TY_(ParseInline),   NULL           },
  { TidyTag_H6,         "h6",         VERS_ELEM_H6,         &TY_(W3CAttrsFor_H6)[0],         (CM_BLOCK|CM_HEADING),                         TY_(ParseInline),   NULL           },
  { TidyTag_HEAD,       "head",       VERS_ELEM_HEAD,       &TY_(W3CAttrsFor_HEAD)[0],       (CM_HTML|CM_OPT|CM_OMITST),                    TY_(ParseHead),     NULL           },
  { TidyTag_HR,         "hr",         VERS_ELEM_HR,         &TY_(W3CAttrsFor_HR)[0],         (CM_BLOCK|CM_EMPTY),                           TY_(ParseEmpty),    NULL           },
  { TidyTag_HTML,       "html",       VERS_ELEM_HTML,       &TY_(W3CAttrsFor_HTML)[0],       (CM_HTML|CM_OPT|CM_OMITST),                    TY_(ParseHTML),     CheckHTML      },
  { TidyTag_I,          "i",          VERS_ELEM_I,          &TY_(W3CAttrsFor_I)[0],          (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_IFRAME,     "iframe",     VERS_ELEM_IFRAME,     &TY_(W3CAttrsFor_IFRAME)[0],     (CM_INLINE),                                   TY_(ParseBlock),    NULL           },
  { TidyTag_IMG,        "img",        VERS_ELEM_IMG,        &TY_(W3CAttrsFor_IMG)[0],        (CM_INLINE|CM_IMG|CM_EMPTY),                   TY_(ParseEmpty),    CheckIMG       },
  { TidyTag_INPUT,      "input",      VERS_ELEM_INPUT,      &TY_(W3CAttrsFor_INPUT)[0],      (CM_INLINE|CM_IMG|CM_EMPTY),                   TY_(ParseEmpty),    NULL           },
  { TidyTag_INS,        "ins",        VERS_ELEM_INS,        &TY_(W3CAttrsFor_INS)[0],        (CM_INLINE|CM_BLOCK|CM_MIXED),                 TY_(ParseInline),   NULL           },
  { TidyTag_ISINDEX,    "isindex",    VERS_ELEM_ISINDEX,    &TY_(W3CAttrsFor_ISINDEX)[0],    (CM_BLOCK|CM_EMPTY),                           TY_(ParseEmpty),    NULL           },
  { TidyTag_KBD,        "kbd",        VERS_ELEM_KBD,        &TY_(W3CAttrsFor_KBD)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_LABEL,      "label",      VERS_ELEM_LABEL,      &TY_(W3CAttrsFor_LABEL)[0],      (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_LEGEND,     "legend",     VERS_ELEM_LEGEND,     &TY_(W3CAttrsFor_LEGEND)[0],     (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_LI,         "li",         VERS_ELEM_LI,         &TY_(W3CAttrsFor_LI)[0],         (CM_LIST|CM_OPT|CM_NO_INDENT),                 TY_(ParseBlock),    NULL           },
  { TidyTag_LINK,       "link",       VERS_ELEM_LINK,       &TY_(W3CAttrsFor_LINK)[0],       (CM_HEAD|CM_BLOCK|CM_EMPTY),                   TY_(ParseEmpty),    CheckLINK      },
  { TidyTag_LISTING,    "listing",    VERS_ELEM_LISTING,    &TY_(W3CAttrsFor_LISTING)[0],    (CM_BLOCK|CM_OBSOLETE),                        TY_(ParsePre),      NULL           },
  { TidyTag_MAP,        "map",        VERS_ELEM_MAP,        &TY_(W3CAttrsFor_MAP)[0],        (CM_INLINE),                                   TY_(ParseBlock),    NULL           },
  { TidyTag_MATHML,     "math",       VERS_ELEM_MATHML,     &TY_(W3CAttrsFor_MATHML)[0],     (CM_INLINE|CM_BLOCK|CM_MIXED),                 TY_(ParseNamespace),NULL           }, /* [i_a]2 */
  /* { TidyTag_MENU,       "menu",       VERS_ELEM_MENU,       &TY_(W3CAttrsFor_MENU)[0],       (CM_BLOCK|CM_OBSOLETE),                        TY_(ParseList),     NULL           }, */
  { TidyTag_META,       "meta",       VERS_ELEM_META,       &TY_(W3CAttrsFor_META)[0],       (CM_HEAD|CM_BLOCK|CM_EMPTY),                   TY_(ParseEmpty),    NULL           },
  { TidyTag_NOFRAMES,   "noframes",   VERS_ELEM_NOFRAMES,   &TY_(W3CAttrsFor_NOFRAMES)[0],   (CM_BLOCK|CM_FRAMES),                          TY_(ParseNoFrames), NULL           },
  { TidyTag_NOSCRIPT,   "noscript",   VERS_ELEM_NOSCRIPT,   &TY_(W3CAttrsFor_NOSCRIPT)[0],   (CM_HEAD|CM_BLOCK|CM_INLINE|CM_MIXED),         TY_(ParseBlock),    NULL           },
  { TidyTag_OBJECT,     "object",     VERS_ELEM_OBJECT,     &TY_(W3CAttrsFor_OBJECT)[0],     (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM),         TY_(ParseBlock),    NULL           },
  { TidyTag_OL,         "ol",         VERS_ELEM_OL,         &TY_(W3CAttrsFor_OL)[0],         (CM_BLOCK),                                    TY_(ParseList),     NULL           },
  { TidyTag_OPTGROUP,   "optgroup",   VERS_ELEM_OPTGROUP,   &TY_(W3CAttrsFor_OPTGROUP)[0],   (CM_FIELD|CM_OPT),                             TY_(ParseOptGroup), NULL           },
  { TidyTag_OPTION,     "option",     VERS_ELEM_OPTION,     &TY_(W3CAttrsFor_OPTION)[0],     (CM_FIELD|CM_OPT),                             TY_(ParseText),     NULL           },
  { TidyTag_P,          "p",          VERS_ELEM_P,          &TY_(W3CAttrsFor_P)[0],          (CM_BLOCK|CM_OPT),                             TY_(ParseInline),   NULL           },
  { TidyTag_PARAM,      "param",      VERS_ELEM_PARAM,      &TY_(W3CAttrsFor_PARAM)[0],      (CM_INLINE|CM_EMPTY),                          TY_(ParseEmpty),    NULL           },
  { TidyTag_PICTURE,    "picture",    VERS_ELEM_PICTURE,    &TY_(W3CAttrsFor_PICTURE)[0],    (CM_INLINE),                                   TY_(ParseInline),   NULL           }, /* Issue #151 html5 */
  { TidyTag_PLAINTEXT,  "plaintext",  VERS_ELEM_PLAINTEXT,  &TY_(W3CAttrsFor_PLAINTEXT)[0],  (CM_BLOCK|CM_OBSOLETE),                        TY_(ParsePre),      NULL           },
  { TidyTag_PRE,        "pre",        VERS_ELEM_PRE,        &TY_(W3CAttrsFor_PRE)[0],        (CM_BLOCK),                                    TY_(ParsePre),      NULL           },
  { TidyTag_Q,          "q",          VERS_ELEM_Q,          &TY_(W3CAttrsFor_Q)[0],          (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_RB,         "rb",         VERS_ELEM_RB,         &TY_(W3CAttrsFor_RB)[0],         (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_RBC,        "rbc",        VERS_ELEM_RBC,        &TY_(W3CAttrsFor_RBC)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_RP,         "rp",         VERS_ELEM_RP,         &TY_(W3CAttrsFor_RP)[0],         (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_RT,         "rt",         VERS_ELEM_RT,         &TY_(W3CAttrsFor_RT)[0],         (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_RTC,        "rtc",        VERS_ELEM_RTC,        &TY_(W3CAttrsFor_RTC)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_RUBY,       "ruby",       VERS_ELEM_RUBY,       &TY_(W3CAttrsFor_RUBY)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_S,          "s",          VERS_ELEM_S,          &TY_(W3CAttrsFor_S)[0],          (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_SAMP,       "samp",       VERS_ELEM_SAMP,       &TY_(W3CAttrsFor_SAMP)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_SCRIPT,     "script",     VERS_ELEM_SCRIPT,     &TY_(W3CAttrsFor_SCRIPT)[0],     (CM_HEAD|CM_MIXED|CM_BLOCK|CM_INLINE),         TY_(ParseScript),   NULL           },
  { TidyTag_SELECT,     "select",     VERS_ELEM_SELECT,     &TY_(W3CAttrsFor_SELECT)[0],     (CM_INLINE|CM_FIELD),                          TY_(ParseSelect),   NULL           },
  { TidyTag_SMALL,      "small",      VERS_ELEM_SMALL,      &TY_(W3CAttrsFor_SMALL)[0],      (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_SPAN,       "span",       VERS_ELEM_SPAN,       &TY_(W3CAttrsFor_SPAN)[0],       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_STRIKE,     "strike",     VERS_ELEM_STRIKE,     &TY_(W3CAttrsFor_STRIKE)[0],     (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_STRONG,     "strong",     VERS_ELEM_STRONG,     &TY_(W3CAttrsFor_STRONG)[0],     (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_STYLE,      "style",      VERS_ELEM_STYLE,      &TY_(W3CAttrsFor_STYLE)[0],      (CM_HEAD|CM_BLOCK),                            TY_(ParseScript),   NULL           },
  { TidyTag_SUB,        "sub",        VERS_ELEM_SUB,        &TY_(W3CAttrsFor_SUB)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_SUP,        "sup",        VERS_ELEM_SUP,        &TY_(W3CAttrsFor_SUP)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_SVG,        "svg",        VERS_ELEM_SVG,        &TY_(W3CAttrsFor_SVG)[0],        (CM_INLINE|CM_BLOCK|CM_MIXED),                 TY_(ParseNamespace),NULL           },
  { TidyTag_TABLE,      "table",      VERS_ELEM_TABLE,      &TY_(W3CAttrsFor_TABLE)[0],      (CM_BLOCK),                                    TY_(ParseTableTag), CheckTABLE     },
  { TidyTag_TBODY,      "tbody",      VERS_ELEM_TBODY,      &TY_(W3CAttrsFor_TBODY)[0],      (CM_TABLE|CM_ROWGRP|CM_OPT),                   TY_(ParseRowGroup), NULL           },
  { TidyTag_TD,         "td",         VERS_ELEM_TD,         &TY_(W3CAttrsFor_TD)[0],         (CM_ROW|CM_OPT|CM_NO_INDENT),                  TY_(ParseBlock),    NULL           },
  { TidyTag_TEXTAREA,   "textarea",   VERS_ELEM_TEXTAREA,   &TY_(W3CAttrsFor_TEXTAREA)[0],   (CM_INLINE|CM_FIELD),                          TY_(ParseText),     NULL           },
  { TidyTag_TFOOT,      "tfoot",      VERS_ELEM_TFOOT,      &TY_(W3CAttrsFor_TFOOT)[0],      (CM_TABLE|CM_ROWGRP|CM_OPT),                   TY_(ParseRowGroup), NULL           },
  { TidyTag_TH,         "th",         VERS_ELEM_TH,         &TY_(W3CAttrsFor_TH)[0],         (CM_ROW|CM_OPT|CM_NO_INDENT),                  TY_(ParseBlock),    NULL           },
  { TidyTag_THEAD,      "thead",      VERS_ELEM_THEAD,      &TY_(W3CAttrsFor_THEAD)[0],      (CM_TABLE|CM_ROWGRP|CM_OPT),                   TY_(ParseRowGroup), NULL           },
  { TidyTag_TITLE,      "title",      VERS_ELEM_TITLE,      &TY_(W3CAttrsFor_TITLE)[0],      (CM_HEAD),                                     TY_(ParseTitle),    NULL           },
  { TidyTag_TR,         "tr",         VERS_ELEM_TR,         &TY_(W3CAttrsFor_TR)[0],         (CM_TABLE|CM_OPT),                             TY_(ParseRow),      NULL           },
  { TidyTag_TT,         "tt",         VERS_ELEM_TT,         &TY_(W3CAttrsFor_TT)[0],         (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_U,          "u",          VERS_ELEM_U,          &TY_(W3CAttrsFor_U)[0],          (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_UL,         "ul",         VERS_ELEM_UL,         &TY_(W3CAttrsFor_UL)[0],         (CM_BLOCK),                                    TY_(ParseList),     NULL           },
  { TidyTag_VAR,        "var",        VERS_ELEM_VAR,        &TY_(W3CAttrsFor_VAR)[0],        (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_XMP,        "xmp",        VERS_ELEM_XMP,        &TY_(W3CAttrsFor_XMP)[0],        (CM_BLOCK|CM_OBSOLETE),                        TY_(ParsePre),      NULL           },
  { TidyTag_NEXTID,     "nextid",     VERS_ELEM_NEXTID,     &TY_(W3CAttrsFor_NEXTID)[0],     (CM_HEAD|CM_EMPTY),                            TY_(ParseEmpty),    NULL           },

  /* proprietary elements */
  { TidyTag_ALIGN,      "align",      VERS_NETSCAPE,        NULL,                       (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_BGSOUND,    "bgsound",    VERS_MICROSOFT,       NULL,                       (CM_HEAD|CM_EMPTY),                            TY_(ParseEmpty),    NULL           },
  { TidyTag_BLINK,      "blink",      VERS_PROPRIETARY,     NULL,                       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_COMMENT,    "comment",    VERS_MICROSOFT,       NULL,                       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_ILAYER,     "ilayer",     VERS_NETSCAPE,        NULL,                       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_LAYER,      "layer",      VERS_NETSCAPE,        NULL,                       (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_MARQUEE,    "marquee",    VERS_MICROSOFT,       NULL,                       (CM_INLINE|CM_OPT),                            TY_(ParseInline),   NULL           },
  { TidyTag_MULTICOL,   "multicol",   VERS_NETSCAPE,        NULL,                       (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_NOBR,       "nobr",       VERS_PROPRIETARY,     NULL,                       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_NOEMBED,    "noembed",    VERS_NETSCAPE,        NULL,                       (CM_INLINE),                                   TY_(ParseInline),   NULL           },
  { TidyTag_NOLAYER,    "nolayer",    VERS_NETSCAPE,        NULL,                       (CM_BLOCK|CM_INLINE|CM_MIXED),                 TY_(ParseBlock),    NULL           },
  { TidyTag_NOSAVE,     "nosave",     VERS_NETSCAPE,        NULL,                       (CM_BLOCK),                                    TY_(ParseBlock),    NULL           },
  { TidyTag_SERVER,     "server",     VERS_NETSCAPE,        NULL,                       (CM_HEAD|CM_MIXED|CM_BLOCK|CM_INLINE),         TY_(ParseScript),   NULL           },
  { TidyTag_SERVLET,    "servlet",    VERS_SUN,             NULL,                       (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM),         TY_(ParseBlock),    NULL           },
  { TidyTag_SPACER,     "spacer",     VERS_NETSCAPE,        NULL,                       (CM_INLINE|CM_EMPTY),                          TY_(ParseEmpty),    NULL           },

  /* HTML5 */
  { TidyTag_ARTICLE,     "article",      VERS_ELEM_ARTICLE,     &TY_(W3CAttrsFor_ARTICLE)[0],     (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_ASIDE,       "aside",        VERS_ELEM_ASIDE,       &TY_(W3CAttrsFor_ASIDE)[0],       (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_AUDIO,       "audio",        VERS_ELEM_AUDIO,       &TY_(W3CAttrsFor_AUDIO)[0],       (CM_BLOCK|CM_INLINE),          TY_(ParseBlock),     NULL           },
  { TidyTag_BDI,         "bdi",          VERS_ELEM_BDI,         &TY_(W3CAttrsFor_BDI)[0],         (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_CANVAS,      "canvas",       VERS_ELEM_CANVAS,      &TY_(W3CAttrsFor_CANVAS)[0],      (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_COMMAND,     "command",      VERS_ELEM_COMMAND,     &TY_(W3CAttrsFor_COMMAND)[0],     (CM_HEAD|CM_INLINE|CM_EMPTY),  TY_(ParseEmpty),     NULL           },
  { TidyTag_DATALIST,    "datalist",     VERS_ELEM_DATALIST,    &TY_(W3CAttrsFor_DATALIST)[0],    (CM_INLINE|CM_FIELD),          TY_(ParseDatalist),  NULL           },
  /* { TidyTag_DATALIST,    "datalist",     VERS_ELEM_DATALIST,    &TY_(W3CAttrsFor_DATALIST)[0],    (CM_FIELD),                   TY_(ParseInline),    NULL           },*/
  { TidyTag_DATA,        "data",         VERS_ELEM_DATA,        &TY_(W3CAttrsFor_DATA)[0],        (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_DETAILS,     "details",      VERS_ELEM_DETAILS,     &TY_(W3CAttrsFor_DETAILS)[0],     (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_DIALOG,      "dialog",       VERS_ELEM_DIALOG,      &TY_(W3CAttrsFor_DIALOG)[0],      (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_EMBED,       "embed",        VERS_ELEM_EMBED,       &TY_(W3CAttrsFor_EMBED)[0],       (CM_INLINE|CM_IMG|CM_EMPTY),   TY_(ParseEmpty),     NULL           },
  { TidyTag_FIGCAPTION,  "figcaption",   VERS_ELEM_FIGCAPTION,  &TY_(W3CAttrsFor_FIGCAPTION)[0],  (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_FIGURE,      "figure",       VERS_ELEM_FIGURE,      &TY_(W3CAttrsFor_FIGURE)[0],      (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_FOOTER,      "footer",       VERS_ELEM_FOOTER,      &TY_(W3CAttrsFor_FOOTER)[0],      (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_HEADER,      "header",       VERS_ELEM_HEADER,      &TY_(W3CAttrsFor_HEADER)[0],      (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_HGROUP,      "hgroup",       VERS_ELEM_HGROUP,      &TY_(W3CAttrsFor_HGROUP)[0],      (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_KEYGEN,      "keygen",       VERS_ELEM_KEYGEN,      &TY_(W3CAttrsFor_KEYGEN)[0],      (CM_INLINE|CM_EMPTY),          TY_(ParseEmpty),     NULL           },
  { TidyTag_MAIN,        "main",         VERS_ELEM_MAIN,        &TY_(W3CAttrsFor_MAIN)[0],        (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_MARK,        "mark",         VERS_ELEM_MARK,        &TY_(W3CAttrsFor_MARK)[0],        (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_MENU,        "menu",         VERS_ELEM_MENU,        &TY_(W3CAttrsFor_MENU)[0],        (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_MENUITEM,    "menuitem",     VERS_ELEM_MENUITEM,    &TY_(W3CAttrsFor_MENUITEM)[0],    (CM_INLINE|CM_BLOCK|CM_MIXED), TY_(ParseInline),    NULL           },
  { TidyTag_METER,       "meter",        VERS_ELEM_METER,       &TY_(W3CAttrsFor_METER)[0],       (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_NAV,         "nav",          VERS_ELEM_NAV,         &TY_(W3CAttrsFor_NAV)[0],         (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_OUTPUT,      "output",       VERS_ELEM_OUTPUT,      &TY_(W3CAttrsFor_OUTPUT)[0],      (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_PROGRESS,    "progress",     VERS_ELEM_PROGRESS,    &TY_(W3CAttrsFor_PROGRESS)[0],    (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_SECTION,     "section",      VERS_ELEM_SECTION,     &TY_(W3CAttrsFor_SECTION)[0],     (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_SOURCE,      "source",       VERS_ELEM_SOURCE,      &TY_(W3CAttrsFor_SOURCE)[0],      (CM_BLOCK|CM_INLINE|CM_EMPTY), TY_(ParseBlock),     NULL           },
  { TidyTag_SUMMARY,     "summary",      VERS_ELEM_SUMMARY,     &TY_(W3CAttrsFor_SUMMARY)[0],     (CM_BLOCK),                    TY_(ParseInline),    NULL           },
  { TidyTag_TEMPLATE,    "template",     VERS_ELEM_TEMPLATE,    &TY_(W3CAttrsFor_TEMPLATE)[0],    (CM_BLOCK),                    TY_(ParseBlock),     NULL           },
  { TidyTag_TIME,        "time",         VERS_ELEM_TIME,        &TY_(W3CAttrsFor_TIME)[0],        (CM_INLINE),                   TY_(ParseInline),    NULL           },
  { TidyTag_TRACK,       "track",        VERS_ELEM_TRACK,       &TY_(W3CAttrsFor_TRACK)[0],       (CM_BLOCK|CM_EMPTY),           TY_(ParseBlock),     NULL           },
  { TidyTag_VIDEO,       "video",        VERS_ELEM_VIDEO,       &TY_(W3CAttrsFor_VIDEO)[0],       (CM_BLOCK|CM_INLINE),          TY_(ParseBlock),     NULL           },
  { TidyTag_WBR,         "wbr",          VERS_ELEM_WBR,         &TY_(W3CAttrsFor_WBR)[0],         (CM_INLINE|CM_EMPTY),          TY_(ParseEmpty),     NULL           },

  /* this must be the final entry */
  { (TidyTagId)0,        NULL,         0,                    NULL,                       (0),                                           NULL,          NULL           }
};

static unsigned int tagsHash(ctmbstr s)
{
    unsigned int hashval;

    for (hashval = 0; *s != '\0'; s++)
        hashval = *s + 31*hashval;

    return hashval % ELEMENT_HASH_SIZE;
}

static const Dict *tagsInstall(TidyDocImpl* doc, TidyTagImpl* tags, const Dict* old)
{
    DictHash *np;
    unsigned int hashval;

    if (old)
    {
        np = (DictHash *)TidyDocAlloc(doc, sizeof(*np));
        np->tag = old;

        hashval = tagsHash(old->name);
        np->next = tags->hashtab[hashval];
        tags->hashtab[hashval] = np;
    }

    return old;
}

static void tagsRemoveFromHash( TidyDocImpl* doc, TidyTagImpl* tags, ctmbstr s )
{
    unsigned int h = tagsHash(s);
    DictHash *p, *prev = NULL;
    for (p = tags->hashtab[h]; p && p->tag; p = p->next)
    {
        if (TY_(tmbstrcmp)(s, p->tag->name) == 0)
        {
            DictHash* next = p->next;
            if ( prev )
                prev->next = next;
            else
                tags->hashtab[h] = next;
            TidyDocFree(doc, p);
            return;
        }
        prev = p;
    }
}

static void tagsEmptyHash( TidyDocImpl* doc, TidyTagImpl* tags )
{
    unsigned int i;
    DictHash *prev, *next;

    for (i = 0; i < ELEMENT_HASH_SIZE; ++i)
    {
        prev = NULL;
        next = tags->hashtab[i];

        while(next)
        {
            prev = next->next;
            TidyDocFree(doc, next);
            next = prev;
        }

        tags->hashtab[i] = NULL;
    }
}

static const Dict* tagsLookup( TidyDocImpl* doc, TidyTagImpl* tags, ctmbstr s )
{
    const Dict *np;
    const DictHash* p;

    if (!s)
        return NULL;

    /* this breaks if declared elements get changed between two   */
    /* parser runs since Tidy would use the cached version rather */
    /* than the new one.                                          */
    /* However, as FreeDeclaredTags() correctly cleans the hash   */
    /* this should not be true anymore.                           */
    for (p = tags->hashtab[tagsHash(s)]; p && p->tag; p = p->next)
        if (TY_(tmbstrcmp)(s, p->tag->name) == 0)
            return p->tag;

    for (np = tag_defs + 1; np < tag_defs + N_TIDY_TAGS; ++np)
        if (TY_(tmbstrcmp)(s, np->name) == 0)
            return tagsInstall(doc, tags, np);

    for (np = tags->declared_tag_list; np; np = np->next)
        if (TY_(tmbstrcmp)(s, np->name) == 0)
            return tagsInstall(doc, tags, np);

    return NULL;
}

static Dict* NewDict( TidyDocImpl* doc, ctmbstr name )
{
    Dict *np = (Dict*) TidyDocAlloc( doc, sizeof(Dict) );
    np->id = TidyTag_UNKNOWN;
    np->name = name ? TY_(tmbstrdup)( doc->allocator, name ) : NULL;
    np->versions = VERS_UNKNOWN;
    np->attrvers = NULL;
    np->model = CM_UNKNOWN;
    np->parser = 0;
    np->chkattrs = 0;
    np->next = NULL;
    return np;
}

static void FreeDict( TidyDocImpl* doc, Dict *d )
{
    if ( d )
        TidyDocFree( doc, d->name );
    TidyDocFree( doc, d );
}

static void declare( TidyDocImpl* doc, TidyTagImpl* tags,
                     ctmbstr name, unsigned int versions, unsigned int model,
                     Parser *parser, CheckAttribs *chkattrs )
{
    if ( name )
    {
        Dict* np = (Dict*) tagsLookup( doc, tags, name );
        if ( np == NULL )
        {
            np = NewDict( doc, name );
            np->next = tags->declared_tag_list;
            tags->declared_tag_list = np;
        }

        /* Make sure we are not over-writing predefined tags */
        if ( np->id == TidyTag_UNKNOWN )
        {
          np->versions = versions;
          np->model   |= model;
          np->parser   = parser;
          np->chkattrs = chkattrs;
          np->attrvers = NULL;
        }
    }
}


/* Coordinates Config update and Tags data */
void TY_(DeclareUserTag)( TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name )
{
    UserTagType tagType;

    switch ( opt->id )
    {
        case TidyInlineTags:  tagType = tagtype_inline;              break;
        case TidyBlockTags:   tagType = tagtype_block;               break;
        case TidyEmptyTags:   tagType = tagtype_empty;               break;
        case TidyPreTags:     tagType = tagtype_pre;                 break;
        case TidyCustomTags:
        {
            switch (cfg( doc, TidyUseCustomTags ))
            {
                case TidyCustomBlocklevel: tagType = tagtype_block;  break;
                case TidyCustomEmpty:      tagType = tagtype_empty;  break;
                case TidyCustomInline:     tagType = tagtype_inline; break;
                case TidyCustomPre:        tagType = tagtype_pre;    break;
                default: TY_(ReportUnknownOption)( doc, opt->name ); return;
            }
        } break;
        default:
        TY_(ReportUnknownOption)( doc, opt->name );
        return;
    }

    TY_(DefineTag)( doc, tagType, name );
}


#if defined(ENABLE_DEBUG_LOG)
void ListElementsPerVersion( unsigned int vers, Bool has )
{
    unsigned int val, cnt, total, wrap = 10;
    const Dict *np = tag_defs + 1;
    const Dict *end = tag_defs + N_TIDY_TAGS;
    cnt = 0;
    total = 0;
    for ( ; np < end; np++) {
        val = (np->versions & vers);
        if (has) {
            if (val) {
                SPRTF("%s ",np->name);
                cnt++;
                total++;
            }
        } else {
            if (!val) {
                SPRTF("%s ",np->name);
                cnt++;
                total++;
            }
        }
        if (cnt == wrap) {
            SPRTF("\n");
            cnt = 0;
        }
    }
    if (cnt)
        SPRTF("\n");
    SPRTF("Listed total %u tags that %s version %u\n", total,
        (has ? "have" : "do not have"),
        vers );

}

void show_not_html5(void)
{
    SPRTF("List tags that do not have version HTML5 (HT50|XH50)\n"),
    ListElementsPerVersion( VERS_HTML5, no );
}
void show_have_html5(void)
{
    ListElementsPerVersion( VERS_HTML5, yes );
}

#endif /* defined(ENABLE_DEBUG_LOG) */

/* public interface for finding tag by name */
Bool TY_(FindTag)( TidyDocImpl* doc, Node *node )
{
    const Dict *np = NULL;

    if ( cfgBool(doc, TidyXmlTags) )
    {
        node->tag = doc->tags.xml_tags;
        return yes;
    }

    if ( node->element && (np = tagsLookup(doc, &doc->tags, node->element)) )
    {
        node->tag = np;
        return yes;
    }
    
    /* Add autonomous custom tag. This can be done in both HTML5 mode and
       earlier, although if it's earlier we will complain about it elsewhere. */
    if ( TY_(nodeIsAutonomousCustomTag)( doc, node) )
    {
        const TidyOptionImpl* opt = TY_(getOption)( TidyCustomTags );

        TY_(DeclareUserTag)( doc, opt, node->element );
        node->tag = tagsLookup(doc, &doc->tags, node->element);

        /* Output a message the first time we encounter an autonomous custom 
           tag. This applies despite the HTML5 mode. */
        TY_(Report)(doc, node, node, CUSTOM_TAG_DETECTED);

        return yes;
    }
    
    return no;
}

const Dict* TY_(LookupTagDef)( TidyTagId tid )
{
    const Dict *np;

    for (np = tag_defs + 1; np < tag_defs + N_TIDY_TAGS; ++np )
        if (np->id == tid)
            return np;

    return NULL;
}

Parser* TY_(FindParser)( TidyDocImpl* doc, Node *node )
{
    const Dict* np = tagsLookup( doc, &doc->tags, node->element );
    if ( np )
        return np->parser;
    return NULL;
}

void TY_(DefineTag)( TidyDocImpl* doc, UserTagType tagType, ctmbstr name )
{
    Parser* parser = 0;
    unsigned int cm = CM_UNKNOWN;
    unsigned int vers = VERS_PROPRIETARY;

    switch (tagType)
    {
    case tagtype_empty:
        cm = CM_EMPTY|CM_NO_INDENT|CM_NEW;
        parser = TY_(ParseBlock);
        break;

    case tagtype_inline:
        cm = CM_INLINE|CM_NO_INDENT|CM_NEW;
        parser = TY_(ParseInline);
        break;

    case tagtype_block:
        cm = CM_BLOCK|CM_NO_INDENT|CM_NEW;
        parser = TY_(ParseBlock);
        break;

    case tagtype_pre:
        cm = CM_BLOCK|CM_NO_INDENT|CM_NEW;
        parser = TY_(ParsePre);
        break;

    case tagtype_null:
        break;
    }
    if ( cm && parser )
        declare( doc, &doc->tags, name, vers, cm, parser, 0 );
}

TidyIterator   TY_(GetDeclaredTagList)( TidyDocImpl* doc )
{
    return (TidyIterator) doc->tags.declared_tag_list;
}

ctmbstr        TY_(GetNextDeclaredTag)( TidyDocImpl* ARG_UNUSED(doc),
                                        UserTagType tagType, TidyIterator* iter )
{
    ctmbstr name = NULL;
    Dict* curr;
    for ( curr = (Dict*) *iter; name == NULL && curr != NULL; curr = curr->next )
    {
        switch ( tagType )
        {
        case tagtype_empty:
            if ( (curr->model & CM_EMPTY) != 0 )
                name = curr->name;
            break;

        case tagtype_inline:
            if ( (curr->model & CM_INLINE) != 0 )
                name = curr->name;
            break;

        case tagtype_block:
            if ( (curr->model & CM_BLOCK) != 0 &&
                 curr->parser == TY_(ParseBlock) )
                name = curr->name;
            break;

        case tagtype_pre:
            if ( (curr->model & CM_BLOCK) != 0 &&
                 curr->parser == TY_(ParsePre) )
                name = curr->name;
            break;

        case tagtype_null:
            break;
        }
    }
    *iter = (TidyIterator) curr;
    return name;
}

void TY_(InitTags)( TidyDocImpl* doc )
{
    Dict* xml;
    TidyTagImpl* tags = &doc->tags;

    TidyClearMemory( tags, sizeof(TidyTagImpl) );

    /* create dummy entry for all xml tags */
    xml =  NewDict( doc, NULL );
    xml->versions = VERS_XML;
    xml->model = CM_BLOCK;
    xml->parser = 0;
    xml->chkattrs = 0;
    xml->attrvers = NULL;
    tags->xml_tags = xml;
}

/* By default, zap all of them.  But allow
** an single type to be specified.
*/
void TY_(FreeDeclaredTags)( TidyDocImpl* doc, UserTagType tagType )
{
    TidyTagImpl* tags = &doc->tags;
    Dict *curr, *next = NULL, *prev = NULL;

    for ( curr=tags->declared_tag_list; curr; curr = next )
    {
        Bool deleteIt = yes;
        next = curr->next;
        switch ( tagType )
        {
        case tagtype_empty:
            deleteIt = ( curr->model & CM_EMPTY ) != 0;
            break;

        case tagtype_inline:
            deleteIt = ( curr->model & CM_INLINE ) != 0;
            break;

        case tagtype_block:
            deleteIt = ( (curr->model & CM_BLOCK) != 0 &&
                         curr->parser == TY_(ParseBlock) );
            break;

        case tagtype_pre:
            deleteIt = ( (curr->model & CM_BLOCK) != 0 &&
                         curr->parser == TY_(ParsePre) );
            break;

        case tagtype_null:
            break;
        }

        if ( deleteIt )
        {
          tagsRemoveFromHash( doc, &doc->tags, curr->name );
          FreeDict( doc, curr );
          if ( prev )
            prev->next = next;
          else
            tags->declared_tag_list = next;
        }
        else
          prev = curr;
    }
}

/*\
 * Issue #167 & #169
 * Tidy defaults to HTML5 mode
 * If the <!DOCTYPE ...> is found to NOT be HTML5,
 * then adjust tags to HTML4 mode
 *
 * NOTE: For each change added to here, there must 
 * be a RESET added in TY_(ResetTags) below!
\*/
void TY_(AdjustTags)( TidyDocImpl *doc )
{
    Dict *np = (Dict *)TY_(LookupTagDef)( TidyTag_A );
    TidyTagImpl* tags = &doc->tags;
    if (np) 
    {
        np->parser = TY_(ParseInline);
        np->model  = CM_INLINE;
    }

/*\
 * Issue #196
 * TidyTag_CAPTION allows %flow; in HTML5,
 * but only %inline; in HTML4
\*/
    np = (Dict *)TY_(LookupTagDef)( TidyTag_CAPTION );
    if (np)
    {
        np->parser = TY_(ParseInline);
    }

/*\
 * Issue #232
 * TidyTag_OBJECT not in head in HTML5,
 * but still allowed in HTML4
\*/
    np = (Dict *)TY_(LookupTagDef)( TidyTag_OBJECT );
    if (np)
    {
        np->model |= CM_HEAD; /* add back allowed in head */
    }

/*\
 * Issue #461
 * TidyTag_BUTTON is a block in HTML4,
 * whereas it is inline in HTML5
\*/
    np = (Dict *)TY_(LookupTagDef)(TidyTag_BUTTON);
    if (np)
    {
        np->parser = TY_(ParseBlock);
    }

    tagsEmptyHash(doc, tags); /* not sure this is really required, but to be sure */
    doc->HTML5Mode = no;   /* set *NOT* HTML5 mode */

}

Bool TY_(IsHTML5Mode)( TidyDocImpl *doc )
{
    return doc->HTML5Mode;
}


/*\
 * Issue #285
 * Reset the table to default HTML5 mode.
 * For every change made in the above AdjustTags,
 * the equivalent reset must be added here.
\*/
void TY_(ResetTags)( TidyDocImpl *doc )
{
    Dict *np = (Dict *)TY_(LookupTagDef)( TidyTag_A );
    TidyTagImpl* tags = &doc->tags;
    if (np) 
    {
        np->parser = TY_(ParseBlock);
        np->model  = (CM_INLINE|CM_BLOCK|CM_MIXED);
    }
    np = (Dict *)TY_(LookupTagDef)( TidyTag_CAPTION );
    if (np)
    {
        np->parser = TY_(ParseBlock);
    }

    np = (Dict *)TY_(LookupTagDef)( TidyTag_OBJECT );
    if (np)
    {
        np->model = (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM); /* reset */
    }
    /*\
     * Issue #461
     * TidyTag_BUTTON reset to inline in HTML5
    \*/
    np = (Dict *)TY_(LookupTagDef)(TidyTag_BUTTON);
    if (np)
    {
        np->parser = TY_(ParseInline);
    }

    tagsEmptyHash( doc, tags ); /* not sure this is really required, but to be sure */
    doc->HTML5Mode = yes;   /* set HTML5 mode */
}

void TY_(FreeTags)( TidyDocImpl* doc )
{
    TidyTagImpl* tags = &doc->tags;

    tagsEmptyHash( doc, tags );
    TY_(FreeDeclaredTags)( doc, tagtype_null );
    FreeDict( doc, tags->xml_tags );

    /* get rid of dangling tag references */
    TidyClearMemory( tags, sizeof(TidyTagImpl) );

}


/* default method for checking an element's attributes */
void TY_(CheckAttributes)( TidyDocImpl* doc, Node *node )
{
    AttVal *next, *attval = node->attributes;
    while (attval)
    {
        next = attval->next;
        TY_(CheckAttribute)( doc, node, attval );
        attval = next;
    }
}

/* methods for checking attributes for specific elements */

void CheckIMG( TidyDocImpl* doc, Node *node )
{
    Bool HasAlt = TY_(AttrGetById)(node, TidyAttr_ALT) != NULL;
    Bool HasSrc = TY_(AttrGetById)(node, TidyAttr_SRC) != NULL;
    Bool HasUseMap = TY_(AttrGetById)(node, TidyAttr_USEMAP) != NULL;
    Bool HasIsMap = TY_(AttrGetById)(node, TidyAttr_ISMAP) != NULL;
    Bool HasDataFld = TY_(AttrGetById)(node, TidyAttr_DATAFLD) != NULL;

    TY_(CheckAttributes)(doc, node);

    if ( !HasAlt )
    {
        ctmbstr alttext = cfgStr(doc, TidyAltText);
        if ( ( cfg(doc, TidyAccessibilityCheckLevel) == 0 ) && ( !alttext ) )
        {
            doc->badAccess |= BA_MISSING_IMAGE_ALT;
            TY_(ReportMissingAttr)( doc, node, "alt" );
        }

        if ( alttext ) {
            AttVal *attval = TY_(AddAttribute)( doc, node, "alt", alttext );
            TY_(ReportAttrError)( doc, node, attval, INSERTING_AUTO_ATTRIBUTE);
        }
    }

    if ( !HasSrc && !HasDataFld )
        TY_(ReportMissingAttr)( doc, node, "src" );

    if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
    {
        if ( HasIsMap && !HasUseMap )
        {
            TY_(ReportAttrError)( doc, node, NULL, MISSING_IMAGEMAP);
            doc->badAccess |= BA_MISSING_IMAGE_MAP;
        }
    }
}

void CheckCaption(TidyDocImpl* doc, Node *node)
{
    AttVal *attval;

    TY_(CheckAttributes)(doc, node);

    attval = TY_(AttrGetById)(node, TidyAttr_ALIGN);

    if (!AttrHasValue(attval))
        return;

    if (AttrValueIs(attval, "left") || AttrValueIs(attval, "right"))
        TY_(ConstrainVersion)(doc, VERS_HTML40_LOOSE);
    else if (AttrValueIs(attval, "top") || AttrValueIs(attval, "bottom"))
        TY_(ConstrainVersion)(doc, ~(VERS_HTML20|VERS_HTML32));
    else
        TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE);
}

void CheckHTML( TidyDocImpl* doc, Node *node )
{
    TY_(CheckAttributes)(doc, node);
}

void CheckAREA( TidyDocImpl* doc, Node *node )
{
    Bool HasAlt = TY_(AttrGetById)(node, TidyAttr_ALT) != NULL;
    Bool HasHref = TY_(AttrGetById)(node, TidyAttr_HREF) != NULL;
    Bool HasNohref = TY_(AttrGetById)(node, TidyAttr_NOHREF) != NULL;

    TY_(CheckAttributes)(doc, node);

    if ( !HasAlt )
    {
        if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
        {
            doc->badAccess |= BA_MISSING_LINK_ALT;
            TY_(ReportMissingAttr)( doc, node, "alt" );
        }
    }

    if ( !HasHref && !HasNohref )
        TY_(ReportMissingAttr)( doc, node, "href" );
}

void CheckTABLE( TidyDocImpl* doc, Node *node )
{
    AttVal* attval;
    Bool HasSummary = (TY_(AttrGetById)(node, TidyAttr_SUMMARY) != NULL) ? yes : no;
    unsigned int vers = TY_(HTMLVersion)(doc);  /* Issue #377 - Also applies to XHTML5 */
    Bool isHTML5 = ((vers == HT50)||(vers == XH50)) ? yes : no;

    TY_(CheckAttributes)(doc, node);

    /* Issue #210 - a missing summary attribute is bad accessibility, no matter
       what HTML version is involved; a document without is valid 
       EXCEPT for HTML5, when to have a summary is wrong */
    if (cfg(doc, TidyAccessibilityCheckLevel) == 0)
    {
        if (HasSummary && isHTML5)
        {
            /* #210 - has summary, and is HTML5, then report obsolete */
            TY_(Report)(doc, node, node, BAD_SUMMARY_HTML5);
        } 
        else if (!HasSummary && !isHTML5) 
        {
            /* #210 - No summary, and NOT HTML5, then report as before */
            doc->badAccess |= BA_MISSING_SUMMARY;
            TY_(ReportMissingAttr)( doc, node, "summary");
        }
    }

    /* convert <table border> to <table border="1"> */
    if ( cfgBool(doc, TidyXmlOut) && (attval = TY_(AttrGetById)(node, TidyAttr_BORDER)) )
    {
        if (attval->value == NULL)
            attval->value = TY_(tmbstrdup)(doc->allocator, "1");
    }
}

/* report missing href attribute; report missing rel attribute */
void CheckLINK( TidyDocImpl* doc, Node *node )
{
    Bool HasHref = TY_(AttrGetById)(node, TidyAttr_HREF) != NULL;
    Bool HasRel = TY_(AttrGetById)(node, TidyAttr_REL) != NULL;
    Bool HasItemprop = TY_(AttrGetById)(node, TidyAttr_ITEMPROP) != NULL;

    if (!HasHref)
    {
      TY_(ReportMissingAttr)( doc, node, "href" );
    }

    if (!HasItemprop && !HasRel)
    {
      TY_(ReportMissingAttr)( doc, node, "rel" );
    }
}

Bool TY_(nodeIsText)( Node* node )
{
  return ( node && node->type == TextNode );
}

Bool TY_(nodeHasText)( TidyDocImpl* doc, Node* node )
{
  if ( doc && node )
  {
    unsigned int ix;
    Lexer* lexer = doc->lexer;
    for ( ix = node->start; ix < node->end; ++ix )
    {
        /* whitespace */
        if ( !TY_(IsWhite)( lexer->lexbuf[ix] ) )
            return yes;
    }
  }
  return no;
}

Bool TY_(nodeIsElement)( Node* node )
{
  return ( node &&
           (node->type == StartTag || node->type == StartEndTag) );
}

Bool TY_(elementIsAutonomousCustomFormat)( ctmbstr element )
{
    if ( element )
    {
        const char *ptr = strchr(element, '-');

        /* Tag must contain hyphen not in first character. */
        if ( ptr && (ptr - element > 0) )
        {
            return yes;
        }
    }

    return no;
}

Bool TY_(nodeIsAutonomousCustomFormat)( Node* node )
{
    if ( node->element )
        return TY_(elementIsAutonomousCustomFormat)( node->element );

    return no;
}

Bool TY_(nodeIsAutonomousCustomTag)( TidyDocImpl* doc, Node* node )
{
    return TY_(nodeIsAutonomousCustomFormat)( node )
            && ( cfg( doc, TidyUseCustomTags ) != TidyCustomNo );
}



/* True if any of the bits requested are set.
*/
Bool TY_(nodeHasCM)( Node* node, unsigned int contentModel )
{
  return ( node && node->tag &&
           (node->tag->model & contentModel) != 0 );
}

Bool TY_(nodeCMIsBlock)( Node* node )
{
  return TY_(nodeHasCM)( node, CM_BLOCK );
}
Bool TY_(nodeCMIsInline)( Node* node )
{
  return TY_(nodeHasCM)( node, CM_INLINE );
}
Bool TY_(nodeCMIsEmpty)( Node* node )
{
  return TY_(nodeHasCM)( node, CM_EMPTY );
}

Bool TY_(nodeIsHeader)( Node* node )
{
    TidyTagId tid = TagId( node  );
    return ( tid && (
             tid == TidyTag_H1 ||
             tid == TidyTag_H2 ||
             tid == TidyTag_H3 ||
             tid == TidyTag_H4 ||
             tid == TidyTag_H5 ||
             tid == TidyTag_H6 ));
}

unsigned int TY_(nodeHeaderLevel)( Node* node )
{
    TidyTagId tid = TagId( node  );
    switch ( tid )
    {
    case TidyTag_H1:
        return 1;
    case TidyTag_H2:
        return 2;
    case TidyTag_H3:
        return 3;
    case TidyTag_H4:
        return 4;
    case TidyTag_H5:
        return 5;
    case TidyTag_H6:
        return 6;
    default:
    {
        /* fall through */
    }
    }
    return 0;
}

/* [i_a] generic node tree traversal; see also <tidy-int.h> */
NodeTraversalSignal TY_(TraverseNodeTree)(TidyDocImpl* doc, Node* node, NodeTraversalCallBack *cb, void *propagate )
{
    while (node)
    {
        NodeTraversalSignal s = (*cb)(doc, node, propagate);

        if (node->content && (s == ContinueTraversal || s == SkipSiblings))
        {
            s = TY_(TraverseNodeTree)(doc, node->content, cb, propagate);
        }

        switch (s)
        {
        case ExitTraversal:
            return ExitTraversal;

        case VisitParent:
            node = node->parent;
            continue;

        case SkipSiblings:
        case SkipChildrenAndSiblings:
            return ContinueTraversal;

        default:
            node = node->next;
            break;
        }
    }
    return ContinueTraversal;
}



/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* tidylib.c -- internal library definitions

  (c) 1998-2008 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Defines HTML Tidy API implemented by tidy library.

  Very rough initial cut for discussion purposes.

  Public interface is const-correct and doesn't explicitly depend
  on any globals.  Thus, thread-safety may be introduced w/out
  changing the interface.

  Looking ahead to a C++ wrapper, C functions always pass
  this-equivalent as 1st arg.

  Created 2001-05-20 by Charles Reitzel

*/

#include <errno.h>

/* #include "tidy-int.h" */
/* #include "parser.h" */
/* #include "clean.h" */
/* #include "gdoc.h" */
/* #include "config.h" */
/* #include "message.h" */
/* #include "messageobj.h" */
/* #include "pprint.h" */
/* #include "entities.h" */
/* #include "tmbstr.h" */
/* #include "utf8.h" */
/* #include "mappedio.h" */
/* #include "language.h" */
/* #include "attrs.h" */
/* #include "sprtf.h" */
#if SUPPORT_LOCALIZATIONS
/* #  include "stdlib.h" */
/* #  include "locale.h" */
#endif

/* Create/Destroy a Tidy "document" object */
static TidyDocImpl* tidyDocCreate( TidyAllocator *allocator );
static void         tidyDocRelease( TidyDocImpl* impl );

static int          tidyDocStatus( TidyDocImpl* impl );

/* Parse Markup */
static int          tidyDocParseFile( TidyDocImpl* impl, ctmbstr htmlfil );
static int          tidyDocParseStdin( TidyDocImpl* impl );
static int          tidyDocParseString( TidyDocImpl* impl, ctmbstr content );
static int          tidyDocParseBuffer( TidyDocImpl* impl, TidyBuffer* inbuf );
static int          tidyDocParseSource( TidyDocImpl* impl, TidyInputSource* docIn );


/* Execute post-parse diagnostics and cleanup.
** Note, the order is important.  You will get different
** results from the diagnostics depending on if they are run
** pre-or-post repair.
*/
static int          tidyDocRunDiagnostics( TidyDocImpl* doc );
static void         tidyDocReportDoctype( TidyDocImpl* doc );
static int          tidyDocCleanAndRepair( TidyDocImpl* doc );


/* Save cleaned up file to file/buffer/sink */
static int          tidyDocSaveFile( TidyDocImpl* impl, ctmbstr htmlfil );
static int          tidyDocSaveStdout( TidyDocImpl* impl );
static int          tidyDocSaveString( TidyDocImpl* impl, tmbstr buffer, unsigned int* buflen );
static int          tidyDocSaveBuffer( TidyDocImpl* impl, TidyBuffer* outbuf );
static int          tidyDocSaveSink( TidyDocImpl* impl, TidyOutputSink* docOut );
static int          tidyDocSaveStream( TidyDocImpl* impl, StreamOut* out );


/* Tidy public interface
**
** Most functions return an integer:
**
** 0    -> SUCCESS
** >0   -> WARNING
** <0   -> ERROR
**
*/

TidyDoc TIDY_CALL       tidyCreate(void)
{
  TidyDocImpl* impl = tidyDocCreate( &TY_(g_default_allocator) );
  return tidyImplToDoc( impl );
}

TidyDoc TIDY_CALL tidyCreateWithAllocator( TidyAllocator *allocator )
{
  TidyDocImpl* impl = tidyDocCreate( allocator );
  return tidyImplToDoc( impl );
}

void TIDY_CALL          tidyRelease( TidyDoc tdoc )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  tidyDocRelease( impl );
}

TidyDocImpl* tidyDocCreate( TidyAllocator *allocator )
{
    TidyDocImpl* doc = (TidyDocImpl*)TidyAlloc( allocator, sizeof(TidyDocImpl) );
    TidyClearMemory( doc, sizeof(*doc) );
    doc->allocator = allocator;

    TY_(InitMap)();
    TY_(InitTags)( doc );
    TY_(InitAttrs)( doc );
    TY_(InitConfig)( doc );
    TY_(InitPrintBuf)( doc );

    /* Set the locale for tidy's output. This both configures
    ** LibTidy to use the environment's locale as well as the
    ** standard library.
    */
#if SUPPORT_LOCALIZATIONS
    if ( TY_(tidyGetLanguageSetByUser)() == no )
    {
        if( ! TY_(tidySetLanguage)( getenv( "LC_MESSAGES" ) ) )
        {
            if( ! TY_(tidySetLanguage)( getenv( "LANG" ) ) )
            {
                /*\
                *  Is. #770 #783 #780 #790 and maybe others -
                *  TY_(tidySetLanguage)( setlocale( LC_ALL, "" ) );
                *  this seems a 'bad' choice!
               \*/
            }
        }
    }
#endif

    /* By default, wire tidy messages to standard error.
    ** Document input will be set by parsing routines.
    ** Document output will be set by pretty print routines.
    ** Config input will be set by config parsing routines.
    ** But we need to start off with a way to report errors.
    */
    doc->errout = TY_(StdErrOutput)();
    return doc;
}

void          tidyDocRelease( TidyDocImpl* doc )
{
    /* doc in/out opened and closed by parse/print routines */
    if ( doc )
    {
        assert( doc->docIn == NULL );
        assert( doc->docOut == NULL );

        TY_(ReleaseStreamOut)( doc, doc->errout );
        doc->errout = NULL;

        TY_(FreePrintBuf)( doc );
        TY_(FreeNode)(doc, &doc->root);
        TidyClearMemory(&doc->root, sizeof(Node));

        if (doc->givenDoctype)
            TidyDocFree(doc, doc->givenDoctype);

        TY_(FreeConfig)( doc );
        TY_(FreeAttrTable)( doc );
        TY_(FreeAttrPriorityList)( doc );
        TY_(FreeMutedMessageList( doc ));
        TY_(FreeTags)( doc );
        /*\ 
         *  Issue #186 - Now FreeNode depend on the doctype, so the lexer is needed
         *  to determine which hash is to be used, so free it last.
        \*/
        TY_(FreeLexer)( doc );
        TidyDocFree( doc, doc );
    }
}

/* Let application store a chunk of data w/ each Tidy tdocance.
** Useful for callbacks.
*/
void TIDY_CALL        tidySetAppData( TidyDoc tdoc, void* appData )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
    impl->appData = appData;
}
void* TIDY_CALL       tidyGetAppData( TidyDoc tdoc )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
    return impl->appData;
  return NULL;
}

ctmbstr TIDY_CALL     tidyReleaseDate(void)
{
    return TY_(ReleaseDate)();
}

ctmbstr TIDY_CALL     tidyLibraryVersion(void)
{
    return TY_(tidyLibraryVersion)();
}

ctmbstr TIDY_CALL     tidyPlatform(void)
{
#ifdef PLATFORM_NAME
    return PLATFORM_NAME;
#else
    return NULL;
#endif
}


/* Get/set configuration options
*/
Bool TIDY_CALL     tidySetOptionCallback( TidyDoc tdoc, TidyOptCallback pOptCallback )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
  {
    impl->pOptCallback = pOptCallback;
    return yes;
  }
  return no;
}

Bool TIDY_CALL     tidySetConfigCallback(TidyDoc tdoc, TidyConfigCallback pConfigCallback)
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
  {
    impl->pConfigCallback = pConfigCallback;
    return yes;
  }
  return no;
}

Bool TIDY_CALL    tidySetConfigChangeCallback(TidyDoc tdoc, TidyConfigChangeCallback pCallback)
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
  {
    impl->pConfigChangeCallback = pCallback;
    return yes;
  }
  return no;
}



int TIDY_CALL     tidyLoadConfig( TidyDoc tdoc, ctmbstr cfgfil )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(ParseConfigFile)( impl, cfgfil );
    return -EINVAL;
}

int TIDY_CALL     tidyLoadConfigEnc( TidyDoc tdoc, ctmbstr cfgfil, ctmbstr charenc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(ParseConfigFileEnc)( impl, cfgfil, charenc );
    return -EINVAL;
}

int TIDY_CALL         tidySetCharEncoding( TidyDoc tdoc, ctmbstr encnam )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        int enc = TY_(CharEncodingId)( impl, encnam );
        if ( enc >= 0 && TY_(AdjustCharEncoding)(impl, enc) )
            return 0;

        TY_(ReportBadArgument)( impl, "char-encoding" );
    }
    return -EINVAL;
}

int TIDY_CALL           tidySetInCharEncoding( TidyDoc tdoc, ctmbstr encnam )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        int enc = TY_(CharEncodingId)( impl, encnam );
        if ( enc >= 0 && TY_(SetOptionInt)( impl, TidyInCharEncoding, enc ) )
            return 0;

        TY_(ReportBadArgument)( impl, "in-char-encoding" );
    }
    return -EINVAL;
}

int TIDY_CALL           tidySetOutCharEncoding( TidyDoc tdoc, ctmbstr encnam )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        int enc = TY_(CharEncodingId)( impl, encnam );
        if ( enc >= 0 && TY_(SetOptionInt)( impl, TidyOutCharEncoding, enc ) )
            return 0;

        TY_(ReportBadArgument)( impl, "out-char-encoding" );
    }
    return -EINVAL;
}

TidyOptionId TIDY_CALL tidyOptGetIdForName( ctmbstr optnam )
{
    const TidyOptionImpl* option = TY_(lookupOption)( optnam );
    if ( option )
        return option->id;
    return N_TIDY_OPTIONS;  /* Error */
}

TidyIterator TIDY_CALL  tidyGetOptionList( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(getOptionList)( impl );
    return (TidyIterator) -1;
}

TidyOption TIDY_CALL    tidyGetNextOption( TidyDoc tdoc, TidyIterator* pos )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    const TidyOptionImpl* option = NULL;
    if ( impl )
        option = TY_(getNextOption)( impl, pos );
    else if ( pos )
        *pos = 0;
    return tidyImplToOption( option );
}


TidyOption TIDY_CALL    tidyGetOption( TidyDoc ARG_UNUSED(tdoc), TidyOptionId optId )
{
    const TidyOptionImpl* option = TY_(getOption)( optId );
    return tidyImplToOption( option );
}
TidyOption TIDY_CALL    tidyGetOptionByName( TidyDoc ARG_UNUSED(doc), ctmbstr optnam )
{
    const TidyOptionImpl* option = TY_(lookupOption)( optnam );
    return tidyImplToOption( option );
}

TidyOptionId TIDY_CALL  tidyOptGetId( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option )
        return option->id;
    return N_TIDY_OPTIONS;
}
ctmbstr TIDY_CALL       tidyOptGetName( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option )
        return option->name;
    return NULL;
}
TidyOptionType TIDY_CALL tidyOptGetType( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option )
        return option->type;
    return (TidyOptionType) -1;
}
Bool TIDY_CALL           tidyOptionIsList( TidyOption opt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( opt );
    if ( option )
        return TY_(getOptionIsList)( option->id );
    return no;
}
TidyConfigCategory TIDY_CALL tidyOptGetCategory( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option )
        return option->category;
    return (TidyConfigCategory) -1;
}
ctmbstr TIDY_CALL       tidyOptGetDefault( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    /* Special case for TidyDoctype, because it is declared as string */
    if ( option && option->id == TidyDoctype )
    {
        const TidyOptionImpl* newopt = TY_(getOption)( TidyDoctypeMode );
        return TY_(GetPickListLabelForPick)( TidyDoctypeMode, newopt->dflt );
    }
    if ( option && option->type == TidyString )
        return option->pdflt; /* Issue #306 - fix an old typo hidden by a cast! */
    return NULL;
}
unsigned int TIDY_CALL          tidyOptGetDefaultInt( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option && option->type != TidyString )
        return option->dflt;

    /* Special case for TidyDoctype, because it has a picklist */
    if ( option->id == TidyDoctype )
    {
        const TidyOptionImpl* newopt = TY_(getOption)( TidyDoctypeMode );
        return newopt->dflt;
    }

    return ~0U;
}
Bool TIDY_CALL          tidyOptGetDefaultBool( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option && option->type != TidyString )
        return ( option->dflt ? yes : no );
    return no;
}
Bool TIDY_CALL          tidyOptIsReadOnly( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option  )
        return ( option->parser == NULL );
    return yes;
}


TidyIterator TIDY_CALL  tidyOptGetPickList( TidyOption topt )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option )
      return TY_(getOptionPickList)( option );
    return (TidyIterator) -1;
}
ctmbstr TIDY_CALL       tidyOptGetNextPick( TidyOption topt, TidyIterator* pos )
{
    const TidyOptionImpl* option = tidyOptionToImpl( topt );
    if ( option )
        return TY_(getNextOptionPick)( option, pos );
    return NULL;
}


ctmbstr TIDY_CALL       tidyOptGetValue( TidyDoc tdoc, TidyOptionId optId )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    ctmbstr optval = NULL;
    if ( impl )
    {
        if ( optId == TidyDoctype )
        {
            /* Special case for TidyDoctype, because it has a picklist and is a string. */
            unsigned int pick = tidyOptGetInt( tdoc, TidyDoctypeMode );
            if ( pick != TidyDoctypeUser )
            {
                optval = TY_(GetPickListLabelForPick)( TidyDoctypeMode, pick );
            } else {
                optval = cfgStr( impl, optId );
            }
        } else {
            /* Standard case. */
            optval = cfgStr( impl, optId );
        }
    }
    return optval;
}
Bool TIDY_CALL        tidyOptSetValue( TidyDoc tdoc, TidyOptionId optId, ctmbstr val )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
    return TY_(ParseConfigValue)( impl, optId, val );
  return no;
}
Bool TIDY_CALL        tidyOptParseValue( TidyDoc tdoc, ctmbstr optnam, ctmbstr val )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
    return TY_(ParseConfigOption)( impl, optnam, val );
  return no;
}

unsigned int TIDY_CALL        tidyOptGetInt( TidyDoc tdoc, TidyOptionId optId )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    unsigned int opti = 0;
    if ( impl )
    {
        /* Special case for TidyDoctype, because it has a picklist */
        if ( optId == TidyDoctype )
            opti = cfg( impl, TidyDoctypeMode);
        else
            opti = cfg( impl, optId );
    }
    return opti;
}

Bool TIDY_CALL        tidyOptSetInt( TidyDoc tdoc, TidyOptionId optId, unsigned int val )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        /* Special case for TidyDoctype, because it has a picklist */
        if ( optId == TidyDoctype )
            return TY_(SetOptionInt)( impl, TidyDoctypeMode, val );
        else
            return TY_(SetOptionInt)( impl, optId, val );
    }
    return no;
}

Bool TIDY_CALL         tidyOptGetBool( TidyDoc tdoc, TidyOptionId optId )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    Bool optb = no;
    if ( impl )
    {
        const TidyOptionImpl* option = TY_(getOption)( optId );
        if ( option )
        {
            optb = cfgBool( impl, optId );
        }
    }
    return optb;
}

Bool TIDY_CALL        tidyOptSetBool( TidyDoc tdoc, TidyOptionId optId, Bool val )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(SetOptionBool)( impl, optId, val );
    return no;
}

ctmbstr TIDY_CALL       tidyOptGetEncName( TidyDoc tdoc, TidyOptionId optId )
{
  unsigned int enc = tidyOptGetInt( tdoc, optId );
  return TY_(CharEncodingOptName)( enc );
}

ctmbstr TIDY_CALL       tidyOptGetCurrPick( TidyDoc tdoc, TidyOptionId optId )
{
    unsigned int pick = tidyOptGetInt( tdoc, optId );
    return TY_(GetPickListLabelForPick)( optId, pick );
}


TidyIterator TIDY_CALL tidyOptGetDeclTagList( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    TidyIterator declIter = 0;
    if ( impl )
        declIter = TY_(GetDeclaredTagList)( impl );
    return declIter;
}

ctmbstr TIDY_CALL       tidyOptGetNextDeclTag( TidyDoc tdoc, TidyOptionId optId,
                                     TidyIterator* iter )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    ctmbstr tagnam = NULL;
    if ( impl )
    {
        UserTagType tagtyp = tagtype_null;
        if ( optId == TidyInlineTags )
            tagtyp = tagtype_inline;
        else if ( optId == TidyBlockTags )
            tagtyp = tagtype_block;
        else if ( optId == TidyEmptyTags )
            tagtyp = tagtype_empty;
        else if ( optId == TidyPreTags )
            tagtyp = tagtype_pre;
        if ( tagtyp != tagtype_null )
            tagnam = TY_(GetNextDeclaredTag)( impl, tagtyp, iter );
    }
    return tagnam;
}

TidyIterator TIDY_CALL tidyOptGetPriorityAttrList( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(getPriorityAttrList)( impl );
    return (TidyIterator) -1;
}

ctmbstr TIDY_CALL      tidyOptGetNextPriorityAttr(TidyDoc tdoc, TidyIterator* iter )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    ctmbstr result = NULL;
    if ( impl )
        result = TY_(getNextPriorityAttr)( impl, iter );
    else if ( iter )
        *iter = 0;
    return result;
}

TidyIterator TIDY_CALL tidyOptGetMutedMessageList( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(getMutedMessageList)( impl );
    return (TidyIterator) -1;
}

ctmbstr TIDY_CALL      tidyOptGetNextMutedMessage(TidyDoc tdoc, TidyIterator* iter )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    ctmbstr result = NULL;
    if ( impl )
        result = TY_(getNextMutedMessage)( impl, iter );
    else if ( iter )
        *iter = 0;
    return result;
}

ctmbstr TIDY_CALL tidyOptGetDoc( TidyDoc ARG_UNUSED(tdoc), TidyOption opt )
{
    const TidyOptionId optId = tidyOptGetId( opt );
    return tidyLocalizedString(optId);
}

#if SUPPORT_CONSOLE_APP
/* TODO - GROUP ALL CONSOLE-ONLY FUNCTIONS */
TidyIterator TIDY_CALL tidyOptGetDocLinksList( TidyDoc ARG_UNUSED(tdoc), TidyOption opt )
{
    const TidyOptionId optId = tidyOptGetId( opt );
    const TidyOptionDoc* docDesc = TY_(OptGetDocDesc)( optId );
    if (docDesc && docDesc->links)
        return (TidyIterator)docDesc->links;
    return (TidyIterator)NULL;
}
#endif /* SUPPORT_CONSOLE_APP */

TidyOption TIDY_CALL tidyOptGetNextDocLinks( TidyDoc tdoc, TidyIterator* pos )
{
    const TidyOptionId* curr = (const TidyOptionId *)*pos;
    TidyOption opt;

    if (*curr == TidyUnknownOption)
    {
        *pos = (TidyIterator)NULL;
        return (TidyOption)0;
    }
    opt = tidyGetOption(tdoc, *curr);
    curr++;
    *pos = (*curr == TidyUnknownOption ) ?
        (TidyIterator)NULL:(TidyIterator)curr;
    return opt;
}

int TIDY_CALL tidyOptSaveFile( TidyDoc tdoc, ctmbstr cfgfil )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(SaveConfigFile)( impl, cfgfil );
    return -EINVAL;
}

int TIDY_CALL tidyOptSaveSink( TidyDoc tdoc, TidyOutputSink* sink )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(SaveConfigSink)( impl, sink );
    return -EINVAL;
}

Bool TIDY_CALL tidyOptSnapshot( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        TY_(TakeConfigSnapshot)( impl );
        return yes;
    }
    return no;
}
Bool TIDY_CALL tidyOptResetToSnapshot( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        TY_(ResetConfigToSnapshot)( impl );
        return yes;
    }
    return no;
}
Bool TIDY_CALL tidyOptResetAllToDefault( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        TY_(ResetConfigToDefault)( impl );
        return yes;
    }
    return no;
}

Bool TIDY_CALL tidyOptResetToDefault( TidyDoc tdoc, TidyOptionId optId )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(ResetOptionToDefault)( impl, optId );
    return no;
}

Bool TIDY_CALL tidyOptDiffThanDefault( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(ConfigDiffThanDefault)( impl );
    return no;
}
Bool TIDY_CALL          tidyOptDiffThanSnapshot( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        return TY_(ConfigDiffThanSnapshot)( impl );
    return no;
}

Bool TIDY_CALL tidyOptCopyConfig( TidyDoc to, TidyDoc from )
{
    TidyDocImpl* docTo = tidyDocToImpl( to );
    TidyDocImpl* docFrom = tidyDocToImpl( from );
    if ( docTo && docFrom )
    {
        TY_(CopyConfig)( docTo, docFrom );
        return yes;
    }
    return no;
}


/* I/O and Message handling interface
**
** By default, Tidy will define, create and use instance of input and output 
** handlers for standard C buffered I/O (i.e. FILE* stdin, FILE* stdout and
** FILE* stderr for content input, content output and diagnostic output,
** respectively.  A FILE* cfgFile input handler will be used for config files.
** Command line options will just be set directly.
*/

void TIDY_CALL tidySetEmacsFile( TidyDoc tdoc, ctmbstr filePath )
{
    tidyOptSetValue( tdoc, TidyEmacsFile, filePath );
}

ctmbstr TIDY_CALL tidyGetEmacsFile( TidyDoc tdoc )
{
    return tidyOptGetValue( tdoc, TidyEmacsFile );
}


/* Use TidyReportFilter to filter messages by diagnostic level:
** info, warning, etc.  Just set diagnostic output
** handler to redirect all diagnostics output.  Return true
** to proceed with output, false to cancel.
*/
Bool TIDY_CALL tidySetReportFilter( TidyDoc tdoc, TidyReportFilter filt )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
  {
    impl->reportFilter = filt;
    return yes;
  }
  return no;
}

/* tidySetReportCallback functions similar to TidyReportFilter, but provides the
 * string version of the internal enum name so that LibTidy users can use
** the string as a lookup key for providing their own error localizations.
** See the string key definitions in tidyenum.h.
*/
Bool TIDY_CALL tidySetReportCallback( TidyDoc tdoc, TidyReportCallback filt )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  if ( impl )
  {
    impl->reportCallback = filt;
    return yes;
  }
  return no;
}

Bool TIDY_CALL tidySetMessageCallback( TidyDoc tdoc, TidyMessageCallback filt )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        impl->messageCallback = filt;
        return yes;
    }
    return no;
}

TidyDoc TIDY_CALL tidyGetMessageDoc( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    TidyDocImpl* doc = TY_(getMessageDoc)(*message);
    return tidyImplToDoc(doc);
}

unsigned int TIDY_CALL tidyGetMessageCode( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageCode)(*message);
}

ctmbstr TIDY_CALL tidyGetMessageKey( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageKey)(*message);
}

int TIDY_CALL tidyGetMessageLine( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageLine)(*message);
}

int TIDY_CALL tidyGetMessageColumn( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageColumn)(*message);
}

TidyReportLevel TIDY_CALL tidyGetMessageLevel( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageLevel)(*message);
}

Bool TIDY_CALL tidyGetMessageIsMuted( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageIsMuted)(*message);
}

ctmbstr TIDY_CALL tidyGetMessageFormatDefault( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageFormatDefault)(*message);
}

ctmbstr TIDY_CALL tidyGetMessageFormat( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageFormat)(*message);
}

ctmbstr TIDY_CALL tidyGetMessageDefault( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageDefault)(*message);
}

ctmbstr TIDY_CALL tidyGetMessage( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessage)(*message);
}

ctmbstr TIDY_CALL tidyGetMessagePosDefault( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessagePosDefault)(*message);
}

ctmbstr TIDY_CALL tidyGetMessagePos( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessagePos)(*message);
}

ctmbstr TIDY_CALL tidyGetMessagePrefixDefault( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessagePrefixDefault)(*message);
}

ctmbstr TIDY_CALL tidyGetMessagePrefix( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessagePrefix)(*message);
}


ctmbstr TIDY_CALL tidyGetMessageOutputDefault( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageOutputDefault)(*message);
}

ctmbstr TIDY_CALL tidyGetMessageOutput( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageOutput)(*message);
}

TidyIterator TIDY_CALL tidyGetMessageArguments( TidyMessage tmessage )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getMessageArguments)(*message);
}

TidyMessageArgument TIDY_CALL tidyGetNextMessageArgument( TidyMessage tmessage, TidyIterator* iter )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getNextMessageArgument)(*message, iter);
}

TidyFormatParameterType TIDY_CALL tidyGetArgType( TidyMessage tmessage, TidyMessageArgument* arg )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getArgType)(*message, arg);
}

ctmbstr TIDY_CALL tidyGetArgFormat( TidyMessage tmessage, TidyMessageArgument* arg )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getArgFormat)(*message, arg);
}

ctmbstr TIDY_CALL tidyGetArgValueString( TidyMessage tmessage, TidyMessageArgument* arg )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getArgValueString)(*message, arg);
}

unsigned int TIDY_CALL tidyGetArgValueUInt( TidyMessage tmessage, TidyMessageArgument* arg )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getArgValueUInt)(*message, arg);
}

int TIDY_CALL tidyGetArgValueInt( TidyMessage tmessage, TidyMessageArgument* arg )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getArgValueInt)(*message, arg);
}

double TIDY_CALL tidyGetArgValueDouble( TidyMessage tmessage, TidyMessageArgument* arg )
{
    TidyMessageImpl *message = tidyMessageToImpl(tmessage);
    return TY_(getArgValueDouble)(*message, arg);
}


FILE* TIDY_CALL   tidySetErrorFile( TidyDoc tdoc, ctmbstr errfilnam )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        FILE* errout = fopen( errfilnam, "wb" );
        if ( errout )
        {
            unsigned int outenc = cfg( impl, TidyOutCharEncoding );
            unsigned int nl = cfg( impl, TidyNewline );
            TY_(ReleaseStreamOut)( impl, impl->errout );
            impl->errout = TY_(FileOutput)( impl, errout, outenc, nl );
            return errout;
        }
        else /* Emit message to current error sink */
            TY_(ReportFileError)( impl, errfilnam, FILE_CANT_OPEN );
    }
    return NULL;
}

int TIDY_CALL    tidySetErrorBuffer( TidyDoc tdoc, TidyBuffer* errbuf )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        unsigned int outenc = cfg( impl, TidyOutCharEncoding );
        unsigned int nl = cfg( impl, TidyNewline );
        TY_(ReleaseStreamOut)( impl, impl->errout );
        impl->errout = TY_(BufferOutput)( impl, errbuf, outenc, nl );
        return ( impl->errout ? 0 : -ENOMEM );
    }
    return -EINVAL;
}

int TIDY_CALL    tidySetErrorSink( TidyDoc tdoc, TidyOutputSink* sink )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        unsigned int outenc = cfg( impl, TidyOutCharEncoding );
        unsigned int nl = cfg( impl, TidyNewline );
        TY_(ReleaseStreamOut)( impl, impl->errout );
        impl->errout = TY_(UserOutput)( impl, sink, outenc, nl );
        return ( impl->errout ? 0 : -ENOMEM );
    }
    return -EINVAL;
}

/* Use TidyPPProgress to monitor the progress of the pretty printer.
 */
Bool TIDY_CALL        tidySetPrettyPrinterCallback(TidyDoc tdoc, TidyPPProgress callback)
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        impl->progressCallback = callback;
        return yes;
    }
    return no;
}


/* Document info */
int TIDY_CALL        tidyStatus( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    int tidyStat = -EINVAL;
    if ( impl )
        tidyStat = tidyDocStatus( impl );
    return tidyStat;
}
int TIDY_CALL        tidyDetectedHtmlVersion( TidyDoc ARG_UNUSED(tdoc) )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    return TY_(HTMLVersionNumberFromCode)( impl->lexer->versionEmitted );
}

Bool TIDY_CALL        tidyDetectedXhtml( TidyDoc ARG_UNUSED(tdoc) )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc ); 
    return impl->lexer->isvoyager;
}
Bool TIDY_CALL        tidyDetectedGenericXml( TidyDoc ARG_UNUSED(tdoc) )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc ); 
    return impl->xmlDetected;
}

unsigned int TIDY_CALL       tidyErrorCount( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    unsigned int count = 0xFFFFFFFF;
    if ( impl )
        count = impl->errors;
    return count;
}
unsigned int TIDY_CALL       tidyWarningCount( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    unsigned int count = 0xFFFFFFFF;
    if ( impl )
        count = impl->warnings;
    return count;
}
unsigned int TIDY_CALL       tidyAccessWarningCount( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    unsigned int count = 0xFFFFFFFF;
    if ( impl )
        count = impl->accessErrors;
    return count;
}
unsigned int TIDY_CALL       tidyConfigErrorCount( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    unsigned int count = 0xFFFFFFFF;
    if ( impl )
        count = impl->optionErrors;
    return count;
}


/* Error reporting functions
*/
void TIDY_CALL         tidyErrorSummary( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
        TY_(ErrorSummary)( impl );
}
void TIDY_CALL         tidyGeneralInfo( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
    {
        TY_(Dialogue)( impl, TEXT_GENERAL_INFO );
        TY_(Dialogue)( impl, TEXT_GENERAL_INFO_PLEA );
    }
}


/* I/O Functions
**
** Initial version supports only whole-file operations.
** Do not expose Tidy StreamIn or Out data structures - yet.
*/

/* Parse/load Functions
**
** HTML/XHTML version determined from input.
*/
int TIDY_CALL  tidyParseFile( TidyDoc tdoc, ctmbstr filnam )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocParseFile( doc, filnam );
}
int TIDY_CALL  tidyParseStdin( TidyDoc tdoc )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocParseStdin( doc );
}
int TIDY_CALL  tidyParseString( TidyDoc tdoc, ctmbstr content )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocParseString( doc, content );
}
int TIDY_CALL  tidyParseBuffer( TidyDoc tdoc, TidyBuffer* inbuf )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocParseBuffer( doc, inbuf );
}
int TIDY_CALL  tidyParseSource( TidyDoc tdoc, TidyInputSource* source )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocParseSource( doc, source );
}


int   tidyDocParseFile( TidyDocImpl* doc, ctmbstr filnam )
{
    int status = -ENOENT;
    FILE* fin = fopen( filnam, "r+" );

    if ( !fin )
    {
        TY_(ReportFileError)( doc, filnam, FILE_NOT_FILE );
        return status;
    }

    fclose( fin );

#ifdef _WIN32
    return TY_(DocParseFileWithMappedFile)( doc, filnam );
#else

    fin = fopen( filnam, "rb" );

#if PRESERVE_FILE_TIMES
    {
        struct stat sbuf = { 0 };
        /* get last modified time */
        TidyClearMemory(&doc->filetimes, sizeof(doc->filetimes));
        if (fin && cfgBool(doc, TidyKeepFileTimes) &&
            fstat(fileno(fin), &sbuf) != -1)
        {
            doc->filetimes.actime = sbuf.st_atime;
            doc->filetimes.modtime = sbuf.st_mtime;
        }
    }
#endif

    if ( fin )
    {
        StreamIn* in = TY_(FileInput)( doc, fin, cfg( doc, TidyInCharEncoding ));
        if ( !in )
        {
            fclose( fin );
            return status;
        }
        status = TY_(DocParseStream)( doc, in );
        TY_(freeFileSource)(&in->source, yes);
        TY_(freeStreamIn)(in);
    }
    else /* Error message! */
        TY_(ReportFileError)( doc, filnam, FILE_CANT_OPEN );
    return status;
#endif
}

int   tidyDocParseStdin( TidyDocImpl* doc )
{
    StreamIn* in = TY_(FileInput)( doc, stdin, cfg( doc, TidyInCharEncoding ));
    int status = TY_(DocParseStream)( doc, in );
    TY_(freeFileSource)(&in->source, yes);
    TY_(freeStreamIn)(in);
    return status;
}

int   tidyDocParseBuffer( TidyDocImpl* doc, TidyBuffer* inbuf )
{
    int status = -EINVAL;
    if ( inbuf )
    {
        StreamIn* in = TY_(BufferInput)( doc, inbuf, cfg( doc, TidyInCharEncoding ));
        status = TY_(DocParseStream)( doc, in );
        TY_(freeStreamIn)(in);
    }
    return status;
}

int   tidyDocParseString( TidyDocImpl* doc, ctmbstr content )
{
    int status = -EINVAL;
    TidyBuffer inbuf;
    StreamIn* in = NULL;

    if ( content )
    {
        tidyBufInitWithAllocator( &inbuf, doc->allocator );
        tidyBufAttach( &inbuf, (byte*)content, TY_(tmbstrlen)(content)+1 );
        in = TY_(BufferInput)( doc, &inbuf, cfg( doc, TidyInCharEncoding ));
        status = TY_(DocParseStream)( doc, in );
        tidyBufDetach( &inbuf );
        TY_(freeStreamIn)(in);
    }
    return status;
}

int   tidyDocParseSource( TidyDocImpl* doc, TidyInputSource* source )
{
    StreamIn* in = TY_(UserInput)( doc, source, cfg( doc, TidyInCharEncoding ));
    int status = TY_(DocParseStream)( doc, in );
    TY_(freeStreamIn)(in);
    return status;
}


/* Print/save Functions
**
*/
int TIDY_CALL        tidySaveFile( TidyDoc tdoc, ctmbstr filnam )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocSaveFile( doc, filnam );
}
int TIDY_CALL        tidySaveStdout( TidyDoc tdoc )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocSaveStdout( doc );
}
int TIDY_CALL        tidySaveString( TidyDoc tdoc, tmbstr buffer, unsigned int* buflen )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocSaveString( doc, buffer, buflen );
}
int TIDY_CALL        tidySaveBuffer( TidyDoc tdoc, TidyBuffer* outbuf )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocSaveBuffer( doc, outbuf );
}
int TIDY_CALL        tidySaveSink( TidyDoc tdoc, TidyOutputSink* sink )
{
    TidyDocImpl* doc = tidyDocToImpl( tdoc );
    return tidyDocSaveSink( doc, sink );
}

int         tidyDocSaveFile( TidyDocImpl* doc, ctmbstr filnam )
{
    int status = -ENOENT;
    FILE* fout = NULL;

    /* Don't zap input file if no output */
    if ( doc->errors > 0 &&
         cfgBool(doc, TidyWriteBack) && !cfgBool(doc, TidyForceOutput) )
        status = tidyDocStatus( doc );
    else
        fout = fopen( filnam, "wb" );

    if ( fout )
    {
        unsigned int outenc = cfg( doc, TidyOutCharEncoding );
        unsigned int nl = cfg( doc, TidyNewline );
        StreamOut* out = TY_(FileOutput)( doc, fout, outenc, nl );

        status = tidyDocSaveStream( doc, out );

        fclose( fout );
        TidyDocFree( doc, out );

#if PRESERVE_FILE_TIMES
        if ( doc->filetimes.actime )
        {
            /* set file last accessed/modified times to original values */
            utime( filnam, &doc->filetimes );
            TidyClearMemory( &doc->filetimes, sizeof(doc->filetimes) );
        }
#endif /* PRESERVFILETIMES */
    }
    if ( status < 0 ) /* Error message! */
        TY_(ReportFileError)( doc, filnam, FILE_CANT_OPEN );
    return status;
}



/* Note, _setmode() does NOT work on Win2K Pro w/ VC++ 6.0 SP3.
** The code has been left in in case it works w/ other compilers
** or operating systems.  If stdout is in Text mode, be aware that
** it will garble UTF16 documents.  In text mode, when it encounters
** a single byte of value 10 (0xA), it will insert a single byte
** value 13 (0xD) just before it.  This has the effect of garbling
** the entire document.
*/

#if !defined(NO_SETMODE_SUPPORT)
#  if defined(_WIN32) || defined(OS2_OS)
#   include <fcntl.h>
#     include <io.h>
#   endif
#endif

int         tidyDocSaveStdout( TidyDocImpl* doc )
{
#if !defined(NO_SETMODE_SUPPORT)
#  if defined(_WIN32) || defined(OS2_OS)
    int oldstdoutmode = -1, oldstderrmode = -1;
#  endif
#endif

    int status = 0;
    unsigned int outenc = cfg( doc, TidyOutCharEncoding );
    unsigned int nl = cfg( doc, TidyNewline );
    StreamOut* out = TY_(FileOutput)( doc, stdout, outenc, nl );

#if !defined(NO_SETMODE_SUPPORT)
#  if defined(_WIN32) || defined(OS2_OS)
    oldstdoutmode = setmode( fileno(stdout), _O_BINARY );
    oldstderrmode = setmode( fileno(stderr), _O_BINARY );
#  endif
#endif

    if ( 0 == status )
      status = tidyDocSaveStream( doc, out );

    fflush(stdout);
    fflush(stderr);

#if !defined(NO_SETMODE_SUPPORT)
#  if defined(_WIN32) || defined(OS2_OS)
    if ( oldstdoutmode != -1 )
        oldstdoutmode = setmode( fileno(stdout), oldstdoutmode );
    if ( oldstderrmode != -1 )
        oldstderrmode = setmode( fileno(stderr), oldstderrmode );
#  endif
#endif

    TidyDocFree( doc, out );
    return status;
}

int         tidyDocSaveString( TidyDocImpl* doc, tmbstr buffer, unsigned int* buflen )
{
    unsigned int outenc = cfg( doc, TidyOutCharEncoding );
    unsigned int nl = cfg( doc, TidyNewline );
    TidyBuffer outbuf;
    StreamOut* out;
    int status;

    tidyBufInitWithAllocator( &outbuf, doc->allocator );
    out = TY_(BufferOutput)( doc, &outbuf, outenc, nl );
    status = tidyDocSaveStream( doc, out );

    if ( outbuf.size > *buflen )
        status = -ENOMEM;
    else
        memcpy( buffer, outbuf.bp, outbuf.size );

    *buflen = outbuf.size;
    tidyBufFree( &outbuf );
    TidyDocFree( doc, out );
    return status;
}

int         tidyDocSaveBuffer( TidyDocImpl* doc, TidyBuffer* outbuf )
{
    int status = -EINVAL;
    if ( outbuf )
    {
        unsigned int outenc = cfg( doc, TidyOutCharEncoding );
        unsigned int nl = cfg( doc, TidyNewline );
        StreamOut* out = TY_(BufferOutput)( doc, outbuf, outenc, nl );

        status = tidyDocSaveStream( doc, out );
        TidyDocFree( doc, out );
    }
    return status;
}

int         tidyDocSaveSink( TidyDocImpl* doc, TidyOutputSink* sink )
{
    unsigned int outenc = cfg( doc, TidyOutCharEncoding );
    unsigned int nl = cfg( doc, TidyNewline );
    StreamOut* out = TY_(UserOutput)( doc, sink, outenc, nl );
    int status = tidyDocSaveStream( doc, out );
    TidyDocFree( doc, out );
    return status;
}

int         tidyDocStatus( TidyDocImpl* doc )
{
    if ( doc->errors > 0 )
        return 2;
    if ( doc->warnings > 0 || doc->accessErrors > 0 )
        return 1;
    return 0;
}



int TIDY_CALL        tidyCleanAndRepair( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
      return tidyDocCleanAndRepair( impl );
    return -EINVAL;
}

int TIDY_CALL        tidyRunDiagnostics( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl )
      return tidyDocRunDiagnostics( impl );
    return -EINVAL;
}

int TIDY_CALL        tidyReportDoctype( TidyDoc tdoc )
{
    int iret = -EINVAL;
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    if ( impl ) {
      tidyDocReportDoctype( impl );
      iret = 0;
    }
    return iret;
}

/* Workhorse functions.
**
** Parse requires input source, all input config items
** and diagnostic sink to have all been set before calling.
**
** Emit likewise requires that document sink and all
** pretty printing options have been set.
*/
static ctmbstr integrity = "\nPanic - tree has lost its integrity\n";

int         TY_(DocParseStream)( TidyDocImpl* doc, StreamIn* in )
{
    Bool xmlIn = cfgBool( doc, TidyXmlTags );
    TidyConfigChangeCallback callback = doc->pConfigChangeCallback;
    
    int bomEnc;
    doc->pConfigChangeCallback = NULL;

    assert( doc != NULL && in != NULL );
    assert( doc->docIn == NULL );
    doc->docIn = in;

    TY_(ResetTags)(doc);    /* reset table to html5 mode */
    TY_(TakeConfigSnapshot)( doc );    /* Save config state */
    TY_(FreeAnchors)( doc );

    TY_(FreeNode)(doc, &doc->root);
    TidyClearMemory(&doc->root, sizeof(Node));

    if (doc->givenDoctype)
        TidyDocFree(doc, doc->givenDoctype);
    /*\ 
     *  Issue #186 - Now FreeNode depend on the doctype, so the lexer is needed
     *  to determine which hash is to be used, so free it last.
    \*/
    TY_(FreeLexer)( doc );
    doc->givenDoctype = NULL;

    doc->lexer = TY_(NewLexer)( doc );
    /* doc->lexer->root = &doc->root; */
    doc->root.line = doc->lexer->lines;
    doc->root.column = doc->lexer->columns;
    doc->inputHadBOM = no;
    doc->xmlDetected = no;

    bomEnc = TY_(ReadBOMEncoding)(in);

    if (bomEnc != -1)
    {
        in->encoding = bomEnc;
        TY_(SetOptionInt)(doc, TidyInCharEncoding, bomEnc);
    }

    /* Tidy doesn't alter the doctype for generic XML docs */
    if ( xmlIn )
    {
        TY_(ParseXMLDocument)( doc );
        if ( !TY_(CheckNodeIntegrity)( &doc->root ) )
            TidyPanic( doc->allocator, integrity );
    }
    else
    {
        doc->warnings = 0;
        TY_(ParseDocument)( doc );
        if ( !TY_(CheckNodeIntegrity)( &doc->root ) )
            TidyPanic( doc->allocator, integrity );
    }

    doc->docIn = NULL;
    doc->pConfigChangeCallback = callback;

    return tidyDocStatus( doc );
}

int         tidyDocRunDiagnostics( TidyDocImpl* doc )
{
    TY_(ReportMarkupVersion)( doc );
    TY_(ReportNumWarnings)( doc );

    if ( doc->errors > 0 && !cfgBool( doc, TidyForceOutput ) )
        TY_(Dialogue)(doc, STRING_NEEDS_INTERVENTION );

     return tidyDocStatus( doc );
}

void         tidyDocReportDoctype( TidyDocImpl* doc )
{
        TY_(ReportMarkupVersion)( doc );
}


/*****************************************************************************
 *  HTML5 STUFF
 *****************************************************************************/
#if 0 && defined(ENABLE_DEBUG_LOG)
extern void show_not_html5(void);
/* -----------------------------
List tags that do not have version HTML5 (HT50|XH50)

acronym applet basefont big center dir font frame frameset isindex
listing noframes plaintext rb rbc rtc strike tt xmp nextid
align bgsound blink comment ilayer layer marquee multicol nobr noembed
nolayer nosave server servlet spacer

Listed total 35 tags that do not have version 393216
   ------------------------------ */

static void list_not_html5(void)
{
    static Bool done_list = no;
    if (done_list == no) {
        done_list = yes;
        show_not_html5();
    }
}
#endif

/* What about <blink>, <s> stike-through, <u> underline */
static struct _html5Info
{
    const char *tag;
    unsigned int id;
} const html5Info[] = {
    {"acronym", TidyTag_ACRONYM},
    {"applet", TidyTag_APPLET  },
    {"basefont",TidyTag_BASEFONT },
    { "big", TidyTag_BIG },
    { "center", TidyTag_CENTER },
    { "dir", TidyTag_DIR },
    { "font", TidyTag_FONT },
    { "frame", TidyTag_FRAME},
    { "frameset", TidyTag_FRAMESET},
    { "noframes", TidyTag_NOFRAMES },
    { "strike", TidyTag_STRIKE },
    { "tt", TidyTag_TT },
    { 0, 0 }
};
Bool inRemovedInfo( unsigned int tid )
{
    int i;
    for (i = 0; ; i++) {
        if (html5Info[i].tag == 0)
            break;
        if (html5Info[i].id == tid)
            return yes;
    }
    return no;
}

/* Things that should not be in an HTML5 body. This is special for CheckHTML5(),
 and we might just want to remove CheckHTML5()'s output altogether and count
 on the default --strict-tags-attributes.
 */
static int BadBody5Attribs[] = {
    TidyAttr_BACKGROUND,
    TidyAttr_BGCOLOR,
    TidyAttr_TEXT,
    TidyAttr_LINK,
    TidyAttr_VLINK,
    TidyAttr_ALINK,
    TidyAttr_UNKNOWN /* Must be last! */
};

static Bool nodeHasAlignAttr( Node *node )
{
    /* #define attrIsALIGN(av) AttrIsId( av, TidyAttr_ALIGN  ) */
    AttVal* av;
    for ( av = node->attributes; av != NULL; av = av->next ) {
        if (attrIsALIGN(av))
            return yes;
    }
    return no;
}

/*
 *  Perform special checks for HTML, even when we're not using the default
 *  option `--strict-tags-attributes yes`. This will ensure that HTML5 warning
 *  and error output is given regardless of the new option, and ensure that
 *  cleanup takes place. This provides mostly consistent Tidy behavior even with
 *  the introduction of this new option. Note that strings have changed, though,
 *  in order to maintain consistency with the `--strict-tags-attributes` 
 *  messages.
 *
 *  See also: http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#obsolete
 */
void TY_(CheckHTML5)( TidyDocImpl* doc, Node* node )
{
    Bool clean = cfgBool( doc, TidyMakeClean );
    Bool already_strict = cfgBool( doc, TidyStrictTagsAttr );
    Node* body = TY_(FindBody)( doc );
    Bool warn = yes;    /* should this be a warning, error, or report??? */
    AttVal* attr = NULL;
    int i = 0;

    while (node)
    {
        if ( nodeHasAlignAttr( node ) ) {
            /* @todo: Is this for ALL elements that accept an 'align' attribute,
             * or should this be a sub-set test?
             */

            /* We will only emit this message if `--strict-tags-attributes==no`;
             * otherwise if yes this message will be output during later
             * checking.
             */
            if ( !already_strict )
                TY_(ReportAttrError)(doc, node, TY_(AttrGetById)(node, TidyAttr_ALIGN), MISMATCHED_ATTRIBUTE_WARN);
        }
        if ( node == body ) {
            i = 0;
            /* We will only emit these messages if `--strict-tags-attributes==no`;
             * otherwise if yes these messages will be output during later
             * checking.
             */
            if ( !already_strict ) {
                while ( BadBody5Attribs[i] != TidyAttr_UNKNOWN ) {
                    attr = TY_(AttrGetById)(node, BadBody5Attribs[i]);
                    if ( attr )
                        TY_(ReportAttrError)(doc, node, attr , MISMATCHED_ATTRIBUTE_WARN);
                    i++;
                }
            }
        } else
        if ( nodeIsACRONYM(node) ) {
            if (clean) {
                /* Replace with 'abbr' with warning to that effect.
                 * Maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid )
                 */
                TY_(CoerceNode)(doc, node, TidyTag_ABBR, warn, no);
            } else {
                if ( !already_strict )
                    TY_(Report)(doc, node, node, REMOVED_HTML5);
            }
        } else
        if ( nodeIsAPPLET(node) ) {
            if (clean) {
                /* replace with 'object' with warning to that effect
                 * maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid )
                 */
                TY_(CoerceNode)(doc, node, TidyTag_OBJECT, warn, no);
            } else {
                if ( !already_strict )
                    TY_(Report)(doc, node, node, REMOVED_HTML5);
            }
        } else
        if ( nodeIsBASEFONT(node) ) {
            /* basefont: CSS equivalent 'font-size', 'font-family' and 'color' 
             * on body or class on each subsequent element.
             * Difficult - If it is the first body element, then could consider
             * adding that to the <body> as a whole, else could perhaps apply it
             * to all subsequent elements. But also in consideration is the fact
             * that it was NOT supported in many browsers.
             * - For now just report a warning
             */
            if ( !already_strict )
                TY_(Report)(doc, node, node, REMOVED_HTML5);
        } else
        if ( nodeIsBIG(node) ) {
            /* big: CSS equivalent 'font-size:larger'
             * so could replace the <big> ... </big> with
             * <span style="font-size: larger"> ... </span>
             * then replace <big> with <span>
             * Need to think about that...
             * Could use -
             *   TY_(AddStyleProperty)( doc, node, "font-size: larger" );
             *   TY_(CoerceNode)(doc, node, TidyTag_SPAN, no, no);
             * Alternatively generated a <style> but how to get the style name
             * TY_(AddAttribute)( doc, node, "class", "????" );
             * Also maybe need a specific message like
             * Element '%s' replaced with 'span' with a 'font-size: larger style attribute
             * maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid )
             */
            if (clean) {
                TY_(AddStyleProperty)( doc, node, "font-size: larger" );
                TY_(CoerceNode)(doc, node, TidyTag_SPAN, warn, no);
            } else {
                if ( !already_strict )
                    TY_(Report)(doc, node, node, REMOVED_HTML5);
            }
        } else
        if ( nodeIsCENTER(node) ) {
            /* center: CSS equivalent 'text-align:center'
             * and 'margin-left:auto; margin-right:auto' on descendant blocks
             * Tidy already handles this if 'clean' by SILENTLY generating the
             * <style> and adding a <div class="c1"> around the elements.
             * see: static Bool Center2Div( TidyDocImpl* doc, Node *node, Node **pnode)
             */
            if ( !already_strict )
                TY_(Report)(doc, node, node, REMOVED_HTML5);
        } else
        if ( nodeIsDIR(node) ) {
            /* dir: replace by <ul>
             * Tidy already actions this and issues a warning
             * Should this be CHANGED???
             */
            if ( !already_strict )
                TY_(Report)(doc, node, node, REMOVED_HTML5);
        } else
        if ( nodeIsFONT(node) ) {
            /* Tidy already handles this -
             * If 'clean' replaced by CSS, else
             * if is NOT clean, and doctype html5 then warnings issued
             * done in Bool Font2Span( TidyDocImpl* doc, Node *node, Node **pnode ) (I think?)
             */
            if ( !already_strict )
                TY_(Report)(doc, node, node, REMOVED_HTML5);
        } else
        if (( nodesIsFRAME(node) ) || ( nodeIsFRAMESET(node) ) || ( nodeIsNOFRAMES(node) )) {
            /* YOW: What to do here?????? Maybe <iframe>????
             */
            if ( !already_strict )
                TY_(Report)(doc, node, node, REMOVED_HTML5);
        } else
        if ( nodeIsSTRIKE(node) ) {
            /* strike: CSS equivalent 'text-decoration:line-through'
             * maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid )
             */
            if (clean) {
                TY_(AddStyleProperty)( doc, node, "text-decoration: line-through" );
                TY_(CoerceNode)(doc, node, TidyTag_SPAN, warn, no);
            } else {
                if ( !already_strict )
                    TY_(Report)(doc, node, node, REMOVED_HTML5);
            }
        } else
        if ( nodeIsTT(node) ) {
            /* tt: CSS equivalent 'font-family:monospace'
             * Tidy presently does nothing. Tidy5 issues a warning
             * But like the 'clean' <font> replacement this could also be replaced with CSS
             * maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid )
             */
            if (clean) {
                TY_(AddStyleProperty)( doc, node, "font-family: monospace" );
                TY_(CoerceNode)(doc, node, TidyTag_SPAN, warn, no);
            } else {
                if ( !already_strict )
                    TY_(Report)(doc, node, node, REMOVED_HTML5);
            }
        } else
            if (TY_(nodeIsElement)(node)) {
                if (node->tag) {
                    if ( (!(node->tag->versions & VERS_HTML5) && !(node->tag->versions & VERS_PROPRIETARY)) || (inRemovedInfo(node->tag->id)) ) {
                        if ( !already_strict )
                            TY_(Report)(doc, node, node, REMOVED_HTML5);
                    }
                }
            }

        if (node->content)
            TY_(CheckHTML5)( doc, node->content );
        
        node = node->next;
    }
}
/*****************************************************************************
 *  END HTML5 STUFF
 *****************************************************************************/


/*
 * Check and report HTML tags and attributes that are:
 *  - Proprietary, and/or
 *  - Not supported in the current version of HTML, defined as the version
 *    of HTML that we are emitting.
 * Proprietary items are reported as WARNINGS, and version mismatches will
 * be reported as WARNING or ERROR in the following conditions:
 *  - ERROR if the emitted doctype is a strict doctype.
 *  - WARNING if the emitted doctype is a non-strict doctype.
 * The propriety checks are *always* run as they have always been an integral
 * part of Tidy. The version checks are controlled by `strict-tags-attributes`.
 */
void TY_(CheckHTMLTagsAttribsVersions)( TidyDocImpl* doc, Node* node )
{
    unsigned int versionEmitted = doc->lexer->versionEmitted;
    unsigned int declared = doc->lexer->doctype;
    unsigned int version = versionEmitted == 0 ? declared : versionEmitted;
    int tagReportType = VERS_STRICT & version ? ELEMENT_VERS_MISMATCH_ERROR : ELEMENT_VERS_MISMATCH_WARN;
    int attrReportType = VERS_STRICT & version ? MISMATCHED_ATTRIBUTE_ERROR : MISMATCHED_ATTRIBUTE_WARN;
    Bool check_versions = cfgBool( doc, TidyStrictTagsAttr );
    AttVal *next_attr, *attval;
    Bool attrIsProprietary = no;
    Bool attrIsMismatched = yes;
    Bool tagLooksCustom = no;
    Bool htmlIs5 = (doc->lexer->doctype & VERS_HTML5) > 0;

    while (node)
    {
        /* This bit here handles our HTML tags */
        if ( TY_(nodeIsElement)(node) && node->tag ) {

            /* Leave XML stuff alone. */
            if ( !cfgBool(doc, TidyXmlTags) )
            {
                /* Version mismatches take priority. */
                if ( check_versions && !(node->tag->versions & version) )
                {
                    TY_(Report)(doc, NULL, node, tagReportType );
                }
                /* If it's not mismatched, it could still be proprietary. */
                else if ( node->tag->versions & VERS_PROPRIETARY )
                {
                    if ( !cfgBool(doc, TidyMakeClean) ||
                        ( !nodeIsNOBR(node) && !nodeIsWBR(node) ) )
                    {
                        /* It looks custom, despite whether it's a known tag. */
                        tagLooksCustom = TY_(nodeIsAutonomousCustomFormat)( node );

                        /* If we're in HTML5 mode and the tag does not look
                           like a valid custom tag, then issue a warning.
                           Appearance is good enough because invalid tags have
                           been dropped. Also, if we're not in HTML5 mode, then
                           then everything that reaches here gets the warning.
                           Everything else can be ignored. */

                        if ( (htmlIs5 && !tagLooksCustom) || !htmlIs5 )
                        {
                            TY_(Report)(doc, NULL, node, PROPRIETARY_ELEMENT );
                        }

                        if ( nodeIsLAYER(node) )
                            doc->badLayout |= USING_LAYER;
                        else if ( nodeIsSPACER(node) )
                            doc->badLayout |= USING_SPACER;
                        else if ( nodeIsNOBR(node) )
                            doc->badLayout |= USING_NOBR;
                    }
                }
            }
        }

        /* And this bit here handles our attributes */
        if (TY_(nodeIsElement)(node))
        {
            attval = node->attributes;

            while (attval)
            {
                next_attr = attval->next;

                attrIsProprietary = TY_(AttributeIsProprietary)(node, attval);
                attrIsMismatched = check_versions ? TY_(AttributeIsMismatched)(node, attval, doc) : no;
                /* Let the PROPRIETARY_ATTRIBUTE warning have precedence. */
                if ( attrIsProprietary )
                {
                    if ( cfgBool(doc, TidyWarnPropAttrs) )
                        TY_(ReportAttrError)(doc, node, attval, PROPRIETARY_ATTRIBUTE);
                }
                else if ( attrIsMismatched )
                {
                    TY_(ReportAttrError)(doc, node, attval, attrReportType);
                }

                /* @todo: do we need a new option to drop mismatches? Or should we
                 simply drop them? */
                if ( ( attrIsProprietary || attrIsMismatched ) && cfgBool(doc, TidyDropPropAttrs) )
                    TY_(RemoveAttribute)( doc, node, attval );

                attval = next_attr;
            }
        }

        if (node->content)
            TY_(CheckHTMLTagsAttribsVersions)( doc, node->content );
        
        node = node->next;
    }
}


#if defined(ENABLE_DEBUG_LOG)
/* *** FOR DEBUG ONLY *** */
const char *dbg_get_lexer_type( void *vp )
{
    Node *node = (Node *)vp;
    switch ( node->type )
    {
    case RootNode:      return "Root";
    case DocTypeTag:    return "DocType";
    case CommentTag:    return "Comment";
    case ProcInsTag:    return "ProcIns";
    case TextNode:      return "Text";
    case StartTag:      return "StartTag";
    case EndTag:        return "EndTag";
    case StartEndTag:   return "StartEnd";
    case CDATATag:      return "CDATA";
    case SectionTag:    return "Section";
    case AspTag:        return "Asp";
    case JsteTag:       return "Jste";
    case PhpTag:        return "Php";
    case XmlDecl:       return "XmlDecl";
    }
    return "Uncased";
}

/* NOTE: THis matches the above lexer type, except when element has a name */
const char *dbg_get_element_name( void *vp )
{
    Node *node = (Node *)vp;
    switch ( node->type )
    {
    case TidyNode_Root:       return "Root";
    case TidyNode_DocType:    return "DocType";
    case TidyNode_Comment:    return "Comment";
    case TidyNode_ProcIns:    return "ProcIns";
    case TidyNode_Text:       return "Text";
    case TidyNode_CDATA:      return "CDATA";
    case TidyNode_Section:    return "Section";
    case TidyNode_Asp:        return "Asp";
    case TidyNode_Jste:       return "Jste";
    case TidyNode_Php:        return "Php";
    case TidyNode_XmlDecl:    return "XmlDecl";

    case TidyNode_Start:
    case TidyNode_End:
    case TidyNode_StartEnd:
    default:
        if (node->element)
            return node->element;
    }
    return "Unknown";
}

void dbg_show_node( TidyDocImpl* doc, Node *node, int caller, int indent )
{
    AttVal* av;
    Lexer* lexer = doc->lexer;
    ctmbstr call = "";
    ctmbstr name = dbg_get_element_name(node);
    ctmbstr type = dbg_get_lexer_type(node);
    ctmbstr impl = node->implicit ? "implicit" : "";
    switch ( caller )
    {
    case 1: call = "discard";   break;
    case 2: call = "trim";      break;
    case 3: call = "test";      break;
    }
    while (indent--)
        SPRTF(" ");
    if (strcmp(type,name))
        SPRTF("%s %s %s %s", type, name, impl, call );
    else
        SPRTF("%s %s %s", name, impl, call );
    if (lexer && (strcmp("Text",name) == 0)) {
        unsigned int len = node->end - node->start;
        unsigned int i;
        SPRTF(" (%d) '", len);
        if (len < 40) {
            /* show it all */
            for (i = node->start; i < node->end; i++) {
                SPRTF("%c", lexer->lexbuf[i]);
            }
        } else {
            /* partial display */
            unsigned int max = 19;
            for (i = node->start; i < max; i++) {
                SPRTF("%c", lexer->lexbuf[i]);
            }
            SPRTF("...");
            i = node->end - 19;
            for (; i < node->end; i++) {
                SPRTF("%c", lexer->lexbuf[i]);
            }
        }
        SPRTF("'");
    }
    for (av = node->attributes; av; av = av->next) {
        name = av->attribute;
        if (name) {
            SPRTF(" %s",name);
            if (av->value) {
                SPRTF("=\"%s\"", av->value);
            }
        }
    }

    SPRTF("\n");
}

void dbg_show_all_nodes( TidyDocImpl* doc, Node *node, int indent )
{
    while (node)
    {
        dbg_show_node( doc, node, 0, indent );
        dbg_show_all_nodes( doc, node->content, indent + 1 );
        node = node->next;
    }
}

#endif

int         tidyDocCleanAndRepair( TidyDocImpl* doc )
{
    Bool word2K   = cfgBool( doc, TidyWord2000 );
    Bool logical  = cfgBool( doc, TidyLogicalEmphasis );
    Bool clean    = cfgBool( doc, TidyMakeClean );
    Bool gdoc     = cfgBool( doc, TidyGDocClean );
    Bool htmlOut  = cfgBool( doc, TidyHtmlOut );
    Bool xmlOut   = cfgBool( doc, TidyXmlOut );
    Bool xhtmlOut = cfgBool( doc, TidyXhtmlOut );
    Bool xmlDecl  = cfgBool( doc, TidyXmlDecl );
    Bool tidyMark = cfgBool( doc, TidyMark );
    Bool tidyXmlTags = cfgBool( doc, TidyXmlTags );
    Bool wantNameAttr = cfgBool( doc, TidyAnchorAsName );
    Bool mergeEmphasis = cfgBool( doc, TidyMergeEmphasis );
    Node* node;
    TidyConfigChangeCallback callback = doc->pConfigChangeCallback;
    doc->pConfigChangeCallback = NULL;

#if defined(ENABLE_DEBUG_LOG)
    SPRTF("All nodes BEFORE clean and repair\n");
    dbg_show_all_nodes( doc, &doc->root, 0  );
#endif
    if (tidyXmlTags)
    {
        doc->pConfigChangeCallback = callback;
        return tidyDocStatus( doc );
    }

    /* Issue #567 - move style elements from body to head */
    TY_(CleanStyle)(doc, &doc->root);

    /* simplifies <b><b> ... </b> ...</b> etc. */
    if ( mergeEmphasis )
        TY_(NestedEmphasis)( doc, &doc->root );

    /* cleans up <dir>indented text</dir> etc. */
    TY_(List2BQ)( doc, &doc->root );
    TY_(BQ2Div)( doc, &doc->root );

    /* replaces i by em and b by strong */
    if ( logical )
        TY_(EmFromI)( doc, &doc->root );

    if ( word2K && TY_(IsWord2000)(doc) )
    {
        /* prune Word2000's <![if ...]> ... <![endif]> */
        TY_(DropSections)( doc, &doc->root );

        /* drop style & class attributes and empty p, span elements */
        TY_(CleanWord2000)( doc, &doc->root );
        TY_(DropEmptyElements)(doc, &doc->root);
    }

    /* replaces presentational markup by style rules */
    if ( clean )
        TY_(CleanDocument)( doc );

    /* clean up html exported by Google Docs */
    if ( gdoc )
        TY_(CleanGoogleDocument)( doc );

    /*  Reconcile http-equiv meta element with output encoding  */
    TY_(TidyMetaCharset)(doc);

    if ( !TY_(CheckNodeIntegrity)( &doc->root ) )
        TidyPanic( doc->allocator, integrity );

    /* remember given doctype for reporting */
    node = TY_(FindDocType)(doc);

    if (node)
    {
        AttVal* fpi = TY_(GetAttrByName)(node, "PUBLIC");
        if (AttrHasValue(fpi))
        {
            if (doc->givenDoctype)
                TidyDocFree(doc, doc->givenDoctype);
            doc->givenDoctype = TY_(tmbstrdup)(doc->allocator,fpi->value);
        }
    }

    if ( doc->root.content )
    {
        /* If we had XHTML input but want HTML output */
        if ( htmlOut && doc->lexer->isvoyager )
        {
            Node* node = TY_(FindDocType)(doc);
            /* Remove reference, but do not free */
            if (node)
              TY_(RemoveNode)(node);
        }

        if (xhtmlOut && !htmlOut)
        {
            TY_(SetXHTMLDocType)(doc);
            TY_(FixAnchors)(doc, &doc->root, wantNameAttr, yes);
            TY_(FixXhtmlNamespace)(doc, yes);
            TY_(FixLanguageInformation)(doc, &doc->root, yes, yes);
        }
        else
        {
            TY_(FixDocType)(doc);
            TY_(FixAnchors)(doc, &doc->root, wantNameAttr, yes);
            TY_(FixXhtmlNamespace)(doc, no);
            TY_(FixLanguageInformation)(doc, &doc->root, no, yes);
        }

        if (tidyMark )
            TY_(AddGenerator)(doc);

    }

    /* ensure presence of initial <?xml version="1.0"?> */
    if ( xmlOut && xmlDecl )
        TY_(FixXmlDecl)( doc );

    /* At this point the apparent doctype is going to be as stable as
       it can ever be, so we can start detecting things that shouldn't
       be in this version of HTML
     */
    if (doc->lexer) 
    {
        /*\ 
         *  Issue #429 #426 - These services can only be used
         *  when there is a document loaded, ie a lexer created.
         *  But really should not be calling a Clean and Repair
         *  service with no doc!
        \*/
        if (doc->lexer->versionEmitted & VERS_HTML5)
            TY_(CheckHTML5)( doc, &doc->root );
        TY_(CheckHTMLTagsAttribsVersions)( doc, &doc->root );

        if ( !doc->lexer->isvoyager && doc->xmlDetected )
        {
            TY_(Report)(doc, NULL, TY_(FindXmlDecl)(doc), XML_DECLARATION_DETECTED );

        }
    }

#if defined(ENABLE_DEBUG_LOG)
    SPRTF("All nodes AFTER clean and repair\n");
    dbg_show_all_nodes( doc, &doc->root, 0  );
#endif

    doc->pConfigChangeCallback = callback;
    return tidyDocStatus( doc );
}

static
Bool showBodyOnly( TidyDocImpl* doc, TidyTriState bodyOnly )
{
    Node* node;

    switch( bodyOnly )
    {
    case TidyNoState:
        return no;
    case TidyYesState:
        return yes;
    default:
        node = TY_(FindBody)( doc );
        if (node && node->implicit )
            return yes;
    }
    return no;
}


int         tidyDocSaveStream( TidyDocImpl* doc, StreamOut* out )
{
    Bool showMarkup  = cfgBool( doc, TidyShowMarkup );
    Bool forceOutput = cfgBool( doc, TidyForceOutput );
    Bool outputBOM   = ( cfgAutoBool(doc, TidyOutputBOM) == TidyYesState );
    Bool smartBOM    = ( cfgAutoBool(doc, TidyOutputBOM) == TidyAutoState );
    Bool xmlOut      = cfgBool( doc, TidyXmlOut );
    Bool xhtmlOut    = cfgBool( doc, TidyXhtmlOut );
    TidyTriState bodyOnly    = cfgAutoBool( doc, TidyBodyOnly );

    Bool dropComments = cfgBool(doc, TidyHideComments);
    Bool makeClean    = cfgBool(doc, TidyMakeClean);
    Bool asciiChars   = cfgBool(doc, TidyAsciiChars);
    Bool makeBare     = cfgBool(doc, TidyMakeBare);
    Bool escapeCDATA  = cfgBool(doc, TidyEscapeCdata);
    Bool ppWithTabs   = cfgBool(doc, TidyPPrintTabs);
    TidyAttrSortStrategy sortAttrStrat = cfg(doc, TidySortAttributes);
    TidyConfigChangeCallback callback = doc->pConfigChangeCallback;
    doc->pConfigChangeCallback = NULL;

    if (ppWithTabs)
        TY_(PPrintTabs)();
    else
        TY_(PPrintSpaces)();

    if (escapeCDATA)
        TY_(ConvertCDATANodes)(doc, &doc->root);

    if (dropComments)
        TY_(DropComments)(doc, &doc->root);

    if (makeClean)
    {
        /* noop */
        TY_(DropFontElements)(doc, &doc->root, NULL);
    }

    if ((makeClean && asciiChars) || makeBare)
        TY_(DowngradeTypography)(doc, &doc->root);

    if (makeBare)
        /* Note: no longer replaces &nbsp; in */
        /* attribute values / non-text tokens */
        TY_(NormalizeSpaces)(doc->lexer, &doc->root);
    else
        TY_(ReplacePreformattedSpaces)(doc, &doc->root);

    TY_(SortAttributes)(doc, &doc->root, sortAttrStrat);

    if ( showMarkup && (doc->errors == 0 || forceOutput) )
    {
        /* Output a Byte Order Mark if required */
        if ( outputBOM || (doc->inputHadBOM && smartBOM) )
            TY_(outBOM)( out );

        /* No longer necessary. No DOCTYPE == HTML 3.2,
        ** which gives you only the basic character entities,
        ** which are safe in any browser.
        ** if ( !TY_(FindDocType)(doc) )
        **    TY_(SetOptionBool)( doc, TidyNumEntities, yes );
        */

        doc->docOut = out;
        if ( xmlOut && !xhtmlOut )
            TY_(PPrintXMLTree)( doc, NORMAL, 0, &doc->root );
        else if ( showBodyOnly( doc, bodyOnly ) )
            TY_(PrintBody)( doc );
        else
            TY_(PPrintTree)( doc, NORMAL, 0, &doc->root );

        TY_(PFlushLine)( doc, 0 );
        doc->docOut = NULL;
    }

    TY_(ResetConfigToSnapshot)( doc );
    doc->pConfigChangeCallback = callback;
    
    return tidyDocStatus( doc );
}

/* Tree traversal functions
**
** The big issue here is the degree to which we should mimic
** a DOM and/or SAX nodes.
**
** Is it 100% possible (and, if so, how difficult is it) to
** emit SAX events from this API?  If SAX events are possible,
** is that 100% of data needed to build a DOM?
*/

TidyNode TIDY_CALL   tidyGetRoot( TidyDoc tdoc )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    Node* node = NULL;
    if ( impl )
        node = &impl->root;
    return tidyImplToNode( node );
}

TidyNode TIDY_CALL   tidyGetHtml( TidyDoc tdoc )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  Node* node = NULL;
  if ( impl )
      node = TY_(FindHTML)( impl );
  return tidyImplToNode( node );
}

TidyNode TIDY_CALL    tidyGetHead( TidyDoc tdoc )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  Node* node = NULL;
  if ( impl )
      node = TY_(FindHEAD)( impl );
  return tidyImplToNode( node );
}

TidyNode TIDY_CALL    tidyGetBody( TidyDoc tdoc )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  Node* node = NULL;
  if ( impl )
      node = TY_(FindBody)( impl );
  return tidyImplToNode( node );
}

/* parent / child */
TidyNode TIDY_CALL    tidyGetParent( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  return tidyImplToNode( nimp->parent );
}
TidyNode TIDY_CALL    tidyGetChild( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  return tidyImplToNode( nimp->content );
}

/* remove a node */
TidyNode TIDY_CALL    tidyDiscardElement( TidyDoc tdoc, TidyNode tnod )
{
  TidyDocImpl* doc = tidyDocToImpl( tdoc );
  Node* nimp = tidyNodeToImpl( tnod );
  Node* next = TY_(DiscardElement)( doc, nimp );
  return tidyImplToNode( next );
}

/* siblings */
TidyNode TIDY_CALL    tidyGetNext( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  return tidyImplToNode( nimp->next );
}
TidyNode TIDY_CALL    tidyGetPrev( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  return tidyImplToNode( nimp->prev );
}

/* Node info */
TidyNodeType TIDY_CALL tidyNodeGetType( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  TidyNodeType ntyp = TidyNode_Root;
  if ( nimp )
    ntyp = (TidyNodeType) nimp->type;
  return ntyp;
}

unsigned int TIDY_CALL tidyNodeLine( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  unsigned int line = 0;
  if ( nimp )
    line = nimp->line;
  return line;
}
unsigned int TIDY_CALL tidyNodeColumn( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  unsigned int col = 0;
  if ( nimp )
    col = nimp->column;
  return col;
}

ctmbstr TIDY_CALL tidyNodeGetName( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  ctmbstr nnam = NULL;
  if ( nimp )
    nnam = nimp->element;
  return nnam;
}


Bool TIDY_CALL tidyNodeHasText( TidyDoc tdoc, TidyNode tnod )
{
  TidyDocImpl* doc = tidyDocToImpl( tdoc );
  if ( doc )
      return TY_(nodeHasText)( doc, tidyNodeToImpl(tnod) );
  return no;
}


Bool TIDY_CALL tidyNodeGetText( TidyDoc tdoc, TidyNode tnod, TidyBuffer* outbuf )
{
  TidyDocImpl* doc = tidyDocToImpl( tdoc );
  Node* nimp = tidyNodeToImpl( tnod );
  if ( doc && nimp && outbuf )
  {
      unsigned int outenc     = cfg( doc, TidyOutCharEncoding );
      unsigned int nl         = cfg( doc, TidyNewline );
      StreamOut* out  = TY_(BufferOutput)( doc, outbuf, outenc, nl );
      Bool xmlOut     = cfgBool( doc, TidyXmlOut );
      Bool xhtmlOut   = cfgBool( doc, TidyXhtmlOut );

      doc->docOut = out;
      if ( xmlOut && !xhtmlOut )
          TY_(PPrintXMLTree)( doc, NORMAL, 0, nimp );
      else
          TY_(PPrintTree)( doc, NORMAL, 0, nimp );

      TY_(PFlushLine)( doc, 0 );
      doc->docOut = NULL;

      TidyDocFree( doc, out );
      return yes;
  }
  return no;
}

Bool TIDY_CALL tidyNodeGetValue( TidyDoc tdoc, TidyNode tnod, TidyBuffer* buf )
{
    TidyDocImpl *doc = tidyDocToImpl( tdoc );
    Node *node = tidyNodeToImpl( tnod );
    if ( doc == NULL || node == NULL || buf == NULL )
        return no;

    switch( node->type ) {
    case TextNode:
    case CDATATag:
    case CommentTag:
    case ProcInsTag:
    case SectionTag:
    case AspTag:
    case JsteTag:
    case PhpTag:
    {
        tidyBufClear( buf );
        tidyBufAppend( buf, doc->lexer->lexbuf + node->start,
                       node->end - node->start );
        break;
    }
    default:
        /* The node doesn't have a value */
        return no;
    }

    return yes;
}

Bool TIDY_CALL tidyNodeIsProp( TidyDoc ARG_UNUSED(tdoc), TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  Bool isProprietary = yes;
  if ( nimp )
  {
    switch ( nimp->type )
    {
    case RootNode:
    case DocTypeTag:
    case CommentTag:
    case XmlDecl:
    case ProcInsTag:
    case TextNode:
    case CDATATag:
        isProprietary = no;
        break;

    case SectionTag:
    case AspTag:
    case JsteTag:
    case PhpTag:
        isProprietary = yes;
        break;

    case StartTag:
    case EndTag:
    case StartEndTag:
        isProprietary = ( nimp->tag
                          ? (nimp->tag->versions&VERS_PROPRIETARY)!=0
                          : yes );
        break;
    }
  }
  return isProprietary;
}

TidyTagId TIDY_CALL tidyNodeGetId(TidyNode tnod)
{
    Node* nimp = tidyNodeToImpl(tnod);

    TidyTagId tagId = TidyTag_UNKNOWN;
    if (nimp && nimp->tag)
        tagId = nimp->tag->id;

    return tagId;
}


/* Iterate over attribute values */
TidyAttr TIDY_CALL   tidyAttrFirst( TidyNode tnod )
{
  Node* nimp = tidyNodeToImpl( tnod );
  AttVal* attval = NULL;
  if ( nimp )
    attval = nimp->attributes;
  return tidyImplToAttr( attval );
}
TidyAttr TIDY_CALL    tidyAttrNext( TidyAttr tattr )
{
  AttVal* attval = tidyAttrToImpl( tattr );
  AttVal* nxtval = NULL;
  if ( attval )
    nxtval = attval->next;
  return tidyImplToAttr( nxtval );
}

ctmbstr TIDY_CALL       tidyAttrName( TidyAttr tattr )
{
  AttVal* attval = tidyAttrToImpl( tattr );
  ctmbstr anam = NULL;
  if ( attval )
    anam = attval->attribute;
  return anam;
}
ctmbstr TIDY_CALL       tidyAttrValue( TidyAttr tattr )
{
  AttVal* attval = tidyAttrToImpl( tattr );
  ctmbstr aval = NULL;
  if ( attval )
    aval = attval->value;
  return aval;
}

void TIDY_CALL           tidyAttrDiscard( TidyDoc tdoc, TidyNode tnod, TidyAttr tattr )
{
  TidyDocImpl* impl = tidyDocToImpl( tdoc );
  Node* nimp = tidyNodeToImpl( tnod );
  AttVal* attval = tidyAttrToImpl( tattr );
  TY_(RemoveAttribute)( impl, nimp, attval );
}

TidyAttrId TIDY_CALL tidyAttrGetId( TidyAttr tattr )
{
  AttVal* attval = tidyAttrToImpl( tattr );
  TidyAttrId attrId = TidyAttr_UNKNOWN;
  if ( attval && attval->dict )
    attrId = attval->dict->id;
  return attrId;
}

TidyAttr TIDY_CALL tidyAttrGetById( TidyNode tnod, TidyAttrId attId )
{
    Node* nimp = tidyNodeToImpl(tnod);
    return tidyImplToAttr( TY_(AttrGetById)( nimp, attId ) );
}


Bool TIDY_CALL tidyAttrIsEvent( TidyAttr tattr )
{
    return TY_(attrIsEvent)( tidyAttrToImpl(tattr) );
}


/*******************************************************************
 ** Message Key Management
 *******************************************************************/
ctmbstr TIDY_CALL tidyErrorCodeAsKey(unsigned int code)
{
    return TY_(tidyErrorCodeAsKey)( code );
}

unsigned int TIDY_CALL tidyErrorCodeFromKey(ctmbstr code)
{
    return TY_(tidyErrorCodeFromKey)( code );
}

TidyIterator TIDY_CALL getErrorCodeList()
{
    return TY_(getErrorCodeList)();
}

unsigned int TIDY_CALL getNextErrorCode( TidyIterator* iter )
{
    return TY_(getNextErrorCode)(iter);
}


/*******************************************************************
 ** Localization Support
 *******************************************************************/


Bool TIDY_CALL tidySetLanguage( ctmbstr languageCode )
{
    Bool result = TY_(tidySetLanguage)( languageCode );

    if ( result )
        TY_(tidySetLanguageSetByUser)();

    return result;
}

ctmbstr TIDY_CALL tidyGetLanguage()
{
    return TY_(tidyGetLanguage)();
}

ctmbstr TIDY_CALL tidyLocalizedStringN( unsigned int messageType, unsigned int quantity )
{
    return TY_(tidyLocalizedStringN)( messageType, quantity);
}

ctmbstr TIDY_CALL tidyLocalizedString( unsigned int messageType )
{
    return TY_(tidyLocalizedString)( messageType );
}

ctmbstr TIDY_CALL tidyDefaultString( unsigned int messageType )
{
    return TY_(tidyDefaultString)( messageType );
}

TidyIterator TIDY_CALL getStringKeyList()
{
    return TY_(getStringKeyList)();
}

unsigned int TIDY_CALL getNextStringKey( TidyIterator* iter )
{
    return TY_(getNextStringKey)( iter );
}

TidyIterator TIDY_CALL getWindowsLanguageList()
{
    return TY_(getWindowsLanguageList)();
}

//#define tidyOptionToImpl( topt )    ((const TidyOptionImpl*)(topt))
//#define tidyImplToOption( option )  ((TidyOption)(option))

const tidyLocaleMapItem* TIDY_CALL getNextWindowsLanguage( TidyIterator* iter )
{
    /* Get a real structure */
    const tidyLocaleMapItemImpl *item = TY_(getNextWindowsLanguage)( iter );

    /* Return it as the opaque version */
    return ((tidyLocaleMapItem*)(item));
}


ctmbstr TIDY_CALL TidyLangWindowsName( const tidyLocaleMapItem *item )
{
    return TY_(TidyLangWindowsName)( (tidyLocaleMapItemImpl*)(item) );
}


ctmbstr TIDY_CALL TidyLangPosixName( const tidyLocaleMapItem *item )
{
    return TY_(TidyLangPosixName)( (tidyLocaleMapItemImpl*)(item) );
}


TidyIterator TIDY_CALL getInstalledLanguageList()
{
    return TY_(getInstalledLanguageList)();
}


ctmbstr TIDY_CALL getNextInstalledLanguage( TidyIterator* iter )
{
    return TY_(getNextInstalledLanguage)( iter );
}




/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* tmbstr.c -- Tidy string utility functions

  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

*/

/* #include "forward.h" */
/* #include "tmbstr.h" */
/* #include "lexer.h" */

/* like strdup but using an allocator */
tmbstr TY_(tmbstrdup)( TidyAllocator *allocator, ctmbstr str )
{
    tmbstr s = NULL;
    if ( str )
    {
        unsigned int len = TY_(tmbstrlen)( str );
        tmbstr cp = s = (tmbstr) TidyAlloc( allocator, 1+len );
        while ( 0 != (*cp++ = *str++) )
            /**/;
    }
    return s;
}

/* like strndup but using an allocator */
tmbstr TY_(tmbstrndup)( TidyAllocator *allocator, ctmbstr str, unsigned int len )
{
    tmbstr s = NULL;
    if ( str && len > 0 )
    {
        tmbstr cp = s = (tmbstr) TidyAlloc( allocator, 1+len );
        while ( len-- > 0 &&  (*cp++ = *str++) )
          /**/;
        *cp = 0;
    }
    return s;
}

/* exactly same as strncpy */
unsigned int TY_(tmbstrncpy)( tmbstr s1, ctmbstr s2, unsigned int size )
{
    if ( s1 != NULL && s2 != NULL )
    {
        tmbstr cp = s1;
        while ( *s2 && --size )  /* Predecrement: reserve byte */
            *cp++ = *s2++;       /* for NULL terminator. */
        *cp = 0;
    }
    return size;
}

/* Allows expressions like:  cp += tmbstrcpy( cp, "joebob" );
*/
unsigned int TY_(tmbstrcpy)( tmbstr s1, ctmbstr s2 )
{
    unsigned int ncpy = 0;
    while (0 != (*s1++ = *s2++) )
        ++ncpy;
    return ncpy;
}

/* Allows expressions like:  cp += tmbstrcat( cp, "joebob" );
*/
unsigned int TY_(tmbstrcat)( tmbstr s1, ctmbstr s2 )
{
    unsigned int ncpy = 0;
    while ( *s1 )
        ++s1;

    while (0 != (*s1++ = *s2++) )
        ++ncpy;
    return ncpy;
}

/* exactly same as strcmp */
int TY_(tmbstrcmp)( ctmbstr s1, ctmbstr s2 )
{
    int c;
    while ((c = *s1) == *s2)
    {
        if (c == '\0')
            return 0;

        ++s1;
        ++s2;
    }

    return (*s1 > *s2 ? 1 : -1);
}

/* returns byte count, not char count */
unsigned int TY_(tmbstrlen)( ctmbstr str )
{
    unsigned int len = 0;
    if ( str ) 
    {
        while ( *str++ )
            ++len;
    }
    return len;
}

/*
 MS C 4.2 (and ANSI C) doesn't include strcasecmp.
 Note that tolower and toupper won't
 work on chars > 127.

 Neither does ToLower()!
*/
int TY_(tmbstrcasecmp)( ctmbstr s1, ctmbstr s2 )
{
    unsigned int c;

    while (c = (unsigned int)(*s1), TY_(ToLower)(c) == TY_(ToLower)((unsigned int)(*s2)))
    {
        if (c == '\0')
            return 0;

        ++s1;
        ++s2;
    }

    return (*s1 > *s2 ? 1 : -1);
}

int TY_(tmbstrncmp)( ctmbstr s1, ctmbstr s2, unsigned int n )
{
    unsigned int c;

	if (s1 == NULL || s2 == NULL)
    {
        if (s1 == s2)
            return 0;
        return (s1 == NULL ? -1 : 1);
    }

    while ((c = (byte)*s1) == (byte)*s2)
    {
        if (c == '\0')
            return 0;

        if (n == 0)
            return 0;

        ++s1;
        ++s2;
        --n;
    }

    if (n == 0)
        return 0;

    return (*s1 > *s2 ? 1 : -1);
}

int TY_(tmbstrncasecmp)( ctmbstr s1, ctmbstr s2, unsigned int n )
{
    unsigned int c;

    while (c = (unsigned int)(*s1), TY_(ToLower)(c) == TY_(ToLower)((unsigned int)(*s2)))
    {
        if (c == '\0')
            return 0;

        if (n == 0)
            return 0;

        ++s1;
        ++s2;
        --n;
    }

    if (n == 0)
        return 0;

    return (*s1 > *s2 ? 1 : -1);
}

ctmbstr TY_(tmbsubstrn)( ctmbstr s1, unsigned int len1, ctmbstr s2 )
{
    unsigned int len2 = TY_(tmbstrlen)(s2);
    int ix, diff = len1 - len2;

    for ( ix = 0; ix <= diff; ++ix )
    {
        if ( TY_(tmbstrncmp)(s1+ix, s2, len2) == 0 )
            return (ctmbstr) s1+ix;
    }
    return NULL;
}

ctmbstr TY_(tmbsubstr)( ctmbstr s1, ctmbstr s2 )
{
    unsigned int len1 = TY_(tmbstrlen)(s1), len2 = TY_(tmbstrlen)(s2);
    int ix, diff = len1 - len2;

    for ( ix = 0; ix <= diff; ++ix )
    {
        if ( TY_(tmbstrncasecmp)(s1+ix, s2, len2) == 0 )
            return (ctmbstr) s1+ix;
    }
    return NULL;
}

/* Transform ASCII chars in string to lower case */
tmbstr TY_(tmbstrtolower)( tmbstr s )
{
    tmbstr cp;
    for ( cp=s; *cp; ++cp )
        *cp = (tmbchar) TY_(ToLower)( *cp );
    return s;
}

/* Transform ASCII chars in string to upper case */
tmbstr TY_(tmbstrtoupper)(tmbstr s)
{
    tmbstr cp;

    for (cp = s; *cp; ++cp)
        *cp = (tmbchar)TY_(ToUpper)(*cp);

    return s;
}

int TY_(tmbvsnprintf)(tmbstr buffer, size_t count, ctmbstr format, va_list args)
{
    int retval;

#if HAS_VSNPRINTF
    retval = vsnprintf(buffer, count - 1, format, args);
    /* todo: conditionally null-terminate the string? */
    buffer[count - 1] = 0;
#else
    retval = vsprintf(buffer, format, args);
#endif /* HAS_VSNPRINTF */
    return retval;
}

int TY_(tmbsnprintf)(tmbstr buffer, size_t count, ctmbstr format, ...)
{
    int retval;
    va_list args;
    va_start(args, format);
    retval = TY_(tmbvsnprintf)(buffer, count, format, args);
    va_end(args);
    return retval;
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* utf8.c -- convert characters to/from UTF-8

  (c) 1998-2007 (W3C) MIT, ERCIM, Keio University
  See tidy.h for the copyright notice.

  Uses public interfaces to abstract input source and output
  sink, which may be user supplied or either FILE* or memory
  based Tidy implementations.  Encoding support is uniform
  regardless of I/O mechanism.

  Note, UTF-8 encoding, by itself, does not affect the actual
  "codepoints" of the underlying character encoding.  In the
  cases of ASCII, Latin1, Unicode (16-bit, BMP), these all 
  refer to ISO-10646 "codepoints".  For anything else, they
  refer to some other "codepoint" set.

  Put another way, UTF-8 is a variable length method to 
  represent any non-negative integer value.  The glyph 
  that a integer value represents is unchanged and defined
  externally (e.g. by ISO-10646, Big5, Win1252, MacRoman,
  Latin2-9, and so on).

  Put still another way, UTF-8 is more of a _transfer_ encoding
  than a _character_ encoding, per se.
*/

/* #include "tidy.h" */
/* #include "forward.h" */
/* #include "utf8.h" */

/* 
UTF-8 encoding/decoding functions
Return # of bytes in UTF-8 sequence; result < 0 if illegal sequence

Also see below for UTF-16 encoding/decoding functions

References :

1) UCS Transformation Format 8 (UTF-8):
ISO/IEC 10646-1:1996 Amendment 2 or ISO/IEC 10646-1:2000 Annex D
<http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335>
<http://www.cl.cam.ac.uk/~mgk25/ucs/ISO-10646-UTF-8.html>

Table 4 - Mapping from UCS-4 to UTF-8

2) Unicode standards:
<http://www.unicode.org/unicode/standard/standard.html>

3) Legal UTF-8 byte sequences:
<http://www.unicode.org/unicode/uni2errata/UTF-8_Corrigendum.html>

Code point          1st byte    2nd byte    3rd byte    4th byte
----------          --------    --------    --------    --------
U+0000..U+007F      00..7F
U+0080..U+07FF      C2..DF      80..BF
U+0800..U+0FFF      E0          A0..BF      80..BF
U+1000..U+FFFF      E1..EF      80..BF      80..BF
U+10000..U+3FFFF    F0          90..BF      80..BF      80..BF
U+40000..U+FFFFF    F1..F3      80..BF      80..BF      80..BF
U+100000..U+10FFFF  F4          80..8F      80..BF      80..BF

The definition of UTF-8 in Annex D of ISO/IEC 10646-1:2000 also
allows for the use of five- and six-byte sequences to encode
characters that are outside the range of the Unicode character
set; those five- and six-byte sequences are illegal for the use
of UTF-8 as a transformation of Unicode characters. ISO/IEC 10646
does not allow mapping of unpaired surrogates, nor U+FFFE and U+FFFF
(but it does allow other noncharacters).

4) RFC 2279: UTF-8, a transformation format of ISO 10646:
<http://www.ietf.org/rfc/rfc2279.txt>

5) UTF-8 and Unicode FAQ:
<http://www.cl.cam.ac.uk/~mgk25/unicode.html>

6) Markus Kuhn's UTF-8 decoder stress test file:
<http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt>

7) UTF-8 Demo:
<http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt>

8) UTF-8 Sampler:
<http://www.columbia.edu/kermit/utf8.html>

9) Transformation Format for 16 Planes of Group 00 (UTF-16):
ISO/IEC 10646-1:1996 Amendment 1 or ISO/IEC 10646-1:2000 Annex C
<http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n2005/n2005.pdf>
<http://www.cl.cam.ac.uk/~mgk25/ucs/ISO-10646-UTF-16.html>

10) RFC 2781: UTF-16, an encoding of ISO 10646:
<http://www.ietf.org/rfc/rfc2781.txt>

11) UTF-16 invalid surrogate pairs:
<http://www.unicode.org/unicode/faq/utf_bom.html#16>

UTF-16       UTF-8          UCS-4
D83F DFF*    F0 9F BF B*    0001FFF*
D87F DFF*    F0 AF BF B*    0002FFF*
D8BF DFF*    F0 BF BF B*    0003FFF*
D8FF DFF*    F1 8F BF B*    0004FFF*
D93F DFF*    F1 9F BF B*    0005FFF*
D97F DFF*    F1 AF BF B*    0006FFF*
                ...
DBBF DFF*    F3 BF BF B*    000FFFF*
DBFF DFF*    F4 8F BF B*    0010FFF*

* = E or F
                                   
1010  A
1011  B
1100  C
1101  D
1110  E
1111  F

*/

#define kNumUTF8Sequences        7
#define kMaxUTF8Bytes            4

#define kUTF8ByteSwapNotAChar    0xFFFE
#define kUTF8NotAChar            0xFFFF

#define kMaxUTF8FromUCS4         0x10FFFF

#define kUTF16SurrogatesBegin    0x10000
#define kMaxUTF16FromUCS4        0x10FFFF

/* UTF-16 surrogate pair areas */
#define kUTF16LowSurrogateBegin  0xD800
#define kUTF16LowSurrogateEnd    0xDBFF
#define kUTF16HighSurrogateBegin 0xDC00
#define kUTF16HighSurrogateEnd   0xDFFF


/* offsets into validUTF8 table below */
static const int offsetUTF8Sequences[kMaxUTF8Bytes + 1] =
{
    0, /* 1 byte */
    1, /* 2 bytes */
    2, /* 3 bytes */
    4, /* 4 bytes */
    kNumUTF8Sequences /* must be last */
};

static const struct validUTF8Sequence
{
     unsigned int lowChar;
     unsigned int highChar;
     int  numBytes;
     byte validBytes[8];
} validUTF8[kNumUTF8Sequences] =
{
/*   low       high   #bytes  byte 1      byte 2      byte 3      byte 4 */
    {0x0000,   0x007F,   1, {0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
    {0x0080,   0x07FF,   2, {0xC2, 0xDF, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00}},
    {0x0800,   0x0FFF,   3, {0xE0, 0xE0, 0xA0, 0xBF, 0x80, 0xBF, 0x00, 0x00}},
    {0x1000,   0xFFFF,   3, {0xE1, 0xEF, 0x80, 0xBF, 0x80, 0xBF, 0x00, 0x00}},
    {0x10000,  0x3FFFF,  4, {0xF0, 0xF0, 0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}},
    {0x40000,  0xFFFFF,  4, {0xF1, 0xF3, 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}},
    {0x100000, 0x10FFFF, 4, {0xF4, 0xF4, 0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}} 
};

int TY_(DecodeUTF8BytesToChar)( unsigned int* c, unsigned int firstByte, ctmbstr successorBytes,
                                TidyInputSource* inp, int* count )
{
    byte tempbuf[10];
    byte *buf = &tempbuf[0];
    unsigned int ch = 0, n = 0;
    int i, bytes = 0;
    Bool hasError = no;
    
    if ( successorBytes )
        buf = (byte*) successorBytes;
        
    /* special check if we have been passed an EOF char */
    if ( firstByte == EndOfStream )
    {
        /* at present */
        *c = firstByte;
        *count = 1;
        return 0;
    }

    ch = firstByte; /* first byte is passed in separately */
    
    if (ch <= 0x7F) /* 0XXX XXXX one byte */
    {
        n = ch;
        bytes = 1;
    }
    else if ((ch & 0xE0) == 0xC0)  /* 110X XXXX  two bytes */
    {
        n = ch & 31;
        bytes = 2;
    }
    else if ((ch & 0xF0) == 0xE0)  /* 1110 XXXX  three bytes */
    {
        n = ch & 15;
        bytes = 3;
    }
    else if ((ch & 0xF8) == 0xF0)  /* 1111 0XXX  four bytes */
    {
        n = ch & 7;
        bytes = 4;
    }
    else if ((ch & 0xFC) == 0xF8)  /* 1111 10XX  five bytes */
    {
        n = ch & 3;
        bytes = 5;
        hasError = yes;
    }
    else if ((ch & 0xFE) == 0xFC)  /* 1111 110X  six bytes */
    {
        n = ch & 1;
        bytes = 6;
        hasError = yes;
    }
    else
    {
        /* not a valid first byte of a UTF-8 sequence */
        n = ch;
        bytes = 1;
        hasError = yes;
    }

    /* successor bytes should have the form 10XX XXXX */

    /* If caller supplied buffer, use it.  Else see if caller
    ** supplied an input source, use that.
    */
    if ( successorBytes )
    {
        for ( i=0; i < bytes-1; ++i )
        {
            if ( !buf[i] || (buf[i] & 0xC0) != 0x80 )
            {
                hasError = yes;
                bytes = i+1;
                break;
            }
            n = (n << 6) | (buf[i] & 0x3F);
        }
    }
    else if ( inp )
    {
        for ( i=0; i < bytes-1 && !inp->eof(inp->sourceData); ++i )
        {
            int b = inp->getByte( inp->sourceData );
            buf[i] = (tmbchar) b;

            /* End of data or illegal successor byte value */
            if ( b == EOF || (buf[i] & 0xC0) != 0x80 )
            {
                hasError = yes;
                bytes = i+1;
                if ( b != EOF )
                    inp->ungetByte( inp->sourceData, buf[i] );
                break;
            }
            n = (n << 6) | (buf[i] & 0x3F);
        }
    }
    else if ( bytes > 1 )
    {
        hasError = yes;
        bytes = 1;
    }
    
    if (!hasError && ((n == kUTF8ByteSwapNotAChar) || (n == kUTF8NotAChar)))
        hasError = yes;
        
    if (!hasError && (n > kMaxUTF8FromUCS4))
        hasError = yes;

    if (!hasError)
    {
        int lo, hi;
        
        lo = offsetUTF8Sequences[bytes - 1];
        hi = offsetUTF8Sequences[bytes] - 1;
        
        /* check for overlong sequences */
        if ((n < validUTF8[lo].lowChar) || (n > validUTF8[hi].highChar))
            hasError = yes;
        else
        {
            hasError = yes; /* assume error until proven otherwise */
        
            for (i = lo; i <= hi; i++)
            {
                int tempCount;
                byte theByte;
                
                for (tempCount = 0; tempCount < bytes; tempCount++)
                {
                    if (!tempCount)
                        theByte = (tmbchar) firstByte;
                    else
                        theByte = buf[tempCount - 1];
                        
                    if ( theByte >= validUTF8[i].validBytes[(tempCount * 2)] &&
                         theByte <= validUTF8[i].validBytes[(tempCount * 2) + 1] )
                        hasError = no;
                    if (hasError)
                        break;
                }
            }
        }
    }

#if 1 && defined(_DEBUG)
    if ( hasError )
    {
       /* debug */
       fprintf( stderr, "UTF-8 decoding error of %d bytes : ", bytes );
       fprintf( stderr, "0x%02x ", firstByte );
       for (i = 1; i < bytes; i++)
           fprintf( stderr, "0x%02x ", buf[i - 1] );
       fprintf( stderr, " = U+%04ulx\n", n );
    }
#endif

    *count = bytes;
    *c = n;
    if ( hasError )
        return -1;
    return 0;
}

int TY_(EncodeCharToUTF8Bytes)( unsigned int c, tmbstr encodebuf,
                                TidyOutputSink* outp, int* count )
{
    byte tempbuf[10] = {0};
    byte* buf = &tempbuf[0];
    int bytes = 0;
    Bool hasError = no;
    
    if ( encodebuf )
        buf = (byte*) encodebuf;
        
    if (c <= 0x7F)  /* 0XXX XXXX one byte */
    {
        buf[0] = (tmbchar) c;
        bytes = 1;
    }
    else if (c <= 0x7FF)  /* 110X XXXX  two bytes */
    {
        buf[0] = (tmbchar) ( 0xC0 | (c >> 6) );
        buf[1] = (tmbchar) ( 0x80 | (c & 0x3F) );
        bytes = 2;
    }
    else if (c <= 0xFFFF)  /* 1110 XXXX  three bytes */
    {
        buf[0] = (tmbchar) (0xE0 | (c >> 12));
        buf[1] = (tmbchar) (0x80 | ((c >> 6) & 0x3F));
        buf[2] = (tmbchar) (0x80 | (c & 0x3F));
        bytes = 3;
        if ( c == kUTF8ByteSwapNotAChar || c == kUTF8NotAChar )
            hasError = yes;
    }
    else if (c <= 0x1FFFFF)  /* 1111 0XXX  four bytes */
    {
        buf[0] = (tmbchar) (0xF0 | (c >> 18));
        buf[1] = (tmbchar) (0x80 | ((c >> 12) & 0x3F));
        buf[2] = (tmbchar) (0x80 | ((c >> 6) & 0x3F));
        buf[3] = (tmbchar) (0x80 | (c & 0x3F));
        bytes = 4;
        if (c > kMaxUTF8FromUCS4)
            hasError = yes;
    }
    else if (c <= 0x3FFFFFF)  /* 1111 10XX  five bytes */
    {
        buf[0] = (tmbchar) (0xF8 | (c >> 24));
        buf[1] = (tmbchar) (0x80 | (c >> 18));
        buf[2] = (tmbchar) (0x80 | ((c >> 12) & 0x3F));
        buf[3] = (tmbchar) (0x80 | ((c >> 6) & 0x3F));
        buf[4] = (tmbchar) (0x80 | (c & 0x3F));
        bytes = 5;
        hasError = yes;
    }
    else if (c <= 0x7FFFFFFF)  /* 1111 110X  six bytes */
    {
        buf[0] = (tmbchar) (0xFC | (c >> 30));
        buf[1] = (tmbchar) (0x80 | ((c >> 24) & 0x3F));
        buf[2] = (tmbchar) (0x80 | ((c >> 18) & 0x3F));
        buf[3] = (tmbchar) (0x80 | ((c >> 12) & 0x3F));
        buf[4] = (tmbchar) (0x80 | ((c >> 6) & 0x3F));
        buf[5] = (tmbchar) (0x80 | (c & 0x3F));
        bytes = 6;
        hasError = yes;
    }
    else
        hasError = yes;
        
    /* don't output invalid UTF-8 byte sequence to a stream */
    if ( !hasError && outp != NULL )
    {
        int ix;
        for ( ix=0; ix < bytes; ++ix )
          outp->putByte( outp->sinkData, buf[ix] );
    }

#if 1 && defined(_DEBUG)
    if ( hasError )
    {
        int i;
        fprintf( stderr, "UTF-8 encoding error for U+%x : ", c );
        for (i = 0; i < bytes; i++)
            fprintf( stderr, "0x%02x ", buf[i] );
        fprintf( stderr, "\n" );
    }
#endif
    
    *count = bytes;
    if (hasError)
        return -1;
    return 0;
}


/* return one less than the number of bytes used by the UTF-8 byte sequence */
/* str points to the UTF-8 byte sequence */
/* the Unicode char is returned in *ch */
unsigned int TY_(GetUTF8)( ctmbstr str, unsigned int *ch )
{
    unsigned int n;
    int bytes;

    int err;
    
    bytes = 0;
    
    /* first byte "str[0]" is passed in separately from the */
    /* rest of the UTF-8 byte sequence starting at "str[1]" */
    err = TY_(DecodeUTF8BytesToChar)( &n, str[0], str+1, NULL, &bytes );
    if (err)
    {
#if 1 && defined(_DEBUG)
        fprintf(stderr, "pprint UTF-8 decoding error for U+%x : ", n);
#endif
        n = 0xFFFD; /* replacement char */
    }

    *ch = n;
    return bytes - 1;
}

/* store char c as UTF-8 encoded byte stream */
tmbstr TY_(PutUTF8)( tmbstr buf, unsigned int c )
{
    int err, count = 0;
        
    err = TY_(EncodeCharToUTF8Bytes)( c, buf, NULL, &count );
    if (err)
    {
#if 1 && defined(_DEBUG)
        fprintf(stderr, "pprint UTF-8 encoding error for U+%x : ", c);
#endif
        /* replacement char 0xFFFD encoded as UTF-8 */
        buf[0] = (byte) 0xEF;
        buf[1] = (byte) 0xBF;
        buf[2] = (byte) 0xBD;
        count = 3;
    }
    
    buf += count;
    return buf;
}

Bool    TY_(IsValidUTF16FromUCS4)( tchar ucs4 )
{
  return ( ucs4 <= kMaxUTF16FromUCS4 );
}

Bool    TY_(IsHighSurrogate)( tchar ch )
{
    return ( ch >= kUTF16HighSurrogateBegin && ch <= kUTF16HighSurrogateEnd );
}
Bool    TY_(IsLowSurrogate)( tchar ch )
{
    return ( ch >= kUTF16LowSurrogateBegin && ch <= kUTF16LowSurrogateEnd );
}

tchar   TY_(CombineSurrogatePair)( tchar high, tchar low )
{
    assert( TY_(IsHighSurrogate)(high) && TY_(IsLowSurrogate)(low) );
    return ( ((low - kUTF16LowSurrogateBegin) * 0x400) + 
             high - kUTF16HighSurrogateBegin + 0x10000 );
}

Bool   TY_(SplitSurrogatePair)( tchar utf16, tchar* low, tchar* high )
{
    Bool status = ( TY_(IsValidCombinedChar)( utf16 ) && high && low );
    if ( status )
    {
        *low  = (utf16 - kUTF16SurrogatesBegin) / 0x400 + kUTF16LowSurrogateBegin;
        *high = (utf16 - kUTF16SurrogatesBegin) % 0x400 + kUTF16HighSurrogateBegin;
    }
    return status;
}

Bool    TY_(IsValidCombinedChar)( tchar ch )
{
    return ( ch >= kUTF16SurrogatesBegin &&
             (ch & 0x0000FFFE) != 0x0000FFFE &&
             (ch & 0x0000FFFF) != 0x0000FFFF );
}

Bool    TY_(IsCombinedChar)( tchar ch )
{
    return ( ch >= kUTF16SurrogatesBegin );
}

/*
 * DISABLEDLOCALVARIABLES
 * mode: c
 * indent-tabs-mode: nil
 * c-basic-offset: 4
 * eval: (c-set-offset 'substatement-open 0)
 * end:
 */
/* ------------------------------------------------------- */

/* The following routines are not part of HTML Tidy, they are
   additions for the HTML::Valid Perl module. */

/* Set the file name. */

void SetFilename( TidyDoc tdoc, ctmbstr filename )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    TY_(SetOptionBool)( impl, TidyEmacs, yes );
    SetOptionValue( impl, TidyEmacsFile, filename );
}

/* Avoid segmentation fault errors which occur due to allocator not
   being set. */

void CopyAllocator( TidyDoc tdoc, TidyBuffer * buf )
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    buf->allocator = impl->allocator;
}

#ifdef HEADER

typedef struct html_valid_tag {
    const char * name;
    unsigned int versions;
    unsigned int model;
}
html_valid_tag_t;

#endif /* def HEADER */

/* We have to subtract 1 from this due to the use of a NULL in the
   final line of tag_defs. */

const int n_html_tags = (sizeof (tag_defs) / sizeof (Dict) - 1);
const int n_attributes = (sizeof (attribute_defs) / sizeof (Attribute) - 1);

/* Export the tag information. */

void TagInformation (html_valid_tag_t * tags)
{
    int i;
    for (i = 0; i < n_html_tags; i++) {
	tags[i].name = tag_defs[i].name;
	tags[i].versions = tag_defs[i].versions;
	tags[i].model = tag_defs[i].model;
    }
}

/* Given a tag id (offset in tag_defs array) and a version bitmap in
   "version", put the attributes for that tag and version into
   "yes_no" where applicable, and the number of tags into
   "n_attr_ptr". */

void TagAttributes (unsigned int tag_id, unsigned int version,
		    const char ** yes_no, int * n_attr_ptr)
{
    int i;
    Dict * tag_def;
    AttrVersion const * attrvers;
    int n_attr;
    if (tag_id >= n_html_tags) {
	fprintf (stderr, "%s:%d: bad tag id %d\n",
		 __FILE__, __LINE__, tag_id);
	return;
    }
    tag_def = & tag_defs[tag_id];
    attrvers = tag_def->attrvers;
    n_attr = 0;
    /* Blank out all the attributes. */
    for (i = 0; i < n_attributes; i++) {
	yes_no[i] = 0;
    }
    for (i = 0; attrvers[i].attribute != TidyAttr_UNKNOWN; i++) {
	if (version & attrvers[i].versions) {
	    int attribute;
	    char * name;
	    attribute = attrvers[i].attribute;

	    /* First check that the number "attribute" makes sense. */

	    if (attribute >= n_attributes || attribute < 0) {
		fprintf (stderr, "%s:%d: Attribute %d of %d "
			 "has attribute id %d "
			 "overflowing the maximum value %d.\n",
			 __FILE__, __LINE__,
			 i, tag_id, attribute, n_attributes);
		return;
	    }
	    name = attribute_defs[attribute].name;

	    if (! yes_no[attribute]) {
		yes_no[attribute] = name;
		n_attr++;
	    }
	}
    }
    * n_attr_ptr = n_attr;
}

/* Make a list of all of the attributes. */

void TagAllAttributes (const char ** yes_no)
{
    int i;
    for (i = 0; i < n_attributes; i++) {
	yes_no[i] = attribute_defs[i].name;
    }
}
#if 0
void get_option_doc (TidyOptionId ti, const char ** doc, const TidyOptionId ** xrefs)
{
    int i;
    for (i = 0; i < sizeof (option_defs) / sizeof (TidyOptionDoc); i++) {
	if (ti == option_defs[i].opt) {
	    * doc = option_defs[i].doc;
	    * xrefs = option_defs[i].links;
	    return;
	}
    }
    * doc = 0;
    * xrefs = 0;
    fprintf (stderr, "no doc for id %d\n", ti);
}

/* Reset the error counters back to zero. This doesn't seem to be
   available in the API, so after parsing a file with an error, the
   next file is listed as having an error too. Thus basically a tdoc
   becomes non-functional after reading a file with an error. It seems
   too obvious a bug to have been neglected, but I cannot find
   anywhere in the API which does this trivial task. */

void reset_doc (TidyDoc tdoc)
{
    TidyDocImpl* impl = tidyDocToImpl( tdoc );
    impl->errors = 0;
    impl->warnings = 0;
    impl->accessErrors = 0;
    impl->docErrors = 0;
}

#endif /* 0 */
/* This works around compilation problems caused by three layers of
   macros in the original project. */

#if !SUPPORT_POSIX_MAPPED_FILES

void TY_(freeFileSource)( TidyInputSource* source, Bool closeIt )
{
    TY_(freeFileSource_fileio_c) (source, closeIt);
}

int TY_(initFileSource)(TidyAllocator * allocator, TidyInputSource* source, FILE * fp)
{
    return TY_(initFileSource_fileio_c) (allocator, source, fp);
}

#endif
