// See the file "COPYING" in the main distribution directory for copyright. #pragma once #include "Configuration.h" #include "Reporter.h" #include "ID.h" #include #include #include #include #include #include template class IntrusivePtr; class TypeDecl; namespace zeekygen { class PackageInfo; class ScriptInfo; /** * Map of info objects. Just a wrapper around std::map to improve code * readability (less typedefs for specific map types and not having to use * iterators directly to find a particular info object). */ template struct InfoMap { typedef std::map map_type; /** * @param name Name of an info object to retrieve. * @return The info object associated with \a name. */ T* GetInfo(const std::string& name) const { typename map_type::const_iterator it = map.find(name); return it == map.end() ? 0 : it->second; } map_type map; }; /** * Manages all documentation tracking and generation. */ class Manager { public: /** * Ctor. * @param config Path to a Zeekygen config file if documentation is to be * written to disk. * @param bro_command The command used to invoke the bro process. * It's used when checking for out-of-date targets. If the bro binary is * newer then a target, it needs to be rebuilt. */ Manager(const std::string& config, const std::string& bro_command); /** * Dtor. */ ~Manager(); /** * Do initialization that needs to happen before scripts are parsed. * Currently nothing outside of what's done in ctor is needed. */ void InitPreScript(); /** * Do initialization that needs to happen after scripts are parsed. * This is primarly dependency resolution/filtering. */ void InitPostScript(); /** * Builds all Zeekygen targets specified by config file and write out * documentation to disk. */ void GenerateDocs() const; /** * Register Bro script for which information/documentation will be gathered. * @param path Absolute path to Bro script. */ void Script(const std::string& path); /** * Register Bro script dependency ("@load"). * @param path Absolute path to a Bro script. * @param dep Absolute path to a Bro script being "@load"d from script given * by \a path. */ void ScriptDependency(const std::string& path, const std::string& dep); /** * Register a module usage (script may export identifiers in to the * module namespace). * @param path Absolute path to a Bro script. * @param module The module which script given by \a path is using. */ void ModuleUsage(const std::string& path, const std::string& module); /** * Signal that a record or enum type is now being parsed. * @param id The record or enum type identifier. */ void StartType(IntrusivePtr id); /** * Register a script-level identifier for which information/documentation * will be gathered. * @param id The script-level identifier. */ void Identifier(IntrusivePtr id); /** * Register a record-field for which information/documentation will be * gathered. * @param id The identifier of the record type which has the field. * @param field The field name/type information. * @param path Absolute path to a Bro script in which this field is * declared. This can be different from the place where the record type * is declared due to redefs. */ void RecordField(const zeek::detail::ID* id, const TypeDecl* field, const std::string& path); /** * Register a redefinition of a particular identifier. * @param id The identifier being redef'd. * @param path Absolute path to a Bro script doing the redef. * @param ic The initialization class that was used (e.g. =, +=, -=). * @param init_expr The intiialization expression that was used. */ void Redef(const zeek::detail::ID* id, const std::string& path, zeek::detail::init_class ic, IntrusivePtr init_expr); void Redef(const zeek::detail::ID* id, const std::string& path, zeek::detail::init_class ic = zeek::detail::INIT_NONE); /** * Register Zeekygen script summary content. * @param path Absolute path to a Bro script. * @param comment Zeekygen-style summary comment ("##!") to associate with * script given by \a path. */ void SummaryComment(const std::string& path, const std::string& comment); /** * Register a Zeekygen comment ("##") for an upcoming identifier (i.e. * this content is buffered and consumed by next identifier/field * declaration. * @param comment Content of the Zeekygen comment. */ void PreComment(const std::string& comment); /** * Register a Zeekygen comment ("##<") for the last identifier seen. * @param comment Content of the Zeekygen comment. * @param identifier_hint Expected name of identifier with which to * associate \a comment. */ void PostComment(const std::string& comment, const std::string& identifier_hint = ""); /** * @param id Name of script-level enum identifier. * @return The name of the enum's type. */ std::string GetEnumTypeName(const std::string& id) const; /** * @param name Name of a script-level identifier. * @return an identifier info object associated with \a name or a null * pointer if it's not a known identifier. */ IdentifierInfo* GetIdentifierInfo(const std::string& name) const { return identifiers.GetInfo(name); } /** * @param name Name of a Zeek script ("normalized" to be a path relative * to a component within ZEEKPATH). * @return a script info object associated with \a name or a null pointer * if it's not a known script name. */ ScriptInfo* GetScriptInfo(const std::string& name) const { return scripts.GetInfo(name); } /** * @param name Name of a Zeek script package ("normalized" to be a path * relative to a component within ZEEKPATH). * @return a package info object assocated with \a name or a null pointer * if it's not a known package name. */ PackageInfo* GetPackageInfo(const std::string& name) const { return packages.GetInfo(name); } /** * Check if a Zeekygen target is up-to-date. * @param target_file output file of a Zeekygen target. * @param dependencies all dependencies of the target. * @return true if modification time of \a target_file is newer than * modification time of Bro binary, Zeekygen config file, and all * dependencies, else false. */ template bool IsUpToDate(const std::string& target_file, const std::vector& dependencies) const; private: typedef std::vector comment_buffer_t; typedef std::map comment_buffer_map_t; IdentifierInfo* CreateIdentifierInfo(IntrusivePtr id, ScriptInfo* script); bool disabled; comment_buffer_t comment_buffer; // For whatever next identifier comes in. comment_buffer_map_t comment_buffer_map; // For a particular identifier. InfoMap packages; InfoMap scripts; InfoMap identifiers; std::vector all_info; IdentifierInfo* last_identifier_seen; IdentifierInfo* incomplete_type; std::map enum_mappings; // enum id -> enum type id Config config; time_t bro_mtime; }; template bool Manager::IsUpToDate(const std::string& target_file, const std::vector& dependencies) const { struct stat s; if ( stat(target_file.c_str(), &s) < 0 ) { if ( errno == ENOENT ) // Doesn't exist. return false; reporter->InternalError("Zeekygen failed to stat target file '%s': %s", target_file.c_str(), strerror(errno)); } if ( difftime(bro_mtime, s.st_mtime) > 0 ) return false; if ( difftime(config.GetModificationTime(), s.st_mtime) > 0 ) return false; for ( size_t i = 0; i < dependencies.size(); ++i ) if ( difftime(dependencies[i]->GetModificationTime(), s.st_mtime) > 0 ) return false; return true; } } // namespace zeekygen extern zeekygen::Manager* zeekygen_mgr;