~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

TidyLib
tidy/src/attrs.c

Version: ~ [ 1.0 ] ~

  1 /* attrs.c -- recognize HTML attributes
  2 
  3   (c) 1998-2005 (W3C) MIT, ERCIM, Keio University
  4   See tidy.h for the copyright notice.
  5   
  6   CVS Info :
  7 
  8     $Author: arnaud02 $ 
  9     $Date: 2005/09/20 09:03:17 $ 
 10     $Revision: 1.115 $ 
 11 
 12 */
 13 
 14 #include "tidy-int.h"
 15 #include "attrs.h"
 16 #include "message.h"
 17 #include "tmbstr.h"
 18 #include "utf8.h"
 19 
 20 static AttrCheck CheckAction;
 21 
 22 #define CH_PCDATA      NULL
 23 #define CH_CHARSET     NULL
 24 #define CH_TYPE        CheckType
 25 #define CH_XTYPE       NULL
 26 #define CH_CHARACTER   NULL
 27 #define CH_URLS        NULL
 28 #define CH_URL         CheckUrl
 29 #define CH_SCRIPT      CheckScript
 30 #define CH_ALIGN       CheckAlign
 31 #define CH_VALIGN      CheckValign
 32 #define CH_COLOR       CheckColor
 33 #define CH_CLEAR       CheckClear
 34 #define CH_BORDER      CheckBool     /* kludge */
 35 #define CH_LANG        CheckLang
 36 #define CH_BOOL        CheckBool
 37 #define CH_COLS        NULL
 38 #define CH_NUMBER      CheckNumber
 39 #define CH_LENGTH      CheckLength
 40 #define CH_COORDS      NULL
 41 #define CH_DATE        NULL
 42 #define CH_TEXTDIR     CheckTextDir
 43 #define CH_IDREFS      NULL
 44 #define CH_IDREF       NULL
 45 #define CH_IDDEF       CheckId
 46 #define CH_NAME        CheckName
 47 #define CH_TFRAME      NULL
 48 #define CH_FBORDER     NULL
 49 #define CH_MEDIA       NULL
 50 #define CH_FSUBMIT     CheckFsubmit
 51 #define CH_LINKTYPES   NULL
 52 #define CH_TRULES      NULL
 53 #define CH_SCOPE       CheckScope
 54 #define CH_SHAPE       CheckShape
 55 #define CH_SCROLL      CheckScroll
 56 #define CH_TARGET      CheckTarget
 57 #define CH_VTYPE       CheckVType
 58 #define CH_ACTION      CheckAction
 59 
 60 static const Attribute attribute_defs [] =
 61 {
 62   { TidyAttr_UNKNOWN,           "unknown!",          VERS_PROPRIETARY,  NULL         }, 
 63   { TidyAttr_ABBR,              "abbr",              VERS_HTML40,       CH_PCDATA    }, 
 64   { TidyAttr_ACCEPT,            "accept",            VERS_ALL,          CH_XTYPE     }, 
 65   { TidyAttr_ACCEPT_CHARSET,    "accept-charset",    VERS_HTML40,       CH_CHARSET   }, 
 66   { TidyAttr_ACCESSKEY,         "accesskey",         VERS_HTML40,       CH_CHARACTER }, 
 67   { TidyAttr_ACTION,            "action",            VERS_ALL,          CH_ACTION    }, 
 68   { TidyAttr_ADD_DATE,          "add_date",          VERS_NETSCAPE,     CH_PCDATA    }, /* A */
 69   { TidyAttr_ALIGN,             "align",             VERS_ALL,          CH_ALIGN     }, /* varies by element */
 70   { TidyAttr_ALINK,             "alink",             VERS_LOOSE,        CH_COLOR     }, 
 71   { TidyAttr_ALT,               "alt",               VERS_ALL,          CH_PCDATA    }, /* nowrap */
 72   { TidyAttr_ARCHIVE,           "archive",           VERS_HTML40,       CH_URLS      }, /* space or comma separated list */
 73   { TidyAttr_AXIS,              "axis",              VERS_HTML40,       CH_PCDATA    }, 
 74   { TidyAttr_BACKGROUND,        "background",        VERS_LOOSE,        CH_URL       }, 
 75   { TidyAttr_BGCOLOR,           "bgcolor",           VERS_LOOSE,        CH_COLOR     }, 
 76   { TidyAttr_BGPROPERTIES,      "bgproperties",      VERS_PROPRIETARY,  CH_PCDATA    }, /* BODY "fixed" fixes background */
 77   { TidyAttr_BORDER,            "border",            VERS_ALL,          CH_BORDER    }, /* like LENGTH + "border" */
 78   { TidyAttr_BORDERCOLOR,       "bordercolor",       VERS_MICROSOFT,    CH_COLOR     }, /* used on TABLE */
 79   { TidyAttr_BOTTOMMARGIN,      "bottommargin",      VERS_MICROSOFT,    CH_NUMBER    }, /* used on BODY */
 80   { TidyAttr_CELLPADDING,       "cellpadding",       VERS_FROM32,       CH_LENGTH    }, /* % or pixel values */
 81   { TidyAttr_CELLSPACING,       "cellspacing",       VERS_FROM32,       CH_LENGTH    }, 
 82   { TidyAttr_CHAR,              "char",              VERS_HTML40,       CH_CHARACTER }, 
 83   { TidyAttr_CHAROFF,           "charoff",           VERS_HTML40,       CH_LENGTH    }, 
 84   { TidyAttr_CHARSET,           "charset",           VERS_HTML40,       CH_CHARSET   }, 
 85   { TidyAttr_CHECKED,           "checked",           VERS_ALL,          CH_BOOL      }, /* i.e. "checked" or absent */
 86   { TidyAttr_CITE,              "cite",              VERS_HTML40,       CH_URL       }, 
 87   { TidyAttr_CLASS,             "class",             VERS_HTML40,       CH_PCDATA    }, 
 88   { TidyAttr_CLASSID,           "classid",           VERS_HTML40,       CH_URL       }, 
 89   { TidyAttr_CLEAR,             "clear",             VERS_LOOSE,        CH_CLEAR     }, /* BR: left, right, all */
 90   { TidyAttr_CODE,              "code",              VERS_LOOSE,        CH_PCDATA    }, /* APPLET */
 91   { TidyAttr_CODEBASE,          "codebase",          VERS_HTML40,       CH_URL       }, /* OBJECT */
 92   { TidyAttr_CODETYPE,          "codetype",          VERS_HTML40,       CH_XTYPE     }, /* OBJECT */
 93   { TidyAttr_COLOR,             "color",             VERS_LOOSE,        CH_COLOR     }, /* BASEFONT, FONT */
 94   { TidyAttr_COLS,              "cols",              VERS_IFRAME,       CH_COLS      }, /* TABLE & FRAMESET */
 95   { TidyAttr_COLSPAN,           "colspan",           VERS_FROM32,       CH_NUMBER    }, 
 96   { TidyAttr_COMPACT,           "compact",           VERS_ALL,          CH_BOOL      }, /* lists */
 97   { TidyAttr_CONTENT,           "content",           VERS_ALL,          CH_PCDATA    }, 
 98   { TidyAttr_COORDS,            "coords",            VERS_FROM32,       CH_COORDS    }, /* AREA, A */
 99   { TidyAttr_DATA,              "data",              VERS_HTML40,       CH_URL       }, /* OBJECT */
100   { TidyAttr_DATAFLD,           "datafld",           VERS_MICROSOFT,    CH_PCDATA    }, /* used on DIV, IMG */
101   { TidyAttr_DATAFORMATAS,      "dataformatas",      VERS_MICROSOFT,    CH_PCDATA    }, /* used on DIV, IMG */
102   { TidyAttr_DATAPAGESIZE,      "datapagesize",      VERS_MICROSOFT,    CH_NUMBER    }, /* used on DIV, IMG */
103   { TidyAttr_DATASRC,           "datasrc",           VERS_MICROSOFT,    CH_URL       }, /* used on TABLE */
104   { TidyAttr_DATETIME,          "datetime",          VERS_HTML40,       CH_DATE      }, /* INS, DEL */
105   { TidyAttr_DECLARE,           "declare",           VERS_HTML40,       CH_BOOL      }, /* OBJECT */
106   { TidyAttr_DEFER,             "defer",             VERS_HTML40,       CH_BOOL      }, /* SCRIPT */
107   { TidyAttr_DIR,               "dir",               VERS_HTML40,       CH_TEXTDIR   }, /* ltr or rtl */
108   { TidyAttr_DISABLED,          "disabled",          VERS_HTML40,       CH_BOOL      }, /* form fields */
109   { TidyAttr_ENCODING,          "encoding",          VERS_XML,          CH_PCDATA    }, /* <?xml?> */
110   { TidyAttr_ENCTYPE,           "enctype",           VERS_ALL,          CH_XTYPE     }, /* FORM */
111   { TidyAttr_FACE,              "face",              VERS_LOOSE,        CH_PCDATA    }, /* BASEFONT, FONT */
112   { TidyAttr_FOR,               "for",               VERS_HTML40,       CH_IDREF     }, /* LABEL */
113   { TidyAttr_FRAME,             "frame",             VERS_HTML40,       CH_TFRAME    }, /* TABLE */
114   { TidyAttr_FRAMEBORDER,       "frameborder",       VERS_FRAMESET,     CH_FBORDER   }, /* 0 or 1 */
115   { TidyAttr_FRAMESPACING,      "framespacing",      VERS_PROPRIETARY,  CH_NUMBER    }, 
116   { TidyAttr_GRIDX,             "gridx",             VERS_PROPRIETARY,  CH_NUMBER    }, /* TABLE Adobe golive*/
117   { TidyAttr_GRIDY,             "gridy",             VERS_PROPRIETARY,  CH_NUMBER    }, /* TABLE Adobe golive */
118   { TidyAttr_HEADERS,           "headers",           VERS_HTML40,       CH_IDREFS    }, /* table cells */
119   { TidyAttr_HEIGHT,            "height",            VERS_ALL,          CH_LENGTH    }, /* pixels only for TH/TD */
120   { TidyAttr_HREF,              "href",              VERS_ALL,          CH_URL       }, /* A, AREA, LINK and BASE */
121   { TidyAttr_HREFLANG,          "hreflang",          VERS_HTML40,       CH_LANG      }, /* A, LINK */
122   { TidyAttr_HSPACE,            "hspace",            VERS_ALL,          CH_NUMBER    }, /* APPLET, IMG, OBJECT */
123   { TidyAttr_HTTP_EQUIV,        "http-equiv",        VERS_ALL,          CH_PCDATA    }, /* META */
124   { TidyAttr_ID,                "id",                VERS_HTML40,       CH_IDDEF     }, 
125   { TidyAttr_ISMAP,             "ismap",             VERS_ALL,          CH_BOOL      }, /* IMG */
126   { TidyAttr_LABEL,             "label",             VERS_HTML40,       CH_PCDATA    }, /* OPT, OPTGROUP */
127   { TidyAttr_LANG,              "lang",              VERS_HTML40,       CH_LANG      }, 
128   { TidyAttr_LANGUAGE,          "language",          VERS_LOOSE,        CH_PCDATA    }, /* SCRIPT */
129   { TidyAttr_LAST_MODIFIED,     "last_modified",     VERS_NETSCAPE,     CH_PCDATA    }, /* A */
130   { TidyAttr_LAST_VISIT,        "last_visit",        VERS_NETSCAPE,     CH_PCDATA    }, /* A */
131   { TidyAttr_LEFTMARGIN,        "leftmargin",        VERS_MICROSOFT,    CH_NUMBER    }, /* used on BODY */
132   { TidyAttr_LINK,              "link",              VERS_LOOSE,        CH_COLOR     }, /* BODY */
133   { TidyAttr_LONGDESC,          "longdesc",          VERS_HTML40,       CH_URL       }, /* IMG */
134   { TidyAttr_LOWSRC,            "lowsrc",            VERS_PROPRIETARY,  CH_URL       }, /* IMG */
135   { TidyAttr_MARGINHEIGHT,      "marginheight",      VERS_IFRAME,       CH_NUMBER    }, /* FRAME, IFRAME, BODY */
136   { TidyAttr_MARGINWIDTH,       "marginwidth",       VERS_IFRAME,       CH_NUMBER    }, /* ditto */
137   { TidyAttr_MAXLENGTH,         "maxlength",         VERS_ALL,          CH_NUMBER    }, /* INPUT */
138   { TidyAttr_MEDIA,             "media",             VERS_HTML40,       CH_MEDIA     }, /* STYLE, LINK */
139   { TidyAttr_METHOD,            "method",            VERS_ALL,          CH_FSUBMIT   }, /* FORM: get or post */
140   { TidyAttr_MULTIPLE,          "multiple",          VERS_ALL,          CH_BOOL      }, /* SELECT */
141   { TidyAttr_NAME,              "name",              VERS_ALL,          CH_NAME      }, 
142   { TidyAttr_NOHREF,            "nohref",            VERS_FROM32,       CH_BOOL      }, /* AREA */
143   { TidyAttr_NORESIZE,          "noresize",          VERS_FRAMESET,     CH_BOOL      }, /* FRAME */
144   { TidyAttr_NOSHADE,           "noshade",           VERS_LOOSE,        CH_BOOL      }, /* HR */
145   { TidyAttr_NOWRAP,            "nowrap",            VERS_LOOSE,        CH_BOOL      }, /* table cells */
146   { TidyAttr_OBJECT,            "object",            VERS_HTML40_LOOSE, CH_PCDATA    }, /* APPLET */
147   { TidyAttr_OnAFTERUPDATE,     "onafterupdate",     VERS_MICROSOFT,    CH_SCRIPT    }, 
148   { TidyAttr_OnBEFOREUNLOAD,    "onbeforeunload",    VERS_MICROSOFT,    CH_SCRIPT    }, 
149   { TidyAttr_OnBEFOREUPDATE,    "onbeforeupdate",    VERS_MICROSOFT,    CH_SCRIPT    }, 
150   { TidyAttr_OnBLUR,            "onblur",            VERS_EVENTS,       CH_SCRIPT    }, /* event */
151   { TidyAttr_OnCHANGE,          "onchange",          VERS_EVENTS,       CH_SCRIPT    }, /* event */
152   { TidyAttr_OnCLICK,           "onclick",           VERS_EVENTS,       CH_SCRIPT    }, /* event */
153   { TidyAttr_OnDATAAVAILABLE,   "ondataavailable",   VERS_MICROSOFT,    CH_SCRIPT    }, /* object, applet */
154   { TidyAttr_OnDATASETCHANGED,  "ondatasetchanged",  VERS_MICROSOFT,    CH_SCRIPT    }, /* object, applet */
155   { TidyAttr_OnDATASETCOMPLETE, "ondatasetcomplete", VERS_MICROSOFT,    CH_SCRIPT    }, 
156   { TidyAttr_OnDBLCLICK,        "ondblclick",        VERS_EVENTS,       CH_SCRIPT    }, /* event */
157   { TidyAttr_OnERRORUPDATE,     "onerrorupdate",     VERS_MICROSOFT,    CH_SCRIPT    }, /* form fields */
158   { TidyAttr_OnFOCUS,           "onfocus",           VERS_EVENTS,       CH_SCRIPT    }, /* event */
159   { TidyAttr_OnKEYDOWN,         "onkeydown",         VERS_EVENTS,       CH_SCRIPT    }, /* event */
160   { TidyAttr_OnKEYPRESS,        "onkeypress",        VERS_EVENTS,       CH_SCRIPT    }, /* event */
161   { TidyAttr_OnKEYUP,           "onkeyup",           VERS_EVENTS,       CH_SCRIPT    }, /* event */
162   { TidyAttr_OnLOAD,            "onload",            VERS_EVENTS,       CH_SCRIPT    }, /* event */
163   { TidyAttr_OnMOUSEDOWN,       "onmousedown",       VERS_EVENTS,       CH_SCRIPT    }, /* event */
164   { TidyAttr_OnMOUSEMOVE,       "onmousemove",       VERS_EVENTS,       CH_SCRIPT    }, /* event */
165   { TidyAttr_OnMOUSEOUT,        "onmouseout",        VERS_EVENTS,       CH_SCRIPT    }, /* event */
166   { TidyAttr_OnMOUSEOVER,       "onmouseover",       VERS_EVENTS,       CH_SCRIPT    }, /* event */
167   { TidyAttr_OnMOUSEUP,         "onmouseup",         VERS_EVENTS,       CH_SCRIPT    }, /* event */
168   { TidyAttr_OnRESET,           "onreset",           VERS_EVENTS,       CH_SCRIPT    }, /* event */
169   { TidyAttr_OnROWENTER,        "onrowenter",        VERS_MICROSOFT,    CH_SCRIPT    }, /* form fields */
170   { TidyAttr_OnROWEXIT,         "onrowexit",         VERS_MICROSOFT,    CH_SCRIPT    }, /* form fields */
171   { TidyAttr_OnSELECT,          "onselect",          VERS_EVENTS,       CH_SCRIPT    }, /* event */
172   { TidyAttr_OnSUBMIT,          "onsubmit",          VERS_EVENTS,       CH_SCRIPT    }, /* event */
173   { TidyAttr_OnUNLOAD,          "onunload",          VERS_EVENTS,       CH_SCRIPT    }, /* event */
174   { TidyAttr_PROFILE,           "profile",           VERS_HTML40,       CH_URL       }, /* HEAD */
175   { TidyAttr_PROMPT,            "prompt",            VERS_LOOSE,        CH_PCDATA    }, /* ISINDEX */
176   { TidyAttr_RBSPAN,            "rbspan",            VERS_XHTML11,      CH_NUMBER    }, /* ruby markup */
177   { TidyAttr_READONLY,          "readonly",          VERS_HTML40,       CH_BOOL      }, /* form fields */
178   { TidyAttr_REL,               "rel",               VERS_ALL,          CH_LINKTYPES }, 
179   { TidyAttr_REV,               "rev",               VERS_ALL,          CH_LINKTYPES }, 
180   { TidyAttr_RIGHTMARGIN,       "rightmargin",       VERS_MICROSOFT,    CH_NUMBER    }, /* used on BODY */
181   { TidyAttr_ROWS,              "rows",              VERS_ALL,          CH_NUMBER    }, /* TEXTAREA */
182   { TidyAttr_ROWSPAN,           "rowspan",           VERS_ALL,          CH_NUMBER    }, /* table cells */
183   { TidyAttr_RULES,             "rules",             VERS_HTML40,       CH_TRULES    }, /* TABLE */
184   { TidyAttr_SCHEME,            "scheme",            VERS_HTML40,       CH_PCDATA    }, /* META */
185   { TidyAttr_SCOPE,             "scope",             VERS_HTML40,       CH_SCOPE     }, /* table cells */
186   { TidyAttr_SCROLLING,         "scrolling",         VERS_IFRAME,       CH_SCROLL    }, /* yes, no or auto */
187   { TidyAttr_SELECTED,          "selected",          VERS_ALL,          CH_BOOL      }, /* OPTION */
188   { TidyAttr_SHAPE,             "shape",             VERS_FROM32,       CH_SHAPE     }, /* AREA, A */
189   { TidyAttr_SHOWGRID,          "showgrid",          VERS_PROPRIETARY,  CH_BOOL      }, /* TABLE Adobe golive */
190   { TidyAttr_SHOWGRIDX,         "showgridx",         VERS_PROPRIETARY,  CH_BOOL      }, /* TABLE Adobe golive*/
191   { TidyAttr_SHOWGRIDY,         "showgridy",         VERS_PROPRIETARY,  CH_BOOL      }, /* TABLE Adobe golive*/
192   { TidyAttr_SIZE,              "size",              VERS_LOOSE,        CH_NUMBER    }, /* HR, FONT, BASEFONT, SELECT */
193   { TidyAttr_SPAN,              "span",              VERS_HTML40,       CH_NUMBER    }, /* COL, COLGROUP */
194   { TidyAttr_SRC,               "src",               VERS_ALL,          CH_URL       }, /* IMG, FRAME, IFRAME */
195   { TidyAttr_STANDBY,           "standby",           VERS_HTML40,       CH_PCDATA    }, /* OBJECT */
196   { TidyAttr_START,             "start",             VERS_ALL,          CH_NUMBER    }, /* OL */
197   { TidyAttr_STYLE,             "style",             VERS_HTML40,       CH_PCDATA    }, 
198   { TidyAttr_SUMMARY,           "summary",           VERS_HTML40,       CH_PCDATA    }, /* TABLE */
199   { TidyAttr_TABINDEX,          "tabindex",          VERS_HTML40,       CH_NUMBER    }, /* fields, OBJECT  and A */
200   { TidyAttr_TARGET,            "target",            VERS_HTML40,       CH_TARGET    }, /* names a frame/window */
201   { TidyAttr_TEXT,              "text",              VERS_LOOSE,        CH_COLOR     }, /* BODY */
202   { TidyAttr_TITLE,             "title",             VERS_HTML40,       CH_PCDATA    }, /* text tool tip */
203   { TidyAttr_TOPMARGIN,         "topmargin",         VERS_MICROSOFT,    CH_NUMBER    }, /* used on BODY */
204   { TidyAttr_TYPE,              "type",              VERS_FROM32,       CH_TYPE      }, /* also used by SPACER */
205   { TidyAttr_USEMAP,            "usemap",            VERS_ALL,          CH_URL       }, /* things with images */
206   { TidyAttr_VALIGN,            "valign",            VERS_FROM32,       CH_VALIGN    }, 
207   { TidyAttr_VALUE,             "value",             VERS_ALL,          CH_PCDATA    }, 
208   { TidyAttr_VALUETYPE,         "valuetype",         VERS_HTML40,       CH_VTYPE     }, /* PARAM: data, ref, object */
209   { TidyAttr_VERSION,           "version",           VERS_ALL|VERS_XML, CH_PCDATA    }, /* HTML <?xml?> */
210   { TidyAttr_VLINK,             "vlink",             VERS_LOOSE,        CH_COLOR     }, /* BODY */
211   { TidyAttr_VSPACE,            "vspace",            VERS_LOOSE,        CH_NUMBER    }, /* IMG, OBJECT, APPLET */
212   { TidyAttr_WIDTH,             "width",             VERS_ALL,          CH_LENGTH    }, /* pixels only for TD/TH */
213   { TidyAttr_WRAP,              "wrap",              VERS_NETSCAPE,     CH_PCDATA    }, /* textarea */
214   { TidyAttr_XML_LANG,          "xml:lang",          VERS_XML,          CH_LANG      }, /* XML language */
215   { TidyAttr_XML_SPACE,         "xml:space",         VERS_XML,          CH_PCDATA    }, /* XML white space */
216 
217   /* todo: VERS_ALL is wrong! */
218   { TidyAttr_XMLNS,             "xmlns",             VERS_ALL,          CH_PCDATA    }, /* name space */
219   { TidyAttr_EVENT,             "event",             VERS_HTML40,       CH_PCDATA    }, /* reserved for <script> */
220   { TidyAttr_METHODS,           "methods",           VERS_HTML20,       CH_PCDATA    }, /* for <a>, never implemented */
221   { TidyAttr_N,                 "n",                 VERS_HTML20,       CH_PCDATA    }, /* for <nextid> */
222   { TidyAttr_SDAFORM,           "sdaform",           VERS_HTML20,       CH_PCDATA    }, /* SDATA attribute in HTML 2.0 */
223   { TidyAttr_SDAPREF,           "sdapref",           VERS_HTML20,       CH_PCDATA    }, /* SDATA attribute in HTML 2.0 */
224   { TidyAttr_SDASUFF,           "sdasuff",           VERS_HTML20,       CH_PCDATA    }, /* SDATA attribute in HTML 2.0 */
225   { TidyAttr_URN,               "urn",               VERS_HTML20,       CH_PCDATA    }, /* for <a>, never implemented */
226 
227   /* this must be the final entry */
228   { N_TIDY_ATTRIBS,             NULL,                VERS_UNKNOWN,      NULL         }
229 };
230 
231 static uint AttributeVersions(Node* node, AttVal* attval)
232 {
233     uint i;
234 
235     if (!attval || !attval->dict)
236         return VERS_UNKNOWN;
237 
238     if (!node || !node->tag || !node->tag->attrvers)
239         return attval->dict->versions;
240 
241     for (i = 0; node->tag->attrvers[i].attribute; ++i)
242         if (node->tag->attrvers[i].attribute == attval->dict->id)
243             return node->tag->attrvers[i].versions;
244 
245     return attval->dict->versions & VERS_ALL
246              ? VERS_UNKNOWN
247              : attval->dict->versions;
248 
249 }
250 
251 
252 /* return the version of the attribute "id" of element "node" */
253 uint NodeAttributeVersions( Node* node, TidyAttrId id )
254 {
255     uint i;
256 
257     if (!node || !node->tag || !node->tag->attrvers)
258         return VERS_UNKNOWN;
259 
260     for (i = 0; node->tag->attrvers[i].attribute; ++i)
261         if (node->tag->attrvers[i].attribute == id)
262             return node->tag->attrvers[i].versions;
263 
264     return VERS_UNKNOWN;
265 }
266 
267 /* returns true if the element is a W3C defined element */
268 /* but the element/attribute combination is not         */
269 static Bool AttributeIsProprietary(Node* node, AttVal* attval)
270 {
271     if (!node || !attval)
272         return no;
273 
274     if (!node->tag)
275         return no;
276 
277     if (!(node->tag->versions & VERS_ALL))
278         return no;
279 
280     if (AttributeVersions(node, attval) & VERS_ALL)
281         return no;
282 
283     return yes;
284 }
285 
286 /* used by CheckColor() */
287 struct _colors
288 {
289     ctmbstr name;
290     ctmbstr hex;
291 };
292 
293 static const struct _colors colors[] =
294 {
295     { "black",   "#000000" },
296     { "green",   "#008000" },
297     { "silver",  "#C0C0C0" },
298     { "lime",    "#00FF00" },
299     { "gray",    "#808080" },
300     { "olive",   "#808000" },
301     { "white",   "#FFFFFF" },
302     { "yellow",  "#FFFF00" },
303     { "maroon",  "#800000" },
304     { "navy",    "#000080" },
305     { "red",     "#FF0000" },
306     { "blue",    "#0000FF" },
307     { "purple",  "#800080" },
308     { "teal",    "#008080" },
309     { "fuchsia", "#FF00FF" },
310     { "aqua",    "#00FFFF" },
311     { NULL,      NULL      }
312 };
313 
314 static ctmbstr GetColorCode(ctmbstr name)
315 {
316     uint i;
317 
318     for (i = 0; colors[i].name; ++i)
319         if (tmbstrcasecmp(name, colors[i].name) == 0)
320             return colors[i].hex;
321 
322     return NULL;
323 }
324 
325 static ctmbstr GetColorName(ctmbstr code)
326 {
327     uint i;
328 
329     for (i = 0; colors[i].name; ++i)
330         if (tmbstrcasecmp(code, colors[i].hex) == 0)
331             return colors[i].name;
332 
333     return NULL;
334 }
335 
336 #if 0
337 static const struct _colors fancy_colors[] =
338 {
339     { "darkgreen",            "#006400" },
340     { "antiquewhite",         "#FAEBD7" },
341     { "aqua",                 "#00FFFF" },
342     { "aquamarine",           "#7FFFD4" },
343     { "azure",                "#F0FFFF" },
344     { "beige",                "#F5F5DC" },
345     { "bisque",               "#FFE4C4" },
346     { "black",                "#000000" },
347     { "blanchedalmond",       "#FFEBCD" },
348     { "blue",                 "#0000FF" },
349     { "blueviolet",           "#8A2BE2" },
350     { "brown",                "#A52A2A" },
351     { "burlywood",            "#DEB887" },
352     { "cadetblue",            "#5F9EA0" },
353     { "chartreuse",           "#7FFF00" },
354     { "chocolate",            "#D2691E" },
355     { "coral",                "#FF7F50" },
356     { "cornflowerblue",       "#6495ED" },
357     { "cornsilk",             "#FFF8DC" },
358     { "crimson",              "#DC143C" },
359     { "cyan",                 "#00FFFF" },
360     { "darkblue",             "#00008B" },
361     { "darkcyan",             "#008B8B" },
362     { "darkgoldenrod",        "#B8860B" },
363     { "darkgray",             "#A9A9A9" },
364     { "darkgreen",            "#006400" },
365     { "darkkhaki",            "#BDB76B" },
366     { "darkmagenta",          "#8B008B" },
367     { "darkolivegreen",       "#556B2F" },
368     { "darkorange",           "#FF8C00" },
369     { "darkorchid",           "#9932CC" },
370     { "darkred",              "#8B0000" },
371     { "darksalmon",           "#E9967A" },
372     { "darkseagreen",         "#8FBC8F" },
373     { "darkslateblue",        "#483D8B" },
374     { "darkslategray",        "#2F4F4F" },
375     { "darkturquoise",        "#00CED1" },
376     { "darkviolet",           "#9400D3" },
377     { "deeppink",             "#FF1493" },
378     { "deepskyblue",          "#00BFFF" },
379     { "dimgray",              "#696969" },
380     { "dodgerblue",           "#1E90FF" },
381     { "firebrick",            "#B22222" },
382     { "floralwhite",          "#FFFAF0" },
383     { "forestgreen",          "#228B22" },
384     { "fuchsia",              "#FF00FF" },
385     { "gainsboro",            "#DCDCDC" },
386     { "ghostwhite",           "#F8F8FF" },
387     { "gold",                 "#FFD700" },
388     { "goldenrod",            "#DAA520" },
389     { "gray",                 "#808080" },
390     { "green",                "#008000" },
391     { "greenyellow",          "#ADFF2F" },
392     { "honeydew",             "#F0FFF0" },
393     { "hotpink",              "#FF69B4" },
394     { "indianred",            "#CD5C5C" },
395     { "indigo",               "#4B0082" },
396     { "ivory",                "#FFFFF0" },
397     { "khaki",                "#F0E68C" },
398     { "lavender",             "#E6E6FA" },
399     { "lavenderblush",        "#FFF0F5" },
400     { "lawngreen",            "#7CFC00" },
401     { "lemonchiffon",         "#FFFACD" },
402     { "lightblue",            "#ADD8E6" },
403     { "lightcoral",           "#F08080" },
404     { "lightcyan",            "#E0FFFF" },
405     { "lightgoldenrodyellow", "#FAFAD2" },
406     { "lightgreen",           "#90EE90" },
407     { "lightgrey",            "#D3D3D3" },
408     { "lightpink",            "#FFB6C1" },
409     { "lightsalmon",          "#FFA07A" },
410     { "lightseagreen",        "#20B2AA" },
411     { "lightskyblue",         "#87CEFA" },
412     { "lightslategray",       "#778899" },
413     { "lightsteelblue",       "#B0C4DE" },
414     { "lightyellow",          "#FFFFE0" },
415     { "lime",                 "#00FF00" },
416     { "limegreen",            "#32CD32" },
417     { "linen",                "#FAF0E6" },
418     { "magenta",              "#FF00FF" },
419     { "maroon",               "#800000" },
420     { "mediumaquamarine",     "#66CDAA" },
421     { "mediumblue",           "#0000CD" },
422     { "mediumorchid",         "#BA55D3" },
423     { "mediumpurple",         "#9370DB" },
424     { "mediumseagreen",       "#3CB371" },
425     { "mediumslateblue",      "#7B68EE" },
426     { "mediumspringgreen",    "#00FA9A" },
427     { "mediumturquoise",      "#48D1CC" },
428     { "mediumvioletred",      "#C71585" },
429     { "midnightblue",         "#191970" },
430     { "mintcream",            "#F5FFFA" },
431     { "mistyrose",            "#FFE4E1" },
432     { "moccasin",             "#FFE4B5" },
433     { "navajowhite",          "#FFDEAD" },
434     { "navy",                 "#000080" },
435     { "oldlace",              "#FDF5E6" },
436     { "olive",                "#808000" },
437     { "olivedrab",            "#6B8E23" },
438     { "orange",               "#FFA500" },
439     { "orangered",            "#FF4500" },
440     { "orchid",               "#DA70D6" },
441     { "palegoldenrod",        "#EEE8AA" },
442     { "palegreen",            "#98FB98" },
443     { "paleturquoise",        "#AFEEEE" },
444     { "palevioletred",        "#DB7093" },
445     { "papayawhip",           "#FFEFD5" },
446     { "peachpuff",            "#FFDAB9" },
447     { "peru",                 "#CD853F" },
448     { "pink",                 "#FFC0CB" },
449     { "plum",                 "#DDA0DD" },
450     { "powderblue",           "#B0E0E6" },
451     { "purple",               "#800080" },
452     { "red",                  "#FF0000" },
453     { "rosybrown",            "#BC8F8F" },
454     { "royalblue",            "#4169E1" },
455     { "saddlebrown",          "#8B4513" },
456     { "salmon",               "#FA8072" },
457     { "sandybrown",           "#F4A460" },
458     { "seagreen",             "#2E8B57" },
459     { "seashell",             "#FFF5EE" },
460     { "sienna",               "#A0522D" },
461     { "silver",               "#C0C0C0" },
462     { "skyblue",              "#87CEEB" },
463     { "slateblue",            "#6A5ACD" },
464     { "slategray",            "#708090" },
465     { "snow",                 "#FFFAFA" },
466     { "springgreen",          "#00FF7F" },
467     { "steelblue",            "#4682B4" },
468     { "tan",                  "#D2B48C" },
469     { "teal",                 "#008080" },
470     { "thistle",              "#D8BFD8" },
471     { "tomato",               "#FF6347" },
472     { "turquoise",            "#40E0D0" },
473     { "violet",               "#EE82EE" },
474     { "wheat",                "#F5DEB3" },
475     { "white",                "#FFFFFF" },
476     { "whitesmoke",           "#F5F5F5" },
477     { "yellow",               "#FFFF00" },
478     { "yellowgreen",          "#9ACD32" },
479     { NULL,                   NULL      }
480 };
481 #endif
482 
483 #ifdef ATTRIBUTE_HASH_LOOKUP
484 static uint hash(ctmbstr s)
485 {
486     uint hashval;
487 
488     for (hashval = 0; *s != '\0'; s++)
489         hashval = *s + 31*hashval;
490 
491     return hashval % ATTRIBUTE_HASH_SIZE;
492 }
493 
494 static Attribute *install(TidyAttribImpl * attribs, const Attribute* old)
495 {
496     Attribute *np;
497     uint hashval;
498 
499     np = (Attribute *)MemAlloc(sizeof(*np));
500 
501     np->name = tmbstrdup(old->name);
502 
503     hashval = hash(np->name);
504     np->next = attribs->hashtab[hashval];
505     attribs->hashtab[hashval] = np;
506 
507     np->id       = old->id;
508     np->versions = old->versions;
509     np->attrchk  = old->attrchk;
510 
511     return np;
512 }
513 #endif
514 
515 static const Attribute* lookup(TidyAttribImpl* ARG_UNUSED(attribs),
516                                ctmbstr atnam)
517 {
518     const Attribute *np;
519 
520     if (!atnam)
521         return NULL;
522 
523 #ifdef ATTRIBUTE_HASH_LOOKUP
524     for (np = attribs->hashtab[hash(atnam)]; np != NULL; np = np->next)
525         if (tmbstrcmp(atnam, np->name) == 0)
526             return np;
527 
528     for (np = attribute_defs; np && np->name; ++np)
529         if (tmbstrcmp(atnam, np->name) == 0)
530             return install(attribs, np);
531 #else
532     for (np = attribute_defs; np && np->name; ++np)
533         if (tmbstrcmp(atnam, np->name) == 0)
534             return np;
535 #endif
536 
537     return NULL;
538 }
539 
540 
541 /* Locate attributes by type */
542 AttVal* AttrGetById( Node* node, TidyAttrId id )
543 {
544    AttVal* av;
545    for ( av = node->attributes; av; av = av->next )
546    {
547      if ( AttrIsId(av, id) )
548          return av;
549    }
550    return NULL;
551 }
552 
553 /* public method for finding attribute definition by name */
554 const Attribute* FindAttribute( TidyDocImpl* doc, AttVal *attval )
555 {
556     if ( attval )
557        return lookup( &doc->attribs, attval->attribute );
558     return NULL;
559 }
560 
561 AttVal* GetAttrByName( Node *node, ctmbstr name )
562 {
563     AttVal *attr;
564     for (attr = node->attributes; attr != NULL; attr = attr->next)
565     {
566         if (attr->attribute && tmbstrcmp(attr->attribute, name) == 0)
567             break;
568     }
569     return attr;
570 }
571 
572 AttVal* AddAttribute( TidyDocImpl* doc,
573                       Node *node, ctmbstr name, ctmbstr value )
574 {
575     AttVal *av = NewAttribute();
576     av->delim = '"';
577     av->attribute = tmbstrdup(name);
578 
579     if (value)
580         av->value = tmbstrdup(value);
581     else
582         av->value = NULL;
583 
584     av->dict = lookup(&doc->attribs, name);
585 
586     InsertAttributeAtEnd(node, av);
587     return av;
588 }
589 
590 AttVal* RepairAttrValue(TidyDocImpl* doc, Node* node, ctmbstr name, ctmbstr value)
591 {
592     AttVal* old = GetAttrByName(node, name);
593 
594     if (old)
595     {
596         if (old->value)
597             MemFree(old->value);
598         if (value)
599             old->value = tmbstrdup(value);
600         else
601             old->value = NULL;
602 
603         return old;
604     }
605     else
606         return AddAttribute(doc, node, name, value);
607 }
608 
609 static Bool CheckAttrType( TidyDocImpl* doc,
610                            ctmbstr attrname, AttrCheck type )
611 {
612     const Attribute* np = lookup( &doc->attribs, attrname );
613     return (Bool)( np && np->attrchk == type );
614 }
615 
616 Bool IsUrl( TidyDocImpl* doc, ctmbstr attrname )
617 {
618     return CheckAttrType( doc, attrname, CH_URL );
619 }
620 
621 Bool IsBool( TidyDocImpl* doc, ctmbstr attrname )
622 {
623     return CheckAttrType( doc, attrname, CH_BOOL );
624 }
625 
626 Bool IsScript( TidyDocImpl* doc, ctmbstr attrname )
627 {
628     return CheckAttrType( doc, attrname, CH_SCRIPT );
629 }
630 
631 /* may id or name serve as anchor? */
632 Bool IsAnchorElement( TidyDocImpl* ARG_UNUSED(doc), Node* node)
633 {
634     TidyTagId tid = TagId( node );
635     if ( tid == TidyTag_A      ||
636          tid == TidyTag_APPLET ||
637          tid == TidyTag_FORM   ||
638          tid == TidyTag_FRAME  ||
639          tid == TidyTag_IFRAME ||
640          tid == TidyTag_IMG    ||
641          tid == TidyTag_MAP )
642         return yes;
643 
644     return no;
645 }
646 
647 /*
648   In CSS1, selectors can contain only the characters A-Z, 0-9,
649   and Unicode characters 161-255, plus dash (-); they cannot start
650   with a dash or a digit; they can also contain escaped characters
651   and any Unicode character as a numeric code (see next item).
652 
653   The backslash followed by at most four hexadecimal digits
654   (0..9A..F) stands for the Unicode character with that number.
655 
656   Any character except a hexadecimal digit can be escaped to remove
657   its special meaning, by putting a backslash in front.
658 
659   #508936 - CSS class naming for -clean option
660 */
661 Bool IsCSS1Selector( ctmbstr buf )
662 {
663     Bool valid = yes;
664     int esclen = 0;
665     byte c;
666     int pos;
667 
668     for ( pos=0; valid && (c = *buf++); ++pos )
669     {
670         if ( c == '\\' )
671         {
672             esclen = 1;  /* ab\555\444 is 4 chars {'a', 'b', \555, \444} */
673         }
674         else if ( isdigit( c ) )
675         {
676             /* Digit not 1st, unless escaped (Max length "\112F") */
677             if ( esclen > 0 )
678                 valid = ( ++esclen < 6 );
679             if ( valid )
680                 valid = ( pos>0 || esclen>0 );
681         }
682         else
683         {
684             valid = (
685                 esclen > 0                       /* Escaped? Anything goes. */
686                 || ( pos>0 && c == '-' )         /* Dash cannot be 1st char */
687                 || isalpha(c)                    /* a-z, A-Z anywhere */
688                 || ( c >= 161 )                  /* Unicode 161-255 anywhere */
689             );
690             esclen = 0;
691         }
692     }
693     return valid;
694 }
695 
696 /* free single anchor */
697 static void FreeAnchor(Anchor *a)
698 {
699     if ( a )
700         MemFree( a->name );
701     MemFree( a );
702 }
703 
704 /* removes anchor for specific node */
705 void RemoveAnchorByNode( TidyDocImpl* doc, Node *node )
706 {
707     TidyAttribImpl* attribs = &doc->attribs;
708     Anchor *delme = NULL, *curr, *prev = NULL;
709 
710     for ( curr=attribs->anchor_list; curr!=NULL; curr=curr->next )
711     {
712         if ( curr->node == node )
713         {
714             if ( prev )
715                 prev->next = curr->next;
716             else
717                 attribs->anchor_list = curr->next;
718             delme = curr;
719             break;
720         }
721         prev = curr;
722     }
723     FreeAnchor( delme );
724 }
725 
726 /* initialize new anchor */
727 static Anchor* NewAnchor( ctmbstr name, Node* node )
728 {
729     Anchor *a = (Anchor*) MemAlloc( sizeof(Anchor) );
730 
731     a->name = tmbstrdup( name );
732     a->name = tmbstrtolower(a->name);
733     a->node = node;
734     a->next = NULL;
735 
736     return a;
737 }
738 
739 /* add new anchor to namespace */
740 Anchor* AddAnchor( TidyDocImpl* doc, ctmbstr name, Node *node )
741 {
742     TidyAttribImpl* attribs = &doc->attribs;
743     Anchor *a = NewAnchor( name, node );
744 
745     if ( attribs->anchor_list == NULL)
746          attribs->anchor_list = a;
747     else
748     {
749         Anchor *here =  attribs->anchor_list;
750         while (here->next)
751             here = here->next;
752         here->next = a;
753     }
754 
755     return attribs->anchor_list;
756 }
757 
758 /* return node associated with anchor */
759 Node* GetNodeByAnchor( TidyDocImpl* doc, ctmbstr name )
760 {
761     TidyAttribImpl* attribs = &doc->attribs;
762     Anchor *found;
763     tmbstr lname = tmbstrdup(name);
764     lname = tmbstrtolower(lname);
765 
766     for ( found = attribs->anchor_list; found != NULL; found = found->next )
767     {
768         if ( tmbstrcmp(found->name, lname) == 0 )
769             break;
770     }
771     
772     MemFree(lname);
773     if ( found )
774         return found->node;
775     return NULL;
776 }
777 
778 /* free all anchors */
779 void FreeAnchors( TidyDocImpl* doc )
780 {
781     TidyAttribImpl* attribs = &doc->attribs;
782     Anchor* a;
783     while (NULL != (a = attribs->anchor_list) )
784     {
785         attribs->anchor_list = a->next;
786         FreeAnchor(a);
787     }
788 }
789 
790 /* public method for inititializing attribute dictionary */
791 void InitAttrs( TidyDocImpl* doc )
792 {
793     ClearMemory( &doc->attribs, sizeof(TidyAttribImpl) );
794 #ifdef _DEBUG
795     {
796       /* Attribute ID is index position in Attribute type lookup table */
797       uint ix;
798       for ( ix=0; ix < N_TIDY_ATTRIBS; ++ix )
799       {
800         const Attribute* dict = &attribute_defs[ ix ];
801         assert( (uint) dict->id == ix );
802       }
803     }
804 #endif
805 }
806 
807 /* free all declared attributes */
808 static void FreeDeclaredAttributes( TidyDocImpl* doc )
809 {
810     TidyAttribImpl* attribs = &doc->attribs;
811     Attribute* dict;
812     while ( NULL != (dict = attribs->declared_attr_list) )
813     {
814         attribs->declared_attr_list = dict->next;
815         MemFree( dict->name );
816         MemFree( dict );
817     }
818 }
819 
820 void FreeAttrTable( TidyDocImpl* doc )
821 {
822 #ifdef ATTRIBUTE_HASH_LOOKUP
823     Attribute *dict, *next;
824     uint i;
825 
826     for (i = 0; i < ATTRIBUTE_HASH_SIZE; ++i)
827     {
828         dict = doc->attribs.hashtab[i];
829 
830         while(dict)
831         {
832             next = dict->next;
833             MemFree(dict->name);
834             MemFree(dict);
835             dict = next;
836         }
837 
838         doc->attribs.hashtab[i] = NULL;
839     }
840 #endif
841 
842     FreeAnchors( doc );
843     FreeDeclaredAttributes( doc );
844 }
845 
846 /*
847  the same attribute name can't be used
848  more than once in each element
849 */
850 void RepairDuplicateAttributes( TidyDocImpl* doc, Node *node)
851 {
852     AttVal *first;
853 
854     for (first = node->attributes; first != NULL;)
855     {
856         AttVal *second;
857         Bool firstRedefined = no;
858 
859         if (!(first->asp == NULL && first->php == NULL))
860         {
861             first = first->next;
862             continue;
863         }
864 
865         for (second = first->next; second != NULL;)
866         {
867             AttVal *temp;
868 
869             if (!(second->asp == NULL && second->php == NULL &&
870                 AttrsHaveSameId(first, second)))
871             {
872                 second = second->next;
873                 continue;
874             }
875 
876             /* first and second attribute have same local name */
877             /* now determine what to do with this duplicate... */
878 
879             if (attrIsCLASS(first) && cfgBool(doc, TidyJoinClasses) && AttrHasValue(first) && AttrHasValue(second))
880             {
881                 /* concatenate classes */
882 
883                 first->value = (tmbstr) MemRealloc(first->value, tmbstrlen(first->value) +
884                     tmbstrlen(second->value)  + 2);
885                 tmbstrcat(first->value, " ");
886                 tmbstrcat(first->value, second->value);
887 
888                 temp = second->next;
889 
890                 ReportAttrError( doc, node, second, JOINING_ATTRIBUTE);
891                 RemoveAttribute( doc, node, second );
892 
893                 second = temp;
894             }
895             else if (attrIsSTYLE(first) && cfgBool(doc, TidyJoinStyles) && AttrHasValue(first) && AttrHasValue(second))
896             {
897                 /* concatenate styles */
898 
899                 /*
900                 this doesn't handle CSS comments and
901                 leading/trailing white-space very well
902                 see http://www.w3.org/TR/css-style-attr
903                 */
904 
905                 uint end = tmbstrlen(first->value);
906 
907                 if (end >0 && first->value[end - 1] == ';')
908                 {
909                     /* attribute ends with declaration seperator */
910 
911                     first->value = (tmbstr) MemRealloc(first->value,
912                         end + tmbstrlen(second->value) + 2);
913 
914                     tmbstrcat(first->value, " ");
915                     tmbstrcat(first->value, second->value);
916                 }
917                 else if (end >0 && first->value[end - 1] == '}')
918                 {
919                     /* attribute ends with rule set */
920 
921                     first->value = (tmbstr) MemRealloc(first->value,
922                         end + tmbstrlen(second->value) + 6);
923 
924                     tmbstrcat(first->value, " { ");
925                     tmbstrcat(first->value, second->value);
926                     tmbstrcat(first->value, " }");
927                 }
928                 else
929                 {
930                     /* attribute ends with property value */
931 
932                     first->value = (tmbstr) MemRealloc(first->value,
933                         end + tmbstrlen(second->value) + 3);
934 
935                     if (end > 0)
936                         tmbstrcat(first->value, "; ");
937                     tmbstrcat(first->value, second->value);
938                 }
939 
940                 temp = second->next;
941 
942                 ReportAttrError( doc, node, second, JOINING_ATTRIBUTE);
943                 RemoveAttribute( doc, node, second );
944                 second = temp;
945 
946             }
947             else if ( cfg(doc, TidyDuplicateAttrs) == TidyKeepLast )
948             {
949                 temp = first->next;
950                 ReportAttrError( doc, node, first, REPEATED_ATTRIBUTE);
951                 RemoveAttribute( doc, node, first );
952                 firstRedefined = yes;
953                 first = temp;
954                 second = second->next;
955             }
956             else /* TidyDuplicateAttrs == TidyKeepFirst */
957             {
958                 temp = second->next;
959 
960                 ReportAttrError( doc, node, second, REPEATED_ATTRIBUTE);
961                 RemoveAttribute( doc, node, second );
962 
963                 second = temp;
964             }
965         }
966         if (!firstRedefined)
967             first = first->next;
968     }
969 }
970 
971 /* ignore unknown attributes for proprietary elements */
972 const Attribute* CheckAttribute( TidyDocImpl* doc, Node *node, AttVal *attval )
973 {
974     const Attribute* attribute = attval->dict;
975 
976     if ( attribute != NULL )
977     {
978         if (attribute->versions & VERS_XML)
979         {
980             doc->lexer->isvoyager = yes;
981             if (!cfgBool(doc, TidyHtmlOut))
982             {
983                 SetOptionBool(doc, TidyXhtmlOut, yes);
984                 SetOptionBool(doc, TidyXmlOut, yes);
985             }
986         }
987 
988         ConstrainVersion(doc, AttributeVersions(node, attval));
989         
990         if (attribute->attrchk)
991             attribute->attrchk( doc, node, attval );
992     }
993 
994     if (AttributeIsProprietary(node, attval))
995     {
996         ReportAttrError(doc, node, attval, PROPRIETARY_ATTRIBUTE);
997 
998         if (cfgBool(doc, TidyDropPropAttrs))
999             RemoveAttribute( doc, node, attval );
1000     }
1001 
1002     return attribute;
1003 }
1004 
1005 Bool IsBoolAttribute(AttVal *attval)
1006 {
1007     const Attribute *attribute = ( attval ? attval->dict : NULL );
1008     if ( attribute && attribute->attrchk == CH_BOOL )
1009         return yes;
1010     return no;
1011 }
1012 
1013 Bool attrIsEvent( AttVal* attval )
1014 {
1015     TidyAttrId atid = AttrId( attval );
1016 
1017     return (atid == TidyAttr_OnAFTERUPDATE     ||
1018             atid == TidyAttr_OnBEFOREUNLOAD    ||
1019             atid == TidyAttr_OnBEFOREUPDATE    ||
1020             atid == TidyAttr_OnBLUR            ||
1021             atid == TidyAttr_OnCHANGE          ||
1022             atid == TidyAttr_OnCLICK           ||
1023             atid == TidyAttr_OnDATAAVAILABLE   ||
1024             atid == TidyAttr_OnDATASETCHANGED  ||
1025             atid == TidyAttr_OnDATASETCOMPLETE ||
1026             atid == TidyAttr_OnDBLCLICK        ||
1027             atid == TidyAttr_OnERRORUPDATE     ||
1028             atid == TidyAttr_OnFOCUS           ||
1029             atid == TidyAttr_OnKEYDOWN         ||
1030             atid == TidyAttr_OnKEYPRESS        ||
1031             atid == TidyAttr_OnKEYUP           ||
1032             atid == TidyAttr_OnLOAD            ||
1033             atid == TidyAttr_OnMOUSEDOWN       ||
1034             atid == TidyAttr_OnMOUSEMOVE       ||
1035             atid == TidyAttr_OnMOUSEOUT        ||
1036             atid == TidyAttr_OnMOUSEOVER       ||
1037             atid == TidyAttr_OnMOUSEUP         ||
1038             atid == TidyAttr_OnRESET           ||
1039             atid == TidyAttr_OnROWENTER        ||
1040             atid == TidyAttr_OnROWEXIT         ||
1041             atid == TidyAttr_OnSELECT          ||
1042             atid == TidyAttr_OnSUBMIT          ||
1043             atid == TidyAttr_OnUNLOAD);
1044 }
1045 
1046 static void CheckLowerCaseAttrValue( TidyDocImpl* doc, Node *node, AttVal *attval)
1047 {
1048     tmbstr p;
1049     Bool hasUpper = no;
1050     
1051     if (!AttrHasValue(attval))
1052         return;
1053 
1054     p = attval->value;
1055     
1056     while (*p)
1057     {
1058         if (IsUpper(*p)) /* #501230 - fix by Terry Teague - 09 Jan 02 */
1059         {
1060             hasUpper = yes;
1061             break;
1062         }
1063         p++;
1064     }
1065 
1066     if (hasUpper)
1067     {
1068         Lexer* lexer = doc->lexer;
1069         if (lexer->isvoyager)
1070             ReportAttrError( doc, node, attval, ATTR_VALUE_NOT_LCASE);
1071   
1072         if ( lexer->isvoyager || cfgBool(doc, TidyLowerLiterals) )
1073             attval->value = tmbstrtolower(attval->value);
1074     }
1075 }
1076 
1077 /* methods for checking value of a specific attribute */
1078 
1079 void CheckUrl( TidyDocImpl* doc, Node *node, AttVal *attval)
1080 {
1081     tmbchar c; 
1082     tmbstr dest, p;
1083     uint escape_count = 0, backslash_count = 0;
1084     uint i, pos = 0;
1085     uint len;
1086     
1087     if (!AttrHasValue(attval))
1088     {
1089         ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1090         return;
1091     }
1092 
1093     p = attval->value;
1094     
1095     for (i = 0; 0 != (c = p[i]); ++i)
1096     {
1097         if (c == '\\')
1098         {
1099             ++backslash_count;
1100             if ( cfgBool(doc, TidyFixBackslash) )
1101                 p[i] = '/';
1102         }
1103         else if ((c > 0x7e) || (c <= 0x20) || (strchr("<>", c)))
1104             ++escape_count;
1105     }
1106     
1107     if (