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

TidyLib
tidy/src/localize.c

Version: ~ [ 1.0 ] ~

  1 /* localize.c -- text strings and routines to handle errors and general messages
  2 
  3   (c) 1998-2005 (W3C) MIT, ERCIM, Keio University
  4   Portions Copyright University of Toronto
  5   See tidy.h and access.h for the copyright notice.
  6 
  7   You should only need to edit this file and tidy.c
  8   to localize HTML tidy. *** This needs checking ***
  9   
 10   CVS Info :
 11 
 12     $Author: arnaud02 $ 
 13     $Date: 2005/10/25 15:57:27 $ 
 14     $Revision: 1.145 $ 
 15 
 16 */
 17 
 18 #include "tidy-int.h"
 19 #include "lexer.h"
 20 #include "streamio.h"
 21 #include "message.h"
 22 #include "tmbstr.h"
 23 #include "utf8.h"
 24 
 25 /* used to point to Web Accessibility Guidelines */
 26 #define ACCESS_URL  "http://www.w3.org/WAI/GL"
 27 
 28 /* points to the Adaptive Technology Resource Centre at the
 29 ** University of Toronto
 30 */
 31 #define ATRC_ACCESS_URL  "http://www.aprompt.ca/Tidy/accessibilitychecks.html"
 32 
 33 static const char release_date[] = "1 September 2005";
 34 
 35 ctmbstr ReleaseDate(void)
 36 {
 37   return release_date;
 38 }
 39 
 40 static struct _msgfmt
 41 {
 42     uint code;
 43     ctmbstr fmt;
 44 } const msgFormat[] = 
 45 {
 46 /* ReportEncodingWarning */
 47   { ENCODING_MISMATCH,            "specified input encoding (%s) does not match actual input encoding (%s)" }, /* Warning */
 48 
 49 /* ReportEncodingError */
 50   { VENDOR_SPECIFIC_CHARS,        "%s invalid character code %s"                                            }, /* Error */
 51   { INVALID_SGML_CHARS,           "%s invalid character code %s"                                            }, /* Error */
 52   { INVALID_UTF8,                 "%s invalid UTF-8 bytes (char. code %s)"                                  }, /* Error */
 53   { INVALID_UTF16,                "%s invalid UTF-16 surrogate pair (char. code %s)"                        }, /* Error */
 54   { INVALID_NCR,                  "%s invalid numeric character reference %s"                               }, /* Error */
 55 
 56 /* ReportEntityError */
 57   { MISSING_SEMICOLON,            "entity \"%s\" doesn't end in ';'"                                        }, /* Warning in HTML, Error in XML/XHTML */
 58   { MISSING_SEMICOLON_NCR,        "numeric character reference \"%s\" doesn't end in ';'"                   }, /* Warning in HTML, Error in XML/XHTML */
 59   { UNESCAPED_AMPERSAND,          "unescaped & which should be written as &"                            }, /* Warning in HTML, Error in XHTML */
 60   { UNKNOWN_ENTITY,               "unescaped & or unknown entity \"%s\""                                    }, /* Error */
 61   { APOS_UNDEFINED,               "named entity ' only defined in XML/XHTML"                           }, /* Error in HTML (should only occur for HTML input) */
 62 
 63 /* ReportAttrError */
 64 
 65   /* attribute name */
 66   { INSERTING_ATTRIBUTE,          "%s inserting \"%s\" attribute"                                           }, /* Warning in CheckLINK, Error otherwise */
 67   { MISSING_ATTR_VALUE,           "%s attribute \"%s\" lacks value"                                         }, /* Warning in CheckUrl, Error otherwise */
 68   { UNKNOWN_ATTRIBUTE,            "%s unknown attribute \"%s\""                                             }, /* Error */
 69   { PROPRIETARY_ATTRIBUTE,        "%s proprietary attribute \"%s\""                                         }, /* Error */
 70   { JOINING_ATTRIBUTE,            "%s joining values of repeated attribute \"%s\""                          }, /* Error */
 71   { XML_ATTRIBUTE_VALUE,          "%s has XML attribute \"%s\""                                             }, /* Error (but deprecated) */
 72 
 73   /* attribute value */
 74   { XML_ID_SYNTAX,                "%s ID \"%s\" uses XML ID syntax"                                         }, /* Warning if XHTML, Error if HTML */
 75   { ATTR_VALUE_NOT_LCASE,         "%s attribute value \"%s\" must be lower case for XHTML"                  }, /* Error if XHTML input, Notice if HTML input and XHTML outout */
 76   { PROPRIETARY_ATTR_VALUE,       "%s proprietary attribute value \"%s\""                                   }, /* Error */
 77   { ANCHOR_NOT_UNIQUE,            "%s anchor \"%s\" already defined"                                        }, /* Error */
 78 
 79   /* attribute name, attribute value */
 80   { BAD_ATTRIBUTE_VALUE,          "%s attribute \"%s\" has invalid value \"%s\""                            }, /* Error */
 81   { BAD_ATTRIBUTE_VALUE_REPLACED, "%s attribute \"%s\" had invalid value \"%s\" and has been replaced"      }, /* Error */
 82   { INVALID_ATTRIBUTE,            "%s attribute name \"%s\" (value=\"%s\") is invalid"                      }, /* Error */
 83 
 84   /* attribute value, attribute name */
 85   { REPEATED_ATTRIBUTE,           "%s dropping value \"%s\" for repeated attribute \"%s\""                  }, /* Error */
 86 
 87   /* no arguments */
 88   { INVALID_XML_ID,               "%s cannot copy name attribute to id"                                     }, /* Warning */
 89   { UNEXPECTED_GT,                "%s missing '>' for end of tag"                                           }, /* Warning if HTML, Error if XML/XHTML */
 90   { UNEXPECTED_QUOTEMARK,         "%s unexpected or duplicate quote mark"                                   }, /* Error */
 91   { MISSING_QUOTEMARK,            "%s attribute with missing trailing quote mark"                           }, /* Error */
 92   { UNEXPECTED_END_OF_FILE_ATTR,  "%s end of file while parsing attributes"                                 }, /* Error */
 93   { ID_NAME_MISMATCH,             "%s id and name attribute value mismatch"                                 }, /* Error */
 94   { BACKSLASH_IN_URI,             "%s URI reference contains backslash. Typo?"                              }, /* Error */
 95   { FIXED_BACKSLASH,              "%s converting backslash in URI to slash"                                 }, /* Error */
 96   { ILLEGAL_URI_REFERENCE,        "%s improperly escaped URI reference"                                     }, /* Error */
 97   { ESCAPED_ILLEGAL_URI,          "%s escaping malformed URI reference"                                     }, /* Error */
 98   { NEWLINE_IN_URI,               "%s discarding newline in URI reference"                                  }, /* Error */
 99   { UNEXPECTED_EQUALSIGN,         "%s unexpected '=', expected attribute name"                              }, /* Error */
100   { MISSING_IMAGEMAP,             "%s should use client-side image map"                                     }, /* Warning (but deprecated) */
101 
102 /* ReportMissingAttr */
103   { MISSING_ATTRIBUTE,            "%s lacks \"%s\" attribute"                                               }, /* Error */
104 /* ReportWarning */
105   { NESTED_EMPHASIS,              "nested emphasis %s"                                                      }, /* Warning */
106   { NESTED_QUOTATION,             "nested q elements, possible typo."                                       }, /* Warning */
107   { OBSOLETE_ELEMENT,             "replacing obsolete element %s by %s"                                     }, /* Warning */
108   { COERCE_TO_ENDTAG_WARN,        "<%s> is probably intended as </%s>"                                      }, /* Warning */
109 
110 /* ReportNotice */
111   { TRIM_EMPTY_ELEMENT,           "trimming empty %s"                                                       }, /* Notice */
112   { REPLACING_ELEMENT,            "replacing %s by %s"                                                      }, /* Notice */
113 
114 /* ReportError */
115   { COERCE_TO_ENDTAG,             "<%s> is probably intended as </%s>"                                      }, /* Error */
116   { REPLACING_UNEX_ELEMENT,       "replacing unexpected %s by %s"                                           }, /* Error */
117   { MISSING_ENDTAG_FOR,           "missing </%s>"                                                           }, /* Error */
118   { MISSING_ENDTAG_BEFORE,        "missing </%s> before %s"                                                 }, /* Error */
119   { DISCARDING_UNEXPECTED,        "discarding unexpected %s"                                                }, /* Error */
120   { NON_MATCHING_ENDTAG,          "replacing unexpected %s by </%s>"                                        }, /* Error */
121   { TAG_NOT_ALLOWED_IN,           "%s isn't allowed in <%s> elements"                                       }, /* Error */
122   { MISSING_STARTTAG,             "missing <%s>"                                                            }, /* Error */
123   { UNEXPECTED_ENDTAG,            "unexpected </%s>"                                                }, /* Error */
124   { TOO_MANY_ELEMENTS,            "too many %s elements"                                            }, /* Error */
125   { USING_BR_INPLACE_OF,          "using <br> in place of %s"                                               }, /* Error */
126   { INSERTING_TAG,                "inserting implicit <%s>"                                                 }, /* Error */
127   { CANT_BE_NESTED,               "%s can't be nested"                                                      }, /* Error */
128   { PROPRIETARY_ELEMENT,          "%s is not approved by W3C"                                               }, /* Error */
129   { ILLEGAL_NESTING,              "%s shouldn't be nested"                                                  }, /* Error */
130   { NOFRAMES_CONTENT,             "%s not inside 'noframes' element"                                        }, /* Error */
131   { UNEXPECTED_END_OF_FILE,       "unexpected end of file %s"                                               }, /* Error */
132   { ELEMENT_NOT_EMPTY,            "%s element not empty or not closed"                                      }, /* Error */
133   { UNEXPECTED_ENDTAG_IN,         "unexpected </%s> in <%s>"                                                }, /* Error */
134   { TOO_MANY_ELEMENTS_IN,         "too many %s elements in <%s>"                                            }, /* Error */
135   { UNESCAPED_ELEMENT,            "unescaped %s in pre content"                                             }, /* Error (but deprecated) */
136 
137   /* no arguments */
138   { DOCTYPE_AFTER_TAGS,           "<!DOCTYPE> isn't allowed after elements"                                 }, /* Error */
139   { MISSING_TITLE_ELEMENT,        "inserting missing 'title' element"                                       }, /* Error */
140   { INCONSISTENT_VERSION,         "HTML DOCTYPE doesn't match content"                                      }, /* Error */
141   { MISSING_DOCTYPE,              "missing <!DOCTYPE> declaration"                                          }, /* Error */
142   { CONTENT_AFTER_BODY,           "content occurs after end of body"                                        }, /* Error */
143   { MALFORMED_COMMENT,            "adjacent hyphens within comment"                                         }, /* Error */
144   { BAD_COMMENT_CHARS,            "expecting -- or >"                                                       }, /* Error */
145   { BAD_CDATA_CONTENT,            "'<' + '/' + letter not allowed here"                                     }, /* Error */
146   { INCONSISTENT_NAMESPACE,       "HTML namespace doesn't match content"                                    }, /* Error */
147   { SPACE_PRECEDING_XMLDECL,      "removing whitespace preceding XML Declaration"                           }, /* Error */
148   { MALFORMED_DOCTYPE,            "discarding malformed <!DOCTYPE>"                                         }, /* Error */
149   { BAD_XML_COMMENT,              "XML comments can't contain --"                                           }, /* Error (but deprecated) */
150   { DTYPE_NOT_UPPER_CASE,         "SYSTEM, PUBLIC, W3C, DTD, EN must be upper case"                         }, /* Error (but deprecated) */
151   { ENCODING_IO_CONFLICT,         "Output encoding does not work with standard output"                      }, /* Error (but deprecated) */
152 
153 /* ReportFatal */
154   { SUSPECTED_MISSING_QUOTE,      "missing quote mark for attribute value"                                  }, /* Error? (not really sometimes) */
155   { DUPLICATE_FRAMESET,           "repeated FRAMESET element"                                               }, /* Error */
156   { UNKNOWN_ELEMENT,              "%s is not recognized!"                                                   }, /* Error */
157   { UNEXPECTED_ENDTAG,            "unexpected </%s>"                                                }, /* Error */
158 
159 #if SUPPORT_ACCESSIBILITY_CHECKS
160 
161 /* ReportAccess */
162 /* 
163     List of error/warning messages.  The error code corresponds to
164     the check that is listed in the AERT (HTML specifications).
165 */
166   { IMG_MISSING_ALT,                               "[1.1.1.1]: <img> missing 'alt' text."                                     }, /* Access */
167   { IMG_ALT_SUSPICIOUS_FILENAME,                   "[1.1.1.2]: suspicious 'alt' text (filename)."                             }, /* Access */
168   { IMG_ALT_SUSPICIOUS_FILE_SIZE,                  "[1.1.1.3]: suspicious 'alt' text (file size)."                            }, /* Access */
169   { IMG_ALT_SUSPICIOUS_PLACEHOLDER,                "[1.1.1.4]: suspicious 'alt' text (placeholder)."                          }, /* Access */
170   { IMG_ALT_SUSPICIOUS_TOO_LONG,                   "[1.1.1.10]: suspicious 'alt' text (too long)."                            }, /* Access */
171   { IMG_MISSING_LONGDESC_DLINK,                    "[1.1.2.1]: <img> missing 'longdesc' and d-link."                          }, /* Access */
172   { IMG_MISSING_DLINK,                             "[1.1.2.2]: <img> missing d-link."                                         }, /* Access */
173   { IMG_MISSING_LONGDESC,                          "[1.1.2.3]: <img> missing 'longdesc'."                                     }, /* Access */
174   { IMG_BUTTON_MISSING_ALT,                        "[1.1.3.1]: <img> (button) missing 'alt' text."                            }, /* Access */
175   { APPLET_MISSING_ALT,                            "[1.1.4.1]: <applet> missing alternate content."                           }, /* Access */
176   { OBJECT_MISSING_ALT,                            "[1.1.5.1]: <object> missing alternate content."                           }, /* Access */
177   { AUDIO_MISSING_TEXT_WAV,                        "[1.1.6.1]: audio missing text transcript (wav)."                          }, /* Access */
178   { AUDIO_MISSING_TEXT_AU,                         "[1.1.6.2]: audio missing text transcript (au)."                           }, /* Access */
179   { AUDIO_MISSING_TEXT_AIFF,                       "[1.1.6.3]: audio missing text transcript (aiff)."                         }, /* Access */
180   { AUDIO_MISSING_TEXT_SND,                        "[1.1.6.4]: audio missing text transcript (snd)."                          }, /* Access */
181   { AUDIO_MISSING_TEXT_RA,                         "[1.1.6.5]: audio missing text transcript (ra)."                           }, /* Access */
182   { AUDIO_MISSING_TEXT_RM,                         "[1.1.6.6]: audio missing text transcript (rm)."                           }, /* Access */
183   { FRAME_MISSING_LONGDESC,                        "[1.1.8.1]: <frame> may require 'longdesc'."                               }, /* Access */
184   { AREA_MISSING_ALT,                              "[1.1.9.1]: <area> missing 'alt' text."                                    }, /* Access */
185   { SCRIPT_MISSING_NOSCRIPT,                       "[1.1.10.1]: <script> missing <noscript> section."                         }, /* Access */
186   { ASCII_REQUIRES_DESCRIPTION,                    "[1.1.12.1]: ascii art requires description."                              }, /* Access */
187   { IMG_MAP_SERVER_REQUIRES_TEXT_LINKS,            "[1.2.1.1]: image map (server-side) requires text links."                  }, /* Access */
188   { MULTIMEDIA_REQUIRES_TEXT,                      "[1.4.1.1]: multimedia requires synchronized text equivalents."            }, /* Access */
189   { IMG_MAP_CLIENT_MISSING_TEXT_LINKS,             "[1.5.1.1]: image map (client-side) missing text links."                   }, /* Access */
190   { INFORMATION_NOT_CONVEYED_IMAGE,                "[2.1.1.1]: ensure information not conveyed through color alone (image)."  }, /* Access */
191   { INFORMATION_NOT_CONVEYED_APPLET,               "[2.1.1.2]: ensure information not conveyed through color alone (applet)." }, /* Access */
192   { INFORMATION_NOT_CONVEYED_OBJECT,               "[2.1.1.3]: ensure information not conveyed through color alone (object)." }, /* Access */
193   { INFORMATION_NOT_CONVEYED_SCRIPT,               "[2.1.1.4]: ensure information not conveyed through color alone (script)." }, /* Access */
194   { INFORMATION_NOT_CONVEYED_INPUT,                "[2.1.1.5]: ensure information not conveyed through color alone (input)."  }, /* Access */
195   { COLOR_CONTRAST_TEXT,                           "[2.2.1.1]: poor color contrast (text)."                                   }, /* Access */
196   { COLOR_CONTRAST_LINK,                           "[2.2.1.2]: poor color contrast (link)."                                   }, /* Access */
197   { COLOR_CONTRAST_ACTIVE_LINK,                    "[2.2.1.3]: poor color contrast (active link)."                            }, /* Access */
198   { COLOR_CONTRAST_VISITED_LINK,                   "[2.2.1.4]: poor color contrast (visited link)."                           }, /* Access */
199   { DOCTYPE_MISSING,                               "[3.2.1.1]: <doctype> missing."                                            }, /* Access */
200   { STYLE_SHEET_CONTROL_PRESENTATION,              "[3.3.1.1]: use style sheets to control presentation."                     }, /* Access */
201   { HEADERS_IMPROPERLY_NESTED,                     "[3.5.1.1]: headers improperly nested."                                    }, /* Access */
202   { POTENTIAL_HEADER_BOLD,                         "[3.5.2.1]: potential header (bold)."                                      }, /* Access */
203   { POTENTIAL_HEADER_ITALICS,                      "[3.5.2.2]: potential header (italics)."                                   }, /* Access */
204   { POTENTIAL_HEADER_UNDERLINE,                    "[3.5.2.3]: potential header (underline)."                                 }, /* Access */
205   { HEADER_USED_FORMAT_TEXT,                       "[3.5.3.1]: header used to format text."                                   }, /* Access */
206   { LIST_USAGE_INVALID_UL,                         "[3.6.1.1]: list usage invalid <ul>."                                      }, /* Access */
207   { LIST_USAGE_INVALID_OL,                         "[3.6.1.2]: list usage invalid <ol>."                                      }, /* Access */
208   { LIST_USAGE_INVALID_LI,                         "[3.6.1.4]: list usage invalid <li>."                                      }, /* Access */
209   { INDICATE_CHANGES_IN_LANGUAGE,                  "[4.1.1.1]: indicate changes in language."                                 }, /* Access */
210   { LANGUAGE_NOT_IDENTIFIED,                       "[4.3.1.1]: language not identified."                                      }, /* Access */
211   { LANGUAGE_INVALID,                              "[4.3.1.2]: language attribute invalid."                                   }, /* Access */
212   { DATA_TABLE_MISSING_HEADERS,                    "[5.1.2.1]: data <table> missing row/column headers (all)."                }, /* Access */
213   { DATA_TABLE_MISSING_HEADERS_COLUMN,             "[5.1.2.2]: data <table> missing row/column headers (1 col)."              }, /* Access */
214   { DATA_TABLE_MISSING_HEADERS_ROW,                "[5.1.2.3]: data <table> missing row/column headers (1 row)."              }, /* Access */
215   { DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS,      "[5.2.1.1]: data <table> may require markup (column headers)."             }, /* Access */
216   { DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS,         "[5.2.1.2]: data <table> may require markup (row headers)."                }, /* Access */
217   { LAYOUT_TABLES_LINEARIZE_PROPERLY,              "[5.3.1.1]: verify layout tables linearize properly."                      }, /* Access */
218   { LAYOUT_TABLE_INVALID_MARKUP,                   "[5.4.1.1]: invalid markup used in layout <table>."                        }, /* Access */
219   { TABLE_MISSING_SUMMARY,                         "[5.5.1.1]: <table> missing summary."                                      }, /* Access */
220   { TABLE_SUMMARY_INVALID_NULL,                    "[5.5.1.2]: <table> summary invalid (null)."                               }, /* Access */
221   { TABLE_SUMMARY_INVALID_SPACES,                  "[5.5.1.3]: <table> summary invalid (spaces)."                             }, /* Access */
222   { TABLE_SUMMARY_INVALID_PLACEHOLDER,             "[5.5.1.6]: <table> summary invalid (placeholder text)."                   }, /* Access */
223   { TABLE_MISSING_CAPTION,                         "[5.5.2.1]: <table> missing <caption>."                                    }, /* Access */
224   { TABLE_MAY_REQUIRE_HEADER_ABBR,                 "[5.6.1.1]: <table> may require header abbreviations."                     }, /* Access */
225   { TABLE_MAY_REQUIRE_HEADER_ABBR_NULL,            "[5.6.1.2]: <table> header abbreviations invalid (null)."                  }, /* Access */
226   { TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES,          "[5.6.1.3]: <table> header abbreviations invalid (spaces)."                }, /* Access */
227   { STYLESHEETS_REQUIRE_TESTING_LINK,              "[6.1.1.1]: style sheets require testing (link)."                          }, /* Access */
228   { STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT,     "[6.1.1.2]: style sheets require testing (style element)."                 }, /* Access */
229   { STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR,        "[6.1.1.3]: style sheets require testing (style attribute)."               }, /* Access */
230   { FRAME_SRC_INVALID,                             "[6.2.1.1]: <frame> source invalid."                                       }, /* Access */
231   { TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET,      "[6.2.2.1]: text equivalents require updating (applet)."                   }, /* Access */
232   { TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT,      "[6.2.2.2]: text equivalents require updating (script)."                   }, /* Access */
233   { TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT,      "[6.2.2.3]: text equivalents require updating (object)."                   }, /* Access */
234   { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT,   "[6.3.1.1]: programmatic objects require testing (script)."                }, /* Access */
235   { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT,   "[6.3.1.2]: programmatic objects require testing (object)."                }, /* Access */
236   { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED,    "[6.3.1.3]: programmatic objects require testing (embed)."                 }, /* Access */
237   { PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET,   "[6.3.1.4]: programmatic objects require testing (applet)."                }, /* Access */
238   { FRAME_MISSING_NOFRAMES,                        "[6.5.1.1]: <frameset> missing <noframes> section."                        }, /* Access */
239   { NOFRAMES_INVALID_NO_VALUE,                     "[6.5.1.2]: <noframes> section invalid (no value)."                        }, /* Access */
240   { NOFRAMES_INVALID_CONTENT,                      "[6.5.1.3]: <noframes> section invalid (content)."                         }, /* Access */
241   { NOFRAMES_INVALID_LINK,                         "[6.5.1.4]: <noframes> section invalid (link)."                            }, /* Access */
242   { REMOVE_FLICKER_SCRIPT,                         "[7.1.1.1]: remove flicker (script)."                                      }, /* Access */
243   { REMOVE_FLICKER_OBJECT,                         "[7.1.1.2]: remove flicker (object)."                                      }, /* Access */
244   { REMOVE_FLICKER_EMBED,                          "[7.1.1.3]: remove flicker (embed)."                                       }, /* Access */
245   { REMOVE_FLICKER_APPLET,                         "[7.1.1.4]: remove flicker (applet)."                                      }, /* Access */
246   { REMOVE_FLICKER_ANIMATED_GIF,                   "[7.1.1.5]: remove flicker (animated gif)."                                }, /* Access */
247   { REMOVE_BLINK_MARQUEE,                          "[7.2.1.1]: remove blink/marquee."                                         }, /* Access */
248   { REMOVE_AUTO_REFRESH,                           "[7.4.1.1]: remove auto-refresh."                                          }, /* Access */
249   { REMOVE_AUTO_REDIRECT,                          "[7.5.1.1]: remove auto-redirect."                                         }, /* Access */
250   { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT, "[8.1.1.1]: ensure programmatic objects are accessible (script)."          }, /* Access */
251   { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT, "[8.1.1.2]: ensure programmatic objects are accessible (object)."          }, /* Access */
252   { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET, "[8.1.1.3]: ensure programmatic objects are accessible (applet)."          }, /* Access */
253   { ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED,  "[8.1.1.4]: ensure programmatic objects are accessible (embed)."           }, /* Access */
254   { IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION,     "[9.1.1.1]: image map (server-side) requires conversion."                  }, /* Access */
255   { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN,  "[9.3.1.1]: <script> not keyboard accessible (onMouseDown)."               }, /* Access */
256   { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP,    "[9.3.1.2]: <script> not keyboard accessible (onMouseUp)."                 }, /* Access */
257   { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK,       "[9.3.1.3]: <script> not keyboard accessible (onClick)."                   }, /* Access */
258   { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER,  "[9.3.1.4]: <script> not keyboard accessible (onMouseOver)."               }, /* Access */
259   { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT,   "[9.3.1.5]: <script> not keyboard accessible (onMouseOut)."                }, /* Access */
260   { SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE,  "[9.3.1.6]: <script> not keyboard accessible (onMouseMove)."               }, /* Access */
261   { NEW_WINDOWS_REQUIRE_WARNING_NEW,               "[10.1.1.1]: new windows require warning (_new)."                          }, /* Access */
262   { NEW_WINDOWS_REQUIRE_WARNING_BLANK,             "[10.1.1.2]: new windows require warning (_blank)."                        }, /* Access */
263   { FORM_CONTROL_REQUIRES_DEFAULT_TEXT,            "[10.4.1.1]: form control requires default text."                          }, /* Access */
264   { FORM_CONTROL_DEFAULT_TEXT_INVALID_NULL,        "[10.4.1.2]: form control default text invalid (null)."                    }, /* Access */
265   { FORM_CONTROL_DEFAULT_TEXT_INVALID_SPACES,      "[10.4.1.3]: form control default text invalid (spaces)."                  }, /* Access */
266   { REPLACE_DEPRECATED_HTML_APPLET,                "[11.2.1.1]: replace deprecated html <applet>."                            }, /* Access */
267   { REPLACE_DEPRECATED_HTML_BASEFONT,              "[11.2.1.2]: replace deprecated html <basefont>."                          }, /* Access */
268   { REPLACE_DEPRECATED_HTML_CENTER,                "[11.2.1.3]: replace deprecated html <center>."                            }, /* Access */
269   { REPLACE_DEPRECATED_HTML_DIR,                   "[11.2.1.4]: replace deprecated html <dir>."                               }, /* Access */
270   { REPLACE_DEPRECATED_HTML_FONT,                  "[11.2.1.5]: replace deprecated html <font>."                              }, /* Access */
271   { REPLACE_DEPRECATED_HTML_ISINDEX,               "[11.2.1.6]: replace deprecated html <isindex>."                           }, /* Access */
272   { REPLACE_DEPRECATED_HTML_MENU,                  "[11.2.1.7]: replace deprecated html <menu>."                              }, /* Access */
273   { REPLACE_DEPRECATED_HTML_S,                     "[11.2.1.8]: replace deprecated html <s>."                                 }, /* Access */
274   { REPLACE_DEPRECATED_HTML_STRIKE,                "[11.2.1.9]: replace deprecated html <strike>."                            }, /* Access */
275   { REPLACE_DEPRECATED_HTML_U,                     "[11.2.1.10]: replace deprecated html <u>."                                }, /* Access */
276   { FRAME_MISSING_TITLE,                           "[12.1.1.1]: <frame> missing title."                                       }, /* Access */
277   { FRAME_TITLE_INVALID_NULL,                      "[12.1.1.2]: <frame> title invalid (null)."                                }, /* Access */
278   { FRAME_TITLE_INVALID_SPACES,                    "[12.1.1.3]: <frame> title invalid (spaces)."                              }, /* Access */
279   { ASSOCIATE_LABELS_EXPLICITLY,                   "[12.4.1.1]: associate labels explicitly with form controls."              }, /* Access */
280   { ASSOCIATE_LABELS_EXPLICITLY_FOR,               "[12.4.1.2]: associate labels explicitly with form controls (for)."        }, /* Access */
281   { ASSOCIATE_LABELS_EXPLICITLY_ID,                "[12.4.1.3]: associate labels explicitly with form controls (id)."         }, /* Access */
282   { LINK_TEXT_NOT_MEANINGFUL,                      "[13.1.1.1]: link text not meaningful."                                    }, /* Access */
283   { LINK_TEXT_MISSING,                             "[13.1.1.2]: link text missing."                                           }, /* Access */
284   { LINK_TEXT_TOO_LONG,                            "[13.1.1.3]: link text too long."                                          }, /* Access */
285   { LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE,           "[13.1.1.4]: link text not meaningful (click here)."                       }, /* Access */
286   { METADATA_MISSING,                              "[13.2.1.1]: Metadata missing."                                            }, /* Access */
287   { METADATA_MISSING_LINK,                         "[13.2.1.2]: Metadata missing (link element)."                             }, /* Access */
288   { METADATA_MISSING_REDIRECT_AUTOREFRESH,         "[13.2.1.3]: Metadata missing (redirect/auto-refresh)."                    }, /* Access */
289   { SKIPOVER_ASCII_ART,                            "[13.10.1.1]: skip over ascii art."                                        }, /* Access */
290 
291 #endif /* SUPPORT_ACCESSIBILITY_CHECKS */
292 
293   /* must be last */
294   { 0,                                             NULL                                                                       }
295 };
296 
297 static ctmbstr GetFormatFromCode(uint code)
298 {
299     uint i;
300 
301     for (i = 0; msgFormat[i].fmt; ++i)
302         if (msgFormat[i].code == code)
303             return msgFormat[i].fmt;
304 
305     return NULL;
306 }
307 
308 /*
309   Documentation of configuration options
310 */
311 
312 /* Cross references */
313 static const TidyOptionId TidyXmlDeclLinks[] =
314   { TidyCharEncoding, TidyOutCharEncoding, TidyUnknownOption };
315 static const TidyOptionId TidyJoinClassesLinks[] =
316   { TidyJoinStyles, TidyDuplicateAttrs, TidyUnknownOption };
317 static const TidyOptionId TidyJoinStylesLinks[] =
318   { TidyJoinClasses, TidyDuplicateAttrs, TidyUnknownOption };
319 static const TidyOptionId TidyDuplicateAttrsLinks[] =
320   { TidyJoinClasses, TidyJoinStyles, TidyUnknownOption };
321 static const TidyOptionId TidyIndentContentLinks[] =
322   { TidyIndentSpaces, TidyUnknownOption };
323 static const TidyOptionId TidyIndentSpacesLinks[] =
324   { TidyIndentContent, TidyUnknownOption };
325 static const TidyOptionId TidyWrapAttValsLinks[] =
326   { TidyWrapScriptlets, TidyUnknownOption };
327 static const TidyOptionId TidyWrapScriptletsLinks[] =
328   { TidyWrapAttVals, TidyUnknownOption };
329 static const TidyOptionId TidyCharEncodingLinks[] =
330   { TidyInCharEncoding, TidyOutCharEncoding, TidyUnknownOption };
331 static const TidyOptionId TidyInCharEncodingLinks[] =
332   { TidyCharEncoding, TidyUnknownOption };
333 static const TidyOptionId TidyOutCharEncodingLinks[] =
334   { TidyCharEncoding, TidyUnknownOption };
335 static const TidyOptionId TidyErrFileLinks[] =
336   { TidyOutFile, TidyUnknownOption };
337 static const TidyOptionId TidyOutFileLinks[] =
338   { TidyErrFile, TidyUnknownOption };
339 static const TidyOptionId TidyBlockTagsLinks[] =
340   { TidyEmptyTags, TidyInlineTags, TidyPreTags, TidyUnknownOption };
341 static const TidyOptionId TidyEmptyTagsLinks[] =
342   { TidyBlockTags, TidyInlineTags, TidyPreTags, TidyUnknownOption };
343 static const TidyOptionId TidyInlineTagsLinks[] =
344   { TidyBlockTags, TidyEmptyTags, TidyPreTags, TidyUnknownOption };
345 static const TidyOptionId TidyPreTagsLinks[] =
346   { TidyBlockTags, TidyEmptyTags, TidyInlineTags, TidyUnknownOption };
347 static const TidyOptionId TidyMergeDivsLinks[] =
348   { TidyMakeClean, TidyUnknownOption };
349 static const TidyOptionId TidyAsciiCharsLinks[] =
350   { TidyMakeClean, TidyUnknownOption };
351 static const TidyOptionId TidyNumEntitiesLinks[] =
352   { TidyDoctype, TidyUnknownOption };
353 
354 /* Documentation of options */
355 static const TidyOptionDoc option_docs[] =
356 {
357   {TidyXmlDecl,
358    "This option specifies if Tidy should add the XML declaration when "
359    "outputting XML or XHTML. Note that if the input already includes an "
360    "&lt;?xml ... ?&gt; declaration then this option will be ignored. "
361    "If the encoding for the output is different from \"ascii\", one of the "
362    "utf encodings or \"raw\", the declaration is always added as required by "
363    "the XML standard. "
364    , TidyXmlDeclLinks
365   },
366   {TidyXmlSpace,
367    "This option specifies if Tidy should add xml:space=\"preserve\" to "
368    "elements such as &lt;PRE&gt;, &lt;STYLE&gt; and &lt;SCRIPT&gt; when "
369    "generating XML. This is needed if the whitespace in such elements is to "
370    "be parsed appropriately without having access to the DTD. "
371   },
372   {TidyAltText,
373    "This option specifies the default \"alt=\" text Tidy uses for "
374    "&lt;IMG&gt; attributes. This feature is dangerous as it suppresses "
375    "further accessibility warnings. You are responsible for making your "
376    "documents accessible to people who can not see the images! "
377   },
378   {TidyXmlPIs,
379    "This option specifies if Tidy should change the parsing of processing "
380    "instructions to require ?&gt; as the terminator rather than &gt;. This "
381    "option is automatically set if the input is in XML. "
382   },
383   {TidyMakeBare,
384    "This option specifies if Tidy should strip Microsoft specific HTML "
385    "from Word 2000 documents, and output spaces rather than non-breaking "
386    "spaces where they exist in the input. "
387   },
388   {TidyCSSPrefix,
389    "This option specifies the prefix that Tidy uses for styles rules. By "
390    "default, \"c\" will be used. "
391   },
392   {TidyMakeClean,
393    "This option specifies if Tidy "
394    "should strip out surplus presentational tags and attributes replacing "
395    "them by style rules and structural markup as appropriate. It works well "
396    "on the HTML saved by Microsoft Office products. "
397   },
398   {TidyDoctype,
399    "This option specifies the DOCTYPE declaration generated by Tidy. If set "
400    "to \"omit\" the output won't contain a DOCTYPE declaration. If set to "
401    "\"auto\" (the default) Tidy will use an educated guess based upon the "
402    "contents of the document. If set to \"strict\", Tidy will set the DOCTYPE "
403    "to the strict DTD. If set to \"loose\", the DOCTYPE is set to the loose "
404    "(transitional) DTD. Alternatively, you can supply a string for the formal "
405    "public identifier (FPI).<br />"
406    "<br />"
407    "For example: <br />"
408    "doctype: \"-//ACME//DTD HTML 3.14159//EN\"<br />"
409    "<br />"
410    "If you specify the FPI for an XHTML document, Tidy will set the "
411    "system identifier to the empty string. For an HTML document, Tidy adds a "
412    "system identifier only if one was already present in order to preserve "
413    "the processing mode of some browsers. Tidy leaves the DOCTYPE for "
414    "generic XML documents unchanged. <code>--doctype omit</code> implies "
415    "<code>--numeric-entities yes</code>. "
416   },
417   {TidyDropEmptyParas,
418    "This option specifies if Tidy should discard empty paragraphs. "
419   },
420   {TidyDropFontTags,
421    "This option specifies if Tidy should discard &lt;FONT&gt; and "
422    "&lt;CENTER&gt; tags without creating the corresponding style rules. This "
423    "option can be set independently of the clean option. "
424   },
425   {TidyDropPropAttrs,
426    "This option specifies if Tidy should strip out proprietary attributes, "
427    "such as MS data binding attributes. "
428   },
429   {TidyEncloseBlockText,
430    "This option specifies if Tidy should insert a &lt;P&gt; element to "
431    "enclose any text it finds in any element that allows mixed content for "
432    "HTML transitional but not HTML strict. "
433   },
434   {TidyEncloseBodyText,
435    "This option specifies if Tidy should enclose any text it finds in the "
436    "body element within a &lt;P&gt; element. This is useful when you want to "
437    "take existing HTML and use it with a style sheet. "
438   },
439   {TidyEscapeCdata,
440    "This option specifies if Tidy should convert &lt;![CDATA[]]&gt; "
441    "sections to normal text. "
442   },
443   {TidyFixComments,
444    "This option specifies if Tidy should replace unexpected hyphens with "
445    "\"=\" characters when it comes across adjacent hyphens. The default is "
446    "yes. This option is provided for users of Cold Fusion which uses the "
447    "comment syntax: &lt;!--- ---&gt; "
448   },
449   {TidyFixUri,
450    "This option specifies if Tidy should check attribute values that carry "
451    "URIs for illegal characters and if such are found, escape them as HTML 4 "
452    "recommends. "
453   },
454   {TidyHideComments,
455    "This option specifies if Tidy should print out comments. "
456   },
457   {TidyHideEndTags,
458    "This option specifies if Tidy should omit optional end-tags when "
459    "generating the pretty printed markup. This option is ignored if you are "
460    "outputting to XML. "
461   },
462   {TidyIndentCdata,
463    "This option specifies if Tidy should indent &lt;![CDATA[]]&gt; sections. "
464   },
465   {TidyXmlTags,
466    "This option specifies if Tidy should use the XML parser rather than the "
467    "error correcting HTML parser. "
468   },
469   {TidyJoinClasses,
470    "This option specifies if Tidy should combine class names to generate "
471    "a single new class name, if multiple class assignments are detected on "
472    "an element. "
473    , TidyJoinClassesLinks
474   },
475   {TidyJoinStyles,
476    "This option specifies if Tidy should combine styles to generate a single "
477    "new style, if multiple style values are detected on an element. "
478    , TidyJoinStylesLinks
479   },
480   {TidyLogicalEmphasis,
481    "This option specifies if Tidy should replace any occurrence of &lt;I&gt; "
482    "by &lt;EM&gt; and any occurrence of &lt;B&gt; by &lt;STRONG&gt;. In both "
483    "cases, the attributes are preserved unchanged. This option can be set "
484    "independently of the clean and drop-font-tags options. "
485   },
486   {TidyLowerLiterals,
487    "This option specifies if Tidy should convert the value of an attribute "
488    "that takes a list of predefined values to lower case. This is required "
489    "for XHTML documents. "
490   },
491   {TidyMergeDivs,
492    "Can be used to modify behavior of -c (--clean yes) option. "
493    "This option specifies if Tidy should merge nested &lt;div&gt; such as "
494    "\"&lt;div&gt;&lt;div&gt;...&lt;/div&gt;&lt;/div&gt;\". If set to "
495    "\"auto\", the attributes of the inner &lt;div&gt; are moved to the "
496    "outer one. As well, nested &lt;div&gt; with ID attributes are not "
497    "merged. If set to \"yes\", the attributes of the inner &lt;div&gt; "
498    "are discarded with the exception of \"class\" and \"style\". "
499    ,TidyMergeDivsLinks
500   },
501 #if SUPPORT_ASIAN_ENCODINGS
502   {TidyNCR,
503    "This option specifies if Tidy should allow numeric character references. "
504   },
505 #endif
506   {TidyBlockTags,
507    "This option specifies new block-level tags. This option takes a space or "
508    "comma separated list of tag names. Unless you declare new tags, Tidy will "
509    "refuse to generate a tidied file if the input includes previously unknown "
510    "tags. Note you can't change the content model for elements such as "
511    "&lt;TABLE&gt;, &lt;UL&gt;, &lt;OL&gt; and &lt;DL&gt;. "
512    ,TidyBlockTagsLinks
513   },
514   {TidyEmptyTags,
515    "This option specifies new empty inline tags. This option takes a space "
516    "or comma separated list of tag names. Unless you declare new tags, Tidy "
517    "will refuse to generate a tidied file if the input includes previously "
518    "unknown tags. Remember to also declare empty tags as either inline or "
519    "blocklevel. "
520    ,TidyEmptyTagsLinks
521   },
522   {TidyInlineTags,
523    "This option specifies new non-empty inline tags. This option takes a "
524    "space or comma separated list of tag names. Unless you declare new tags, "
525    "Tidy will refuse to generate a tidied file if the input includes "
526    "previously unknown tags. "
527    ,TidyInlineTagsLinks
528   },
529   { TidyPreTags,
530     "This option specifies "
531     "new tags that are to be processed in exactly the same way as HTML's "
532     "&lt;PRE&gt; element. This option takes a space or comma separated list "
533     "of tag names. Unless you declare new tags, Tidy will refuse to generate "
534     "a tidied file if the input includes previously unknown tags. Note you "
535     "can not as yet add new CDATA elements (similar to &lt;SCRIPT&gt;). "
536     ,TidyPreTagsLinks
537   },
538   {TidyNumEntities,
539    "This option specifies if Tidy should output entities other than the "
540    "built-in HTML entities (&amp;amp;, &amp;lt;, &amp;gt; and &amp;quot;) in "
541    "the numeric rather than the named entity form. "
542     ,TidyNumEntitiesLinks
543   },
544   {TidyHtmlOut,
545    "This option specifies if Tidy should generate pretty printed output, "
546    "writing it as HTML. "
547   },
548   {TidyXhtmlOut,
549    "This option specifies if Tidy should generate pretty printed output, "
550    "writing it as extensible HTML. "
551    "This option causes Tidy to set the DOCTYPE and default namespace as "
552    "appropriate to XHTML. If a DOCTYPE or namespace is given they will "
553    "checked for consistency with the content of the document. In the case of "
554    "an inconsistency, the corrected values will appear in the output. For "
555    "XHTML, entities can be written as named or numeric entities according to "
556    "the setting of the \"numeric-entities\" option. The original case of tags "
557    "and attributes will be preserved, regardless of other options. "
558   },
559   {TidyXmlOut,
560    "This option specifies if Tidy should pretty print output, writing it as "
561    "well-formed XML. Any entities not defined in XML 1.0 will be written as "
562    "numeric entities to allow them to be parsed by a XML parser. The original "
563    "case of tags and attributes will be preserved, regardless of other "
564    "options. "
565   },
566   {TidyQuoteAmpersand,
567    "This option specifies if Tidy should output unadorned &amp; characters as "
568    "&amp;amp;. "
569   },
570   {TidyQuoteMarks,
571    "This option specifies if Tidy should output &quot; characters as "
572    "&amp;quot; as is preferred by some editing environments. The apostrophe "
573    "character ' is written out as &amp;#39; since many web browsers don't yet "
574    "support &amp;apos;. "
575   },
576   {TidyQuoteNbsp,
577    "This option specifies if Tidy should output non-breaking space characters "
578    "as entities, rather than as the Unicode character value 160 (decimal). "
579   },
580   {TidyDuplicateAttrs,
581    "This option specifies if Tidy should keep the first or last attribute, if "
582    "an attribute is repeated, e.g. has two align attributes. "
583    , TidyDuplicateAttrsLinks
584   },
585   {TidyReplaceColor,
586    "This option specifies if Tidy should replace numeric values in color "
587    "attributes by HTML/XHTML color names where defined, e.g. replace "
588    "\"#ffffff\" with \"white\". "
589   },
590   {TidyBodyOnly,
591    "This option specifies if Tidy should print only the contents of the "
592    "body tag as an HTML fragment.  Useful for incorporating existing whole "
593    "pages as a portion of another page. "
594   },
595   {TidyUpperCaseAttrs,
596    "This option specifies if Tidy should output attribute names in upper "
597    "case. The default is no, which results in lower case attribute names, "
598    "except for XML input, where the original case is preserved. "
599   },
600   {TidyUpperCaseTags,
601    "This option specifies if Tidy should output tag names in upper case. "
602    "The default is no, which results in lower case tag names, except for XML "
603    "input, where the original case is preserved. "
604   },
605   {TidyWord2000,
606    "This option specifies if Tidy should go to great pains to strip out all "
607    "the surplus stuff Microsoft Word 2000 inserts when you save Word "
608    "documents as \"Web pages\". Doesn't handle embedded images or VML. "
609    "You should consider using Word's \"Save As: Web Page, Filtered\". "
610   },
611   {TidyAccessibilityCheckLevel,
612    "This option specifies what level of accessibility checking, if any, "
613    "that Tidy should do. Level 0 is equivalent to Tidy Classic's "
614    "accessibility checking. "
615    "For more information on Tidy's accessibility checking, visit the "
616    "<a href=\"http://www.aprompt.ca/Tidy/accessibilitychecks.html\" "
617    ">Adaptive Technology Resource Centre at the University of Toronto</a>. "
618   },
619   {TidyShowErrors,
620    "This option specifies the number Tidy uses to determine if further errors "
621    "should be shown. If set to 0, then no errors are shown. "
622   },
623   {TidyShowWarnings,
624    "This option specifies if Tidy should suppress warnings. This can be "
625    "useful when a few errors are hidden in a flurry of warnings. "
626   },
627   {TidyBreakBeforeBR,
628    "This option specifies if Tidy should output a line break before each "
629    "&lt;BR&gt; element. "
630   },
631   {TidyIndentContent,
632    "This option specifies if Tidy should indent block-level tags. If set to "
633    "\"auto\", this option causes Tidy to decide whether or not to indent the "
634    "content of tags such as TITLE, H1-H6, LI, TD, TD, or P depending on "
635    "whether or not the content includes a block-level element. You are "
636    "advised to avoid setting indent to yes as this can expose layout bugs in "
637    "some browsers. "
638    ,TidyIndentContentLinks
639   },
640   {TidyIndentAttributes,
641    "This option specifies if Tidy should begin each attribute on a new line. "
642   },
643   {TidyIndentSpaces,
644    "This option specifies the number of spaces Tidy uses to indent content, "
645    "when indentation is enabled. "
646    ,TidyIndentSpacesLinks
647   },
648   {TidyLiteralAttribs,
649    "This option specifies if Tidy should ensure that whitespace characters "
650    "within attribute values are passed through unchanged. "
651   },
652   {TidyShowMarkup,
653    "This option specifies if Tidy should generate a pretty printed version "
654    "of the markup. Note that Tidy won't generate a pretty printed version if "
655    "it finds significant errors (see force-output). "
656   },
657 #if SUPPORT_ASIAN_ENCODINGS
658   {TidyPunctWrap,
659    "This option specifies if Tidy should line wrap after some Unicode or "
660    "Chinese punctuation characters. "
661   },
662 #endif
663   {TidyBurstSlides,
664    "Currently not used. Tidy Classic only. "
665   },
666   {TidyTabSize,
667    "This option specifies the number of columns that Tidy uses between "
668    "successive tab stops. It is used to map tabs to spaces when reading the "
669    "input. Tidy never outputs tabs. "
670   },
671   {TidyVertSpace,
672    "This option specifies if Tidy should add some empty lines for "
673    "readability. "
674   },
675   {TidyWrapLen,
676    "This option specifies the right margin Tidy uses for line wrapping. Tidy "
677    "tries to wrap lines so that they do not exceed this length. Set wrap to "
678    "zero if you want to disable line wrapping. "
679   },
680   {TidyWrapAsp,
681    "This option specifies if Tidy should line wrap text contained within ASP "
682    "pseudo elements, which look like: &lt;% ... %&gt;. "
683   },
684   {TidyWrapAttVals,
685    "This option specifies if Tidy should line wrap attribute values, for "
686    "easier editing. This option can be set independently of "
687    "wrap-script-literals. "
688    ,TidyWrapAttValsLinks
689   },
690   {TidyWrapJste,
691    "This option specifies if Tidy should line wrap text contained within "
692    "JSTE pseudo elements, which look like: &lt;# ... #&gt;. "
693   },
694   {TidyWrapPhp,
695    "This option specifies if Tidy should line wrap text contained within PHP "
696    "pseudo elements, which look like: &lt;?php ... ?&gt;. "
697   },
698   {TidyWrapScriptlets,
699    "This option specifies if Tidy should line wrap string literals that "
700    "appear in script attributes. Tidy wraps long script string literals by "
701    "inserting a backslash character before the line break. "
702    ,TidyWrapScriptletsLinks
703   },
704   {TidyWrapSection,
705    "This option specifies if Tidy should line wrap text contained within "
706    "&lt;![ ... ]&gt; section tags. "
707   },
708   {TidyAsciiChars,
709    "Can be used to modify behavior of -c (--clean yes) option.  If set "
710    "to \"yes\" when using -c, &amp;emdash;, &amp;rdquo;, and other named "
711    "character entities are downgraded to their closest ascii equivalents. "
712    ,TidyAsciiCharsLinks
713   },
714   {TidyCharEncoding,
715    "This option specifies the character encoding Tidy uses for both the input "
716    "and output. For ascii, Tidy will accept Latin-1 (ISO-8859-1) character "
717    "values, but will use entities for all characters whose value &gt; 127. "
718    "For raw, Tidy will output values above 127 without translating them into "
719    "entities. For latin1, characters above 255 will be written as entities. "
720    "For utf8, Tidy assumes that both input and output is encoded as UTF-8. "
721    "You can use iso2022 for files encoded using the ISO-2022 family of "
722    "encodings e.g. ISO-2022-JP. For mac and win1252, Tidy will accept vendor "
723    "specific character values, but will use entities for all characters whose "
724    "value &gt; 127. "
725    ,TidyCharEncodingLinks
726   },
727   {TidyInCharEncoding,
728    "This option specifies the character encoding Tidy uses for the input. See "
729    "char-encoding for more info. "
730    ,TidyInCharEncodingLinks
731   },
732 #if SUPPORT_ASIAN_ENCODINGS
733   {TidyLanguage,
734    "Currently not used, but this option specifies the language Tidy uses "
735    "(for instance \"en\"). "
736   },
737 #endif
738 #if SUPPORT_UTF16_ENCODINGS
739   {TidyOutputBOM,
740    "This option specifies if Tidy should write a Unicode Byte Order Mark "
741    "character (BOM; also known as Zero Width No-Break Space; has value of "
742    "U+FEFF) to the beginning of the output; only for UTF-8 and UTF-16 output "
743    "encodings. If set to \"auto\", this option causes Tidy to write a BOM to "
744    "the output only if a BOM was present at the beginning of the input. A BOM "
745    "is always written for XML/XHTML output using UTF-16 output encodings. "
746   },
747 #endif
748   {TidyOutCharEncoding,
749    "This option specifies the character encoding Tidy uses for the output. "
750    "See char-encoding for more info. May only be different from "
751    "input-encoding for Latin encodings (ascii, latin0, latin1, mac, win1252, "
752    "ibm858). "
753    ,TidyOutCharEncodingLinks
754   },
755   {TidyNewline,
756    "The default is appropriate to the current platform: CRLF on PC-DOS, "
757    "MS-Windows and OS/2, CR on Classic Mac OS, and LF everywhere else "
758    "(Unix and Linux). "
759   },
760   {TidyErrFile,
761    "This option specifies the error file Tidy uses for errors and warnings. "
762    "Normally errors and warnings are output to \"stderr\". "
763    ,TidyErrFileLinks
764   },
765   {TidyFixBackslash,
766    "This option specifies if Tidy should replace backslash characters "
767    "\"<code>\\</code>\" in URLs by forward slashes \"<code>/</code>\". "
768   },
769   {TidyForceOutput,
770    "This option specifies if Tidy should produce output even if errors are "
771    "encountered. Use this option with care - if Tidy reports an error, this "
772    "means Tidy was not able to, or is not sure how to, fix the error, so the "
773    "resulting output may not reflect your intention. "
774   },
775   {TidyEmacs,
776    "This option specifies if Tidy should change the format for reporting "
777    "errors and warnings to a format that is more easily parsed by GNU Emacs. "
778   },
779   {TidyEmacsFile,
780    "Used internally. "
781   },
782   {TidyKeepFileTimes,
783    "This option specifies if Tidy should keep the original modification time "
784    "of files that Tidy modifies in place. The default is no. Setting the "
785    "option to yes allows you to tidy files without causing these files to be "
786    "uploaded to a web server when using a tool such as SiteCopy. Note this "
787    "feature is not supported on some platforms. "
788   },
789   {TidyOutFile,
790    "This option specifies the output file Tidy uses for markup. Normally "
791    "markup is written to \"stdout\". "
792    ,TidyOutFileLinks
793   },
794   {TidyQuiet,
795    "This option specifies if Tidy should output the summary of the numbers "
796    "of errors and warnings, or the welcome or informational messages. "
797   },
798   {TidySlideStyle,
799    "Currently not used.  Tidy Classic only. "
800   },
801   {TidyMark,
802    "This option specifies if Tidy should add a meta element to the document "
803    "head to indicate that the document has been tidied. Tidy won't add a meta "
804    "element if one is already present. "
805   },
806   {TidyWriteBack,
807    "This option specifies if Tidy should write back the tidied markup to the "
808    "same file it read from. You are advised to keep copies of important files "
809    "before tidying them, as on rare occasions the result may not be what you "
810    "expect. "
811   },
812   {N_TIDY_OPTIONS,
813    NULL
814   }
815 };
816 
817 const TidyOptionDoc* tidyOptGetDocDesc( TidyOptionId optId )
818 {
819     uint i = 0;
820 
821     while( option_docs[i].opt != N_TIDY_OPTIONS )
822     {
823         if ( option_docs[i].opt == optId )
824             return &option_docs[i];
825         ++i;
826     }
827     return NULL;
828 }
829 
830 
831 static char* LevelPrefix( TidyReportLevel level, char* buf, size_t count )
832 {
833   *buf = 0;
834   switch ( level )
835   {
836   case TidyInfo:
837     tmbstrncpy( buf, "Info: ", count );
838     break;
839   case TidyWarning:
840     tmbstrncpy( buf, "Warning: ", count );
841     break;
842   case TidyConfig:
843     tmbstrncpy( buf, "Config: ", count );
844     break;
845   case TidyAccess:
846     tmbstrncpy( buf, "Access: ", count );
847     break;
848   case TidyError:
849     tmbstrncpy( buf, "Error: ", count );
850     break;
851   case TidyBadDocument:
852     tmbstrncpy( buf, "Document: ", count );
853     break;
854   case TidyFatal:
855     tmbstrncpy( buf, "panic: ", count );
856     break;
857   }
858   return buf + tmbstrlen( buf );
859 }
860 
861 /* Updates document message counts and
862 ** compares counts to options to see if message
863 ** display should go forward.
864 */
865 static Bool UpdateCount( TidyDocImpl* doc, TidyReportLevel level )
866 {
867   /* keep quiet after <ShowErrors> errors */
868   Bool go = ( doc->errors < cfg(doc, TidyShowErrors) );
869 
870   switch ( level )
871   {
872   case TidyInfo:
873     doc->infoMessages++;
874     break;
875   case TidyWarning:
876     doc->warnings++;
877     go = go && cfgBool( doc, TidyShowWarnings );
878     break;
879   case TidyConfig:
880     doc->optionErrors++;
881     break;
882   case TidyAccess:
883     doc->accessErrors++;
884     break;
885   case TidyError:
886     doc->errors++;
887     break;
888   case TidyBadDocument:
889     doc->docErrors++;
890     break;
891   case TidyFatal:
892     /* Ack! */;
893     break;
894   }
895 
896   return go;
897 }
898 
899 static char* ReportPosition(TidyDocImpl* doc, int line, int col, char* buf, size_t count)
900 {
901     *buf = 0;
902 
903     /* Change formatting to be parsable by GNU Emacs */
904     if ( cfgBool(doc, TidyEmacs) && cfgStr(doc, TidyEmacsFile) )
905         tmbsnprintf(buf, count, "%s:%d:%d: ", 
906                  cfgStr(doc, TidyEmacsFile), line, col);
907     else /* traditional format */
908         tmbsnprintf(buf, count, "line %d column %d - ", line, col);
909     return buf + tmbstrlen( buf );
910 }
911 
912 /* General message writing routine.
913 ** Each message is a single warning, error, etc.
914 ** 
915 ** This routine will keep track of counts and,
916 ** if the caller has set a filter, it will be 
917 ** called.  The new preferred way of handling
918 ** Tidy diagnostics output is either a) define
919 ** a new output sink or b) install a message
920 ** filter routine.
921 */
922 
923 static void messagePos( TidyDocImpl* doc, TidyReportLevel level,
924                         int line, int col, ctmbstr msg, va_list args )
925 #ifdef __GNUC__
926 __attribute__((format(printf, 5, 0)))
927 #endif
928 ;
929 static void messagePos( TidyDocImpl* doc, TidyReportLevel level,
930                         int line, int col, ctmbstr msg, va_list args )
931 {
932     char messageBuf[ 2048 ];
933     Bool go = UpdateCount( doc, level );
934 
935     if ( go )
936     {
937         tmbvsnprintf(messageBuf, sizeof(messageBuf), msg, args);
938         if ( doc->mssgFilt )
939         {
940             TidyDoc tdoc = tidyImplToDoc( doc );
941             go = doc->mssgFilt( tdoc, level, line, col, messageBuf );
942         }
943     }
944 
945     if ( go )
946     {
947         char buf[ 64 ];
948         const char *cp;
949         if ( line > 0 && col > 0 )
950         {
951             ReportPosition(doc, line, col, buf, sizeof(buf));
952             for ( cp = buf; *cp; ++cp )
953                 WriteChar( *cp, doc->errout );
954         }
955 
956         LevelPrefix( level, buf, sizeof(buf) );
957         for ( cp = buf; *cp; ++cp )
958             WriteChar( *cp, doc->errout );
959 
960         for ( cp = messageBuf; *cp; ++cp )
961             WriteChar( *cp, doc->errout );
962         WriteChar( '\n', doc->errout );
963     }
964 }
965 
966 void message( TidyDocImpl* doc, TidyReportLevel level, ctmbstr msg, ... )
967 {
968     va_list args;
969     va_start( args, msg );
970     messagePos( doc, level, 0, 0, msg, args );
971     va_end( args );
972 }
973 
974 
975 void messageLexer( TidyDocImpl* doc, TidyReportLevel level, ctmbstr msg, ... )
976 {
977     int line = ( doc->lexer ? doc->lexer->lines : 0 );
978     int col  = ( doc->lexer ? doc->lexer->columns : 0 );
979 
980     va_list args;
981     va_start( args, msg );
982     messagePos( doc, level, line, col, msg, args );
983     va_end( args );
984 }
985 
986 void messageNode( TidyDocImpl* doc, TidyReportLevel level, Node* node,
987                   ctmbstr msg, ... )
988 {
989     int line = ( node ? node->line :
990                  ( doc->lexer ? doc->lexer->lines : 0 ) );
991     int col  = ( node ? node->column :
992                  ( doc->lexer ? doc->lexer->columns : 0 ) );
993 
994     va_list args;
995     va_start( args, msg );
996     messagePos( doc, level, line, col, msg, args );
997     va_end( args );
998 }
999 
1000 void tidy_out( TidyDocImpl* doc, ctmbstr msg, ... )
1001 {
1002     if ( !cfgBool(doc, TidyQuiet) )
1003     {
1004         ctmbstr cp;
1005         char buf[ 2048 ];
1006 
1007         va_list args;
1008         va_start( args, msg );
1009         tmbvsnprintf(buf, sizeof(buf), msg, args);
1010         va_end( args );
1011 
1012         for ( cp=buf; *cp; ++cp )
1013           WriteChar( *cp, doc->errout );
1014     }
1015 }
1016 
1017 void ShowVersion( TidyDocImpl* doc )
1018 {