/* 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; } } }