/* tags.c -- recognize HTML tags
(c) 1998 (W3C) MIT, INRIA, Keio University
See tidy.c for the copyright notice.
The HTML tags are stored as 8 bit ASCII strings.
Use lookupw() to find a tag given a wide char string.
*/
#include "platform.h" /* platform independent stuff */
#include "html.h" /* to pull in definition of nodes */
#define HASHSIZE 101
extern Bool XmlTags;
Dict *tag_html;
Dict *tag_head;
Dict *tag_title;
Dict *tag_body;
Dict *tag_frameset;
Dict *tag_noframes;
Dict *tag_hr;
Dict *tag_h1;
Dict *tag_h2;
Dict *tag_pre;
Dict *tag_listing;
Dict *tag_p;
Dict *tag_ul;
Dict *tag_ol;
Dict *tag_dir;
Dict *tag_li;
Dict *tag_dt;
Dict *tag_dd;
Dict *tag_td;
Dict *tag_th;
Dict *tag_tr;
Dict *tag_col;
Dict *tag_br;
Dict *tag_a;
Dict *tag_link;
Dict *tag_b;
Dict *tag_i;
Dict *tag_param;
Dict *tag_option;
Dict *tag_optgroup;
Dict *tag_map;
Dict *tag_area;
Dict *tag_nobr;
Dict *tag_wbr;
Dict *tag_font;
Dict *tag_layer;
Dict *tag_spacer;
Dict *tag_center;
Dict *tag_style;
Dict *tag_script;
Dict *tag_noscript;
Dict *tag_table;
Dict *tag_caption;
Dict *tag_form;
Dict *tag_blockquote;
Dict *tag_div;
Dict *tag_span;
Dict *xml_tags; /* dummy for xml tags */
static Dict *hashtab[HASHSIZE];
static struct tag
{
char *name;
unsigned versions;
unsigned model;
Parser *parser;
CheckAttribs *chkattrs;
} tags[] =
{
"HTML", (VERS_ALL|VERS_FRAMES), CM_HTML, ParseHTML, CheckHTML,
"HEAD", (VERS_ALL|VERS_FRAMES), (CM_HTML|CM_OPT), ParseHead, null,
"TITLE", (VERS_ALL|VERS_FRAMES), CM_HEAD, ParseTitle, null,
"BASE", (VERS_ALL|VERS_FRAMES), (CM_HEAD|CM_EMPTY), null, null,
"LINK", (VERS_ALL|VERS_FRAMES), (CM_HEAD|CM_EMPTY), null, null,
"META", (VERS_ALL|VERS_FRAMES), (CM_HEAD|CM_EMPTY), null, null,
"STYLE", (VERS_FROM32|VERS_FRAMES), CM_HEAD, ParseScript, null,
"SCRIPT", (VERS_FROM32|VERS_FRAMES), (CM_HEAD|CM_MIXED|CM_BLOCK|CM_INLINE), ParseScript, CheckSCRIPT,
"BODY", VERS_ALL, (CM_HTML|CM_OPT), ParseBody, null,
"FRAMESET", VERS_FRAMES, (CM_HTML|CM_FRAMES), ParseFrameSet, null,
"P", VERS_ALL, (CM_BLOCK|CM_OPT), ParseInline, null,
"H1", VERS_ALL, (CM_BLOCK|CM_HEADING), ParseInline, null,
"H2", VERS_ALL, (CM_BLOCK|CM_HEADING), ParseInline, null,
"H3", VERS_ALL, (CM_BLOCK|CM_HEADING), ParseInline, null,
"H4", VERS_ALL, (CM_BLOCK|CM_HEADING), ParseInline, null,
"H5", VERS_ALL, (CM_BLOCK|CM_HEADING), ParseInline, null,
"H6", VERS_ALL, (CM_BLOCK|CM_HEADING), ParseInline, null,
"UL", VERS_ALL, CM_BLOCK, ParseList, null,
"OL", VERS_ALL, CM_BLOCK, ParseList, null,
"DL", VERS_ALL, CM_BLOCK, ParseDefList, null,
"DIR", VERS_LOOSE, (CM_BLOCK|CM_OBSOLETE), ParseList, null,
"MENU", VERS_LOOSE, (CM_BLOCK|CM_OBSOLETE), ParseList, null,
"PRE", VERS_ALL, CM_BLOCK, ParsePre, null,
"LISTING", VERS_ALL, (CM_BLOCK|CM_OBSOLETE), ParsePre, null,
"XMP", VERS_ALL, (CM_BLOCK|CM_OBSOLETE), ParsePre, null,
"PLAINTEXT", VERS_ALL, (CM_BLOCK|CM_OBSOLETE), ParsePre, null,
"ADDRESS", VERS_ALL, CM_BLOCK, ParseBlock, null,
"BLOCKQUOTE", VERS_ALL, CM_BLOCK, ParseBlock, null,
"FORM", VERS_ALL, CM_BLOCK, ParseBlock, null,
"ISINDEX", VERS_ALL, (CM_BLOCK|CM_EMPTY), null, null,
"FIELDSET", VERS_HTML40, CM_BLOCK, ParseBlock, null,
"TABLE", VERS_FROM32, CM_BLOCK, ParseTableTag, CheckTABLE,
"HR", VERS_ALL, (CM_BLOCK|CM_EMPTY), null, null,
"DIV", VERS_FROM32, CM_BLOCK, ParseBlock, null,
"NOSAVE", VERS_NETSCAPE, CM_BLOCK, ParseBlock, null,
"LAYER", VERS_NETSCAPE, CM_BLOCK, ParseBlock, null,
"NOLAYER", VERS_NETSCAPE, CM_BLOCK, ParseBlock, null,
"ALIGN", VERS_NETSCAPE, CM_BLOCK, ParseBlock, null,
"CENTER", VERS_LOOSE, CM_BLOCK, ParseBlock, null,
"INS", VERS_HTML40, (CM_INLINE|CM_BLOCK|CM_MIXED), ParseInline, null,
"DEL", VERS_HTML40, (CM_INLINE|CM_BLOCK|CM_MIXED), ParseInline, null,
"LI", VERS_ALL, (CM_LIST|CM_OPT|CM_NO_INDENT), ParseBlock, null,
"DT", VERS_ALL, (CM_DEFLIST|CM_OPT|CM_NO_INDENT), ParseInline, null,
"DD", VERS_ALL, (CM_DEFLIST|CM_OPT|CM_NO_INDENT), ParseBlock, null,
"CAPTION", VERS_FROM32, CM_TABLE, ParseInline, CheckCaption,
"COLGROUP", VERS_HTML40, (CM_TABLE|CM_OPT), ParseColGroup, null,
"COL", VERS_HTML40, (CM_TABLE|CM_EMPTY), null, null,
"THEAD", VERS_HTML40, (CM_TABLE|CM_ROWGRP|CM_OPT), ParseRowGroup, null,
"TFOOT", VERS_HTML40, (CM_TABLE|CM_ROWGRP|CM_OPT), ParseRowGroup, null,
"TBODY", VERS_HTML40, (CM_TABLE|CM_ROWGRP|CM_OPT), ParseRowGroup, null,
"TR", VERS_FROM32, (CM_TABLE|CM_OPT), ParseRow, null,
"TD", VERS_FROM32, (CM_ROW|CM_OPT|CM_NO_INDENT), ParseBlock, null,
"TH", VERS_FROM32, (CM_ROW|CM_OPT|CM_NO_INDENT), ParseBlock, null,
"Q", VERS_HTML40, CM_INLINE, ParseInline, null,
"A", VERS_ALL, CM_INLINE, ParseInline, null,
"BR", VERS_ALL, (CM_INLINE|CM_EMPTY), null, null,
"IMG", VERS_ALL, (CM_INLINE|CM_IMG|CM_EMPTY), null, CheckIMG,
"OBJECT", VERS_HTML40, (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM), ParseBlock, null,
"APPLET", VERS_LOOSE, (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM), ParseBlock, null,
"SERVLET", VERS_SUN, (CM_OBJECT|CM_IMG|CM_INLINE|CM_PARAM), ParseBlock, null,
"PARAM", VERS_FROM32, (CM_INLINE|CM_EMPTY), null, null,
"EMBED", VERS_NETSCAPE, (CM_INLINE|CM_IMG|CM_EMPTY), null, null,
"IFRAME", VERS_HTML40_LOOSE, CM_INLINE, ParseBlock, null,
"FRAME", VERS_FRAMES, (CM_FRAMES|CM_EMPTY), null, null,
"NOFRAMES", VERS_IFRAMES, (CM_BLOCK|CM_FRAMES), ParseNoFrames, null,
"NOSCRIPT", (VERS_FRAMES|VERS_HTML40), (CM_BLOCK|CM_INLINE|CM_MIXED), ParseBlock, null,
"B", VERS_ALL, CM_INLINE, ParseInline, null,
"I", VERS_ALL, CM_INLINE, ParseInline, null,
"U", VERS_ALL, CM_INLINE, ParseInline, null,
"TT", VERS_ALL, CM_INLINE, ParseInline, null,
"S", VERS_HTML40, CM_INLINE, ParseInline, null,
"STRIKE", VERS_FROM32, CM_INLINE, ParseInline, null,
"BIG", VERS_FROM32, CM_INLINE, ParseInline, null,
"SMALL", VERS_FROM32, CM_INLINE, ParseInline, null,
"SUB", VERS_FROM32, CM_INLINE, ParseInline, null,
"SUP", VERS_FROM32, CM_INLINE, ParseInline, null,
"EM", VERS_ALL, CM_INLINE, ParseInline, null,
"STRONG", VERS_ALL, CM_INLINE, ParseInline, null,
"DFN", VERS_ALL, CM_INLINE, ParseInline, null,
"CODE", VERS_ALL, CM_INLINE, ParseInline, null,
"SAMP", VERS_ALL, CM_INLINE, ParseInline, null,
"KBD", VERS_ALL, CM_INLINE, ParseInline, null,
"VAR", VERS_ALL, CM_INLINE, ParseInline, null,
"CITE", VERS_ALL, CM_INLINE, ParseInline, null,
"ABBR", VERS_HTML40, CM_INLINE, ParseInline, null,
"ACRONYM", VERS_HTML40, CM_INLINE, ParseInline, null,
"SPAN", VERS_FROM32, CM_INLINE, ParseInline, null,
"BLINK", VERS_PROPRIETARY, CM_INLINE, ParseInline, null,
"NOBR", VERS_PROPRIETARY, CM_INLINE, ParseInline, null,
"WBR", VERS_PROPRIETARY, (CM_INLINE|CM_EMPTY), null, null,
"MARQUEE", VERS_MICROSOFT, (CM_INLINE|CM_EMPTY), null, null,
"EMBED", VERS_NETSCAPE, (CM_INLINE|CM_EMPTY), null, null,
"SPACER", VERS_NETSCAPE, (CM_INLINE|CM_EMPTY), null, null,
"MAP", VERS_FROM32, CM_INLINE, ParseBlock, null,
"AREA", VERS_ALL, (CM_BLOCK|CM_EMPTY), null, CheckAREA,
"INPUT", VERS_ALL, (CM_INLINE|CM_IMG|CM_EMPTY), null, null,
"SELECT", VERS_ALL, (CM_INLINE|CM_FIELD), ParseSelect, null,
"OPTION", VERS_ALL, (CM_FIELD|CM_OPT), ParseText, null,
"OPTGROUP", VERS_HTML40, (CM_FIELD|CM_OPT), ParseOptGroup, null,
"TEXTAREA", VERS_ALL, (CM_INLINE|CM_FIELD), ParseText, null,
"LABEL", VERS_HTML40, CM_INLINE, ParseInline, null,
"LEGEND", VERS_HTML40, CM_INLINE, ParseInline, null,
"BUTTON", VERS_HTML40, CM_INLINE, ParseInline, null,
"BASEFONT", VERS_LOOSE, (CM_INLINE|CM_EMPTY), null, null,
"FONT", VERS_LOOSE, CM_INLINE, ParseInline, null,
"BDO", VERS_HTML40, CM_INLINE, ParseInline, null,
/* this must be the final entry */
null, 0, 0, 0, 0
};
/* choose what version to use for new doctype */
int HTMLVersion(Lexer *lexer)
{
uint versions;
versions = lexer->versions;
if (versions & VERS_HTML20)
return VERS_HTML20;
if (versions & VERS_HTML32)
return VERS_HTML32;
if (versions & VERS_HTML40_STRICT)
return VERS_HTML40_STRICT;
if (versions & VERS_HTML40_LOOSE)
return VERS_HTML40_LOOSE;
if (versions & VERS_FRAMES)
return VERS_FRAMES;
return VERS_UNKNOWN;
}
static unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31*hashval;
return hashval % HASHSIZE;
}
static Dict *lookup(char *s)
{
Dict *np;
for (np = hashtab[hash(s)]; np != null; np = np->next)
if (wstrcmp(s, np->name) == 0)
return np;
return null;
}
static Dict *install(char *name, uint versions, uint model,
Parser *parser, CheckAttribs *chkattrs)
{
Dict *np;
unsigned hashval;
if ((np = lookup(name)) == null)
{
np = (Dict *)MemAlloc(sizeof(*np));
if (np == null || (np->name = wstrdup(name)) == null)
return null;
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval] = np;
}
np->versions = versions;
np->model = model;
np->parser = parser;
np->chkattrs = chkattrs;
return np;
}
/* public interface for finding tag by name */
Bool FindTag(Node *node)
{
Dict *np;
if (node->element && (np = lookup(node->element)))
{
node->tag = np;
return yes;
}
if (XmlTags)
{
node->tag = xml_tags;
return yes;
}
return no;
}
void DefineInlineTag(char *name)
{
install(name, VERS_PROPRIETARY, (CM_INLINE|CM_NO_INDENT|CM_NEW), ParseBlock, null);
}
void DefineBlockTag(char *name)
{
install(name, VERS_PROPRIETARY, (CM_BLOCK|CM_NO_INDENT|CM_NEW), ParseBlock, null);
}
void InitTags(void)
{
struct tag *tp;
for(tp = tags; tp->name != null; ++tp)
install(tp->name, tp->versions, tp->model, tp->parser, tp->chkattrs);
tag_html = lookup("HTML");
tag_head = lookup("HEAD");
tag_body = lookup("BODY");
tag_frameset = lookup("FRAMESET");
tag_noframes = lookup("NOFRAMES");
tag_title = lookup("TITLE");
tag_hr = lookup("HR");
tag_pre = lookup("PRE");
tag_listing = lookup("LISTING");
tag_h1 = lookup("H1");
tag_h2 = lookup("H2");
tag_p = lookup("P");
tag_ul = lookup("UL");
tag_ol = lookup("OL");
tag_dir = lookup("DIR");
tag_li = lookup("LI");
tag_dt = lookup("DT");
tag_dd = lookup("DD");
tag_td = lookup("TD");
tag_th = lookup("TH");
tag_tr = lookup("TR");
tag_col = lookup("COL");
tag_br = lookup("BR");
tag_a = lookup("A");
tag_link = lookup("LINK");
tag_b = lookup("B");
tag_i = lookup("I");
tag_param = lookup("PARAM");
tag_option = lookup("OPTION");
tag_optgroup = lookup("OPTGROUP");
tag_map = lookup("MAP");
tag_area = lookup("AREA");
tag_nobr = lookup("NOBR");
tag_wbr = lookup("WBR");
tag_font = lookup("FONT");
tag_spacer = lookup("SPACER");
tag_layer = lookup("LAYER");
tag_center = lookup("CENTER");
tag_style = lookup("STYLE");
tag_script = lookup("SCRIPT");
tag_noscript = lookup("NOSCRIPT");
tag_table = lookup("TABLE");
tag_caption = lookup("CAPTION");
tag_form = lookup("FORM");
tag_blockquote = lookup("BLOCKQUOTE");
tag_div = lookup("DIV");
tag_span = lookup("SPAN");
/* create dummy entry for all xml tags */
xml_tags = (Dict *)MemAlloc(sizeof(*xml_tags));
xml_tags->name = null;
xml_tags->versions = VERS_ALL;
xml_tags->model = CM_BLOCK;
xml_tags->parser = null;
xml_tags->chkattrs = null;
}
void FreeTags(void)
{
Dict *prev, *next;
int i;
MemFree(xml_tags);
for (i = 0; i < HASHSIZE; ++i)
{
prev = null;
next = hashtab[i];
while(next)
{
prev = next->next;
MemFree(next);
next = prev;
}
}
}