mirror of
https://github.com/zeek/zeek.git
synced 2025-10-01 22:28:20 +00:00
Flesh out Broxygen doc-gathering skeleton.
This commit is contained in:
parent
47d7d9047b
commit
f18436640e
15 changed files with 669 additions and 126 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -371,6 +371,7 @@ set(bro_SRCS
|
|||
plugin/Macros.h
|
||||
|
||||
broxygen/Manager.cc
|
||||
broxygen/Document.cc
|
||||
|
||||
nb_dns.c
|
||||
digest.h
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
74
src/broxygen/Document.cc
Normal file
74
src/broxygen/Document.cc
Normal file
|
@ -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<string>& 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<string>& 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)
|
||||
}
|
154
src/broxygen/Document.h
Normal file
154
src/broxygen/Document.h
Normal file
|
@ -0,0 +1,154 @@
|
|||
#ifndef BROXYGEN_DOCUMENT_H
|
||||
#define BROXYGEN_DOCUMENT_H
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <time.h>
|
||||
|
||||
#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<std::string>& cmtns)
|
||||
{ comments.insert(comments.end(), cmtns.begin(), cmtns.end() ); }
|
||||
|
||||
void AddRedef(const std::string& from_script,
|
||||
const std::vector<std::string>& comments);
|
||||
|
||||
void AddRecordField(const TypeDecl* field, const std::string& script,
|
||||
std::vector<std::string>& 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<std::string> comments;
|
||||
};
|
||||
|
||||
struct RecordField {
|
||||
~RecordField()
|
||||
{ delete field; }
|
||||
|
||||
TypeDecl* field;
|
||||
std::string from_script;
|
||||
std::vector<std::string> comments;
|
||||
};
|
||||
|
||||
typedef std::list<Redefinition*> RedefList;
|
||||
|
||||
// TODO
|
||||
time_t DoGetModificationTime() const
|
||||
{ return 0; }
|
||||
|
||||
std::vector<std::string> comments;
|
||||
ID* id;
|
||||
Val* initial_val;
|
||||
RedefList redefs;
|
||||
std::vector<RecordField*> 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<std::string, IdentifierDocument*> IdentifierDocMap;
|
||||
|
||||
// TODO
|
||||
time_t DoGetModificationTime() const
|
||||
{ return 0; }
|
||||
|
||||
std::string name;
|
||||
bool is_pkg_loader;
|
||||
std::set<std::string> dependencies;
|
||||
std::set<std::string> module_usages;
|
||||
std::vector<std::string> comments;
|
||||
IdentifierDocMap identifier_docs;
|
||||
};
|
||||
|
||||
|
||||
} // namespace broxygen
|
||||
|
||||
#endif
|
|
@ -1,88 +1,384 @@
|
|||
#include "Manager.h"
|
||||
#include "Reporter.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
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 == "<params>" )
|
||||
// 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<IdentifierDocument*>(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;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
#ifndef BROXYGEN_MANAGER_H
|
||||
#define BROXYGEN_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Document.h"
|
||||
#include "ID.h"
|
||||
#include "Type.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
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<std::string> CommentBuffer;
|
||||
typedef std::map<std::string, PackageDocument*> PackageMap;
|
||||
typedef std::map<std::string, ScriptDocument*> ScriptMap;
|
||||
typedef std::map<std::string, IdentifierDocument*> IdentifierMap;
|
||||
typedef std::set<Document*> 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
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
22
src/scan.l
22
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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@"
|
||||
|
|
81
src/util.cc
81
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<string>* 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<string> 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;
|
||||
|
|
15
src/util.h
15
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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue