home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / tidy26jul99 / attrs.c next >
Encoding:
C/C++ Source or Header  |  1999-12-08  |  21.6 KB  |  662 lines

  1. /* attrs.c -- recognize HTML attributes
  2.  
  3.   (c) 1998 (W3C) MIT, INRIA, Keio University
  4.   See tidy.c for the copyright notice.
  5. */
  6.  
  7. #include "platform.h"   /* platform independent stuff */
  8. #include "html.h"       /* to pull in definition of nodes */
  9.  
  10. Attribute *attr_href;
  11. Attribute *attr_src;
  12. Attribute *attr_id;
  13. Attribute *attr_name;
  14. Attribute *attr_summary;
  15. Attribute *attr_alt;
  16. Attribute *attr_longdesc;
  17. Attribute *attr_usemap;
  18. Attribute *attr_ismap;
  19. Attribute *attr_language;
  20. Attribute *attr_type;
  21. Attribute *attr_value;
  22. Attribute *attr_content;
  23. Attribute *attr_title;
  24. Attribute *attr_xmlns;
  25.  
  26. AttrCheck CheckUrl;
  27. AttrCheck CheckScript;
  28. AttrCheck CheckName;
  29. AttrCheck CheckId;
  30. AttrCheck CheckAlign;
  31. AttrCheck CheckValign;
  32. AttrCheck CheckBool;
  33.  
  34. extern Bool XmlTags;
  35. extern Bool XmlOut;
  36.  
  37.  
  38. #define HASHSIZE 101
  39.  
  40. static Attribute *hashtab[HASHSIZE];
  41.  
  42. /*
  43.  Bind attribute types to procedures to check values.
  44.  You can add new procedures for better validation
  45.  and each procedure has access to the node in which
  46.  the attribute occurred as well as the attribute name
  47.  and its value.
  48.  
  49.  By default, attributes are checked without regard
  50.  to the element they are found on. You have the choice
  51.  of making the procedure test which element is involved
  52.  or in writing methods for each element which controls
  53.  exactly how the attributes of that element are checked.
  54.  This latter approach is best for detecting the absence
  55.  of required attributes.
  56. */
  57.  
  58. #define TEXT        null
  59. #define CHARSET     null
  60. #define TYPE        null
  61. #define CHARACTER   null
  62. #define URLS        null
  63. #define URL         CheckUrl
  64. #define SCRIPT      CheckScript
  65. #define ALIGN       CheckAlign
  66. #define VALIGN      CheckValign
  67. #define COLOR       null
  68. #define CLEAR       null
  69. #define BORDER      CheckBool     /* kludge */
  70. #define LENGTH      null
  71. #define CHARSET     null
  72. #define LANG        null
  73. #define BOOL        CheckBool
  74. #define COLS        null
  75. #define NUMBER      null
  76. #define LENGTH      null
  77. #define COORDS      null
  78. #define DATE        null
  79. #define TEXTDIR     null
  80. #define IDREFS      null
  81. #define IDREF       null
  82. #define IDDEF       CheckId
  83. #define NAME        CheckName
  84. #define TFRAME      null
  85. #define FBORDER     null
  86. #define MEDIA       null
  87. #define FSUBMIT     null
  88. #define LINKTYPES   null
  89. #define TRULES      null
  90. #define SCOPE       null
  91. #define SHAPE       null
  92. #define SCROLL      null
  93. #define TARGET      null
  94. #define VTYPE       null
  95.  
  96. static struct _attrlist
  97. {
  98.     char *name;
  99.     unsigned versions;
  100.     AttrCheck *attrchk;
  101. } attrlist[] =
  102. {
  103.     "abbr",             VERS_HTML40,            TEXT,
  104.     "accept-charset",   VERS_HTML40,            CHARSET,
  105.     "accept",           VERS_ALL,               TYPE,
  106.     "accesskey",        VERS_HTML40,            CHARACTER,
  107.     "action",           VERS_ALL,               URL,
  108.     "add_date",         VERS_NETSCAPE,          TEXT,     /* A */
  109.     "align",            VERS_ALL,               ALIGN,    /* set varies with element */
  110.     "alink",            VERS_LOOSE,             COLOR,
  111.     "alt",              VERS_ALL,               TEXT,
  112.     "archive",          VERS_HTML40,            URLS,     /* space or comma separated list */
  113.     "axis",             VERS_HTML40,            TEXT,
  114.     "background",       VERS_LOOSE,             URL,
  115.     "bgcolor",          VERS_LOOSE,             COLOR,
  116.     "border",           VERS_ALL,               BORDER,   /* like LENGTH + "border" */
  117.     "cellpadding",      VERS_FROM32,            LENGTH,   /* % or pixel values */
  118.     "cellspacing",      VERS_FROM32,            LENGTH,
  119.     "charoff",          VERS_HTML40,            LENGTH,
  120.     "charset",          VERS_HTML40,            CHARSET,
  121.     "checked",          VERS_ALL,               BOOL,     /* i.e. "checked" or absent */
  122.     "cite",             VERS_HTML40,            URL,
  123.     "class",            VERS_HTML40,            TEXT,
  124.     "classid",          VERS_HTML40,            URL,
  125.     "clear",            VERS_LOOSE,             CLEAR,    /* BR: left, right, all */
  126.     "code",             VERS_LOOSE,             TEXT,     /* APPLET */
  127.     "codebase",         VERS_HTML40,            URL,      /* OBJECT */
  128.     "codetype",         VERS_HTML40,            TYPE,     /* OBJECT */
  129.     "color",            VERS_LOOSE,             COLOR,    /* BASEFONT, FONT */
  130.     "cols",             VERS_IFRAMES,           COLS,     /* TABLE & FRAMESET */
  131.     "colspan",          VERS_FROM32,            NUMBER,
  132.     "compact",          VERS_ALL,               BOOL,     /* lists */
  133.     "content",          VERS_ALL,               TEXT,     /* META */
  134.     "coords",           VERS_FROM32,            COORDS,   /* AREA, A */    
  135.     "data",             VERS_HTML40,            URL,      /* OBJECT */
  136.     "datetime",         VERS_HTML40,            DATE,     /* INS, DEL */
  137.     "declare",          VERS_HTML40,            BOOL,     /* OBJECT */
  138.     "defer",            VERS_HTML40,            BOOL,     /* SCRIPT */
  139.     "dir",              VERS_HTML40,            TEXTDIR,  /* ltr or rtl */
  140.     "disabled",         VERS_HTML40,            BOOL,     /* form fields */
  141.     "enctype",          VERS_ALL,               TYPE,     /* FORM */
  142.     "face",             VERS_LOOSE,             TEXT,     /* BASEFONT, FONT */
  143.     "for",              VERS_HTML40,            IDREF,    /* LABEL */
  144.     "frame",            VERS_HTML40,            TFRAME,   /* TABLE */
  145.     "frameborder",      VERS_FRAMES,            FBORDER,  /* 0 or 1 */
  146.     "headers",          VERS_HTML40,            IDREFS,   /* table cells */
  147.     "height",           VERS_ALL,               LENGTH,   /* pixels only for TH/TD */
  148.     "href",             VERS_ALL,               URL,      /* A, AREA, LINK and BASE */
  149.     "hreflang",         VERS_HTML40,            LANG,     /* A, LINK */
  150.     "hspace",           VERS_ALL,               NUMBER,   /* APPLET, IMG, OBJECT */
  151.     "http-equiv",       VERS_ALL,               TEXT,     /* META */
  152.     "id",               VERS_HTML40,            IDDEF,
  153.     "ismap",            VERS_ALL,               BOOL,     /* IMG */
  154.     "label",            VERS_HTML40,            TEXT,     /* OPT, OPTGROUP */
  155.     "lang",             VERS_HTML40,            LANG,
  156.     "language",         VERS_LOOSE,             TEXT,     /* SCRIPT */
  157.     "last_modified",    VERS_NETSCAPE,          TEXT,     /* A */
  158.     "last_visit",       VERS_NETSCAPE,          TEXT,     /* A */
  159.     "leftmargin",       VERS_MICROSOFT,         NUMBER,   /* used on BODY */
  160.     "link",             VERS_LOOSE,             COLOR,    /* BODY */
  161.     "longdesc",         VERS_HTML40,            URL,      /* IMG */
  162.     "marginheight",     VERS_IFRAMES,           NUMBER,   /* FRAME, IFRAME, BODY */
  163.     "marginwidth",      VERS_IFRAMES,           NUMBER,   /* ditto */
  164.     "maxlength",        VERS_ALL,               NUMBER,   /* INPUT */
  165.     "media",            VERS_HTML40,            MEDIA,    /* STYLE, LINK */
  166.     "method",           VERS_ALL,               FSUBMIT,  /* FORM: get or post */
  167.     "multiple",         VERS_ALL,               BOOL,     /* SELECT */
  168.     "name",             VERS_ALL,               NAME,
  169.     "nohref",           VERS_FROM32,            BOOL,     /* AREA */
  170.     "noresize",         VERS_FRAMES,            BOOL,     /* FRAME */
  171.     "noshade",          VERS_LOOSE,             BOOL,     /* HR */
  172.     "nowrap",           VERS_LOOSE,             BOOL,     /* table cells */
  173.     "object",           VERS_HTML40_LOOSE,      TEXT,     /* APPLET */
  174.     "onblur",           VERS_HTML40,            SCRIPT,   /* event */
  175.     "onchange",         VERS_HTML40,            SCRIPT,   /* event */
  176.     "onclick",          VERS_HTML40,            SCRIPT,   /* event */
  177.     "ondblclick",       VERS_HTML40,            SCRIPT,   /* event */
  178.     "onkeydown",        VERS_HTML40,            SCRIPT,   /* event */
  179.     "onkeypress",       VERS_HTML40,            SCRIPT,   /* event */
  180.     "onkeyup",          VERS_HTML40,            SCRIPT,   /* event */
  181.     "onload",           VERS_HTML40,            SCRIPT,   /* event */
  182.     "onmousedown",      VERS_HTML40,            SCRIPT,   /* event */
  183.     "onmousemove",      VERS_HTML40,            SCRIPT,   /* event */
  184.     "onmouseout",       VERS_HTML40,            SCRIPT,   /* event */
  185.     "onmouseover",      VERS_HTML40,            SCRIPT,   /* event */
  186.     "onmouseup",        VERS_HTML40,            SCRIPT,   /* event */
  187.     "onsubmit",         VERS_HTML40,            SCRIPT,   /* event */
  188.     "onreset",          VERS_HTML40,            SCRIPT,   /* event */
  189.     "onselect",         VERS_HTML40,            SCRIPT,   /* event */
  190.     "onunload",         VERS_HTML40,            SCRIPT,   /* event */
  191.     "profile",          VERS_HTML40,            URL,      /* HEAD */
  192.     "prompt",           VERS_LOOSE,             TEXT,     /* ISINDEX */
  193.     "readonly",         VERS_HTML40,            BOOL,     /* form fields */
  194.     "rel",              VERS_ALL,               LINKTYPES, /* A, LINK */
  195.     "rev",              VERS_ALL,               LINKTYPES, /* A, LINK */
  196.     "rows",             VERS_ALL,               NUMBER,   /* TEXTAREA */
  197.     "rowspan",          VERS_ALL,               NUMBER,   /* table cells */
  198.     "rules",            VERS_HTML40,            TRULES,   /* TABLE */
  199.     "scheme",           VERS_HTML40,            TEXT,     /* META */
  200.     "scope",            VERS_HTML40,            SCOPE,    /* table cells */
  201.     "scrolling",        VERS_IFRAMES,           SCROLL,   /* yes, no or auto */
  202.     "selected",         VERS_ALL,               BOOL,     /* OPTION */
  203.     "shape",            VERS_FROM32,            SHAPE,    /* AREA, A */
  204.     "size",             VERS_LOOSE,             NUMBER,   /* HR, FONT, BASEFONT, SELECT */
  205.     "span",             VERS_HTML40,            NUMBER,   /* COL, COLGROUP */
  206.     "src",              (VERS_ALL|VERS_FRAMES), URL,      /* IMG, FRAME, IFRAME */
  207.     "standby",          VERS_HTML40,            TEXT,     /* OBJECT */
  208.     "start",            VERS_ALL,               NUMBER,   /* OL */
  209.     "style",            VERS_HTML40,            TEXT,
  210.     "summary",          VERS_HTML40,            TEXT,     /* TABLE */
  211.     "tabindex",         VERS_HTML40,            NUMBER,   /* fields, OBJECT  and A */
  212.     "target",           VERS_HTML40,            TARGET,   /* names a frame/window */
  213.     "text",             VERS_LOOSE,             COLOR,    /* BODY */
  214.     "title",            VERS_HTML40,            TEXT,     /* text tool tip */
  215.     "topmargin",        VERS_MICROSOFT,         NUMBER,   /* used on BODY */
  216.     "type",             VERS_FROM32,            TYPE,
  217.     "usemap",           VERS_ALL,               BOOL,     /* things with images */
  218.     "valign",           VERS_FROM32,            VALIGN,
  219.     "value",            VERS_ALL,               TEXT,     /* OPTION, PARAM */
  220.     "valuetype",        VERS_HTML40,            VTYPE,    /* PARAM: data, ref, object */
  221.     "version",          VERS_ALL,               TEXT,     /* HTML */
  222.     "vlink",            VERS_LOOSE,             COLOR,    /* BODY */
  223.     "vspace",           VERS_LOOSE,             NUMBER,   /* IMG, OBJECT, APPLET */
  224.     "width",            VERS_ALL,               LENGTH,   /* pixels only for TD/TH */
  225.     "xml-lang",         VERS_XML,               TEXT,     /* XML language */
  226.     "xmlns",            VERS_ALL,               TEXT,     /* name space */
  227.    
  228.    /* this must be the final entry */
  229.     null,               0,                      0
  230. };
  231.  
  232. static unsigned hash(char *s)
  233. {
  234.     unsigned hashval;
  235.  
  236.     for (hashval = 0; *s != '\0'; s++)
  237.         hashval = *s + 31*hashval;
  238.  
  239.     return hashval % HASHSIZE;
  240. }
  241.  
  242. static Attribute *lookup(char *s)
  243. {
  244.     Attribute *np;
  245.  
  246.     for (np = hashtab[hash(s)]; np != null; np = np->next)
  247.         if (wstrcmp(s, np->name) == 0)
  248.             return np;
  249.     return null;
  250. }
  251.  
  252. static Attribute *install(char *name, uint versions, AttrCheck *attrchk)
  253. {
  254.     Attribute *np;
  255.     unsigned hashval;
  256.  
  257.     if ((np = lookup(name)) == null)
  258.     {
  259.         np = (Attribute *)MemAlloc(sizeof(*np));
  260.  
  261.         if (np == null || (np->name = wstrdup(name)) == null)
  262.             return null;
  263.  
  264.         hashval = hash(name);
  265.         np->next = hashtab[hashval];
  266.         hashtab[hashval] = np;
  267.     }
  268.  
  269.     np->versions = versions;
  270.     np->attrchk = attrchk;
  271.     np->nowrap = no;
  272.     return np;
  273. }
  274.  
  275. void SetNoWrap(Attribute *attr)
  276. {
  277.     attr->nowrap = yes;  /* defaults to no */
  278. }
  279.  
  280. /* public method for finding attribute definition by name */
  281. Attribute *FindAttribute(AttVal *attval)
  282. {
  283.     Attribute *np;
  284.  
  285.     if (attval->attribute && (np = lookup(attval->attribute)))
  286.         return np;
  287.  
  288.     return null;
  289. }
  290.  
  291. Bool IsUrl(char *attrname)
  292. {
  293.     Attribute *np;
  294.  
  295.     return (Bool)((np = lookup(attrname)) && np->attrchk == URL);
  296. }
  297.  
  298. Bool IsScript(char *attrname)
  299. {
  300.     Attribute *np;
  301.  
  302.     return (Bool)((np = lookup(attrname)) && np->attrchk == SCRIPT);
  303. }
  304.  
  305. /* public method for inititializing attribute dictionary */
  306. void InitAttrs(void)
  307. {
  308.     struct _attrlist *ap;
  309.     
  310.     for(ap = attrlist; ap->name != null; ++ap)
  311.         install(ap->name, ap->versions, ap->attrchk);
  312.  
  313.     attr_href = lookup("href");
  314.     attr_src = lookup("src");
  315.     attr_id = lookup("id");
  316.     attr_name = lookup("name");
  317.     attr_summary = lookup("summary");
  318.     attr_alt = lookup("alt");
  319.     attr_longdesc = lookup("longdesc");
  320.     attr_usemap = lookup("usemap");
  321.     attr_ismap = lookup("ismap");
  322.     attr_language = lookup("language");
  323.     attr_type = lookup("type");
  324.     attr_title = lookup("title");
  325.     attr_xmlns = lookup("xmlns");
  326.     attr_value = lookup("value");
  327.     attr_content = lookup("content");
  328.  
  329.     SetNoWrap(attr_alt);
  330.     SetNoWrap(attr_value);
  331.     SetNoWrap(attr_content);
  332. }
  333.  
  334. void FreeAttrTable(void)
  335. {
  336.     Attribute *dict, *next;
  337.     int i;
  338.  
  339.     for (i = 0; i < HASHSIZE; ++i)
  340.     {
  341.         dict = hashtab[i];
  342.  
  343.         while(dict)
  344.         {
  345.             next = dict->next;
  346.             MemFree(dict->name);
  347.             MemFree(dict);
  348.             dict = next;
  349.         }
  350.     }
  351. }
  352.  
  353. /* ignore unknown attributes for proprietary elements */
  354. Attribute *CheckAttribute(Lexer *lexer, Node *node, AttVal *attval)
  355. {
  356.     Attribute *attribute;
  357.  
  358.     if ((attribute = attval->dict) != null)
  359.     {
  360.         /* title is vers 2.0 for A and LINK otherwise vers 4.0 */
  361.         if (attribute == attr_title &&
  362.                 (node->tag == tag_a || node->tag == tag_link))
  363.                 lexer->versions &= VERS_ALL;
  364.         else if (attribute->versions & VERS_XML)
  365.         {
  366.             if (!(XmlTags || XmlOut))
  367.                 ReportAttrError(lexer, node, attval->attribute, XML_ATTRIBUTE_VALUE);
  368.         }
  369.         else
  370.             lexer->versions &= attribute->versions;
  371.         
  372.         if (attribute->attrchk)
  373.             attribute->attrchk(lexer, node, attval);
  374.     }
  375.     else if (!XmlTags && !(node->tag == null) && attval->asp == null &&
  376.              !(node->tag && (node->tag->versions & VERS_PROPRIETARY)))
  377.         ReportAttrError(lexer, node, attval->attribute, UNKNOWN_ATTRIBUTE);
  378.  
  379.     return attribute;
  380. }
  381.  
  382. Bool IsBoolAttribute(AttVal *attval)
  383. {
  384.     Attribute *attribute;
  385.  
  386.     if ((attribute = attval->dict) != null)
  387.     {
  388.         if (attribute->attrchk == CheckBool)
  389.             return yes;
  390.     }
  391.  
  392.     return no;
  393. }
  394.  
  395. /* methods for checking value of a specific attribute */
  396.  
  397. void CheckUrl(Lexer *lexer, Node *node, AttVal *attval)
  398. {
  399.     char c, *p = attval->value;
  400.  
  401.     if (FixBackslash)
  402.     {
  403.         while (c = *p)
  404.         {
  405.             if (c =='\\')
  406.                 *p = '/';
  407.  
  408.             ++p;
  409.         }
  410.     }
  411. }
  412.  
  413. void CheckScript(Lexer *lexer, Node *node, AttVal *attval)
  414. {
  415. }
  416.  
  417. void CheckName(Lexer *lexer, Node *node, AttVal *attval)
  418. {
  419. }
  420.  
  421. void CheckId(Lexer *lexer, Node *node, AttVal *attval)
  422. {
  423. }
  424.  
  425. void CheckBool(Lexer *lexer, Node *node, AttVal *attval)
  426. {
  427. }
  428.  
  429. void CheckAlign(Lexer *lexer, Node *node, AttVal *attval)
  430. {
  431.     char *value;
  432.  
  433.     /* IMG, OBJECT, APPLET and EMBED use align for vertical position */
  434.     if (node->tag && (node->tag->model & CM_IMG))
  435.     {
  436.         CheckValign(lexer, node, attval);
  437.         return;
  438.     }
  439.  
  440.     value = attval->value;
  441.  
  442.     if (value == null)
  443.         ReportAttrError(lexer, node, attval->attribute, MISSING_ATTR_VALUE);
  444.     else if (! (wstrcasecmp(value, "left") == 0 ||
  445.                 wstrcasecmp(value, "center") == 0 ||
  446.                 wstrcasecmp(value, "right") == 0 ||
  447.                 wstrcasecmp(value, "justify") == 0))
  448.           ReportAttrError(lexer, node, attval->value, BAD_ATTRIBUTE_VALUE);
  449. }
  450.  
  451. void CheckValign(Lexer *lexer, Node *node, AttVal *attval)
  452. {
  453.     char *value;
  454.  
  455.     value = attval->value;
  456.  
  457.     if (value == null)
  458.         ReportAttrError(lexer, node, attval->attribute, MISSING_ATTR_VALUE);
  459.     else if (wstrcasecmp(value, "top") == 0 ||
  460.            wstrcasecmp(value, "middle") == 0 ||
  461.            wstrcasecmp(value, "bottom") == 0 ||
  462.           wstrcasecmp(value, "baseline") == 0)
  463.     {
  464.         /* all is fine */
  465.     }
  466.     else if (wstrcasecmp(value, "left") == 0 ||
  467.               wstrcasecmp(value, "right") == 0)
  468.     {
  469.         if (!(node->tag && (node->tag->model & CM_IMG)))
  470.             ReportAttrError(lexer, node, attval->value, BAD_ATTRIBUTE_VALUE);
  471.     }
  472.     else if (wstrcasecmp(value, "texttop") == 0 ||
  473.            wstrcasecmp(value, "absmiddle") == 0 ||
  474.            wstrcasecmp(value, "textbottom") == 0)
  475.     {
  476.         lexer->versions &= VERS_PROPRIETARY;
  477.         ReportAttrError(lexer, node, attval->value, PROPRIETARY_ATTR_VALUE);
  478.     }
  479.     else
  480.           ReportAttrError(lexer, node, attval->value, BAD_ATTRIBUTE_VALUE);
  481. }
  482.  
  483.  
  484. /* default method for checking an element's attributes */
  485. void CheckAttributes(Lexer *lexer, Node *node)
  486. {
  487.     AttVal *attval;
  488.  
  489.     for (attval = node->attributes; attval != null; attval = attval->next)
  490.         CheckAttribute(lexer, node, attval);
  491. }
  492.  
  493. /* methods for checking attributes for specific elements */
  494.  
  495. void CheckIMG(Lexer *lexer, Node *node)
  496. {
  497.     AttVal *attval;
  498.     Attribute *attribute;
  499.     Bool HasAlt = no;
  500.     Bool HasSrc = no;
  501.     Bool HasUseMap = no;
  502.     Bool HasIsMap = no;
  503.  
  504.     for (attval = node->attributes; attval != null; attval = attval->next)
  505.     {
  506.         attribute = CheckAttribute(lexer, node, attval);
  507.  
  508.         if (attribute == attr_alt)
  509.             HasAlt = yes;
  510.         else if (attribute == attr_src)
  511.             HasSrc = yes;
  512.         else if (attribute == attr_usemap)
  513.             HasUseMap = yes;
  514.         else if (attribute == attr_ismap)
  515.             HasIsMap = yes;
  516.     }
  517.  
  518.     if (!HasAlt)
  519.     {
  520.         lexer->badAccess |= MISSING_IMAGE_ALT;
  521.         ReportAttrError(lexer, node, "alt", MISSING_ATTRIBUTE);
  522.     }
  523.  
  524.     if (!HasSrc)
  525.         ReportAttrError(lexer, node, "src", MISSING_ATTRIBUTE);
  526.  
  527.     if (HasIsMap && !HasUseMap)
  528.         ReportAttrError(lexer, node, "ismap", MISSING_IMAGEMAP);
  529. }
  530.  
  531. void CheckCaption(Lexer *lexer, Node *node)
  532. {
  533.     AttVal *attval;
  534.     char *value = null;
  535.  
  536.     for (attval = node->attributes; attval != null; attval = attval->next)
  537.     {
  538.         if (wstrcasecmp(attval->attribute, "align") == 0)
  539.         {
  540.             value = attval->value;
  541.             break;
  542.         }
  543.     }
  544.  
  545.     if (value != null)
  546.     {
  547.         if (wstrcasecmp(value, "left") == 0 || wstrcasecmp(value, "right") == 0)
  548.             lexer->versions &= (VERS_HTML40_LOOSE|VERS_FRAMES);
  549.         else if (wstrcasecmp(value, "top") == 0 || wstrcasecmp(value, "bottom") == 0)
  550.             lexer->versions &= VERS_FROM32;
  551.         else
  552.             ReportAttrError(lexer, node, value, BAD_ATTRIBUTE_VALUE);
  553.     }
  554. }
  555.  
  556. void CheckHTML(Lexer *lexer, Node *node)
  557. {
  558.     AttVal *attval;
  559.     Attribute *attribute;
  560.  
  561.     for (attval = node->attributes; attval != null; attval = attval->next)
  562.     {
  563.         attribute = CheckAttribute(lexer, node, attval);
  564.  
  565.         if (attribute == attr_xmlns)
  566.             lexer->isvoyager = yes;
  567.     }
  568. }
  569.  
  570. void CheckAREA(Lexer *lexer, Node *node)
  571. {
  572.     AttVal *attval;
  573.     Attribute *attribute;
  574.     Bool HasAlt = no;
  575.     Bool HasHref = no;
  576.  
  577.     for (attval = node->attributes; attval != null; attval = attval->next)
  578.     {
  579.         attribute = CheckAttribute(lexer, node, attval);
  580.  
  581.         if (attribute == attr_alt)
  582.             HasAlt = yes;
  583.         else if (attribute == attr_href)
  584.             HasHref = yes;
  585.     }
  586.  
  587.     if (!HasAlt)
  588.     {
  589.         lexer->badAccess |= MISSING_LINK_ALT;
  590.         ReportAttrError(lexer, node, "alt", MISSING_ATTRIBUTE);
  591.     }
  592.     if (!HasHref)
  593.         ReportAttrError(lexer, node, "href", MISSING_ATTRIBUTE);
  594. }
  595.  
  596. void CheckTABLE(Lexer *lexer, Node *node)
  597. {
  598.     AttVal *attval;
  599.     Attribute *attribute;
  600.     Bool HasSummary = no;
  601.  
  602.     for (attval = node->attributes; attval != null; attval = attval->next)
  603.     {
  604.         attribute = CheckAttribute(lexer, node, attval);
  605.  
  606.         if (attribute == attr_summary)
  607.             HasSummary = yes;
  608.     }
  609.  
  610.     /* suppress warning for missing summary for HTML 2.0 and HTML 3.2 */
  611.     if (!HasSummary && lexer->doctype != VERS_HTML20 && lexer->doctype != VERS_HTML32)
  612.     {
  613.         lexer->badAccess |= MISSING_SUMMARY;
  614.         ReportAttrError(lexer, node, "summary", MISSING_ATTRIBUTE);
  615.     }
  616. }
  617.  
  618. /* add missing type attribute when appropriate */
  619. void CheckSCRIPT(Lexer *lexer, Node *node)
  620. {
  621.     Attribute *attribute;
  622.     AttVal *attval, *lang, *type;
  623.     char buf[16];
  624.  
  625.     lang = type = null;
  626.  
  627.     for (attval = node->attributes; attval != null; attval = attval->next)
  628.     {
  629.         attribute = CheckAttribute(lexer, node, attval);
  630.  
  631.         if (attribute == attr_language)
  632.             lang = attval;
  633.         else if (attribute == attr_type)
  634.             type = attval;
  635.     }
  636.  
  637.     if (!type)
  638.     {
  639.         ReportAttrError(lexer, node, "type", MISSING_ATTRIBUTE);
  640.  
  641.         /* check for javascript */
  642.  
  643.         if (lang)
  644.         {
  645.             wstrncpy(buf, lang->value, 10);
  646.             buf[10] = '\0';
  647.  
  648.             if ( (wstrcasecmp(buf, "javascript") == 0) ||
  649.                  (wstrcasecmp(buf, "jscript") == 0) )
  650.             {
  651.                 type = (AttVal *)MemAlloc(sizeof(AttVal));
  652.                 type->attribute = wstrdup("type");
  653.                 type->value = wstrdup("text/javascript");
  654.                 type->next = node->attributes;
  655.                 type->delim = '"';
  656.                 type->dict = FindAttribute(type);
  657.                 node->attributes = type;
  658.             }
  659.         }
  660.     }
  661. }
  662.