/* tidylib.c -- internal library definitions (c) 1998-2008 (W3C) MIT, ERCIM, Keio University See tidy.h for the copyright notice. Defines HTML Tidy API implemented by tidy library. Very rough initial cut for discussion purposes. Public interface is const-correct and doesn't explicitly depend on any globals. Thus, thread-safety may be introduced w/out changing the interface. Looking ahead to a C++ wrapper, C functions always pass this-equivalent as 1st arg. Created 2001-05-20 by Charles Reitzel */ #include "third_party/tidy/tidy-int.h" #include "third_party/tidy/parser.h" #include "third_party/tidy/clean.h" #include "third_party/tidy/gdoc.h" #include "third_party/tidy/config.h" #include "third_party/tidy/message.h" #include "third_party/tidy/messageobj.h" #include "third_party/tidy/pprint.h" #include "third_party/tidy/entities.h" #include "third_party/tidy/tmbstr.h" #include "third_party/tidy/utf8.h" #include "third_party/tidy/mappedio.h" #include "third_party/tidy/language.h" #include "third_party/tidy/attrs.h" #include "libc/assert.h" #include "libc/errno.h" #include "libc/calls/struct/stat.h" #include "libc/sysv/consts/s.h" #include "libc/time.h" #include "third_party/tidy/sprtf.h" /* Create/Destroy a Tidy "document" object */ static TidyDocImpl* tidyDocCreate( TidyAllocator *allocator ); static void tidyDocRelease( TidyDocImpl* impl ); static int tidyDocStatus( TidyDocImpl* impl ); /* Parse Markup */ static int tidyDocParseFile( TidyDocImpl* impl, ctmbstr htmlfil ); static int tidyDocParseStdin( TidyDocImpl* impl ); static int tidyDocParseString( TidyDocImpl* impl, ctmbstr content ); static int tidyDocParseBuffer( TidyDocImpl* impl, TidyBuffer* inbuf ); static int tidyDocParseSource( TidyDocImpl* impl, TidyInputSource* docIn ); /* Execute post-parse diagnostics and cleanup. ** Note, the order is important. You will get different ** results from the diagnostics depending on if they are run ** pre-or-post repair. */ static int tidyDocRunDiagnostics( TidyDocImpl* doc ); static void tidyDocReportDoctype( TidyDocImpl* doc ); static int tidyDocCleanAndRepair( TidyDocImpl* doc ); /* Save cleaned up file to file/buffer/sink */ static int tidyDocSaveFile( TidyDocImpl* impl, ctmbstr htmlfil ); static int tidyDocSaveStdout( TidyDocImpl* impl ); static int tidyDocSaveString( TidyDocImpl* impl, tmbstr buffer, uint* buflen ); static int tidyDocSaveBuffer( TidyDocImpl* impl, TidyBuffer* outbuf ); static int tidyDocSaveSink( TidyDocImpl* impl, TidyOutputSink* docOut ); static int tidyDocSaveStream( TidyDocImpl* impl, StreamOut* out ); /* Tidy public interface ** ** Most functions return an integer: ** ** 0 -> SUCCESS ** >0 -> WARNING ** <0 -> ERROR ** */ TidyDoc tidyCreate(void) { TidyDocImpl* impl = tidyDocCreate( &TY_(g_default_allocator) ); return tidyImplToDoc( impl ); } TidyDoc tidyCreateWithAllocator( TidyAllocator *allocator ) { TidyDocImpl* impl = tidyDocCreate( allocator ); return tidyImplToDoc( impl ); } void tidyRelease( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); tidyDocRelease( impl ); } TidyDocImpl* tidyDocCreate( TidyAllocator *allocator ) { TidyDocImpl* doc = (TidyDocImpl*)TidyAlloc( allocator, sizeof(TidyDocImpl) ); TidyClearMemory( doc, sizeof(*doc) ); doc->allocator = allocator; TY_(InitMap)(); TY_(InitTags)( doc ); TY_(InitAttrs)( doc ); TY_(InitConfig)( doc ); TY_(InitPrintBuf)( doc ); TY_(InitParserStack)( doc ); /* Set the locale for tidy's output. This both configures ** LibTidy to use the environment's locale as well as the ** standard library. */ #if SUPPORT_LOCALIZATIONS if ( TY_(tidyGetLanguageSetByUser)() == no ) { if( ! TY_(tidySetLanguage)( getenv( "LC_MESSAGES" ) ) ) { if( ! TY_(tidySetLanguage)( getenv( "LANG" ) ) ) { /*\ * Is. #770 #783 #780 #790 and maybe others - * TY_(tidySetLanguage)( setlocale( LC_ALL, "" ) ); * this seems a 'bad' choice! \*/ } } } #endif /* By default, wire tidy messages to standard error. ** Document input will be set by parsing routines. ** Document output will be set by pretty print routines. ** Config input will be set by config parsing routines. ** But we need to start off with a way to report errors. */ doc->errout = TY_(StdErrOutput)(); return doc; } void tidyDocRelease( TidyDocImpl* doc ) { /* doc in/out opened and closed by parse/print routines */ if ( doc ) { assert( doc->docIn == NULL ); assert( doc->docOut == NULL ); TY_(ReleaseStreamOut)( doc, doc->errout ); doc->errout = NULL; TY_(FreePrintBuf)( doc ); TY_(FreeNode)(doc, &doc->root); TidyClearMemory(&doc->root, sizeof(Node)); if (doc->givenDoctype) TidyDocFree(doc, doc->givenDoctype); TY_(FreeConfig)( doc ); TY_(FreeAttrTable)( doc ); TY_(FreeAttrPriorityList)( doc ); TY_(FreeMutedMessageList( doc )); TY_(FreeTags)( doc ); /*\ * Issue #186 - Now FreeNode depend on the doctype, so the lexer is needed * to determine which hash is to be used, so free it last. \*/ TY_(FreeLexer)( doc ); TY_(FreeParserStack)( doc ); TidyDocFree( doc, doc ); } } /* Let application store a chunk of data w/ each Tidy tdocance. ** Useful for callbacks. */ void tidySetAppData( TidyDoc tdoc, void* appData ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) impl->appData = appData; } void* tidyGetAppData( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return impl->appData; return NULL; } ctmbstr tidyReleaseDate(void) { return TY_(ReleaseDate)(); } ctmbstr tidyLibraryVersion(void) { return TY_(tidyLibraryVersion)(); } ctmbstr tidyPlatform(void) { #ifdef PLATFORM_NAME return PLATFORM_NAME; #else return NULL; #endif } /* Get/set configuration options */ Bool tidySetOptionCallback( TidyDoc tdoc, TidyOptCallback pOptCallback ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->pOptCallback = pOptCallback; return yes; } return no; } Bool tidySetConfigCallback(TidyDoc tdoc, TidyConfigCallback pConfigCallback) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->pConfigCallback = pConfigCallback; return yes; } return no; } Bool tidySetConfigChangeCallback(TidyDoc tdoc, TidyConfigChangeCallback pCallback) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->pConfigChangeCallback = pCallback; return yes; } return no; } int tidyLoadConfig( TidyDoc tdoc, ctmbstr cfgfil ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ParseConfigFile)( impl, cfgfil ); return -EINVAL; } int tidyLoadConfigEnc( TidyDoc tdoc, ctmbstr cfgfil, ctmbstr charenc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ParseConfigFileEnc)( impl, cfgfil, charenc ); return -EINVAL; } int tidySetCharEncoding( TidyDoc tdoc, ctmbstr encnam ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { int enc = TY_(CharEncodingId)( impl, encnam ); if ( enc >= 0 && TY_(AdjustCharEncoding)(impl, enc) ) return 0; TY_(ReportBadArgument)( impl, "char-encoding" ); } return -EINVAL; } int tidySetInCharEncoding( TidyDoc tdoc, ctmbstr encnam ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { int enc = TY_(CharEncodingId)( impl, encnam ); if ( enc >= 0 && TY_(SetOptionInt)( impl, TidyInCharEncoding, enc ) ) return 0; TY_(ReportBadArgument)( impl, "in-char-encoding" ); } return -EINVAL; } int tidySetOutCharEncoding( TidyDoc tdoc, ctmbstr encnam ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { int enc = TY_(CharEncodingId)( impl, encnam ); if ( enc >= 0 && TY_(SetOptionInt)( impl, TidyOutCharEncoding, enc ) ) return 0; TY_(ReportBadArgument)( impl, "out-char-encoding" ); } return -EINVAL; } TidyOptionId tidyOptGetIdForName( ctmbstr optnam ) { const TidyOptionImpl* option = TY_(lookupOption)( optnam ); if ( option ) return option->id; return N_TIDY_OPTIONS; /* Error */ } TidyIterator tidyGetOptionList( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(getOptionList)( impl ); return (TidyIterator) -1; } TidyOption tidyGetNextOption( TidyDoc tdoc, TidyIterator* pos ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); const TidyOptionImpl* option = NULL; if ( impl ) option = TY_(getNextOption)( impl, pos ); else if ( pos ) *pos = 0; return tidyImplToOption( option ); } TidyOption tidyGetOption( TidyDoc ARG_UNUSED(tdoc), TidyOptionId optId ) { const TidyOptionImpl* option = TY_(getOption)( optId ); return tidyImplToOption( option ); } TidyOption tidyGetOptionByName( TidyDoc ARG_UNUSED(doc), ctmbstr optnam ) { const TidyOptionImpl* option = TY_(lookupOption)( optnam ); return tidyImplToOption( option ); } TidyOptionId tidyOptGetId( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return option->id; return N_TIDY_OPTIONS; } ctmbstr tidyOptGetName( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return option->name; return NULL; } TidyOptionType tidyOptGetType( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return option->type; return (TidyOptionType) -1; } Bool tidyOptionIsList( TidyOption opt ) { const TidyOptionImpl* option = tidyOptionToImpl( opt ); if ( option ) return TY_(getOptionIsList)( option->id ); return no; } TidyConfigCategory tidyOptGetCategory( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return option->category; return (TidyConfigCategory) -1; } ctmbstr tidyOptGetDefault( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); /* Special case for TidyDoctype, because it is declared as string */ if ( option && option->id == TidyDoctype ) { const TidyOptionImpl* newopt = TY_(getOption)( TidyDoctypeMode ); return TY_(GetPickListLabelForPick)( TidyDoctypeMode, newopt->dflt ); } if ( option && option->type == TidyString ) return option->pdflt; /* Issue #306 - fix an old typo hidden by a cast! */ return NULL; } ulong tidyOptGetDefaultInt( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option && option->type != TidyString ) return option->dflt; /* Special case for TidyDoctype, because it has a picklist */ if ( option->id == TidyDoctype ) { const TidyOptionImpl* newopt = TY_(getOption)( TidyDoctypeMode ); return newopt->dflt; } return ~0U; } Bool tidyOptGetDefaultBool( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option && option->type != TidyString ) return ( option->dflt ? yes : no ); return no; } Bool tidyOptIsReadOnly( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return ( option->parser == NULL ); return yes; } TidyIterator tidyOptGetPickList( TidyOption topt ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return TY_(getOptionPickList)( option ); return (TidyIterator) -1; } ctmbstr tidyOptGetNextPick( TidyOption topt, TidyIterator* pos ) { const TidyOptionImpl* option = tidyOptionToImpl( topt ); if ( option ) return TY_(getNextOptionPick)( option, pos ); return NULL; } ctmbstr tidyOptGetValue( TidyDoc tdoc, TidyOptionId optId ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); ctmbstr optval = NULL; if ( impl ) { if ( optId == TidyDoctype ) { /* Special case for TidyDoctype, because it has a picklist and is a string. */ uint pick = tidyOptGetInt( tdoc, TidyDoctypeMode ); if ( pick != TidyDoctypeUser ) { optval = TY_(GetPickListLabelForPick)( TidyDoctypeMode, pick ); } else { optval = cfgStr( impl, optId ); } } else { /* Standard case. */ optval = cfgStr( impl, optId ); } } return optval; } Bool tidyOptSetValue( TidyDoc tdoc, TidyOptionId optId, ctmbstr val ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ParseConfigValue)( impl, optId, val ); return no; } Bool tidyOptParseValue( TidyDoc tdoc, ctmbstr optnam, ctmbstr val ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ParseConfigOption)( impl, optnam, val ); return no; } ulong tidyOptGetInt( TidyDoc tdoc, TidyOptionId optId ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); ulong opti = 0; if ( impl ) { /* Special case for TidyDoctype, because it has a picklist */ if ( optId == TidyDoctype ) opti = cfg( impl, TidyDoctypeMode); else opti = cfg( impl, optId ); } return opti; } Bool tidyOptSetInt( TidyDoc tdoc, TidyOptionId optId, ulong val ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { /* Special case for TidyDoctype, because it has a picklist */ if ( optId == TidyDoctype ) return TY_(SetOptionInt)( impl, TidyDoctypeMode, val ); else return TY_(SetOptionInt)( impl, optId, val ); } return no; } Bool tidyOptGetBool( TidyDoc tdoc, TidyOptionId optId ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); Bool optb = no; if ( impl ) { const TidyOptionImpl* option = TY_(getOption)( optId ); if ( option ) { optb = cfgBool( impl, optId ); } } return optb; } Bool tidyOptSetBool( TidyDoc tdoc, TidyOptionId optId, Bool val ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(SetOptionBool)( impl, optId, val ); return no; } ctmbstr tidyOptGetEncName( TidyDoc tdoc, TidyOptionId optId ) { uint enc = tidyOptGetInt( tdoc, optId ); return TY_(CharEncodingOptName)( enc ); } ctmbstr tidyOptGetCurrPick( TidyDoc tdoc, TidyOptionId optId ) { uint pick = tidyOptGetInt( tdoc, optId ); return TY_(GetPickListLabelForPick)( optId, pick ); } TidyIterator tidyOptGetDeclTagList( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); TidyIterator declIter = 0; if ( impl ) declIter = TY_(GetDeclaredTagList)( impl ); return declIter; } ctmbstr tidyOptGetNextDeclTag( TidyDoc tdoc, TidyOptionId optId, TidyIterator* iter ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); ctmbstr tagnam = NULL; if ( impl ) { UserTagType tagtyp = tagtype_null; if ( optId == TidyInlineTags ) tagtyp = tagtype_inline; else if ( optId == TidyBlockTags ) tagtyp = tagtype_block; else if ( optId == TidyEmptyTags ) tagtyp = tagtype_empty; else if ( optId == TidyPreTags ) tagtyp = tagtype_pre; if ( tagtyp != tagtype_null ) tagnam = TY_(GetNextDeclaredTag)( impl, tagtyp, iter ); } return tagnam; } TidyIterator tidyOptGetPriorityAttrList( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(getPriorityAttrList)( impl ); return (TidyIterator) -1; } ctmbstr tidyOptGetNextPriorityAttr(TidyDoc tdoc, TidyIterator* iter ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); ctmbstr result = NULL; if ( impl ) result = TY_(getNextPriorityAttr)( impl, iter ); else if ( iter ) *iter = 0; return result; } TidyIterator tidyOptGetMutedMessageList( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(getMutedMessageList)( impl ); return (TidyIterator) -1; } ctmbstr tidyOptGetNextMutedMessage(TidyDoc tdoc, TidyIterator* iter ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); ctmbstr result = NULL; if ( impl ) result = TY_(getNextMutedMessage)( impl, iter ); else if ( iter ) *iter = 0; return result; } ctmbstr tidyOptGetDoc( TidyDoc ARG_UNUSED(tdoc), TidyOption opt ) { const TidyOptionId optId = tidyOptGetId( opt ); return tidyLocalizedString(optId); } #if SUPPORT_CONSOLE_APP /* TODO - GROUP ALL CONSOLE-ONLY FUNCTIONS */ TidyIterator tidyOptGetDocLinksList( TidyDoc ARG_UNUSED(tdoc), TidyOption opt ) { const TidyOptionId optId = tidyOptGetId( opt ); const TidyOptionDoc* docDesc = TY_(OptGetDocDesc)( optId ); if (docDesc && docDesc->links) return (TidyIterator)docDesc->links; return (TidyIterator)NULL; } #endif /* SUPPORT_CONSOLE_APP */ TidyOption tidyOptGetNextDocLinks( TidyDoc tdoc, TidyIterator* pos ) { const TidyOptionId* curr = (const TidyOptionId *)*pos; TidyOption opt; if (*curr == TidyUnknownOption) { *pos = (TidyIterator)NULL; return (TidyOption)0; } opt = tidyGetOption(tdoc, *curr); curr++; *pos = (*curr == TidyUnknownOption ) ? (TidyIterator)NULL:(TidyIterator)curr; return opt; } int tidyOptSaveFile( TidyDoc tdoc, ctmbstr cfgfil ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(SaveConfigFile)( impl, cfgfil ); return -EINVAL; } int tidyOptSaveSink( TidyDoc tdoc, TidyOutputSink* sink ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(SaveConfigSink)( impl, sink ); return -EINVAL; } Bool tidyOptSnapshot( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { TY_(TakeConfigSnapshot)( impl ); return yes; } return no; } Bool tidyOptResetToSnapshot( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { TY_(ResetConfigToSnapshot)( impl ); return yes; } return no; } Bool tidyOptResetAllToDefault( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { TY_(ResetConfigToDefault)( impl ); return yes; } return no; } Bool tidyOptResetToDefault( TidyDoc tdoc, TidyOptionId optId ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ResetOptionToDefault)( impl, optId ); return no; } Bool tidyOptDiffThanDefault( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ConfigDiffThanDefault)( impl ); return no; } Bool tidyOptDiffThanSnapshot( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return TY_(ConfigDiffThanSnapshot)( impl ); return no; } Bool tidyOptCopyConfig( TidyDoc to, TidyDoc from ) { TidyDocImpl* docTo = tidyDocToImpl( to ); TidyDocImpl* docFrom = tidyDocToImpl( from ); if ( docTo && docFrom ) { TY_(CopyConfig)( docTo, docFrom ); return yes; } return no; } /* I/O and Message handling interface ** ** By default, Tidy will define, create and use instance of input and output ** handlers for standard C buffered I/O (i.e. FILE* stdin, FILE* stdout and ** FILE* stderr for content input, content output and diagnostic output, ** respectively. A FILE* cfgFile input handler will be used for config files. ** Command line options will just be set directly. */ void tidySetEmacsFile( TidyDoc tdoc, ctmbstr filePath ) { tidyOptSetValue( tdoc, TidyEmacsFile, filePath ); } ctmbstr tidyGetEmacsFile( TidyDoc tdoc ) { return tidyOptGetValue( tdoc, TidyEmacsFile ); } /* Use TidyReportFilter to filter messages by diagnostic level: ** info, warning, etc. Just set diagnostic output ** handler to redirect all diagnostics output. Return true ** to proceed with output, false to cancel. */ Bool tidySetReportFilter( TidyDoc tdoc, TidyReportFilter filt ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->reportFilter = filt; return yes; } return no; } /* tidySetReportCallback functions similar to TidyReportFilter, but provides the * string version of the internal enum name so that LibTidy users can use ** the string as a lookup key for providing their own error localizations. ** See the string key definitions in tidyenum.h. */ Bool tidySetReportCallback( TidyDoc tdoc, TidyReportCallback filt ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->reportCallback = filt; return yes; } return no; } Bool tidySetMessageCallback( TidyDoc tdoc, TidyMessageCallback filt ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->messageCallback = filt; return yes; } return no; } TidyDoc tidyGetMessageDoc( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); TidyDocImpl* doc = TY_(getMessageDoc)(*message); return tidyImplToDoc(doc); } uint tidyGetMessageCode( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageCode)(*message); } ctmbstr tidyGetMessageKey( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageKey)(*message); } int tidyGetMessageLine( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageLine)(*message); } int tidyGetMessageColumn( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageColumn)(*message); } TidyReportLevel tidyGetMessageLevel( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageLevel)(*message); } Bool tidyGetMessageIsMuted( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageIsMuted)(*message); } ctmbstr tidyGetMessageFormatDefault( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageFormatDefault)(*message); } ctmbstr tidyGetMessageFormat( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageFormat)(*message); } ctmbstr tidyGetMessageDefault( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageDefault)(*message); } ctmbstr tidyGetMessage( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessage)(*message); } ctmbstr tidyGetMessagePosDefault( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessagePosDefault)(*message); } ctmbstr tidyGetMessagePos( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessagePos)(*message); } ctmbstr tidyGetMessagePrefixDefault( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessagePrefixDefault)(*message); } ctmbstr tidyGetMessagePrefix( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessagePrefix)(*message); } ctmbstr tidyGetMessageOutputDefault( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageOutputDefault)(*message); } ctmbstr tidyGetMessageOutput( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageOutput)(*message); } TidyIterator tidyGetMessageArguments( TidyMessage tmessage ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getMessageArguments)(*message); } TidyMessageArgument tidyGetNextMessageArgument( TidyMessage tmessage, TidyIterator* iter ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getNextMessageArgument)(*message, iter); } TidyFormatParameterType tidyGetArgType( TidyMessage tmessage, TidyMessageArgument* arg ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getArgType)(*message, arg); } ctmbstr tidyGetArgFormat( TidyMessage tmessage, TidyMessageArgument* arg ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getArgFormat)(*message, arg); } ctmbstr tidyGetArgValueString( TidyMessage tmessage, TidyMessageArgument* arg ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getArgValueString)(*message, arg); } uint tidyGetArgValueUInt( TidyMessage tmessage, TidyMessageArgument* arg ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getArgValueUInt)(*message, arg); } int tidyGetArgValueInt( TidyMessage tmessage, TidyMessageArgument* arg ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getArgValueInt)(*message, arg); } double tidyGetArgValueDouble( TidyMessage tmessage, TidyMessageArgument* arg ) { TidyMessageImpl *message = tidyMessageToImpl(tmessage); return TY_(getArgValueDouble)(*message, arg); } FILE* tidySetErrorFile( TidyDoc tdoc, ctmbstr errfilnam ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { FILE* errout = fopen( errfilnam, "wb" ); if ( errout ) { uint outenc = cfg( impl, TidyOutCharEncoding ); uint nl = cfg( impl, TidyNewline ); TY_(ReleaseStreamOut)( impl, impl->errout ); impl->errout = TY_(FileOutput)( impl, errout, outenc, nl ); return errout; } else /* Emit message to current error sink */ TY_(ReportFileError)( impl, errfilnam, FILE_CANT_OPEN ); } return NULL; } int tidySetErrorBuffer( TidyDoc tdoc, TidyBuffer* errbuf ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { uint outenc = cfg( impl, TidyOutCharEncoding ); uint nl = cfg( impl, TidyNewline ); TY_(ReleaseStreamOut)( impl, impl->errout ); impl->errout = TY_(BufferOutput)( impl, errbuf, outenc, nl ); return ( impl->errout ? 0 : -ENOMEM ); } return -EINVAL; } int tidySetErrorSink( TidyDoc tdoc, TidyOutputSink* sink ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { uint outenc = cfg( impl, TidyOutCharEncoding ); uint nl = cfg( impl, TidyNewline ); TY_(ReleaseStreamOut)( impl, impl->errout ); impl->errout = TY_(UserOutput)( impl, sink, outenc, nl ); return ( impl->errout ? 0 : -ENOMEM ); } return -EINVAL; } /* Use TidyPPProgress to monitor the progress of the pretty printer. */ Bool tidySetPrettyPrinterCallback(TidyDoc tdoc, TidyPPProgress callback) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { impl->progressCallback = callback; return yes; } return no; } /* Document info */ int tidyStatus( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); int tidyStat = -EINVAL; if ( impl ) tidyStat = tidyDocStatus( impl ); return tidyStat; } int tidyDetectedHtmlVersion( TidyDoc ARG_UNUSED(tdoc) ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); return TY_(HTMLVersionNumberFromCode)( impl->lexer->versionEmitted ); } Bool tidyDetectedXhtml( TidyDoc ARG_UNUSED(tdoc) ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); return impl->lexer->isvoyager; } Bool tidyDetectedGenericXml( TidyDoc ARG_UNUSED(tdoc) ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); return impl->xmlDetected; } uint tidyErrorCount( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); uint count = 0xFFFFFFFF; if ( impl ) count = impl->errors; return count; } uint tidyWarningCount( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); uint count = 0xFFFFFFFF; if ( impl ) count = impl->warnings; return count; } uint tidyAccessWarningCount( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); uint count = 0xFFFFFFFF; if ( impl ) count = impl->accessErrors; return count; } uint tidyConfigErrorCount( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); uint count = 0xFFFFFFFF; if ( impl ) count = impl->optionErrors; return count; } /* Error reporting functions */ void tidyErrorSummary( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) TY_(ErrorSummary)( impl ); } void tidyGeneralInfo( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { TY_(Dialogue)( impl, TEXT_GENERAL_INFO ); TY_(Dialogue)( impl, TEXT_GENERAL_INFO_PLEA ); } } /* I/O Functions ** ** Initial version supports only whole-file operations. ** Do not expose Tidy StreamIn or Out data structures - yet. */ /* Parse/load Functions ** ** HTML/XHTML version determined from input. */ int tidyParseFile( TidyDoc tdoc, ctmbstr filnam ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocParseFile( doc, filnam ); } int tidyParseStdin( TidyDoc tdoc ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocParseStdin( doc ); } int tidyParseString( TidyDoc tdoc, ctmbstr content ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocParseString( doc, content ); } int tidyParseBuffer( TidyDoc tdoc, TidyBuffer* inbuf ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocParseBuffer( doc, inbuf ); } int tidyParseSource( TidyDoc tdoc, TidyInputSource* source ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocParseSource( doc, source ); } #ifdef WIN32 #define M_IS_DIR _S_IFDIR #else // !WIN32 #define M_IS_DIR S_IFDIR #endif int tidyDocParseFile( TidyDocImpl* doc, ctmbstr filnam ) { int status = -ENOENT; FILE* fin = 0; struct stat sbuf = { 0 }; /* Is. #681 - read-only files */ if ( stat(filnam,&sbuf) != 0 ) { TY_(ReportFileError)( doc, filnam, FILE_NOT_FILE ); return status; } if (sbuf.st_mode & M_IS_DIR) /* and /NOT/ if a DIRECTORY */ { TY_(ReportFileError)(doc, filnam, FILE_NOT_FILE); return status; } #ifdef _WIN32 return TY_(DocParseFileWithMappedFile)( doc, filnam ); #else fin = fopen( filnam, "rb" ); #if PRESERVE_FILE_TIMES { /* get last modified time */ TidyClearMemory(&doc->filetimes, sizeof(doc->filetimes)); if (fin && cfgBool(doc, TidyKeepFileTimes) && fstat(fileno(fin), &sbuf) != -1) { doc->filetimes.actime = sbuf.st_atim.tv_sec; doc->filetimes.modtime = sbuf.st_mtim.tv_sec; } } #endif if ( fin ) { StreamIn* in = TY_(FileInput)( doc, fin, cfg( doc, TidyInCharEncoding )); if ( !in ) { fclose( fin ); return status; } status = TY_(DocParseStream)( doc, in ); TY_(freeFileSource)(&in->source, yes); TY_(freeStreamIn)(in); } else /* Error message! */ TY_(ReportFileError)( doc, filnam, FILE_CANT_OPEN ); return status; #endif } int tidyDocParseStdin( TidyDocImpl* doc ) { StreamIn* in = TY_(FileInput)( doc, stdin, cfg( doc, TidyInCharEncoding )); int status = TY_(DocParseStream)( doc, in ); TY_(freeFileSource)(&in->source, yes); TY_(freeStreamIn)(in); return status; } int tidyDocParseBuffer( TidyDocImpl* doc, TidyBuffer* inbuf ) { int status = -EINVAL; if ( inbuf ) { StreamIn* in = TY_(BufferInput)( doc, inbuf, cfg( doc, TidyInCharEncoding )); status = TY_(DocParseStream)( doc, in ); TY_(freeStreamIn)(in); } return status; } int tidyDocParseString( TidyDocImpl* doc, ctmbstr content ) { int status = -EINVAL; TidyBuffer inbuf; StreamIn* in = NULL; if ( content ) { tidyBufInitWithAllocator( &inbuf, doc->allocator ); tidyBufAttach( &inbuf, (byte*)content, TY_(tmbstrlen)(content)+1 ); in = TY_(BufferInput)( doc, &inbuf, cfg( doc, TidyInCharEncoding )); status = TY_(DocParseStream)( doc, in ); tidyBufDetach( &inbuf ); TY_(freeStreamIn)(in); } return status; } int tidyDocParseSource( TidyDocImpl* doc, TidyInputSource* source ) { StreamIn* in = TY_(UserInput)( doc, source, cfg( doc, TidyInCharEncoding )); int status = TY_(DocParseStream)( doc, in ); TY_(freeStreamIn)(in); return status; } /* Print/save Functions ** */ int tidySaveFile( TidyDoc tdoc, ctmbstr filnam ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocSaveFile( doc, filnam ); } int tidySaveStdout( TidyDoc tdoc ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocSaveStdout( doc ); } int tidySaveString( TidyDoc tdoc, tmbstr buffer, uint* buflen ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocSaveString( doc, buffer, buflen ); } int tidySaveBuffer( TidyDoc tdoc, TidyBuffer* outbuf ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocSaveBuffer( doc, outbuf ); } int tidySaveSink( TidyDoc tdoc, TidyOutputSink* sink ) { TidyDocImpl* doc = tidyDocToImpl( tdoc ); return tidyDocSaveSink( doc, sink ); } int tidyDocSaveFile( TidyDocImpl* doc, ctmbstr filnam ) { int status = -ENOENT; FILE* fout = NULL; /* Don't zap input file if no output */ if ( doc->errors > 0 && cfgBool(doc, TidyWriteBack) && !cfgBool(doc, TidyForceOutput) ) status = tidyDocStatus( doc ); else fout = fopen( filnam, "wb" ); if ( fout ) { uint outenc = cfg( doc, TidyOutCharEncoding ); uint nl = cfg( doc, TidyNewline ); StreamOut* out = TY_(FileOutput)( doc, fout, outenc, nl ); status = tidyDocSaveStream( doc, out ); fclose( fout ); TidyDocFree( doc, out ); #if PRESERVE_FILE_TIMES if ( doc->filetimes.actime ) { /* set file last accessed/modified times to original values */ utime( filnam, &doc->filetimes ); TidyClearMemory( &doc->filetimes, sizeof(doc->filetimes) ); } #endif /* PRESERVFILETIMES */ } if ( status < 0 ) /* Error message! */ TY_(ReportFileError)( doc, filnam, FILE_CANT_OPEN ); return status; } /* Note, _setmode() does NOT work on Win2K Pro w/ VC++ 6.0 SP3. ** The code has been left in in case it works w/ other compilers ** or operating systems. If stdout is in Text mode, be aware that ** it will garble UTF16 documents. In text mode, when it encounters ** a single byte of value 10 (0xA), it will insert a single byte ** value 13 (0xD) just before it. This has the effect of garbling ** the entire document. */ #if !defined(NO_SETMODE_SUPPORT) # if defined(_WIN32) || defined(OS2_OS) # endif #endif int tidyDocSaveStdout( TidyDocImpl* doc ) { #if !defined(NO_SETMODE_SUPPORT) # if defined(_WIN32) || defined(OS2_OS) int oldstdoutmode = -1, oldstderrmode = -1; # endif #endif int status = 0; uint outenc = cfg( doc, TidyOutCharEncoding ); uint nl = cfg( doc, TidyNewline ); StreamOut* out = TY_(FileOutput)( doc, stdout, outenc, nl ); #if !defined(NO_SETMODE_SUPPORT) # if defined(_WIN32) || defined(OS2_OS) oldstdoutmode = setmode( fileno(stdout), _O_BINARY ); oldstderrmode = setmode( fileno(stderr), _O_BINARY ); # endif #endif if ( 0 == status ) status = tidyDocSaveStream( doc, out ); fflush(stdout); fflush(stderr); #if !defined(NO_SETMODE_SUPPORT) # if defined(_WIN32) || defined(OS2_OS) if ( oldstdoutmode != -1 ) oldstdoutmode = setmode( fileno(stdout), oldstdoutmode ); if ( oldstderrmode != -1 ) oldstderrmode = setmode( fileno(stderr), oldstderrmode ); # endif #endif TidyDocFree( doc, out ); return status; } int tidyDocSaveString( TidyDocImpl* doc, tmbstr buffer, uint* buflen ) { uint outenc = cfg( doc, TidyOutCharEncoding ); uint nl = cfg( doc, TidyNewline ); TidyBuffer outbuf; StreamOut* out; int status; tidyBufInitWithAllocator( &outbuf, doc->allocator ); out = TY_(BufferOutput)( doc, &outbuf, outenc, nl ); status = tidyDocSaveStream( doc, out ); if ( outbuf.size > *buflen ) status = -ENOMEM; else memcpy( buffer, outbuf.bp, outbuf.size ); *buflen = outbuf.size; tidyBufFree( &outbuf ); TidyDocFree( doc, out ); return status; } int tidyDocSaveBuffer( TidyDocImpl* doc, TidyBuffer* outbuf ) { int status = -EINVAL; if ( outbuf ) { uint outenc = cfg( doc, TidyOutCharEncoding ); uint nl = cfg( doc, TidyNewline ); StreamOut* out = TY_(BufferOutput)( doc, outbuf, outenc, nl ); status = tidyDocSaveStream( doc, out ); TidyDocFree( doc, out ); } return status; } int tidyDocSaveSink( TidyDocImpl* doc, TidyOutputSink* sink ) { uint outenc = cfg( doc, TidyOutCharEncoding ); uint nl = cfg( doc, TidyNewline ); StreamOut* out = TY_(UserOutput)( doc, sink, outenc, nl ); int status = tidyDocSaveStream( doc, out ); TidyDocFree( doc, out ); return status; } int tidyDocStatus( TidyDocImpl* doc ) { if ( doc->errors > 0 ) return 2; if ( doc->warnings > 0 || doc->accessErrors > 0 ) return 1; return 0; } int tidyCleanAndRepair( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return tidyDocCleanAndRepair( impl ); return -EINVAL; } int tidyRunDiagnostics( TidyDoc tdoc ) { TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) return tidyDocRunDiagnostics( impl ); return -EINVAL; } int tidyReportDoctype( TidyDoc tdoc ) { int iret = -EINVAL; TidyDocImpl* impl = tidyDocToImpl( tdoc ); if ( impl ) { tidyDocReportDoctype( impl ); iret = 0; } return iret; } /* Workhorse functions. ** ** Parse requires input source, all input config items ** and diagnostic sink to have all been set before calling. ** ** Emit likewise requires that document sink and all ** pretty printing options have been set. */ static ctmbstr integrity = "\nPanic - tree has lost its integrity\n"; int TY_(DocParseStream)( TidyDocImpl* doc, StreamIn* in ) { Bool xmlIn = cfgBool( doc, TidyXmlTags ); TidyConfigChangeCallback callback = doc->pConfigChangeCallback; int bomEnc; doc->pConfigChangeCallback = NULL; assert( doc != NULL && in != NULL ); assert( doc->docIn == NULL ); doc->docIn = in; TY_(ResetTags)(doc); /* Reset table to html5 mode */ TY_(TakeConfigSnapshot)( doc ); /* Save config state */ TY_(AdjustConfig)( doc ); /* Ensure config internal consistency */ TY_(FreeAnchors)( doc ); TY_(FreeNode)(doc, &doc->root); TidyClearMemory(&doc->root, sizeof(Node)); if (doc->givenDoctype) TidyDocFree(doc, doc->givenDoctype); /*\ * Issue #186 - Now FreeNode depend on the doctype, so the lexer is needed * to determine which hash is to be used, so free it last. \*/ TY_(FreeLexer)( doc ); doc->givenDoctype = NULL; doc->lexer = TY_(NewLexer)( doc ); /* doc->lexer->root = &doc->root; */ doc->root.line = doc->lexer->lines; doc->root.column = doc->lexer->columns; doc->inputHadBOM = no; doc->xmlDetected = no; bomEnc = TY_(ReadBOMEncoding)(in); if (bomEnc != -1) { in->encoding = bomEnc; TY_(SetOptionInt)(doc, TidyInCharEncoding, bomEnc); } /* Tidy doesn't alter the doctype for generic XML docs */ if ( xmlIn ) { TY_(ParseXMLDocument)( doc ); if ( !TY_(CheckNodeIntegrity)( &doc->root ) ) TidyPanic( doc->allocator, integrity ); } else { doc->warnings = 0; TY_(ParseDocument)( doc ); if ( !TY_(CheckNodeIntegrity)( &doc->root ) ) TidyPanic( doc->allocator, integrity ); } doc->docIn = NULL; doc->pConfigChangeCallback = callback; return tidyDocStatus( doc ); } int tidyDocRunDiagnostics( TidyDocImpl* doc ) { TY_(ReportMarkupVersion)( doc ); TY_(ReportNumWarnings)( doc ); if ( doc->errors > 0 && !cfgBool( doc, TidyForceOutput ) ) TY_(Dialogue)(doc, STRING_NEEDS_INTERVENTION ); return tidyDocStatus( doc ); } void tidyDocReportDoctype( TidyDocImpl* doc ) { TY_(ReportMarkupVersion)( doc ); } /***************************************************************************** * HTML5 STUFF *****************************************************************************/ #if 0 && defined(ENABLE_DEBUG_LOG) extern void show_not_html5(void); /* ----------------------------- List tags that do not have version HTML5 (HT50|XH50) acronym applet basefont big center dir font frame frameset isindex listing noframes plaintext rb rbc rtc strike tt xmp nextid align bgsound blink comment ilayer layer marquee multicol nobr noembed nolayer nosave server servlet spacer Listed total 35 tags that do not have version 393216 ------------------------------ */ static void list_not_html5(void) { static Bool done_list = no; if (done_list == no) { done_list = yes; show_not_html5(); } } #endif /* What about , stike-through, underline */ static struct _html5Info { const char *tag; uint id; } const html5Info[] = { {"acronym", TidyTag_ACRONYM}, {"applet", TidyTag_APPLET }, {"basefont",TidyTag_BASEFONT }, { "big", TidyTag_BIG }, { "center", TidyTag_CENTER }, { "dir", TidyTag_DIR }, { "font", TidyTag_FONT }, { "frame", TidyTag_FRAME}, { "frameset", TidyTag_FRAMESET}, { "noframes", TidyTag_NOFRAMES }, { "strike", TidyTag_STRIKE }, { "tt", TidyTag_TT }, { 0, 0 } }; static Bool inRemovedInfo( uint tid ) { int i; for (i = 0; ; i++) { if (html5Info[i].tag == 0) break; if (html5Info[i].id == tid) return yes; } return no; } /* Things that should not be in an HTML5 body. This is special for CheckHTML5(), and we might just want to remove CheckHTML5()'s output altogether and count on the default --strict-tags-attributes. */ static int BadBody5Attribs[] = { TidyAttr_BACKGROUND, TidyAttr_BGCOLOR, TidyAttr_TEXT, TidyAttr_LINK, TidyAttr_VLINK, TidyAttr_ALINK, TidyAttr_UNKNOWN /* Must be last! */ }; static Bool nodeHasAlignAttr( Node *node ) { /* #define attrIsALIGN(av) AttrIsId( av, TidyAttr_ALIGN ) */ AttVal* av; for ( av = node->attributes; av != NULL; av = av->next ) { if (attrIsALIGN(av)) return yes; } return no; } /* * Perform special checks for HTML, even when we're not using the default * option `--strict-tags-attributes yes`. This will ensure that HTML5 warning * and error output is given regardless of the new option, and ensure that * cleanup takes place. This provides mostly consistent Tidy behavior even with * the introduction of this new option. Note that strings have changed, though, * in order to maintain consistency with the `--strict-tags-attributes` * messages. * * See also: http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#obsolete */ static void TY_(CheckHTML5)( TidyDocImpl* doc, Node* node ) { Stack *stack = TY_(newStack)(doc, 16); Bool clean = cfgBool( doc, TidyMakeClean ); Bool already_strict = cfgBool( doc, TidyStrictTagsAttr ); Node* body = TY_(FindBody)( doc ); Node* next; Bool warn = yes; /* should this be a warning, error, or report??? */ AttVal* attr = NULL; int i = 0; while (node) { next = node->next; if ( nodeHasAlignAttr( node ) ) { /* @todo: Is this for ALL elements that accept an 'align' attribute, * or should this be a sub-set test? */ /* We will only emit this message if `--strict-tags-attributes==no`; * otherwise if yes this message will be output during later * checking. */ if ( !already_strict ) TY_(ReportAttrError)(doc, node, TY_(AttrGetById)(node, TidyAttr_ALIGN), MISMATCHED_ATTRIBUTE_WARN); } if ( node == body ) { i = 0; /* We will only emit these messages if `--strict-tags-attributes==no`; * otherwise if yes these messages will be output during later * checking. */ if ( !already_strict ) { while ( BadBody5Attribs[i] != TidyAttr_UNKNOWN ) { attr = TY_(AttrGetById)(node, BadBody5Attribs[i]); if ( attr ) TY_(ReportAttrError)(doc, node, attr , MISMATCHED_ATTRIBUTE_WARN); i++; } } } else if ( nodeIsACRONYM(node) ) { if (clean) { /* Replace with 'abbr' with warning to that effect. * Maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid ) */ TY_(CoerceNode)(doc, node, TidyTag_ABBR, warn, no); } else { if ( !already_strict ) TY_(Report)(doc, node, node, REMOVED_HTML5); } } else if ( nodeIsAPPLET(node) ) { if (clean) { /* replace with 'object' with warning to that effect * maybe should use static void RenameElem( TidyDocImpl* doc, Node* node, TidyTagId tid ) */ TY_(CoerceNode)(doc, node, TidyTag_OBJECT, warn, no); } else { if ( !already_strict ) TY_(Report)(doc, node, node, REMOVED_HTML5); } } else if ( nodeIsBASEFONT(node) ) { /* basefont: CSS equivalent 'font-size', 'font-family' and 'color' * on body or class on each subsequent element. * Difficult - If it is the first body element, then could consider * adding that to the as a whole, else could perhaps apply it * to all subsequent elements. But also in consideration is the fact * that it was NOT supported in many browsers. * - For now just report a warning */ if ( !already_strict ) TY_(Report)(doc, node, node, REMOVED_HTML5); } else if ( nodeIsBIG(node) ) { /* big: CSS equivalent 'font-size:larger' * so could replace the ... with * ... * then replace with * Need to think about that... * Could use - * TY_(AddStyleProperty)( doc, node, "font-size: larger" ); * TY_(CoerceNode)(doc, node, TidyTag_SPAN, no, no); * Alternatively generated a