📄 helpgen.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: HelpGen.cpp
// Purpose: Main program file for HelpGen
// Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Modified by:
// Created: 06/01/99
// RCS-ID: $Id: HelpGen.cpp,v 1.44 2005/05/31 17:47:45 ABX Exp $
// Copyright: (c) 1999 VZ
// Licence: wxWindows Licence
/////////////////////////////////////////////////////////////////////////////
/*
BUGS
1. wx/string.h confuses C++ parser terribly
2. C++ parser doesn't know about virtual functions, nor static ones
3. param checking is not done for vararg functions
4. type comparison is dumb: it doesn't know that "char *" is the same
that "char []" nor that "const char *" is the same as "char const *"
TODO (+ means fixed), see also the change log at the end of the file.
(i) small fixes in the current version
+1. Quote special TeX characters like '&' and '_' (=> derive from wxFile)
2. Document typedefs
3. Document global variables
4. Document #defines
+5. Program options
6. Include file name/line number in the "diff" messages?
+7. Support for vararg functions
(ii) plans for version 2
1. Use wxTextFile for direct file access to avoid one scan method problems
2. Use command line parser class for the options
3. support for overloaded functions in diff mode (search for OVER)
(iii) plans for version 3
1. Merging with existing files
2. GUI
*/
// =============================================================================
// declarations
// =============================================================================
// -----------------------------------------------------------------------------
// headers
// -----------------------------------------------------------------------------
// wxWidgets
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_UNICODE
#error "HelpGen doesn't build in Unicode mode"
#endif
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/log.h"
#include "wx/dynarray.h"
#include "wx/app.h"
#endif // WX_PRECOMP
#include "wx/file.h"
#include "wx/regex.h"
#include "wx/hash.h"
// C++ parsing classes
#include "cjparser.h"
// standard headers
#include <stdio.h>
#include <time.h>
// -----------------------------------------------------------------------------
// private functions
// -----------------------------------------------------------------------------
// return the label for the given function name (i.e. argument of \label)
static wxString MakeLabel(const wxChar *classname, const wxChar *funcname = NULL);
// return the whole \helpref{arg}{arg_label} string
static wxString MakeHelpref(const wxChar *argument);
// [un]quote special TeX characters (in place)
static void TeXFilter(wxString* str);
static void TeXUnfilter(wxString* str); // also trims spaces
// get all comments associated with this context
static wxString GetAllComments(const spContext& ctx);
// get the string with current time (returns pointer to static buffer)
// timeFormat is used for the call of strftime(3)
static const char *GetCurrentTimeFormatted(const char *timeFormat);
// get the string containing the program version
static const wxString GetVersionString();
// -----------------------------------------------------------------------------
// private classes
// -----------------------------------------------------------------------------
// a function documentation entry
struct FunctionDocEntry
{
FunctionDocEntry(const wxString& name_, const wxString& text_)
: name(name_), text(text_) { }
// the function name
wxString name;
// the function doc text
wxString text;
// sorting stuff
static int Compare(FunctionDocEntry **pp1, FunctionDocEntry **pp2)
{
// the methods should appear in the following order: ctors, dtor, all
// the rest in the alphabetical order
bool isCtor1 = (*pp1)->name == classname;
bool isCtor2 = (*pp2)->name == classname;
if ( isCtor1 ) {
if ( isCtor2 ) {
// we don't order the ctors because we don't know how to do it
return 0;
}
// ctor comes before non-ctor
return -1;
}
else {
if ( isCtor2 ) {
// non-ctor must come after ctor
return 1;
}
wxString dtorname = wxString(_T("~")) + classname;
// there is only one dtor, so the logic here is simpler
if ( (*pp1)->name == dtorname ) {
return -1;
}
else if ( (*pp2)->name == dtorname ) {
return 1;
}
// two normal methods
return wxStrcmp((*pp1)->name, (*pp2)->name);
}
}
static wxString classname;
};
wxString FunctionDocEntry::classname;
WX_DECLARE_OBJARRAY(FunctionDocEntry, FunctionDocEntries);
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(FunctionDocEntries);
// add a function which sanitazes the string before writing it to the file and
// also capable of delaying output and sorting it before really writing it to
// the file (done from FlushAll())
class wxTeXFile : public wxFile
{
public:
wxTeXFile() { }
// write a string to file verbatim (should only be used for the strings
// inside verbatim environment)
void WriteVerbatim(const wxString& s)
{
m_text += s;
}
// write a string quoting TeX specials in it
void WriteTeX(const wxString& s)
{
wxString t(s);
TeXFilter(&t);
m_text += t;
}
// do write everything to file
bool FlushAll()
{
if ( m_text.empty() )
return true;
if ( !Write(m_text) ) {
wxLogError(_T("Failed to output generated documentation."));
return false;
}
m_text.clear();
return true;
}
private:
wxTeXFile(const wxTeXFile&);
wxTeXFile& operator=(const wxTeXFile&);
wxString m_text;
};
// helper class which manages the classes and function names to ignore for
// the documentation purposes (used by both HelpGenVisitor and DocManager)
class IgnoreNamesHandler
{
public:
IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries) { }
~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore); }
// load file with classes/functions to ignore (add them to the names we
// already have)
bool AddNamesFromFile(const wxString& filename);
// return true if we ignore this function
bool IgnoreMethod(const wxString& classname,
const wxString& funcname) const
{
if ( IgnoreClass(classname) )
return true;
IgnoreListEntry ignore(classname, funcname);
return m_ignore.Index(&ignore) != wxNOT_FOUND;
}
// return true if we ignore this class entirely
bool IgnoreClass(const wxString& classname) const
{
IgnoreListEntry ignore(classname, wxEmptyString);
return m_ignore.Index(&ignore) != wxNOT_FOUND;
}
protected:
struct IgnoreListEntry
{
IgnoreListEntry(const wxString& classname,
const wxString& funcname)
: m_classname(classname), m_funcname(funcname)
{
}
wxString m_classname;
wxString m_funcname; // if empty, ignore class entirely
};
static int CompareIgnoreListEntries(IgnoreListEntry *first,
IgnoreListEntry *second);
// for efficiency, let's sort it
public: // FIXME: macro requires it
WX_DEFINE_SORTED_ARRAY(IgnoreListEntry *, ArrayNamesToIgnore);
protected:
ArrayNamesToIgnore m_ignore;
private:
IgnoreNamesHandler(const IgnoreNamesHandler&);
IgnoreNamesHandler& operator=(const IgnoreNamesHandler&);
};
// visitor implementation which writes all collected data to a .tex file
class HelpGenVisitor : public spVisitor
{
public:
// ctor
HelpGenVisitor(const wxString& directoryOut, bool overwrite);
virtual void VisitFile( spFile& fl );
virtual void VisitClass( spClass& cl );
virtual void VisitEnumeration( spEnumeration& en );
virtual void VisitTypeDef( spTypeDef& td );
virtual void VisitPreprocessorLine( spPreprocessorLine& pd );
virtual void VisitAttribute( spAttribute& attr );
virtual void VisitOperation( spOperation& op );
virtual void VisitParameter( spParameter& param );
void EndVisit();
// get our `ignore' object
IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
// shut up g++ warning (ain't it stupid?)
virtual ~HelpGenVisitor() { }
protected:
// (re)initialize the state
void Reset();
// insert documentation for enums/typedefs coming immediately before the
// class declaration into the class documentation
void InsertTypedefDocs();
void InsertEnumDocs();
// write the headers for corresponding sections (only once)
void InsertDataStructuresHeader();
void InsertMethodsHeader();
// terminate the function documentation if it was started
void CloseFunction();
// write out all function docs when there are no more left in this class
// after sorting them in alphabetical order
void CloseClass();
wxString m_directoryOut, // directory for the output
m_fileHeader; // name of the .h file we parse
bool m_overwrite; // overwrite existing files?
wxTeXFile m_file; // file we're writing to now
// state variables
bool m_inClass, // true after file successfully opened
m_inTypesSection, // enums & typedefs go there
m_inMethodSection, // functions go here
m_isFirstParam; // first parameter of current function?
// non empty while parsing a class
wxString m_classname;
// these are only non-empty while parsing a method:
wxString m_funcName, // the function name
m_textFunc; // the function doc text
// the array containing the documentation entries for the functions in the
// class currently being parsed
FunctionDocEntries m_arrayFuncDocs;
// holders for "saved" documentation
wxString m_textStoredTypedefs,
m_textStoredFunctionComment;
// for enums we have to use an array as we can't intermix the normal text
// and the text inside verbatim environment
wxArrayString m_storedEnums,
m_storedEnumsVerb;
// headers included by this file
wxArrayString m_headers;
// ignore handler: tells us which classes to ignore for doc generation
// purposes
IgnoreNamesHandler m_ignoreNames;
private:
HelpGenVisitor(const HelpGenVisitor&);
HelpGenVisitor& operator=(const HelpGenVisitor&);
};
// documentation manager - a class which parses TeX files and remembers the
// functions documented in them and can later compare them with all functions
// found under ctxTop by C++ parser
class DocManager
{
public:
DocManager(bool checkParamNames);
~DocManager();
// returns false on failure
bool ParseTeXFile(const wxString& filename);
// returns false if there were any differences
bool DumpDifferences(spContext *ctxTop) const;
// get our `ignore' object
IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
protected:
// parsing TeX files
// -----------------
// returns the length of 'match' if the string 'str' starts with it or 0
// otherwise
static size_t TryMatch(const wxChar *str, const wxChar *match);
// skip spaces: returns pointer to first non space character (also
// updates the value of m_line)
const char *SkipSpaces(const char *p)
{
while ( isspace(*p) ) {
if ( *p++ == '\n' )
m_line++;
}
return p;
}
// skips characters until the next 'c' in '*pp' unless it ends before in
// which case false is returned and pp points to '\0', otherwise true is
// returned and pp points to 'c'
bool SkipUntil(const char **pp, char c);
// the same as SkipUntil() but only spaces are skipped: on first non space
// character different from 'c' the function stops and returns false
bool SkipSpaceUntil(const char **pp, char c);
// extract the string between {} and modify '*pp' to point at the
// character immediately after the closing '}'. The returned string is empty
// on error.
wxString ExtractStringBetweenBraces(const char **pp);
// the current file and line while we're in ParseTeXFile (for error
// messages)
wxString m_filename;
size_t m_line;
// functions and classes to ignore during diff
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -