diff --git a/src/BroDoc.cc b/src/BroDoc.cc index 6a91f59153..722a8861cd 100644 --- a/src/BroDoc.cc +++ b/src/BroDoc.cc @@ -47,14 +47,7 @@ BroDoc::~BroDoc() if ( reST_file ) if ( fclose( reST_file ) ) fprintf(stderr, "Failed to close %s", reST_filename.c_str()); - FreeBroDocObjPtrList(options); - FreeBroDocObjPtrList(constants); - FreeBroDocObjPtrList(state_vars); - FreeBroDocObjPtrList(types); - FreeBroDocObjPtrList(notices); - FreeBroDocObjPtrList(events); - FreeBroDocObjPtrList(functions); - FreeBroDocObjPtrList(redefs); + FreeBroDocObjPtrList(all); } void BroDoc::AddImport(const std::string& s) @@ -109,7 +102,7 @@ void BroDoc::WriteDocFile() const WriteToDoc("\n`Original Source File <%s>`_\n\n", source_filename.c_str()); - WriteSectionHeading("Summary", '-'); + WriteSectionHeading("Overview", '-'); WriteStringList("%s\n", "%s\n\n", summary); if ( ! imports.empty() ) @@ -120,18 +113,20 @@ void BroDoc::WriteDocFile() const WriteToDoc("\n"); + WriteInterface("Summary", '~', '#', true, true); + if ( ! modules.empty() ) { - WriteSectionHeading("Namespaces", '-'); + WriteSectionHeading("Namespaces", '~'); WriteStringList(".. bro:namespace:: %s\n", modules); WriteToDoc("\n"); } if ( ! notices.empty() ) - WriteBroDocObjList(notices, "Notices", '-'); + WriteBroDocObjList(notices, "Notices", '~'); - WriteInterface("Public Interface", '-', '~', true); - WriteInterface("Private Interface", '-', '~', false); + WriteInterface("Public Interface", '-', '~', true, false); + WriteInterface("Private Interface", '-', '~', false, false); if ( ! port_analysis.empty() ) { @@ -150,16 +145,16 @@ void BroDoc::WriteDocFile() const } void BroDoc::WriteInterface(const char* heading, char underline, - char sub, bool isPublic) const + char sub, bool isPublic, bool isShort) const { WriteSectionHeading(heading, underline); - WriteBroDocObjList(options, isPublic, "Options", sub); - WriteBroDocObjList(constants, isPublic, "Constants", sub); - WriteBroDocObjList(state_vars, isPublic, "State Variables", sub); - WriteBroDocObjList(types, isPublic, "Types", sub); - WriteBroDocObjList(events, isPublic, "Events", sub); - WriteBroDocObjList(functions, isPublic, "Functions", sub); - WriteBroDocObjList(redefs, isPublic, "Redefinitions", sub); + WriteBroDocObjList(options, isPublic, "Options", sub, isShort); + WriteBroDocObjList(constants, isPublic, "Constants", sub, isShort); + WriteBroDocObjList(state_vars, isPublic, "State Variables", sub, isShort); + WriteBroDocObjList(types, isPublic, "Types", sub, isShort); + WriteBroDocObjList(events, isPublic, "Events", sub, isShort); + WriteBroDocObjList(functions, isPublic, "Functions", sub, isShort); + WriteBroDocObjList(redefs, isPublic, "Redefinitions", sub, isShort); } void BroDoc::WriteStringList(const char* format, @@ -179,10 +174,48 @@ void BroDoc::WriteStringList(const char* format, WriteToDoc(last_format, last->c_str()); } +void BroDoc::WriteBroDocObjTable(const BroDocObjList& l) const + { + int max_id_col = 0; + int max_com_col = 0; + BroDocObjList::const_iterator it; + + for ( it = l.begin(); it != l.end(); ++it ) + { + int c = (*it)->ColumnSize(); + if ( c > max_id_col ) max_id_col = c; + c = (*it)->LongestShortDescLen(); + if ( c > max_com_col ) max_com_col = c; + } + + // start table + WriteRepeatedChar('=', max_id_col); + WriteToDoc(" "); + if ( max_com_col == 0 ) WriteToDoc("="); + else WriteRepeatedChar('=', max_com_col); + WriteToDoc("\n"); + + for ( it = l.begin(); it != l.end(); ++it ) + { + if ( it != l.begin() ) + WriteToDoc("\n\n"); + (*it)->WriteReSTCompact(reST_file, max_id_col); + } + + // end table + WriteToDoc("\n"); + WriteRepeatedChar('=', max_id_col); + WriteToDoc(" "); + if ( max_com_col == 0 ) WriteToDoc("="); + else WriteRepeatedChar('=', max_com_col); + WriteToDoc("\n\n"); + } + void BroDoc::WriteBroDocObjList(const BroDocObjList& l, bool wantPublic, const char* heading, - char underline) const + char underline, + bool isShort) const { if ( l.empty() ) return; @@ -196,23 +229,33 @@ void BroDoc::WriteBroDocObjList(const BroDocObjList& l, it = std::find_if(l.begin(), l.end(), f_ptr); if ( it == l.end() ) return; + WriteSectionHeading(heading, underline); + + BroDocObjList filtered_list; + while ( it != l.end() ) { - (*it)->WriteReST(reST_file); + filtered_list.push_back(*it); it = find_if(++it, l.end(), f_ptr); } + + if ( isShort ) + WriteBroDocObjTable(filtered_list); + else + WriteBroDocObjList(filtered_list); } void BroDoc::WriteBroDocObjList(const BroDocObjMap& m, bool wantPublic, const char* heading, - char underline) const + char underline, + bool isShort) const { BroDocObjMap::const_iterator it; BroDocObjList l; for ( it = m.begin(); it != m.end(); ++it ) l.push_back(it->second); - WriteBroDocObjList(l, wantPublic, heading, underline); + WriteBroDocObjList(l, wantPublic, heading, underline, isShort); } void BroDoc::WriteBroDocObjList(const BroDocObjList& l, @@ -220,8 +263,12 @@ void BroDoc::WriteBroDocObjList(const BroDocObjList& l, char underline) const { WriteSectionHeading(heading, underline); - BroDocObjList::const_iterator it; - for ( it = l.begin(); it != l.end(); ++it ) + WriteBroDocObjList(l); + } + +void BroDoc::WriteBroDocObjList(const BroDocObjList& l) const + { + for ( BroDocObjList::const_iterator it = l.begin(); it != l.end(); ++it ) (*it)->WriteReST(reST_file); } @@ -246,12 +293,15 @@ void BroDoc::WriteToDoc(const char* format, ...) const void BroDoc::WriteSectionHeading(const char* heading, char underline) const { WriteToDoc("%s\n", heading); - size_t len = strlen(heading); - for ( size_t i = 0; i < len; ++i ) - WriteToDoc("%c", underline); + WriteRepeatedChar(underline, strlen(heading)); WriteToDoc("\n"); } +void BroDoc::WriteRepeatedChar(char c, size_t n) const + { + for ( size_t i = 0; i < n; ++i ) WriteToDoc("%c", c); + } + void BroDoc::FreeBroDocObjPtrList(BroDocObjList& l) { for ( BroDocObjList::const_iterator it = l.begin(); it != l.end(); ++it ) @@ -259,18 +309,14 @@ void BroDoc::FreeBroDocObjPtrList(BroDocObjList& l) l.clear(); } -void BroDoc::FreeBroDocObjPtrList(BroDocObjMap& l) - { - for ( BroDocObjMap::const_iterator it = l.begin(); it != l.end(); ++it ) - delete it->second; - l.clear(); - } - void BroDoc::AddFunction(BroDocObj* o) { BroDocObjMap::const_iterator it = functions.find(o->Name()); if ( it == functions.end() ) + { functions[o->Name()] = o; + all.push_back(o); + } else functions[o->Name()]->Combine(o); } diff --git a/src/BroDoc.h b/src/BroDoc.h index 08477d51c2..1096a030f3 100644 --- a/src/BroDoc.h +++ b/src/BroDoc.h @@ -88,7 +88,8 @@ public: * Bro language representation of the script option and * also any associated comments about it. */ - void AddOption(const BroDocObj* o) { options.push_back(o); } + void AddOption(const BroDocObj* o) { options.push_back(o); + all.push_back(o); } /** * Schedules documentation of a script constant. An option is @@ -98,7 +99,8 @@ public: * Bro language representation of the script constant and * also any associated comments about it. */ - void AddConstant(const BroDocObj* o) { constants.push_back(o); } + void AddConstant(const BroDocObj* o) { constants.push_back(o); + all.push_back(o); } /** * Schedules documentation of a script state variable. A state variable @@ -107,7 +109,8 @@ public: * Bro language representation of the script state variable * and also any associated comments about it. */ - void AddStateVar(const BroDocObj* o) { state_vars.push_back(o); } + void AddStateVar(const BroDocObj* o) { state_vars.push_back(o); + all.push_back(o); } /** * Schedules documentation of a type declared by the script. @@ -115,7 +118,8 @@ public: * Bro language representation of the script option and * also any associated comments about it. */ - void AddType(const BroDocObj* o) { types.push_back(o); } + void AddType(const BroDocObj* o) { types.push_back(o); + all.push_back(o); } /** * Schedules documentation of a Notice (enum redef) declared by script @@ -123,7 +127,8 @@ public: * Bro language representation of the Notice and also * any associated comments about it. */ - void AddNotice(const BroDocObj* o) { notices.push_back(o); } + void AddNotice(const BroDocObj* o) { notices.push_back(o); + all.push_back(o); } /** * Schedules documentation of an event declared by the script. @@ -131,7 +136,8 @@ public: * Bro language representation of the script event and * also any associated comments about it. */ - void AddEvent(const BroDocObj* o) { events.push_back(o); } + void AddEvent(const BroDocObj* o) { events.push_back(o); + all.push_back(o); } /** * Schedules documentation of a function declared by the script. @@ -147,7 +153,8 @@ public: * Bro language representation of the script identifier * that was redefined and also any associated comments. */ - void AddRedef(const BroDocObj* o) { redefs.push_back(o); } + void AddRedef(const BroDocObj* o) { redefs.push_back(o); + all.push_back(o); } /** * Gets the name of the Bro script source file for which reST @@ -185,6 +192,8 @@ protected: BroDocObjMap functions; BroDocObjList redefs; + BroDocObjList all; + /** * Writes out a list of strings to the reST document. * If the list is empty, prints a newline character. @@ -206,6 +215,13 @@ protected: const std::list& l) const { WriteStringList(format, format, l); } + + /** + * Writes out a table of BroDocObj's to the reST document + * @param l A list of BroDocObj pointers + */ + void WriteBroDocObjTable(const BroDocObjList& l) const; + /** * Writes out a list of BroDocObj objects to the reST document * @param l A list of BroDocObj pointers @@ -215,21 +231,26 @@ protected: * @param heading The title of the section to create in the reST doc. * @param underline The character to use to underline the reST * section heading. + * @param isShort Whether to write the full documentation or a "short" + * version (a single sentence) */ void WriteBroDocObjList(const BroDocObjList& l, bool wantPublic, const char* heading, - char underline) const; + char underline, + bool isShort) const; /** * Wraps the BroDocObjMap into a BroDocObjList and the writes that list * to the reST document - * @see WriteBroDocObjList(const BroDocObjList&, bool, const char*, char) + * @see WriteBroDocObjList(const BroDocObjList&, bool, const char*, char, + bool) */ void WriteBroDocObjList(const BroDocObjMap& m, bool wantPublic, const char* heading, - char underline) const; + char underline, + bool isShort) const; /** * Writes out a list of BroDocObj objects to the reST document @@ -242,6 +263,12 @@ protected: const char* heading, char underline) const; + /** + * Writes out a list of BroDocObj objects to the reST document + * @param l A list of BroDocObj pointers + */ + void WriteBroDocObjList(const BroDocObjList& l) const; + /** * Wraps the BroDocObjMap into a BroDocObjList and the writes that list * to the reST document @@ -266,6 +293,13 @@ protected: */ void WriteSectionHeading(const char* heading, char underline) const; + /** + * Writes out given number of characters to reST document + * @param c the character to write + * @param n the number of characters to write + */ + void WriteRepeatedChar(char c, size_t n) const; + /** * Writes out the reST for either the script's public or private interface * @param heading The title of the interfaces section heading @@ -275,9 +309,11 @@ protected: * sub-sections * @param isPublic Whether to write out the public or private script * interface + * @param isShort Whether to write out the full documentation or a "short" + * description (a single sentence) */ void WriteInterface(const char* heading, char underline, char subunderline, - bool isPublic) const; + bool isPublic, bool isShort) const; private: /** @@ -285,7 +321,6 @@ private: * @param a reference to a list of BroDocObj pointers */ void FreeBroDocObjPtrList(BroDocObjList& l); - void FreeBroDocObjPtrList(BroDocObjMap& l); static bool IsPublicAPI(const BroDocObj* o) { return o->IsPublicAPI(); } static bool IsPrivateAPI(const BroDocObj* o) { return ! o->IsPublicAPI(); } diff --git a/src/BroDocObj.cc b/src/BroDocObj.cc index 85ad2b85cd..1b26334c9e 100644 --- a/src/BroDocObj.cc +++ b/src/BroDocObj.cc @@ -12,6 +12,7 @@ BroDocObj::BroDocObj(const ID* id, std::list*& reST, reST = 0; is_fake_id = is_fake; use_role = 0; + FormulateShortDesc(); } BroDocObj::~BroDocObj() @@ -20,13 +21,84 @@ BroDocObj::~BroDocObj() if ( is_fake_id ) delete broID; } +void BroDocObj::WriteReSTCompact(FILE* file, int max_col) const + { + ODesc desc; + desc.SetQuotes(1); + broID->DescribeReSTShort(&desc); + + fprintf(file, "%s", desc.Description()); + + std::list::const_iterator it; + for ( it = short_desc.begin(); it != short_desc.end(); ++it ) + { + int start_col; + if ( it == short_desc.begin() ) + start_col = max_col - desc.Len() + 1; + else + { + start_col = max_col + 1; + fprintf(file, "\n"); + } + + for ( int i = 0; i < start_col; ++i ) + fprintf(file, " "); + + fprintf(file, "%s", it->c_str()); + } + } + +int BroDocObj::LongestShortDescLen() const + { + size_t max = 0; + std::list::const_iterator it; + for ( it = short_desc.begin(); it != short_desc.end(); ++it ) + if ( it->size() > max ) max = it->size(); + return max; + } + +void BroDocObj::FormulateShortDesc() + { + if ( ! reST_doc_strings ) return; + + short_desc.clear(); + std::list::const_iterator it; + for ( it = reST_doc_strings->begin(); + it != reST_doc_strings->end(); ++it ) + { + // the short description stops at the first sentence + // or the first empty comment + size_t end = it->find_first_of("."); + if ( end == string::npos ) + { + std::string::const_iterator s; + bool empty = true; + for ( s = it->begin(); s != it->end(); ++s ) + if ( *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' ) + { + empty = false; + short_desc.push_back(*it); + break; + } + if ( empty ) break; + } + else + { + short_desc.push_back(it->substr(0, end + 1)); + break; + } + } + } + void BroDocObj::WriteReST(FILE* file) const { int indent_spaces = 3; ODesc desc; desc.SetIndentSpaces(indent_spaces); desc.SetQuotes(1); + broID->DescribeReST(&desc, use_role); + fprintf(file, "%s", desc.Description()); if ( HasDocumentation() ) @@ -45,6 +117,14 @@ void BroDocObj::WriteReST(FILE* file) const fprintf(file, "\n"); } +int BroDocObj::ColumnSize() const + { + ODesc desc; + desc.SetQuotes(1); + broID->DescribeReSTShort(&desc); + return desc.Len(); + } + bool BroDocObj::IsPublicAPI() const { return (broID->Scope() == SCOPE_GLOBAL) || @@ -63,4 +143,5 @@ void BroDocObj::Combine(const BroDocObj* o) } delete o; + FormulateShortDesc(); } diff --git a/src/BroDocObj.h b/src/BroDocObj.h index 0660d510f6..a6f497db50 100644 --- a/src/BroDocObj.h +++ b/src/BroDocObj.h @@ -28,14 +28,27 @@ public: /** * Writes the reST representation of this object which includes - * 1) Any "##" or "##<" stylized comments. + * 1) a reST friendly description of the ID + * 2) "##" or "##<" stylized comments. * Anything after these style of comments is inserted as-is into * the reST document. - * 2) a reST friendly description of the ID - * @param The (already opened) file to write the reST to. + * @param file The (already opened) file to write the reST to. */ void WriteReST(FILE* file) const; + /** + * Writes a compact version of the ID and associated documentation + * for insertion into a table. + * @param file The (already opened) file to write the reST to. + * @param max_col The maximum length of the first table column + */ + void WriteReSTCompact(FILE* file, int max_col) const; + + /** + * @return the column size required by the reST representation of the ID + */ + int ColumnSize() const; + /** * Check whether this documentation is part of the public API. In * other words, this means that the identifier is declared as part of @@ -78,12 +91,27 @@ public: */ const char* Name() const { return broID->Name(); } + /** + * @return the longest string element of the short description's list of + * strings + */ + int LongestShortDescLen() const; + + protected: std::list* reST_doc_strings; + std::list short_desc; const ID* broID; bool is_fake_id; /**< Whether the ID* is a dummy just for doc purposes */ bool use_role; /**< Whether to use a reST role or directive for the ID */ + /** + * Set the short_desc member to be a subset of reST_doc_strings. + * Specifically, short_desc will be everything in reST_doc_strings + * up until the first period or first empty string list element found. + */ + void FormulateShortDesc(); + private: }; diff --git a/src/ID.cc b/src/ID.cc index b3fcf8f5c3..7678953445 100644 --- a/src/ID.cc +++ b/src/ID.cc @@ -607,6 +607,33 @@ void ID::DescribeExtended(ODesc* d) const } } +void ID::DescribeReSTShort(ODesc* d) const + { + if ( is_type ) + d->Add(":bro:type:`"); + else + d->Add(":bro:id:`"); + d->Add(name); + d->Add("`"); + + if ( type ) + { + d->Add(": "); + d->Add(":bro:type:`"); + if ( ! is_type && type->GetTypeID() ) + d->Add(type->GetTypeID()); + else + d->Add(type_name(type->Tag())); + d->Add("`"); + } + + if ( attrs ) + { + d->SP(); + attrs->DescribeReST(d); + } + } + void ID::DescribeReST(ODesc* d, bool is_role) const { if ( is_role ) diff --git a/src/ID.h b/src/ID.h index 90a0862a18..440f9c8d20 100644 --- a/src/ID.h +++ b/src/ID.h @@ -86,6 +86,7 @@ public: void DescribeExtended(ODesc* d) const; // Produces a description that's reST-ready void DescribeReST(ODesc* d, bool is_role=false) const; + void DescribeReSTShort(ODesc* d) const; bool Serialize(SerialInfo* info) const; static ID* Unserialize(UnserialInfo* info);