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

TidyLib
tidy/src/config.c

Version: ~ [ 1.0 ] ~

** Warning: Cannot open xref database.

1 /* 2 config.c -- read config file and manage config properties 3 4 (c) 1998-2005 (W3C) MIT, ERCIM, Keio University 5 See tidy.h for the copyright notice. 6 7 CVS Info : 8 9 $Author: arnaud02 $ 10 $Date: 2005/08/16 17:02:18 $ 11 $Revision: 1.92 $ 12 13 */ 14 15 /* 16 config files associate a property name with a value. 17 18 // comments can start at the beginning of a line 19 # comments can start at the beginning of a line 20 name: short values fit onto one line 21 name: a really long value that 22 continues on the next line 23 24 property names are case insensitive and should be less than 25 60 characters in length and must start at the begining of 26 the line, as whitespace at the start of a line signifies a 27 line continuation. 28 */ 29 30 #include "config.h" 31 #include "tidy-int.h" 32 #include "message.h" 33 #include "tmbstr.h" 34 #include "tags.h" 35 36 #ifdef WINDOWS_OS 37 #include <io.h> 38 #else 39 #ifdef DMALLOC 40 /* 41 macro for valloc() in dmalloc.h may conflict with declaration for valloc() in unistd.h - 42 we don't need (debugging for) valloc() here. dmalloc.h should come last but it doesn't. 43 */ 44 #ifdef valloc 45 #undef valloc 46 #endif 47 #endif 48 #include <unistd.h> 49 #endif 50 51 #ifdef TIDY_WIN32_MLANG_SUPPORT 52 #include "win32tc.h" 53 #endif 54 55 void InitConfig( TidyDocImpl* doc ) 56 { 57 ClearMemory( &doc->config, sizeof(TidyConfigImpl) ); 58 ResetConfigToDefault( doc ); 59 } 60 61 void FreeConfig( TidyDocImpl* doc ) 62 { 63 ResetConfigToDefault( doc ); 64 TakeConfigSnapshot( doc ); 65 } 66 67 68 /* Arrange so index can be cast to enum 69 */ 70 static const ctmbstr boolPicks[] = 71 { 72 "no", 73 "yes", 74 NULL 75 }; 76 77 static const ctmbstr autoBoolPicks[] = 78 { 79 "no", 80 "yes", 81 "auto", 82 NULL 83 }; 84 85 static const ctmbstr repeatAttrPicks[] = 86 { 87 "keep-first", 88 "keep-last", 89 NULL 90 }; 91 92 static const ctmbstr accessPicks[] = 93 { 94 "0 (Tidy Classic)", 95 "1 (Priority 1 Checks)", 96 "2 (Priority 2 Checks)", 97 "3 (Priority 3 Checks)", 98 NULL 99 }; 100 101 static const ctmbstr charEncPicks[] = 102 { 103 "raw", 104 "ascii", 105 "latin0", 106 "latin1", 107 "utf8", 108 #ifndef NO_NATIVE_ISO2022_SUPPORT 109 "iso2022", 110 #endif 111 "mac", 112 "win1252", 113 "ibm858", 114 115 #if SUPPORT_UTF16_ENCODINGS 116 "utf16le", 117 "utf16be", 118 "utf16", 119 #endif 120 121 #if SUPPORT_ASIAN_ENCODINGS 122 "big5", 123 "shiftjis", 124 #endif 125 126 NULL 127 }; 128 129 static const ctmbstr newlinePicks[] = 130 { 131 "LF", 132 "CRLF", 133 "CR", 134 NULL 135 }; 136 137 static const ctmbstr doctypePicks[] = 138 { 139 "omit", 140 "auto", 141 "strict", 142 "transitional", 143 "user", 144 NULL 145 }; 146 147 #define MU TidyMarkup 148 #define DG TidyDiagnostics 149 #define PP TidyPrettyPrint 150 #define CE TidyEncoding 151 #define MS TidyMiscellaneous 152 153 #define IN TidyInteger 154 #define BL TidyBoolean 155 #define ST TidyString 156 157 #define XX (TidyConfigCategory)-1 158 #define XY (TidyOptionType)-1 159 160 #define DLF DEFAULT_NL_CONFIG 161 162 /* If Accessibility checks not supported, make config setting read-only */ 163 #if SUPPORT_ACCESSIBILITY_CHECKS 164 #define ParseAcc ParseInt 165 #else 166 #define ParseAcc NULL 167 #endif 168 169 static const TidyOptionImpl option_defs[] = 170 { 171 { TidyUnknownOption, MS, "unknown!", IN, 0, NULL, NULL }, 172 { TidyIndentSpaces, PP, "indent-spaces", IN, 2, ParseInt, NULL }, 173 { TidyWrapLen, PP, "wrap", IN, 68, ParseInt, NULL }, 174 { TidyTabSize, PP, "tab-size", IN, 8, ParseInt, NULL }, 175 { TidyCharEncoding, CE, "char-encoding", IN, ASCII, ParseCharEnc, charEncPicks }, 176 { TidyInCharEncoding, CE, "input-encoding", IN, LATIN1, ParseCharEnc, charEncPicks }, 177 { TidyOutCharEncoding, CE, "output-encoding", IN, ASCII, ParseCharEnc, charEncPicks }, 178 { TidyNewline, CE, "newline", IN, DLF, ParseNewline, newlinePicks }, 179 { TidyDoctypeMode, MU, "doctype-mode", IN, TidyDoctypeAuto, NULL, doctypePicks }, 180 { TidyDoctype, MU, "doctype", ST, 0, ParseDocType, doctypePicks }, 181 { TidyDuplicateAttrs, MU, "repeated-attributes", IN, TidyKeepLast, ParseRepeatAttr, repeatAttrPicks }, 182 { TidyAltText, MU, "alt-text", ST, 0, ParseString, NULL }, 183 184 /* obsolete */ 185 { TidySlideStyle, MS, "slide-style", ST, 0, ParseName, NULL }, 186 187 { TidyErrFile, MS, "error-file", ST, 0, ParseString, NULL }, 188 { TidyOutFile, MS, "output-file", ST, 0, ParseString, NULL }, 189 { TidyWriteBack, MS, "write-back", BL, no, ParseBool, boolPicks }, 190 { TidyShowMarkup, PP, "markup", BL, yes, ParseBool, boolPicks }, 191 { TidyShowWarnings, DG, "show-warnings", BL, yes, ParseBool, boolPicks }, 192 { TidyQuiet, MS, "quiet", BL, no, ParseBool, boolPicks }, 193 { TidyIndentContent, PP, "indent", IN, TidyNoState, ParseAutoBool, autoBoolPicks }, 194 { TidyHideEndTags, MU, "hide-endtags", BL, no, ParseBool, boolPicks }, 195 { TidyXmlTags, MU, "input-xml", BL, no, ParseBool, boolPicks }, 196 { TidyXmlOut, MU, "output-xml", BL, no, ParseBool, boolPicks }, 197 { TidyXhtmlOut, MU, "output-xhtml", BL, no, ParseBool, boolPicks }, 198 { TidyHtmlOut, MU, "output-html", BL, no, ParseBool, boolPicks }, 199 { TidyXmlDecl, MU, "add-xml-decl", BL, no, ParseBool, boolPicks }, 200 { TidyUpperCaseTags, MU, "uppercase-tags", BL, no, ParseBool, boolPicks }, 201 { TidyUpperCaseAttrs, MU, "uppercase-attributes", BL, no, ParseBool, boolPicks }, 202 { TidyMakeBare, MU, "bare", BL, no, ParseBool, boolPicks }, 203 { TidyMakeClean, MU, "clean", BL, no, ParseBool, boolPicks }, 204 { TidyLogicalEmphasis, MU, "logical-emphasis", BL, no, ParseBool, boolPicks }, 205 { TidyDropPropAttrs, MU, "drop-proprietary-attributes", BL, no, ParseBool, boolPicks }, 206 { TidyDropFontTags, MU, "drop-font-tags", BL, no, ParseBool, boolPicks }, 207 { TidyDropEmptyParas, MU, "drop-empty-paras", BL, yes, ParseBool, boolPicks }, 208 { TidyFixComments, MU, "fix-bad-comments", BL, yes, ParseBool, boolPicks }, 209 { TidyBreakBeforeBR, PP, "break-before-br", BL, no, ParseBool, boolPicks }, 210 211 /* obsolete */ 212 { TidyBurstSlides, PP, "split", BL, no, ParseBool, boolPicks }, 213 214 { TidyNumEntities, MU, "numeric-entities", BL, no, ParseBool, boolPicks }, 215 { TidyQuoteMarks, MU, "quote-marks", BL, no, ParseBool, boolPicks }, 216 { TidyQuoteNbsp, MU, "quote-nbsp", BL, yes, ParseBool, boolPicks }, 217 { TidyQuoteAmpersand, MU, "quote-ampersand", BL, yes, ParseBool, boolPicks }, 218 { TidyWrapAttVals, PP, "wrap-attributes", BL, no, ParseBool, boolPicks }, 219 { TidyWrapScriptlets, PP, "wrap-script-literals", BL, no, ParseBool, boolPicks }, 220 { TidyWrapSection, PP, "wrap-sections", BL, yes, ParseBool, boolPicks }, 221 { TidyWrapAsp, PP, "wrap-asp", BL, yes, ParseBool, boolPicks }, 222 { TidyWrapJste, PP, "wrap-jste", BL, yes, ParseBool, boolPicks }, 223 { TidyWrapPhp, PP, "wrap-php", BL, yes, ParseBool, boolPicks }, 224 { TidyFixBackslash, MU, "fix-backslash", BL, yes, ParseBool, boolPicks }, 225 { TidyIndentAttributes, PP, "indent-attributes", BL, no, ParseBool, boolPicks }, 226 { TidyXmlPIs, MU, "assume-xml-procins", BL, no, ParseBool, boolPicks }, 227 { TidyXmlSpace, MU, "add-xml-space", BL, no, ParseBool, boolPicks }, 228 { TidyEncloseBodyText, MU, "enclose-text", BL, no, ParseBool, boolPicks }, 229 { TidyEncloseBlockText, MU, "enclose-block-text", BL, no, ParseBool, boolPicks }, 230 { TidyKeepFileTimes, MS, "keep-time", BL, no, ParseBool, boolPicks }, 231 { TidyWord2000, MU, "word-2000", BL, no, ParseBool, boolPicks }, 232 { TidyMark, MS, "tidy-mark", BL, yes, ParseBool, boolPicks }, 233 { TidyEmacs, MS, "gnu-emacs", BL, no, ParseBool, boolPicks }, 234 { TidyEmacsFile, MS, "gnu-emacs-file", ST, 0, ParseString, NULL }, 235 { TidyLiteralAttribs, MU, "literal-attributes", BL, no, ParseBool, boolPicks }, 236 { TidyBodyOnly, MU, "show-body-only", BL, no, ParseBool, boolPicks }, 237 { TidyFixUri, MU, "fix-uri", BL, yes, ParseBool, boolPicks }, 238 { TidyLowerLiterals, MU, "lower-literals", BL, yes, ParseBool, boolPicks }, 239 { TidyHideComments, MU, "hide-comments", BL, no, ParseBool, boolPicks }, 240 { TidyIndentCdata, MU, "indent-cdata", BL, no, ParseBool, boolPicks }, 241 { TidyForceOutput, MS, "force-output", BL, no, ParseBool, boolPicks }, 242 { TidyShowErrors, DG, "show-errors", IN, 6, ParseInt, NULL }, 243 { TidyAsciiChars, CE, "ascii-chars", BL, no, ParseBool, boolPicks }, 244 { TidyJoinClasses, MU, "join-classes", BL, no, ParseBool, boolPicks }, 245 { TidyJoinStyles, MU, "join-styles", BL, yes, ParseBool, boolPicks }, 246 { TidyEscapeCdata, MU, "escape-cdata", BL, no, ParseBool, boolPicks }, 247 #if SUPPORT_ASIAN_ENCODINGS 248 { TidyLanguage, CE, "language", ST, 0, ParseName, NULL }, 249 { TidyNCR, MU, "ncr", BL, yes, ParseBool, boolPicks }, 250 #endif 251 #if SUPPORT_UTF16_ENCODINGS 252 { TidyOutputBOM, CE, "output-bom", IN, TidyAutoState, ParseAutoBool, autoBoolPicks }, 253 #endif 254 { TidyReplaceColor, MU, "replace-color", BL, no, ParseBool, boolPicks }, 255 { TidyCSSPrefix, MU, "css-prefix", ST, 0, ParseCSS1Selector, NULL }, 256 { TidyInlineTags, MU, "new-inline-tags", ST, 0, ParseTagNames, NULL }, 257 { TidyBlockTags, MU, "new-blocklevel-tags", ST, 0, ParseTagNames, NULL }, 258 { TidyEmptyTags, MU, "new-empty-tags", ST, 0, ParseTagNames, NULL }, 259 { TidyPreTags, MU, "new-pre-tags", ST, 0, ParseTagNames, NULL }, 260 { TidyAccessibilityCheckLevel, DG, "accessibility-check", IN, 0, ParseAcc, accessPicks }, 261 { TidyVertSpace, PP, "vertical-space", BL, no, ParseBool, boolPicks }, 262 #if SUPPORT_ASIAN_ENCODINGS 263 { TidyPunctWrap, PP, "punctuation-wrap", BL, no, ParseBool, boolPicks }, 264 #endif 265 { TidyMergeDivs, MU, "merge-divs", IN, TidyAutoState, ParseAutoBool, autoBoolPicks }, 266 { N_TIDY_OPTIONS, XX, NULL, XY, 0, NULL, NULL } 267 }; 268 269 /* Should only be called by options set by name 270 ** thus, it is cheaper to do a few scans than set 271 ** up every option in a hash table. 272 */ 273 const TidyOptionImpl* lookupOption( ctmbstr s ) 274 { 275 const TidyOptionImpl* np = option_defs; 276 for ( /**/; np < option_defs + N_TIDY_OPTIONS; ++np ) 277 { 278 if ( tmbstrcasecmp(s, np->name) == 0 ) 279 return np; 280 } 281 return NULL; 282 } 283 284 const TidyOptionImpl* getOption( TidyOptionId optId ) 285 { 286 if ( optId < N_TIDY_OPTIONS ) 287 return option_defs + optId; 288 return NULL; 289 } 290 291 292 static void FreeOptionValue( const TidyOptionImpl* option, ulong value ) 293 { 294 if ( value && option->type == TidyString && value != option->dflt ) 295 { 296 MemFree( (void*) value ); 297 } 298 } 299 300 static void CopyOptionValue( const TidyOptionImpl* option, 301 ulong* oldval, ulong newval ) 302 { 303 assert( oldval != NULL ); 304 FreeOptionValue( option, *oldval ); 305 306 if ( newval && option->type == TidyString && newval != option->dflt ) 307 *oldval = (ulong) tmbstrdup( (ctmbstr) newval ); 308 else 309 *oldval = newval; 310 } 311 312 313 Bool SetOptionValue( TidyDocImpl* doc, TidyOptionId optId, ctmbstr val ) 314 { 315 const TidyOptionImpl* option = &option_defs[ optId ]; 316 Bool status = ( optId < N_TIDY_OPTIONS ); 317 if ( status ) 318 { 319 assert( option->id == optId && option->type == TidyString ); 320 FreeOptionValue( option, doc->config.value[ optId ] ); 321 doc->config.value[ optId ] = (ulong) tmbstrdup( val ); 322 } 323 return status; 324 } 325 326 Bool SetOptionInt( TidyDocImpl* doc, TidyOptionId optId, ulong val ) 327 { 328 Bool status = ( optId < N_TIDY_OPTIONS ); 329 if ( status ) 330 { 331 assert( option_defs[ optId ].type == TidyInteger ); 332 doc->config.value[ optId ] = val; 333 } 334 return status; 335 } 336 337 Bool SetOptionBool( TidyDocImpl* doc, TidyOptionId optId, Bool val ) 338 { 339 Bool status = ( optId < N_TIDY_OPTIONS ); 340 if ( status ) 341 { 342 assert( option_defs[ optId ].type == TidyBoolean ); 343 doc->config.value[ optId ] = val; 344 } 345 return status; 346 } 347 348 Bool ResetOptionToDefault( TidyDocImpl* doc, TidyOptionId optId ) 349 { 350 Bool status = ( optId > 0 && optId < N_TIDY_OPTIONS ); 351 if ( status ) 352 { 353 const TidyOptionImpl* option = option_defs + optId; 354 ulong* value = &doc->config.value[ optId ]; 355 assert( optId == option->id ); 356 CopyOptionValue( option, value, option->dflt ); 357 } 358 return status; 359 } 360 361 static void ReparseTagType( TidyDocImpl* doc, TidyOptionId optId ) 362 { 363 ctmbstr tagdecl = cfgStr( doc, optId ); 364 tmbstr dupdecl = tmbstrdup( tagdecl ); 365 ParseConfigValue( doc, optId, dupdecl ); 366 MemFree( dupdecl ); 367 } 368 369 /* Not efficient, but effective */ 370 static void ReparseTagDecls( TidyDocImpl* doc ) 371 { 372 FreeDeclaredTags( doc, tagtype_null ); 373 if ( cfg(doc, TidyInlineTags) ) 374 ReparseTagType( doc, TidyInlineTags ); 375 if ( cfg(doc, TidyBlockTags) ) 376 ReparseTagType( doc, TidyBlockTags ); 377 if ( cfg(doc, TidyEmptyTags) ) 378 ReparseTagType( doc, TidyEmptyTags ); 379 if ( cfg(doc, TidyPreTags) ) 380 ReparseTagType( doc, TidyPreTags ); 381 } 382 383 void ResetConfigToDefault( TidyDocImpl* doc ) 384 { 385 uint ixVal; 386 const TidyOptionImpl* option = option_defs; 387 ulong* value = &doc->config.value[ 0 ]; 388 for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal ) 389 { 390 assert( ixVal == (uint) option->id ); 391 CopyOptionValue( option, &value[ixVal], option->dflt ); 392 } 393 FreeDeclaredTags( doc, tagtype_null ); 394 } 395 396 void TakeConfigSnapshot( TidyDocImpl* doc ) 397 { 398 uint ixVal; 399 const TidyOptionImpl* option = option_defs; 400 ulong* value = &doc->config.value[ 0 ]; 401 ulong* snap = &doc->config.snapshot[ 0 ]; 402 403 AdjustConfig( doc ); /* Make sure it's consistent */ 404 for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal ) 405 { 406 assert( ixVal == (uint) option->id ); 407 CopyOptionValue( option, &snap[ixVal], value[ixVal] ); 408 } 409 } 410 411 void ResetConfigToSnapshot( TidyDocImpl* doc ) 412 { 413 uint ixVal; 414 const TidyOptionImpl* option = option_defs; 415 ulong* value = &doc->config.value[ 0 ]; 416 ulong* snap = &doc->config.snapshot[ 0 ]; 417 418 for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal ) 419 { 420 assert( ixVal == (uint) option->id ); 421 CopyOptionValue( option, &value[ixVal], snap[ixVal] ); 422 } 423 FreeDeclaredTags( doc, tagtype_null ); 424 ReparseTagDecls( doc ); 425 } 426 427 void CopyConfig( TidyDocImpl* docTo, TidyDocImpl* docFrom ) 428 { 429 if ( docTo != docFrom ) 430 { 431 uint ixVal; 432 const TidyOptionImpl* option = option_defs; 433 ulong* from = &docFrom->config.value[ 0 ]; 434 ulong* to = &docTo->config.value[ 0 ]; 435 436 TakeConfigSnapshot( docTo ); 437 for ( ixVal=0; ixVal < N_TIDY_OPTIONS; ++option, ++ixVal ) 438 { 439 assert( ixVal == (uint) option->id ); 440 CopyOptionValue( option, &to[ixVal], from[ixVal] ); 441 } 442 ReparseTagDecls( docTo ); 443 AdjustConfig( docTo ); /* Make sure it's consistent */ 444 } 445 } 446 447 448 #ifdef _DEBUG 449 450 /* Debug accessor functions will be type-safe and assert option type match */ 451 ulong _cfgGet( TidyDocImpl* doc, TidyOptionId optId ) 452 { 453 assert( optId < N_TIDY_OPTIONS ); 454 return doc->config.value[ optId ]; 455 } 456 457 Bool _cfgGetBool( TidyDocImpl* doc, TidyOptionId optId ) 458 { 459 ulong val = _cfgGet( doc, optId ); 460 const TidyOptionImpl* opt = &option_defs[ optId ]; 461 assert( opt && opt->type == TidyBoolean ); 462 return (Bool) val; 463 } 464 465 TidyTriState _cfgGetAutoBool( TidyDocImpl* doc, TidyOptionId optId ) 466 { 467 ulong val = _cfgGet( doc, optId ); 468 const TidyOptionImpl* opt = &option_defs[ optId ]; 469 assert( opt && opt->type == TidyInteger ); 470 return (TidyTriState) val; 471 } 472 473 ctmbstr _cfgGetString( TidyDocImpl* doc, TidyOptionId optId ) 474 { 475 ulong val = _cfgGet( doc, optId ); 476 const TidyOptionImpl* opt = &option_defs[ optId ]; 477 assert( opt && opt->type == TidyString ); 478 return (ctmbstr) val; 479 } 480 #endif 481 482 483 /* for use with Gnu Emacs */ 484 void SetEmacsFilename( TidyDocImpl* doc, ctmbstr filename ) 485 { 486 SetOptionValue( doc, TidyEmacsFile, filename ); 487 } 488 489 490 static tchar GetC( TidyConfigImpl* config ) 491 { 492 if ( config->cfgIn ) 493 return ReadChar( config->cfgIn ); 494 return EndOfStream; 495 } 496 497 static tchar FirstChar( TidyConfigImpl* config ) 498 { 499 config->c = GetC( config ); 500 return config->c; 501 } 502 503 static tchar AdvanceChar( TidyConfigImpl* config ) 504 { 505 if ( config->c != EndOfStream ) 506 config->c = GetC( config ); 507 return config->c; 508 } 509 510 static tchar SkipWhite( TidyConfigImpl* config ) 511 { 512 while ( IsWhite(config->c) && !IsNewline(config->c) ) 513 config->c = GetC( config ); 514 return config->c; 515 } 516 517 /* skip until end of line 518 static tchar SkipToEndofLine( TidyConfigImpl* config ) 519 { 520 while ( config->c != EndOfStream ) 521 { 522 config->c = GetC( config ); 523 if ( config->c == '\n' || config->c == '\r' ) 524 break; 525 } 526 return config->c; 527 } 528 */ 529 530 /* 531 skip over line continuations 532 to start of next property 533 */ 534 static uint NextProperty( TidyConfigImpl* config ) 535 { 536 do 537 { 538 /* skip to end of line */ 539 while ( config->c != '\n' && config->c != '\r' && config->c != EndOfStream ) 540 config->c = GetC( config ); 541 542 /* treat \r\n \r or \n as line ends */ 543 if ( config->c == '\r' ) 544 config->c = GetC( config ); 545 546 if ( config->c == '\n' ) 547 config->c = GetC( config ); 548 } 549 while ( IsWhite(config->c) ); /* line continuation? */ 550 551 return config->c; 552 } 553 554 /* 555 Todd Lewis contributed this code for expanding 556 ~/foo or ~your/foo according to $HOME and your 557 user name. This will work partially on any system 558 which defines $HOME. Support for ~user/foo will 559 work on systems that support getpwnam(userid), 560 namely Unix/Linux. 561 */ 562 ctmbstr ExpandTilde( ctmbstr filename ) 563 { 564 char *home_dir = NULL; 565 566 if ( !filename ) 567 return NULL; 568 569 if ( filename[0] != '~' ) 570 return filename; 571 572 if (filename[1] == '/') 573 { 574 home_dir = getenv("HOME"); 575 if ( home_dir ) 576 ++filename; 577 } 578 #ifdef SUPPORT_GETPWNAM 579 else 580 { 581 struct passwd *passwd = NULL; 582 ctmbstr s = filename + 1; 583 tmbstr t; 584 585 while ( *s && *s != '/' ) 586 s++; 587 588 if ( t = MemAlloc(s - filename) ) 589 { 590 memcpy(t, filename+1, s-filename-1); 591 t[s-filename-1] = 0; 592 593 passwd = getpwnam(t); 594 595 MemFree(t); 596 } 597 598 if ( passwd ) 599 { 600 filename = s; 601 home_dir = passwd->pw_dir; 602 } 603 } 604 #endif /* SUPPORT_GETPWNAM */ 605 606 if ( home_dir ) 607 { 608 uint len = tmbstrlen(filename) + tmbstrlen(home_dir) + 1; 609 tmbstr p = (tmbstr)MemAlloc( len ); 610 tmbstrcpy( p, home_dir ); 611 tmbstrcat( p, filename ); 612 return (ctmbstr) p; 613 } 614 return (ctmbstr) filename; 615 } 616 617 Bool TIDY_CALL tidyFileExists( ctmbstr filename ) 618 { 619 ctmbstr fname = (tmbstr) ExpandTilde( filename ); 620 #ifndef NO_ACCESS_SUPPORT 621 Bool exists = ( access(fname, 0) == 0 ); 622 #else 623 Bool exists; 624 /* at present */ 625 FILE* fin = fopen(fname, "r"); 626 if (fin != NULL) 627 fclose(fin); 628 exists = ( fin != NULL ); 629 #endif 630 if ( fname != filename ) 631 MemFree( (tmbstr) fname ); 632 return exists; 633 } 634 635 636 #ifndef TIDY_MAX_NAME 637 #define TIDY_MAX_NAME 64 638 #endif 639 640 int ParseConfigFile( TidyDocImpl* doc, ctmbstr file ) 641 { 642 return ParseConfigFileEnc( doc, file, "ascii" ); 643 } 644 645 /* open the file and parse its contents 646 */ 647 int ParseConfigFileEnc( TidyDocImpl* doc, ctmbstr file, ctmbstr charenc ) 648 { 649 uint opterrs = doc->optionErrors; 650 tmbstr fname = (tmbstr) ExpandTilde( file ); 651 TidyConfigImpl* cfg = &doc->config; 652 FILE* fin = fopen( fname, "r" ); 653 int enc = CharEncodingId( charenc ); 654 655 if ( fin == NULL || enc < 0 ) 656 { 657 FileError( doc, fname, TidyConfig ); 658 return -1; 659 } 660 else 661 { 662 tchar c; 663 cfg->cfgIn = FileInput( doc, fin, enc ); 664 c = FirstChar( cfg ); 665 666 for ( c = SkipWhite(cfg); c != EndOfStream; c = NextProperty(cfg) ) 667 { 668 uint ix = 0; 669 tmbchar name[ TIDY_MAX_NAME ] = {0}; 670 671 /* // or # start a comment */ 672 if ( c == '/' || c == '#' ) 673 continue; 674 675 while ( ix < sizeof(name)-1 && c != '\n' && c != EndOfStream && c != ':' ) 676 { 677 name[ ix++ ] = (tmbchar) c; /* Option names all ASCII */ 678 c = AdvanceChar( cfg ); 679 } 680 681 if ( c == ':' ) 682 { 683 const TidyOptionImpl* option = lookupOption( name ); 684 c = AdvanceChar( cfg ); 685 if ( option ) 686 option->parser( doc, option ); 687 else 688 { 689 if (NULL != doc->pOptCallback) 690 { 691 TidyConfigImpl* cfg = &doc->config; 692 tmbchar buf[8192]; 693 uint i = 0; 694 tchar delim = 0; 695 Bool waswhite = yes; 696 697 tchar c = SkipWhite( cfg ); 698 699 if ( c == '"' || c == '\'' ) 700 { 701 delim = c; 702 c = AdvanceChar( cfg ); 703 } 704 705 while ( i < sizeof(buf)-2 && c != EndOfStream && c != '\r' && c != '\n' ) 706 { 707 if ( delim && c == delim ) 708 break; 709 710 if ( IsWhite(c) ) 711 { 712 if ( waswhite ) 713 { 714 c = AdvanceChar( cfg ); 715 continue; 716 } 717 c = ' '; 718 } 719 else 720 waswhite = no; 721 722 buf[i++] = (tmbchar) c; 723 c = AdvanceChar( cfg ); 724 } 725 buf[i] = '\0'; 726 if (no == (*doc->pOptCallback)( name, buf )) 727 ReportUnknownOption( doc, name ); 728 } 729 else 730 ReportUnknownOption( doc, name ); 731 } 732 } 733 } 734 735 fclose( fin ); 736 MemFree( (void *)cfg->cfgIn->source.sourceData ); /* fix for bug #810259 */ 737 freeStreamIn( cfg->cfgIn ); 738 cfg->cfgIn = NULL; 739 } 740 741 if ( fname != (tmbstr) file ) 742 MemFree( fname ); 743 744 AdjustConfig( doc ); 745 746 /* any new config errors? If so, return warning status. */ 747 return (doc->optionErrors > opterrs ? 1 : 0); 748 } 749 750 /* returns false if unknown option, missing parameter, 751 ** or option doesn't use parameter 752 */ 753 Bool ParseConfigOption( TidyDocImpl* doc, ctmbstr optnam, ctmbstr optval ) 754 { 755 const TidyOptionImpl* option = lookupOption( optnam ); 756 Bool status = ( option != NULL ); 757 if ( !status ) 758 { 759 /* Not a standard tidy option. Check to see if the user application 760 recognizes it */ 761 if (NULL != doc->pOptCallback) 762 status = (*doc->pOptCallback)( optnam, optval ); 763 if (!status) 764 ReportUnknownOption( doc, optnam ); 765 } 766 else 767 status = ParseConfigValue( doc, option->id, optval ); 768 return status; 769 } 770 771 /* returns false if unknown option, missing parameter, 772 ** or option doesn't use parameter 773 */ 774 Bool ParseConfigValue( TidyDocImpl* doc, TidyOptionId optId, ctmbstr optval ) 775 { 776 const TidyOptionImpl* option = option_defs + optId; 777 Bool status = ( optId < N_TIDY_OPTIONS && optval != NULL ); 778 779 if ( !status ) 780 ReportBadArgument( doc, option->name ); 781 else 782 { 783 TidyBuffer inbuf = {0}; /* Set up input source */ 784 tidyBufAttach( &inbuf, (byte*)optval, tmbstrlen(optval)+1 ); 785 doc->config.cfgIn = BufferInput( doc, &inbuf, ASCII ); 786 doc->config.c = GetC( &doc->config ); 787 788 status = option->parser( doc, option ); 789 790 freeStreamIn(doc->config.cfgIn); /* Release input source */ 791 doc->config.cfgIn = NULL; 792 tidyBufDetach( &inbuf ); 793 } 794 return status; 795 } 796 797 798 /* ensure that char encodings are self consistent */ 799 Bool AdjustCharEncoding( TidyDocImpl* doc, int encoding ) 800 { 801 int outenc = -1; 802 int inenc = -1; 803 804 switch( encoding ) 805 { 806 case MACROMAN: 807 inenc = MACROMAN; 808 outenc = ASCII; 809 break; 810 811 case WIN1252: 812 inenc = WIN1252; 813 outenc = ASCII; 814 break; 815 816 case IBM858: 817 inenc = IBM858; 818 outenc = ASCII; 819 break; 820 821 case ASCII: 822 inenc = LATIN1; 823 outenc = ASCII; 824 break; 825 826 case LATIN0: 827 inenc = LATIN0; 828 outenc = ASCII; 829 break; 830 831 case RAW: 832 case LATIN1: 833 case UTF8: 834 #ifndef NO_NATIVE_ISO2022_SUPPORT 835 case ISO2022: 836 #endif 837 838 #if SUPPORT_UTF16_ENCODINGS 839 case UTF16LE: 840 case UTF16BE: 841 case UTF16: 842 #endif 843 #if SUPPORT_ASIAN_ENCODINGS 844 case SHIFTJIS: 845 case BIG5: 846 #endif 847 inenc = outenc = encoding; 848 break; 849 } 850 851 if ( inenc >= 0 ) 852 { 853 SetOptionInt( doc, TidyCharEncoding, encoding ); 854 SetOptionInt( doc, TidyInCharEncoding, inenc ); 855 SetOptionInt( doc, TidyOutCharEncoding, outenc ); 856 return yes; 857 } 858 return no; 859 } 860 861 /* ensure that config is self consistent */ 862 void AdjustConfig( TidyDocImpl* doc ) 863 { 864 if ( cfgBool(doc, TidyEncloseBlockText) ) 865 SetOptionBool( doc, TidyEncloseBodyText, yes ); 866 867 if ( cfgAutoBool(doc, TidyIndentContent) == TidyNoState ) 868 SetOptionInt( doc, TidyIndentSpaces, 0 ); 869 870 /* disable wrapping */ 871 if ( cfg(doc, TidyWrapLen) == 0 ) 872 SetOptionInt( doc, TidyWrapLen, 0x7FFFFFFF ); 873 874 /* Word 2000 needs o:p to be declared as inline */ 875 if ( cfgBool(doc, TidyWord2000) ) 876 { 877 doc->config.defined_tags |= tagtype_inline; 878 DefineTag( doc, tagtype_inline, "o:p" ); 879 } 880 881 /* #480701 disable XHTML output flag if both output-xhtml and xml input are set */ 882 if ( cfgBool(doc, TidyXmlTags) ) 883 SetOptionBool( doc, TidyXhtmlOut, no ); 884 885 /* XHTML is written in lower case */ 886 if ( cfgBool(doc, TidyXhtmlOut) ) 887 { 888 SetOptionBool( doc, TidyXmlOut, yes ); 889 SetOptionBool( doc, TidyUpperCaseTags, no ); 890 SetOptionBool( doc, TidyUpperCaseAttrs, no ); 891 /* SetOptionBool( doc, TidyXmlPIs, yes ); */ 892 } 893 894 /* if XML in, then XML out */ 895 if ( cfgBool(doc, TidyXmlTags) ) 896 { 897 SetOptionBool( doc, TidyXmlOut, yes ); 898 SetOptionBool( doc, TidyXmlPIs, yes ); 899 } 900 901 /* #427837 - fix by Dave Raggett 02 Jun 01 902 ** generate <?xml version="1.0" encoding="iso-8859-1"?> 903 ** if the output character encoding is Latin-1 etc. 904 */ 905 if ( cfg(doc, TidyOutCharEncoding) != ASCII && 906 cfg(doc, TidyOutCharEncoding) != UTF8 && 907 #if SUPPORT_UTF16_ENCODINGS 908 cfg(doc, TidyOutCharEncoding) != UTF16 && 909 cfg(doc, TidyOutCharEncoding) != UTF16BE && 910 cfg(doc, TidyOutCharEncoding) != UTF16LE && 911 #endif 912 cfg(doc, TidyOutCharEncoding) != RAW && 913 cfgBool(doc, TidyXmlOut) ) 914 { 915 SetOptionBool( doc, TidyXmlDecl, yes ); 916 } 917 918 /* XML requires end tags */ 919 if ( cfgBool(doc, TidyXmlOut) ) 920 { 921 #if SUPPORT_UTF16_ENCODINGS 922 /* XML requires a BOM on output if using UTF-16 encoding */ 923 ulong enc = cfg( doc, TidyOutCharEncoding ); 924 if ( enc == UTF16LE || enc == UTF16BE || enc == UTF16 ) 925 SetOptionInt( doc, TidyOutputBOM, yes ); 926 #endif 927 SetOptionBool( doc, TidyQuoteAmpersand, yes ); 928 SetOptionBool( doc, TidyHideEndTags, no ); 929 } 930 } 931 932 /* unsigned integers */ 933 Bool ParseInt( TidyDocImpl* doc, const TidyOptionImpl* entry ) 934 { 935 ulong number = 0; 936 Bool digits = no; 937 TidyConfigImpl* cfg = &doc->config; 938 tchar c = SkipWhite( cfg ); 939 940 while ( IsDigit(c) ) 941 { 942 number = c - '' + (10 * number); 943 digits = yes; 944 c = AdvanceChar( cfg ); 945 } 946 947 if ( !digits ) 948 ReportBadArgument( doc, entry->name ); 949 else 950 SetOptionInt( doc, entry->id, number ); 951 return digits; 952 } 953 954 /* true/false or yes/no or 0/1 or "auto" only looks at 1st char */ 955 static Bool ParseTriState( TidyTriState theState, TidyDocImpl* doc, 956 const TidyOptionImpl* entry, ulong* flag ) 957 { 958 TidyConfigImpl* cfg = &doc->config; 959 tchar c = SkipWhite( cfg ); 960 961 if (c == 't' || c == 'T' || c == 'y' || c == 'Y' || c == '1') 962 *flag = yes; 963 else if (c == 'f' || c == 'F' || c == 'n' || c == 'N' || c == '') 964 *flag = no; 965 else if (theState == TidyAutoState && (c == 'a' || c =='A')) 966 *flag = TidyAutoState; 967 else 968 { 969 ReportBadArgument( doc, entry->name ); 970 return no; 971 } 972 973 return yes; 974 } 975 976 /* cr, lf or crlf */ 977 Bool ParseNewline( TidyDocImpl* doc, const TidyOptionImpl* entry ) 978 { 979 int nl = -1; 980 tmbchar work[ 16 ] = {0}; 981 tmbstr cp = work, end = work + sizeof(work); 982 TidyConfigImpl* cfg = &doc->config; 983 tchar c = SkipWhite( cfg ); 984 985 while ( c!=EndOfStream && cp < end && !IsWhite(c) && c != '\r' && c != '\n' ) 986 { 987 *cp++ = (tmbchar) c; 988 c = AdvanceChar( cfg ); 989 } 990 *cp = 0; 991 992 if ( tmbstrcasecmp(work, "lf") == 0 ) 993 nl = TidyLF; 994 else if ( tmbstrcasecmp(work, "crlf") == 0 ) 995 nl = TidyCRLF; 996 else if ( tmbstrcasecmp(work, "cr") == 0 ) 997 nl = TidyCR; 998 999 if ( nl < TidyLF || nl > TidyCR ) 1000 ReportBadArgument( doc, entry->name ); 1001 else 1002 SetOptionInt( doc, entry->id, nl ); 1003 return ( nl >= TidyLF && nl <= TidyCR ); 1004 } 1005 1006 Bool ParseBool( TidyDocImpl* doc, const TidyOptionImpl* entry ) 1007 { 1008 ulong flag = 0; 1009 Bool status = ParseTriState( TidyNoState, doc, entry, &flag ); 1010 if ( status ) 1011 SetOptionBool( doc, entry->id, flag != 0 ); 1012 return status; 1013 } 1014 1015 Bool ParseAutoBool( TidyDocImpl* doc, const TidyOptionImpl* entry ) 1016 { 1017 ulong flag = 0; 1018 Bool status = ParseTriState( TidyAutoState, doc, entry, &flag ); 1019 if ( status ) 1020 SetOptionInt( doc, entry->id, flag ); 1021 return status; 1022 } 1023 1024 /* a string excluding whitespace */ 1025 Bool ParseName( TidyDocImpl* doc, const TidyOptionImpl* option ) 1026 { 1027 tmbchar buf[ 1024 ] = {0}; 1028 uint i = 0; 1029 uint c = SkipWhite( &doc->config ); 1030 1031 while ( i < sizeof(buf)-2 && c != EndOfStream && !IsWhite(c) ) 1032 { 1033 buf[i++] = (tmbchar) c; 1034 c = AdvanceChar( &doc->config ); 1035 } 1036 buf[i] = 0; 1037 1038 if ( i == 0 ) 1039 ReportBadArgument( doc, option->name ); 1040 else 1041 SetOptionValue( doc, option->id, buf ); 1042 return ( i > 0 ); 1043 } 1044 1045 /* #508936 - CSS class naming for -clean option */ 1046 Bool ParseCSS1Selector( TidyDocImpl* doc, const TidyOptionImpl* option ) 1047 { 1048 char buf[256] = {0}; 1049 uint i = 0; 1050 uint c = SkipWhite( &doc->config ); 1051 1052 while ( i < sizeof(buf)-2 && c != EndOfStream && !IsWhite(c) ) 1053 { 1054 buf[i++] = (tmbchar) c; 1055 c = AdvanceChar( &doc->config ); 1056 } 1057 buf[i] = '\0'; 1058 1059 if ( i == 0 || !IsCSS1Selector(buf) ) { 1060 ReportBadArgument( doc, option->name ); 1061 return no; 1062 } 1063 1064 buf[i++] = '-'; /* Make sure any escaped Unicode is terminated */ 1065 buf[i] = 0; /* so valid class names are generated after */ 1066 /* Tidy appends last digits. */ 1067 1068 SetOptionValue( doc, option->id, buf ); 1069 return yes; 1070 } 1071 1072 /* Coordinates Config update and Tags data */ 1073 static void DeclareUserTag( TidyDocImpl* doc, TidyOptionId optId, 1074 UserTagType tagType, ctmbstr name ) 1075 { 1076 ctmbstr prvval = cfgStr( doc, optId ); 1077 tmbstr catval = NULL; 1078 ctmbstr theval = name; 1079 if ( prvval ) 1080 { 1081 uint len = tmbstrlen(name) + tmbstrlen(prvval) + 3; 1082 catval = tmbstrndup( prvval, len ); 1083 tmbstrcat( catval, ", " ); 1084 tmbstrcat( catval, name ); 1085 theval = catval; 1086 } 1087 DefineTag( doc, tagType, name ); 1088 SetOptionValue( doc, optId, theval ); 1089 if ( catval ) 1090 MemFree( catval ); 1091 } 1092 1093 /* a space or comma separated list of tag names */ 1094 Bool ParseTagNames( TidyDocImpl* doc, const TidyOptionImpl* option ) 1095 { 1096 TidyConfigImpl* cfg = &doc->config; 1097 tmbchar buf[1024]; 1098 uint i = 0, nTags = 0; 1099 uint c = SkipWhite( cfg ); 1100 UserTagType ttyp = tagtype_null; 1101 1102 switch ( option->id ) 1103 { 1104 case TidyInlineTags: ttyp = tagtype_inline; break; 1105 case TidyBlockTags: ttyp = tagtype_block; break; 1106 case TidyEmptyTags: ttyp = tagtype_empty; break; 1107 case TidyPreTags: ttyp = tagtype_pre; break; 1108 default: 1109 ReportUnknownOption( doc, option->name ); 1110 return no; 1111 } 1112 1113 SetOptionValue( doc, option->id, NULL ); 1114 FreeDeclaredTags( doc, ttyp ); 1115 cfg->defined_tags |= ttyp; 1116 1117 do 1118 { 1119 if (c == ' ' || c == '\t' || c == ',') 1120 { 1121 c = AdvanceChar( cfg ); 1122 continue; 1123 } 1124 1125 if ( c == '\r' || c == '\n' ) 1126 { 1127 uint c2 = AdvanceChar( cfg ); 1128 if ( c == '\r' && c2 == '\n' ) 1129 c = AdvanceChar( cfg ); 1130 else 1131 c = c2; 1132 1133 if ( !IsWhite(c) ) 1134 { 1135 buf[i] = 0; 1136 UngetChar( c, cfg->cfgIn ); 1137 UngetChar( '\n', cfg->cfgIn ); 1138 break; 1139 } 1140 } 1141 1142 /* 1143 if ( c == '\n' ) 1144 { 1145 c = AdvanceChar( cfg ); 1146 if ( !IsWhite(c) ) 1147 { 1148 buf[i] = 0; 1149 UngetChar( c, cfg->cfgIn ); 1150 UngetChar( '\n', cfg->cfgIn ); 1151 break; 1152 } 1153 } 1154 */ 1155 1156 while ( i < sizeof(buf)-2 && c != EndOfStream && !IsWhite(c) && c != ',' ) 1157 { 1158 buf[i++] = (tmbchar) c; 1159 c = AdvanceChar( cfg ); 1160 } 1161 1162 buf[i] = '\0'; 1163 if (i == 0) /* Skip empty tag definition. Possible when */ 1164 continue; /* there is a trailing space on the line. */ 1165 1166 /* add tag to dictionary */ 1167 DeclareUserTag( doc, option->id, ttyp, buf ); 1168 i = 0; 1169 ++nTags; 1170 } 1171 while ( c != EndOfStream ); 1172 1173 if ( i > 0 ) 1174 DeclareUserTag( doc, option->id, ttyp, buf ); 1175 return ( nTags > 0 ); 1176 } 1177 1178 /* a string including whitespace */ 1179 /* munges whitespace sequences */ 1180 1181 Bool ParseString( TidyDocImpl* doc, const TidyOptionImpl* option ) 1182 { 1183 TidyConfigImpl* cfg = &doc->config; 1184 tmbchar buf[8192]; 1185 uint i = 0; 1186 tchar delim = 0; 1187 Bool waswhite = yes; 1188 1189 tchar c = SkipWhite( cfg ); 1190 1191 if ( c == '"' || c == '\'' ) 1192 { 1193 delim = c; 1194 c = AdvanceChar( cfg ); 1195 } 1196 1197 while ( i < sizeof(buf)-2 && c != EndOfStream && c != '\r' && c != '\n' ) 1198 { 1199 if ( delim && c == delim ) 1200 break; 1201 1202 if ( IsWhite(c) ) 1203 { 1204 if ( waswhite ) 1205 { 1206 c = AdvanceChar( cfg ); 1207 continue; 1208 } 1209 c = ' '; 1210 } 1211 else 1212 waswhite = no; 1213 1214 buf[i++] = (tmbchar) c; 1215 c = AdvanceChar( cfg ); 1216 } 1217 buf[i] = '\0'; 1218 1219 SetOptionValue( doc, option->id, buf ); 1220 return yes; 1221 } 1222 1223 Bool ParseCharEnc( TidyDocImpl* doc, const TidyOptionImpl* option ) 1224 { 1225 tmbchar buf[64] = {0}; 1226 uint i = 0; 1227 int enc = ASCII; 1228 Bool validEncoding = yes; 1229 tchar c = SkipWhite( &doc->config ); 1230 1231 while ( i < sizeof(buf)-2 && c != EndOfStream && !IsWhite(c) ) 1232 { 1233 buf[i++] = (tmbchar) ToLower( c ); 1234 c = AdvanceChar( &doc->config ); 1235 } 1236 buf[i] = 0; 1237 1238 enc = CharEncodingId( buf ); 1239 1240 #ifdef TIDY_WIN32_MLANG_SUPPORT 1241 /* limit support to --input-encoding */ 1242 if (option->id != TidyInCharEncoding && enc > WIN32MLANG) 1243 enc = -1; 1244 #endif 1245 1246 if ( enc < 0 ) 1247 { 1248 validEncoding = no; 1249 ReportBadArgument( doc, option->name ); 1250 } 1251 else 1252 SetOptionInt( doc, option->id, enc ); 1253 1254 if ( validEncoding && option->id == TidyCharEncoding ) 1255 AdjustCharEncoding( doc, enc ); 1256 return validEncoding; 1257 } 1258 1259 1260 int CharEncodingId( ctmbstr charenc ) 1261 { 1262 int enc = GetCharEncodingFromOptName( charenc ); 1263 1264 #ifdef TIDY_WIN32_MLANG_SUPPORT 1265 if (enc == -1) 1266 { 1267 uint wincp = Win32MLangGetCPFromName(charenc); 1268 if (wincp) 1269 enc = wincp; 1270 } 1271 #endif 1272 1273 return enc; 1274 } 1275 1276 ctmbstr CharEncodingName( int encoding ) 1277 { 1278 ctmbstr encodingName = GetEncodingNameFromTidyId(encoding); 1279 1280 if (!encodingName) 1281 encodingName = "unknown"; 1282 1283 return encodingName; 1284 } 1285 1286 ctmbstr CharEncodingOptName( int encoding ) 1287 { 1288 ctmbstr encodingName = GetEncodingOptNameFromTidyId(encoding); 1289 1290 if (!encodingName) 1291 encodingName = "unknown"; 1292 1293 return encodingName; 1294 } 1295 1296 /* 1297 doctype: omit | auto | strict | loose | <fpi> 1298 1299 where the fpi is a string similar to 1300 1301 "-//ACME//DTD HTML 3.14159//EN" 1302 */ 1303 Bool ParseDocType( TidyDocImpl* doc, const TidyOptionImpl* option ) 1304 { 1305 tmbchar buf[ 32 ] = {0}; 1306 uint i = 0; 1307 Bool status = yes; 1308 TidyDoctypeModes dtmode = TidyDoctypeAuto; 1309 1310 TidyConfigImpl* cfg = &doc->config; 1311 tchar c = SkipWhite( cfg ); 1312 1313 /* "-//ACME//DTD HTML 3.14159//EN" or similar */ 1314 1315 if ( c == '"' || c == '\'' ) 1316 { 1317 status = ParseString(doc, option); 1318 if (status) 1319 SetOptionInt( doc, TidyDoctypeMode, TidyDoctypeUser ); 1320 1321 return status; 1322 } 1323 1324 /* read first word */ 1325 while ( i < sizeof(buf)-1 && c != EndOfStream && !IsWhite(c) ) 1326 { 1327 buf[i++] = (tmbchar) c; 1328 c = AdvanceChar( cfg ); 1329 } 1330 buf[i] = '\0'; 1331 1332 if ( tmbstrcasecmp(buf, "auto") == 0 ) 1333 dtmode = TidyDoctypeAuto; 1334 else if ( tmbstrcasecmp(buf, "omit") == 0 ) 1335 dtmode = TidyDoctypeOmit; 1336 else if ( tmbstrcasecmp(buf, "strict") == 0 ) 1337 dtmode = TidyDoctypeStrict; 1338 else if ( tmbstrcasecmp(buf, "loose") == 0 || 1339 tmbstrcasecmp(buf, "transitional") == 0 ) 1340 dtmode = TidyDoctypeLoose; 1341 else 1342 { 1343 ReportBadArgument( doc, option->name ); 1344 status = no; 1345 } 1346 1347 if ( status ) 1348 SetOptionInt( doc, TidyDoctypeMode, dtmode ); 1349 return status; 1350 } 1351 1352 Bool ParseRepeatAttr( TidyDocImpl* doc, const TidyOptionImpl* option ) 1353 { 1354 Bool status = yes; 1355 tmbchar buf[64] = {0}; 1356 uint i = 0; 1357 1358 TidyConfigImpl* cfg = &doc->config; 1359 tchar c = SkipWhite( cfg ); 1360 1361 while (i < sizeof(buf)-1 && c != EndOfStream && !IsWhite(c)) 1362 { 1363 buf[i++] = (tmbchar) c; 1364 c = AdvanceChar( cfg ); 1365 } 1366 buf[i] = '\0'; 1367 1368 if ( tmbstrcasecmp(buf, "keep-first") == 0 ) 1369 cfg->value[ TidyDuplicateAttrs ] = TidyKeepFirst; 1370 else if ( tmbstrcasecmp(buf, "keep-last") == 0 ) 1371 cfg->value[ TidyDuplicateAttrs ] = TidyKeepLast; 1372 else 1373 { 1374 ReportBadArgument( doc, option->name ); 1375 status = no; 1376 } 1377 return status; 1378 } 1379 1380 /* Use TidyOptionId as iterator. 1381 ** Send index of 1st option after TidyOptionUnknown as start of list. 1382 */ 1383 TidyIterator getOptionList( TidyDocImpl* ARG_UNUSED(doc) ) 1384 { 1385 return (TidyIterator) 1; 1386 } 1387 1388 /* Check if this item is last valid option. 1389 ** If so, zero out iterator. 1390 */ 1391 const TidyOptionImpl* getNextOption( TidyDocImpl* ARG_UNUSED(doc), 1392 TidyIterator* iter ) 1393 { 1394 const TidyOptionImpl* option = NULL; 1395 ulong optId; 1396 assert( iter != NULL ); 1397 optId = (ulong) *iter; 1398 if ( optId > TidyUnknownOption && optId < N_TIDY_OPTIONS ) 1399 { 1400 option = &option_defs[ optId ]; 1401 optId++; 1402 } 1403 *iter = (TidyIterator) ( optId < N_TIDY_OPTIONS ? optId : 0 ); 1404 return option; 1405 } 1406 1407 /* Use a 1-based array index as iterator: 0 == end-of-list 1408 */ 1409 TidyIterator getOptionPickList( const TidyOptionImpl* option ) 1410 { 1411 ulong ix = 0; 1412 if ( option && option->pickList ) 1413 ix = 1; 1414 return (TidyIterator) ix; 1415 } 1416 1417 ctmbstr getNextOptionPick( const TidyOptionImpl* option, 1418 TidyIterator* iter ) 1419 { 1420 ulong ix; 1421 ctmbstr val = NULL; 1422 assert( option!=NULL && iter != NULL ); 1423 1424 ix = (ulong) *iter; 1425 if ( ix > 0 && ix < 16 && option->pickList ) 1426 val = option->pickList[ ix-1 ]; 1427 *iter = (TidyIterator) ( val && option->pickList[ix] ? ix + 1 : 0 ); 1428 return val; 1429 } 1430 1431 static int WriteOptionString( const TidyOptionImpl* option, 1432 ctmbstr sval, StreamOut* out ) 1433 { 1434 ctmbstr cp = option->name; 1435 while ( *cp ) 1436 WriteChar( *cp++, out ); 1437 WriteChar( ':', out ); 1438 WriteChar( ' ', out ); 1439 cp = sval; 1440 while ( *cp ) 1441 WriteChar( *cp++, out ); 1442 WriteChar( '\n', out ); 1443 return 0; 1444 } 1445 1446 static int WriteOptionInt( const TidyOptionImpl* option, uint ival, StreamOut* out ) 1447 { 1448 tmbchar sval[ 32 ] = {0}; 1449 tmbsnprintf(sval, sizeof(sval), "%u", ival ); 1450 return WriteOptionString( option, sval, out ); 1451 } 1452 1453 static int WriteOptionBool( const TidyOptionImpl* option, Bool bval, StreamOut* out ) 1454 { 1455 ctmbstr sval = bval ? "yes" : "no"; 1456 return WriteOptionString( option, sval, out ); 1457 } 1458 1459 static int WriteOptionPick( const TidyOptionImpl* option, uint ival, StreamOut* out ) 1460 { 1461 uint ix; 1462 const ctmbstr* val = option->pickList; 1463 for ( ix=0; val[ix] && ix<ival; ++ix ) 1464 /**/; 1465 if ( ix==ival && val[ix] ) 1466 return WriteOptionString( option, val[ix], out ); 1467 return -1; 1468 } 1469 1470 Bool ConfigDiffThanSnapshot( TidyDocImpl* doc ) 1471 { 1472 int diff = memcmp( &doc->config.value, &doc->config.snapshot, 1473 N_TIDY_OPTIONS * sizeof(uint) ); 1474 return ( diff != 0 ); 1475 } 1476 1477 Bool ConfigDiffThanDefault( TidyDocImpl* doc ) 1478 { 1479 Bool diff = no; 1480 const TidyOptionImpl* option = option_defs + 1; 1481 ulong* ival = doc->config.value; 1482 for ( /**/; !diff && option && option->name; ++option, ++ival ) 1483 { 1484 diff = ( *ival != option->dflt ); 1485 } 1486 return diff; 1487 } 1488 1489 1490 static int SaveConfigToStream( TidyDocImpl* doc, StreamOut* out ) 1491 { 1492 int rc = 0; 1493 const TidyOptionImpl* option; 1494 for ( option=option_defs+1; 0==rc && option && option->name; ++option ) 1495 { 1496 ulong ival = doc->config.value[ option->id ]; 1497 if ( option->parser == NULL ) 1498 continue; 1499 if ( ival == option->dflt && option->id != TidyDoctype) 1500 continue; 1501 1502 if ( option->id == TidyDoctype ) /* Special case */ 1503 { 1504 ulong dtmode = cfg( doc, TidyDoctypeMode ); 1505 if ( dtmode == TidyDoctypeUser ) 1506 { 1507 tmbstr t; 1508 1509 /* add 2 double quotes */ 1510 if (( t = (tmbstr)MemAlloc( tmbstrlen( (ctmbstr)ival) + 2 ) )) 1511 { 1512 t[0] = '\"'; t[1] = 0; 1513 1514 tmbstrcat( t, (ctmbstr)ival ); 1515 tmbstrcat( t, "\"" ); 1516 rc = WriteOptionString( option, (ctmbstr)t, out ); 1517 1518 MemFree( t ); 1519 } 1520 } 1521 else if ( dtmode == option_defs[TidyDoctypeMode].dflt ) 1522 continue; 1523 else 1524 rc = WriteOptionPick( option, dtmode, out ); 1525 } 1526 else if ( option->pickList ) 1527 rc = WriteOptionPick( option, ival, out ); 1528 else 1529 { 1530 switch ( option->type ) 1531 { 1532 case TidyString: 1533 rc = WriteOptionString( option, (ctmbstr) ival, out ); 1534 break; 1535 case TidyInteger: 1536 rc = WriteOptionInt( option, ival, out ); 1537 break; 1538 case TidyBoolean: 1539 rc = WriteOptionBool( option, ival ? yes : no, out ); 1540 break; 1541 } 1542 } 1543 } 1544 return rc; 1545 } 1546 1547 int SaveConfigFile( TidyDocImpl* doc, ctmbstr cfgfil ) 1548 { 1549 int status = -1; 1550 StreamOut* out = NULL; 1551 uint outenc = cfg( doc, TidyOutCharEncoding ); 1552 uint nl = cfg( doc, TidyNewline ); 1553 FILE* fout = fopen( cfgfil, "wb" ); 1554 if ( fout ) 1555 { 1556 out = FileOutput( fout, outenc, nl ); 1557 status = SaveConfigToStream( doc, out ); 1558 fclose( fout ); 1559 MemFree( out ); 1560 } 1561 return status; 1562 } 1563 1564 int SaveConfigSink( TidyDocImpl* doc, TidyOutputSink* sink ) 1565 { 1566 uint outenc = cfg( doc, TidyOutCharEncoding ); 1567 uint nl = cfg( doc, TidyNewline ); 1568 StreamOut* out = UserOutput( sink, outenc, nl ); 1569 int status = SaveConfigToStream( doc, out ); 1570 MemFree( out ); 1571 return status; 1572 } 1573

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.