diff --git a/src/BroDoc.cc b/src/BroDoc.cc index 715e8d9cf9..27895990cf 100644 --- a/src/BroDoc.cc +++ b/src/BroDoc.cc @@ -40,6 +40,7 @@ BroDoc::BroDoc(const std::string& sourcename) else fprintf(stdout, "Created reST document: %s\n", reST_filename.c_str()); #endif + notices = 0; } BroDoc::~BroDoc() @@ -50,9 +51,10 @@ BroDoc::~BroDoc() FreeBroDocObjPtrList(options); FreeBroDocObjPtrList(state_vars); FreeBroDocObjPtrList(types); - FreeBroDocObjPtrList(notices); FreeBroDocObjPtrList(events); FreeBroDocObjPtrList(functions); + FreeBroDocObjPtrList(redefs); + if ( notices ) delete notices; } void BroDoc::SetPacketFilter(const std::string& s) @@ -90,6 +92,10 @@ void BroDoc::WriteDocFile() const WriteStringList(" :bro:script: `%s`\n", " :bro:script: `%s`\n\n", imports); + WriteSectionHeading("Notices", '-'); + if ( notices ) + notices->WriteReST(reST_file); + WriteSectionHeading("Port Analysis", '-'); WriteStringList("%s", port_analysis); @@ -100,15 +106,16 @@ void BroDoc::WriteDocFile() const WriteBroDocObjList(options, true, "Options", '~'); WriteBroDocObjList(state_vars, true, "State Variables", '~'); WriteBroDocObjList(types, true, "Types", '~'); - WriteBroDocObjList(notices, true, "Notices", '~'); WriteBroDocObjList(events, true, "Events", '~'); WriteBroDocObjList(functions, true, "Functions", '~'); + WriteBroDocObjList(redefs, true, "Redefinitions", '~'); WriteSectionHeading("Private Interface", '-'); WriteBroDocObjList(state_vars, false, "State Variables", '~'); WriteBroDocObjList(types, false, "Types", '~'); WriteBroDocObjList(events, false, "Events", '~'); WriteBroDocObjList(functions, false, "Functions", '~'); + WriteBroDocObjList(redefs, false, "Redefinitions", '~'); } void BroDoc::WriteStringList(const char* format, diff --git a/src/BroDoc.h b/src/BroDoc.h index 37adcc8b70..1f5dae78c0 100644 --- a/src/BroDoc.h +++ b/src/BroDoc.h @@ -95,9 +95,10 @@ public: void AddOption(const BroDocObj* o) { options.push_back(o); } void AddStateVar(const BroDocObj* o) { state_vars.push_back(o); } void AddType(const BroDocObj* o) { types.push_back(o); } - void AddNotice(const BroDocObj* o) { notices.push_back(o); } + void AddNotice(const BroDocObj* o) { notices = o; } void AddEvent(const BroDocObj* o) { events.push_back(o); } void AddFunction(const BroDocObj* o) { functions.push_back(o); } + void AddRedef(const BroDocObj* o) { redefs.push_back(o); } /** * Gets the name of the Bro script source file for which reST @@ -128,9 +129,10 @@ protected: std::list options; // identifiers with &redef attr std::list state_vars; // identifiers without &redef? std::list types; - std::list notices; + const BroDocObj* notices; std::list events; std::list functions; + std::list redefs; /** * Writes out a list of strings to the reST document. diff --git a/src/BroDocObj.cc b/src/BroDocObj.cc index b8f3309f05..2b79d9fcdf 100644 --- a/src/BroDocObj.cc +++ b/src/BroDocObj.cc @@ -4,16 +4,19 @@ #include "ID.h" #include "BroDocObj.h" -BroDocObj::BroDocObj(const ID* id, std::list*& reST) +BroDocObj::BroDocObj(const ID* id, std::list*& reST, + bool is_fake) { broID = id; reST_doc_strings = reST; reST = 0; + is_fake_id = is_fake; } BroDocObj::~BroDocObj() { delete reST_doc_strings; + if ( is_fake_id ) delete broID; } void BroDocObj::WriteReST(FILE* file) const diff --git a/src/BroDocObj.h b/src/BroDocObj.h index 0fdbcca8a5..38f3d8f182 100644 --- a/src/BroDocObj.h +++ b/src/BroDocObj.h @@ -15,8 +15,10 @@ public: * @param reST a reference to a pointer of a list of strings that represent the reST documentation for the ID. The pointer will be set to 0 after this constructor finishes. + * @param is_fake whether the ID* is a dummy just for doc purposes */ - BroDocObj(const ID* id, std::list*& reST); + BroDocObj(const ID* id, std::list*& reST, + bool is_fake = false); /** * BroDocObj destructor @@ -60,6 +62,7 @@ public: protected: std::list* reST_doc_strings; const ID* broID; + bool is_fake_id; /**< Whether the ID* is a dummy just for doc purposes */ private: }; diff --git a/src/Type.cc b/src/Type.cc index 56d51e98da..d74d02770c 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1235,7 +1235,10 @@ EnumType::~EnumType() { for ( NameMap::iterator iter = names.begin(); iter != names.end(); ++iter ) delete [] iter->first; + } +CommentedEnumType::~CommentedEnumType() + { for ( CommentMap::iterator iter = comments.begin(); iter != comments.end(); ++iter ) { delete [] iter->first; @@ -1272,7 +1275,7 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va AddNameInternal(module_name, name, val, is_export); } -void EnumType::AddComment(const string& module_name, const char* name, const char* comment) +void CommentedEnumType::AddComment(const string& module_name, const char* name, const char* comment) { if ( ! comment ) return; @@ -1323,6 +1326,12 @@ void EnumType::AddNameInternal(const string& module_name, const char* name, bro_ names[copy_string(fullname.c_str())] = val; } +void CommentedEnumType::AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export) + { + string fullname = make_full_var_name(module_name.c_str(), name); + names[copy_string(fullname.c_str())] = val; + } + bro_int_t EnumType::Lookup(const string& module_name, const char* name) { NameMap::iterator pos = @@ -1344,7 +1353,7 @@ const char* EnumType::Lookup(bro_int_t value) return 0; } -void EnumType::DescribeReST(ODesc* d) const +void CommentedEnumType::DescribeReST(ODesc* d) const { // create temporary, reverse name map so that enums can be documented // in ascending order of their actual integral value instead of by name @@ -1384,10 +1393,6 @@ bool EnumType::DoSerialize(SerialInfo* info) const SERIALIZE(false)) ) return false; - if ( generate_documentation ) - if ( ! (SERIALIZE((unsigned int) comments.size())) ) - return false; - for ( NameMap::const_iterator iter = names.begin(); iter != names.end(); ++iter ) { @@ -1395,14 +1400,6 @@ bool EnumType::DoSerialize(SerialInfo* info) const return false; } - if ( generate_documentation ) - for ( CommentMap::const_iterator it = comments.begin(); - it != comments.end(); ++ it ) - { - if ( ! SERIALIZE(it->first) || ! SERIALIZE(it->second) ) - return false; - } - return true; } @@ -1411,7 +1408,6 @@ bool EnumType::DoUnserialize(UnserialInfo* info) DO_UNSERIALIZE(BroType); unsigned int len; - unsigned int cmnt_len; bool dummy; if ( ! UNSERIALIZE(&counter) || ! UNSERIALIZE(&len) || @@ -1419,10 +1415,6 @@ bool EnumType::DoUnserialize(UnserialInfo* info) ! UNSERIALIZE(&dummy) ) return false; - if ( generate_documentation ) - if ( ! UNSERIALIZE(&cmnt_len) ) - return false; - while ( len-- ) { const char* name; @@ -1433,16 +1425,6 @@ bool EnumType::DoUnserialize(UnserialInfo* info) names[name] = val; } - if ( generate_documentation ) - while ( cmnt_len-- ) - { - const char* cmnt; - const char* name; - if ( ! (UNSERIALIZE_STR(&name, 0) && UNSERIALIZE_STR(&cmnt, 0)) ) - return false; - comments[name] = cmnt; - } - return true; } diff --git a/src/Type.h b/src/Type.h index 1bffa0bbe2..7fc89dfcaf 100644 --- a/src/Type.h +++ b/src/Type.h @@ -480,26 +480,18 @@ public: // added that aren't likewise explicitly initalized. void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export); - void AddComment(const string& module_name, const char* name, const char* comment); - // -1 indicates not found. bro_int_t Lookup(const string& module_name, const char* name); const char* Lookup(bro_int_t value); // Returns 0 if not found - void DescribeReST(ODesc* d) const; - protected: DECLARE_SERIAL(EnumType) - void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export); + virtual void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export); typedef std::map< const char*, bro_int_t, ltstr > NameMap; NameMap names; - // comments are only filled when in "documentation mode" - typedef std::map< const char*, const char*, ltstr > CommentMap; - CommentMap comments; - // The counter is initialized to 0 and incremented on every implicit // auto-increment name that gets added (thus its > 0 if // auto-increment is used). Once an explicit value has been @@ -509,6 +501,24 @@ protected: bro_int_t counter; }; +class CommentedEnumType: public EnumType { +public: + CommentedEnumType() {} + ~CommentedEnumType(); + void DescribeReST(ODesc* d) const; + void AddComment(const string& module_name, const char* name, const char* comment); + +protected: + // This overriden method does not install the given ID name into a + // scope and it also does not do any kind of checking that the provided + // name already exists. + void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export); + + // comments are only filled when in "documentation mode" + typedef std::map< const char*, const char*, ltstr > CommentMap; + CommentMap comments; +}; + class VectorType : public BroType { public: VectorType(BroType* t); diff --git a/src/parse.y b/src/parse.y index e9ee044c50..5e4966fd5e 100644 --- a/src/parse.y +++ b/src/parse.y @@ -116,6 +116,7 @@ bool resolving_global_ID = false; ID* func_id = 0; EnumType *cur_enum_type = 0; +CommentedEnumType *cur_enum_type_doc = 0; const char* cur_enum_elem_id = 0; static void parser_new_enum (void) @@ -123,6 +124,10 @@ static void parser_new_enum (void) /* Starting a new enum definition. */ assert(cur_enum_type == NULL); cur_enum_type = new EnumType(); + // for documentation purpose, a separate type object is created + // in order to avoid overlap that can be caused by redefs + if ( generate_documentation ) + cur_enum_type_doc = new CommentedEnumType(); } static void parser_redef_enum (ID *id) @@ -138,6 +143,24 @@ static void parser_redef_enum (ID *id) if ( ! cur_enum_type ) id->Error("not an enum"); } + + if ( generate_documentation ) + cur_enum_type_doc = new CommentedEnumType(); + } + +static void add_enum_comment (const char* comment) + { + cur_enum_type_doc->AddComment(current_module, cur_enum_elem_id, comment); + } + +static ID* create_dummy_id (const char* name, const BroType* type) + { + // normally, install_ID() figures out the right IDScope + // but it doesn't matter for the dummy ID so use SCOPE_GLOBAL + ID* fake_id = new ID(copy_string(name), SCOPE_GLOBAL, is_export); + fake_id->SetType(cur_enum_type_doc); + fake_id->MakeType(); + return fake_id; } static char* concat_opt_docs (const char* pre, const char* post) @@ -615,7 +638,7 @@ enum_body: $$ = cur_enum_type; if ( generate_documentation ) { - cur_enum_type->AddComment(current_module, cur_enum_elem_id, $2); + add_enum_comment($2); cur_enum_elem_id = 0; } cur_enum_type = NULL; @@ -625,7 +648,7 @@ enum_body: $$ = cur_enum_type; if ( generate_documentation ) { - cur_enum_type->AddComment(current_module, cur_enum_elem_id, $3); + add_enum_comment($3); cur_enum_elem_id = 0; } cur_enum_type = NULL; @@ -636,12 +659,12 @@ enum_body_list: enum_body_elem opt_post_doc_list { if ( generate_documentation ) - cur_enum_type->AddComment(current_module, cur_enum_elem_id, $2); + add_enum_comment($2); } | enum_body_list ',' opt_post_doc_list { if ( generate_documentation ) - cur_enum_type->AddComment(current_module, cur_enum_elem_id, $3); + add_enum_comment($3); } enum_body_elem ; @@ -662,8 +685,9 @@ enum_body_elem: if ( generate_documentation ) { + cur_enum_type_doc->AddName(current_module, $2, $4->InternalUnsigned(), is_export); cur_enum_elem_id = $2; - cur_enum_type->AddComment(current_module, cur_enum_elem_id, $1); + add_enum_comment($1); } } @@ -684,8 +708,9 @@ enum_body_elem: if ( generate_documentation ) { + cur_enum_type_doc->AddName(current_module, $2, is_export); cur_enum_elem_id = $2; - cur_enum_type->AddComment(current_module, cur_enum_elem_id, $1); + add_enum_comment($1); } } ; @@ -957,23 +982,42 @@ decl: add_global($2, $3, $4, $5, $6, VAR_REDEF); if ( generate_documentation ) { - // TODO: eventually handle type redefs that add record fields + // TODO: handle more types of redefs, e.g. adding record fields } } | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO - '{' { parser_redef_enum($3); } enum_body '}' ';' + '{' { parser_redef_enum($3); do_doc_token_start(); } enum_body '}' ';' { - /* no action */ - // TODO: handle "Notice" redefinitions for doc framework + do_doc_token_stop(); + if ( generate_documentation ) + { + ID* fake_id = create_dummy_id($3->Name(), cur_enum_type_doc); + cur_enum_type_doc = 0; + BroDocObj* o = new BroDocObj(fake_id, reST_doc_comments, true); + if ( streq(fake_id->Name(), "Notice" ) ) + current_reST_doc->AddNotice(o); + else + current_reST_doc->AddRedef(o); + } } | TOK_TYPE global_id ':' refined_type opt_attr ';' { add_type($2, $4, $5, 0); if ( generate_documentation ) - current_reST_doc->AddType( - new BroDocObj($2, reST_doc_comments)); + { + if ( $2->AsType()->Tag() == TYPE_ENUM && cur_enum_type_doc ) + { + ID* fake = create_dummy_id($2->Name(), cur_enum_type_doc); + cur_enum_type_doc = 0; + current_reST_doc->AddType( + new BroDocObj(fake, reST_doc_comments, true)); + } + else + current_reST_doc->AddType( + new BroDocObj($2, reST_doc_comments)); + } } | TOK_EVENT event_id ':' refined_type opt_attr ';'