~ubuntu-branches/ubuntu/gutsy/tidy/gutsy

« back to all changes in this revision

Viewing changes to src/attrs.c

  • Committer: Bazaar Package Importer
  • Author(s): Jason Thomas
  • Date: 2005-04-20 11:22:49 UTC
  • mfrom: (0.2.1 upstream) (1.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050420112249-mygnr5vcrutwsen3
Tags: 20050415-1
New upstream release 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* attrs.c -- recognize HTML attributes
2
2
 
3
 
  (c) 1998-2001 (W3C) MIT, INRIA, Keio University
4
 
  See tidy.c for the copyright notice.
 
3
  (c) 1998-2005 (W3C) MIT, ERCIM, Keio University
 
4
  See tidy.h for the copyright notice.
5
5
  
6
6
  CVS Info :
7
7
 
8
 
    $Author: creitzel $ 
9
 
    $Date: 2002/03/01 04:47:12 $ 
10
 
    $Revision: 1.45 $ 
11
 
 
12
 
*/
13
 
 
14
 
#include "platform.h"   /* platform independent stuff */
15
 
#include "html.h"       /* to pull in definition of nodes */
16
 
 
17
 
Attribute *attr_href;
18
 
Attribute *attr_src;
19
 
Attribute *attr_id;
20
 
Attribute *attr_name;
21
 
Attribute *attr_summary;
22
 
Attribute *attr_alt;
23
 
Attribute *attr_longdesc;
24
 
Attribute *attr_usemap;
25
 
Attribute *attr_ismap;
26
 
Attribute *attr_language;
27
 
Attribute *attr_type;
28
 
Attribute *attr_value;
29
 
Attribute *attr_content;
30
 
Attribute *attr_title;
31
 
Attribute *attr_xmlns;
32
 
Attribute *attr_datafld;
33
 
Attribute *attr_width;
34
 
Attribute *attr_height;
35
 
 
36
 
AttrCheck CheckUrl;
37
 
AttrCheck CheckScript;
38
 
AttrCheck CheckName;
39
 
AttrCheck CheckId;
40
 
AttrCheck CheckAlign;
41
 
AttrCheck CheckValign;
42
 
AttrCheck CheckBool;
43
 
AttrCheck CheckLength;
44
 
AttrCheck CheckTarget;
45
 
AttrCheck CheckFsubmit;
46
 
AttrCheck CheckClear;
47
 
AttrCheck CheckShape;
48
 
AttrCheck CheckNumber;
49
 
AttrCheck CheckScope;
50
 
AttrCheck CheckColor;
51
 
AttrCheck CheckVType;
52
 
AttrCheck CheckScroll;
53
 
AttrCheck CheckTextDir;
54
 
AttrCheck CheckLang;
55
 
 
56
 
extern Bool XmlTags;
57
 
extern Bool XmlOut;
58
 
extern char *alt_text;
59
 
 
60
 
#define XHTML_NAMESPACE "http://www.w3.org/1999/xhtml"
61
 
 
62
 
#define HASHSIZE 357
63
 
 
64
 
static Attribute *hashtab[HASHSIZE];
65
 
 
66
 
/*
67
 
 Bind attribute types to procedures to check values.
68
 
 You can add new procedures for better validation
69
 
 and each procedure has access to the node in which
70
 
 the attribute occurred as well as the attribute name
71
 
 and its value.
72
 
 
73
 
 By default, attributes are checked without regard
74
 
 to the element they are found on. You have the choice
75
 
 of making the procedure test which element is involved
76
 
 or in writing methods for each element which controls
77
 
 exactly how the attributes of that element are checked.
78
 
 This latter approach is best for detecting the absence
79
 
 of required attributes.
80
 
*/
81
 
 
82
 
#define TEXT        null
83
 
#define CHARSET     null
84
 
#define TYPE        null
85
 
#define CHARACTER   null
86
 
#define URLS        null
87
 
#define URL         CheckUrl
88
 
#define SCRIPT      CheckScript
89
 
#define ALIGN       CheckAlign
90
 
#define VALIGN      CheckValign
91
 
#define COLOR       CheckColor
92
 
#define CLEAR       CheckClear
93
 
#define BORDER      CheckBool     /* kludge */
94
 
#define LANG        CheckLang
95
 
#define BOOL        CheckBool
96
 
#define COLS        null
97
 
#define NUMBER      CheckNumber
98
 
#define LENGTH      CheckLength
99
 
#define COORDS      null
100
 
#define DATE        null
101
 
#define TEXTDIR     CheckTextDir
102
 
#define IDREFS      null
103
 
#define IDREF       null
104
 
#define IDDEF       CheckId
105
 
#define NAME        CheckName
106
 
#define TFRAME      null
107
 
#define FBORDER     null
108
 
#define MEDIA       null
109
 
#define FSUBMIT     CheckFsubmit
110
 
#define LINKTYPES   null
111
 
#define TRULES      null
112
 
#define SCOPE       CheckScope
113
 
#define SHAPE       CheckShape
114
 
#define SCROLL      CheckScroll
115
 
#define TARGET      CheckTarget
116
 
#define VTYPE       CheckVType
117
 
 
118
 
static struct _attrlist
119
 
{
120
 
    char *name;
121
 
    unsigned versions;
122
 
    AttrCheck *attrchk;
123
 
} attrlist[] =
124
 
{
125
 
    {"abbr",             VERS_HTML40,            TEXT},
126
 
    {"accept-charset",   VERS_HTML40,            CHARSET},
127
 
    {"accept",           VERS_ALL,               TYPE},
128
 
    {"accesskey",        VERS_HTML40,            CHARACTER},
129
 
    {"action",           VERS_ALL,               URL},
130
 
    {"add_date",         VERS_NETSCAPE,          TEXT},     /* A */
131
 
    {"align",            VERS_ALL,               ALIGN},    /* set varies with element */
132
 
    {"alink",            VERS_LOOSE,             COLOR},
133
 
    {"alt",              VERS_ALL,               TEXT},
134
 
    {"archive",          VERS_HTML40,            URLS},     /* space or comma separated list */
135
 
    {"axis",             VERS_HTML40,            TEXT},
136
 
    {"background",       VERS_LOOSE,             URL},
137
 
    {"bgcolor",          VERS_LOOSE,             COLOR},
138
 
    {"bgproperties",     VERS_PROPRIETARY,       TEXT},     /* BODY "fixed" fixes background */
139
 
    {"border",           VERS_ALL,               BORDER},   /* like LENGTH + "border" */
140
 
    {"bordercolor",      VERS_MICROSOFT,         COLOR},    /* used on TABLE */
141
 
    {"bottommargin",     VERS_MICROSOFT,         NUMBER},   /* used on BODY */
142
 
    {"cellpadding",      VERS_FROM32,            LENGTH},   /* % or pixel values */
143
 
    {"cellspacing",      VERS_FROM32,            LENGTH},
144
 
    {"char",             VERS_HTML40,            CHARACTER},
145
 
    {"charoff",          VERS_HTML40,            LENGTH},
146
 
    {"charset",          VERS_HTML40,            CHARSET},
147
 
    {"checked",          VERS_ALL,               BOOL},     /* i.e. "checked" or absent */
148
 
    {"cite",             VERS_HTML40,            URL},
149
 
    {"class",            VERS_HTML40,            TEXT},
150
 
    {"classid",          VERS_HTML40,            URL},
151
 
    {"clear",            VERS_LOOSE,             CLEAR},    /* BR: left, right, all */
152
 
    {"code",             VERS_LOOSE,             TEXT},     /* APPLET */
153
 
    {"codebase",         VERS_HTML40,            URL},      /* OBJECT */
154
 
    {"codetype",         VERS_HTML40,            TYPE},     /* OBJECT */
155
 
    {"color",            VERS_LOOSE,             COLOR},    /* BASEFONT, FONT */
156
 
    {"cols",             VERS_IFRAME,            COLS},     /* TABLE & FRAMESET */
157
 
    {"colspan",          VERS_FROM32,            NUMBER},
158
 
    {"compact",          VERS_ALL,               BOOL},     /* lists */
159
 
    {"content",          VERS_ALL,               TEXT},     /* META */
160
 
    {"coords",           VERS_FROM32,            COORDS},   /* AREA, A */    
161
 
    {"data",             VERS_HTML40,            URL},      /* OBJECT */
162
 
    {"datafld",          VERS_MICROSOFT,         TEXT},     /* used on DIV, IMG */
163
 
    {"dataformatas",     VERS_MICROSOFT,         TEXT},     /* used on DIV, IMG */
164
 
    {"datapagesize",     VERS_MICROSOFT,         NUMBER},   /* used on DIV, IMG */
165
 
    {"datasrc",          VERS_MICROSOFT,         URL},      /* used on TABLE */
166
 
    {"datetime",         VERS_HTML40,            DATE},     /* INS, DEL */
167
 
    {"declare",          VERS_HTML40,            BOOL},     /* OBJECT */
168
 
    {"defer",            VERS_HTML40,            BOOL},     /* SCRIPT */
169
 
    {"dir",              VERS_HTML40,            TEXTDIR},  /* ltr or rtl */
170
 
    {"disabled",         VERS_HTML40,            BOOL},     /* form fields */
171
 
    {"enctype",          VERS_ALL,               TYPE},     /* FORM */
172
 
    {"face",             VERS_LOOSE,             TEXT},     /* BASEFONT, FONT */
173
 
    {"for",              VERS_HTML40,            IDREF},    /* LABEL */
174
 
    {"frame",            VERS_HTML40,            TFRAME},   /* TABLE */
175
 
    {"frameborder",      VERS_FRAMESET,          FBORDER},  /* 0 or 1 */
176
 
    {"framespacing",     VERS_PROPRIETARY,       NUMBER},   /* pixel value */
177
 
    {"gridx",            VERS_PROPRIETARY,       NUMBER},   /* TABLE Adobe golive*/
178
 
    {"gridy",            VERS_PROPRIETARY,       NUMBER},   /* TABLE Adobe golive */
179
 
    {"headers",          VERS_HTML40,            IDREFS},   /* table cells */
180
 
    {"height",           VERS_ALL,               LENGTH},   /* pixels only for TH/TD */
181
 
    {"href",             VERS_ALL,               URL},      /* A, AREA, LINK and BASE */
182
 
    {"hreflang",         VERS_HTML40,            LANG},     /* A, LINK */
183
 
    {"hspace",           VERS_ALL,               NUMBER},   /* APPLET, IMG, OBJECT */
184
 
    {"http-equiv",       VERS_ALL,               TEXT},     /* META */
185
 
    {"id",               VERS_HTML40,            IDDEF},
186
 
    {"ismap",            VERS_ALL,               BOOL},     /* IMG */
187
 
    {"label",            VERS_HTML40,            TEXT},     /* OPT, OPTGROUP */
188
 
    {"lang",             VERS_HTML40,            LANG},
189
 
    {"language",         VERS_LOOSE,             TEXT},     /* SCRIPT */
190
 
    {"last_modified",    VERS_NETSCAPE,          TEXT},     /* A */
191
 
    {"last_visit",       VERS_NETSCAPE,          TEXT},     /* A */
192
 
    {"leftmargin",       VERS_MICROSOFT,         NUMBER},   /* used on BODY */
193
 
    {"link",             VERS_LOOSE,             COLOR},    /* BODY */
194
 
    {"longdesc",         VERS_HTML40,            URL},      /* IMG */
195
 
    {"lowsrc",           VERS_PROPRIETARY,       URL},      /* IMG */
196
 
    {"marginheight",     VERS_IFRAME,            NUMBER},   /* FRAME, IFRAME, BODY */
197
 
    {"marginwidth",      VERS_IFRAME,            NUMBER},   /* ditto */
198
 
    {"maxlength",        VERS_ALL,               NUMBER},   /* INPUT */
199
 
    {"media",            VERS_HTML40,            MEDIA},    /* STYLE, LINK */
200
 
    {"method",           VERS_ALL,               FSUBMIT},  /* FORM: get or post */
201
 
    {"multiple",         VERS_ALL,               BOOL},     /* SELECT */
202
 
    {"name",             VERS_ALL,               NAME},
203
 
    {"nohref",           VERS_FROM32,            BOOL},     /* AREA */
204
 
    {"noresize",         VERS_FRAMESET,          BOOL},     /* FRAME */
205
 
    {"noshade",          VERS_LOOSE,             BOOL},     /* HR */
206
 
    {"nowrap",           VERS_LOOSE,             BOOL},     /* table cells */
207
 
    {"object",           VERS_HTML40_LOOSE,      TEXT},     /* APPLET */
208
 
    {"onblur",           VERS_EVENTS,            SCRIPT},   /* event */
209
 
    {"onchange",         VERS_EVENTS,            SCRIPT},   /* event */
210
 
    {"onclick",          VERS_EVENTS,            SCRIPT},   /* event */
211
 
    {"ondblclick",       VERS_EVENTS,            SCRIPT},   /* event */
212
 
    {"onkeydown",        VERS_EVENTS,            SCRIPT},   /* event */
213
 
    {"onkeypress",       VERS_EVENTS,            SCRIPT},   /* event */
214
 
    {"onkeyup",          VERS_EVENTS,            SCRIPT},   /* event */
215
 
    {"onload",           VERS_EVENTS,            SCRIPT},   /* event */
216
 
    {"onmousedown",      VERS_EVENTS,            SCRIPT},   /* event */
217
 
    {"onmousemove",      VERS_EVENTS,            SCRIPT},   /* event */
218
 
    {"onmouseout",       VERS_EVENTS,            SCRIPT},   /* event */
219
 
    {"onmouseover",      VERS_EVENTS,            SCRIPT},   /* event */
220
 
    {"onmouseup",        VERS_EVENTS,            SCRIPT},   /* event */
221
 
    {"onsubmit",         VERS_EVENTS,            SCRIPT},   /* event */
222
 
    {"onreset",          VERS_EVENTS,            SCRIPT},   /* event */
223
 
    {"onselect",         VERS_EVENTS,            SCRIPT},   /* event */
224
 
    {"onunload",         VERS_EVENTS,            SCRIPT},   /* event */
225
 
    {"onfocus",          VERS_EVENTS,            SCRIPT},   /* event */
226
 
    {"onafterupdate",    VERS_MICROSOFT,         SCRIPT},   /* form fields */
227
 
    {"onbeforeupdate",   VERS_MICROSOFT,         SCRIPT},   /* form fields */
228
 
    {"onerrorupdate",    VERS_MICROSOFT,         SCRIPT},   /* form fields */
229
 
    {"onrowenter",       VERS_MICROSOFT,         SCRIPT},   /* form fields */
230
 
    {"onrowexit",        VERS_MICROSOFT,         SCRIPT},   /* form fields */
231
 
    {"onbeforeunload",   VERS_MICROSOFT,         SCRIPT},   /* form fields */
232
 
    {"ondatasetchanged", VERS_MICROSOFT,         SCRIPT},   /* object, applet */
233
 
    {"ondataavailable",  VERS_MICROSOFT,         SCRIPT},   /* object, applet */
234
 
    {"ondatasetcomplete",VERS_MICROSOFT,         SCRIPT},   /* object, applet */
235
 
    {"profile",          VERS_HTML40,            URL},      /* HEAD */
236
 
    {"prompt",           VERS_LOOSE,             TEXT},     /* ISINDEX */
237
 
    {"readonly",         VERS_HTML40,            BOOL},     /* form fields */
238
 
    {"rel",              VERS_ALL,               LINKTYPES}, /* A, LINK */
239
 
    {"rev",              VERS_ALL,               LINKTYPES}, /* A, LINK */
240
 
    {"rightmargin",      VERS_MICROSOFT,         NUMBER},   /* used on BODY */
241
 
    {"rows",             VERS_ALL,               NUMBER},   /* TEXTAREA */
242
 
    {"rowspan",          VERS_ALL,               NUMBER},   /* table cells */
243
 
    {"rules",            VERS_HTML40,            TRULES},   /* TABLE */
244
 
    {"scheme",           VERS_HTML40,            TEXT},     /* META */
245
 
    {"scope",            VERS_HTML40,            SCOPE},    /* table cells */
246
 
    {"scrolling",        VERS_IFRAME,            SCROLL},   /* yes, no or auto */
247
 
    {"selected",         VERS_ALL,               BOOL},     /* OPTION */
248
 
    {"shape",            VERS_FROM32,            SHAPE},    /* AREA, A */
249
 
    {"showgrid",         VERS_PROPRIETARY,       BOOL},     /* TABLE Adobe golive */
250
 
    {"showgridx",        VERS_PROPRIETARY,       BOOL},     /* TABLE Adobe golive*/
251
 
    {"showgridy",        VERS_PROPRIETARY,       BOOL},     /* TABLE Adobe golive*/
252
 
    {"size",             VERS_LOOSE,             NUMBER},   /* HR, FONT, BASEFONT, SELECT */
253
 
    {"span",             VERS_HTML40,            NUMBER},   /* COL, COLGROUP */
254
 
    {"src",              VERS_ALL,               URL},      /* IMG, FRAME, IFRAME */
255
 
    {"standby",          VERS_HTML40,            TEXT},     /* OBJECT */
256
 
    {"start",            VERS_ALL,               NUMBER},   /* OL */
257
 
    {"style",            VERS_HTML40,            TEXT},
258
 
    {"summary",          VERS_HTML40,            TEXT},     /* TABLE */
259
 
    {"tabindex",         VERS_HTML40,            NUMBER},   /* fields, OBJECT  and A */
260
 
    {"target",           VERS_HTML40,            TARGET},   /* names a frame/window */
261
 
    {"text",             VERS_LOOSE,             COLOR},    /* BODY */
262
 
    {"title",            VERS_HTML40,            TEXT},     /* text tool tip */
263
 
    {"topmargin",        VERS_MICROSOFT,         NUMBER},   /* used on BODY */
264
 
    {"type",             VERS_FROM32,            TYPE},     /* also used by SPACER */
265
 
    {"usemap",           VERS_ALL,               BOOL},     /* things with images */
266
 
    {"valign",           VERS_FROM32,            VALIGN},
267
 
    {"value",            VERS_ALL,               TEXT},     /* OPTION, PARAM */
268
 
    {"valuetype",        VERS_HTML40,            VTYPE},    /* PARAM: data, ref, object */
269
 
    {"version",          VERS_ALL,               TEXT},     /* HTML */
270
 
    {"vlink",            VERS_LOOSE,             COLOR},    /* BODY */
271
 
    {"vspace",           VERS_LOOSE,             NUMBER},   /* IMG, OBJECT, APPLET */
272
 
    {"width",            VERS_ALL,               LENGTH},   /* pixels only for TD/TH */
273
 
    {"wrap",             VERS_NETSCAPE,          TEXT},     /* textarea */
274
 
    {"xml:lang",         VERS_XML,               TEXT},     /* XML language */
275
 
    {"xml:space",        VERS_XML,               TEXT},     /* XML language */
276
 
    {"xmlns",            VERS_ALL,               TEXT},     /* name space */
277
 
    {"rbspan",           VERS_XHTML11,           NUMBER},   /* ruby markup */
278
 
   
279
 
   /* this must be the final entry */
280
 
    {null,               0,                      0}
 
8
    $Author: arnaud02 $ 
 
9
    $Date: 2005/04/15 13:52:06 $ 
 
10
    $Revision: 1.110 $ 
 
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 const Attribute attribute_defs [] =
 
21
{
 
22
  { TidyAttr_UNKNOWN,           "unknown!",          VERS_PROPRIETARY,  NULL      }, 
 
23
  { TidyAttr_ABBR,              "abbr",              VERS_HTML40,       PCDATA    }, 
 
24
  { TidyAttr_ACCEPT,            "accept",            VERS_ALL,          TYPE      }, 
 
25
  { TidyAttr_ACCEPT_CHARSET,    "accept-charset",    VERS_HTML40,       CHARSET   }, 
 
26
  { TidyAttr_ACCESSKEY,         "accesskey",         VERS_HTML40,       CHARACTER }, 
 
27
  { TidyAttr_ACTION,            "action",            VERS_ALL,          URL       }, 
 
28
  { TidyAttr_ADD_DATE,          "add_date",          VERS_NETSCAPE,     PCDATA    }, /* A */
 
29
  { TidyAttr_ALIGN,             "align",             VERS_ALL,          ALIGN     }, /* varies by element */
 
30
  { TidyAttr_ALINK,             "alink",             VERS_LOOSE,        COLOR     }, 
 
31
  { TidyAttr_ALT,               "alt",               VERS_ALL,          PCDATA    }, /* nowrap */
 
32
  { TidyAttr_ARCHIVE,           "archive",           VERS_HTML40,       URLS      }, /* space or comma separated list */
 
33
  { TidyAttr_AXIS,              "axis",              VERS_HTML40,       PCDATA    }, 
 
34
  { TidyAttr_BACKGROUND,        "background",        VERS_LOOSE,        URL       }, 
 
35
  { TidyAttr_BGCOLOR,           "bgcolor",           VERS_LOOSE,        COLOR     }, 
 
36
  { TidyAttr_BGPROPERTIES,      "bgproperties",      VERS_PROPRIETARY,  PCDATA    }, /* BODY "fixed" fixes background */
 
37
  { TidyAttr_BORDER,            "border",            VERS_ALL,          BORDER    }, /* like LENGTH + "border" */
 
38
  { TidyAttr_BORDERCOLOR,       "bordercolor",       VERS_MICROSOFT,    COLOR     }, /* used on TABLE */
 
39
  { TidyAttr_BOTTOMMARGIN,      "bottommargin",      VERS_MICROSOFT,    NUMBER    }, /* used on BODY */
 
40
  { TidyAttr_CELLPADDING,       "cellpadding",       VERS_FROM32,       LENGTH    }, /* % or pixel values */
 
41
  { TidyAttr_CELLSPACING,       "cellspacing",       VERS_FROM32,       LENGTH    }, 
 
42
  { TidyAttr_CHAR,              "char",              VERS_HTML40,       CHARACTER }, 
 
43
  { TidyAttr_CHAROFF,           "charoff",           VERS_HTML40,       LENGTH    }, 
 
44
  { TidyAttr_CHARSET,           "charset",           VERS_HTML40,       CHARSET   }, 
 
45
  { TidyAttr_CHECKED,           "checked",           VERS_ALL,          BOOL      }, /* i.e. "checked" or absent */
 
46
  { TidyAttr_CITE,              "cite",              VERS_HTML40,       URL       }, 
 
47
  { TidyAttr_CLASS,             "class",             VERS_HTML40,       PCDATA    }, 
 
48
  { TidyAttr_CLASSID,           "classid",           VERS_HTML40,       URL       }, 
 
49
  { TidyAttr_CLEAR,             "clear",             VERS_LOOSE,        CLEAR     }, /* BR: left, right, all */
 
50
  { TidyAttr_CODE,              "code",              VERS_LOOSE,        PCDATA    }, /* APPLET */
 
51
  { TidyAttr_CODEBASE,          "codebase",          VERS_HTML40,       URL       }, /* OBJECT */
 
52
  { TidyAttr_CODETYPE,          "codetype",          VERS_HTML40,       TYPE      }, /* OBJECT */
 
53
  { TidyAttr_COLOR,             "color",             VERS_LOOSE,        COLOR     }, /* BASEFONT, FONT */
 
54
  { TidyAttr_COLS,              "cols",              VERS_IFRAME,       COLS      }, /* TABLE & FRAMESET */
 
55
  { TidyAttr_COLSPAN,           "colspan",           VERS_FROM32,       NUMBER    }, 
 
56
  { TidyAttr_COMPACT,           "compact",           VERS_ALL,          BOOL      }, /* lists */
 
57
  { TidyAttr_CONTENT,           "content",           VERS_ALL,          PCDATA    }, 
 
58
  { TidyAttr_COORDS,            "coords",            VERS_FROM32,       COORDS    }, /* AREA, A */
 
59
  { TidyAttr_DATA,              "data",              VERS_HTML40,       URL       }, /* OBJECT */
 
60
  { TidyAttr_DATAFLD,           "datafld",           VERS_MICROSOFT,    PCDATA    }, /* used on DIV, IMG */
 
61
  { TidyAttr_DATAFORMATAS,      "dataformatas",      VERS_MICROSOFT,    PCDATA    }, /* used on DIV, IMG */
 
62
  { TidyAttr_DATAPAGESIZE,      "datapagesize",      VERS_MICROSOFT,    NUMBER    }, /* used on DIV, IMG */
 
63
  { TidyAttr_DATASRC,           "datasrc",           VERS_MICROSOFT,    URL       }, /* used on TABLE */
 
64
  { TidyAttr_DATETIME,          "datetime",          VERS_HTML40,       DATE      }, /* INS, DEL */
 
65
  { TidyAttr_DECLARE,           "declare",           VERS_HTML40,       BOOL      }, /* OBJECT */
 
66
  { TidyAttr_DEFER,             "defer",             VERS_HTML40,       BOOL      }, /* SCRIPT */
 
67
  { TidyAttr_DIR,               "dir",               VERS_HTML40,       TEXTDIR   }, /* ltr or rtl */
 
68
  { TidyAttr_DISABLED,          "disabled",          VERS_HTML40,       BOOL      }, /* form fields */
 
69
  { TidyAttr_ENCODING,          "encoding",          VERS_XML,          PCDATA    }, /* <?xml?> */
 
70
  { TidyAttr_ENCTYPE,           "enctype",           VERS_ALL,          TYPE      }, /* FORM */
 
71
  { TidyAttr_FACE,              "face",              VERS_LOOSE,        PCDATA    }, /* BASEFONT, FONT */
 
72
  { TidyAttr_FOR,               "for",               VERS_HTML40,       IDREF     }, /* LABEL */
 
73
  { TidyAttr_FRAME,             "frame",             VERS_HTML40,       TFRAME    }, /* TABLE */
 
74
  { TidyAttr_FRAMEBORDER,       "frameborder",       VERS_FRAMESET,     FBORDER   }, /* 0 or 1 */
 
75
  { TidyAttr_FRAMESPACING,      "framespacing",      VERS_PROPRIETARY,  NUMBER    }, 
 
76
  { TidyAttr_GRIDX,             "gridx",             VERS_PROPRIETARY,  NUMBER    }, /* TABLE Adobe golive*/
 
77
  { TidyAttr_GRIDY,             "gridy",             VERS_PROPRIETARY,  NUMBER    }, /* TABLE Adobe golive */
 
78
  { TidyAttr_HEADERS,           "headers",           VERS_HTML40,       IDREFS    }, /* table cells */
 
79
  { TidyAttr_HEIGHT,            "height",            VERS_ALL,          LENGTH    }, /* pixels only for TH/TD */
 
80
  { TidyAttr_HREF,              "href",              VERS_ALL,          URL       }, /* A, AREA, LINK and BASE */
 
81
  { TidyAttr_HREFLANG,          "hreflang",          VERS_HTML40,       LANG      }, /* A, LINK */
 
82
  { TidyAttr_HSPACE,            "hspace",            VERS_ALL,          NUMBER    }, /* APPLET, IMG, OBJECT */
 
83
  { TidyAttr_HTTP_EQUIV,        "http-equiv",        VERS_ALL,          PCDATA    }, /* META */
 
84
  { TidyAttr_ID,                "id",                VERS_HTML40,       IDDEF     }, 
 
85
  { TidyAttr_ISMAP,             "ismap",             VERS_ALL,          BOOL      }, /* IMG */
 
86
  { TidyAttr_LABEL,             "label",             VERS_HTML40,       PCDATA    }, /* OPT, OPTGROUP */
 
87
  { TidyAttr_LANG,              "lang",              VERS_HTML40,       LANG      }, 
 
88
  { TidyAttr_LANGUAGE,          "language",          VERS_LOOSE,        PCDATA    }, /* SCRIPT */
 
89
  { TidyAttr_LAST_MODIFIED,     "last_modified",     VERS_NETSCAPE,     PCDATA    }, /* A */
 
90
  { TidyAttr_LAST_VISIT,        "last_visit",        VERS_NETSCAPE,     PCDATA    }, /* A */
 
91
  { TidyAttr_LEFTMARGIN,        "leftmargin",        VERS_MICROSOFT,    NUMBER    }, /* used on BODY */
 
92
  { TidyAttr_LINK,              "link",              VERS_LOOSE,        COLOR     }, /* BODY */
 
93
  { TidyAttr_LONGDESC,          "longdesc",          VERS_HTML40,       URL       }, /* IMG */
 
94
  { TidyAttr_LOWSRC,            "lowsrc",            VERS_PROPRIETARY,  URL       }, /* IMG */
 
95
  { TidyAttr_MARGINHEIGHT,      "marginheight",      VERS_IFRAME,       NUMBER    }, /* FRAME, IFRAME, BODY */
 
96
  { TidyAttr_MARGINWIDTH,       "marginwidth",       VERS_IFRAME,       NUMBER    }, /* ditto */
 
97
  { TidyAttr_MAXLENGTH,         "maxlength",         VERS_ALL,          NUMBER    }, /* INPUT */
 
98
  { TidyAttr_MEDIA,             "media",             VERS_HTML40,       MEDIA     }, /* STYLE, LINK */
 
99
  { TidyAttr_METHOD,            "method",            VERS_ALL,          FSUBMIT   }, /* FORM: get or post */
 
100
  { TidyAttr_MULTIPLE,          "multiple",          VERS_ALL,          BOOL      }, /* SELECT */
 
101
  { TidyAttr_NAME,              "name",              VERS_ALL,          NAME      }, 
 
102
  { TidyAttr_NOHREF,            "nohref",            VERS_FROM32,       BOOL      }, /* AREA */
 
103
  { TidyAttr_NORESIZE,          "noresize",          VERS_FRAMESET,     BOOL      }, /* FRAME */
 
104
  { TidyAttr_NOSHADE,           "noshade",           VERS_LOOSE,        BOOL      }, /* HR */
 
105
  { TidyAttr_NOWRAP,            "nowrap",            VERS_LOOSE,        BOOL      }, /* table cells */
 
106
  { TidyAttr_OBJECT,            "object",            VERS_HTML40_LOOSE, PCDATA    }, /* APPLET */
 
107
  { TidyAttr_OnAFTERUPDATE,     "onafterupdate",     VERS_MICROSOFT,    SCRIPT    }, 
 
108
  { TidyAttr_OnBEFOREUNLOAD,    "onbeforeunload",    VERS_MICROSOFT,    SCRIPT    }, 
 
109
  { TidyAttr_OnBEFOREUPDATE,    "onbeforeupdate",    VERS_MICROSOFT,    SCRIPT    }, 
 
110
  { TidyAttr_OnBLUR,            "onblur",            VERS_EVENTS,       SCRIPT    }, /* event */
 
111
  { TidyAttr_OnCHANGE,          "onchange",          VERS_EVENTS,       SCRIPT    }, /* event */
 
112
  { TidyAttr_OnCLICK,           "onclick",           VERS_EVENTS,       SCRIPT    }, /* event */
 
113
  { TidyAttr_OnDATAAVAILABLE,   "ondataavailable",   VERS_MICROSOFT,    SCRIPT    }, /* object, applet */
 
114
  { TidyAttr_OnDATASETCHANGED,  "ondatasetchanged",  VERS_MICROSOFT,    SCRIPT    }, /* object, applet */
 
115
  { TidyAttr_OnDATASETCOMPLETE, "ondatasetcomplete", VERS_MICROSOFT,    SCRIPT    }, 
 
116
  { TidyAttr_OnDBLCLICK,        "ondblclick",        VERS_EVENTS,       SCRIPT    }, /* event */
 
117
  { TidyAttr_OnERRORUPDATE,     "onerrorupdate",     VERS_MICROSOFT,    SCRIPT    }, /* form fields */
 
118
  { TidyAttr_OnFOCUS,           "onfocus",           VERS_EVENTS,       SCRIPT    }, /* event */
 
119
  { TidyAttr_OnKEYDOWN,         "onkeydown",         VERS_EVENTS,       SCRIPT    }, /* event */
 
120
  { TidyAttr_OnKEYPRESS,        "onkeypress",        VERS_EVENTS,       SCRIPT    }, /* event */
 
121
  { TidyAttr_OnKEYUP,           "onkeyup",           VERS_EVENTS,       SCRIPT    }, /* event */
 
122
  { TidyAttr_OnLOAD,            "onload",            VERS_EVENTS,       SCRIPT    }, /* event */
 
123
  { TidyAttr_OnMOUSEDOWN,       "onmousedown",       VERS_EVENTS,       SCRIPT    }, /* event */
 
124
  { TidyAttr_OnMOUSEMOVE,       "onmousemove",       VERS_EVENTS,       SCRIPT    }, /* event */
 
125
  { TidyAttr_OnMOUSEOUT,        "onmouseout",        VERS_EVENTS,       SCRIPT    }, /* event */
 
126
  { TidyAttr_OnMOUSEOVER,       "onmouseover",       VERS_EVENTS,       SCRIPT    }, /* event */
 
127
  { TidyAttr_OnMOUSEUP,         "onmouseup",         VERS_EVENTS,       SCRIPT    }, /* event */
 
128
  { TidyAttr_OnRESET,           "onreset",           VERS_EVENTS,       SCRIPT    }, /* event */
 
129
  { TidyAttr_OnROWENTER,        "onrowenter",        VERS_MICROSOFT,    SCRIPT    }, /* form fields */
 
130
  { TidyAttr_OnROWEXIT,         "onrowexit",         VERS_MICROSOFT,    SCRIPT    }, /* form fields */
 
131
  { TidyAttr_OnSELECT,          "onselect",          VERS_EVENTS,       SCRIPT    }, /* event */
 
132
  { TidyAttr_OnSUBMIT,          "onsubmit",          VERS_EVENTS,       SCRIPT    }, /* event */
 
133
  { TidyAttr_OnUNLOAD,          "onunload",          VERS_EVENTS,       SCRIPT    }, /* event */
 
134
  { TidyAttr_PROFILE,           "profile",           VERS_HTML40,       URL       }, /* HEAD */
 
135
  { TidyAttr_PROMPT,            "prompt",            VERS_LOOSE,        PCDATA    }, /* ISINDEX */
 
136
  { TidyAttr_RBSPAN,            "rbspan",            VERS_XHTML11,      NUMBER    }, /* ruby markup */
 
137
  { TidyAttr_READONLY,          "readonly",          VERS_HTML40,       BOOL      }, /* form fields */
 
138
  { TidyAttr_REL,               "rel",               VERS_ALL,          LINKTYPES }, 
 
139
  { TidyAttr_REV,               "rev",               VERS_ALL,          LINKTYPES }, 
 
140
  { TidyAttr_RIGHTMARGIN,       "rightmargin",       VERS_MICROSOFT,    NUMBER    }, /* used on BODY */
 
141
  { TidyAttr_ROWS,              "rows",              VERS_ALL,          NUMBER    }, /* TEXTAREA */
 
142
  { TidyAttr_ROWSPAN,           "rowspan",           VERS_ALL,          NUMBER    }, /* table cells */
 
143
  { TidyAttr_RULES,             "rules",             VERS_HTML40,       TRULES    }, /* TABLE */
 
144
  { TidyAttr_SCHEME,            "scheme",            VERS_HTML40,       PCDATA    }, /* META */
 
145
  { TidyAttr_SCOPE,             "scope",             VERS_HTML40,       SCOPE     }, /* table cells */
 
146
  { TidyAttr_SCROLLING,         "scrolling",         VERS_IFRAME,       SCROLL    }, /* yes, no or auto */
 
147
  { TidyAttr_SELECTED,          "selected",          VERS_ALL,          BOOL      }, /* OPTION */
 
148
  { TidyAttr_SHAPE,             "shape",             VERS_FROM32,       SHAPE     }, /* AREA, A */
 
149
  { TidyAttr_SHOWGRID,          "showgrid",          VERS_PROPRIETARY,  BOOL      }, /* TABLE Adobe golive */
 
150
  { TidyAttr_SHOWGRIDX,         "showgridx",         VERS_PROPRIETARY,  BOOL      }, /* TABLE Adobe golive*/
 
151
  { TidyAttr_SHOWGRIDY,         "showgridy",         VERS_PROPRIETARY,  BOOL      }, /* TABLE Adobe golive*/
 
152
  { TidyAttr_SIZE,              "size",              VERS_LOOSE,        NUMBER    }, /* HR, FONT, BASEFONT, SELECT */
 
153
  { TidyAttr_SPAN,              "span",              VERS_HTML40,       NUMBER    }, /* COL, COLGROUP */
 
154
  { TidyAttr_SRC,               "src",               VERS_ALL,          URL       }, /* IMG, FRAME, IFRAME */
 
155
  { TidyAttr_STANDBY,           "standby",           VERS_HTML40,       PCDATA    }, /* OBJECT */
 
156
  { TidyAttr_START,             "start",             VERS_ALL,          NUMBER    }, /* OL */
 
157
  { TidyAttr_STYLE,             "style",             VERS_HTML40,       PCDATA    }, 
 
158
  { TidyAttr_SUMMARY,           "summary",           VERS_HTML40,       PCDATA    }, /* TABLE */
 
159
  { TidyAttr_TABINDEX,          "tabindex",          VERS_HTML40,       NUMBER    }, /* fields, OBJECT  and A */
 
160
  { TidyAttr_TARGET,            "target",            VERS_HTML40,       TARGET    }, /* names a frame/window */
 
161
  { TidyAttr_TEXT,              "text",              VERS_LOOSE,        COLOR     }, /* BODY */
 
162
  { TidyAttr_TITLE,             "title",             VERS_HTML40,       PCDATA    }, /* text tool tip */
 
163
  { TidyAttr_TOPMARGIN,         "topmargin",         VERS_MICROSOFT,    NUMBER    }, /* used on BODY */
 
164
  { TidyAttr_TYPE,              "type",              VERS_FROM32,       TYPE      }, /* also used by SPACER */
 
165
  { TidyAttr_USEMAP,            "usemap",            VERS_ALL,          URL       }, /* things with images */
 
166
  { TidyAttr_VALIGN,            "valign",            VERS_FROM32,       VALIGN    }, 
 
167
  { TidyAttr_VALUE,             "value",             VERS_ALL,          PCDATA    }, 
 
168
  { TidyAttr_VALUETYPE,         "valuetype",         VERS_HTML40,       VTYPE     }, /* PARAM: data, ref, object */
 
169
  { TidyAttr_VERSION,           "version",           VERS_ALL|VERS_XML, PCDATA    }, /* HTML <?xml?> */
 
170
  { TidyAttr_VLINK,             "vlink",             VERS_LOOSE,        COLOR     }, /* BODY */
 
171
  { TidyAttr_VSPACE,            "vspace",            VERS_LOOSE,        NUMBER    }, /* IMG, OBJECT, APPLET */
 
172
  { TidyAttr_WIDTH,             "width",             VERS_ALL,          LENGTH    }, /* pixels only for TD/TH */
 
173
  { TidyAttr_WRAP,              "wrap",              VERS_NETSCAPE,     PCDATA    }, /* textarea */
 
174
  { TidyAttr_XML_LANG,          "xml:lang",          VERS_XML,          LANG      }, /* XML language */
 
175
  { TidyAttr_XML_SPACE,         "xml:space",         VERS_XML,          PCDATA    }, /* XML white space */
 
176
 
 
177
  /* todo: VERS_ALL is wrong! */
 
178
  { TidyAttr_XMLNS,             "xmlns",             VERS_ALL,          PCDATA    }, /* name space */
 
179
  { TidyAttr_EVENT,             "event",             VERS_HTML40,       PCDATA    }, /* reserved for <script> */
 
180
  { TidyAttr_METHODS,           "methods",           VERS_HTML20,       PCDATA    }, /* for <a>, never implemented */
 
181
  { TidyAttr_N,                 "n",                 VERS_HTML20,       PCDATA    }, /* for <nextid> */
 
182
  { TidyAttr_SDAFORM,           "sdaform",           VERS_HTML20,       PCDATA    }, /* SDATA attribute in HTML 2.0 */
 
183
  { TidyAttr_SDAPREF,           "sdapref",           VERS_HTML20,       PCDATA    }, /* SDATA attribute in HTML 2.0 */
 
184
  { TidyAttr_SDASUFF,           "sdasuff",           VERS_HTML20,       PCDATA    }, /* SDATA attribute in HTML 2.0 */
 
185
  { TidyAttr_URN,               "urn",               VERS_HTML20,       PCDATA    }, /* for <a>, never implemented */
 
186
 
 
187
  /* this must be the final entry */
 
188
  { N_TIDY_ATTRIBS,             NULL,                VERS_UNKNOWN,      NULL      }
281
189
};
282
190
 
 
191
static uint AttributeVersions(Node* node, AttVal* attval)
 
192
{
 
193
    uint i;
 
194
 
 
195
    if (!attval || !attval->dict)
 
196
        return VERS_UNKNOWN;
 
197
 
 
198
    if (!node || !node->tag || !node->tag->attrvers)
 
199
        return attval->dict->versions;
 
200
 
 
201
    for (i = 0; node->tag->attrvers[i].attribute; ++i)
 
202
        if (node->tag->attrvers[i].attribute == attval->dict->id)
 
203
            return node->tag->attrvers[i].versions;
 
204
 
 
205
    return attval->dict->versions & VERS_ALL
 
206
             ? VERS_UNKNOWN
 
207
             : attval->dict->versions;
 
208
 
 
209
}
 
210
 
 
211
 
 
212
/* return the version of the attribute "id" of element "node" */
 
213
uint NodeAttributeVersions( Node* node, TidyAttrId id )
 
214
{
 
215
    uint i;
 
216
 
 
217
    if (!node || !node->tag || !node->tag->attrvers)
 
218
        return VERS_UNKNOWN;
 
219
 
 
220
    for (i = 0; node->tag->attrvers[i].attribute; ++i)
 
221
        if (node->tag->attrvers[i].attribute == id)
 
222
            return node->tag->attrvers[i].versions;
 
223
 
 
224
    return VERS_UNKNOWN;
 
225
}
 
226
 
 
227
/* returns true if the element is a W3C defined element */
 
228
/* but the element/attribute combination is not         */
 
229
static Bool AttributeIsProprietary(Node* node, AttVal* attval)
 
230
{
 
231
    if (!node || !attval)
 
232
        return no;
 
233
 
 
234
    if (!node->tag)
 
235
        return no;
 
236
 
 
237
    if (!(node->tag->versions & VERS_ALL))
 
238
        return no;
 
239
 
 
240
    if (AttributeVersions(node, attval) & VERS_ALL)
 
241
        return no;
 
242
 
 
243
    return yes;
 
244
}
 
245
 
283
246
/* used by CheckColor() */
284
 
static struct _colors
285
 
{
286
 
    char *name;
287
 
    char *hex;
288
 
} colors[] =
289
 
{
290
 
    {"black",   "#000000"}, {"green",  "#008000"},
291
 
    {"silver",  "#C0C0C0"}, {"lime",   "#00FF00"},
292
 
    {"gray",    "#808080"}, {"olive",  "#808000"},
293
 
    {"white",   "#FFFFFF"}, {"yellow", "#FFFF00"},
294
 
    {"maroon",  "#800000"}, {"navy",   "#000080"},
295
 
    {"red",     "#FF0000"}, {"blue",   "#0000FF"},
296
 
    {"purple",  "#800080"}, {"teal",   "#008080"},
297
 
    {"fuchsia", "#FF00FF"}, {"aqua",   "#00FFFF"},
298
 
    {null,      null}
299
 
};
300
 
 
301
 
static unsigned hash(char *s)
302
 
{
303
 
    unsigned hashval;
 
247
struct _colors
 
248
{
 
249
    ctmbstr name;
 
250
    ctmbstr hex;
 
251
};
 
252
 
 
253
static const struct _colors colors[] =
 
254
{
 
255
    { "black",   "#000000" },
 
256
    { "green",   "#008000" },
 
257
    { "silver",  "#C0C0C0" },
 
258
    { "lime",    "#00FF00" },
 
259
    { "gray",    "#808080" },
 
260
    { "olive",   "#808000" },
 
261
    { "white",   "#FFFFFF" },
 
262
    { "yellow",  "#FFFF00" },
 
263
    { "maroon",  "#800000" },
 
264
    { "navy",    "#000080" },
 
265
    { "red",     "#FF0000" },
 
266
    { "blue",    "#0000FF" },
 
267
    { "purple",  "#800080" },
 
268
    { "teal",    "#008080" },
 
269
    { "fuchsia", "#FF00FF" },
 
270
    { "aqua",    "#00FFFF" },
 
271
    { NULL,      NULL      }
 
272
};
 
273
 
 
274
static ctmbstr GetColorCode(ctmbstr name)
 
275
{
 
276
    uint i;
 
277
 
 
278
    for (i = 0; colors[i].name; ++i)
 
279
        if (tmbstrcasecmp(name, colors[i].name) == 0)
 
280
            return colors[i].hex;
 
281
 
 
282
    return NULL;
 
283
}
 
284
 
 
285
static ctmbstr GetColorName(ctmbstr code)
 
286
{
 
287
    uint i;
 
288
 
 
289
    for (i = 0; colors[i].name; ++i)
 
290
        if (tmbstrcasecmp(code, colors[i].hex) == 0)
 
291
            return colors[i].name;
 
292
 
 
293
    return NULL;
 
294
}
 
295
 
 
296
#if 0
 
297
static const struct _colors fancy_colors[] =
 
298
{
 
299
    { "darkgreen",            "#006400" },
 
300
    { "antiquewhite",         "#FAEBD7" },
 
301
    { "aqua",                 "#00FFFF" },
 
302
    { "aquamarine",           "#7FFFD4" },
 
303
    { "azure",                "#F0FFFF" },
 
304
    { "beige",                "#F5F5DC" },
 
305
    { "bisque",               "#FFE4C4" },
 
306
    { "black",                "#000000" },
 
307
    { "blanchedalmond",       "#FFEBCD" },
 
308
    { "blue",                 "#0000FF" },
 
309
    { "blueviolet",           "#8A2BE2" },
 
310
    { "brown",                "#A52A2A" },
 
311
    { "burlywood",            "#DEB887" },
 
312
    { "cadetblue",            "#5F9EA0" },
 
313
    { "chartreuse",           "#7FFF00" },
 
314
    { "chocolate",            "#D2691E" },
 
315
    { "coral",                "#FF7F50" },
 
316
    { "cornflowerblue",       "#6495ED" },
 
317
    { "cornsilk",             "#FFF8DC" },
 
318
    { "crimson",              "#DC143C" },
 
319
    { "cyan",                 "#00FFFF" },
 
320
    { "darkblue",             "#00008B" },
 
321
    { "darkcyan",             "#008B8B" },
 
322
    { "darkgoldenrod",        "#B8860B" },
 
323
    { "darkgray",             "#A9A9A9" },
 
324
    { "darkgreen",            "#006400" },
 
325
    { "darkkhaki",            "#BDB76B" },
 
326
    { "darkmagenta",          "#8B008B" },
 
327
    { "darkolivegreen",       "#556B2F" },
 
328
    { "darkorange",           "#FF8C00" },
 
329
    { "darkorchid",           "#9932CC" },
 
330
    { "darkred",              "#8B0000" },
 
331
    { "darksalmon",           "#E9967A" },
 
332
    { "darkseagreen",         "#8FBC8F" },
 
333
    { "darkslateblue",        "#483D8B" },
 
334
    { "darkslategray",        "#2F4F4F" },
 
335
    { "darkturquoise",        "#00CED1" },
 
336
    { "darkviolet",           "#9400D3" },
 
337
    { "deeppink",             "#FF1493" },
 
338
    { "deepskyblue",          "#00BFFF" },
 
339
    { "dimgray",              "#696969" },
 
340
    { "dodgerblue",           "#1E90FF" },
 
341
    { "firebrick",            "#B22222" },
 
342
    { "floralwhite",          "#FFFAF0" },
 
343
    { "forestgreen",          "#228B22" },
 
344
    { "fuchsia",              "#FF00FF" },
 
345
    { "gainsboro",            "#DCDCDC" },
 
346
    { "ghostwhite",           "#F8F8FF" },
 
347
    { "gold",                 "#FFD700" },
 
348
    { "goldenrod",            "#DAA520" },
 
349
    { "gray",                 "#808080" },
 
350
    { "green",                "#008000" },
 
351
    { "greenyellow",          "#ADFF2F" },
 
352
    { "honeydew",             "#F0FFF0" },
 
353
    { "hotpink",              "#FF69B4" },
 
354
    { "indianred",            "#CD5C5C" },
 
355
    { "indigo",               "#4B0082" },
 
356
    { "ivory",                "#FFFFF0" },
 
357
    { "khaki",                "#F0E68C" },
 
358
    { "lavender",             "#E6E6FA" },
 
359
    { "lavenderblush",        "#FFF0F5" },
 
360
    { "lawngreen",            "#7CFC00" },
 
361
    { "lemonchiffon",         "#FFFACD" },
 
362
    { "lightblue",            "#ADD8E6" },
 
363
    { "lightcoral",           "#F08080" },
 
364
    { "lightcyan",            "#E0FFFF" },
 
365
    { "lightgoldenrodyellow", "#FAFAD2" },
 
366
    { "lightgreen",           "#90EE90" },
 
367
    { "lightgrey",            "#D3D3D3" },
 
368
    { "lightpink",            "#FFB6C1" },
 
369
    { "lightsalmon",          "#FFA07A" },
 
370
    { "lightseagreen",        "#20B2AA" },
 
371
    { "lightskyblue",         "#87CEFA" },
 
372
    { "lightslategray",       "#778899" },
 
373
    { "lightsteelblue",       "#B0C4DE" },
 
374
    { "lightyellow",          "#FFFFE0" },
 
375
    { "lime",                 "#00FF00" },
 
376
    { "limegreen",            "#32CD32" },
 
377
    { "linen",                "#FAF0E6" },
 
378
    { "magenta",              "#FF00FF" },
 
379
    { "maroon",               "#800000" },
 
380
    { "mediumaquamarine",     "#66CDAA" },
 
381
    { "mediumblue",           "#0000CD" },
 
382
    { "mediumorchid",         "#BA55D3" },
 
383
    { "mediumpurple",         "#9370DB" },
 
384
    { "mediumseagreen",       "#3CB371" },
 
385
    { "mediumslateblue",      "#7B68EE" },
 
386
    { "mediumspringgreen",    "#00FA9A" },
 
387
    { "mediumturquoise",      "#48D1CC" },
 
388
    { "mediumvioletred",      "#C71585" },
 
389
    { "midnightblue",         "#191970" },
 
390
    { "mintcream",            "#F5FFFA" },
 
391
    { "mistyrose",            "#FFE4E1" },
 
392
    { "moccasin",             "#FFE4B5" },
 
393
    { "navajowhite",          "#FFDEAD" },
 
394
    { "navy",                 "#000080" },
 
395
    { "oldlace",              "#FDF5E6" },
 
396
    { "olive",                "#808000" },
 
397
    { "olivedrab",            "#6B8E23" },
 
398
    { "orange",               "#FFA500" },
 
399
    { "orangered",            "#FF4500" },
 
400
    { "orchid",               "#DA70D6" },
 
401
    { "palegoldenrod",        "#EEE8AA" },
 
402
    { "palegreen",            "#98FB98" },
 
403
    { "paleturquoise",        "#AFEEEE" },
 
404
    { "palevioletred",        "#DB7093" },
 
405
    { "papayawhip",           "#FFEFD5" },
 
406
    { "peachpuff",            "#FFDAB9" },
 
407
    { "peru",                 "#CD853F" },
 
408
    { "pink",                 "#FFC0CB" },
 
409
    { "plum",                 "#DDA0DD" },
 
410
    { "powderblue",           "#B0E0E6" },
 
411
    { "purple",               "#800080" },
 
412
    { "red",                  "#FF0000" },
 
413
    { "rosybrown",            "#BC8F8F" },
 
414
    { "royalblue",            "#4169E1" },
 
415
    { "saddlebrown",          "#8B4513" },
 
416
    { "salmon",               "#FA8072" },
 
417
    { "sandybrown",           "#F4A460" },
 
418
    { "seagreen",             "#2E8B57" },
 
419
    { "seashell",             "#FFF5EE" },
 
420
    { "sienna",               "#A0522D" },
 
421
    { "silver",               "#C0C0C0" },
 
422
    { "skyblue",              "#87CEEB" },
 
423
    { "slateblue",            "#6A5ACD" },
 
424
    { "slategray",            "#708090" },
 
425
    { "snow",                 "#FFFAFA" },
 
426
    { "springgreen",          "#00FF7F" },
 
427
    { "steelblue",            "#4682B4" },
 
428
    { "tan",                  "#D2B48C" },
 
429
    { "teal",                 "#008080" },
 
430
    { "thistle",              "#D8BFD8" },
 
431
    { "tomato",               "#FF6347" },
 
432
    { "turquoise",            "#40E0D0" },
 
433
    { "violet",               "#EE82EE" },
 
434
    { "wheat",                "#F5DEB3" },
 
435
    { "white",                "#FFFFFF" },
 
436
    { "whitesmoke",           "#F5F5F5" },
 
437
    { "yellow",               "#FFFF00" },
 
438
    { "yellowgreen",          "#9ACD32" },
 
439
    { NULL,                   NULL      }
 
440
};
 
441
#endif
 
442
 
 
443
#ifdef ATTRIBUTE_HASH_LOOKUP
 
444
static uint hash(ctmbstr s)
 
445
{
 
446
    uint hashval;
304
447
 
305
448
    for (hashval = 0; *s != '\0'; s++)
306
449
        hashval = *s + 31*hashval;
307
450
 
308
 
    return hashval % HASHSIZE;
309
 
}
310
 
 
311
 
static Attribute *lookup(char *s)
312
 
{
313
 
    Attribute *np;
314
 
 
315
 
    for (np = hashtab[hash(s)]; np != null; np = np->next)
316
 
        if (wstrcmp(s, np->name) == 0)
317
 
            return np;
318
 
    return null;
319
 
}
320
 
 
321
 
static Attribute *install(char *name, uint versions, AttrCheck *attrchk)
322
 
{
323
 
    Attribute *np;
324
 
    unsigned hashval;
325
 
 
326
 
    if ((np = lookup(name)) == null)
327
 
    {
328
 
        np = (Attribute *)MemAlloc(sizeof(*np));
329
 
 
330
 
        if (np == null || (np->name = wstrdup(name)) == null)
331
 
            return null;
332
 
 
333
 
        hashval = hash(name);
334
 
        np->next = hashtab[hashval];
335
 
        hashtab[hashval] = np;
336
 
    }
337
 
 
338
 
    np->versions = versions;
339
 
    np->attrchk = attrchk;
340
 
    np->nowrap = no;
341
 
    np->literal = no;
 
451
    return hashval % ATTRIBUTE_HASH_SIZE;
 
452
}
 
453
 
 
454
static Attribute *install(TidyAttribImpl * attribs, const Attribute* old)
 
455
{
 
456
    Attribute *np;
 
457
    uint hashval;
 
458
 
 
459
    np = (Attribute *)MemAlloc(sizeof(*np));
 
460
 
 
461
    np->name = tmbstrdup(old->name);
 
462
 
 
463
    hashval = hash(np->name);
 
464
    np->next = attribs->hashtab[hashval];
 
465
    attribs->hashtab[hashval] = np;
 
466
 
 
467
    np->id       = old->id;
 
468
    np->versions = old->versions;
 
469
    np->attrchk  = old->attrchk;
 
470
 
342
471
    return np;
343
472
}
344
 
 
345
 
static void SetNoWrap(Attribute *attr)
346
 
{
347
 
    attr->nowrap = yes;  /* defaults to no */
 
473
#endif
 
474
 
 
475
static const Attribute* lookup(TidyAttribImpl* ARG_UNUSED(attribs),
 
476
                               ctmbstr atnam)
 
477
{
 
478
    const Attribute *np;
 
479
 
 
480
    if (!atnam)
 
481
        return NULL;
 
482
 
 
483
#ifdef ATTRIBUTE_HASH_LOOKUP
 
484
    for (np = attribs->hashtab[hash(atnam)]; np != NULL; np = np->next)
 
485
        if (tmbstrcmp(atnam, np->name) == 0)
 
486
            return np;
 
487
 
 
488
    for (np = attribute_defs; np && np->name; ++np)
 
489
        if (tmbstrcmp(atnam, np->name) == 0)
 
490
            return install(attribs, np);
 
491
#else
 
492
    for (np = attribute_defs; np && np->name; ++np)
 
493
        if (tmbstrcmp(atnam, np->name) == 0)
 
494
            return np;
 
495
#endif
 
496
 
 
497
    return NULL;
 
498
}
 
499
 
 
500
 
 
501
/* Locate attributes by type */
 
502
AttVal* AttrGetById( Node* node, TidyAttrId id )
 
503
{
 
504
   AttVal* av;
 
505
   for ( av = node->attributes; av; av = av->next )
 
506
   {
 
507
     if ( AttrIsId(av, id) )
 
508
         return av;
 
509
   }
 
510
   return NULL;
348
511
}
349
512
 
350
513
/* public method for finding attribute definition by name */
351
 
Attribute *FindAttribute(AttVal *attval)
 
514
const Attribute* FindAttribute( TidyDocImpl* doc, AttVal *attval )
352
515
{
353
 
    Attribute *np;
354
 
 
355
 
    if (attval->attribute && (np = lookup(attval->attribute)))
356
 
        return np;
357
 
 
358
 
    return null;
 
516
    if ( attval )
 
517
       return lookup( &doc->attribs, attval->attribute );
 
518
    return NULL;
359
519
}
360
520
 
361
 
AttVal *GetAttrByName(Node *node, char *name)
 
521
AttVal* GetAttrByName( Node *node, ctmbstr name )
362
522
{
363
523
    AttVal *attr;
364
 
 
365
 
    for (attr = node->attributes; attr != null; attr = attr->next)
 
524
    for (attr = node->attributes; attr != NULL; attr = attr->next)
366
525
    {
367
 
        if (wstrcmp(attr->attribute, name) == 0)
 
526
        if (attr->attribute && tmbstrcmp(attr->attribute, name) == 0)
368
527
            break;
369
528
    }
370
 
 
371
529
    return attr;
372
530
}
373
531
 
374
 
void AddAttribute(Node *node, char *name, char *value)
 
532
AttVal* AddAttribute( TidyDocImpl* doc,
 
533
                      Node *node, ctmbstr name, ctmbstr value )
375
534
{
376
535
    AttVal *av = NewAttribute();
377
536
    av->delim = '"';
378
 
    av->attribute = wstrdup(name);
379
 
    av->value = wstrdup(value);
380
 
    av->dict = FindAttribute(av);
381
 
 
382
 
    if (node->attributes == null)
383
 
        node->attributes = av;
384
 
    else /* append to end of attributes */
 
537
    av->attribute = tmbstrdup(name);
 
538
 
 
539
    if (value)
 
540
        av->value = tmbstrdup(value);
 
541
    else
 
542
        av->value = NULL;
 
543
 
 
544
    av->dict = lookup(&doc->attribs, name);
 
545
 
 
546
    InsertAttributeAtEnd(node, av);
 
547
    return av;
 
548
}
 
549
 
 
550
AttVal* RepairAttrValue(TidyDocImpl* doc, Node* node, ctmbstr name, ctmbstr value)
 
551
{
 
552
    AttVal* old = GetAttrByName(node, name);
 
553
 
 
554
    if (old)
385
555
    {
386
 
        AttVal *here = node->attributes;
387
 
 
388
 
        while (here->next)
389
 
            here = here->next;
390
 
 
391
 
        here->next = av;
 
556
        if (old->value)
 
557
            MemFree(old->value);
 
558
        if (value)
 
559
            old->value = tmbstrdup(value);
 
560
        else
 
561
            old->value = NULL;
 
562
 
 
563
        return old;
392
564
    }
393
 
}
394
 
 
395
 
Bool IsUrl(char *attrname)
396
 
{
397
 
    Attribute *np;
398
 
 
399
 
    return (Bool)((np = lookup(attrname)) && np->attrchk == URL);
400
 
}
401
 
 
402
 
Bool IsBool(char *attrname)
403
 
{
404
 
    Attribute *np;
405
 
 
406
 
    return (Bool)((np = lookup(attrname)) && np->attrchk == BOOL);
407
 
}
408
 
 
409
 
Bool IsScript(char *attrname)
410
 
{
411
 
    Attribute *np;
412
 
 
413
 
    return (Bool)((np = lookup(attrname)) && np->attrchk == SCRIPT);
414
 
}
415
 
 
416
 
Bool IsLiteralAttribute(char *attrname)
417
 
{
418
 
    Attribute *np;
419
 
 
420
 
    return (Bool)((np = lookup(attrname)) && np->literal);
 
565
    else
 
566
        return AddAttribute(doc, node, name, value);
 
567
}
 
568
 
 
569
static Bool CheckAttrType( TidyDocImpl* doc,
 
570
                           ctmbstr attrname, AttrCheck type )
 
571
{
 
572
    const Attribute* np = lookup( &doc->attribs, attrname );
 
573
    return (Bool)( np && np->attrchk == type );
 
574
}
 
575
 
 
576
Bool IsUrl( TidyDocImpl* doc, ctmbstr attrname )
 
577
{
 
578
    return CheckAttrType( doc, attrname, URL );
 
579
}
 
580
 
 
581
Bool IsBool( TidyDocImpl* doc, ctmbstr attrname )
 
582
{
 
583
    return CheckAttrType( doc, attrname, BOOL );
 
584
}
 
585
 
 
586
Bool IsScript( TidyDocImpl* doc, ctmbstr attrname )
 
587
{
 
588
    return CheckAttrType( doc, attrname, SCRIPT );
421
589
}
422
590
 
423
591
/* may id or name serve as anchor? */
424
 
Bool IsAnchorElement(Node *node)
 
592
Bool IsAnchorElement( TidyDocImpl* ARG_UNUSED(doc), Node* node)
425
593
{
426
 
    if (node->tag == tag_a      ||
427
 
        node->tag == tag_applet ||
428
 
        node->tag == tag_form   ||
429
 
        node->tag == tag_frame  ||
430
 
        node->tag == tag_iframe ||
431
 
        node->tag == tag_img    ||
432
 
        node->tag == tag_map)
 
594
    TidyTagId tid = TagId( node );
 
595
    if ( tid == TidyTag_A      ||
 
596
         tid == TidyTag_APPLET ||
 
597
         tid == TidyTag_FORM   ||
 
598
         tid == TidyTag_FRAME  ||
 
599
         tid == TidyTag_IFRAME ||
 
600
         tid == TidyTag_IMG    ||
 
601
         tid == TidyTag_MAP )
433
602
        return yes;
434
603
 
435
604
    return no;
436
605
}
437
606
 
438
607
/*
439
 
  In CSS1, selectors can contain only the characters A-Z, 0-9, and Unicode characters 161-255, plus dash (-);
440
 
  they cannot start with a dash or a digit; they can also contain escaped characters and any Unicode character
441
 
  as a numeric code (see next item).
442
 
 
443
 
  The backslash followed by at most four hexadecimal digits (0..9A..F) stands for the Unicode character with that number.
444
 
 
445
 
  Any character except a hexadecimal digit can be escaped to remove its special meaning, by putting a backslash in front.
 
608
  In CSS1, selectors can contain only the characters A-Z, 0-9,
 
609
  and Unicode characters 161-255, plus dash (-); they cannot start
 
610
  with a dash or a digit; they can also contain escaped characters
 
611
  and any Unicode character as a numeric code (see next item).
 
612
 
 
613
  The backslash followed by at most four hexadecimal digits
 
614
  (0..9A..F) stands for the Unicode character with that number.
 
615
 
 
616
  Any character except a hexadecimal digit can be escaped to remove
 
617
  its special meaning, by putting a backslash in front.
446
618
 
447
619
  #508936 - CSS class naming for -clean option
448
620
*/
449
 
Bool IsCSS1Selector(char *buf)
 
621
Bool IsCSS1Selector( ctmbstr buf )
450
622
{
451
623
    Bool valid = yes;
452
624
    int esclen = 0;
453
 
    unsigned char c;
 
625
    byte c;
454
626
    int pos;
455
627
 
456
628
    for ( pos=0; valid && (c = *buf++); ++pos )
459
631
        {
460
632
            esclen = 1;  /* ab\555\444 is 4 chars {'a', 'b', \555, \444} */
461
633
        }
462
 
        else if ( isxdigit( c ) )
 
634
        else if ( isdigit( c ) )
463
635
        {
464
636
            /* Digit not 1st, unless escaped (Max length "\112F") */
465
637
            if ( esclen > 0 )
473
645
                esclen > 0                       /* Escaped? Anything goes. */
474
646
                || ( pos>0 && c == '-' )         /* Dash cannot be 1st char */
475
647
                || isalpha(c)                    /* a-z, A-Z anywhere */
476
 
                || ( c >= 161 && c <= 255 )      /* Unicode 161-255 anywhere */
 
648
                || ( c >= 161 )                  /* Unicode 161-255 anywhere */
477
649
            );
478
650
            esclen = 0;
479
651
        }
481
653
    return valid;
482
654
}
483
655
 
484
 
 
485
 
 
486
 
/* anchor/node hash */
487
 
 
488
 
Anchor *anchor_list = null;
489
 
 
490
656
/* free single anchor */
491
 
void FreeAnchor(Anchor *a)
 
657
static void FreeAnchor(Anchor *a)
492
658
{
493
 
    if (a->name)
494
 
        MemFree(a->name);
495
 
 
496
 
    MemFree(a);
 
659
    if ( a )
 
660
        MemFree( a->name );
 
661
    MemFree( a );
497
662
}
498
663
 
499
664
/* removes anchor for specific node */
500
 
void RemoveAnchorByNode(Node *node)
 
665
void RemoveAnchorByNode( TidyDocImpl* doc, Node *node )
501
666
{
502
 
    Anchor *delme = null, *found, *prev = null, *next;
 
667
    TidyAttribImpl* attribs = &doc->attribs;
 
668
    Anchor *delme = NULL, *curr, *prev = NULL;
503
669
 
504
 
    for (found = anchor_list; found != null; found = found->next)
 
670
    for ( curr=attribs->anchor_list; curr!=NULL; curr=curr->next )
505
671
    {
506
 
        next = found->next;
507
 
 
508
 
        if (found->node == node)
 
672
        if ( curr->node == node )
509
673
        {
510
 
            if (prev)
511
 
                prev->next = next;
 
674
            if ( prev )
 
675
                prev->next = curr->next;
512
676
            else
513
 
                anchor_list = next;
514
 
 
515
 
            delme = found;
 
677
                attribs->anchor_list = curr->next;
 
678
            delme = curr;
 
679
            break;
516
680
        }
517
 
        else
518
 
            prev = found;
 
681
        prev = curr;
519
682
    }
520
 
    if (delme)
521
 
        FreeAnchor(delme);
 
683
    FreeAnchor( delme );
522
684
}
523
685
 
524
686
/* initialize new anchor */
525
 
Anchor *NewAnchor(void)
 
687
static Anchor* NewAnchor( ctmbstr name, Node* node )
526
688
{
527
 
    Anchor *a = (Anchor *)MemAlloc(sizeof(Anchor));
 
689
    Anchor *a = (Anchor*) MemAlloc( sizeof(Anchor) );
528
690
 
529
 
    a->name = null;
530
 
    a->next = null;
531
 
    a->node = null;
 
691
    a->name = tmbstrdup( name );
 
692
    a->name = tmbstrtolower(a->name);
 
693
    a->node = node;
 
694
    a->next = NULL;
532
695
 
533
696
    return a;
534
697
}
535
698
 
536
699
/* add new anchor to namespace */
537
 
Anchor *AddAnchor(char *name, Node *node)
 
700
Anchor* AddAnchor( TidyDocImpl* doc, ctmbstr name, Node *node )
538
701
{
539
 
    Anchor *a = NewAnchor();
540
 
 
541
 
    a->name = wstrdup(name);
542
 
    a->node = node;
543
 
 
544
 
    if (anchor_list == null)
545
 
        anchor_list = a;
 
702
    TidyAttribImpl* attribs = &doc->attribs;
 
703
    Anchor *a = NewAnchor( name, node );
 
704
 
 
705
    if ( attribs->anchor_list == NULL)
 
706
         attribs->anchor_list = a;
546
707
    else
547
708
    {
548
 
        Anchor *here = anchor_list;
549
 
 
 
709
        Anchor *here =  attribs->anchor_list;
550
710
        while (here->next)
551
711
            here = here->next;
552
 
 
553
712
        here->next = a;
554
713
    }
555
714
 
556
 
    return anchor_list;
 
715
    return attribs->anchor_list;
557
716
}
558
717
 
559
718
/* return node associated with anchor */
560
 
Node *GetNodeByAnchor(char *name)
 
719
Node* GetNodeByAnchor( TidyDocImpl* doc, ctmbstr name )
561
720
{
 
721
    TidyAttribImpl* attribs = &doc->attribs;
562
722
    Anchor *found;
563
 
    
564
 
    for (found = anchor_list; found != null; found = found->next)
 
723
    for ( found = attribs->anchor_list; found != NULL; found = found->next )
565
724
    {
566
 
        if (wstrcasecmp(found->name, name) == 0)
 
725
        if ( tmbstrcmp(found->name, name) == 0 )
567
726
            break;
568
727
    }
569
728
    
570
 
    if (found == null)
571
 
        return null;
572
 
    else
 
729
    if ( found )
573
730
        return found->node;
 
731
    return NULL;
574
732
}
575
733
 
576
734
/* free all anchors */
577
 
void FreeAnchors(void)
 
735
void FreeAnchors( TidyDocImpl* doc )
578
736
{
579
 
    Anchor *a;
580
 
    
581
 
    while (anchor_list)
 
737
    TidyAttribImpl* attribs = &doc->attribs;
 
738
    Anchor* a;
 
739
    while (NULL != (a = attribs->anchor_list) )
582
740
    {
583
 
        a = anchor_list;
584
 
        
585
 
        if (a->name)
586
 
            MemFree(a->name);
587
 
        
588
 
        anchor_list = a->next;
589
 
        MemFree(a);
 
741
        attribs->anchor_list = a->next;
 
742
        MemFree( a->name );
 
743
        MemFree( a );
590
744
    }
591
745
}
592
746
 
593
747
/* public method for inititializing attribute dictionary */
594
 
void InitAttrs(void)
595
 
{
596
 
    struct _attrlist *ap;
597
 
    
598
 
    for(ap = attrlist; ap->name != null; ++ap)
599
 
        install(ap->name, ap->versions, ap->attrchk);
600
 
 
601
 
    attr_href = lookup("href");
602
 
    attr_src = lookup("src");
603
 
    attr_id = lookup("id");
604
 
    attr_name = lookup("name");
605
 
    attr_summary = lookup("summary");
606
 
    attr_alt = lookup("alt");
607
 
    attr_longdesc = lookup("longdesc");
608
 
    attr_usemap = lookup("usemap");
609
 
    attr_ismap = lookup("ismap");
610
 
    attr_language = lookup("language");
611
 
    attr_type = lookup("type");
612
 
    attr_title = lookup("title");
613
 
    attr_xmlns = lookup("xmlns");
614
 
    attr_datafld = lookup("datafld");
615
 
    attr_value = lookup("value");
616
 
    attr_content = lookup("content");
617
 
    attr_width = lookup("width");
618
 
    attr_height = lookup("height");
619
 
 
620
 
    SetNoWrap(attr_alt);
621
 
    SetNoWrap(attr_value);
622
 
    SetNoWrap(attr_content);
623
 
}
624
 
 
625
 
/*
626
 
Henry Zrepa reports that some folk are
627
 
using embed with script attributes where
628
 
newlines are signficant. These need to be
629
 
declared and handled specially!
630
 
*/
631
 
void DeclareLiteralAttrib(char *name)
632
 
{
633
 
    Attribute *attrib = lookup(name);
634
 
 
635
 
    if (attrib == null) /* #431337 - fix by Terry Teague 07 Jun 01 */
636
 
        attrib = install(name, VERS_PROPRIETARY, null);
637
 
 
638
 
    attrib->literal = yes;
639
 
}
640
 
 
641
 
void FreeAttrTable(void)
642
 
{
 
748
void InitAttrs( TidyDocImpl* doc )
 
749
{
 
750
    ClearMemory( &doc->attribs, sizeof(TidyAttribImpl) );
 
751
#ifdef _DEBUG
 
752
    {
 
753
      /* Attribute ID is index position in Attribute type lookup table */
 
754
      uint ix;
 
755
      for ( ix=0; ix < N_TIDY_ATTRIBS; ++ix )
 
756
      {
 
757
        const Attribute* dict = &attribute_defs[ ix ];
 
758
        assert( (uint) dict->id == ix );
 
759
      }
 
760
    }
 
761
#endif
 
762
}
 
763
 
 
764
/* free all declared attributes */
 
765
static void FreeDeclaredAttributes( TidyDocImpl* doc )
 
766
{
 
767
    TidyAttribImpl* attribs = &doc->attribs;
 
768
    Attribute* dict;
 
769
    while ( NULL != (dict = attribs->declared_attr_list) )
 
770
    {
 
771
        attribs->declared_attr_list = dict->next;
 
772
        MemFree( dict->name );
 
773
        MemFree( dict );
 
774
    }
 
775
}
 
776
 
 
777
void FreeAttrTable( TidyDocImpl* doc )
 
778
{
 
779
#ifdef ATTRIBUTE_HASH_LOOKUP
643
780
    Attribute *dict, *next;
644
 
    int i;
 
781
    uint i;
645
782
 
646
 
    for (i = 0; i < HASHSIZE; ++i)
 
783
    for (i = 0; i < ATTRIBUTE_HASH_SIZE; ++i)
647
784
    {
648
 
        dict = hashtab[i];
 
785
        dict = doc->attribs.hashtab[i];
649
786
 
650
787
        while(dict)
651
788
        {
655
792
            dict = next;
656
793
        }
657
794
 
658
 
        hashtab[i] = null;
 
795
        doc->attribs.hashtab[i] = NULL;
659
796
    }
 
797
#endif
660
798
 
661
 
    FreeAnchors();
 
799
    FreeAnchors( doc );
 
800
    FreeDeclaredAttributes( doc );
662
801
}
663
802
 
664
803
/*
665
804
 the same attribute name can't be used
666
805
 more than once in each element
667
806
*/
668
 
 
669
 
void RepairDuplicateAttributes(Lexer *lexer, Node *node)
 
807
void RepairDuplicateAttributes( TidyDocImpl* doc, Node *node)
670
808
{
671
 
    AttVal *attval;
 
809
    AttVal *first;
672
810
 
673
 
    for (attval = node->attributes; attval != null;)
 
811
    for (first = node->attributes; first != NULL;)
674
812
    {
675
 
        if (attval->asp == null && attval->php == null)
676
 
        {
677
 
            AttVal *current;
678
 
            
679
 
            for (current = attval->next; current != null;)
680
 
            {
681
 
                if (current->asp == null && current->php == null &&
682
 
                    wstrcasecmp(attval->attribute, current->attribute) == 0)
683
 
                {
684
 
                    AttVal *temp;
685
 
 
686
 
                    if (wstrcasecmp(current->attribute, "class") == 0 && JoinClasses)
687
 
                    {
688
 
                        /* concatenate classes */
689
 
 
690
 
                        current->value = (char *)MemRealloc(current->value, wstrlen(current->value) +
691
 
                                                                            wstrlen(attval->value)  + 2);
692
 
                        wstrcat(current->value, " ");
693
 
                        wstrcat(current->value, attval->value);
694
 
 
695
 
                        temp = attval->next;
696
 
 
697
 
                        if (temp->next == null)
698
 
                            current = null;
699
 
                        else
700
 
                            current = current->next;
701
 
 
702
 
                        ReportAttrError(lexer, node, attval, JOINING_ATTRIBUTE);
703
 
 
704
 
                        RemoveAttribute(node, attval);
705
 
                        attval = temp;
706
 
                    }
707
 
                    else if (wstrcasecmp(current->attribute, "style") == 0 && JoinStyles)
708
 
                    {
709
 
                        /* concatenate styles */
710
 
 
711
 
                        /*
712
 
                          this doesn't handle CSS comments and
713
 
                          leading/trailing white-space very well
714
 
                          see http://www.w3.org/TR/css-style-attr
715
 
                        */
716
 
 
717
 
                        size_t end = strlen(current->value);
718
 
 
719
 
                        if (current->value[end] == ';')
720
 
                        {
721
 
                            /* attribute ends with declaration seperator */
722
 
 
723
 
                            current->value = (char *)MemRealloc(current->value,
724
 
                                end + wstrlen(attval->value) + 2);
725
 
 
726
 
                            wstrcat(current->value, " ");
727
 
                            wstrcat(current->value, attval->value);
728
 
                        }
729
 
                        else if (current->value[end] == '}')
730
 
                        {
731
 
                            /* attribute ends with rule set */
732
 
 
733
 
                            current->value = (char *)MemRealloc(current->value,
734
 
                                end + wstrlen(attval->value) + 6);
735
 
 
736
 
                            wstrcat(current->value, " { ");
737
 
                            wstrcat(current->value, attval->value);
738
 
                            wstrcat(current->value, " }");
739
 
                        }
740
 
                        else
741
 
                        {
742
 
                            /* attribute ends with property value */
743
 
 
744
 
                            current->value = (char *)MemRealloc(current->value,
745
 
                                end + wstrlen(attval->value) + 3);
746
 
 
747
 
                            wstrcat(current->value, "; ");
748
 
                            wstrcat(current->value, attval->value);
749
 
                        }
750
 
 
751
 
                        temp = attval->next;
752
 
 
753
 
                        if (temp->next == null)
754
 
                            current = null;
755
 
                        else
756
 
                            current = current->next;
757
 
 
758
 
                        ReportAttrError(lexer, node, attval, JOINING_ATTRIBUTE);
759
 
 
760
 
                        RemoveAttribute(node, attval);
761
 
                        attval = temp;
762
 
 
763
 
                    }
764
 
                    else if (DuplicateAttrs == keep_last)
765
 
                    {
766
 
                        temp = current->next;
767
 
 
768
 
                        ReportAttrError(lexer, node, current, REPEATED_ATTRIBUTE);
769
 
                        
770
 
                        RemoveAttribute(node, current);
771
 
                        current = temp;
772
 
                    }
773
 
                    else
774
 
                    {
775
 
                        temp = attval->next;
776
 
 
777
 
                        if (attval->next == null)
778
 
                            current = null;
779
 
                        else
780
 
                            current = current->next;
781
 
 
782
 
                        ReportAttrError(lexer, node, attval, REPEATED_ATTRIBUTE);
783
 
 
784
 
                        RemoveAttribute(node, attval);
785
 
                        attval = temp;
786
 
                    }
 
813
        AttVal *second;
 
814
        Bool firstRedefined = no;
 
815
 
 
816
        if (!(first->asp == NULL && first->php == NULL))
 
817
        {
 
818
            first = first->next;
 
819
            continue;
 
820
        }
 
821
 
 
822
        for (second = first->next; second != NULL;)
 
823
        {
 
824
            AttVal *temp;
 
825
 
 
826
            if (!(second->asp == NULL && second->php == NULL &&
 
827
                AttrsHaveSameId(first, second)))
 
828
            {
 
829
                second = second->next;
 
830
                continue;
 
831
            }
 
832
 
 
833
            /* first and second attribute have same local name */
 
834
            /* now determine what to do with this duplicate... */
 
835
 
 
836
            if (attrIsCLASS(first) && cfgBool(doc, TidyJoinClasses) && AttrHasValue(first) && AttrHasValue(second))
 
837
            {
 
838
                /* concatenate classes */
 
839
 
 
840
                first->value = (tmbstr) MemRealloc(first->value, tmbstrlen(first->value) +
 
841
                    tmbstrlen(second->value)  + 2);
 
842
                tmbstrcat(first->value, " ");
 
843
                tmbstrcat(first->value, second->value);
 
844
 
 
845
                temp = second->next;
 
846
 
 
847
                ReportAttrError( doc, node, second, JOINING_ATTRIBUTE);
 
848
                RemoveAttribute( doc, node, second );
 
849
 
 
850
                second = temp;
 
851
            }
 
852
            else if (attrIsSTYLE(first) && cfgBool(doc, TidyJoinStyles) && AttrHasValue(first) && AttrHasValue(second))
 
853
            {
 
854
                /* concatenate styles */
 
855
 
 
856
                /*
 
857
                this doesn't handle CSS comments and
 
858
                leading/trailing white-space very well
 
859
                see http://www.w3.org/TR/css-style-attr
 
860
                */
 
861
 
 
862
                uint end = tmbstrlen(first->value);
 
863
 
 
864
                if (end >0 && first->value[end - 1] == ';')
 
865
                {
 
866
                    /* attribute ends with declaration seperator */
 
867
 
 
868
                    first->value = (tmbstr) MemRealloc(first->value,
 
869
                        end + tmbstrlen(second->value) + 2);
 
870
 
 
871
                    tmbstrcat(first->value, " ");
 
872
                    tmbstrcat(first->value, second->value);
 
873
                }
 
874
                else if (end >0 && first->value[end - 1] == '}')
 
875
                {
 
876
                    /* attribute ends with rule set */
 
877
 
 
878
                    first->value = (tmbstr) MemRealloc(first->value,
 
879
                        end + tmbstrlen(second->value) + 6);
 
880
 
 
881
                    tmbstrcat(first->value, " { ");
 
882
                    tmbstrcat(first->value, second->value);
 
883
                    tmbstrcat(first->value, " }");
787
884
                }
788
885
                else
789
 
                    current = current->next;
790
 
            }
791
 
            attval = attval->next;
 
886
                {
 
887
                    /* attribute ends with property value */
 
888
 
 
889
                    first->value = (tmbstr) MemRealloc(first->value,
 
890
                        end + tmbstrlen(second->value) + 3);
 
891
 
 
892
                    if (end > 0)
 
893
                        tmbstrcat(first->value, "; ");
 
894
                    tmbstrcat(first->value, second->value);
 
895
                }
 
896
 
 
897
                temp = second->next;
 
898
 
 
899
                ReportAttrError( doc, node, second, JOINING_ATTRIBUTE);
 
900
                RemoveAttribute( doc, node, second );
 
901
                second = temp;
 
902
 
 
903
            }
 
904
            else if ( cfg(doc, TidyDuplicateAttrs) == TidyKeepLast )
 
905
            {
 
906
                temp = first->next;
 
907
                ReportAttrError( doc, node, first, REPEATED_ATTRIBUTE);
 
908
                RemoveAttribute( doc, node, first );
 
909
                firstRedefined = yes;
 
910
                first = temp;
 
911
                second = second->next;
 
912
            }
 
913
            else /* TidyDuplicateAttrs == TidyKeepFirst */
 
914
            {
 
915
                temp = second->next;
 
916
 
 
917
                ReportAttrError( doc, node, second, REPEATED_ATTRIBUTE);
 
918
                RemoveAttribute( doc, node, second );
 
919
 
 
920
                second = temp;
 
921
            }
792
922
        }
793
 
        else
794
 
            attval = attval->next;
 
923
        if (!firstRedefined)
 
924
            first = first->next;
795
925
    }
796
926
}
797
927
 
798
 
 
799
928
/* ignore unknown attributes for proprietary elements */
800
 
Attribute *CheckAttribute(Lexer *lexer, Node *node, AttVal *attval)
 
929
const Attribute* CheckAttribute( TidyDocImpl* doc, Node *node, AttVal *attval )
801
930
{
802
 
    Attribute *attribute;
 
931
    const Attribute* attribute = attval->dict;
803
932
 
804
 
    if ((attribute = attval->dict) != null)
 
933
    if ( attribute != NULL )
805
934
    {
806
 
        /* if attribute looks like <foo/> check XML is ok */
807
935
        if (attribute->versions & VERS_XML)
808
936
        {
809
 
            if (!(XmlTags || XmlOut))
810
 
                ReportAttrError(lexer, node, attval, XML_ATTRIBUTE_VALUE);
811
 
        } /* title first appeared in HTML 4.0 except for a/link */
812
 
        else if (attribute != attr_title ||
813
 
                    !(node->tag == tag_a || node->tag == tag_link))
814
 
            ConstrainVersion(lexer, attribute->versions);
 
937
            doc->lexer->isvoyager = yes;
 
938
            if (!cfgBool(doc, TidyHtmlOut))
 
939
            {
 
940
                SetOptionBool(doc, TidyXhtmlOut, yes);
 
941
                SetOptionBool(doc, TidyXmlOut, yes);
 
942
            }
 
943
        }
 
944
 
 
945
        ConstrainVersion(doc, AttributeVersions(node, attval));
815
946
        
816
947
        if (attribute->attrchk)
817
 
            attribute->attrchk(lexer, node, attval);
818
 
        else if (attval->dict->versions & VERS_PROPRIETARY)
819
 
            ReportAttrError(lexer, node, attval, PROPRIETARY_ATTRIBUTE);
820
 
    }
821
 
    else if (!XmlTags && !(node->tag == null) && attval->asp == null &&
822
 
             !(node->tag && (node->tag->versions & VERS_PROPRIETARY)))
823
 
        ReportAttrError(lexer, node, attval, UNKNOWN_ATTRIBUTE);
 
948
            attribute->attrchk( doc, node, attval );
 
949
    }
 
950
 
 
951
    if (AttributeIsProprietary(node, attval))
 
952
    {
 
953
        ReportAttrError(doc, node, attval, PROPRIETARY_ATTRIBUTE);
 
954
 
 
955
        if (cfgBool(doc, TidyDropPropAttrs))
 
956
            RemoveAttribute( doc, node, attval );
 
957
    }
824
958
 
825
959
    return attribute;
826
960
}
827
961
 
828
962
Bool IsBoolAttribute(AttVal *attval)
829
963
{
830
 
    Attribute *attribute;
831
 
 
832
 
    if ((attribute = attval->dict) != null)
833
 
    {
834
 
        if (attribute->attrchk == CheckBool)
835
 
            return yes;
836
 
    }
837
 
 
 
964
    const Attribute *attribute = ( attval ? attval->dict : NULL );
 
965
    if ( attribute && attribute->attrchk == CheckBool )
 
966
        return yes;
838
967
    return no;
839
968
}
840
969
 
841
 
static void CheckLowerCaseAttrValue(Lexer *lexer, Node *node, AttVal *attval)
842
 
{
843
 
    char *p;
 
970
Bool attrIsEvent( AttVal* attval )
 
971
{
 
972
    TidyAttrId atid = AttrId( attval );
 
973
 
 
974
    return (atid == TidyAttr_OnAFTERUPDATE     ||
 
975
            atid == TidyAttr_OnBEFOREUNLOAD    ||
 
976
            atid == TidyAttr_OnBEFOREUPDATE    ||
 
977
            atid == TidyAttr_OnBLUR            ||
 
978
            atid == TidyAttr_OnCHANGE          ||
 
979
            atid == TidyAttr_OnCLICK           ||
 
980
            atid == TidyAttr_OnDATAAVAILABLE   ||
 
981
            atid == TidyAttr_OnDATASETCHANGED  ||
 
982
            atid == TidyAttr_OnDATASETCOMPLETE ||
 
983
            atid == TidyAttr_OnDBLCLICK        ||
 
984
            atid == TidyAttr_OnERRORUPDATE     ||
 
985
            atid == TidyAttr_OnFOCUS           ||
 
986
            atid == TidyAttr_OnKEYDOWN         ||
 
987
            atid == TidyAttr_OnKEYPRESS        ||
 
988
            atid == TidyAttr_OnKEYUP           ||
 
989
            atid == TidyAttr_OnLOAD            ||
 
990
            atid == TidyAttr_OnMOUSEDOWN       ||
 
991
            atid == TidyAttr_OnMOUSEMOVE       ||
 
992
            atid == TidyAttr_OnMOUSEOUT        ||
 
993
            atid == TidyAttr_OnMOUSEOVER       ||
 
994
            atid == TidyAttr_OnMOUSEUP         ||
 
995
            atid == TidyAttr_OnRESET           ||
 
996
            atid == TidyAttr_OnROWENTER        ||
 
997
            atid == TidyAttr_OnROWEXIT         ||
 
998
            atid == TidyAttr_OnSELECT          ||
 
999
            atid == TidyAttr_OnSUBMIT          ||
 
1000
            atid == TidyAttr_OnUNLOAD);
 
1001
}
 
1002
 
 
1003
static void CheckLowerCaseAttrValue( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1004
{
 
1005
    tmbstr p;
844
1006
    Bool hasUpper = no;
845
1007
    
846
 
    if (attval == null || attval->value == null)
 
1008
    if (!AttrHasValue(attval))
847
1009
        return;
848
1010
 
849
1011
    p = attval->value;
860
1022
 
861
1023
    if (hasUpper)
862
1024
    {
 
1025
        Lexer* lexer = doc->lexer;
863
1026
        if (lexer->isvoyager)
864
 
            ReportAttrError(lexer, node, attval, ATTR_VALUE_NOT_LCASE);
 
1027
            ReportAttrError( doc, node, attval, ATTR_VALUE_NOT_LCASE);
865
1028
  
866
 
        if (lexer->isvoyager || LowerLiterals)
867
 
            attval->value = wstrtolower(attval->value);
 
1029
        if ( lexer->isvoyager || cfgBool(doc, TidyLowerLiterals) )
 
1030
            attval->value = tmbstrtolower(attval->value);
868
1031
    }
869
1032
}
870
1033
 
871
1034
/* methods for checking value of a specific attribute */
872
1035
 
873
 
void CheckUrl(Lexer *lexer, Node *node, AttVal *attval)
 
1036
void CheckUrl( TidyDocImpl* doc, Node *node, AttVal *attval)
874
1037
{
875
 
    char c, *dest, *p;
 
1038
    tmbchar c; 
 
1039
    tmbstr dest, p;
876
1040
    uint escape_count = 0, backslash_count = 0;
877
1041
    uint i, pos = 0;
878
 
    size_t len;
 
1042
    uint len;
879
1043
    
880
 
    if (attval == null || attval->value == null)
 
1044
    if (!AttrHasValue(attval))
881
1045
    {
882
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1046
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
883
1047
        return;
884
1048
    }
885
1049
 
886
1050
    p = attval->value;
887
1051
    
888
 
    for (i = 0; c = p[i]; ++i)
 
1052
    for (i = 0; 0 != (c = p[i]); ++i)
889
1053
    {
890
1054
        if (c == '\\')
891
1055
        {
892
1056
            ++backslash_count;
893
 
            if (FixBackslash)
 
1057
            if ( cfgBool(doc, TidyFixBackslash) )
894
1058
                p[i] = '/';
895
1059
        }
896
1060
        else if ((c > 0x7e) || (c <= 0x20) || (strchr("<>", c)))
897
1061
            ++escape_count;
898
1062
    }
899
1063
    
900
 
    if (FixUri && escape_count)
 
1064
    if ( cfgBool(doc, TidyFixUri) && escape_count )
901
1065
    {
902
 
        len = wstrlen(p) + escape_count * 2 + 1;
903
 
        dest = (char *)MemAlloc(len);
 
1066
        len = tmbstrlen(p) + escape_count * 2 + 1;
 
1067
        dest = (tmbstr) MemAlloc(len);
904
1068
        
905
 
        for (i = 0; c = p[i]; ++i)
 
1069
        for (i = 0; 0 != (c = p[i]); ++i)
906
1070
        {
907
1071
            if ((c > 0x7e) || (c <= 0x20) || (strchr("<>", c)))
908
 
                pos += sprintf(dest + pos, "%%%02X", (unsigned char)c);
 
1072
                pos += sprintf( dest + pos, "%%%02X", (byte)c );
909
1073
            else
910
1074
                dest[pos++] = c;
911
1075
        }
912
 
        dest[pos++] = 0;
 
1076
        dest[pos] = 0;
913
1077
 
914
1078
        MemFree(attval->value);
915
1079
        attval->value = dest;
916
1080
    }
917
 
    if (backslash_count)
918
 
    {
919
 
        if (FixBackslash)
920
 
            ReportAttrError(lexer, node, attval, FIXED_BACKSLASH);
921
 
        else
922
 
            ReportAttrError(lexer, node, attval, BACKSLASH_IN_URI);
923
 
    }
924
 
    if (escape_count)
925
 
    {
926
 
        if (FixUri)
927
 
            ReportAttrError(lexer, node, attval, ESCAPED_ILLEGAL_URI);
928
 
        else
929
 
            ReportAttrError(lexer, node, attval, ILLEGAL_URI_REFERENCE);
930
 
 
931
 
        lexer->badChars |= INVALID_URI;
932
 
    }
933
 
}
934
 
 
935
 
void CheckScript(Lexer *lexer, Node *node, AttVal *attval)
936
 
{
937
 
}
938
 
 
939
 
void CheckName(Lexer *lexer, Node *node, AttVal *attval)
940
 
{
941
 
    Node *old;
942
 
 
943
 
    if (attval == null || attval->value == null)
944
 
    {
945
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
946
 
        return;
947
 
    }
948
 
 
949
 
    if (IsAnchorElement(node))
950
 
    {
951
 
        ConstrainVersion(lexer, ~VERS_XHTML11);
952
 
 
953
 
        if ((old = GetNodeByAnchor(attval->value)) &&  old != node)
954
 
        {
955
 
            ReportAttrError(lexer, node, attval, ANCHOR_NOT_UNIQUE);
956
 
        }
957
 
        else
958
 
            anchor_list = AddAnchor(attval->value, node);
959
 
    }
960
 
}
961
 
 
962
 
void CheckId(Lexer *lexer, Node *node, AttVal *attval)
963
 
{
964
 
    char *p;
965
 
    Node *old;
966
 
    
967
 
    if (attval == null || attval->value == null)
968
 
    {
969
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
970
 
        return;
971
 
    }
972
 
 
973
 
    p = attval->value;
974
 
    
975
 
    if (!IsLetter(*p++))
976
 
    {
977
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
978
 
    } else {
979
 
 
980
 
        while(*p)
981
 
        {
982
 
            if (!IsNamechar(*p++))
983
 
            {
984
 
                ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
985
 
                break;
986
 
            }
987
 
        }
988
 
    }
989
 
 
990
 
    if ((old = GetNodeByAnchor(attval->value)) &&  old != node)
991
 
    {
992
 
        ReportAttrError(lexer, node, attval, ANCHOR_NOT_UNIQUE);
 
1081
    if ( backslash_count )
 
1082
    {
 
1083
        if ( cfgBool(doc, TidyFixBackslash) )
 
1084
            ReportAttrError( doc, node, attval, FIXED_BACKSLASH );
 
1085
        else
 
1086
            ReportAttrError( doc, node, attval, BACKSLASH_IN_URI );
 
1087
    }
 
1088
    if ( escape_count )
 
1089
    {
 
1090
        if ( cfgBool(doc, TidyFixUri) )
 
1091
            ReportAttrError( doc, node, attval, ESCAPED_ILLEGAL_URI);
 
1092
        else
 
1093
            ReportAttrError( doc, node, attval, ILLEGAL_URI_REFERENCE);
 
1094
 
 
1095
        doc->badChars |= BC_INVALID_URI;
 
1096
    }
 
1097
}
 
1098
 
 
1099
void CheckScript( TidyDocImpl* ARG_UNUSED(doc), Node* ARG_UNUSED(node),
 
1100
                  AttVal* ARG_UNUSED(attval))
 
1101
{
 
1102
}
 
1103
 
 
1104
Bool IsValidHTMLID(ctmbstr id)
 
1105
{
 
1106
    ctmbstr s = id;
 
1107
 
 
1108
    if (!s)
 
1109
        return no;
 
1110
 
 
1111
    if (!IsLetter(*s++))
 
1112
        return no;
 
1113
 
 
1114
    while (*s)
 
1115
        if (!IsNamechar(*s++))
 
1116
            return no;
 
1117
 
 
1118
    return yes;
 
1119
 
 
1120
}
 
1121
 
 
1122
Bool IsValidXMLID(ctmbstr id)
 
1123
{
 
1124
    ctmbstr s = id;
 
1125
    tchar c;
 
1126
 
 
1127
    if (!s)
 
1128
        return no;
 
1129
 
 
1130
    c = *s++;
 
1131
    if (c > 0x7F)
 
1132
        s += GetUTF8(s, &c);
 
1133
 
 
1134
    if (!(IsXMLLetter(c) || c == '_' || c == ':'))
 
1135
        return no;
 
1136
 
 
1137
    while (*s)
 
1138
    {
 
1139
        c = (unsigned char)*s;
 
1140
 
 
1141
        if (c > 0x7F)
 
1142
            s += GetUTF8(s, &c);
 
1143
 
 
1144
        ++s;
 
1145
 
 
1146
        if (!IsXMLNamechar(c))
 
1147
            return no;
 
1148
    }
 
1149
 
 
1150
    return yes;
 
1151
}
 
1152
 
 
1153
static Bool IsValidNMTOKEN(ctmbstr name)
 
1154
{
 
1155
    ctmbstr s = name;
 
1156
    tchar c;
 
1157
 
 
1158
    if (!s)
 
1159
        return no;
 
1160
 
 
1161
    while (*s)
 
1162
    {
 
1163
        c = (unsigned char)*s;
 
1164
 
 
1165
        if (c > 0x7F)
 
1166
            s += GetUTF8(s, &c);
 
1167
 
 
1168
        ++s;
 
1169
 
 
1170
        if (!IsXMLNamechar(c))
 
1171
            return no;
 
1172
    }
 
1173
 
 
1174
    return yes;
 
1175
}
 
1176
 
 
1177
void CheckName( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1178
{
 
1179
    Node *old;
 
1180
 
 
1181
    if (!AttrHasValue(attval))
 
1182
    {
 
1183
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1184
        return;
 
1185
    }
 
1186
 
 
1187
    if ( IsAnchorElement(doc, node) )
 
1188
    {
 
1189
        if (cfgBool(doc, TidyXmlOut) && !IsValidNMTOKEN(attval->value))
 
1190
            ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1191
 
 
1192
        if ((old = GetNodeByAnchor(doc, attval->value)) &&  old != node)
 
1193
        {
 
1194
            ReportAttrError( doc, node, attval, ANCHOR_NOT_UNIQUE);
 
1195
        }
 
1196
        else
 
1197
            AddAnchor( doc, attval->value, node );
 
1198
    }
 
1199
}
 
1200
 
 
1201
void CheckId( TidyDocImpl* doc, Node *node, AttVal *attval )
 
1202
{
 
1203
    Lexer* lexer = doc->lexer;
 
1204
    Node *old;
 
1205
 
 
1206
    if (!AttrHasValue(attval))
 
1207
    {
 
1208
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1209
        return;
 
1210
    }
 
1211
 
 
1212
    if (!IsValidHTMLID(attval->value))
 
1213
    {
 
1214
        if (lexer->isvoyager && IsValidXMLID(attval->value))
 
1215
            ReportAttrError( doc, node, attval, XML_ID_SYNTAX);
 
1216
        else
 
1217
            ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1218
    }
 
1219
 
 
1220
    if ((old = GetNodeByAnchor(doc, attval->value)) &&  old != node)
 
1221
    {
 
1222
        ReportAttrError( doc, node, attval, ANCHOR_NOT_UNIQUE);
993
1223
    }
994
1224
    else
995
 
        anchor_list = AddAnchor(attval->value, node);
 
1225
        AddAnchor( doc, attval->value, node );
996
1226
}
997
1227
 
998
 
void CheckBool(Lexer *lexer, Node *node, AttVal *attval)
 
1228
void CheckBool( TidyDocImpl* doc, Node *node, AttVal *attval)
999
1229
{
1000
 
    if (attval == null || attval->value == null)
 
1230
    if (!AttrHasValue(attval))
1001
1231
        return;
1002
1232
 
1003
 
    CheckLowerCaseAttrValue(lexer, node, attval);
 
1233
    CheckLowerCaseAttrValue( doc, node, attval );
1004
1234
}
1005
1235
 
1006
 
void CheckAlign(Lexer *lexer, Node *node, AttVal *attval)
 
1236
void CheckAlign( TidyDocImpl* doc, Node *node, AttVal *attval)
1007
1237
{
1008
 
    char *value;
1009
 
 
1010
1238
    /* IMG, OBJECT, APPLET and EMBED use align for vertical position */
1011
1239
    if (node->tag && (node->tag->model & CM_IMG))
1012
1240
    {
1013
 
        CheckValign(lexer, node, attval);
1014
 
        return;
1015
 
    }
1016
 
 
1017
 
    if (attval == null || attval->value == null)
1018
 
    {
1019
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1020
 
        return;
1021
 
    }
1022
 
 
1023
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1024
 
 
1025
 
    value = attval->value;
1026
 
 
1027
 
    if (! (wstrcasecmp(value,    "left") == 0 ||
1028
 
           wstrcasecmp(value,  "center") == 0 ||
1029
 
           wstrcasecmp(value,   "right") == 0 ||
1030
 
           wstrcasecmp(value, "justify") == 0))
1031
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1241
        CheckValign( doc, node, attval );
 
1242
        return;
 
1243
    }
 
1244
 
 
1245
    if (!AttrHasValue(attval))
 
1246
    {
 
1247
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1248
        return;
 
1249
    }
 
1250
 
 
1251
    CheckLowerCaseAttrValue( doc, node, attval);
 
1252
 
 
1253
    /* currently CheckCaption(...) takes care of the remaining cases */
 
1254
    if (nodeIsCAPTION(node))
 
1255
        return;
 
1256
 
 
1257
    if (!(AttrValueIs(attval, "left")   ||
 
1258
          AttrValueIs(attval, "right")  ||
 
1259
          AttrValueIs(attval, "center") ||
 
1260
          AttrValueIs(attval, "justify")))
 
1261
    {
 
1262
        /* align="char" is allowed for elements with CM_TABLE|CM_ROW
 
1263
           except CAPTION which is excluded above, */
 
1264
        if( !(AttrValueIs(attval, "char")
 
1265
              && node->tag && (node->tag->model & CM_TABLE|CM_ROW)))
 
1266
             ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1267
    }
1032
1268
}
1033
1269
 
1034
 
void CheckValign(Lexer *lexer, Node *node, AttVal *attval)
 
1270
void CheckValign( TidyDocImpl* doc, Node *node, AttVal *attval)
1035
1271
{
1036
 
    char *value;
1037
 
 
1038
 
    if (attval == null || attval->value == null)
 
1272
    if (!AttrHasValue(attval))
1039
1273
    {
1040
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1274
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1041
1275
        return;
1042
1276
    }
1043
1277
 
1044
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1045
 
 
1046
 
    value = attval->value;
1047
 
 
1048
 
    if (wstrcasecmp(value,      "top") == 0 ||
1049
 
        wstrcasecmp(value,   "middle") == 0 ||
1050
 
        wstrcasecmp(value,   "bottom") == 0 ||
1051
 
        wstrcasecmp(value, "baseline") == 0)
 
1278
    CheckLowerCaseAttrValue( doc, node, attval );
 
1279
 
 
1280
    if (AttrValueIs(attval, "top")    ||
 
1281
        AttrValueIs(attval, "middle") ||
 
1282
        AttrValueIs(attval, "bottom") ||
 
1283
        AttrValueIs(attval, "baseline"))
1052
1284
    {
1053
1285
            /* all is fine */
1054
1286
    }
1055
 
    else if (wstrcasecmp(value,  "left") == 0 ||
1056
 
             wstrcasecmp(value, "right") == 0)
 
1287
    else if (AttrValueIs(attval, "left") ||
 
1288
             AttrValueIs(attval, "right"))
1057
1289
    {
1058
1290
        if (!(node->tag && (node->tag->model & CM_IMG)))
1059
 
            ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1291
            ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1060
1292
    }
1061
 
    else if (wstrcasecmp(value,    "texttop") == 0 ||
1062
 
             wstrcasecmp(value,  "absmiddle") == 0 ||
1063
 
             wstrcasecmp(value,  "absbottom") == 0 ||
1064
 
             wstrcasecmp(value, "textbottom") == 0)
 
1293
    else if (AttrValueIs(attval, "texttop")   ||
 
1294
             AttrValueIs(attval, "absmiddle") ||
 
1295
             AttrValueIs(attval, "absbottom") ||
 
1296
             AttrValueIs(attval, "textbottom"))
1065
1297
    {
1066
 
        ConstrainVersion(lexer, VERS_PROPRIETARY);
1067
 
        ReportAttrError(lexer, node, attval, PROPRIETARY_ATTR_VALUE);
 
1298
        ConstrainVersion( doc, VERS_PROPRIETARY );
 
1299
        ReportAttrError( doc, node, attval, PROPRIETARY_ATTR_VALUE);
1068
1300
    }
1069
1301
    else
1070
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1302
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1071
1303
}
1072
1304
 
1073
 
void CheckLength(Lexer *lexer, Node *node, AttVal *attval)
 
1305
void CheckLength( TidyDocImpl* doc, Node *node, AttVal *attval)
1074
1306
{
1075
 
    char *p;
 
1307
    tmbstr p;
1076
1308
    
1077
 
    if (attval == null || attval->value == null)
 
1309
    if (!AttrHasValue(attval))
1078
1310
    {
1079
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1311
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1080
1312
        return;
1081
1313
    }
1082
1314
 
 
1315
    /* don't check for <col width=...> and <colgroup width=...> */
 
1316
    if (attrIsWIDTH(attval) && (nodeIsCOL(node) || nodeIsCOLGROUP(node)))
 
1317
        return;
 
1318
 
1083
1319
    p = attval->value;
1084
1320
    
1085
1321
    if (!IsDigit(*p++))
1086
1322
    {
1087
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1088
 
    } else {
1089
 
 
 
1323
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1324
    }
 
1325
    else
 
1326
    {
1090
1327
        while (*p)
1091
1328
        {
1092
1329
            if (!IsDigit(*p) && *p != '%')
1093
1330
            {
1094
 
                ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1331
                ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1095
1332
                break;
1096
1333
            }
1097
1334
            ++p;
1099
1336
    }
1100
1337
}
1101
1338
 
1102
 
void CheckTarget(Lexer *lexer, Node *node, AttVal *attval)
1103
 
{
1104
 
    char *value;
1105
 
    
1106
 
    if (attval == null || attval->value == null)
1107
 
    {
1108
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1109
 
        return;
1110
 
    }
1111
 
 
1112
 
    /*
1113
 
      target names must begin with A-Za-z or be one of
1114
 
      _blank, _self, _parent and _top
1115
 
    */
1116
 
    
1117
 
    value = attval->value;
1118
 
 
1119
 
    if (IsLetter(value[0]))
1120
 
        return;
1121
 
    
1122
 
    if (! (wstrcasecmp(value,  "_blank") == 0 ||
1123
 
           wstrcasecmp(value,   "_self") == 0 ||
1124
 
           wstrcasecmp(value, "_parent") == 0 ||
1125
 
           wstrcasecmp(value,    "_top") == 0))
1126
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1127
 
}
1128
 
 
1129
 
void CheckFsubmit(Lexer *lexer, Node *node, AttVal *attval)
1130
 
{
1131
 
    char *value;
1132
 
    
1133
 
    if (attval == null || attval->value == null)
1134
 
    {
1135
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1136
 
        return;
1137
 
    }
1138
 
 
1139
 
    value = attval->value;
1140
 
 
1141
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1142
 
 
1143
 
    if (! (wstrcasecmp(value,  "get") == 0 ||
1144
 
           wstrcasecmp(value, "post") == 0))
1145
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1146
 
}
1147
 
 
1148
 
void CheckClear(Lexer *lexer, Node *node, AttVal *attval)
1149
 
{
1150
 
    char *value;
1151
 
 
1152
 
    if (attval == null || attval->value == null)
1153
 
    {
1154
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1155
 
        if (attval->value == null)
1156
 
            attval->value = wstrdup( "none" );
1157
 
        return;
1158
 
    }
1159
 
 
1160
 
    CheckLowerCaseAttrValue(lexer, node, attval);
 
1339
void CheckTarget( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1340
{
 
1341
    if (!AttrHasValue(attval))
 
1342
    {
 
1343
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1344
        return;
 
1345
    }
 
1346
 
 
1347
    /* target names must begin with A-Za-z ... */
 
1348
    if (IsLetter(attval->value[0]))
 
1349
        return;
 
1350
 
 
1351
    /* or be one of _blank, _self, _parent and _top */
 
1352
    if (!(AttrValueIs(attval, "_blank")  ||
 
1353
          AttrValueIs(attval, "_self")   ||
 
1354
          AttrValueIs(attval, "_parent") ||
 
1355
          AttrValueIs(attval, "_top")))
 
1356
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1357
}
 
1358
 
 
1359
void CheckFsubmit( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1360
{
 
1361
    if (!AttrHasValue(attval))
 
1362
    {
 
1363
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1364
        return;
 
1365
    }
 
1366
 
 
1367
    CheckLowerCaseAttrValue( doc, node, attval);
 
1368
 
 
1369
    if (!(AttrValueIs(attval, "get") ||
 
1370
          AttrValueIs(attval, "post")))
 
1371
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1372
}
 
1373
 
 
1374
void CheckClear( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1375
{
 
1376
    if (!AttrHasValue(attval))
 
1377
    {
 
1378
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1379
        if (attval->value == NULL)
 
1380
            attval->value = tmbstrdup( "none" );
 
1381
        return;
 
1382
    }
 
1383
 
 
1384
    CheckLowerCaseAttrValue( doc, node, attval );
1161
1385
        
1162
 
    value = attval->value;
1163
 
    
1164
 
    if (! (wstrcasecmp(value,  "none") == 0 ||
1165
 
           wstrcasecmp(value,  "left") == 0 ||
1166
 
           wstrcasecmp(value, "right") == 0 ||
1167
 
           wstrcasecmp(value,   "all") == 0))
1168
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1169
 
}
1170
 
 
1171
 
void CheckShape(Lexer *lexer, Node *node, AttVal *attval)
1172
 
{
1173
 
    char *value;
1174
 
    
1175
 
    if (attval == null || attval->value == null)
1176
 
    {
1177
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1178
 
        return;
1179
 
    }
1180
 
 
1181
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1182
 
 
1183
 
    value = attval->value;
1184
 
    
1185
 
    if (! (wstrcasecmp(value,    "rect") == 0 ||
1186
 
           wstrcasecmp(value, "default") == 0 ||
1187
 
           wstrcasecmp(value,  "circle") == 0 ||
1188
 
           wstrcasecmp(value,    "poly") == 0))
1189
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1190
 
}
1191
 
 
1192
 
void CheckScope(Lexer *lexer, Node *node, AttVal *attval)
1193
 
{
1194
 
    char *value;
1195
 
    
1196
 
    if (attval == null || attval->value == null)
1197
 
    {
1198
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1199
 
        return;
1200
 
    }
1201
 
 
1202
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1203
 
 
1204
 
    value = attval->value;
1205
 
    
1206
 
    if (! (wstrcasecmp(value,      "row") == 0 ||
1207
 
           wstrcasecmp(value, "rowgroup") == 0 ||
1208
 
           wstrcasecmp(value,      "col") == 0 ||
1209
 
           wstrcasecmp(value, "colgroup") == 0))
1210
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1211
 
}
1212
 
 
1213
 
void CheckNumber(Lexer *lexer, Node *node, AttVal *attval)
1214
 
{
1215
 
    char *p;
1216
 
    
1217
 
    if (attval == null || attval->value == null)
1218
 
    {
1219
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
1220
 
        return;
1221
 
    }
 
1386
    if (!(AttrValueIs(attval, "none")  ||
 
1387
          AttrValueIs(attval, "left")  ||
 
1388
          AttrValueIs(attval, "right") ||
 
1389
          AttrValueIs(attval, "all")))
 
1390
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1391
}
 
1392
 
 
1393
void CheckShape( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1394
{
 
1395
    if (!AttrHasValue(attval))
 
1396
    {
 
1397
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1398
        return;
 
1399
    }
 
1400
 
 
1401
    CheckLowerCaseAttrValue( doc, node, attval );
 
1402
 
 
1403
    if (!(AttrValueIs(attval, "rect")    ||
 
1404
          AttrValueIs(attval, "default") ||
 
1405
          AttrValueIs(attval, "circle")  ||
 
1406
          AttrValueIs(attval, "poly")))
 
1407
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1408
}
 
1409
 
 
1410
void CheckScope( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1411
{
 
1412
    if (!AttrHasValue(attval))
 
1413
    {
 
1414
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1415
        return;
 
1416
    }
 
1417
 
 
1418
    CheckLowerCaseAttrValue( doc, node, attval);
 
1419
 
 
1420
    if (!(AttrValueIs(attval, "row")      ||
 
1421
          AttrValueIs(attval, "rowgroup") ||
 
1422
          AttrValueIs(attval, "col")      ||
 
1423
          AttrValueIs(attval, "colgroup")))
 
1424
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
 
1425
}
 
1426
 
 
1427
void CheckNumber( TidyDocImpl* doc, Node *node, AttVal *attval)
 
1428
{
 
1429
    tmbstr p;
 
1430
    
 
1431
    if (!AttrHasValue(attval))
 
1432
    {
 
1433
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
 
1434
        return;
 
1435
    }
 
1436
 
 
1437
    /* don't check <frameset cols=... rows=...> */
 
1438
    if ( nodeIsFRAMESET(node) &&
 
1439
        (attrIsCOLS(attval) || attrIsROWS(attval)))
 
1440
     return;
1222
1441
 
1223
1442
    p  = attval->value;
1224
1443
    
1225
1444
    /* font size may be preceded by + or - */
1226
 
    if (node->tag == tag_font && (*p == '+' || *p == '-'))
 
1445
    if ( nodeIsFONT(node) && (*p == '+' || *p == '-') )
1227
1446
        ++p;
1228
1447
 
1229
1448
    while (*p)
1230
1449
    {
1231
1450
        if (!IsDigit(*p))
1232
1451
        {
1233
 
            ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1452
            ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1234
1453
            break;
1235
1454
        }
1236
1455
        ++p;
1237
1456
    }
1238
1457
}
1239
1458
 
 
1459
/* check hexadecimal color value */
 
1460
static Bool IsValidColorCode(ctmbstr color)
 
1461
{
 
1462
    uint i;
 
1463
 
 
1464
    if (tmbstrlen(color) != 6)
 
1465
        return no;
 
1466
 
 
1467
    /* check if valid hex digits and letters */
 
1468
    for (i = 0; i < 6; i++)
 
1469
        if (!IsDigit(color[i]) && !strchr("abcdef", ToLower(color[i])))
 
1470
            return no;
 
1471
 
 
1472
    return yes;
 
1473
}
 
1474
 
1240
1475
/* check color syntax and beautify value by option */
1241
 
void CheckColor(Lexer *lexer, Node *node, AttVal *attval)
 
1476
void CheckColor( TidyDocImpl* doc, Node *node, AttVal *attval)
1242
1477
{
1243
 
    /* Bool ReplaceColor = yes; */ /* #477643 - replace hex color attribute values with names */
1244
 
    Bool HexUppercase = yes;
1245
 
    Bool invalid = no;
1246
 
    Bool found = no;
1247
 
    char *given;
1248
 
    struct _colors *color;
1249
 
    uint i = 0;
 
1478
    Bool valid = no;
 
1479
    tmbstr given;
1250
1480
 
1251
 
    if (attval == null || attval->value == null)
 
1481
    if (!AttrHasValue(attval))
1252
1482
    {
1253
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1483
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1254
1484
        return;
1255
1485
    }
1256
1486
 
1257
1487
    given = attval->value;
1258
 
    
1259
 
    for (color = colors; color->name; ++color)
1260
 
    {
1261
 
        if (given[0] == '#')
1262
 
        {
1263
 
            if (wstrlen(given) != 7)
1264
 
            {
1265
 
                ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1266
 
                invalid = yes;
1267
 
                break;
1268
 
            }
1269
 
            else if (wstrcasecmp(given, color->hex) == 0)
1270
 
            {
1271
 
                if (ReplaceColor)
1272
 
                {
1273
 
                    MemFree(attval->value);
1274
 
                    attval->value = wstrdup(color->name);
1275
 
                }
1276
 
                found = yes;
1277
 
                break;
1278
 
            }
1279
 
        }
1280
 
        else if (IsLetter(given[0]))
1281
 
        {
1282
 
            if (wstrcasecmp(given, color->name) == 0)
1283
 
            {
1284
 
                if (ReplaceColor)
1285
 
                {
1286
 
                    MemFree(attval->value);
1287
 
                    attval->value = wstrdup(color->name);
1288
 
                }
1289
 
                found = yes;
1290
 
                break;
1291
 
            }
1292
 
        }
1293
 
        else
1294
 
        {
1295
 
            ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1296
 
            invalid = yes;
1297
 
            break;
1298
 
        }
1299
 
    }
1300
 
    
1301
 
    if (!found && !invalid)
1302
 
    {
1303
 
        if (given[0] == '#')
1304
 
        {
1305
 
            /* check if valid hex digits and letters */
1306
 
            for (i = 1; i < 7; ++i)
1307
 
            {
1308
 
                if (!IsDigit(given[i]) &&
1309
 
                    !strchr("abcdef", ToLower(given[i])))
1310
 
                {
1311
 
                    ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1312
 
                    invalid = yes;
1313
 
                    break;
1314
 
                }
1315
 
            }
1316
 
            
1317
 
            /* convert hex letters to uppercase */
1318
 
            if (!invalid && HexUppercase)
1319
 
            {
1320
 
                for (i = 1; i < 7; ++i)
1321
 
                {
1322
 
                    given[i] = ToUpper(given[i]);
1323
 
                }
1324
 
            }
1325
 
        }
1326
 
        else
1327
 
        {
1328
 
            /* we could search for more colors and mark the file as HTML
1329
 
               Proprietary, but I don't thinks it's worth the effort,
1330
 
               so values not in HTML 4.01 are invalid */
1331
 
 
1332
 
            ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1333
 
        }
1334
 
    }
 
1488
 
 
1489
    /* 727851 - add hash to hash-less color values */
 
1490
    if (given[0] != '#' && (valid = IsValidColorCode(given)))
 
1491
    {
 
1492
        tmbstr cp, s;
 
1493
 
 
1494
        cp = s = (tmbstr) MemAlloc(2 + tmbstrlen (given));
 
1495
        *cp++ = '#';
 
1496
        while ('\0' != (*cp++ = *given++))
 
1497
            continue;
 
1498
 
 
1499
        ReportAttrError(doc, node, attval, BAD_ATTRIBUTE_VALUE_REPLACED);
 
1500
 
 
1501
        MemFree(attval->value);
 
1502
        given = attval->value = s;
 
1503
    }
 
1504
 
 
1505
    if (!valid && given[0] == '#')
 
1506
        valid = IsValidColorCode(given + 1);
 
1507
 
 
1508
    if (valid && given[0] == '#' && cfgBool(doc, TidyReplaceColor))
 
1509
    {
 
1510
        ctmbstr newName = GetColorName(given);
 
1511
 
 
1512
        if (newName)
 
1513
        {
 
1514
            MemFree(attval->value);
 
1515
            given = attval->value = tmbstrdup(newName);
 
1516
        }
 
1517
    }
 
1518
 
 
1519
    /* if it is not a valid color code, it is a color name */
 
1520
    if (!valid)
 
1521
        valid = GetColorCode(given) != NULL;
 
1522
 
 
1523
    if (valid && given[0] == '#')
 
1524
        attval->value = tmbstrtoupper(attval->value);
 
1525
    else if (valid)
 
1526
        attval->value = tmbstrtolower(attval->value);
 
1527
 
 
1528
    if (!valid)
 
1529
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1335
1530
}
1336
1531
 
1337
1532
/* check valuetype attribute for element param */
1338
 
void CheckVType(Lexer *lexer, Node *node, AttVal *attval)
 
1533
void CheckVType( TidyDocImpl* doc, Node *node, AttVal *attval)
1339
1534
{
1340
 
    char *value;
1341
 
 
1342
 
    if (attval == null || attval->value == null)
 
1535
    if (!AttrHasValue(attval))
1343
1536
    {
1344
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1537
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1345
1538
        return;
1346
1539
    }
1347
1540
 
1348
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1349
 
 
1350
 
    value = attval->value;
1351
 
 
1352
 
    if (! (wstrcasecmp(value,   "data") == 0 ||
1353
 
           wstrcasecmp(value, "object") == 0 ||
1354
 
           wstrcasecmp(value,    "ref") == 0))
1355
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1541
    CheckLowerCaseAttrValue( doc, node, attval );
 
1542
 
 
1543
    if (!(AttrValueIs(attval, "data")   ||
 
1544
          AttrValueIs(attval, "object") ||
 
1545
          AttrValueIs(attval, "ref")))
 
1546
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1356
1547
}
1357
1548
 
1358
1549
/* checks scrolling attribute */
1359
 
void CheckScroll(Lexer *lexer, Node *node, AttVal *attval)
 
1550
void CheckScroll( TidyDocImpl* doc, Node *node, AttVal *attval)
1360
1551
{
1361
 
    char *value;
1362
 
 
1363
 
    if (attval == null || attval->value == null)
 
1552
    if (!AttrHasValue(attval))
1364
1553
    {
1365
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1554
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1366
1555
        return;
1367
1556
    }
1368
1557
 
1369
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1370
 
 
1371
 
    value = attval->value;
1372
 
 
1373
 
    if (! (wstrcasecmp(value,   "no") == 0 ||
1374
 
           wstrcasecmp(value, "auto") == 0 ||
1375
 
           wstrcasecmp(value,  "yes") == 0))
1376
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1558
    CheckLowerCaseAttrValue( doc, node, attval );
 
1559
 
 
1560
    if (!(AttrValueIs(attval, "no")   ||
 
1561
          AttrValueIs(attval, "auto") ||
 
1562
          AttrValueIs(attval, "yes")))
 
1563
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1377
1564
}
1378
1565
 
1379
1566
/* checks dir attribute */
1380
 
void CheckTextDir(Lexer *lexer, Node *node, AttVal *attval)
 
1567
void CheckTextDir( TidyDocImpl* doc, Node *node, AttVal *attval)
1381
1568
{
1382
 
    char *value;
1383
 
 
1384
 
    if (attval == null || attval->value == null)
 
1569
    if (!AttrHasValue(attval))
1385
1570
    {
1386
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1571
        ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE);
1387
1572
        return;
1388
1573
    }
1389
1574
 
1390
 
    CheckLowerCaseAttrValue(lexer, node, attval);
1391
 
 
1392
 
    value = attval->value;
1393
 
 
1394
 
    if (! (wstrcasecmp(value, "rtl") == 0 ||
1395
 
           wstrcasecmp(value, "ltr") == 0))
1396
 
        ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
 
1575
    CheckLowerCaseAttrValue( doc, node, attval);
 
1576
 
 
1577
    if (!(AttrValueIs(attval, "rtl") ||
 
1578
          AttrValueIs(attval, "ltr")))
 
1579
        ReportAttrError( doc, node, attval, BAD_ATTRIBUTE_VALUE);
1397
1580
}
1398
1581
 
1399
1582
/* checks lang and xml:lang attributes */
1400
 
void CheckLang(Lexer *lexer, Node *node, AttVal *attval)
 
1583
void CheckLang( TidyDocImpl* doc, Node *node, AttVal *attval)
1401
1584
{
1402
 
    if (attval == null || attval->value == null)
 
1585
    /* empty xml:lang is allowed through XML 1.0 SE errata */
 
1586
    if (!AttrHasValue(attval) && !attrIsXML_LANG(attval))
1403
1587
    {
1404
 
        ReportAttrError(lexer, node, attval, MISSING_ATTR_VALUE);
 
1588
        if ( cfg(doc, TidyAccessibilityCheckLevel) == 0 )
 
1589
        {
 
1590
            ReportAttrError( doc, node, attval, MISSING_ATTR_VALUE );
 
1591
        }
1405
1592
        return;
1406
1593
    }
1407
 
 
1408
 
    if (wstrcasecmp(attval->attribute, "lang") == 0)
1409
 
        ConstrainVersion(lexer, ~VERS_XHTML11);
1410
 
}
1411
 
 
1412
 
/* default method for checking an element's attributes */
1413
 
void CheckAttributes(Lexer *lexer, Node *node)
1414
 
{
1415
 
    AttVal *attval;
1416
 
 
1417
 
    for (attval = node->attributes; attval != null; attval = attval->next)
1418
 
        CheckAttribute(lexer, node, attval);
1419
 
}
1420
 
 
1421
 
/* methods for checking attributes for specific elements */
1422
 
 
1423
 
void CheckHR(Lexer *lexer, Node *node)
1424
 
{
1425
 
    AttVal *av = GetAttrByName(node, "src");
1426
 
 
1427
 
    CheckAttributes(lexer, node);
1428
 
 
1429
 
    if (av)
1430
 
        ReportAttrError(lexer, node, av, PROPRIETARY_ATTR_VALUE);
1431
 
}
1432
 
 
1433
 
void CheckIMG(Lexer *lexer, Node *node)
1434
 
{
1435
 
    AttVal *attval;
1436
 
    Attribute *attribute;
1437
 
    Bool HasAlt = no;
1438
 
    Bool HasSrc = no;
1439
 
    Bool HasUseMap = no;
1440
 
    Bool HasIsMap = no;
1441
 
    Bool HasDataFld = no;
1442
 
 
1443
 
    for (attval = node->attributes; attval != null; attval = attval->next)
1444
 
    {
1445
 
        attribute = CheckAttribute(lexer, node, attval);
1446
 
 
1447
 
        if (attribute == attr_alt)
1448
 
            HasAlt = yes;
1449
 
        else if (attribute == attr_src)
1450
 
            HasSrc = yes;
1451
 
        else if (attribute == attr_usemap)
1452
 
            HasUseMap = yes;
1453
 
        else if (attribute == attr_ismap)
1454
 
            HasIsMap = yes;
1455
 
        else if (attribute == attr_datafld)
1456
 
            HasDataFld = yes;
1457
 
        else if (attribute == attr_width || attribute == attr_height)
1458
 
            ConstrainVersion(lexer, ~VERS_HTML20);
1459
 
    }
1460
 
 
1461
 
    if (!HasAlt)
1462
 
    {
1463
 
        lexer->badAccess |= MISSING_IMAGE_ALT;
1464
 
        ReportMissingAttr(lexer, node, "alt");
1465
 
 
1466
 
        if (alt_text)
1467
 
            AddAttribute(node, "alt", alt_text);
1468
 
    }
1469
 
 
1470
 
    if (!HasSrc && !HasDataFld)
1471
 
        ReportMissingAttr(lexer, node, "src");
1472
 
 
1473
 
    if (HasIsMap && !HasUseMap)
1474
 
        ReportMissingAttr(lexer, node, "ismap");
1475
 
}
1476
 
 
1477
 
void CheckAnchor(Lexer *lexer, Node *node)
1478
 
{
1479
 
    CheckAttributes(lexer, node);
1480
 
 
1481
 
    FixId(lexer, node);
1482
 
}
1483
 
 
1484
 
void CheckMap(Lexer *lexer, Node *node)
1485
 
{
1486
 
    CheckAttributes(lexer, node);
1487
 
 
1488
 
    FixId(lexer, node);
1489
 
}
1490
 
 
1491
 
void CheckTableCell(Lexer *lexer, Node *node)
1492
 
{
1493
 
    CheckAttributes(lexer, node);
1494
 
 
1495
 
    /*
1496
 
      HTML4 strict doesn't allow mixed content for
1497
 
      elements with %block; as their content model
1498
 
    */
1499
 
    if (GetAttrByName(node, "width") || GetAttrByName(node, "height"))
1500
 
        ConstrainVersion(lexer, ~VERS_HTML40_STRICT);
1501
 
}
1502
 
 
1503
 
void CheckCaption(Lexer *lexer, Node *node)
1504
 
{
1505
 
    AttVal *attval;
1506
 
    char *value = null;
1507
 
 
1508
 
    CheckAttributes(lexer, node);
1509
 
 
1510
 
    for (attval = node->attributes; attval != null; attval = attval->next)
1511
 
    {
1512
 
        if (wstrcasecmp(attval->attribute, "align") == 0)
1513
 
        {
1514
 
            value = attval->value;
1515
 
            break;
1516
 
        }
1517
 
    }
1518
 
 
1519
 
    if (value != null)
1520
 
    {
1521
 
        if (wstrcasecmp(value, "left") == 0 || wstrcasecmp(value, "right") == 0)
1522
 
            ConstrainVersion(lexer, VERS_HTML40_LOOSE);
1523
 
        else if (wstrcasecmp(value, "top") == 0 || wstrcasecmp(value, "bottom") == 0)
1524
 
            ConstrainVersion(lexer, ~(VERS_HTML20|VERS_HTML32));
1525
 
        else
1526
 
            ReportAttrError(lexer, node, attval, BAD_ATTRIBUTE_VALUE);
1527
 
    }
1528
 
}
1529
 
 
1530
 
void CheckHTML(Lexer *lexer, Node *node)
1531
 
{
1532
 
    AttVal *attval;
1533
 
    Attribute *attribute;
1534
 
 
1535
 
    for (attval = node->attributes; attval != null; attval = attval->next)
1536
 
    {
1537
 
        attribute = CheckAttribute(lexer, node, attval);
1538
 
        if (attribute == attr_xmlns && wstrcmp(attval->value, XHTML_NAMESPACE)==0 )
1539
 
        {
1540
 
            lexer->isvoyager = yes;
1541
 
            if ( ! HtmlOut )  /* Unless user has specified plain HTML output, */
1542
 
              xHTML = yes;    /* output format will be XHTML. */
1543
 
        }
1544
 
    }
1545
 
}
1546
 
 
1547
 
void CheckAREA(Lexer *lexer, Node *node)
1548
 
{
1549
 
    AttVal *attval;
1550
 
    Attribute *attribute;
1551
 
    Bool HasAlt = no;
1552
 
    Bool HasHref = no;
1553
 
 
1554
 
    for (attval = node->attributes; attval != null; attval = attval->next)
1555
 
    {
1556
 
        attribute = CheckAttribute(lexer, node, attval);
1557
 
 
1558
 
        if (attribute == attr_alt)
1559
 
            HasAlt = yes;
1560
 
        else if (attribute == attr_href)
1561
 
            HasHref = yes;
1562
 
    }
1563
 
 
1564
 
    if (!HasAlt)
1565
 
    {
1566
 
        lexer->badAccess |= MISSING_LINK_ALT;
1567
 
        ReportMissingAttr(lexer, node, "alt");
1568
 
    }
1569
 
    if (!HasHref)
1570
 
        ReportMissingAttr(lexer, node, "href");
1571
 
}
1572
 
 
1573
 
void CheckTABLE(Lexer *lexer, Node *node)
1574
 
{
1575
 
    AttVal *attval;
1576
 
    Attribute *attribute;
1577
 
    Bool HasSummary = no;
1578
 
 
1579
 
    for (attval = node->attributes; attval != null; attval = attval->next)
1580
 
    {
1581
 
        attribute = CheckAttribute(lexer, node, attval);
1582
 
 
1583
 
        if (attribute == attr_summary)
1584
 
            HasSummary = yes;
1585
 
    }
1586
 
 
1587
 
    /* suppress warning for missing summary for HTML 2.0 and HTML 3.2 */
1588
 
    if (!HasSummary && lexer->doctype != VERS_HTML20 && lexer->doctype != VERS_HTML32)
1589
 
    {
1590
 
        lexer->badAccess |= MISSING_SUMMARY;
1591
 
        ReportMissingAttr(lexer, node, "summary");
1592
 
    }
1593
 
 
1594
 
    /* convert <table border> to <table border="1"> */
1595
 
    if (XmlOut && (attval = GetAttrByName(node, "border")))
1596
 
    {
1597
 
        if (attval->value == null)
1598
 
            attval->value = wstrdup("1");
1599
 
    }
1600
 
 
1601
 
    /* <table height="..."> is proprietary */
1602
 
    if (attval = GetAttrByName(node, "height"))
1603
 
    {
1604
 
        ReportAttrError(lexer, node, attval, PROPRIETARY_ATTRIBUTE);
1605
 
        ConstrainVersion(lexer, VERS_PROPRIETARY);
1606
 
    }
1607
 
}
1608
 
 
1609
 
/* add missing type attribute when appropriate */
1610
 
void CheckSCRIPT(Lexer *lexer, Node *node)
1611
 
{
1612
 
    AttVal *lang, *type;
1613
 
    char buf[16];
1614
 
 
1615
 
    CheckAttributes(lexer, node);
1616
 
 
1617
 
    lang = GetAttrByName(node, "language");
1618
 
    type = GetAttrByName(node, "type");
1619
 
 
1620
 
    if (!type)
1621
 
    {
1622
 
        ReportMissingAttr(lexer, node, "type");
1623
 
 
1624
 
        /* check for javascript */
1625
 
 
1626
 
        if (lang)
1627
 
        {
1628
 
            wstrncpy(buf, lang->value, 10);
1629
 
            buf[10] = '\0';
1630
 
 
1631
 
            if ( (wstrncasecmp(buf, "javascript", 10) == 0) ||
1632
 
                 (wstrncasecmp(buf,    "jscript", 7) == 0) )
1633
 
            {
1634
 
                AddAttribute(node, "type", "text/javascript");
1635
 
            }
1636
 
            else if ( wstrcasecmp(buf, "vbscript") == 0 )
1637
 
            {
1638
 
               /* per Randy Waki 8/6/01 */
1639
 
                AddAttribute(node, "type", "text/vbscript");
1640
 
            }
1641
 
        }
1642
 
        else
1643
 
            AddAttribute(node, "type", "text/javascript");
1644
 
    }
1645
 
}
1646
 
 
1647
 
 
1648
 
/* add missing type attribute when appropriate */
1649
 
void CheckSTYLE(Lexer *lexer, Node *node)
1650
 
{
1651
 
    AttVal *type = GetAttrByName(node, "type");
1652
 
 
1653
 
    CheckAttributes(lexer, node);
1654
 
 
1655
 
    if (!type)
1656
 
    {
1657
 
        ReportMissingAttr(lexer, node, "type");
1658
 
 
1659
 
        AddAttribute(node, "type", "text/css");
1660
 
    }
1661
 
}
1662
 
 
1663
 
/* add missing type attribute when appropriate */
1664
 
void CheckLINK(Lexer *lexer, Node *node)
1665
 
{
1666
 
    AttVal *rel = GetAttrByName(node, "rel");
1667
 
 
1668
 
    CheckAttributes(lexer, node);
1669
 
 
1670
 
    if (rel && rel->value &&
1671
 
          wstrcmp(rel->value, "stylesheet") == 0)
1672
 
    {
1673
 
        AttVal *type = GetAttrByName(node, "type");
1674
 
 
1675
 
        if (!type)
1676
 
        {
1677
 
            ReportMissingAttr(lexer, node, "type");
1678
 
 
1679
 
            AddAttribute(node, "type", "text/css");
1680
 
        }
1681
 
    }
1682
 
}
1683
 
 
1684
 
/* reports missing action attribute */
1685
 
void CheckFORM(Lexer *lexer, Node *node)
1686
 
{
1687
 
    AttVal *action = GetAttrByName(node, "action");
1688
 
 
1689
 
    CheckAttributes(lexer, node);
1690
 
 
1691
 
    if (!action)
1692
 
        ReportMissingAttr(lexer, node, "action");
1693
 
}
1694
 
 
1695
 
/* reports missing content attribute */
1696
 
void CheckMETA(Lexer *lexer, Node *node)
1697
 
{
1698
 
    AttVal *content = GetAttrByName(node, "content");
1699
 
 
1700
 
    CheckAttributes(lexer, node);
1701
 
 
1702
 
    if (!content)
1703
 
        ReportMissingAttr(lexer, node, "content");
1704
 
 
1705
 
    /* name or http-equiv attribute must also be set */
1706
 
}
1707
 
 
 
1594
}