diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c427188ca..88cee2ec29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,6 @@ if (NOT BRO_SCRIPT_INSTALL_PATH) # set the default Bro script installation path (user did not specify one) set(BRO_SCRIPT_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro) endif () -set(BRO_SCRIPT_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/scripts) # sanitize the Bro script install directory into an absolute path # (CMake is confused by ~ as a representation of home directory) diff --git a/bro-path-dev.in b/bro-path-dev.in index 2c17d057c9..de8b0274b9 100755 --- a/bro-path-dev.in +++ b/bro-path-dev.in @@ -10,10 +10,4 @@ # BROPATH=`./bro-path-dev` ./src/bro # -broPolicies=${BRO_SCRIPT_SOURCE_PATH}:${BRO_SCRIPT_SOURCE_PATH}/policy:${BRO_SCRIPT_SOURCE_PATH}/site - -broGenPolicies=${CMAKE_BINARY_DIR}/scripts - -installedPolicies=${BRO_SCRIPT_INSTALL_PATH}:${BRO_SCRIPT_INSTALL_PATH}/site - -echo .:$broPolicies:$broGenPolicies +echo .:${CMAKE_SOURCE_DIR}/scripts:${CMAKE_SOURCE_DIR}/scripts/policy:${CMAKE_SOURCE_DIR}/scripts/site:${CMAKE_BINARY_DIR}/scripts diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4145984f3b..dec2ea6680 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -371,6 +371,7 @@ set(bro_SRCS plugin/Macros.h broxygen/Manager.cc + broxygen/Document.cc nb_dns.c digest.h diff --git a/src/DebugLogger.cc b/src/DebugLogger.cc index 95049ef70b..78377eafcf 100644 --- a/src/DebugLogger.cc +++ b/src/DebugLogger.cc @@ -17,7 +17,7 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = { { "dpd", 0, false }, { "tm", 0, false }, { "logging", 0, false }, {"input", 0, false }, { "threading", 0, false }, { "file_analysis", 0, false }, - { "plugins", 0, false} + { "plugins", 0, false }, { "broxygen", 0, false } }; DebugLogger::DebugLogger(const char* filename) diff --git a/src/DebugLogger.h b/src/DebugLogger.h index c5744642f5..d1f053788e 100644 --- a/src/DebugLogger.h +++ b/src/DebugLogger.h @@ -28,6 +28,7 @@ enum DebugStream { DBG_THREADING, // Threading system DBG_FILE_ANALYSIS, // File analysis DBG_PLUGINS, + DBG_BROXYGEN, NUM_DBGS // Has to be last }; diff --git a/src/broxygen/Document.cc b/src/broxygen/Document.cc new file mode 100644 index 0000000000..ab8aca08aa --- /dev/null +++ b/src/broxygen/Document.cc @@ -0,0 +1,74 @@ +#include "Document.h" + +#include "util.h" + +using namespace broxygen; +using namespace std; + +PackageDocument::PackageDocument(const string& arg_name) + : Document(), + pkg_loader_name(arg_name) + { + // TODO: probably need to determine modification times of all files + // within the directory, recursively + } + +IdentifierDocument::IdentifierDocument(ID* arg_id) + : Document(), + comments(), id(arg_id), initial_val(), redefs(), fields(), + last_field_seen() + { + Ref(id); + + if ( id->ID_Val() ) + initial_val = id->ID_Val()->Clone(); + } + +IdentifierDocument::~IdentifierDocument() + { + Unref(id); + //Unref(initial_val); // TODO: problematic w/ PatternVals + + for ( RedefList::const_iterator it = redefs.begin(); it != redefs.end(); + ++it ) + delete *it; + + for ( size_t i = 0; i < fields.size(); ++i ) + delete fields[i]; + } + +void IdentifierDocument::AddRedef(const string& script, + const vector& comments) + { + Redefinition* redef = new Redefinition(); + redef->from_script = script; + redef->new_val = id->ID_Val() ? id->ID_Val()->Clone() : 0; + redef->comments = comments; + redefs.push_back(redef); + } + +void IdentifierDocument::AddRecordField(const TypeDecl* field, + const string& script, + std::vector& comments) + { + RecordField* rf = new RecordField(); + rf->field = new TypeDecl(*field); + rf->from_script = script; + rf->comments = comments; + fields.push_back(rf); + last_field_seen = rf; + } + +ScriptDocument::ScriptDocument(const string& arg_name) + : Document(), + name(arg_name), + is_pkg_loader(safe_basename(name) == PACKAGE_LOADER), + dependencies(), module_usages(), comments(), identifier_docs() + { + } + +void ScriptDocument::AddIdentifierDoc(IdentifierDocument* doc) + { + identifier_docs[doc->Name()] = doc; + // TODO: sort things (e.g. function flavor, state var vs. option var) + } diff --git a/src/broxygen/Document.h b/src/broxygen/Document.h new file mode 100644 index 0000000000..34742f8069 --- /dev/null +++ b/src/broxygen/Document.h @@ -0,0 +1,154 @@ +#ifndef BROXYGEN_DOCUMENT_H +#define BROXYGEN_DOCUMENT_H + +#include +#include +#include +#include +#include +#include +#include + +#include "ID.h" +#include "Val.h" +#include "Type.h" + +namespace broxygen { + +// TODO: documentation... + +class Document { + +public: + + Document() + { } + + virtual ~Document() + { } + + time_t GetModificationTime() const + { return DoGetModificationTime(); } + +private: + + virtual time_t DoGetModificationTime() const = 0; +}; + +class PackageDocument : public Document { + +public: + + PackageDocument(const std::string& name); + +private: + + // TODO + time_t DoGetModificationTime() const + { return 0; } + + std::string pkg_loader_name; +}; + + +class IdentifierDocument : public Document { + +public: + + IdentifierDocument(ID* id); + + ~IdentifierDocument(); + + void AddComment(const std::string& comment) + { last_field_seen ? last_field_seen->comments.push_back(comment) + : comments.push_back(comment); } + + void AddComments(const std::vector& cmtns) + { comments.insert(comments.end(), cmtns.begin(), cmtns.end() ); } + + void AddRedef(const std::string& from_script, + const std::vector& comments); + + void AddRecordField(const TypeDecl* field, const std::string& script, + std::vector& comments); + + string Name() const + { return id->Name(); } + + ID* GetID() const + { return id; } + +private: + + struct Redefinition { + ~Redefinition() + { Unref(new_val); } + + std::string from_script; + Val* new_val; + std::vector comments; + }; + + struct RecordField { + ~RecordField() + { delete field; } + + TypeDecl* field; + std::string from_script; + std::vector comments; + }; + + typedef std::list RedefList; + + // TODO + time_t DoGetModificationTime() const + { return 0; } + + std::vector comments; + ID* id; + Val* initial_val; + RedefList redefs; + std::vector fields; + RecordField* last_field_seen; +}; + +class ScriptDocument : public Document { + +public: + + ScriptDocument(const std::string& name); + + void AddComment(const std::string& comment) + { comments.push_back(comment); } + + void AddDependency(const std::string& name) + { dependencies.insert(name); } + + void AddModule(const std::string& name) + { module_usages.insert(name); } + + void AddIdentifierDoc(IdentifierDocument* doc); + + bool IsPkgLoader() const + { return is_pkg_loader; } + +private: + + typedef std::map IdentifierDocMap; + + // TODO + time_t DoGetModificationTime() const + { return 0; } + + std::string name; + bool is_pkg_loader; + std::set dependencies; + std::set module_usages; + std::vector comments; + IdentifierDocMap identifier_docs; +}; + + +} // namespace broxygen + +#endif diff --git a/src/broxygen/Manager.cc b/src/broxygen/Manager.cc index ee995d8b4a..8d01c51224 100644 --- a/src/broxygen/Manager.cc +++ b/src/broxygen/Manager.cc @@ -1,88 +1,384 @@ #include "Manager.h" +#include "Reporter.h" +#include "util.h" + +#include using namespace broxygen; +using namespace std; -Manager::Manager(const std::string& config) +static void DbgAndWarn(const char* msg) { - // TODO + reporter->InternalWarning("%s", msg); + DBG_LOG(DBG_BROXYGEN, "%s", msg); + } + +static string RemoveLeadingSpace(const string& s) + { + if ( s.empty() || s[0] != ' ' ) + return s; + + // Treat "##Text" and "## Text" the same, so that a single space doesn't + // cause reST formatting to think the later is indented a level. + string rval = s; + rval.erase(0, 1); + return rval; + } + +static string PrettifyParams(const string& s) + { + size_t identifier_start_pos = 0; + bool in_identifier = false; + string identifier; + + for ( size_t i = 0; i < s.size(); ++i ) + { + char next = s[i]; + + if ( ! in_identifier ) + { + // Pass by leading whitespace. + if ( isspace(next) ) + continue; + + // Only allow alphabetic and '_' as first char of identifier. + if ( isalpha(next) || next == '_' ) + { + identifier_start_pos = i; + identifier += next; + in_identifier = true; + continue; + } + + // Don't need to change anything. + return s; + } + + // All other character of identifier are alphanumeric or '_'. + if ( isalnum(next) || next == '_' ) + { + identifier += next; + continue; + } + + // Prettify param and return value docs for a function's reST markup. + if ( next == ':' ) + { + string rval = s; + string subst; + + if ( identifier == "Returns" ) + subst = "\n:returns"; + else + subst = "\n:param " + identifier; + + rval.replace(identifier_start_pos, identifier.size(), subst); + return rval; + } + + // Don't need to change anything. + return s; + } + + return s; + } + +Manager::Manager(const string& config) + : comment_buffer(), packages(), scripts(), identifiers(), all_docs(), + last_doc_seen(), incomplete_type() + { + // TODO config file stuff + } + +Manager::~Manager() + { + for ( DocSet::const_iterator it = all_docs.begin(); it != all_docs.end(); + ++it ) + delete *it; + } + +void Manager::InitPreScript() + { + // TODO: create file/proto analyzer doc + } + +void Manager::InitPostScript() + { + // TODO: dependency resolution stuff? } void Manager::GenerateDocs() const { // TODO - // may be a no-op if no config - - // does the old canon_doc_func_param stuff happen here now on the fly - // for functions we're about to document? + // may be a no-op if no config file } -void Manager::File(const std::string& path) +void Manager::File(const string& path) { - // TODO - // can be a file or directory? - // determine path within BROPATH + string name = without_bropath_component(path); + + if ( scripts.find(name) != scripts.end() ) + { + DbgAndWarn(fmt("Duplicate script documentation: %s", name.c_str())); + return; + } + + ScriptDocument* doc = new ScriptDocument(name); + scripts[name] = doc; + RegisterDoc(doc); + DBG_LOG(DBG_BROXYGEN, "Made ScriptDocument %s", name.c_str()); + + if ( ! doc->IsPkgLoader() ) + return; + + if ( packages.find(name) != packages.end() ) + { + DbgAndWarn(fmt("Duplicate package documentation: %s", name.c_str())); + return; + } + + packages[name] = new PackageDocument(name); + DBG_LOG(DBG_BROXYGEN, "Made PackageDocument %s", name.c_str()); } -void Manager::ScriptDependency(const std::string& path, const std::string& dep) +void Manager::ScriptDependency(const string& path, const string& dep) { - // TODO: - // need anything from BroDoc::AddImport? - // warn about unconsumed comments (and discard any) + if ( dep.empty() ) + { + DbgAndWarn(fmt("Empty script doc dependency: %s", path.c_str())); + return; + } + + string name = without_bropath_component(path); + string depname = without_bropath_component(dep); + ScriptMap::const_iterator it = scripts.find(name); + + if ( it == scripts.end() ) + { + DbgAndWarn(fmt("Failed to add script doc dependency %s for %s", + depname.c_str(), name.c_str())); + return; + } + + it->second->AddDependency(depname); + DBG_LOG(DBG_BROXYGEN, "Added script dependency %s for %s", + depname.c_str(), name.c_str()); + + for ( CommentBuffer::const_iterator it = comment_buffer.begin(); + it != comment_buffer.end(); ++it ) + DbgAndWarn(fmt("Discarded extraneous Broxygen comment: %s", + it->c_str())); } -void Manager::ModuleUsage(const std::string& path, const std::string& module) +void Manager::ModuleUsage(const string& path, const string& module) { - // TODO lookup script and add module to a set + string name = without_bropath_component(path); + ScriptMap::const_iterator it = scripts.find(name); + + if ( it == scripts.end() ) + { + DbgAndWarn(fmt("Failed to add module usage %s in %s", + module.c_str(), name.c_str())); + return; + } + + DBG_LOG(DBG_BROXYGEN, "Added module usage %s in %s", + module.c_str(), name.c_str()); } -void Manager::Identifier(const ID *id) +void Manager::StartType(ID* id) { - // TODO: lookup script to associate w/ by GetLocationInfo()->filename - // do different things depending on Type? (eg function flavor versus state) - // do different things based on redef attr + const ? - // consume any buffered comments and associate w/ id - // deal w/ type aliasing - // special enum or record handing? - // if it's a function we may already have added it (decl versus impl) + if ( id->GetLocationInfo() == &no_location ) + { + DbgAndWarn(fmt("Can't document %s, no location available", id->Name())); + return; + } + + string script = without_bropath_component(id->GetLocationInfo()->filename); + ScriptMap::const_iterator sit = scripts.find(script); + + if ( sit == scripts.end() ) + { + DbgAndWarn(fmt("Can't document identifier %s, lookup of %s failed", + id->Name(), script.c_str())); + return; + } + + IdentifierDocument* doc = new IdentifierDocument(id); + doc->AddComments(comment_buffer); + comment_buffer.clear(); + identifiers[id->Name()] = doc; + RegisterDoc(doc); + sit->second->AddIdentifierDoc(doc); + incomplete_type = doc; + DBG_LOG(DBG_BROXYGEN, "Made IdentifierDocument (incomplete) %s, in %s", + id->Name(), script.c_str()); } -void Manager::RecordField(const ID *id, const TypeDecl *field, - const std::string& path) +void Manager::Identifier(ID* id) { - // TODO: consume comments - // redef is implicit -- script path of field will differ from ID/type's + if ( incomplete_type && incomplete_type->Name() == id->Name() ) + { + DBG_LOG(DBG_BROXYGEN, "Finished document for type %s", id->Name()); + incomplete_type = 0; + return; + } + + if ( id->GetLocationInfo() == &no_location ) + { + // Internally-created identifier (e.g. file/proto analyzer enum tags). + // Can be ignored here as they need to be documented via other means. + DBG_LOG(DBG_BROXYGEN, "Skip documenting identifier %s: no location", + id->Name()); + return; + } + + IdentifierMap::const_iterator iit = identifiers.find(id->Name()); + + if ( iit != identifiers.end() ) + { + if ( IsFunc(iit->second->GetID()->Type()->Tag()) ) + { + // Function may already been seen (declaration versus body). + iit->second->AddComments(comment_buffer); + comment_buffer.clear(); + return; + } + + DbgAndWarn(fmt("Duplicate identifier documentation: %s", id->Name())); + return; + } + + string script = without_bropath_component(id->GetLocationInfo()->filename); + ScriptMap::const_iterator sit = scripts.find(script); + + if ( sit == scripts.end() ) + { + DbgAndWarn(fmt("Can't document identifier %s, lookup of %s failed", + id->Name(), script.c_str())); + return; + } + + IdentifierDocument* doc = new IdentifierDocument(id); + doc->AddComments(comment_buffer); + comment_buffer.clear(); + identifiers[id->Name()] = doc; + RegisterDoc(doc); + sit->second->AddIdentifierDoc(doc); + DBG_LOG(DBG_BROXYGEN, "Made IdentifierDocument %s, in script %s", + id->Name(), script.c_str()); + } + +void Manager::RecordField(const ID* id, const TypeDecl* field, + const string& path) + { + IdentifierDocument* idd = 0; + + if ( incomplete_type ) + { + if ( incomplete_type->Name() != id->Name() ) + { + DbgAndWarn(fmt("Can't document record field %s in record %s, " + "expected record %s", field->id, id->Name(), + incomplete_type->Name().c_str())); + return; + } + + idd = incomplete_type; + } + else + { + IdentifierMap::const_iterator it = identifiers.find(id->Name()); + + if ( it == identifiers.end() ) + { + DbgAndWarn(fmt("Can't document record field %s, unknown record: %s", + field->id, id->Name())); + return; + } + + idd = it->second; + } + + string script = without_bropath_component(path); + + idd->AddRecordField(field, script, comment_buffer); + comment_buffer.clear(); + DBG_LOG(DBG_BROXYGEN, "Document record field %s, identifier %s, script %s", + field->id, id->Name(), script.c_str()); } void Manager::Redef(const ID* id, const string& path) { - // TODO: lookup script w/ 'path' to associate the id in as redef'd - // consume any buffered comments and associate w/ redef'd id - // can sort notices here + if ( path == "" ) + // This is a redef defined on the command line. + return; + + IdentifierMap::const_iterator iit = identifiers.find(id->Name()); + + if ( iit == identifiers.end() ) + { + DbgAndWarn(fmt("Can't document redef of %s, identifier lookup failed", + id->Name())); + return; + } + + string from_script = without_bropath_component(path); + ScriptMap::const_iterator sit = scripts.find(from_script); + + if ( sit == scripts.end() ) + { + DbgAndWarn(fmt("Can't document redef of %s, lookup of %s failed", + id->Name(), from_script.c_str())); + return; + } + + iit->second->AddRedef(from_script, comment_buffer); + comment_buffer.clear(); + DBG_LOG(DBG_BROXYGEN, "Added redef of %s to %s", + id->Name(), from_script.c_str()); } -void Manager::SummaryComment(const std::string& script, - const std::string& comment) +void Manager::SummaryComment(const string& script, const string& comment) { - // TODO - // canon_doc_comment ? + string name = without_bropath_component(script); + ScriptMap::const_iterator it = scripts.find(name); + + if ( it == scripts.end() ) + { + DbgAndWarn(fmt("Lookup of script %s failed for summary comment %s", + name.c_str(), comment.c_str())); + return; + } + + it->second->AddComment(RemoveLeadingSpace(comment)); } -void Manager::PreComment(const std::string& comment) +void Manager::PreComment(const string& comment) { - // TODO - // canon_doc_comment + comment_buffer.push_back(PrettifyParams(RemoveLeadingSpace(comment))); } -void Manager::PostComment(const std::string& comment) +void Manager::PostComment(const string& comment) { - // TODO this gets associated with the last thing registered - // canon_doc_comment + IdentifierDocument* doc = dynamic_cast(last_doc_seen); + + if ( ! doc ) + { + DbgAndWarn(fmt("Discarded comment not associated w/ an identifier %s", + comment.c_str())); + return; + } + + doc->AddComment(RemoveLeadingSpace(comment)); } +void Manager::RegisterDoc(Document* d) + { + if ( ! d ) + return; -// TODO: "canon_doc_comment" means treat "##Text" and "## Text" the same -// so that a single space doesn't generate an indentation level. - - -// TODO: creating proto/file analyzer docs + all_docs.insert(d); + last_doc_seen = d; + } diff --git a/src/broxygen/Manager.h b/src/broxygen/Manager.h index d0665c307d..10b63af945 100644 --- a/src/broxygen/Manager.h +++ b/src/broxygen/Manager.h @@ -1,19 +1,32 @@ #ifndef BROXYGEN_MANAGER_H #define BROXYGEN_MANAGER_H -#include - +#include "Document.h" #include "ID.h" #include "Type.h" +#include +#include +#include +#include + namespace broxygen { +// TODO: documentation... +// TODO: optimize parse time... maybe an env. option to disable doc collection? + class Manager { public: Manager(const std::string& config); + ~Manager(); + + void InitPreScript(); + + void InitPostScript(); + void GenerateDocs() const; void File(const std::string& path); @@ -22,7 +35,9 @@ public: void ModuleUsage(const std::string& path, const std::string& module); - void Identifier(const ID* id); + void StartType(ID* id); + + void Identifier(ID* id); void RecordField(const ID* id, const TypeDecl* field, const std::string& path); @@ -34,6 +49,24 @@ public: void PreComment(const std::string& comment); void PostComment(const std::string& comment); + +private: + + typedef std::vector CommentBuffer; + typedef std::map PackageMap; + typedef std::map ScriptMap; + typedef std::map IdentifierMap; + typedef std::set DocSet; + + void RegisterDoc(Document* d); + + CommentBuffer comment_buffer; + PackageMap packages; + ScriptMap scripts; + IdentifierMap identifiers; + DocSet all_docs; + Document* last_doc_seen; + IdentifierDocument* incomplete_type; }; } // namespace broxygen diff --git a/src/main.cc b/src/main.cc index f61e8cc1c5..764b508749 100644 --- a/src/main.cc +++ b/src/main.cc @@ -850,6 +850,7 @@ int main(int argc, char** argv) plugin_mgr->InitPreScript(); analyzer_mgr->InitPreScript(); file_mgr->InitPreScript(); + broxygen_mgr->InitPreScript(); if ( events_file ) event_player = new EventPlayer(events_file); @@ -882,6 +883,7 @@ int main(int argc, char** argv) plugin_mgr->InitPostScript(); analyzer_mgr->InitPostScript(); file_mgr->InitPostScript(); + broxygen_mgr->InitPostScript(); if ( print_plugins ) { diff --git a/src/parse.y b/src/parse.y index ed79808c78..75be472853 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1039,7 +1039,9 @@ decl: extend_record($3, $8, $11); } - | TOK_TYPE global_id ':' { cur_decl_type_id = $2; } type opt_attr ';' + | TOK_TYPE global_id ':' + { cur_decl_type_id = $2; broxygen_mgr->StartType($2); } + type opt_attr ';' { cur_decl_type_id = 0; add_type($2, $5, $6); diff --git a/src/scan.l b/src/scan.l index 899fa77b66..3ac256969a 100644 --- a/src/scan.l +++ b/src/scan.l @@ -271,7 +271,7 @@ when return TOK_WHEN; @DEBUG return TOK_DEBUG; // marks input for debugger @DIR { - string rval(safe_dirname(::filename)); + string rval = safe_dirname(::filename); if ( ! rval.empty() && rval[0] == '.' ) { @@ -300,13 +300,15 @@ when return TOK_WHEN; @load{WS}{FILE} { const char* new_file = skip_whitespace(yytext + 5); // Skip "@load". - broxygen_mgr->ScriptDependency(::filename, new_file); + string loader = ::filename; // load_files may change ::filename, save copy + string loading = find_relative_file(new_file, "bro"); (void) load_files(new_file); + broxygen_mgr->ScriptDependency(loader, loading); } @load-sigs{WS}{FILE} { const char* file = skip_whitespace(yytext + 10); - string path(find_relative_file(file, "sig")); + string path = find_relative_file(file, "sig"); if ( path.empty() ) reporter->Error("failed to find file associated with @load-sigs %s", @@ -318,7 +320,7 @@ when return TOK_WHEN; @unload{WS}{FILE} { // Skip "@unload". const char* file = skip_whitespace(yytext + 7); - string path(find_relative_file(file, "bro")); + string path = find_relative_file(file, "bro"); if ( path.empty() ) reporter->Error("failed find file associated with @unload %s", file); @@ -751,9 +753,9 @@ int yywrap() if ( ! prefixes[i][0] ) continue; - string sub(find_dir_in_bropath(it->name)); - string flat(flatten_script_name(sub, it->name, prefixes[i])); - string path(find_relative_file(flat, "bro")); + string canon = without_bropath_component(it->name); + string flat = flatten_script_name(canon, prefixes[i]); + string path = find_relative_file(flat, "bro"); if ( ! path.empty() ) { @@ -763,9 +765,9 @@ int yywrap() //printf("====== prefix search ======\n"); //printf("File : %s\n", it->name.c_str()); - //printf("Path : %s\n", sub.c_str()); - //printf("Dotted: %s\n", flat.c_str()); - //printf("Found : %s\n", f ? "T" : "F"); + //printf("Canon : %s\n", canon.c_str()); + //printf("Flat : %s\n", flat.c_str()); + //printf("Found : %s\n", path.empty() ? "F" : "T"); //printf("===========================\n"); } } diff --git a/src/util-config.h.in b/src/util-config.h.in index ff5e28537a..385c789b97 100644 --- a/src/util-config.h.in +++ b/src/util-config.h.in @@ -1,5 +1,2 @@ #define BRO_SCRIPT_INSTALL_PATH "@BRO_SCRIPT_INSTALL_PATH@" -#define BRO_SCRIPT_SOURCE_PATH "@BRO_SCRIPT_SOURCE_PATH@" -#define BRO_BUILD_SOURCE_PATH "@CMAKE_BINARY_DIR@/src" -#define BRO_BUILD_SCRIPTS_PATH "@CMAKE_BINARY_DIR@/scripts" #define BRO_MAGIC_INSTALL_PATH "@BRO_MAGIC_INSTALL_PATH@" diff --git a/src/util.cc b/src/util.cc index 3973ece37d..bf98bb9ed3 100644 --- a/src/util.cc +++ b/src/util.cc @@ -933,7 +933,7 @@ static bool can_read(const string& path) FILE* open_package(string& path, const string& mode) { - string arg_path(path); + string arg_path = path; path.append("/").append(PACKAGE_LOADER); if ( can_read(path) ) @@ -954,7 +954,7 @@ string safe_dirname(const char* path) string safe_dirname(const string& path) { char* tmp = copy_string(path.c_str()); - string rval(dirname(tmp)); + string rval = dirname(tmp); delete [] tmp; return rval; } @@ -969,36 +969,29 @@ string safe_basename(const char* path) string safe_basename(const string& path) { char* tmp = copy_string(path.c_str()); - string rval(basename(tmp)); + string rval = basename(tmp); delete [] tmp; return rval; } -string flatten_script_name(const string& dir, const string& file, - const string& prefix) +string flatten_script_name(const string& name, const string& prefix) { - string dottedform(prefix); + string rval = prefix; - if ( prefix != "" ) - dottedform.append("."); + if ( ! rval.empty() ) + rval.append("."); - dottedform.append(dir); - string bname(safe_basename(file)); + if ( safe_basename(name) == PACKAGE_LOADER ) + rval.append(safe_dirname(name)); + else + rval.append(name); - if ( bname != string(PACKAGE_LOADER) ) - { - if ( dir != "" ) - dottedform.append("."); + size_t i; - dottedform.append(bname); - } + while ( (i = rval.find('/')) != string::npos ) + rval[i] = '.'; - size_t n; - - while ( (n = dottedform.find("/")) != string::npos ) - dottedform.replace(n, 1, "."); - - return dottedform; + return rval; } static vector* tokenize_string(string input, const string& delim, @@ -1058,35 +1051,31 @@ string normalize_path(const string& path) return new_path; } -string find_dir_in_bropath(const string& path) +string without_bropath_component(const string& path) { - size_t p; - string rval(path); + string rval = normalize_path(path); - // get the parent directory of file (if not already a directory) - if ( ! is_dir(path.c_str()) ) - rval = safe_dirname(path); + vector paths; + tokenize_string(bro_path(), ":", &paths); - // first check if this is some subpath of the installed scripts root path, - // if not check if it's a subpath of the script source root path, - // then check if it's a subpath of the build directory (where BIF scripts - // will get generated). - // If none of those, will just use the given directory. - if ( (p = rval.find(BRO_SCRIPT_INSTALL_PATH)) != std::string::npos ) - rval.erase(0, strlen(BRO_SCRIPT_INSTALL_PATH)); - else if ( (p = rval.find(BRO_SCRIPT_SOURCE_PATH)) != std::string::npos ) - rval.erase(0, strlen(BRO_SCRIPT_SOURCE_PATH)); - else if ( (p = rval.find(BRO_BUILD_SOURCE_PATH)) != std::string::npos ) - rval.erase(0, strlen(BRO_BUILD_SOURCE_PATH)); - else if ( (p = rval.find(BRO_BUILD_SCRIPTS_PATH)) != std::string::npos ) - rval.erase(0, strlen(BRO_BUILD_SCRIPTS_PATH)); + for ( size_t i = 0; i < paths.size(); ++i ) + { + string common = normalize_path(paths[i]); - // if root path found, remove path separators until next path component - if ( p != std::string::npos ) + if ( rval.find(common) != 0 ) + continue; + + // Found the containing directory. + rval.erase(0, common.size()); + + // Remove leading path separators. while ( rval.size() && rval[0] == '/' ) rval.erase(0, 1); - return normalize_path(rval); + return rval; + } + + return rval; } static string find_file_in_path(const string& filename, const string& path, @@ -1104,11 +1093,11 @@ static string find_file_in_path(const string& filename, const string& path, return string(); } - string abs_path(path + '/' + filename); + string abs_path = path + '/' + filename; if ( ! opt_ext.empty() ) { - string with_ext(abs_path + '.' + opt_ext); + string with_ext = abs_path + '.' + opt_ext; if ( can_read(with_ext) ) return with_ext; diff --git a/src/util.h b/src/util.h index e35a1605e5..faca450cd8 100644 --- a/src/util.h +++ b/src/util.h @@ -202,6 +202,8 @@ static const SourceID SOURCE_LOCAL = 0; extern void pinpoint(); extern int int_list_cmp(const void* v1, const void* v2); +extern const char* PACKAGE_LOADER; + extern const char* bro_path(); extern const char* bro_magic_path(); extern std::string bro_prefixes(); @@ -216,14 +218,12 @@ std::string safe_basename(const std::string& path); /** * Flatten a script name by replacing '/' path separators with '.'. - * @param dir A directory containing \a file. * @param file A path to a Bro script. If it is a __load__.bro, that part * is discarded when constructing the flattened the name. * @param prefix A string to prepend to the flattened script name. * @return The flattened script name. */ -std::string flatten_script_name(const std::string& dir, - const std::string& file, +std::string flatten_script_name(const std::string& name, const std::string& prefix = ""); /** @@ -235,12 +235,11 @@ std::string flatten_script_name(const std::string& dir, std::string normalize_path(const std::string& path); /** - * Locate a file/direcotry within BROPATH. - * @param path A file/directory to locate within BROPATH. - * @return The directory within BROPATH that \a path located or an absolute - * path to \a path if it couldn't be located in BROPATH + * Strip the BROPATH component from a path. + * @param path A file/directory path that may be within a BROPATH component. + * @return *path* minus the common BROPATH component (if any) removed. */ -std::string find_dir_in_bropath(const std::string& path); +std::string without_bropath_component(const std::string& path); /** * Locate a file within a given search path.