2017-05-08 20:14:35 +00:00
|
|
|
/* config.c
|
|
|
|
* Read configuration files and manage configuration properties.
|
|
|
|
*
|
|
|
|
* Copyright (c) 1998-2017 World Wide Web Consortium (Massachusetts
|
|
|
|
* Institute of Technology, European Research Consortium for Informatics
|
|
|
|
* and Mathematics, Keio University) and HTACG.
|
|
|
|
*
|
|
|
|
* See tidy.h for the copyright notice.
|
|
|
|
*/
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "tidy-int.h"
|
|
|
|
#include "message.h"
|
|
|
|
#include "tmbstr.h"
|
|
|
|
#include "tags.h"
|
|
|
|
|
|
|
|
#ifdef WINDOWS_OS
|
2017-10-03 19:30:21 +00:00
|
|
|
# include <io.h>
|
2011-11-17 02:44:16 +00:00
|
|
|
#else
|
2017-10-03 19:30:21 +00:00
|
|
|
# ifdef DMALLOC
|
|
|
|
/* macro for valloc() in dmalloc.h may conflict with declaration for valloc()
|
|
|
|
in unistd.h - we don't need (debugging for) valloc() here. dmalloc.h should
|
|
|
|
come last but it doesn't.*/
|
|
|
|
# ifdef valloc
|
|
|
|
# undef valloc
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
# include <unistd.h>
|
2011-11-17 02:44:16 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
** Picklist Configuration
|
|
|
|
**
|
|
|
|
** Arrange so index can be cast to enum. Note that the value field in the
|
|
|
|
** following structures is not currently used in code; they're present for
|
|
|
|
** documentation purposes currently. The arrays must be populated in enum
|
|
|
|
** order.
|
|
|
|
******************************************************************************/
|
2011-11-17 02:44:16 +00:00
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems boolPicks = {
|
|
|
|
{ "no", TidyNoState, { "0", "n", "f", "no", "false", NULL } },
|
|
|
|
{ "yes", TidyYesState, { "1", "y", "t", "yes", "true", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems autoBoolPicks = {
|
2017-09-25 19:26:03 +00:00
|
|
|
{ "no", TidyNoState, { "0", "n", "f", "no", "false", NULL } },
|
|
|
|
{ "yes", TidyYesState, { "1", "y", "t", "yes", "true", NULL } },
|
|
|
|
{ "auto", TidyAutoState, { "auto", NULL } },
|
2017-05-08 20:14:35 +00:00
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems repeatAttrPicks = {
|
|
|
|
{ "keep-first", TidyNoState, { "keep-first", NULL } },
|
|
|
|
{ "keep-last", TidyYesState, { "keep-last", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems accessPicks = {
|
|
|
|
{ "0 (Tidy Classic)", 0, { "0", "0 (Tidy Classic)", NULL } },
|
|
|
|
{ "1 (Priority 1 Checks)", 1, { "1", "1 (Priority 1 Checks)", NULL } },
|
|
|
|
{ "2 (Priority 2 Checks)", 2, { "2", "2 (Priority 2 Checks)", NULL } },
|
|
|
|
{ "3 (Priority 3 Checks)", 3, { "3", "3 (Priority 3 Checks)", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems charEncPicks = {
|
|
|
|
{ "raw", TidyEncRaw, { "raw", NULL } },
|
|
|
|
{ "ascii", TidyEncAscii, { "ascii", NULL } },
|
|
|
|
{ "latin0", TidyEncLatin0, { "latin0", NULL } },
|
|
|
|
{ "latin1", TidyEncLatin1, { "latin1", NULL } },
|
|
|
|
{ "utf8", TidyEncUtf8, { "utf8", NULL } },
|
2011-11-17 02:44:16 +00:00
|
|
|
#ifndef NO_NATIVE_ISO2022_SUPPORT
|
2017-05-08 20:14:35 +00:00
|
|
|
{ "iso2022", TidyEncIso2022, { "iso2022", NULL } },
|
2011-11-17 02:44:16 +00:00
|
|
|
#endif
|
2017-05-08 20:14:35 +00:00
|
|
|
{ "mac", TidyEncMac, { "mac", NULL } },
|
|
|
|
{ "win1252", TidyEncWin1252, { "win1252", NULL } },
|
|
|
|
{ "ibm858", TidyEncIbm858, { "ibm858", NULL } },
|
|
|
|
{ "utf16le", TidyEncUtf16le, { "utf16le", NULL } },
|
|
|
|
{ "utf16be", TidyEncUtf16be, { "utf16be", NULL } },
|
|
|
|
{ "utf16", TidyEncUtf16, { "utf16", NULL } },
|
|
|
|
{ "big5", TidyEncBig5, { "big5", NULL } },
|
|
|
|
{ "shiftjis", TidyEncShiftjis, { "shiftjis", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems newlinePicks = {
|
|
|
|
{ "LF", TidyLF, { "lf", NULL } },
|
|
|
|
{ "CRLF", TidyCRLF, { "crlf", NULL } },
|
|
|
|
{ "CR", TidyCR, { "cr", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems doctypePicks = {
|
|
|
|
{ "html5", TidyDoctypeHtml5, { "html5", NULL } },
|
|
|
|
{ "omit", TidyDoctypeOmit, { "omit", NULL } },
|
|
|
|
{ "auto", TidyDoctypeAuto, { "auto", NULL } },
|
|
|
|
{ "strict", TidyDoctypeStrict, { "strict", NULL } },
|
|
|
|
{ "transitional", TidyDoctypeLoose, { "loose", "transitional", NULL } },
|
|
|
|
{ "user", TidyDoctypeUser, { "user", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems sorterPicks = {
|
|
|
|
{ "none", TidySortAttrNone, { "none", NULL } },
|
|
|
|
{ "alpha", TidySortAttrAlpha, { "alpha", NULL } },
|
|
|
|
{ NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
static PickListItems customTagsPicks = {
|
|
|
|
{"no", TidyCustomNo, { "no", "n", NULL } },
|
|
|
|
{"blocklevel", TidyCustomBlocklevel, { "blocklevel", NULL } },
|
|
|
|
{"empty", TidyCustomEmpty, { "empty", NULL } },
|
|
|
|
{"inline", TidyCustomInline, { "inline", "y", "yes", NULL } },
|
|
|
|
{"pre", TidyCustomPre, { "pre", NULL } },
|
|
|
|
{ NULL }
|
2017-03-13 17:45:32 +00:00
|
|
|
};
|
|
|
|
|
2017-05-11 22:12:56 +00:00
|
|
|
static PickListItems attributeCasePicks = {
|
|
|
|
{ "no", TidyUppercaseNo, { "0", "n", "f", "no", "false", NULL } },
|
|
|
|
{ "yes", TidyUppercaseYes, { "1", "y", "t", "yes", "true", NULL } },
|
|
|
|
{ "preserve", TidyUppercasePreserve, { "preserve", NULL } },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
** Option Configuration
|
|
|
|
******************************************************************************/
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
#define DG TidyDiagnostics
|
2017-10-04 16:24:07 +00:00
|
|
|
#define DD TidyDisplay
|
|
|
|
#define DT TidyDocumentIO
|
2011-11-17 02:44:16 +00:00
|
|
|
#define CE TidyEncoding
|
2017-10-04 16:24:07 +00:00
|
|
|
#define IO TidyFileIO
|
|
|
|
#define MC TidyMarkupCleanup
|
|
|
|
#define ME TidyMarkupEntities
|
|
|
|
#define MR TidyMarkupRepair
|
|
|
|
#define MT TidyMarkupTeach
|
|
|
|
#define MX TidyMarkupXForm
|
|
|
|
#define PP TidyPrettyPrint
|
2017-03-09 21:04:03 +00:00
|
|
|
#define IR TidyInternalCategory
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
#define IN TidyInteger
|
|
|
|
#define BL TidyBoolean
|
|
|
|
#define ST TidyString
|
|
|
|
|
|
|
|
#define XX (TidyConfigCategory)-1
|
|
|
|
#define XY (TidyOptionType)-1
|
|
|
|
|
|
|
|
#define DLF DEFAULT_NL_CONFIG
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/* forward declarations */
|
2011-11-17 02:44:16 +00:00
|
|
|
static ParseProperty ParseInt;
|
2017-09-23 11:30:17 +00:00
|
|
|
static ParseProperty ParseList;
|
2011-11-17 02:44:16 +00:00
|
|
|
static ParseProperty ParseName;
|
|
|
|
static ParseProperty ParseCSS1Selector;
|
|
|
|
static ParseProperty ParseString;
|
|
|
|
static ParseProperty ParseCharEnc;
|
|
|
|
static ParseProperty ParseDocType;
|
2015-05-15 13:06:52 +00:00
|
|
|
static ParseProperty ParseTabs;
|
2017-05-08 20:14:35 +00:00
|
|
|
static ParseProperty ParsePickList;
|
2017-03-13 17:45:32 +00:00
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/*****************************************************************/
|
2017-03-08 15:29:41 +00:00
|
|
|
/* Ensure struct order is same order as tidyenum.h:TidyOptionId! */
|
2017-10-07 20:11:51 +00:00
|
|
|
/*****************************************************************/
|
2011-11-17 02:44:16 +00:00
|
|
|
static const TidyOptionImpl option_defs[] =
|
|
|
|
{
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyUnknownOption, IR, "unknown!", IN, 0, NULL, NULL },
|
2017-10-03 16:45:34 +00:00
|
|
|
{ TidyAccessibilityCheckLevel, DG, "accessibility-check", IN, 0, ParsePickList, &accessPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyAltText, MR, "alt-text", ST, 0, ParseString, NULL },
|
|
|
|
{ TidyAnchorAsName, MR, "anchor-as-name", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyAsciiChars, ME, "ascii-chars", BL, no, ParsePickList, &boolPicks },
|
2017-10-27 20:13:08 +00:00
|
|
|
{ TidyBlockTags, MT, "new-blocklevel-tags", ST, 0, ParseList, NULL },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyBodyOnly, DD, "show-body-only", IN, no, ParsePickList, &autoBoolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyBreakBeforeBR, PP, "break-before-br", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyCharEncoding, CE, "char-encoding", IN, UTF8, ParseCharEnc, &charEncPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyCoerceEndTags, MR, "coerce-endtags", BL, yes, ParsePickList, &boolPicks },
|
2017-10-26 18:24:35 +00:00
|
|
|
{ TidyCSSPrefix, MR, "css-prefix", ST, 0, ParseCSS1Selector, NULL, "c" },
|
2017-10-27 20:13:08 +00:00
|
|
|
{ TidyCustomTags, IR, "new-custom-tags", ST, 0, ParseList, NULL }, /* 20170309 - Issue #119 */
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyDecorateInferredUL, MX, "decorate-inferred-ul", BL, no, ParsePickList, &boolPicks },
|
2017-11-16 20:07:52 +00:00
|
|
|
{ TidyDoctype, DT, "doctype", ST, TidyDoctypeAuto, ParseDocType, &doctypePicks },
|
2017-03-10 13:24:23 +00:00
|
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyDoctypeMode, IR, "doctype-mode", IN, TidyDoctypeAuto, NULL, &doctypePicks },
|
2017-03-10 13:24:23 +00:00
|
|
|
#endif
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyDropEmptyElems, MC, "drop-empty-elements", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyDropEmptyParas, MC, "drop-empty-paras", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyDropPropAttrs, MC, "drop-proprietary-attributes", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyDuplicateAttrs, MR, "repeated-attributes", IN, TidyKeepLast, ParsePickList, &repeatAttrPicks },
|
|
|
|
{ TidyEmacs, DD, "gnu-emacs", BL, no, ParsePickList, &boolPicks },
|
2017-03-10 13:24:23 +00:00
|
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyEmacsFile, IR, "gnu-emacs-file", ST, 0, ParseString, NULL },
|
2017-03-10 13:24:23 +00:00
|
|
|
#endif
|
2017-10-27 20:13:08 +00:00
|
|
|
{ TidyEmptyTags, MT, "new-empty-tags", ST, 0, ParseList, NULL },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyEncloseBlockText, MR, "enclose-block-text", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyEncloseBodyText, MR, "enclose-text", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyErrFile, IO, "error-file", ST, 0, ParseString, NULL },
|
|
|
|
{ TidyEscapeCdata, MX, "escape-cdata", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyEscapeScripts, MR, "escape-scripts", BL, yes, ParsePickList, &boolPicks }, /* 20160227 - Issue #348 */
|
|
|
|
{ TidyFixBackslash, MR, "fix-backslash", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyFixComments, MR, "fix-bad-comments", IN, TidyAutoState, ParsePickList, &autoBoolPicks },
|
|
|
|
{ TidyFixUri, MR, "fix-uri", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyForceOutput, DG, "force-output", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyGDocClean, MC, "gdoc", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyHideComments, MX, "hide-comments", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyHtmlOut, DT, "output-html", BL, no, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyInCharEncoding, CE, "input-encoding", IN, UTF8, ParseCharEnc, &charEncPicks },
|
|
|
|
{ TidyIndentAttributes, PP, "indent-attributes", BL, no, ParsePickList, &boolPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyIndentCdata, PP, "indent-cdata", BL, no, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyIndentContent, PP, "indent", IN, TidyNoState, ParsePickList, &autoBoolPicks },
|
|
|
|
{ TidyIndentSpaces, PP, "indent-spaces", IN, 2, ParseInt, NULL },
|
2017-10-27 20:13:08 +00:00
|
|
|
{ TidyInlineTags, MT, "new-inline-tags", ST, 0, ParseList, NULL },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyJoinClasses, MX, "join-classes", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyJoinStyles, MX, "join-styles", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyKeepFileTimes, IO, "keep-time", BL, no, ParsePickList, &boolPicks },
|
2017-11-03 18:16:17 +00:00
|
|
|
{ TidyKeepTabs, PP, "keep-tabs", BL, no, ParsePickList, &boolPicks }, /* 20171103 - Issue #403 */
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyLiteralAttribs, MR, "literal-attributes", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyLogicalEmphasis, MC, "logical-emphasis", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyLowerLiterals, MR, "lower-literals", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyMakeBare, MC, "bare", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyMakeClean, MC, "clean", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyMark, PP, "tidy-mark", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyMergeDivs, MC, "merge-divs", IN, TidyAutoState, ParsePickList, &autoBoolPicks },
|
|
|
|
{ TidyMergeEmphasis, MX, "merge-emphasis", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyMergeSpans, MC, "merge-spans", IN, TidyAutoState, ParsePickList, &autoBoolPicks },
|
|
|
|
{ TidyMetaCharset, DT, "add-meta-charset", BL, no, ParsePickList, &boolPicks }, /* 20161004 - Issue #456 */
|
2017-11-18 00:16:58 +00:00
|
|
|
{ TidyMuteReports, DD, "mute", ST, 0, ParseList, NULL },
|
|
|
|
{ TidyMuteShow, DD, "mute-id", BL, no, ParsePickList, &boolPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyNCR, ME, "ncr", BL, yes, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyNewline, CE, "newline", IN, DLF, ParsePickList, &newlinePicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyNumEntities, ME, "numeric-entities", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyOmitOptionalTags, PP, "omit-optional-tags", BL, no, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyOutCharEncoding, CE, "output-encoding", IN, UTF8, ParseCharEnc, &charEncPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyOutFile, IO, "output-file", ST, 0, ParseString, NULL },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyOutputBOM, CE, "output-bom", IN, TidyAutoState, ParsePickList, &autoBoolPicks },
|
|
|
|
{ TidyPPrintTabs, PP, "indent-with-tabs", BL, no, ParseTabs, &boolPicks }, /* 20150515 - Issue #108 */
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyPreserveEntities, ME, "preserve-entities", BL, no, ParsePickList, &boolPicks },
|
2017-10-27 20:13:08 +00:00
|
|
|
{ TidyPreTags, MT, "new-pre-tags", ST, 0, ParseList, NULL },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyPriorityAttributes, PP, "priority-attributes", ST, 0, ParseList, NULL },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyPunctWrap, PP, "punctuation-wrap", BL, no, ParsePickList, &boolPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyQuiet, DD, "quiet", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyQuoteAmpersand, ME, "quote-ampersand", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyQuoteMarks, ME, "quote-marks", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyQuoteNbsp, ME, "quote-nbsp", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyReplaceColor, MX, "replace-color", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyShowErrors, DD, "show-errors", IN, 6, ParseInt, NULL },
|
2018-04-13 14:25:01 +00:00
|
|
|
{ TidyShowFilename, DD, "show-filename", BL, no, ParsePickList, &boolPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyShowInfo, DD, "show-info", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyShowMarkup, DD, "markup", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyShowMetaChange, DG, "show-meta-change", BL, no, ParsePickList, &boolPicks }, /* 20170609 - Issue #456 */
|
|
|
|
{ TidyShowWarnings, DD, "show-warnings", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidySkipNested, MR, "skip-nested", BL, yes, ParsePickList, &boolPicks }, /* 1642186 - Issue #65 */
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidySortAttributes, PP, "sort-attributes", IN, TidySortAttrNone,ParsePickList, &sorterPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyStrictTagsAttr, MR, "strict-tags-attributes", BL, no, ParsePickList, &boolPicks }, /* 20160209 - Issue #350 */
|
|
|
|
{ TidyStyleTags, MR, "fix-style-tags", BL, yes, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyTabSize, PP, "tab-size", IN, 8, ParseInt, NULL },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyUpperCaseAttrs, MR, "uppercase-attributes", IN, TidyUppercaseNo, ParsePickList, &attributeCasePicks },
|
|
|
|
{ TidyUpperCaseTags, MR, "uppercase-tags", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyUseCustomTags, MR, "custom-tags", IN, TidyCustomNo, ParsePickList, &customTagsPicks }, /* 20170309 - Issue #119 */
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyVertSpace, PP, "vertical-space", IN, no, ParsePickList, &autoBoolPicks }, /* #228 - tri option */
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyWarnPropAttrs, DG, "warn-proprietary-attributes", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyWord2000, MC, "word-2000", BL, no, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyWrapAsp, PP, "wrap-asp", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyWrapAttVals, PP, "wrap-attributes", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyWrapJste, PP, "wrap-jste", BL, yes, ParsePickList, &boolPicks },
|
|
|
|
{ TidyWrapLen, PP, "wrap", IN, 68, ParseInt, NULL },
|
2020-11-22 15:44:31 +00:00
|
|
|
{ TidyWrapPhp, PP, "wrap-php", BL, no, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ TidyWrapScriptlets, PP, "wrap-script-literals", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyWrapSection, PP, "wrap-sections", BL, yes, ParsePickList, &boolPicks },
|
2017-10-04 16:24:07 +00:00
|
|
|
{ TidyWriteBack, IO, "write-back", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyXhtmlOut, DT, "output-xhtml", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyXmlDecl, DT, "add-xml-decl", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyXmlOut, DT, "output-xml", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyXmlPIs, MR, "assume-xml-procins", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyXmlSpace, DT, "add-xml-space", BL, no, ParsePickList, &boolPicks },
|
|
|
|
{ TidyXmlTags, DT, "input-xml", BL, no, ParsePickList, &boolPicks },
|
2017-05-11 22:12:56 +00:00
|
|
|
{ N_TIDY_OPTIONS, XX, NULL, XY, 0, NULL, NULL }
|
2011-11-17 02:44:16 +00:00
|
|
|
};
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
** Deleted Options Configuration
|
|
|
|
**
|
|
|
|
** Keep track of options that have been removed from Tidy, so that we can
|
|
|
|
** suggests a replacement. When a deleted option is used, client programs
|
|
|
|
** will have the opportunity to consume the option first via the callback,
|
|
|
|
** and if not handled by the callback, will be handled by Tidy, generally
|
|
|
|
** by setting an alternate or new option, in `subDeprecatedOption()`.
|
|
|
|
******************************************************************************/
|
|
|
|
|
2017-10-06 20:14:54 +00:00
|
|
|
static const struct {
|
|
|
|
ctmbstr name; /**< name of the deprecated option */
|
|
|
|
TidyOptionId replacementId; /**< Id of the replacement option, or 0 if none. */
|
|
|
|
} deprecatedOptions[] = {
|
2017-10-27 20:13:08 +00:00
|
|
|
/* { "show-body-only", TidyBodyOnly }, */
|
2017-10-06 20:14:54 +00:00
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
** Supporting Functions
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* forward declarations */
|
2017-10-08 15:40:53 +00:00
|
|
|
static Bool GetPickListValue( ctmbstr value, PickListItems* pickList, uint *result );
|
2017-10-07 20:11:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
void TY_(InitConfig)( TidyDocImpl* doc )
|
|
|
|
{
|
|
|
|
TidyClearMemory( &doc->config, sizeof(TidyConfigImpl) );
|
|
|
|
TY_(ResetConfigToDefault)( doc );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TY_(FreeConfig)( TidyDocImpl* doc )
|
|
|
|
{
|
2017-11-19 21:58:01 +00:00
|
|
|
doc->pConfigChangeCallback = NULL;
|
2017-10-07 20:11:51 +00:00
|
|
|
TY_(ResetConfigToDefault)( doc );
|
|
|
|
TY_(TakeConfigSnapshot)( doc );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* Should only be called by options set by name
|
|
|
|
** thus, it is cheaper to do a few scans than set
|
|
|
|
** up every option in a hash table.
|
|
|
|
*/
|
|
|
|
const TidyOptionImpl* TY_(lookupOption)( ctmbstr s )
|
|
|
|
{
|
|
|
|
const TidyOptionImpl* np = option_defs;
|
|
|
|
for ( /**/; np < option_defs + N_TIDY_OPTIONS; ++np )
|
|
|
|
{
|
|
|
|
if ( TY_(tmbstrcasecmp)(s, np->name) == 0 )
|
|
|
|
return np;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-10-08 15:44:45 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
const TidyOptionImpl* TY_(getOption)( TidyOptionId optId )
|
|
|
|
{
|
|
|
|
if ( optId < N_TIDY_OPTIONS )
|
|
|
|
return option_defs + optId;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-11-19 17:02:24 +00:00
|
|
|
const Bool TY_(getOptionIsList)( TidyOptionId optId )
|
|
|
|
{
|
|
|
|
const TidyOptionImpl* option = TY_(getOption)( optId );
|
|
|
|
return option->parser == ParseList;
|
|
|
|
}
|
2011-11-17 02:44:16 +00:00
|
|
|
|
2017-11-19 21:58:01 +00:00
|
|
|
static Bool OptionChangedValuesDiffer( ctmbstr a, ctmbstr b )
|
|
|
|
{
|
|
|
|
if ( a != b )
|
|
|
|
{
|
|
|
|
if ( a == NULL || b == NULL ) /* can't both be null at this point. */
|
|
|
|
return yes;
|
|
|
|
else
|
|
|
|
return TY_(tmbstrcmp)( a, b ) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PerformOptionChangedCallback( TidyDocImpl* doc, const TidyOptionImpl* option )
|
|
|
|
{
|
|
|
|
if ( doc->pConfigChangeCallback )
|
|
|
|
{
|
|
|
|
TidyDoc tdoc = tidyImplToDoc( doc );
|
|
|
|
TidyOption opt = tidyImplToOption( option );
|
|
|
|
doc->pConfigChangeCallback( tdoc, opt );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static void FreeOptionValue( TidyDocImpl* doc, const TidyOptionImpl* option, TidyOptionValue* value )
|
|
|
|
{
|
|
|
|
if ( option->type == TidyString && value->p && value->p != option->pdflt )
|
|
|
|
TidyDocFree( doc, value->p );
|
|
|
|
}
|
|
|
|
|
2017-10-08 15:44:45 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static void CopyOptionValue( TidyDocImpl* doc, const TidyOptionImpl* option,
|
|
|
|
TidyOptionValue* oldval, const TidyOptionValue* newval )
|
|
|
|
{
|
2017-11-19 21:58:01 +00:00
|
|
|
Bool fire_callback = no;
|
2011-11-17 02:44:16 +00:00
|
|
|
assert( oldval != NULL );
|
2017-11-19 21:58:01 +00:00
|
|
|
|
|
|
|
/* Compare the old and new values. */
|
|
|
|
if ( doc->pConfigChangeCallback )
|
|
|
|
{
|
|
|
|
if ( option->type == TidyString )
|
|
|
|
fire_callback = OptionChangedValuesDiffer( oldval->p, newval->p );
|
|
|
|
else
|
|
|
|
fire_callback = oldval->v != newval->v;
|
|
|
|
}
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
FreeOptionValue( doc, option, oldval );
|
|
|
|
|
|
|
|
if ( option->type == TidyString )
|
|
|
|
{
|
|
|
|
if ( newval->p && newval->p != option->pdflt )
|
|
|
|
oldval->p = TY_(tmbstrdup)( doc->allocator, newval->p );
|
|
|
|
else
|
|
|
|
oldval->p = newval->p;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
oldval->v = newval->v;
|
2017-11-19 21:58:01 +00:00
|
|
|
|
|
|
|
if ( fire_callback )
|
|
|
|
PerformOptionChangedCallback( doc, option );
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Bool SetOptionValue( TidyDocImpl* doc, TidyOptionId optId, ctmbstr val )
|
|
|
|
{
|
2017-11-19 21:58:01 +00:00
|
|
|
const TidyOptionImpl* option = &option_defs[ optId ];
|
|
|
|
Bool fire_callback = no;
|
|
|
|
Bool status = ( optId < N_TIDY_OPTIONS );
|
|
|
|
|
|
|
|
if ( status )
|
|
|
|
{
|
|
|
|
assert( option->id == optId && option->type == TidyString );
|
|
|
|
|
|
|
|
/* Compare the old and new values. */
|
|
|
|
if ( doc->pConfigChangeCallback )
|
|
|
|
{
|
|
|
|
TidyOptionValue* oldval = &(doc->config.value[ optId ]);
|
|
|
|
fire_callback = OptionChangedValuesDiffer( oldval->p, val );
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeOptionValue( doc, option, &doc->config.value[ optId ] );
|
|
|
|
if ( TY_(tmbstrlen)(val)) /* Issue #218 - ONLY if it has LENGTH! */
|
|
|
|
doc->config.value[ optId ].p = TY_(tmbstrdup)( doc->allocator, val );
|
|
|
|
else
|
|
|
|
doc->config.value[ optId ].p = 0; /* should already be zero, but to be sure... */
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( fire_callback )
|
|
|
|
PerformOptionChangedCallback( doc, option );
|
|
|
|
|
|
|
|
return status;
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2017-11-16 20:07:52 +00:00
|
|
|
ctmbstr TY_(GetPickListLabelForPick)( TidyOptionId optId, uint pick )
|
|
|
|
{
|
|
|
|
const TidyOptionImpl* option = TY_(getOption)( optId );
|
|
|
|
|
|
|
|
if ( option && option->pickList )
|
|
|
|
{
|
|
|
|
uint ix = 0;
|
|
|
|
const PickListItem *item = NULL;
|
|
|
|
|
|
|
|
/* Loop through the picklist until index matches the value. */
|
|
|
|
while ( (item = &(*option->pickList)[ ix ]) && item->label && ix<pick )
|
|
|
|
{
|
|
|
|
++ix;
|
|
|
|
}
|
|
|
|
if ( ix==pick && item->label )
|
|
|
|
return item->label;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-19 21:58:01 +00:00
|
|
|
static void SetOptionInteger( TidyDocImpl* doc, TidyOptionId optId, ulong val )
|
|
|
|
{
|
|
|
|
const TidyOptionImpl* option = &option_defs[ optId ];
|
|
|
|
ulong* optVal = &(doc->config.value[ optId ].v);
|
|
|
|
Bool fire_callback = doc->pConfigChangeCallback && *optVal != val;
|
|
|
|
|
|
|
|
*optVal = val;
|
|
|
|
|
|
|
|
if ( fire_callback )
|
|
|
|
PerformOptionChangedCallback( doc, option );
|
|
|
|
}
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool TY_(SetOptionInt)( TidyDocImpl* doc, TidyOptionId optId, ulong val )
|
|
|
|
{
|
2017-11-19 21:58:01 +00:00
|
|
|
Bool status = ( optId < N_TIDY_OPTIONS );
|
|
|
|
if ( status )
|
|
|
|
{
|
|
|
|
assert( option_defs[ optId ].type == TidyInteger );
|
|
|
|
SetOptionInteger( doc, optId, val );
|
|
|
|
}
|
|
|
|
return status;
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool TY_(SetOptionBool)( TidyDocImpl* doc, TidyOptionId optId, Bool val )
|
|
|
|
{
|
2017-11-19 21:58:01 +00:00
|
|
|
Bool status = ( optId < N_TIDY_OPTIONS );
|
|
|
|
if ( status )
|
|
|
|
{
|
|
|
|
assert( option_defs[ optId ].type == TidyBoolean );
|
|
|
|
SetOptionInteger( doc, optId, (ulong)val );
|
|
|
|
}
|
|
|
|
return status;
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
|
2017-10-08 15:44:45 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static void GetOptionDefault( const TidyOptionImpl* option,
|
|
|
|
TidyOptionValue* dflt )
|
|
|
|
{
|
|
|
|
if ( option->type == TidyString )
|
|
|
|
dflt->p = (char*)option->pdflt;
|
|
|
|
else
|
|
|
|
dflt->v = option->dflt;
|
|
|
|
}
|
|
|
|
|
2017-10-08 15:44:45 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static Bool OptionValueEqDefault( const TidyOptionImpl* option,
|
|
|
|
const TidyOptionValue* val )
|
|
|
|
{
|
|
|
|
return ( option->type == TidyString ) ?
|
|
|
|
val->p == option->pdflt :
|
|
|
|
val->v == option->dflt;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool TY_(ResetOptionToDefault)( TidyDocImpl* doc, TidyOptionId optId )
|
|
|
|
{
|
|
|
|
Bool status = ( optId > 0 && optId < N_TIDY_OPTIONS );
|
|
|
|
if ( status )
|
|
|
|
{
|
|
|
|
TidyOptionValue dflt;
|
|
|
|
const TidyOptionImpl* option = option_defs + optId;
|
|
|
|
TidyOptionValue* value = &doc->config.value[ optId ];
|
|
|
|
assert( optId == option->id );
|
|
|
|
GetOptionDefault( option, &dflt );
|
|
|
|
CopyOptionValue( doc, option, value, &dflt );
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static void ReparseTagType( TidyDocImpl* doc, TidyOptionId optId )
|
|
|
|
{
|
|
|
|
ctmbstr tagdecl = cfgStr( doc, optId );
|
|
|
|
tmbstr dupdecl = TY_(tmbstrdup)( doc->allocator, tagdecl );
|
|
|
|
TY_(ParseConfigValue)( doc, optId, dupdecl );
|
|
|
|
TidyDocFree( doc, dupdecl );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static Bool OptionValueIdentical( const TidyOptionImpl* option,
|
|
|
|
const TidyOptionValue* val1,
|
|
|
|
const TidyOptionValue* val2 )
|
|
|
|
{
|
|
|
|
if ( option->type == TidyString )
|
|
|
|
{
|
|
|
|
if ( val1->p == val2->p )
|
|
|
|
return yes;
|
|
|
|
if ( !val1->p || !val2->p )
|
|
|
|
return no;
|
|
|
|
return TY_(tmbstrcmp)( val1->p, val2->p ) == 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return val1->v == val2->v;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2017-03-13 17:45:32 +00:00
|
|
|
static Bool NeedReparseTagDecls( TidyDocImpl* doc,
|
|
|
|
const TidyOptionValue* current,
|
2011-11-17 02:44:16 +00:00
|
|
|
const TidyOptionValue* new,
|
|
|
|
uint *changedUserTags )
|
|
|
|
{
|
|
|
|
Bool ret = no;
|
|
|
|
uint ixVal;
|
|
|
|
const TidyOptionImpl* option = option_defs;
|
|
|
|
*changedUserTags = tagtype_null;
|
|
|
|
|
|
|
|
for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
|
|
|
|
{
|
|
|
|
assert( ixVal == (uint) option->id );
|
|
|
|
switch (option->id)
|
|
|
|
{
|
|
|
|
#define TEST_USERTAGS(USERTAGOPTION,USERTAGTYPE) \
|
|
|
|
case USERTAGOPTION: \
|
|
|
|
if (!OptionValueIdentical(option,¤t[ixVal],&new[ixVal])) \
|
|
|
|
{ \
|
|
|
|
*changedUserTags |= USERTAGTYPE; \
|
|
|
|
ret = yes; \
|
|
|
|
} \
|
|
|
|
break
|
|
|
|
TEST_USERTAGS(TidyInlineTags,tagtype_inline);
|
|
|
|
TEST_USERTAGS(TidyBlockTags,tagtype_block);
|
|
|
|
TEST_USERTAGS(TidyEmptyTags,tagtype_empty);
|
|
|
|
TEST_USERTAGS(TidyPreTags,tagtype_pre);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static void ReparseTagDecls( TidyDocImpl* doc, uint changedUserTags )
|
|
|
|
{
|
|
|
|
#define REPARSE_USERTAGS(USERTAGOPTION,USERTAGTYPE) \
|
|
|
|
if ( changedUserTags & USERTAGTYPE ) \
|
|
|
|
{ \
|
|
|
|
TY_(FreeDeclaredTags)( doc, USERTAGTYPE ); \
|
|
|
|
ReparseTagType( doc, USERTAGOPTION ); \
|
|
|
|
}
|
|
|
|
REPARSE_USERTAGS(TidyInlineTags,tagtype_inline);
|
|
|
|
REPARSE_USERTAGS(TidyBlockTags,tagtype_block);
|
|
|
|
REPARSE_USERTAGS(TidyEmptyTags,tagtype_empty);
|
|
|
|
REPARSE_USERTAGS(TidyPreTags,tagtype_pre);
|
|
|
|
}
|
|
|
|
|
2017-10-06 20:14:54 +00:00
|
|
|
|
2017-10-07 15:04:18 +00:00
|
|
|
/* Returns the option id of the replacement Tidy option for optName. Because
|
|
|
|
** an option might not have a replacement (0, TidyUnknownOption), a return
|
|
|
|
** value of N_TIDY_OPTIONS indicates an error, i.e., that the option isn't
|
|
|
|
** in the deprecated list.
|
|
|
|
*/
|
2017-10-06 20:14:54 +00:00
|
|
|
static TidyOptionId getOptionReplacement( ctmbstr optName )
|
|
|
|
{
|
|
|
|
uint i = 0;
|
|
|
|
ctmbstr testName;
|
|
|
|
while ( (testName = deprecatedOptions[i].name) )
|
|
|
|
{
|
|
|
|
if ( TY_(tmbstrcasecmp)( optName, testName ) == 0 )
|
|
|
|
return deprecatedOptions[i].replacementId;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return N_TIDY_OPTIONS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-07 15:04:18 +00:00
|
|
|
/* Indicates whether or not optName is deprecated */
|
2017-10-06 20:14:54 +00:00
|
|
|
static Bool isOptionDeprecated( ctmbstr optName )
|
|
|
|
{
|
|
|
|
return getOptionReplacement( optName ) != N_TIDY_OPTIONS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-08 15:53:36 +00:00
|
|
|
/* Substitute the new option for the deprecated one. */
|
2017-10-06 20:14:54 +00:00
|
|
|
static Bool subDeprecatedOption( TidyDocImpl* doc, ctmbstr oldName, ctmbstr oldValue)
|
|
|
|
{
|
|
|
|
TidyOptionId newOptId = getOptionReplacement( oldName );
|
2017-10-07 15:04:18 +00:00
|
|
|
ctmbstr newName = TY_(getOption)( newOptId )->name;
|
|
|
|
TidyDoc tdoc = tidyImplToDoc( doc );
|
2017-10-06 20:14:54 +00:00
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
assert( isOptionDeprecated(oldName));
|
|
|
|
|
2017-10-06 20:14:54 +00:00
|
|
|
if ( newOptId == TidyUnknownOption )
|
|
|
|
{
|
2017-10-07 15:04:18 +00:00
|
|
|
TY_(Report)( doc, NULL, NULL, OPTION_REMOVED, oldName );
|
2017-10-06 20:14:54 +00:00
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
2017-10-07 15:04:18 +00:00
|
|
|
/********************/
|
|
|
|
/* `show-body-only` */
|
|
|
|
/********************/
|
2017-10-06 20:14:54 +00:00
|
|
|
if ( TY_(tmbstrcasecmp)( oldName, "show-body-only" ) == 0 )
|
|
|
|
{
|
|
|
|
uint value;
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/* `show-body-only` used to use the autoBoolPicks */
|
2017-10-08 15:44:45 +00:00
|
|
|
if ( GetPickListValue( oldValue, &autoBoolPicks, &value ) )
|
2017-10-06 20:14:54 +00:00
|
|
|
{
|
|
|
|
if ( value == TidyNoState )
|
|
|
|
{
|
2017-10-07 20:11:51 +00:00
|
|
|
TY_(SetOptionInt)( doc, newOptId, value );
|
2017-10-07 15:04:18 +00:00
|
|
|
TY_(Report)( doc, NULL, NULL, OPTION_REMOVED_UNAPPLIED, oldName, newName );
|
2017-10-06 20:14:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-11-02 17:42:38 +00:00
|
|
|
ctmbstr val;
|
2017-10-07 20:11:51 +00:00
|
|
|
TY_(SetOptionInt)( doc, newOptId, value );
|
2017-11-02 17:42:38 +00:00
|
|
|
val = tidyOptGetCurrPick( tdoc, newOptId );
|
2017-10-07 15:04:18 +00:00
|
|
|
TY_(Report)( doc, NULL, NULL, OPTION_REMOVED_APPLIED, oldName, newName, val );
|
2017-10-06 20:14:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-07 20:11:51 +00:00
|
|
|
TY_(ReportBadArgument)(doc, oldName);
|
2017-10-06 20:14:54 +00:00
|
|
|
}
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
void TY_(ResetConfigToDefault)( TidyDocImpl* doc )
|
|
|
|
{
|
|
|
|
uint ixVal;
|
|
|
|
const TidyOptionImpl* option = option_defs;
|
|
|
|
TidyOptionValue* value = &doc->config.value[ 0 ];
|
|
|
|
for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
|
|
|
|
{
|
|
|
|
TidyOptionValue dflt;
|
|
|
|
assert( ixVal == (uint) option->id );
|
|
|
|
GetOptionDefault( option, &dflt );
|
|
|
|
CopyOptionValue( doc, option, &value[ixVal], &dflt );
|
|
|
|
}
|
|
|
|
TY_(FreeDeclaredTags)( doc, tagtype_null );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
void TY_(TakeConfigSnapshot)( TidyDocImpl* doc )
|
|
|
|
{
|
|
|
|
uint ixVal;
|
|
|
|
const TidyOptionImpl* option = option_defs;
|
|
|
|
const TidyOptionValue* value = &doc->config.value[ 0 ];
|
|
|
|
TidyOptionValue* snap = &doc->config.snapshot[ 0 ];
|
|
|
|
|
2021-07-01 19:36:27 +00:00
|
|
|
/* @jsd: do NOT mess with user-specified settings until
|
|
|
|
* absolutely necessary, and ensure that we can
|
|
|
|
* can restore them immediately after the need.
|
|
|
|
*/
|
|
|
|
// TY_(AdjustConfig)( doc ); /* Make sure it's consistent */
|
2011-11-17 02:44:16 +00:00
|
|
|
for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
|
|
|
|
{
|
|
|
|
assert( ixVal == (uint) option->id );
|
|
|
|
CopyOptionValue( doc, option, &snap[ixVal], &value[ixVal] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
void TY_(ResetConfigToSnapshot)( TidyDocImpl* doc )
|
|
|
|
{
|
|
|
|
uint ixVal;
|
|
|
|
const TidyOptionImpl* option = option_defs;
|
|
|
|
TidyOptionValue* value = &doc->config.value[ 0 ];
|
|
|
|
const TidyOptionValue* snap = &doc->config.snapshot[ 0 ];
|
|
|
|
uint changedUserTags;
|
2017-03-13 17:45:32 +00:00
|
|
|
Bool needReparseTagsDecls = NeedReparseTagDecls( doc, value, snap,
|
2011-11-17 02:44:16 +00:00
|
|
|
&changedUserTags );
|
|
|
|
|
|
|
|
for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
|
|
|
|
{
|
|
|
|
assert( ixVal == (uint) option->id );
|
|
|
|
CopyOptionValue( doc, option, &value[ixVal], &snap[ixVal] );
|
|
|
|
}
|
|
|
|
if ( needReparseTagsDecls )
|
|
|
|
ReparseTagDecls( doc, changedUserTags );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
void TY_(CopyConfig)( TidyDocImpl* docTo, TidyDocImpl* docFrom )
|
|
|
|
{
|
|
|
|
if ( docTo != docFrom )
|
|
|
|
{
|
|
|
|
uint ixVal;
|
|
|
|
const TidyOptionImpl* option = option_defs;
|
|
|
|
const TidyOptionValue* from = &docFrom->config.value[ 0 ];
|
|
|
|
TidyOptionValue* to = &docTo->config.value[ 0 ];
|
|
|
|
uint changedUserTags;
|
2017-03-13 17:45:32 +00:00
|
|
|
Bool needReparseTagsDecls = NeedReparseTagDecls( docTo, to, from,
|
2011-11-17 02:44:16 +00:00
|
|
|
&changedUserTags );
|
|
|
|
|
|
|
|
TY_(TakeConfigSnapshot)( docTo );
|
|
|
|
for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal )
|
|
|
|
{
|
|
|
|
assert( ixVal == (uint) option->id );
|
|
|
|
CopyOptionValue( docTo, option, &to[ixVal], &from[ixVal] );
|
|
|
|
}
|
|
|
|
if ( needReparseTagsDecls )
|
|
|
|
ReparseTagDecls( docTo, changedUserTags );
|
2021-07-01 19:36:27 +00:00
|
|
|
|
|
|
|
/* @jsd: do NOT mess with user-specified settings until
|
|
|
|
* absolutely necessary, and ensure that we can
|
|
|
|
* can restore them immediately after the need.
|
|
|
|
*/
|
|
|
|
// TY_(AdjustConfig)( docTo ); /* Make sure it's consistent */
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
|
|
|
/* Debug accessor functions will be type-safe and assert option type match */
|
|
|
|
ulong TY_(_cfgGet)( TidyDocImpl* doc, TidyOptionId optId )
|
|
|
|
{
|
|
|
|
assert( optId < N_TIDY_OPTIONS );
|
|
|
|
return doc->config.value[ optId ].v;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool TY_(_cfgGetBool)( TidyDocImpl* doc, TidyOptionId optId )
|
|
|
|
{
|
|
|
|
ulong val = TY_(_cfgGet)( doc, optId );
|
|
|
|
const TidyOptionImpl* opt = &option_defs[ optId ];
|
|
|
|
assert( opt && opt->type == TidyBoolean );
|
|
|
|
return (Bool) val;
|
|
|
|
}
|
|
|
|
|
|
|
|
TidyTriState TY_(_cfgGetAutoBool)( TidyDocImpl* doc, TidyOptionId optId )
|
|
|
|
{
|
|
|
|
ulong val = TY_(_cfgGet)( doc, optId );
|
|
|
|
const TidyOptionImpl* opt = &option_defs[ optId ];
|
|
|
|
assert( opt && opt->type == TidyInteger
|
2017-05-13 15:39:13 +00:00
|
|
|
&& opt->parser == ParsePickList );
|
2011-11-17 02:44:16 +00:00
|
|
|
return (TidyTriState) val;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctmbstr TY_(_cfgGetString)( TidyDocImpl* doc, TidyOptionId optId )
|
|
|
|
{
|
|
|
|
const TidyOptionImpl* opt;
|
|
|
|
|
|
|
|
assert( optId < N_TIDY_OPTIONS );
|
|
|
|
opt = &option_defs[ optId ];
|
|
|
|
assert( opt && opt->type == TidyString );
|
|
|
|
return doc->config.value[ optId ].p;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static tchar GetC( TidyConfigImpl* config )
|
|
|
|
{
|
|
|
|
if ( config->cfgIn )
|
|
|
|
return TY_(ReadChar)( config->cfgIn );
|
|
|
|
return EndOfStream;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static tchar FirstChar( TidyConfigImpl* config )
|
|
|
|
{
|
|
|
|
config->c = GetC( config );
|
|
|
|
return config->c;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static tchar AdvanceChar( TidyConfigImpl* config )
|
|
|
|
{
|
|
|
|
if ( config->c != EndOfStream )
|
|
|
|
config->c = GetC( config );
|
|
|
|
return config->c;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static tchar SkipWhite( TidyConfigImpl* config )
|
|
|
|
{
|
|
|
|
while ( TY_(IsWhite)(config->c) && !TY_(IsNewline)(config->c) )
|
|
|
|
config->c = GetC( config );
|
|
|
|
return config->c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
/* skip over line continuations to start of next property */
|
2011-11-17 02:44:16 +00:00
|
|
|
static uint NextProperty( TidyConfigImpl* config )
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* skip to end of line */
|
|
|
|
while ( config->c != '\n' && config->c != '\r' && config->c != EndOfStream )
|
|
|
|
config->c = GetC( config );
|
|
|
|
|
|
|
|
/* treat \r\n \r or \n as line ends */
|
|
|
|
if ( config->c == '\r' )
|
|
|
|
config->c = GetC( config );
|
|
|
|
|
|
|
|
if ( config->c == '\n' )
|
|
|
|
config->c = GetC( config );
|
|
|
|
}
|
|
|
|
while ( TY_(IsWhite)(config->c) ); /* line continuation? */
|
|
|
|
|
|
|
|
return config->c;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/*
|
2017-10-07 20:11:51 +00:00
|
|
|
Todd Lewis contributed this code for expanding ~/foo or ~your/foo according
|
|
|
|
to $HOME and your user name. This will work partially on any system which
|
|
|
|
defines $HOME. Support for ~user/foo will work on systems that support
|
|
|
|
getpwnam(userid), namely Unix/Linux.
|
2011-11-17 02:44:16 +00:00
|
|
|
*/
|
|
|
|
static ctmbstr ExpandTilde( TidyDocImpl* doc, ctmbstr filename )
|
|
|
|
{
|
|
|
|
char *home_dir = NULL;
|
|
|
|
|
|
|
|
if ( !filename )
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ( filename[0] != '~' )
|
|
|
|
return filename;
|
|
|
|
|
|
|
|
if (filename[1] == '/')
|
|
|
|
{
|
|
|
|
home_dir = getenv("HOME");
|
2018-09-02 18:07:11 +00:00
|
|
|
if (home_dir) {
|
2011-11-17 02:44:16 +00:00
|
|
|
++filename;
|
2018-09-02 18:07:11 +00:00
|
|
|
}
|
2018-09-04 18:22:56 +00:00
|
|
|
#ifdef _WIN32
|
2018-09-02 18:07:11 +00:00
|
|
|
else if (strlen(filename) >= 3) { /* at least '~/+1' */
|
|
|
|
/* no HOME env in Windows - got for HOMEDRIVE=C: HOMEPATH=\Users\user */
|
|
|
|
char * hd = getenv("HOMEDRIVE");
|
|
|
|
char * hp = getenv("HOMEPATH");
|
|
|
|
if (hd && hp) {
|
|
|
|
ctmbstr s = TidyDocAlloc(doc, _MAX_PATH);
|
|
|
|
strcpy(s, hd);
|
|
|
|
strcat(s, hp);
|
|
|
|
strcat(s, "\\");
|
|
|
|
strcat(s, &filename[2]);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-09-04 18:22:56 +00:00
|
|
|
#endif /* _WIN32 */
|
2018-09-02 18:07:11 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
#ifdef SUPPORT_GETPWNAM
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct passwd *passwd = NULL;
|
|
|
|
ctmbstr s = filename + 1;
|
|
|
|
tmbstr t;
|
|
|
|
|
|
|
|
while ( *s && *s != '/' )
|
|
|
|
s++;
|
|
|
|
|
2017-09-30 21:06:19 +00:00
|
|
|
if ( (t = TidyDocAlloc(doc, s - filename)) )
|
2011-11-17 02:44:16 +00:00
|
|
|
{
|
|
|
|
memcpy(t, filename+1, s-filename-1);
|
|
|
|
t[s-filename-1] = 0;
|
|
|
|
|
|
|
|
passwd = getpwnam(t);
|
|
|
|
|
|
|
|
TidyDocFree(doc, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( passwd )
|
|
|
|
{
|
|
|
|
filename = s;
|
|
|
|
home_dir = passwd->pw_dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* SUPPORT_GETPWNAM */
|
|
|
|
|
|
|
|
if ( home_dir )
|
|
|
|
{
|
|
|
|
uint len = TY_(tmbstrlen)(filename) + TY_(tmbstrlen)(home_dir) + 1;
|
|
|
|
tmbstr p = (tmbstr)TidyDocAlloc( doc, len );
|
|
|
|
TY_(tmbstrcpy)( p, home_dir );
|
|
|
|
TY_(tmbstrcat)( p, filename );
|
|
|
|
return (ctmbstr) p;
|
|
|
|
}
|
|
|
|
return (ctmbstr) filename;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool TIDY_CALL tidyFileExists( TidyDoc tdoc, ctmbstr filename )
|
|
|
|
{
|
|
|
|
TidyDocImpl* doc = tidyDocToImpl( tdoc );
|
|
|
|
ctmbstr fname = (tmbstr) ExpandTilde( doc, filename );
|
|
|
|
#ifndef NO_ACCESS_SUPPORT
|
|
|
|
Bool exists = ( access(fname, 0) == 0 );
|
|
|
|
#else
|
|
|
|
Bool exists;
|
|
|
|
/* at present */
|
|
|
|
FILE* fin = fopen(fname, "r");
|
|
|
|
if (fin != NULL)
|
|
|
|
fclose(fin);
|
|
|
|
exists = ( fin != NULL );
|
|
|
|
#endif
|
|
|
|
if ( fname != filename )
|
|
|
|
TidyDocFree( doc, (tmbstr) fname );
|
|
|
|
return exists;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int TY_(ParseConfigFile)( TidyDocImpl* doc, ctmbstr file )
|
|
|
|
{
|
|
|
|
return TY_(ParseConfigFileEnc)( doc, file, "ascii" );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* open the file and parse its contents
|
|
|
|
*/
|
|
|
|
int TY_(ParseConfigFileEnc)( TidyDocImpl* doc, ctmbstr file, ctmbstr charenc )
|
|
|
|
{
|
2017-10-03 17:56:31 +00:00
|
|
|
enum { tidy_max_name = 64 };
|
2011-11-17 02:44:16 +00:00
|
|
|
uint opterrs = doc->optionErrors;
|
|
|
|
tmbstr fname = (tmbstr) ExpandTilde( doc, file );
|
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
|
|
|
FILE* fin = fopen( fname, "r" );
|
|
|
|
int enc = TY_(CharEncodingId)( doc, charenc );
|
|
|
|
|
|
|
|
if ( fin == NULL || enc < 0 )
|
|
|
|
{
|
2017-09-04 15:24:48 +00:00
|
|
|
TY_(ReportFileError)( doc, fname, FILE_CANT_OPEN_CFG );
|
2011-11-17 02:44:16 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tchar c;
|
|
|
|
cfg->cfgIn = TY_(FileInput)( doc, fin, enc );
|
|
|
|
c = FirstChar( cfg );
|
|
|
|
|
|
|
|
for ( c = SkipWhite(cfg); c != EndOfStream; c = NextProperty(cfg) )
|
|
|
|
{
|
|
|
|
uint ix = 0;
|
2017-10-03 17:56:31 +00:00
|
|
|
tmbchar name[ tidy_max_name ] = {0};
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
/* // or # start a comment */
|
|
|
|
if ( c == '/' || c == '#' )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while ( ix < sizeof(name)-1 && c != '\n' && c != EndOfStream && c != ':' )
|
|
|
|
{
|
|
|
|
name[ ix++ ] = (tmbchar) c; /* Option names all ASCII */
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( c == ':' )
|
|
|
|
{
|
2017-10-07 15:20:57 +00:00
|
|
|
Bool isDeprecated = isOptionDeprecated( name );
|
2011-11-17 02:44:16 +00:00
|
|
|
const TidyOptionImpl* option = TY_(lookupOption)( name );
|
|
|
|
c = AdvanceChar( cfg );
|
2017-10-07 15:20:57 +00:00
|
|
|
if ( option && !isDeprecated )
|
2011-11-17 02:44:16 +00:00
|
|
|
option->parser( doc, option );
|
|
|
|
else
|
|
|
|
{
|
2017-10-07 15:20:57 +00:00
|
|
|
if ( (NULL != doc->pOptCallback) || (NULL != doc->pConfigCallback) || isDeprecated )
|
2011-11-17 02:44:16 +00:00
|
|
|
{
|
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
|
|
|
tmbchar buf[8192];
|
|
|
|
uint i = 0;
|
|
|
|
tchar delim = 0;
|
|
|
|
Bool waswhite = yes;
|
2017-10-07 15:20:57 +00:00
|
|
|
Bool response = no;
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
tchar c = SkipWhite( cfg );
|
|
|
|
|
|
|
|
if ( c == '"' || c == '\'' )
|
|
|
|
{
|
|
|
|
delim = c;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( i < sizeof(buf)-2 && c != EndOfStream && c != '\r' && c != '\n' )
|
|
|
|
{
|
|
|
|
if ( delim && c == delim )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ( TY_(IsWhite)(c) )
|
|
|
|
{
|
|
|
|
if ( waswhite )
|
|
|
|
{
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
c = ' ';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
waswhite = no;
|
|
|
|
|
|
|
|
buf[i++] = (tmbchar) c;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
buf[i] = '\0';
|
2017-08-26 16:47:18 +00:00
|
|
|
|
|
|
|
if ( doc->pOptCallback )
|
2017-10-07 15:20:57 +00:00
|
|
|
response = (*doc->pOptCallback)( name, buf );
|
2017-08-26 16:47:18 +00:00
|
|
|
|
|
|
|
if ( doc->pConfigCallback )
|
2017-10-20 11:46:00 +00:00
|
|
|
response = response || (*doc->pConfigCallback)( tidyImplToDoc(doc), name, buf );
|
2017-08-26 16:47:18 +00:00
|
|
|
|
2017-10-07 15:20:57 +00:00
|
|
|
if ( !response && isDeprecated )
|
|
|
|
response = subDeprecatedOption( doc, name, buf);
|
|
|
|
|
|
|
|
if ( response == no )
|
2011-11-17 02:44:16 +00:00
|
|
|
TY_(ReportUnknownOption)( doc, name );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
TY_(ReportUnknownOption)( doc, name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TY_(freeFileSource)(&cfg->cfgIn->source, yes);
|
|
|
|
TY_(freeStreamIn)( cfg->cfgIn );
|
|
|
|
cfg->cfgIn = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( fname != (tmbstr) file )
|
|
|
|
TidyDocFree( doc, fname );
|
|
|
|
|
2021-07-01 19:36:27 +00:00
|
|
|
/* @jsd: do NOT mess with user-specified settings until
|
|
|
|
* absolutely necessary, and ensure that we can
|
|
|
|
* can restore them immediately after the need.
|
|
|
|
*/
|
|
|
|
// TY_(AdjustConfig)( docTo ); /* Make sure it's consistent */
|
2018-02-14 17:50:36 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* any new config errors? If so, return warning status. */
|
|
|
|
return (doc->optionErrors > opterrs ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* returns false if unknown option, missing parameter,
|
|
|
|
** or option doesn't use parameter
|
|
|
|
*/
|
|
|
|
Bool TY_(ParseConfigOption)( TidyDocImpl* doc, ctmbstr optnam, ctmbstr optval )
|
|
|
|
{
|
|
|
|
const TidyOptionImpl* option = TY_(lookupOption)( optnam );
|
2017-10-06 20:14:54 +00:00
|
|
|
Bool isDeprecated = isOptionDeprecated( optnam );
|
|
|
|
Bool status = ( option != NULL ) && !isDeprecated;
|
2011-11-17 02:44:16 +00:00
|
|
|
if ( !status )
|
|
|
|
{
|
2017-10-06 20:14:54 +00:00
|
|
|
/* Unknown or deprecated, so check to see if the user application
|
|
|
|
wants to deal with it first. */
|
2011-11-17 02:44:16 +00:00
|
|
|
if (NULL != doc->pOptCallback)
|
|
|
|
status = (*doc->pOptCallback)( optnam, optval );
|
2017-10-06 13:41:54 +00:00
|
|
|
if (NULL != doc->pConfigCallback )
|
2017-10-29 19:04:51 +00:00
|
|
|
status = status || (*doc->pConfigCallback)( tidyImplToDoc(doc), optnam, optval );
|
2017-10-06 20:14:54 +00:00
|
|
|
if (!status && isDeprecated)
|
|
|
|
status = subDeprecatedOption( doc, optnam, optval);
|
2011-11-17 02:44:16 +00:00
|
|
|
if (!status)
|
|
|
|
TY_(ReportUnknownOption)( doc, optnam );
|
|
|
|
}
|
2017-10-06 20:14:54 +00:00
|
|
|
else
|
2011-11-17 02:44:16 +00:00
|
|
|
status = TY_(ParseConfigValue)( doc, option->id, optval );
|
2017-10-06 20:14:54 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* returns false if unknown option, missing parameter,
|
|
|
|
** or option doesn't use parameter
|
|
|
|
*/
|
|
|
|
Bool TY_(ParseConfigValue)( TidyDocImpl* doc, TidyOptionId optId, ctmbstr optval )
|
|
|
|
{
|
2017-03-08 15:29:41 +00:00
|
|
|
const TidyOptionImpl* option = NULL;
|
|
|
|
/* #472: fail status if there is a NULL parser. @ralfjunker */
|
|
|
|
Bool status = ( optId < N_TIDY_OPTIONS
|
|
|
|
&& (option = option_defs + optId)->parser
|
|
|
|
&& optval != NULL );
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
if ( !status )
|
2017-03-08 15:29:41 +00:00
|
|
|
if ( option )
|
|
|
|
TY_(ReportBadArgument)(doc, option->name);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If optId < N_TIDY_OPTIONS then option remains unassigned,
|
|
|
|
and we have to fall back to an ugly error message. */
|
2017-03-09 17:44:48 +00:00
|
|
|
enum { sizeBuf = 11 }; /* uint_max is 10 characters */
|
|
|
|
char buffer[sizeBuf];
|
2017-03-08 15:29:41 +00:00
|
|
|
TY_(tmbsnprintf(buffer, sizeBuf, "%u", optId));
|
|
|
|
TY_(ReportUnknownOption(doc, buffer));
|
|
|
|
}
|
2011-11-17 02:44:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
TidyBuffer inbuf; /* Set up input source */
|
|
|
|
tidyBufInitWithAllocator( &inbuf, doc->allocator );
|
|
|
|
tidyBufAttach( &inbuf, (byte*)optval, TY_(tmbstrlen)(optval)+1 );
|
2011-07-26 12:31:36 +00:00
|
|
|
if (optId == TidyOutFile)
|
|
|
|
doc->config.cfgIn = TY_(BufferInput)( doc, &inbuf, RAW );
|
|
|
|
else
|
2017-02-23 15:28:19 +00:00
|
|
|
doc->config.cfgIn = TY_(BufferInput)( doc, &inbuf, RAW ); /* Issue #468 - Was ASCII! */
|
2011-11-17 02:44:16 +00:00
|
|
|
doc->config.c = GetC( &doc->config );
|
|
|
|
|
|
|
|
status = option->parser( doc, option );
|
|
|
|
|
|
|
|
TY_(freeStreamIn)(doc->config.cfgIn); /* Release input source */
|
|
|
|
doc->config.cfgIn = NULL;
|
|
|
|
tidyBufDetach( &inbuf );
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ensure that char encodings are self consistent */
|
|
|
|
Bool TY_(AdjustCharEncoding)( TidyDocImpl* doc, int encoding )
|
|
|
|
{
|
|
|
|
int outenc = -1;
|
|
|
|
int inenc = -1;
|
|
|
|
|
|
|
|
switch( encoding )
|
|
|
|
{
|
|
|
|
case MACROMAN:
|
|
|
|
inenc = MACROMAN;
|
|
|
|
outenc = ASCII;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WIN1252:
|
|
|
|
inenc = WIN1252;
|
|
|
|
outenc = ASCII;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IBM858:
|
|
|
|
inenc = IBM858;
|
|
|
|
outenc = ASCII;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ASCII:
|
|
|
|
inenc = LATIN1;
|
|
|
|
outenc = ASCII;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LATIN0:
|
|
|
|
inenc = LATIN0;
|
|
|
|
outenc = ASCII;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RAW:
|
|
|
|
case LATIN1:
|
|
|
|
case UTF8:
|
|
|
|
#ifndef NO_NATIVE_ISO2022_SUPPORT
|
|
|
|
case ISO2022:
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case UTF16LE:
|
|
|
|
case UTF16BE:
|
|
|
|
case UTF16:
|
|
|
|
case SHIFTJIS:
|
|
|
|
case BIG5:
|
|
|
|
inenc = outenc = encoding;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( inenc >= 0 )
|
|
|
|
{
|
|
|
|
TY_(SetOptionInt)( doc, TidyCharEncoding, encoding );
|
|
|
|
TY_(SetOptionInt)( doc, TidyInCharEncoding, inenc );
|
|
|
|
TY_(SetOptionInt)( doc, TidyOutCharEncoding, outenc );
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* ensure that config is self consistent */
|
2021-07-01 19:36:27 +00:00
|
|
|
void TY_(AdjustConfig)( TidyDocImpl* doc )
|
2011-11-17 02:44:16 +00:00
|
|
|
{
|
|
|
|
if ( cfgBool(doc, TidyEncloseBlockText) )
|
|
|
|
TY_(SetOptionBool)( doc, TidyEncloseBodyText, yes );
|
|
|
|
|
|
|
|
if ( cfgAutoBool(doc, TidyIndentContent) == TidyNoState )
|
|
|
|
TY_(SetOptionInt)( doc, TidyIndentSpaces, 0 );
|
|
|
|
|
|
|
|
/* disable wrapping */
|
|
|
|
if ( cfg(doc, TidyWrapLen) == 0 )
|
|
|
|
TY_(SetOptionInt)( doc, TidyWrapLen, 0x7FFFFFFF );
|
|
|
|
|
|
|
|
/* Word 2000 needs o:p to be declared as inline */
|
|
|
|
if ( cfgBool(doc, TidyWord2000) )
|
|
|
|
{
|
|
|
|
doc->config.defined_tags |= tagtype_inline;
|
|
|
|
TY_(DefineTag)( doc, tagtype_inline, "o:p" );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* #480701 disable XHTML output flag if both output-xhtml and xml input are set */
|
|
|
|
if ( cfgBool(doc, TidyXmlTags) )
|
|
|
|
TY_(SetOptionBool)( doc, TidyXhtmlOut, no );
|
|
|
|
|
|
|
|
/* XHTML is written in lower case */
|
|
|
|
if ( cfgBool(doc, TidyXhtmlOut) )
|
|
|
|
{
|
|
|
|
TY_(SetOptionBool)( doc, TidyXmlOut, yes );
|
|
|
|
TY_(SetOptionBool)( doc, TidyUpperCaseTags, no );
|
2017-05-12 11:30:20 +00:00
|
|
|
TY_(SetOptionInt)( doc, TidyUpperCaseAttrs, no );
|
2011-11-17 02:44:16 +00:00
|
|
|
/* TY_(SetOptionBool)( doc, TidyXmlPIs, yes ); */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if XML in, then XML out */
|
|
|
|
if ( cfgBool(doc, TidyXmlTags) )
|
|
|
|
{
|
|
|
|
TY_(SetOptionBool)( doc, TidyXmlOut, yes );
|
|
|
|
TY_(SetOptionBool)( doc, TidyXmlPIs, yes );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* #427837 - fix by Dave Raggett 02 Jun 01
|
|
|
|
** generate <?xml version="1.0" encoding="iso-8859-1"?>
|
|
|
|
** if the output character encoding is Latin-1 etc.
|
|
|
|
*/
|
|
|
|
if ( cfg(doc, TidyOutCharEncoding) != ASCII &&
|
|
|
|
cfg(doc, TidyOutCharEncoding) != UTF8 &&
|
|
|
|
cfg(doc, TidyOutCharEncoding) != UTF16 &&
|
|
|
|
cfg(doc, TidyOutCharEncoding) != UTF16BE &&
|
|
|
|
cfg(doc, TidyOutCharEncoding) != UTF16LE &&
|
|
|
|
cfg(doc, TidyOutCharEncoding) != RAW &&
|
|
|
|
cfgBool(doc, TidyXmlOut) )
|
|
|
|
{
|
|
|
|
TY_(SetOptionBool)( doc, TidyXmlDecl, yes );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XML requires end tags */
|
|
|
|
if ( cfgBool(doc, TidyXmlOut) )
|
|
|
|
{
|
|
|
|
/* XML requires a BOM on output if using UTF-16 encoding */
|
|
|
|
ulong enc = cfg( doc, TidyOutCharEncoding );
|
|
|
|
if ( enc == UTF16LE || enc == UTF16BE || enc == UTF16 )
|
|
|
|
TY_(SetOptionInt)( doc, TidyOutputBOM, yes );
|
2017-10-03 16:26:38 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
TY_(SetOptionBool)( doc, TidyQuoteAmpersand, yes );
|
2017-05-03 22:16:03 +00:00
|
|
|
TY_(SetOptionBool)( doc, TidyOmitOptionalTags, no );
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
2021-08-19 22:12:29 +00:00
|
|
|
|
|
|
|
/* Setup the indent character. */
|
|
|
|
if cfgBool(doc, TidyPPrintTabs)
|
|
|
|
doc->indent_char = '\t';
|
|
|
|
else
|
|
|
|
doc->indent_char = ' ';
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 02:14:59 +00:00
|
|
|
|
2017-10-08 14:47:03 +00:00
|
|
|
/* A service to ParseList(), keeps option values nicely formatted and
|
|
|
|
coordinates additions to the internal lists. Within Tidy, this function
|
|
|
|
might be used to programmatically add individual values to items that use
|
|
|
|
this service.
|
2017-09-23 11:30:17 +00:00
|
|
|
*/
|
2017-10-08 14:47:03 +00:00
|
|
|
void TY_(DeclareListItem)( TidyDocImpl* doc, const TidyOptionImpl* opt, ctmbstr name )
|
2017-09-23 02:14:59 +00:00
|
|
|
{
|
2017-10-08 14:47:03 +00:00
|
|
|
ctmbstr prvval = cfgStr( doc, opt->id );
|
2017-09-23 02:14:59 +00:00
|
|
|
tmbstr catval = NULL;
|
|
|
|
ctmbstr theval = name;
|
|
|
|
if ( prvval )
|
|
|
|
{
|
|
|
|
uint len = TY_(tmbstrlen)(name) + TY_(tmbstrlen)(prvval) + 3;
|
|
|
|
catval = TY_(tmbstrndup)( doc->allocator, prvval, len );
|
|
|
|
TY_(tmbstrcat)( catval, ", " );
|
|
|
|
TY_(tmbstrcat)( catval, name );
|
|
|
|
theval = catval;
|
|
|
|
}
|
|
|
|
|
2017-10-08 14:47:03 +00:00
|
|
|
switch ( opt->id )
|
|
|
|
{
|
|
|
|
case TidyPriorityAttributes:
|
|
|
|
TY_(DefinePriorityAttribute)( doc, name );
|
|
|
|
break;
|
|
|
|
|
2017-10-10 12:21:14 +00:00
|
|
|
case TidyMuteReports:
|
|
|
|
TY_(DefineMutedMessage)( doc, opt, name );
|
2017-10-08 14:47:03 +00:00
|
|
|
break;
|
|
|
|
|
2017-10-27 20:13:08 +00:00
|
|
|
case TidyInlineTags:
|
|
|
|
case TidyBlockTags:
|
|
|
|
case TidyEmptyTags:
|
|
|
|
case TidyPreTags:
|
|
|
|
case TidyCustomTags:
|
|
|
|
TY_(DeclareUserTag)( doc, opt, name );
|
|
|
|
break;
|
|
|
|
|
2017-10-08 14:47:03 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetOptionValue( doc, opt->id, theval );
|
2017-09-23 02:14:59 +00:00
|
|
|
if ( catval )
|
|
|
|
TidyDocFree( doc, catval );
|
2017-10-08 14:47:03 +00:00
|
|
|
}
|
2017-09-23 02:14:59 +00:00
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2017-10-08 14:47:03 +00:00
|
|
|
/* a space or comma separated list of items */
|
2017-09-23 11:30:17 +00:00
|
|
|
Bool ParseList( TidyDocImpl* doc, const TidyOptionImpl* option )
|
2017-09-23 02:14:59 +00:00
|
|
|
{
|
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
|
|
|
tmbchar buf[1024];
|
2017-09-23 11:30:17 +00:00
|
|
|
uint i = 0, nItems = 0;
|
2017-11-18 02:30:19 +00:00
|
|
|
uint c;
|
2017-11-19 21:58:01 +00:00
|
|
|
TidyConfigChangeCallback callback = doc->pConfigChangeCallback;
|
|
|
|
tmbstr oldbuff = NULL;
|
|
|
|
|
|
|
|
/* Handle comparing before and after for the config change callback.
|
|
|
|
We have do handle this manually, because otherwise TY_(DeclareListItem)
|
|
|
|
would fire a callback for EVERY list item being added. */
|
|
|
|
doc->pConfigChangeCallback = NULL;
|
|
|
|
if ( callback )
|
|
|
|
{
|
|
|
|
TidyOptionValue* oldval = &(doc->config.value[ option->id ]);
|
|
|
|
oldbuff = TY_(tmbstrdup)( doc->allocator, oldval->p );
|
|
|
|
}
|
2017-09-23 02:14:59 +00:00
|
|
|
|
|
|
|
SetOptionValue( doc, option->id, NULL );
|
|
|
|
|
2017-11-18 02:30:19 +00:00
|
|
|
/* Given an empty string, so signal success. */
|
|
|
|
if ( cfg->c == EndOfStream )
|
|
|
|
return yes;
|
|
|
|
|
|
|
|
c = SkipWhite( cfg );
|
|
|
|
|
2017-09-23 02:14:59 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if (c == ' ' || c == '\t' || c == ',')
|
|
|
|
{
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( c == '\r' || c == '\n' )
|
|
|
|
{
|
|
|
|
uint c2 = AdvanceChar( cfg );
|
|
|
|
if ( c == '\r' && c2 == '\n' )
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
else
|
|
|
|
c = c2;
|
|
|
|
|
|
|
|
if ( !TY_(IsWhite)(c) )
|
|
|
|
{
|
|
|
|
buf[i] = 0;
|
|
|
|
TY_(UngetChar)( c, cfg->cfgIn );
|
|
|
|
TY_(UngetChar)( '\n', cfg->cfgIn );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) && c != ',' )
|
|
|
|
{
|
|
|
|
buf[i++] = (tmbchar) c;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[i] = '\0';
|
|
|
|
if (i == 0) /* Skip empty attribute definition. Possible when */
|
|
|
|
continue; /* there is a trailing space on the line. */
|
|
|
|
|
|
|
|
/* add attribute to array */
|
2017-10-08 14:47:03 +00:00
|
|
|
TY_(DeclareListItem)( doc, option, buf );
|
2017-09-23 11:30:17 +00:00
|
|
|
|
2017-09-23 02:14:59 +00:00
|
|
|
i = 0;
|
2017-09-23 11:30:17 +00:00
|
|
|
++nItems;
|
2017-09-23 02:14:59 +00:00
|
|
|
}
|
|
|
|
while ( c != EndOfStream );
|
|
|
|
|
|
|
|
if ( i > 0 )
|
2017-10-08 14:47:03 +00:00
|
|
|
TY_(DeclareListItem)( doc, option, buf );
|
2017-09-23 02:14:59 +00:00
|
|
|
|
2017-11-19 21:58:01 +00:00
|
|
|
/* If there's a callback, compare the old and new values, and fire
|
|
|
|
the callback appropriately. */
|
|
|
|
if ( callback )
|
|
|
|
{
|
|
|
|
TidyOptionValue* val = &(doc->config.value[ option->id ]);
|
|
|
|
Bool fire_callback = OptionChangedValuesDiffer( val->p, oldbuff);
|
|
|
|
|
|
|
|
doc->pConfigChangeCallback = callback;
|
|
|
|
|
|
|
|
if ( oldbuff )
|
|
|
|
TidyFree( doc->allocator, oldbuff );
|
|
|
|
|
|
|
|
if ( fire_callback )
|
|
|
|
PerformOptionChangedCallback( doc, option );
|
|
|
|
}
|
|
|
|
|
2017-09-23 11:30:17 +00:00
|
|
|
return ( nItems > 0 );
|
2017-09-23 02:14:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* unsigned integers */
|
|
|
|
Bool ParseInt( TidyDocImpl* doc, const TidyOptionImpl* entry )
|
|
|
|
{
|
|
|
|
ulong number = 0;
|
|
|
|
Bool digits = no;
|
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
|
|
|
tchar c = SkipWhite( cfg );
|
|
|
|
|
|
|
|
while ( TY_(IsDigit)(c) )
|
|
|
|
{
|
|
|
|
number = c - '0' + (10 * number);
|
|
|
|
digits = yes;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !digits )
|
|
|
|
TY_(ReportBadArgument)( doc, entry->name );
|
|
|
|
else
|
|
|
|
TY_(SetOptionInt)( doc, entry->id, number );
|
|
|
|
return digits;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* a string excluding whitespace */
|
2017-02-18 23:14:51 +00:00
|
|
|
Bool FUNC_UNUSED ParseName( TidyDocImpl* doc, const TidyOptionImpl* option )
|
2011-11-17 02:44:16 +00:00
|
|
|
{
|
|
|
|
tmbchar buf[ 1024 ] = {0};
|
|
|
|
uint i = 0;
|
|
|
|
uint c = SkipWhite( &doc->config );
|
|
|
|
|
|
|
|
while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) )
|
|
|
|
{
|
|
|
|
buf[i++] = (tmbchar) c;
|
|
|
|
c = AdvanceChar( &doc->config );
|
|
|
|
}
|
|
|
|
buf[i] = 0;
|
|
|
|
|
|
|
|
if ( i == 0 )
|
|
|
|
TY_(ReportBadArgument)( doc, option->name );
|
|
|
|
else
|
|
|
|
SetOptionValue( doc, option->id, buf );
|
|
|
|
return ( i > 0 );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* #508936 - CSS class naming for -clean option */
|
|
|
|
Bool ParseCSS1Selector( TidyDocImpl* doc, const TidyOptionImpl* option )
|
|
|
|
{
|
2017-11-18 02:30:19 +00:00
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
2011-11-17 02:44:16 +00:00
|
|
|
char buf[256] = {0};
|
|
|
|
uint i = 0;
|
2017-11-18 02:30:19 +00:00
|
|
|
uint c;
|
|
|
|
|
|
|
|
/* Given an empty string, so signal success. */
|
|
|
|
if ( cfg->c == EndOfStream )
|
|
|
|
{
|
|
|
|
SetOptionValue( doc, option->id, NULL );
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = SkipWhite( cfg );
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) )
|
|
|
|
{
|
|
|
|
buf[i++] = (tmbchar) c;
|
|
|
|
c = AdvanceChar( &doc->config );
|
|
|
|
}
|
|
|
|
buf[i] = '\0';
|
|
|
|
|
2015-11-26 03:21:48 +00:00
|
|
|
if ( i == 0 ) {
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
else if ( !TY_(IsCSS1Selector)(buf) ) {
|
2011-11-17 02:44:16 +00:00
|
|
|
TY_(ReportBadArgument)( doc, option->name );
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
2018-02-19 02:21:04 +00:00
|
|
|
buf[i] = 0; /* Is #697 - Do *not* add '-' */
|
|
|
|
#if 0 /* Is #697 - Is this still required? KEEP HISTORY - DO NOT DELETE */
|
2011-11-17 02:44:16 +00:00
|
|
|
buf[i++] = '-'; /* Make sure any escaped Unicode is terminated */
|
|
|
|
buf[i] = 0; /* so valid class names are generated after */
|
|
|
|
/* Tidy appends last digits. */
|
2018-02-19 02:21:04 +00:00
|
|
|
#endif /* Is #697 - Is this still required? */
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
SetOptionValue( doc, option->id, buf );
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
2017-10-06 20:14:54 +00:00
|
|
|
|
|
|
|
/* Given a string, return the picklist value from an arbitrary picklist. */
|
2017-10-07 20:11:51 +00:00
|
|
|
static Bool GetPickListValue( ctmbstr value, PickListItems* pickList, uint *result )
|
2017-05-08 20:14:35 +00:00
|
|
|
{
|
|
|
|
const PickListItem *item = NULL;
|
|
|
|
uint ix = 0;
|
2017-10-06 20:14:54 +00:00
|
|
|
|
|
|
|
while ( (item = &(*pickList)[ ix ]) && item->label )
|
2017-05-08 20:14:35 +00:00
|
|
|
{
|
|
|
|
ctmbstr input;
|
|
|
|
uint i = 0;
|
|
|
|
while ( ( input = &(*item->inputs[i]) ) )
|
|
|
|
{
|
2017-10-06 20:14:54 +00:00
|
|
|
if (TY_(tmbstrcasecmp)(value, input) == 0 )
|
2017-05-08 20:14:35 +00:00
|
|
|
{
|
|
|
|
*result = ix;
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
++ix;
|
|
|
|
}
|
2017-10-06 20:14:54 +00:00
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-06 20:14:54 +00:00
|
|
|
/* A general parser for anything using pick lists. This provides the engine to
|
|
|
|
determine the proper option value, and can be used by parsers in addition to
|
|
|
|
ParsePickList that require special handling.
|
|
|
|
*/
|
2017-10-07 20:11:51 +00:00
|
|
|
static Bool GetParsePickListValue( TidyDocImpl* doc, const TidyOptionImpl* entry, uint *result )
|
2017-10-06 20:14:54 +00:00
|
|
|
{
|
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
|
|
|
tchar c = SkipWhite( cfg );
|
|
|
|
tmbchar work[ 16 ] = {0};
|
|
|
|
tmbstr cp = work, end = work + sizeof(work);
|
|
|
|
|
|
|
|
while ( c!=EndOfStream && cp < end && !TY_(IsWhite)(c) && c != '\r' && c != '\n' )
|
|
|
|
{
|
|
|
|
*cp++ = (tmbchar) c;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( GetPickListValue( work, entry->pickList, result ) != yes )
|
|
|
|
{
|
|
|
|
TY_(ReportBadArgument)( doc, entry->name );
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-08 20:14:35 +00:00
|
|
|
/* A general parser for anything using pick lists that don't require special
|
|
|
|
handling.
|
|
|
|
*/
|
|
|
|
Bool ParsePickList( TidyDocImpl* doc, const TidyOptionImpl* entry )
|
|
|
|
{
|
|
|
|
uint value;
|
|
|
|
|
|
|
|
if ( GetParsePickListValue( doc, entry, &value ) )
|
|
|
|
{
|
|
|
|
if ( entry->type == TidyBoolean )
|
|
|
|
TY_(SetOptionBool)( doc, entry->id, value );
|
|
|
|
else if ( entry->type == TidyInteger )
|
|
|
|
TY_(SetOptionInt)( doc, entry->id, value );
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
TY_(ReportBadArgument)( doc, entry->name );
|
|
|
|
return no;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-15 13:06:52 +00:00
|
|
|
/*\
|
|
|
|
* 20150515 - support using tabs instead of spaces - Issue #108
|
|
|
|
* Sets the indent character to a tab if on, and set indent space count to 1
|
|
|
|
* and sets indent character to a space if off.
|
2017-05-08 20:14:35 +00:00
|
|
|
\*/
|
2015-05-15 13:06:52 +00:00
|
|
|
Bool ParseTabs( TidyDocImpl* doc, const TidyOptionImpl* entry )
|
|
|
|
{
|
2017-05-08 20:14:35 +00:00
|
|
|
uint flag = 0;
|
|
|
|
Bool status = GetParsePickListValue( doc, entry, &flag );
|
|
|
|
|
2015-05-15 13:06:52 +00:00
|
|
|
if ( status ) {
|
|
|
|
Bool tabs = flag != 0 ? yes : no;
|
|
|
|
TY_(SetOptionBool)( doc, entry->id, tabs );
|
|
|
|
if (tabs) {
|
|
|
|
TY_(SetOptionInt)( doc, TidyIndentSpaces, 1 );
|
|
|
|
} else {
|
|
|
|
/* optional - TY_(ResetOptionToDefault)( doc, TidyIndentSpaces ); */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* a string including whitespace */
|
|
|
|
/* munges whitespace sequences */
|
|
|
|
Bool ParseString( TidyDocImpl* doc, const TidyOptionImpl* option )
|
|
|
|
{
|
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
|
|
|
tmbchar buf[8192];
|
|
|
|
uint i = 0;
|
|
|
|
tchar delim = 0;
|
|
|
|
Bool waswhite = yes;
|
|
|
|
|
|
|
|
tchar c = SkipWhite( cfg );
|
|
|
|
|
|
|
|
if ( c == '"' || c == '\'' )
|
|
|
|
{
|
|
|
|
delim = c;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( i < sizeof(buf)-2 && c != EndOfStream && c != '\r' && c != '\n' )
|
|
|
|
{
|
|
|
|
if ( delim && c == delim )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ( TY_(IsWhite)(c) )
|
|
|
|
{
|
|
|
|
if ( waswhite )
|
|
|
|
{
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
c = ' ';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
waswhite = no;
|
|
|
|
|
|
|
|
buf[i++] = (tmbchar) c;
|
|
|
|
c = AdvanceChar( cfg );
|
|
|
|
}
|
|
|
|
buf[i] = '\0';
|
|
|
|
|
|
|
|
SetOptionValue( doc, option->id, buf );
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool ParseCharEnc( TidyDocImpl* doc, const TidyOptionImpl* option )
|
|
|
|
{
|
|
|
|
tmbchar buf[64] = {0};
|
|
|
|
uint i = 0;
|
|
|
|
int enc = ASCII;
|
|
|
|
Bool validEncoding = yes;
|
|
|
|
tchar c = SkipWhite( &doc->config );
|
|
|
|
|
|
|
|
while ( i < sizeof(buf)-2 && c != EndOfStream && !TY_(IsWhite)(c) )
|
|
|
|
{
|
|
|
|
buf[i++] = (tmbchar) TY_(ToLower)( c );
|
|
|
|
c = AdvanceChar( &doc->config );
|
|
|
|
}
|
|
|
|
buf[i] = 0;
|
|
|
|
|
|
|
|
enc = TY_(CharEncodingId)( doc, buf );
|
|
|
|
|
|
|
|
if ( enc < 0 )
|
|
|
|
{
|
|
|
|
validEncoding = no;
|
|
|
|
TY_(ReportBadArgument)( doc, option->name );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
TY_(SetOptionInt)( doc, option->id, enc );
|
|
|
|
|
|
|
|
if ( validEncoding && option->id == TidyCharEncoding )
|
|
|
|
TY_(AdjustCharEncoding)( doc, enc );
|
|
|
|
return validEncoding;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int TY_(CharEncodingId)( TidyDocImpl* ARG_UNUSED(doc), ctmbstr charenc )
|
|
|
|
{
|
|
|
|
int enc = TY_(GetCharEncodingFromOptName)( charenc );
|
|
|
|
return enc;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
ctmbstr TY_(CharEncodingName)( int encoding )
|
|
|
|
{
|
|
|
|
ctmbstr encodingName = TY_(GetEncodingNameFromTidyId)(encoding);
|
|
|
|
|
|
|
|
if (!encodingName)
|
|
|
|
encodingName = "unknown";
|
|
|
|
|
|
|
|
return encodingName;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
ctmbstr TY_(CharEncodingOptName)( int encoding )
|
|
|
|
{
|
|
|
|
ctmbstr encodingName = TY_(GetEncodingOptNameFromTidyId)(encoding);
|
|
|
|
|
|
|
|
if (!encodingName)
|
|
|
|
encodingName = "unknown";
|
|
|
|
|
|
|
|
return encodingName;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/*
|
2012-03-15 05:11:01 +00:00
|
|
|
doctype: html5 | omit | auto | strict | loose | <fpi>
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
where the fpi is a string similar to
|
|
|
|
|
|
|
|
"-//ACME//DTD HTML 3.14159//EN"
|
|
|
|
*/
|
|
|
|
Bool ParseDocType( TidyDocImpl* doc, const TidyOptionImpl* option )
|
|
|
|
{
|
|
|
|
Bool status = yes;
|
2017-05-08 20:14:35 +00:00
|
|
|
uint value;
|
2011-11-17 02:44:16 +00:00
|
|
|
TidyConfigImpl* cfg = &doc->config;
|
2017-11-18 02:30:19 +00:00
|
|
|
tchar c;
|
|
|
|
|
|
|
|
/* Given an empty string, so signal success. */
|
|
|
|
if ( cfg->c == EndOfStream )
|
|
|
|
{
|
|
|
|
SetOptionValue( doc, option->id, NULL );
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = SkipWhite( cfg );
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
|
|
|
|
/* "-//ACME//DTD HTML 3.14159//EN" or similar */
|
|
|
|
|
2017-11-19 17:54:08 +00:00
|
|
|
if ( c == '"' || c == '\''|| c == '-' || c == '+' )
|
2011-11-17 02:44:16 +00:00
|
|
|
{
|
|
|
|
status = ParseString(doc, option);
|
|
|
|
if (status)
|
2017-05-08 20:14:35 +00:00
|
|
|
{
|
2011-11-17 02:44:16 +00:00
|
|
|
TY_(SetOptionInt)( doc, TidyDoctypeMode, TidyDoctypeUser );
|
2017-05-08 20:14:35 +00:00
|
|
|
}
|
2011-11-17 02:44:16 +00:00
|
|
|
return status;
|
|
|
|
}
|
2017-05-08 20:14:35 +00:00
|
|
|
|
|
|
|
if ( (status = GetParsePickListValue( doc, option, &value ) ) )
|
2011-11-17 02:44:16 +00:00
|
|
|
{
|
2017-05-08 20:14:35 +00:00
|
|
|
TY_(SetOptionInt)( doc, TidyDoctypeMode, value );
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TY_(ReportBadArgument)( doc, option->name );
|
|
|
|
}
|
2017-05-08 20:14:35 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* Use TidyOptionId as iterator.
|
|
|
|
** Send index of 1st option after TidyOptionUnknown as start of list.
|
|
|
|
*/
|
|
|
|
TidyIterator TY_(getOptionList)( TidyDocImpl* ARG_UNUSED(doc) )
|
|
|
|
{
|
|
|
|
return (TidyIterator) (size_t)1;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* Check if this item is last valid option.
|
|
|
|
** If so, zero out iterator.
|
|
|
|
*/
|
|
|
|
const TidyOptionImpl* TY_(getNextOption)( TidyDocImpl* ARG_UNUSED(doc),
|
|
|
|
TidyIterator* iter )
|
|
|
|
{
|
2017-03-09 21:04:03 +00:00
|
|
|
const TidyOptionImpl* option = NULL;
|
|
|
|
size_t optId;
|
|
|
|
assert( iter != NULL );
|
|
|
|
optId = (size_t) *iter;
|
|
|
|
if ( optId > TidyUnknownOption && optId < N_TIDY_OPTIONS )
|
|
|
|
{
|
|
|
|
option = &option_defs[ optId ];
|
2017-03-08 01:11:31 +00:00
|
|
|
optId++;
|
2017-03-09 21:04:03 +00:00
|
|
|
}
|
|
|
|
*iter = (TidyIterator) ( optId < N_TIDY_OPTIONS ? optId : (size_t)0 );
|
|
|
|
return option;
|
2011-11-17 02:44:16 +00:00
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
/* Use a 1-based array index as iterator: 0 == end-of-list
|
|
|
|
*/
|
|
|
|
TidyIterator TY_(getOptionPickList)( const TidyOptionImpl* option )
|
|
|
|
{
|
|
|
|
size_t ix = 0;
|
|
|
|
if ( option && option->pickList )
|
|
|
|
ix = 1;
|
|
|
|
return (TidyIterator) ix;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
ctmbstr TY_(getNextOptionPick)( const TidyOptionImpl* option,
|
|
|
|
TidyIterator* iter )
|
|
|
|
{
|
|
|
|
size_t ix;
|
|
|
|
ctmbstr val = NULL;
|
2017-05-08 20:14:35 +00:00
|
|
|
const PickListItem *item= NULL;
|
2011-11-17 02:44:16 +00:00
|
|
|
assert( option!=NULL && iter != NULL );
|
|
|
|
|
|
|
|
ix = (size_t) *iter;
|
2017-05-08 20:14:35 +00:00
|
|
|
|
|
|
|
if ( option->pickList )
|
|
|
|
{
|
|
|
|
if ( ix > 0 && ix < TIDY_PL_SIZE && option->pickList )
|
|
|
|
{
|
|
|
|
item = &(*option->pickList)[ ix-1 ];
|
|
|
|
val = item->label;
|
|
|
|
}
|
|
|
|
item = &(*option->pickList)[ ix ];
|
|
|
|
*iter = (TidyIterator) ( val && item->label ? ix + 1 : (size_t)0 );
|
|
|
|
}
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static int WriteOptionString( const TidyOptionImpl* option,
|
|
|
|
ctmbstr sval, StreamOut* out )
|
|
|
|
{
|
|
|
|
ctmbstr cp = option->name;
|
|
|
|
while ( *cp )
|
|
|
|
TY_(WriteChar)( *cp++, out );
|
|
|
|
TY_(WriteChar)( ':', out );
|
|
|
|
TY_(WriteChar)( ' ', out );
|
|
|
|
cp = sval;
|
|
|
|
while ( *cp )
|
|
|
|
TY_(WriteChar)( *cp++, out );
|
|
|
|
TY_(WriteChar)( '\n', out );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static int WriteOptionInt( const TidyOptionImpl* option, uint ival, StreamOut* out )
|
|
|
|
{
|
|
|
|
tmbchar sval[ 32 ] = {0};
|
|
|
|
TY_(tmbsnprintf)(sval, sizeof(sval), "%u", ival );
|
|
|
|
return WriteOptionString( option, sval, out );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static int WriteOptionBool( const TidyOptionImpl* option, Bool bval, StreamOut* out )
|
|
|
|
{
|
|
|
|
ctmbstr sval = bval ? "yes" : "no";
|
|
|
|
return WriteOptionString( option, sval, out );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
static int WriteOptionPick( const TidyOptionImpl* option, uint ival, StreamOut* out )
|
|
|
|
{
|
2017-05-08 20:14:35 +00:00
|
|
|
uint ix = 0;
|
|
|
|
const PickListItem *item = NULL;
|
|
|
|
|
|
|
|
if ( option-> pickList )
|
|
|
|
{
|
|
|
|
while ( (item = &(*option->pickList)[ ix ]) && item->label && ix<ival )
|
|
|
|
{
|
|
|
|
++ix;
|
|
|
|
}
|
|
|
|
if ( ix==ival && item->label )
|
|
|
|
return WriteOptionString( option, item->label, out );
|
|
|
|
}
|
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool TY_(ConfigDiffThanSnapshot)( TidyDocImpl* doc )
|
|
|
|
{
|
|
|
|
int diff = memcmp( &doc->config.value, &doc->config.snapshot,
|
|
|
|
N_TIDY_OPTIONS * sizeof(uint) );
|
|
|
|
return ( diff != 0 );
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
Bool TY_(ConfigDiffThanDefault)( TidyDocImpl* doc )
|
|
|
|
{
|
|
|
|
Bool diff = no;
|
|
|
|
const TidyOptionImpl* option = option_defs + 1;
|
2017-10-25 19:04:49 +00:00
|
|
|
const TidyOptionValue* val = doc->config.value + 1;
|
2011-11-17 02:44:16 +00:00
|
|
|
for ( /**/; !diff && option && option->name; ++option, ++val )
|
|
|
|
{
|
|
|
|
diff = !OptionValueEqDefault( option, val );
|
|
|
|
}
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int SaveConfigToStream( TidyDocImpl* doc, StreamOut* out )
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
const TidyOptionImpl* option;
|
|
|
|
for ( option=option_defs+1; 0==rc && option && option->name; ++option )
|
|
|
|
{
|
|
|
|
const TidyOptionValue* val = &doc->config.value[ option->id ];
|
|
|
|
if ( option->parser == NULL )
|
|
|
|
continue;
|
|
|
|
if ( OptionValueEqDefault( option, val ) && option->id != TidyDoctype)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( option->id == TidyDoctype ) /* Special case */
|
|
|
|
{
|
|
|
|
ulong dtmode = cfg( doc, TidyDoctypeMode );
|
|
|
|
if ( dtmode == TidyDoctypeUser )
|
|
|
|
{
|
|
|
|
tmbstr t;
|
|
|
|
|
|
|
|
/* add 2 double quotes */
|
|
|
|
if (( t = (tmbstr)TidyDocAlloc( doc, TY_(tmbstrlen)( val->p ) + 2 ) ))
|
|
|
|
{
|
|
|
|
t[0] = '\"'; t[1] = 0;
|
|
|
|
|
|
|
|
TY_(tmbstrcat)( t, val->p );
|
|
|
|
TY_(tmbstrcat)( t, "\"" );
|
|
|
|
rc = WriteOptionString( option, t, out );
|
|
|
|
|
|
|
|
TidyDocFree( doc, t );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( dtmode == option_defs[TidyDoctypeMode].dflt )
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
rc = WriteOptionPick( option, dtmode, out );
|
|
|
|
}
|
2017-05-08 20:14:35 +00:00
|
|
|
else if ( option->pickList)
|
2011-11-17 02:44:16 +00:00
|
|
|
rc = WriteOptionPick( option, val->v, out );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch ( option->type )
|
|
|
|
{
|
|
|
|
case TidyString:
|
|
|
|
rc = WriteOptionString( option, val->p, out );
|
|
|
|
break;
|
|
|
|
case TidyInteger:
|
|
|
|
rc = WriteOptionInt( option, val->v, out );
|
|
|
|
break;
|
|
|
|
case TidyBoolean:
|
|
|
|
rc = WriteOptionBool( option, val->v ? yes : no, out );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
int TY_(SaveConfigFile)( TidyDocImpl* doc, ctmbstr cfgfil )
|
|
|
|
{
|
|
|
|
int status = -1;
|
|
|
|
StreamOut* out = NULL;
|
|
|
|
uint outenc = cfg( doc, TidyOutCharEncoding );
|
|
|
|
uint nl = cfg( doc, TidyNewline );
|
|
|
|
FILE* fout = fopen( cfgfil, "wb" );
|
|
|
|
if ( fout )
|
|
|
|
{
|
|
|
|
out = TY_(FileOutput)( doc, fout, outenc, nl );
|
|
|
|
status = SaveConfigToStream( doc, out );
|
|
|
|
fclose( fout );
|
|
|
|
TidyDocFree( doc, out );
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-10-07 20:11:51 +00:00
|
|
|
|
2011-11-17 02:44:16 +00:00
|
|
|
int TY_(SaveConfigSink)( TidyDocImpl* doc, TidyOutputSink* sink )
|
|
|
|
{
|
|
|
|
uint outenc = cfg( doc, TidyOutCharEncoding );
|
|
|
|
uint nl = cfg( doc, TidyNewline );
|
|
|
|
StreamOut* out = TY_(UserOutput)( doc, sink, outenc, nl );
|
|
|
|
int status = SaveConfigToStream( doc, out );
|
|
|
|
TidyDocFree( doc, out );
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|