// See the file "COPYING" in the main distribution directory for copyright. #ifndef ZEEKYGEN_TARGET_H #define ZEEKYGEN_TARGET_H #include "Info.h" #include "PackageInfo.h" #include "ScriptInfo.h" #include "IdentifierInfo.h" #include #include #include #include namespace zeekygen { /** * Helper class to create files in arbitrary file paths and automatically * close it on destruction. */ struct TargetFile { /** * Open a file. * @param arg_name Path to a file to create. It's a fatal error if * creating it fails. Creating it will also create any intermediate * directories that don't already exist. * */ explicit TargetFile(const std::string& arg_name); /** * Close the file. */ ~TargetFile(); std::string name; /**< File name. */ FILE* f; /**< File stream. */ }; /** * A Zeekygen target abstract base class. A target is generally any portion of * documentation that Bro can build. It's identified by a type (e.g. script, * identifier, package), a pattern (e.g. "example.zeek", "HTTP::Info"), and * a path to an output file. */ class Target { public: /** * Ctor. * @param arg_name output file name of the target. * @param arg_pattern pattern of info objects the target depends upon. Only * exact string and simple prefix matching is currently allowed. */ Target(const std::string& arg_name, const std::string& arg_pattern); /** * Dtor. */ virtual ~Target() { } /** * Filter out any dependency information from a set of all known info. * @param infos All known info objects. */ void FindDependencies(const std::vector& infos) { DoFindDependencies(infos); } /** * Build the target by generating its output file. Implementations may * not always write to the output file if they determine an existing * version is already up-to-date. */ void Generate() const { DoGenerate(); } /** * Check if a particular info object matches the target pattern. * Currently only exact string and simple prefix matching patterns are * used. E.g. for prefix matching "HTTP::*" or "base/protocols/http*". * @param info An info object for some thing that is documentable. * @return true if it matches, else false. */ bool MatchesPattern(Info* info) const; /** * @return The output file name of the target. */ std::string Name() const { return name; } /** * @return The pattern string of the target. */ std::string Pattern() const { return pattern; } private: virtual void DoFindDependencies(const std::vector& infos) = 0; virtual void DoGenerate() const = 0; std::string name; std::string pattern; std::string prefix; }; template static Target* create_target(const std::string& name, const std::string& pattern) { return new T(name, pattern); } /** * Factory for creating Target instances. */ class TargetFactory { public: /** * Register a new target type. * @param type_name The target type name as it will appear in Zeekygen * config files. */ template void Register(const std::string& type_name) { target_creators[type_name] = &create_target; } /** * Instantiate a target. * @param type_name The target type name as it appears in Zeekygen config * files. * @param name The output file name of the target. * @param pattern The dependency pattern of the target. * @return A new target instance or a pointer if \a type_name is not * registered. */ Target* Create(const std::string& type_name, const std::string& name, const std::string& pattern) { target_creator_map::const_iterator it = target_creators.find(type_name); if ( it == target_creators.end() ) return 0; return it->second(name, pattern); } private: typedef Target* (*TargetFactoryFn)(const std::string& name, const std::string& pattern); typedef std::map target_creator_map; target_creator_map target_creators; }; /** * Target to build analyzer documentation. */ class AnalyzerTarget : public Target { public: /** * Writes out plugin index documentation for all analyzer plugins. * @param f an open file stream to write docs into. */ void CreateAnalyzerDoc(FILE* f) const { return DoCreateAnalyzerDoc(f); } protected: typedef void (*doc_creator_fn)(FILE*); AnalyzerTarget(const std::string& name, const std::string& pattern) : Target(name, pattern) { } private: void DoFindDependencies(const std::vector& infos) override; void DoGenerate() const override; virtual void DoCreateAnalyzerDoc(FILE* f) const = 0; }; /** * Target to build protocol analyzer documentation. */ class ProtoAnalyzerTarget : public AnalyzerTarget { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ ProtoAnalyzerTarget(const std::string& name, const std::string& pattern) : AnalyzerTarget(name, pattern) { } private: void DoCreateAnalyzerDoc(FILE* f) const override; }; /** * Target to build file analyzer documentation. */ class FileAnalyzerTarget : public AnalyzerTarget { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ FileAnalyzerTarget(const std::string& name, const std::string& pattern) : AnalyzerTarget(name, pattern) { } private: void DoCreateAnalyzerDoc(FILE* f) const override; }; /** * Target to build package documentation. */ class PackageTarget : public Target { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ PackageTarget(const std::string& name, const std::string& pattern) : Target(name, pattern), pkg_deps(), script_deps(), pkg_manifest() { } private: void DoFindDependencies(const std::vector& infos) override; void DoGenerate() const override; std::vector pkg_deps; std::vector script_deps; typedef std::map > manifest_t; manifest_t pkg_manifest; }; /** * Target to build package index documentation. */ class PackageIndexTarget : public Target { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ PackageIndexTarget(const std::string& name, const std::string& pattern) : Target(name, pattern), pkg_deps() { } private: void DoFindDependencies(const std::vector& infos) override; void DoGenerate() const override; std::vector pkg_deps; }; /** * Target to build script documentation. */ class ScriptTarget : public Target { public: /** * Ctor. * @param name Output file name or directory. If it's a directory, * then one document for each script that matches the pattern is written to * the directory in a directory structure which mirrors the script's path * relative to a component in ZEEKPATH. * @param pattern Dependency pattern. */ ScriptTarget(const std::string& name, const std::string& pattern) : Target(name, pattern), script_deps() { } ~ScriptTarget() override { for ( size_t i = 0; i < pkg_deps.size(); ++i ) delete pkg_deps[i]; } protected: std::vector script_deps; private: void DoFindDependencies(const std::vector& infos) override; void DoGenerate() const override; bool IsDir() const { return Name()[Name().size() - 1] == '/'; } std::vector pkg_deps; }; /** * Target to build script summary documentation. */ class ScriptSummaryTarget : public ScriptTarget { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ ScriptSummaryTarget(const std::string& name, const std::string& pattern) : ScriptTarget(name, pattern) { } private: void DoGenerate() const override /* override */; }; /** * Target to build script index documentation. */ class ScriptIndexTarget : public ScriptTarget { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ ScriptIndexTarget(const std::string& name, const std::string& pattern) : ScriptTarget(name, pattern) { } private: void DoGenerate() const override /* override */; }; /** * Target to build identifier documentation. */ class IdentifierTarget : public Target { public: /** * Ctor. * @param name Output file name. * @param pattern Dependency pattern. */ IdentifierTarget(const std::string& name, const std::string& pattern) : Target(name, pattern), id_deps() { } private: void DoFindDependencies(const std::vector& infos) override; void DoGenerate() const override; std::vector id_deps; }; } // namespace zeekygen #endif