]> git.saurik.com Git - wxWidgets.git/blame - utils/HelpGen/src/HelpGen.cpp
corrected wxMacSetColorTableEntry (although it is not needed currently)
[wxWidgets.git] / utils / HelpGen / src / HelpGen.cpp
CommitLineData
cecfc5e7
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: HelpGen.cpp
3// Purpose: Main program file for HelpGen
4// Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
5// Modified by:
6// Created: 06/01/99
7// RCS-ID: $Id$
8// Copyright: (c) 1999 VZ
9// Licence: GPL
10/////////////////////////////////////////////////////////////////////////////
11
12/*
5f7cf62f
VZ
13 BUGS
14
15 1. wx/string.h confuses C++ parser terribly
16 2. C++ parser doesn't know about virtual functions, nor static ones
17 3. param checking is not done for vararg functions
18 4. type comparison is dumb: it doesn't know that "char *" is the same
19 that "char []" nor that "const char *" is the same as "char const *"
20
21 TODO (+ means fixed), see also the change log at the end of the file.
cecfc5e7
VZ
22
23 (i) small fixes in the current version
59734eb5 24
cecfc5e7
VZ
25 +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile)
26 2. Document typedefs
27 3. Document global variables
28 4. Document #defines
ed38ec7e 29 +5. Program options
5f7cf62f
VZ
30 6. Include file name/line number in the "diff" messages?
31 +7. Support for vararg functions
cecfc5e7
VZ
32
33 (ii) plans for version 2
34 1. Use wxTextFile for direct file access to avoid one scan method problems
5f7cf62f 35 2. Use command line parser class for the options
d12e3536 36 3. support for overloaded functions in diff mode (search for OVER)
59734eb5 37
5f7cf62f
VZ
38 (iii) plans for version 3
39 1. Merging with existing files
40 2. GUI
cecfc5e7
VZ
41*/
42
43// =============================================================================
44// declarations
45// =============================================================================
46
47// -----------------------------------------------------------------------------
48// headers
49// -----------------------------------------------------------------------------
50
51// wxWindows
52#include "wx/wxprec.h"
53
a3b72ffb
VZ
54#if wxUSE_GUI
55 #error "This is a console program and can be only compiled using wxBase"
56#endif
57
cecfc5e7 58#ifndef WX_PRECOMP
5aa5c1e4
GD
59 #include "wx/string.h"
60 #include "wx/log.h"
61 #include "wx/dynarray.h"
62 #include "wx/wx.h"
cecfc5e7
VZ
63#endif // WX_PRECOMP
64
5aa5c1e4
GD
65#include "wx/file.h"
66#include "wx/regex.h"
eb420090 67#include "wx/hash.h"
3d05544e 68
cecfc5e7
VZ
69// C++ parsing classes
70#include "cjparser.h"
71
72// standard headers
73#include <stdio.h>
74#include <time.h>
75
a7adaeda
VZ
76// argh, Windows defines this
77#ifdef GetCurrentTime
78#undef GetCurrentTime
79#endif
80
5f7cf62f
VZ
81// -----------------------------------------------------------------------------
82// global vars
83// -----------------------------------------------------------------------------
84
28468136
JS
85class HelpGenApp: public wxApp
86{
87public:
88 HelpGenApp() {};
89
a7adaeda
VZ
90 // don't let wxWin parse our cmd line, we do it ourselves
91 virtual bool OnInit() { return TRUE; }
92
93 virtual int OnRun();
28468136
JS
94};
95
31dc7e49 96// IMPLEMENT_APP(HelpGenApp);
28468136 97
cecfc5e7
VZ
98// -----------------------------------------------------------------------------
99// private functions
100// -----------------------------------------------------------------------------
101
ed38ec7e
VZ
102// return the label for the given function name (i.e. argument of \label)
103static wxString MakeLabel(const char *classname, const char *funcname = NULL);
104
105// return the whole \helpref{arg}{arg_label} string
106static wxString MakeHelpref(const char *argument);
107
5f7cf62f 108// [un]quote special TeX characters (in place)
cecfc5e7 109static void TeXFilter(wxString* str);
5f7cf62f 110static void TeXUnfilter(wxString* str); // also trims spaces
cecfc5e7 111
ed38ec7e
VZ
112// get all comments associated with this context
113static wxString GetAllComments(const spContext& ctx);
114
115// get the string with current time (returns pointer to static buffer)
116// timeFormat is used for the call of strftime(3)
117static const char *GetCurrentTime(const char *timeFormat);
118
2f919f99
VZ
119// get the string containing the program version
120static const wxString GetVersionString();
121
cecfc5e7
VZ
122// -----------------------------------------------------------------------------
123// private classes
124// -----------------------------------------------------------------------------
125
d8b6f4d9
VZ
126// a function documentation entry
127struct FunctionDocEntry
128{
129 FunctionDocEntry(const wxString& name_, const wxString& text_)
130 : name(name_), text(text_) { }
131
132 // the function name
133 wxString name;
134
135 // the function doc text
136 wxString text;
137
138 // sorting stuff
139 static int Compare(FunctionDocEntry **pp1, FunctionDocEntry **pp2)
140 {
141 // the methods should appear in the following order: ctors, dtor, all
142 // the rest in the alphabetical order
143 bool isCtor1 = (*pp1)->name == classname;
144 bool isCtor2 = (*pp2)->name == classname;
145
146 if ( isCtor1 ) {
147 if ( isCtor2 ) {
148 // we don't order the ctors because we don't know how to do it
149 return 0;
150 }
151
152 // ctor comes before non-ctor
153 return -1;
154 }
155 else {
156 if ( isCtor2 ) {
157 // non-ctor must come after ctor
158 return 1;
159 }
160
161 wxString dtorname = wxString('~') + classname;
162
163 // there is only one dtor, so the logic here is simpler
164 if ( (*pp1)->name == dtorname ) {
165 return -1;
166 }
167 else if ( (*pp2)->name == dtorname ) {
168 return 1;
169 }
170
171 // two normal methods
172 return strcmp((*pp1)->name, (*pp2)->name);
173 }
174 }
175
176 static wxString classname;
177};
178
179wxString FunctionDocEntry::classname;
180
181WX_DECLARE_OBJARRAY(FunctionDocEntry, FunctionDocEntries);
182
183#include "wx/arrimpl.cpp"
184
185WX_DEFINE_OBJARRAY(FunctionDocEntries);
186
187// add a function which sanitazes the string before writing it to the file and
188// also capable of delaying output and sorting it before really writing it to
189// the file (done from FlushAll())
cecfc5e7
VZ
190class wxTeXFile : public wxFile
191{
192public:
59734eb5 193 wxTeXFile() { }
cecfc5e7 194
a7adaeda
VZ
195 // write a string to file verbatim (should only be used for the strings
196 // inside verbatim environment)
d8b6f4d9 197 void WriteVerbatim(const wxString& s)
a7adaeda 198 {
d8b6f4d9 199 m_text += s;
a7adaeda
VZ
200 }
201
202 // write a string quoting TeX specials in it
d8b6f4d9 203 void WriteTeX(const wxString& s)
cecfc5e7
VZ
204 {
205 wxString t(s);
206 TeXFilter(&t);
207
d8b6f4d9
VZ
208 m_text += t;
209 }
210
211 // do write everything to file
212 bool FlushAll()
213 {
214 if ( m_text.empty() )
215 return TRUE;
216
217 if ( !Write(m_text) ) {
218 wxLogError("Failed to output generated documentation.");
219
220 return FALSE;
221 }
222
223 m_text.clear();
224
225 return TRUE;
cecfc5e7 226 }
59734eb5
VZ
227
228private:
229 wxTeXFile(const wxTeXFile&);
230 wxTeXFile& operator=(const wxTeXFile&);
d8b6f4d9
VZ
231
232 wxString m_text;
cecfc5e7
VZ
233};
234
d12e3536
VZ
235// helper class which manages the classes and function names to ignore for
236// the documentation purposes (used by both HelpGenVisitor and DocManager)
237class IgnoreNamesHandler
238{
239public:
240 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries) { }
241 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore); }
242
243 // load file with classes/functions to ignore (add them to the names we
244 // already have)
245 bool AddNamesFromFile(const wxString& filename);
246
247 // return TRUE if we ignore this function
248 bool IgnoreMethod(const wxString& classname,
249 const wxString& funcname) const
250 {
251 if ( IgnoreClass(classname) )
252 return TRUE;
253
254 IgnoreListEntry ignore(classname, funcname);
255
256 return m_ignore.Index(&ignore) != wxNOT_FOUND;
257 }
258
259 // return TRUE if we ignore this class entirely
260 bool IgnoreClass(const wxString& classname) const
261 {
262 IgnoreListEntry ignore(classname, "");
263
264 return m_ignore.Index(&ignore) != wxNOT_FOUND;
265 }
266
267protected:
268 struct IgnoreListEntry
269 {
270 IgnoreListEntry(const wxString& classname,
271 const wxString& funcname)
272 : m_classname(classname), m_funcname(funcname)
273 {
274 }
275
276 wxString m_classname;
277 wxString m_funcname; // if empty, ignore class entirely
278 };
279
280 static int CompareIgnoreListEntries(IgnoreListEntry *first,
281 IgnoreListEntry *second);
282
283 // for efficiency, let's sort it
284 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry *, ArrayNamesToIgnore);
285
286 ArrayNamesToIgnore m_ignore;
287
288private:
289 IgnoreNamesHandler(const IgnoreNamesHandler&);
290 IgnoreNamesHandler& operator=(const IgnoreNamesHandler&);
291};
292
5f7cf62f 293// visitor implementation which writes all collected data to a .tex file
cecfc5e7
VZ
294class HelpGenVisitor : public spVisitor
295{
296public:
297 // ctor
d12e3536 298 HelpGenVisitor(const wxString& directoryOut, bool overwrite);
cecfc5e7
VZ
299
300 virtual void VisitFile( spFile& fl );
301 virtual void VisitClass( spClass& cl );
302 virtual void VisitEnumeration( spEnumeration& en );
303 virtual void VisitTypeDef( spTypeDef& td );
59734eb5 304 virtual void VisitPreprocessorLine( spPreprocessorLine& pd );
cecfc5e7
VZ
305 virtual void VisitAttribute( spAttribute& attr );
306 virtual void VisitOperation( spOperation& op );
307 virtual void VisitParameter( spParameter& param );
308
309 void EndVisit();
310
d12e3536
VZ
311 // get our `ignore' object
312 IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
313
cecfc5e7
VZ
314 // shut up g++ warning (ain't it stupid?)
315 virtual ~HelpGenVisitor() { }
316
317protected:
318 // (re)initialize the state
319 void Reset();
320
321 // insert documentation for enums/typedefs coming immediately before the
322 // class declaration into the class documentation
323 void InsertTypedefDocs();
324 void InsertEnumDocs();
325
326 // write the headers for corresponding sections (only once)
327 void InsertDataStructuresHeader();
328 void InsertMethodsHeader();
59734eb5 329
cecfc5e7
VZ
330 // terminate the function documentation if it was started
331 void CloseFunction();
332
d8b6f4d9
VZ
333 // write out all function docs when there are no more left in this class
334 // after sorting them in alphabetical order
335 void CloseClass();
336
d12e3536
VZ
337 wxString m_directoryOut, // directory for the output
338 m_fileHeader; // name of the .h file we parse
339 bool m_overwrite; // overwrite existing files?
59734eb5 340 wxTeXFile m_file; // file we're writing to now
cecfc5e7
VZ
341
342 // state variables
343 bool m_inClass, // TRUE after file successfully opened
344 m_inTypesSection, // enums & typedefs go there
345 m_inMethodSection, // functions go here
d8b6f4d9
VZ
346 m_isFirstParam; // first parameter of current function?
347
348 // non empty while parsing a class
349 wxString m_classname;
350
351 // these are only non-empty while parsing a method:
352 wxString m_funcName, // the function name
353 m_textFunc; // the function doc text
354
355 // the array containing the documentation entries for the functions in the
356 // class currently being parsed
357 FunctionDocEntries m_arrayFuncDocs;
cecfc5e7
VZ
358
359 // holders for "saved" documentation
a7adaeda 360 wxString m_textStoredTypedefs,
cecfc5e7 361 m_textStoredFunctionComment;
ed38ec7e 362
a7adaeda
VZ
363 // for enums we have to use an array as we can't intermix the normal text
364 // and the text inside verbatim environment
365 wxArrayString m_storedEnums,
366 m_storedEnumsVerb;
367
59734eb5 368 // headers included by this file
ed38ec7e 369 wxArrayString m_headers;
59734eb5 370
d12e3536
VZ
371 // ignore handler: tells us which classes to ignore for doc generation
372 // purposes
373 IgnoreNamesHandler m_ignoreNames;
374
59734eb5
VZ
375private:
376 HelpGenVisitor(const HelpGenVisitor&);
377 HelpGenVisitor& operator=(const HelpGenVisitor&);
cecfc5e7
VZ
378};
379
5f7cf62f
VZ
380// documentation manager - a class which parses TeX files and remembers the
381// functions documented in them and can later compare them with all functions
382// found under ctxTop by C++ parser
383class DocManager
384{
385public:
d12e3536 386 DocManager(bool checkParamNames);
5f7cf62f
VZ
387 ~DocManager();
388
5f7cf62f
VZ
389 // returns FALSE on failure
390 bool ParseTeXFile(const wxString& filename);
391
392 // returns FALSE if there were any differences
393 bool DumpDifferences(spContext *ctxTop) const;
394
d12e3536
VZ
395 // get our `ignore' object
396 IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
397
5f7cf62f
VZ
398protected:
399 // parsing TeX files
400 // -----------------
401
402 // returns the length of 'match' if the string 'str' starts with it or 0
403 // otherwise
404 static size_t TryMatch(const char *str, const char *match);
405
406 // skip spaces: returns pointer to first non space character (also
407 // updates the value of m_line)
408 const char *SkipSpaces(const char *p)
409 {
410 while ( isspace(*p) ) {
411 if ( *p++ == '\n' )
412 m_line++;
413 }
414
415 return p;
416 }
417
418 // skips characters until the next 'c' in '*pp' unless it ends before in
419 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
420 // returned and pp points to 'c'
421 bool SkipUntil(const char **pp, char c);
422
423 // the same as SkipUntil() but only spaces are skipped: on first non space
424 // character different from 'c' the function stops and returns FALSE
425 bool SkipSpaceUntil(const char **pp, char c);
426
427 // extract the string between {} and modify '*pp' to point at the
428 // character immediately after the closing '}'. The returned string is empty
429 // on error.
430 wxString ExtractStringBetweenBraces(const char **pp);
431
432 // the current file and line while we're in ParseTeXFile (for error
433 // messages)
434 wxString m_filename;
435 size_t m_line;
436
437 // functions and classes to ignore during diff
438 // -------------------------------------------
5f7cf62f 439
d12e3536 440 IgnoreNamesHandler m_ignoreNames;
5f7cf62f
VZ
441
442 // information about all functions documented in the TeX file(s)
443 // -------------------------------------------------------------
444
445 // info about a type: for now stored as text string, but must be parsed
446 // further later (to know that "char *" == "char []" - TODO)
447 class TypeInfo
448 {
449 public:
450 TypeInfo(const wxString& type) : m_type(type) { }
451
452 bool operator==(const wxString& type) const { return m_type == type; }
453 bool operator!=(const wxString& type) const { return m_type != type; }
454
455 const wxString& GetName() const { return m_type; }
456
457 private:
458 wxString m_type;
459 };
460
461 // info abotu a function parameter
462 class ParamInfo
463 {
464 public:
465 ParamInfo(const wxString& type,
466 const wxString& name,
467 const wxString& value)
468 : m_type(type), m_name(name), m_value(value)
469 {
470 }
471
472 const TypeInfo& GetType() const { return m_type; }
473 const wxString& GetName() const { return m_name; }
474 const wxString& GetDefValue() const { return m_value; }
475
476 private:
477 TypeInfo m_type; // type of parameter
478 wxString m_name; // name
479 wxString m_value; // default value
480 };
481
482 WX_DEFINE_ARRAY(ParamInfo *, ArrayParamInfo);
483
484 // info about a function
485 struct MethodInfo
486 {
487 public:
488 enum MethodFlags
489 {
490 Const = 0x0001,
491 Virtual = 0x0002,
492 Pure = 0x0004,
493 Static = 0x0008,
494 Vararg = 0x0010
495 };
496
497 MethodInfo(const wxString& type,
498 const wxString& name,
499 const ArrayParamInfo& params)
500 : m_typeRet(type), m_name(name), m_params(params)
501 {
502 m_flags = 0;
503 }
504
505 void SetFlag(MethodFlags flag) { m_flags |= flag; }
506
507 const TypeInfo& GetType() const { return m_typeRet; }
508 const wxString& GetName() const { return m_name; }
509 const ParamInfo& GetParam(size_t n) const { return *(m_params[n]); }
510 size_t GetParamCount() const { return m_params.GetCount(); }
511
512 bool HasFlag(MethodFlags flag) const { return (m_flags & flag) != 0; }
513
514 ~MethodInfo() { WX_CLEAR_ARRAY(m_params); }
515
516 private:
517 TypeInfo m_typeRet; // return type
518 wxString m_name;
519 int m_flags; // bit mask of the value from the enum above
520
521 ArrayParamInfo m_params;
522 };
523
524 WX_DEFINE_ARRAY(MethodInfo *, ArrayMethodInfo);
525 WX_DEFINE_ARRAY(ArrayMethodInfo *, ArrayMethodInfos);
526
527 // first array contains the names of all classes we found, the second has a
528 // pointer to the array of methods of the given class at the same index as
529 // the class name appears in m_classes
530 wxArrayString m_classes;
531 ArrayMethodInfos m_methods;
d12e3536
VZ
532
533 // are we checking parameter names?
534 bool m_checkParamNames;
535
536private:
537 DocManager(const DocManager&);
538 DocManager& operator=(const DocManager&);
5f7cf62f
VZ
539};
540
cecfc5e7
VZ
541// =============================================================================
542// implementation
543// =============================================================================
544
ed38ec7e
VZ
545// this function never returns
546static void usage()
547{
a7adaeda 548 wxString prog = wxTheApp->argv[0];
f6bcfd97 549 wxString basename = prog.AfterLast('/');
5f7cf62f
VZ
550#ifdef __WXMSW__
551 if ( !basename )
f6bcfd97 552 basename = prog.AfterLast('\\');
5f7cf62f
VZ
553#endif
554 if ( !basename )
555 basename = prog;
556
a7adaeda 557 wxLogMessage(
5f7cf62f
VZ
558"usage: %s [global options] <mode> [mode options] <files...>\n"
559"\n"
560" where global options are:\n"
561" -q be quiet\n"
562" -v be verbose\n"
563" -H give this usage message\n"
564" -V print the version info\n"
d12e3536 565" -i file file with classes/function to ignore\n"
5f7cf62f
VZ
566"\n"
567" where mode is one of: dump, diff\n"
568"\n"
569" dump means generate .tex files for TeX2RTF converter from specified\n"
570" headers files, mode options are:\n"
d12e3536 571" -f overwrite existing files\n"
5f7cf62f
VZ
572" -o outdir directory for generated files\n"
573"\n"
574" diff means compare the set of methods documented .tex file with the\n"
575" methods declared in the header:\n"
576" %s diff <file.h> <files.tex...>.\n"
d12e3536
VZ
577" mode specific options are:\n"
578" -p do check parameter names (not done by default)\n"
5f7cf62f 579"\n", basename.c_str(), basename.c_str());
a7adaeda 580
ed38ec7e
VZ
581 exit(1);
582}
583
de528224 584int HelpGenApp::OnRun()
cecfc5e7 585{
5f7cf62f
VZ
586 enum
587 {
588 Mode_None,
589 Mode_Dump,
590 Mode_Diff
591 } mode = Mode_None;
592
cecfc5e7 593 if ( argc < 2 ) {
ed38ec7e 594 usage();
cecfc5e7
VZ
595 }
596
5f7cf62f 597 wxArrayString filesH, filesTeX;
d12e3536
VZ
598 wxString directoryOut, // directory for 'dmup' output
599 ignoreFile; // file with classes/functions to ignore
600 bool overwrite = FALSE, // overwrite existing files during 'dump'?
601 paramNames = FALSE; // check param names during 'diff'?
59734eb5 602
5f7cf62f 603 for ( int current = 1; current < argc ; current++ ) {
59734eb5 604 // all options have one letter
5f7cf62f
VZ
605 if ( argv[current][0] == '-' ) {
606 if ( argv[current][2] == '\0' ) {
607 switch ( argv[current][1] ) {
608 case 'v':
609 // be verbose
610 wxLog::GetActiveTarget()->SetVerbose();
611 continue;
612
613 case 'q':
614 // be quiet
615 wxLog::GetActiveTarget()->SetVerbose(FALSE);
616 continue;
617
618 case 'H':
619 // help requested
620 usage();
a7adaeda
VZ
621 // doesn't return
622
623 case 'V':
624 // version requested
625 wxLogMessage("HelpGen version %s\n"
626 "(c) 1999-2001 Vadim Zeitlin\n",
2f919f99 627 GetVersionString().c_str());
a7adaeda 628 return 0;
5f7cf62f
VZ
629
630 case 'i':
d12e3536
VZ
631 current++;
632 if ( current >= argc ) {
633 wxLogError("-i option requires an argument.");
634
635 break;
636 }
637
638 ignoreFile = argv[current];
639 continue;
640
641 case 'p':
5f7cf62f 642 if ( mode != Mode_Diff ) {
d12e3536 643 wxLogError("-p is only valid with diff.");
5f7cf62f
VZ
644
645 break;
646 }
59734eb5 647
d12e3536
VZ
648 paramNames = TRUE;
649 continue;
650
651 case 'f':
652 if ( mode != Mode_Dump ) {
653 wxLogError("-f is only valid with dump.");
59734eb5 654
5f7cf62f
VZ
655 break;
656 }
59734eb5 657
d12e3536 658 overwrite = TRUE;
5f7cf62f
VZ
659 continue;
660
661 case 'o':
662 if ( mode != Mode_Dump ) {
663 wxLogError("-o is only valid with dump.");
664
665 break;
666 }
667
668 current++;
669 if ( current >= argc ) {
670 wxLogError("-o option requires an argument.");
671
672 break;
673 }
59734eb5 674
5f7cf62f
VZ
675 directoryOut = argv[current];
676 if ( !!directoryOut ) {
677 // terminate with a '/' if it doesn't have it
678 switch ( directoryOut.Last() ) {
679 case '/':
59734eb5 680#ifdef __WXMSW__
5f7cf62f 681 case '\\':
59734eb5 682#endif
5f7cf62f 683 break;
ed38ec7e 684
5f7cf62f
VZ
685 default:
686 directoryOut += '/';
687 }
59734eb5 688 }
5f7cf62f 689 //else: it's empty, do nothing
59734eb5 690
5f7cf62f 691 continue;
ed38ec7e 692
5f7cf62f 693 default:
d12e3536 694 wxLogError("unknown option '%s'", argv[current]);
5f7cf62f
VZ
695 break;
696 }
59734eb5 697 }
d12e3536
VZ
698 else {
699 wxLogError("only one letter options are allowed, not '%s'.",
700 argv[current]);
701 }
59734eb5 702
5f7cf62f 703 // only get here after a break from switch or from else branch of if
59734eb5 704
5f7cf62f
VZ
705 usage();
706 }
707 else {
708 if ( mode == Mode_None ) {
709 if ( strcmp(argv[current], "diff") == 0 )
710 mode = Mode_Diff;
711 else if ( strcmp(argv[current], "dump") == 0 )
712 mode = Mode_Dump;
713 else {
d12e3536 714 wxLogError("unknown mode '%s'.", argv[current]);
5f7cf62f
VZ
715
716 usage();
717 }
718 }
719 else {
720 if ( mode == Mode_Dump || filesH.IsEmpty() ) {
721 filesH.Add(argv[current]);
722 }
723 else {
724 // 2nd files and further are TeX files in diff mode
725 wxASSERT( mode == Mode_Diff );
726
727 filesTeX.Add(argv[current]);
728 }
729 }
730 }
ed38ec7e 731 }
cecfc5e7
VZ
732
733 // create a parser object and a visitor derivation
734 CJSourceParser parser;
d12e3536
VZ
735 HelpGenVisitor visitor(directoryOut, overwrite);
736 if ( !!ignoreFile && mode == Mode_Dump )
737 visitor.GetIgnoreHandler().AddNamesFromFile(ignoreFile);
738
5f7cf62f 739 spContext *ctxTop = NULL;
cecfc5e7 740
5f7cf62f
VZ
741 // parse all header files
742 size_t nFiles = filesH.GetCount();
743 for ( size_t n = 0; n < nFiles; n++ ) {
744 wxString header = filesH[n];
745 ctxTop = parser.ParseFile(header);
cecfc5e7 746 if ( !ctxTop ) {
5f7cf62f
VZ
747 wxLogWarning("Header file '%s' couldn't be processed.",
748 header.c_str());
cecfc5e7 749 }
5f7cf62f
VZ
750 else if ( mode == Mode_Dump ) {
751 ((spFile *)ctxTop)->mFileName = header;
cecfc5e7
VZ
752 visitor.VisitAll(*ctxTop);
753 visitor.EndVisit();
754 }
d12e3536
VZ
755
756#ifdef __WXDEBUG__
757 if ( 0 && ctxTop )
758 ctxTop->Dump("");
759#endif // __WXDEBUG__
cecfc5e7
VZ
760 }
761
5f7cf62f
VZ
762 // parse all TeX files
763 if ( mode == Mode_Diff ) {
764 if ( !ctxTop ) {
765 wxLogError("Can't complete diff.");
766
767 // failure
a7adaeda 768 return FALSE;
5f7cf62f
VZ
769 }
770
d12e3536 771 DocManager docman(paramNames);
5f7cf62f
VZ
772
773 size_t nFiles = filesTeX.GetCount();
774 for ( size_t n = 0; n < nFiles; n++ ) {
775 wxString file = filesTeX[n];
776 if ( !docman.ParseTeXFile(file) ) {
777 wxLogWarning("TeX file '%s' couldn't be processed.",
778 file.c_str());
779 }
780 }
781
782 if ( !!ignoreFile )
d12e3536 783 docman.GetIgnoreHandler().AddNamesFromFile(ignoreFile);
5f7cf62f
VZ
784
785 docman.DumpDifferences(ctxTop);
786 }
787
a7adaeda 788 return 0;
cecfc5e7
VZ
789}
790
31dc7e49
JS
791int main(int argc, char **argv)
792{
793 wxInitializer initializer;
794 if ( !initializer )
795 {
796 fprintf(stderr, "Failed to initialize the wxWindows library, aborting.");
797
798 return -1;
799 }
800 HelpGenApp app;
801 app.argc = argc;
802 app.argv = argv;
803 return app.OnRun();
804}
805
cecfc5e7
VZ
806// -----------------------------------------------------------------------------
807// HelpGenVisitor implementation
808// -----------------------------------------------------------------------------
809
d12e3536
VZ
810HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut,
811 bool overwrite)
812 : m_directoryOut(directoryOut)
813{
814 m_overwrite = overwrite;
815
816 Reset();
817}
818
cecfc5e7
VZ
819void HelpGenVisitor::Reset()
820{
821 m_inClass =
cecfc5e7 822 m_inTypesSection =
5f7cf62f 823 m_inMethodSection = FALSE;
ed38ec7e 824
d8b6f4d9
VZ
825 m_classname =
826 m_funcName =
827 m_textFunc =
ed38ec7e 828 m_textStoredTypedefs =
ed38ec7e 829 m_textStoredFunctionComment = "";
a7adaeda 830
d8b6f4d9
VZ
831 m_arrayFuncDocs.Empty();
832
a7adaeda
VZ
833 m_storedEnums.Empty();
834 m_storedEnumsVerb.Empty();
ed38ec7e 835 m_headers.Empty();
cecfc5e7
VZ
836}
837
838void HelpGenVisitor::InsertTypedefDocs()
839{
840 m_file.WriteTeX(m_textStoredTypedefs);
841 m_textStoredTypedefs.Empty();
842}
843
844void HelpGenVisitor::InsertEnumDocs()
845{
a7adaeda
VZ
846 size_t count = m_storedEnums.GetCount();
847 for ( size_t n = 0; n < count; n++ )
848 {
849 m_file.WriteTeX(m_storedEnums[n]);
850 m_file.WriteVerbatim(m_storedEnumsVerb[n] + '\n');
851 }
852
853 m_storedEnums.Empty();
854 m_storedEnumsVerb.Empty();
cecfc5e7
VZ
855}
856
857void HelpGenVisitor::InsertDataStructuresHeader()
858{
859 if ( !m_inTypesSection ) {
5f7cf62f 860 m_inTypesSection = TRUE;
cecfc5e7 861
d8b6f4d9 862 m_file.WriteVerbatim("\\wxheading{Data structures}\n\n");
cecfc5e7
VZ
863 }
864}
865
866void HelpGenVisitor::InsertMethodsHeader()
867{
868 if ( !m_inMethodSection ) {
5f7cf62f 869 m_inMethodSection = TRUE;
cecfc5e7 870
d8b6f4d9 871 m_file.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
cecfc5e7
VZ
872 }
873}
874
875void HelpGenVisitor::CloseFunction()
876{
d8b6f4d9 877 if ( !m_funcName.empty() ) {
cecfc5e7
VZ
878 if ( m_isFirstParam ) {
879 // no params found
d8b6f4d9
VZ
880 m_textFunc << "\\void";
881 }
882
883 m_textFunc << "}\n\n";
884
885 if ( !m_textStoredFunctionComment.IsEmpty() ) {
886 m_textFunc << m_textStoredFunctionComment << '\n';
cecfc5e7
VZ
887 }
888
d8b6f4d9 889 m_arrayFuncDocs.Add(new FunctionDocEntry(m_funcName, m_textFunc));
cecfc5e7 890
d8b6f4d9
VZ
891 m_funcName.clear();
892 }
893}
894
895void HelpGenVisitor::CloseClass()
896{
df6e7577
JS
897 CloseFunction();
898
d8b6f4d9
VZ
899 if ( m_inClass ) {
900 size_t count = m_arrayFuncDocs.GetCount();
901 if ( count ) {
df6e7577 902 size_t n;
d8b6f4d9 903 FunctionDocEntry::classname = m_classname;
df6e7577 904
d8b6f4d9
VZ
905 m_arrayFuncDocs.Sort(FunctionDocEntry::Compare);
906
df6e7577
JS
907 // Now examine each first line and if it's been seen, cut it
908 // off (it's a duplicate \membersection)
909 wxHashTable membersections(wxKEY_STRING);
910
911 for ( n = 0; n < count; n++ )
912 {
913 wxString section(m_arrayFuncDocs[n].text);
914
915 // Strip leading whitespace
916 int pos = section.Find("\\membersection");
917 if (pos > -1)
918 {
919 section = section.Mid(pos);
920 }
921
922 wxString ms(section.BeforeFirst(wxT('\n')));
923 if (membersections.Get(ms))
924 {
925 m_arrayFuncDocs[n].text = section.AfterFirst(wxT('\n'));
926 }
927 else
928 {
929 membersections.Put(ms, & membersections);
930 }
931 }
932
933 for ( n = 0; n < count; n++ ) {
d8b6f4d9
VZ
934 m_file.WriteTeX(m_arrayFuncDocs[n].text);
935 }
936
937 m_arrayFuncDocs.Empty();
938 }
939
940 m_inClass = FALSE;
941 m_classname.clear();
cecfc5e7 942 }
3689307f 943 m_file.FlushAll();
cecfc5e7
VZ
944}
945
946void HelpGenVisitor::EndVisit()
947{
948 CloseFunction();
ed38ec7e 949
d8b6f4d9
VZ
950 CloseClass();
951
d12e3536
VZ
952 m_fileHeader.Empty();
953
d8b6f4d9 954 m_file.FlushAll();
3689307f
JS
955 if (m_file.IsOpened())
956 {
957 m_file.Flush();
958 m_file.Close();
959 }
d8b6f4d9 960
5f7cf62f
VZ
961 wxLogVerbose("%s: finished generating for the current file.",
962 GetCurrentTime("%H:%M:%S"));
cecfc5e7
VZ
963}
964
965void HelpGenVisitor::VisitFile( spFile& file )
966{
d12e3536 967 m_fileHeader = file.mFileName;
5f7cf62f 968 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
d12e3536 969 GetCurrentTime("%H:%M:%S"), m_fileHeader.c_str());
cecfc5e7
VZ
970}
971
972void HelpGenVisitor::VisitClass( spClass& cl )
973{
d8b6f4d9 974 CloseClass();
d12e3536 975
3689307f
JS
976 if (m_file.IsOpened())
977 {
978 m_file.Flush();
979 m_file.Close();
980 }
981
cecfc5e7
VZ
982 wxString name = cl.GetName();
983
d12e3536
VZ
984 if ( m_ignoreNames.IgnoreClass(name) ) {
985 wxLogVerbose("Skipping ignored class '%s'.", name.c_str());
986
987 return;
988 }
989
cecfc5e7
VZ
990 // the file name is built from the class name by removing the leading "wx"
991 // if any and converting it to the lower case
f6bcfd97 992 wxString filename;
59734eb5
VZ
993 if ( name(0, 2) == "wx" ) {
994 filename << name.c_str() + 2;
995 }
996 else {
997 filename << name;
cecfc5e7
VZ
998 }
999
1000 filename.MakeLower();
1001 filename += ".tex";
f6bcfd97 1002 filename.Prepend(m_directoryOut);
cecfc5e7 1003
d12e3536
VZ
1004 if ( !m_overwrite && wxFile::Exists(filename) ) {
1005 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
5f7cf62f
VZ
1006 filename.c_str());
1007
5f7cf62f
VZ
1008 return;
1009 }
1010
cecfc5e7
VZ
1011 m_inClass = m_file.Open(filename, wxFile::write);
1012 if ( !m_inClass ) {
1013 wxLogError("Can't generate documentation for the class '%s'.",
1014 name.c_str());
1015
1016 return;
1017 }
1018
1019 m_inMethodSection =
5f7cf62f 1020 m_inTypesSection = FALSE;
cecfc5e7
VZ
1021
1022 wxLogInfo("Created new file '%s' for class '%s'.",
1023 filename.c_str(), name.c_str());
1024
a7adaeda
VZ
1025 // write out the header
1026 wxString header;
1027 header.Printf("%%\n"
1028 "%% automatically generated by HelpGen %s from\n"
1029 "%% %s at %s\n"
1030 "%%\n"
1031 "\n"
1032 "\n"
1033 "\\section{\\class{%s}}\\label{%s}\n\n",
2f919f99 1034 GetVersionString().c_str(),
a7adaeda
VZ
1035 m_fileHeader.c_str(),
1036 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1037 name.c_str(),
1038 wxString(name).MakeLower().c_str());
1039
d8b6f4d9 1040 m_file.WriteVerbatim(header);
a7adaeda 1041
cecfc5e7
VZ
1042 // the entire text we're writing to file
1043 wxString totalText;
1044
ed38ec7e
VZ
1045 // if the header includes other headers they must be related to it... try to
1046 // automatically generate the "See also" clause
1047 if ( !m_headers.IsEmpty() ) {
1048 // correspondence between wxWindows headers and class names
1049 static const char *headers[] = {
1050 "object",
1051 "defs",
1052 "string",
1053 "dynarray",
59734eb5 1054 "file",
ed38ec7e
VZ
1055 "time",
1056 };
1057
1058 // NULL here means not to insert anything in "See also" for the
1059 // corresponding header
1060 static const char *classes[] = {
1061 NULL,
1062 NULL,
1063 NULL,
1064 NULL,
1065 "wxFile",
1066 "wxTime",
1067 };
1068
1069 wxASSERT_MSG( WXSIZEOF(headers) == WXSIZEOF(classes),
1070 "arrays must be in sync!" );
1071
1072 wxArrayInt interestingClasses;
1073
1074 size_t count = m_headers.Count(), index;
1075 for ( size_t n = 0; n < count; n++ ) {
1076 wxString baseHeaderName = m_headers[n].Before('.');
1077 if ( baseHeaderName(0, 3) != "wx/" )
1078 continue;
1079
1080 baseHeaderName.erase(0, 3);
1081 for ( index = 0; index < WXSIZEOF(headers); index++ ) {
1082 if ( Stricmp(baseHeaderName, headers[index]) == 0 )
1083 break;
1084 }
1085
1086 if ( (index < WXSIZEOF(headers)) && classes[index] ) {
1087 // interesting header
1088 interestingClasses.Add(index);
1089 }
1090 }
1091
1092 if ( !interestingClasses.IsEmpty() ) {
1093 // do generate "See also" clause
1094 totalText << "\\wxheading{See also:}\n\n";
1095
1096 count = interestingClasses.Count();
1097 for ( index = 0; index < count; index++ ) {
1098 if ( index > 0 )
1099 totalText << ", ";
1100
1101 totalText << MakeHelpref(classes[interestingClasses[index]]);
1102 }
1103
1104 totalText << "\n\n";
1105 }
1106 }
1107
cecfc5e7
VZ
1108 // the comment before the class generally explains what is it for so put it
1109 // in place of the class description
1110 if ( cl.HasComments() ) {
ed38ec7e 1111 wxString comment = GetAllComments(cl);
cecfc5e7
VZ
1112
1113 totalText << '\n' << comment << '\n';
1114 }
1115
1116 // derived from section
1117 wxString derived = "\\wxheading{Derived from}\n\n";
1118
1119 const StrListT& baseClasses = cl.mSuperClassNames;
1120 if ( baseClasses.size() == 0 ) {
1121 derived << "No base class";
1122 }
1123 else {
5f7cf62f 1124 bool first = TRUE;
cecfc5e7
VZ
1125 for ( StrListT::const_iterator i = baseClasses.begin();
1126 i != baseClasses.end();
1127 i++ ) {
1128 if ( !first ) {
1129 // separate from the previous one
1130 derived << "\\\\\n";
1131 }
1132 else {
5f7cf62f 1133 first = FALSE;
cecfc5e7
VZ
1134 }
1135
1136 wxString baseclass = *i;
dface61c 1137 derived << "\\helpref{" << baseclass << "}";
59734eb5 1138 derived << "{" << baseclass.MakeLower() << "}";
cecfc5e7
VZ
1139 }
1140 }
1141 totalText << derived << "\n\n";
1142
5bdad898
JS
1143 // include file section
1144 wxString includeFile = "\\wxheading{Include files}\n\n";
1145 includeFile << "<" << m_fileHeader << ">";
1146
1147 totalText << includeFile << "\n\n";
1148
cecfc5e7
VZ
1149 // write all this to file
1150 m_file.WriteTeX(totalText);
1151
1152 // if there were any enums/typedefs before, insert their documentation now
1153 InsertDataStructuresHeader();
1154 InsertTypedefDocs();
1155 InsertEnumDocs();
3689307f 1156
df6e7577 1157 //m_file.Flush();
cecfc5e7
VZ
1158}
1159
1160void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
1161{
1162 CloseFunction();
1163
1164 if ( m_inMethodSection ) {
1165 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1166 // should be smart enough to process even the enums which come after the
1167 // functions
1168 wxLogWarning("enum '%s' ignored, please put it before the class "
1169 "methods.", en.GetName().c_str());
1170 return;
1171 }
1172
1173 // simply copy the enum text in the docs
a7adaeda
VZ
1174 wxString enumeration = GetAllComments(en),
1175 enumerationVerb;
1176
1177 enumerationVerb << "\\begin{verbatim}\n"
1178 << en.mEnumContent
1179 << "\n\\end{verbatim}\n";
cecfc5e7
VZ
1180
1181 // remember for later use if we're not inside a class yet
1182 if ( !m_inClass ) {
a7adaeda
VZ
1183 m_storedEnums.Add(enumeration);
1184 m_storedEnumsVerb.Add(enumerationVerb);
cecfc5e7
VZ
1185 }
1186 else {
1187 // write the header for this section if not done yet
1188 InsertDataStructuresHeader();
1189
cecfc5e7 1190 m_file.WriteTeX(enumeration);
a7adaeda 1191 m_file.WriteVerbatim(enumerationVerb);
d8b6f4d9 1192 m_file.WriteVerbatim('\n');
cecfc5e7
VZ
1193 }
1194}
1195
1196void HelpGenVisitor::VisitTypeDef( spTypeDef& td )
1197{
1198 CloseFunction();
1199
ed38ec7e
VZ
1200 if ( m_inMethodSection ) {
1201 // FIXME that's a bug, but tell the user aboit it nevertheless...
1202 wxLogWarning("typedef '%s' ignored, please put it before the class "
1203 "methods.", td.GetName().c_str());
1204 return;
1205 }
1206
1207 wxString typedefdoc;
1208 typedefdoc << "{\\small \\begin{verbatim}\n"
1209 << "typedef " << td.mOriginalType << ' ' << td.GetName()
1210 << "\n\\end{verbatim}}\n"
1211 << GetAllComments(td);
1212
1213 // remember for later use if we're not inside a class yet
1214 if ( !m_inClass ) {
1215 if ( !m_textStoredTypedefs.IsEmpty() ) {
1216 m_textStoredTypedefs << '\n';
1217 }
1218
1219 m_textStoredTypedefs << typedefdoc;
1220 }
1221 else {
1222 // write the header for this section if not done yet
1223 InsertDataStructuresHeader();
1224
1225 typedefdoc << '\n';
1226 m_file.WriteTeX(typedefdoc);
1227 }
1228}
1229
1230void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine& pd )
1231{
1232 switch ( pd.GetStatementType() ) {
1233 case SP_PREP_DEF_INCLUDE_FILE:
1234 m_headers.Add(pd.CPP_GetIncludedFileNeme());
1235 break;
1236
1237 case SP_PREP_DEF_DEFINE_SYMBOL:
1238 // TODO decide if it's a constant and document it if it is
1239 break;
1240 }
cecfc5e7
VZ
1241}
1242
1243void HelpGenVisitor::VisitAttribute( spAttribute& attr )
1244{
1245 CloseFunction();
1246
1247 // only document the public member variables
1248 if ( !m_inClass || !attr.IsPublic() )
1249 return;
1250
ed38ec7e 1251 wxLogWarning("Ignoring member variable '%s'.", attr.GetName().c_str());
cecfc5e7
VZ
1252}
1253
1254void HelpGenVisitor::VisitOperation( spOperation& op )
1255{
1256 CloseFunction();
1257
d12e3536
VZ
1258 if ( !m_inClass ) {
1259 // we don't generate docs right now - either we ignore this class
1260 // entirely or we couldn't open the file
1261 return;
1262 }
1263
1264 if ( !op.IsInClass() ) {
1265 // TODO document global functions
cecfc5e7
VZ
1266 wxLogWarning("skipped global function '%s'.", op.GetName().c_str());
1267
1268 return;
1269 }
1270
1271 if ( op.mVisibility == SP_VIS_PRIVATE ) {
1272 // FIXME should we document protected functions?
1273 return;
1274 }
1275
d8b6f4d9
VZ
1276 m_classname = op.GetClass().GetName();
1277 wxString funcname = op.GetName();
1278
1279 if ( m_ignoreNames.IgnoreMethod(m_classname, funcname) ) {
d12e3536 1280 wxLogVerbose("Skipping ignored '%s::%s'.",
d8b6f4d9 1281 m_classname.c_str(), funcname.c_str());
d12e3536
VZ
1282
1283 return;
1284 }
1285
cecfc5e7
VZ
1286 InsertMethodsHeader();
1287
1288 // save state info
d8b6f4d9 1289 m_funcName = funcname;
5f7cf62f 1290 m_isFirstParam = TRUE;
cecfc5e7 1291
ed38ec7e 1292 m_textStoredFunctionComment = GetAllComments(op);
cecfc5e7
VZ
1293
1294 // start function documentation
1295 wxString totalText;
59734eb5 1296
cecfc5e7
VZ
1297 // check for the special case of dtor
1298 wxString dtor;
d8b6f4d9
VZ
1299 if ( (funcname[0] == '~') && (m_classname == funcname.c_str() + 1) ) {
1300 dtor.Printf("\\destruct{%s}", m_classname.c_str());
cecfc5e7
VZ
1301 funcname = dtor;
1302 }
1303
df6e7577
JS
1304 m_textFunc.Printf("\n"
1305 "\\membersection{%s::%s}\\label{%s}\n",
1306 m_classname.c_str(), funcname.c_str(),
1307 MakeLabel(m_classname, funcname).c_str());
eb420090
JS
1308
1309 wxString func;
1310 func.Printf("\n"
1311 "\\%sfunc{%s%s}{%s}{",
d8b6f4d9
VZ
1312 op.mIsConstant ? "const" : "",
1313 op.mIsVirtual ? "virtual " : "",
1314 op.mRetType.c_str(),
1315 funcname.c_str());
eb420090 1316 m_textFunc += func;
cecfc5e7
VZ
1317}
1318
1319void HelpGenVisitor::VisitParameter( spParameter& param )
1320{
d8b6f4d9 1321 if ( m_funcName.empty() )
cecfc5e7
VZ
1322 return;
1323
cecfc5e7 1324 if ( m_isFirstParam ) {
5f7cf62f 1325 m_isFirstParam = FALSE;
cecfc5e7
VZ
1326 }
1327 else {
d8b6f4d9 1328 m_textFunc << ", ";
cecfc5e7 1329 }
59734eb5 1330
d8b6f4d9 1331 m_textFunc << "\\param{" << param.mType << " }{" << param.GetName();
cecfc5e7
VZ
1332 wxString defvalue = param.mInitVal;
1333 if ( !defvalue.IsEmpty() ) {
d8b6f4d9 1334 m_textFunc << " = " << defvalue;
cecfc5e7 1335 }
59734eb5 1336
d8b6f4d9 1337 m_textFunc << '}';
cecfc5e7
VZ
1338}
1339
5f7cf62f
VZ
1340// ---------------------------------------------------------------------------
1341// DocManager
1342// ---------------------------------------------------------------------------
1343
d12e3536
VZ
1344DocManager::DocManager(bool checkParamNames)
1345{
1346 m_checkParamNames = checkParamNames;
1347}
1348
5f7cf62f
VZ
1349size_t DocManager::TryMatch(const char *str, const char *match)
1350{
1351 size_t lenMatch = 0;
1352 while ( str[lenMatch] == match[lenMatch] ) {
1353 lenMatch++;
1354
1355 if ( match[lenMatch] == '\0' )
1356 return lenMatch;
1357 }
1358
1359 return 0;
1360}
1361
1362bool DocManager::SkipUntil(const char **pp, char c)
1363{
1364 const char *p = *pp;
1365 while ( *p != c ) {
1366 if ( *p == '\0' )
1367 break;
1368
1369 if ( *p == '\n' )
1370 m_line++;
1371
1372 p++;
1373 }
1374
1375 *pp = p;
1376
1377 return *p == c;
1378}
1379
1380bool DocManager::SkipSpaceUntil(const char **pp, char c)
1381{
1382 const char *p = *pp;
1383 while ( *p != c ) {
1384 if ( !isspace(*p) || *p == '\0' )
1385 break;
1386
1387 if ( *p == '\n' )
1388 m_line++;
1389
1390 p++;
1391 }
1392
1393 *pp = p;
1394
1395 return *p == c;
1396}
1397
1398wxString DocManager::ExtractStringBetweenBraces(const char **pp)
1399{
1400 wxString result;
1401
1402 if ( !SkipSpaceUntil(pp, '{') ) {
1403 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1404 m_filename.c_str(), m_line);
1405
1406 }
1407 else {
1408 const char *startParam = ++*pp; // skip '{'
1409
1410 if ( !SkipUntil(pp, '}') ) {
1411 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1412 m_filename.c_str(), m_line);
1413 }
1414 else {
1415 result = wxString(startParam, (*pp)++ - startParam);
1416 }
1417 }
1418
1419 return result;
1420}
1421
1422bool DocManager::ParseTeXFile(const wxString& filename)
1423{
1424 m_filename = filename;
1425
1426 wxFile file(m_filename, wxFile::read);
1427 if ( !file.IsOpened() )
1428 return FALSE;
1429
1430 off_t len = file.Length();
1431 if ( len == wxInvalidOffset )
1432 return FALSE;
1433
1434 char *buf = new char[len + 1];
1435 buf[len] = '\0';
1436
1437 if ( file.Read(buf, len) == wxInvalidOffset ) {
1438 delete [] buf;
1439
1440 return FALSE;
1441 }
1442
1443 // reinit everything
1444 m_line = 1;
1445
1446 wxLogVerbose("%s: starting to parse doc file '%s'.",
1447 GetCurrentTime("%H:%M:%S"), m_filename.c_str());
1448
1449 // the name of the class from the last "\membersection" command: we assume
1450 // that the following "\func" or "\constfunc" always documents a method of
1451 // this class (and it should always be like that in wxWindows documentation)
1452 wxString classname;
1453
1454 for ( const char *current = buf; current - buf < len; current++ ) {
1455 // FIXME parsing is awfully inefficient
1456
1457 if ( *current == '%' ) {
1458 // comment, skip until the end of line
1459 current++;
1460 SkipUntil(&current, '\n');
1461
1462 continue;
1463 }
1464
1465 // all the command we're interested in start with '\\'
1466 while ( *current != '\\' && *current != '\0' ) {
1467 if ( *current++ == '\n' )
1468 m_line++;
1469 }
1470
1471 if ( *current == '\0' ) {
1472 // no more TeX commands left
1473 break;
1474 }
1475
1476 current++; // skip '\\'
1477
1478 enum
1479 {
1480 Nothing,
1481 Func,
1482 ConstFunc,
1483 MemberSect
1484 } foundCommand = Nothing;
1485
1486 size_t lenMatch = TryMatch(current, "func");
1487 if ( lenMatch ) {
1488 foundCommand = Func;
1489 }
1490 else {
1491 lenMatch = TryMatch(current, "constfunc");
1492 if ( lenMatch )
1493 foundCommand = ConstFunc;
1494 else {
1495 lenMatch = TryMatch(current, "membersection");
1496
1497 if ( lenMatch )
1498 foundCommand = MemberSect;
1499 }
1500 }
1501
1502 if ( foundCommand == Nothing )
1503 continue;
1504
1505 current += lenMatch;
1506
1507 if ( !SkipSpaceUntil(&current, '{') ) {
1508 wxLogWarning("file %s(%d): '{' expected after \\func, "
1509 "\\constfunc or \\membersection.",
1510 m_filename.c_str(), m_line);
1511
1512 continue;
1513 }
1514
1515 current++;
1516
1517 if ( foundCommand == MemberSect ) {
1518 // what follows has the form <classname>::<funcname>
1519 const char *startClass = current;
1520 if ( !SkipUntil(&current, ':') || *(current + 1) != ':' ) {
1521 wxLogWarning("file %s(%d): '::' expected after "
1522 "\\membersection.", m_filename.c_str(), m_line);
1523 }
1524 else {
1525 classname = wxString(startClass, current - startClass);
1526 TeXUnfilter(&classname);
1527 }
1528
1529 continue;
1530 }
1531
1532 // extract the return type
1533 const char *startRetType = current;
1534
1535 if ( !SkipUntil(&current, '}') ) {
1536 wxLogWarning("file %s(%d): '}' expected after return type",
1537 m_filename.c_str(), m_line);
1538
1539 continue;
1540 }
1541
1542 wxString returnType = wxString(startRetType, current - startRetType);
1543 TeXUnfilter(&returnType);
1544
1545 current++;
1546 if ( !SkipSpaceUntil(&current, '{') ) {
1547 wxLogWarning("file %s(%d): '{' expected after return type",
1548 m_filename.c_str(), m_line);
1549
1550 continue;
1551 }
1552
1553 current++;
1554 const char *funcEnd = current;
1555 if ( !SkipUntil(&funcEnd, '}') ) {
1556 wxLogWarning("file %s(%d): '}' expected after function name",
1557 m_filename.c_str(), m_line);
1558
1559 continue;
1560 }
1561
1562 wxString funcName = wxString(current, funcEnd - current);
1563 current = funcEnd + 1;
1564
1565 // trim spaces from both sides
1566 funcName.Trim(FALSE);
1567 funcName.Trim(TRUE);
1568
1569 // special cases: '$...$' may be used for LaTeX inline math, remove the
1570 // '$'s
1571 if ( funcName.Find('$') != wxNOT_FOUND ) {
1572 wxString name;
1573 for ( const char *p = funcName.c_str(); *p != '\0'; p++ ) {
1574 if ( *p != '$' && !isspace(*p) )
1575 name += *p;
1576 }
1577
1578 funcName = name;
1579 }
1580
1581 // \destruct{foo} is really ~foo
1582 if ( funcName[0u] == '\\' ) {
1583 size_t len = strlen("\\destruct{");
1584 if ( funcName(0, len) != "\\destruct{" ) {
1585 wxLogWarning("file %s(%d): \\destruct expected",
1586 m_filename.c_str(), m_line);
1587
1588 continue;
1589 }
1590
1591 funcName.erase(0, len);
1592 funcName.Prepend('~');
1593
1594 if ( !SkipSpaceUntil(&current, '}') ) {
1595 wxLogWarning("file %s(%d): '}' expected after destructor",
1596 m_filename.c_str(), m_line);
1597
1598 continue;
1599 }
1600
1601 funcEnd++; // there is an extra '}' to count
1602 }
1603
1604 TeXUnfilter(&funcName);
1605
1606 // extract params
1607 current = funcEnd + 1; // skip '}'
1608 if ( !SkipSpaceUntil(&current, '{') ||
1609 (current++, !SkipSpaceUntil(&current, '\\')) ) {
1610 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1611 m_filename.c_str(), m_line);
1612
1613 continue;
1614 }
1615
1616 wxArrayString paramNames, paramTypes, paramValues;
1617
1618 bool isVararg = FALSE;
1619
1620 current++; // skip '\\'
1621 lenMatch = TryMatch(current, "void");
1622 if ( !lenMatch ) {
1623 lenMatch = TryMatch(current, "param");
d12e3536 1624 while ( lenMatch && (current - buf < len) ) {
5f7cf62f
VZ
1625 current += lenMatch;
1626
1627 // now come {paramtype}{paramname}
1628 wxString paramType = ExtractStringBetweenBraces(&current);
1629 if ( !!paramType ) {
1630 wxString paramText = ExtractStringBetweenBraces(&current);
1631 if ( !!paramText ) {
1632 // the param declaration may contain default value
1633 wxString paramName = paramText.BeforeFirst('='),
1634 paramValue = paramText.AfterFirst('=');
1635
1636 // sanitize all strings
1637 TeXUnfilter(&paramValue);
1638 TeXUnfilter(&paramName);
1639 TeXUnfilter(&paramType);
1640
1641 paramValues.Add(paramValue);
1642 paramNames.Add(paramName);
1643 paramTypes.Add(paramType);
1644 }
1645 }
1646 else {
1647 // vararg function?
1648 wxString paramText = ExtractStringBetweenBraces(&current);
1649 if ( paramText == "..." ) {
1650 isVararg = TRUE;
1651 }
1652 else {
1653 wxLogWarning("Parameters of '%s::%s' are in "
1654 "incorrect form.",
1655 classname.c_str(), funcName.c_str());
1656 }
1657 }
1658
1659 // what's next?
1660 current = SkipSpaces(current);
1661 if ( *current == ',' || *current == '}' ) {
1662 current = SkipSpaces(++current);
1663
1664 lenMatch = TryMatch(current, "\\param");
1665 }
1666 else {
1667 wxLogWarning("file %s(%d): ',' or '}' expected after "
1668 "'\\param'", m_filename.c_str(), m_line);
1669
1670 continue;
1671 }
1672 }
1673
1674 // if we got here there was no '\\void', so must have some params
1675 if ( paramNames.IsEmpty() ) {
1676 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1677 m_filename.c_str(), m_line);
1678
1679 continue;
1680 }
1681 }
1682
1683 // verbose diagnostic output
1684 wxString paramsAll;
1685 size_t param, paramCount = paramNames.GetCount();
1686 for ( param = 0; param < paramCount; param++ ) {
1687 if ( param != 0 ) {
1688 paramsAll << ", ";
1689 }
1690
1691 paramsAll << paramTypes[param] << ' ' << paramNames[param];
1692 }
1693
1694 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1695 m_filename.c_str(), m_line,
1696 returnType.c_str(),
1697 classname.c_str(),
1698 funcName.c_str(),
1699 paramsAll.c_str(),
1700 foundCommand == ConstFunc ? " const" : "");
1701
1702 // store the info about the just found function
1703 ArrayMethodInfo *methods;
1704 int index = m_classes.Index(classname);
1705 if ( index == wxNOT_FOUND ) {
1706 m_classes.Add(classname);
1707
1708 methods = new ArrayMethodInfo;
1709 m_methods.Add(methods);
1710 }
1711 else {
1712 methods = m_methods[(size_t)index];
1713 }
1714
1715 ArrayParamInfo params;
1716 for ( param = 0; param < paramCount; param++ ) {
1717 params.Add(new ParamInfo(paramTypes[param],
1718 paramNames[param],
1719 paramValues[param]));
1720 }
1721
1722 MethodInfo *method = new MethodInfo(returnType, funcName, params);
1723 if ( foundCommand == ConstFunc )
1724 method->SetFlag(MethodInfo::Const);
1725 if ( isVararg )
1726 method->SetFlag(MethodInfo::Vararg);
1727
1728 methods->Add(method);
1729 }
1730
1731 delete [] buf;
1732
1733 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1734 GetCurrentTime("%H:%M:%S"), m_filename.c_str());
1735
1736 return TRUE;
1737}
1738
1739bool DocManager::DumpDifferences(spContext *ctxTop) const
1740{
1741 typedef MMemberListT::const_iterator MemberIndex;
1742
1743 bool foundDiff = FALSE;
1744
1745 // flag telling us whether the given class was found at all in the header
1746 size_t nClass, countClassesInDocs = m_classes.GetCount();
1747 bool *classExists = new bool[countClassesInDocs];
1748 for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
1749 classExists[nClass] = FALSE;
1750 }
1751
1752 // ctxTop is normally an spFile
1753 wxASSERT( ctxTop->GetContextType() == SP_CTX_FILE );
1754
1755 const MMemberListT& classes = ctxTop->GetMembers();
1756 for ( MemberIndex i = classes.begin(); i != classes.end(); i++ ) {
1757 spContext *ctx = *i;
1758 if ( ctx->GetContextType() != SP_CTX_CLASS ) {
1759 // TODO process also global functions, macros, ...
1760 continue;
1761 }
1762
1763 spClass *ctxClass = (spClass *)ctx;
1764 const wxString& nameClass = ctxClass->mName;
1765 int index = m_classes.Index(nameClass);
1766 if ( index == wxNOT_FOUND ) {
d12e3536 1767 if ( !m_ignoreNames.IgnoreClass(nameClass) ) {
5f7cf62f
VZ
1768 foundDiff = TRUE;
1769
1770 wxLogError("Class '%s' is not documented at all.",
1771 nameClass.c_str());
1772 }
1773
1774 // it makes no sense to check for its functions
1775 continue;
1776 }
1777 else {
1778 classExists[index] = TRUE;
1779 }
1780
1781 // array of method descriptions for this class
1782 const ArrayMethodInfo& methods = *(m_methods[index]);
1783 size_t nMethod, countMethods = methods.GetCount();
1784
1785 // flags telling if we already processed given function
1786 bool *methodExists = new bool[countMethods];
1787 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1788 methodExists[nMethod] = FALSE;
1789 }
1790
1791 wxArrayString aOverloadedMethods;
1792
1793 const MMemberListT& functions = ctxClass->GetMembers();
1794 for ( MemberIndex j = functions.begin(); j != functions.end(); j++ ) {
1795 ctx = *j;
1796 if ( ctx->GetContextType() != SP_CTX_OPERATION )
1797 continue;
1798
1799 spOperation *ctxMethod = (spOperation *)ctx;
1800 const wxString& nameMethod = ctxMethod->mName;
1801
1802 // find all functions with the same name
1803 wxArrayInt aMethodsWithSameName;
1804 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1805 if ( methods[nMethod]->GetName() == nameMethod )
1806 aMethodsWithSameName.Add(nMethod);
1807 }
1808
1809 if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
d12e3536 1810 if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
5f7cf62f
VZ
1811 foundDiff = TRUE;
1812
1813 wxLogError("'%s::%s' is not documented.",
1814 nameClass.c_str(),
1815 nameMethod.c_str());
1816 }
1817
1818 // don't check params
1819 continue;
1820 }
1821 else if ( aMethodsWithSameName.GetCount() == 1 ) {
1822 index = (size_t)aMethodsWithSameName[0u];
1823 methodExists[index] = TRUE;
1824
d12e3536 1825 if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
5f7cf62f
VZ
1826 continue;
1827
1828 if ( !ctxMethod->IsPublic() ) {
1829 wxLogWarning("'%s::%s' is documented but not public.",
1830 nameClass.c_str(),
1831 nameMethod.c_str());
1832 }
1833
1834 // check that the flags match
1835 const MethodInfo& method = *(methods[index]);
1836
1837 bool isVirtual = ctxMethod->mIsVirtual;
1838 if ( isVirtual != method.HasFlag(MethodInfo::Virtual) ) {
1839 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1840 "virtual.",
1841 nameClass.c_str(),
1842 nameMethod.c_str(),
1843 isVirtual ? "not " : "");
1844 }
1845
1846 bool isConst = ctxMethod->mIsConstant;
1847 if ( isConst != method.HasFlag(MethodInfo::Const) ) {
1848 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1849 "constant.",
1850 nameClass.c_str(),
1851 nameMethod.c_str(),
1852 isConst ? "not " : "");
1853 }
1854
1855 // check that the params match
1856 const MMemberListT& params = ctxMethod->GetMembers();
1857
1858 if ( params.size() != method.GetParamCount() ) {
1859 wxLogError("Incorrect number of parameters for '%s::%s' "
1860 "in the docs: should be %d instead of %d.",
1861 nameClass.c_str(),
1862 nameMethod.c_str(),
1863 params.size(), method.GetParamCount());
1864 }
1865 else {
1866 size_t nParam = 0;
1867 for ( MemberIndex k = params.begin();
1868 k != params.end();
1869 k++, nParam++ ) {
1870 ctx = *k;
1871
1872 // what else can a function have?
1873 wxASSERT( ctx->GetContextType() == SP_CTX_PARAMETER );
1874
1875 spParameter *ctxParam = (spParameter *)ctx;
1876 const ParamInfo& param = method.GetParam(nParam);
d12e3536
VZ
1877 if ( m_checkParamNames &&
1878 (param.GetName() != ctxParam->mName) ) {
5f7cf62f
VZ
1879 foundDiff = TRUE;
1880
1881 wxLogError("Parameter #%d of '%s::%s' should be "
1882 "'%s' and not '%s'.",
1883 nParam + 1,
1884 nameClass.c_str(),
1885 nameMethod.c_str(),
1886 ctxParam->mName.c_str(),
1887 param.GetName().c_str());
1888
1889 continue;
1890 }
1891
1892 if ( param.GetType() != ctxParam->mType ) {
1893 foundDiff = TRUE;
1894
1895 wxLogError("Type of parameter '%s' of '%s::%s' "
1896 "should be '%s' and not '%s'.",
1897 ctxParam->mName.c_str(),
1898 nameClass.c_str(),
1899 nameMethod.c_str(),
1900 ctxParam->mType.c_str(),
1901 param.GetType().GetName().c_str());
1902
1903 continue;
1904 }
1905
1906 if ( param.GetDefValue() != ctxParam->mInitVal ) {
1907 wxLogWarning("Default value of parameter '%s' of "
1908 "'%s::%s' should be '%s' and not "
1909 "'%s'.",
1910 ctxParam->mName.c_str(),
1911 nameClass.c_str(),
1912 nameMethod.c_str(),
1913 ctxParam->mInitVal.c_str(),
1914 param.GetDefValue().c_str());
1915 }
1916 }
1917 }
1918 }
1919 else {
d12e3536 1920 // TODO OVER add real support for overloaded methods
5f7cf62f 1921
d12e3536 1922 if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
5f7cf62f
VZ
1923 continue;
1924
1925 if ( aOverloadedMethods.Index(nameMethod) == wxNOT_FOUND ) {
1926 // mark all methods with this name as existing
1927 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1928 if ( methods[nMethod]->GetName() == nameMethod )
1929 methodExists[nMethod] = TRUE;
1930 }
1931
1932 aOverloadedMethods.Add(nameMethod);
1933
1934 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1935 "stupid to find the right match - skipping "
1936 "the param and flags checks.",
1937 nameClass.c_str(),
1938 nameMethod.c_str());
1939 }
1940 //else: warning already given
1941 }
1942 }
1943
1944 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1945 if ( !methodExists[nMethod] ) {
1946 const wxString& nameMethod = methods[nMethod]->GetName();
d12e3536 1947 if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
5f7cf62f
VZ
1948 foundDiff = TRUE;
1949
1950 wxLogError("'%s::%s' is documented but doesn't exist.",
1951 nameClass.c_str(),
1952 nameMethod.c_str());
1953 }
1954 }
1955 }
1956
1957 delete [] methodExists;
1958 }
1959
1960 // check that all classes we found in the docs really exist
1961 for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
1962 if ( !classExists[nClass] ) {
1963 foundDiff = TRUE;
1964
1965 wxLogError("Class '%s' is documented but doesn't exist.",
1966 m_classes[nClass].c_str());
1967 }
1968 }
1969
1970 delete [] classExists;
1971
1972 return !foundDiff;
1973}
1974
1975DocManager::~DocManager()
1976{
1977 WX_CLEAR_ARRAY(m_methods);
5f7cf62f
VZ
1978}
1979
d12e3536
VZ
1980// ---------------------------------------------------------------------------
1981// IgnoreNamesHandler implementation
1982// ---------------------------------------------------------------------------
1983
1984int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first,
1985 IgnoreListEntry *second)
5f7cf62f
VZ
1986{
1987 // first compare the classes
1988 int rc = first->m_classname.Cmp(second->m_classname);
1989 if ( rc == 0 )
1990 rc = first->m_funcname.Cmp(second->m_funcname);
1991
1992 return rc;
1993}
1994
d12e3536 1995bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
5f7cf62f
VZ
1996{
1997 wxFile file(filename, wxFile::read);
1998 if ( !file.IsOpened() )
1999 return FALSE;
2000
2001 off_t len = file.Length();
2002 if ( len == wxInvalidOffset )
2003 return FALSE;
2004
2005 char *buf = new char[len + 1];
2006 buf[len] = '\0';
2007
2008 if ( file.Read(buf, len) == wxInvalidOffset ) {
2009 delete [] buf;
2010
2011 return FALSE;
2012 }
2013
2014 wxString line;
2015 for ( const char *current = buf; ; current++ ) {
2016#ifdef __WXMSW__
2017 // skip DOS line separator
2018 if ( *current == '\r' )
2019 current++;
2020#endif // wxMSW
2021
2022 if ( *current == '\n' || *current == '\0' ) {
2023 if ( line[0u] != '#' ) {
2024 if ( line.Find(':') != wxNOT_FOUND ) {
2025 wxString classname = line.BeforeFirst(':'),
2026 funcname = line.AfterLast(':');
2027 m_ignore.Add(new IgnoreListEntry(classname, funcname));
2028 }
2029 else {
2030 // entire class
2031 m_ignore.Add(new IgnoreListEntry(line, ""));
2032 }
2033 }
2034 //else: comment
2035
2036 if ( *current == '\0' )
2037 break;
2038
2039 line.Empty();
2040 }
2041 else {
2042 line += *current;
2043 }
2044 }
2045
2046 delete [] buf;
2047
2048 return TRUE;
2049}
2050
cecfc5e7
VZ
2051// -----------------------------------------------------------------------------
2052// global function implementation
2053// -----------------------------------------------------------------------------
2054
2055static wxString MakeLabel(const char *classname, const char *funcname)
2056{
2057 wxString label(classname);
ed38ec7e 2058 if ( funcname && funcname[0] == '\\' ) {
cecfc5e7
VZ
2059 // we may have some special TeX macro - so far only \destruct exists,
2060 // but may be later others will be added
2061 static const char *macros[] = { "destruct" };
2062 static const char *replacement[] = { "dtor" };
59734eb5 2063
cecfc5e7
VZ
2064 size_t n;
2065 for ( n = 0; n < WXSIZEOF(macros); n++ ) {
2066 if ( strncmp(funcname + 1, macros[n], strlen(macros[n])) == 0 ) {
2067 // found
2068 break;
2069 }
2070 }
2071
2072 if ( n == WXSIZEOF(macros) ) {
2073 wxLogWarning("unknown function name '%s' - leaving as is.",
2074 funcname);
2075 }
2076 else {
2077 funcname = replacement[n];
2078 }
2079 }
2080
d8b6f4d9
VZ
2081 if ( funcname ) {
2082 // special treatment for operatorXXX() stuff because the C operators
2083 // are not valid in LaTeX labels
2084 wxString oper;
2085 if ( wxString(funcname).StartsWith("operator", &oper) ) {
2086 label << "operator";
2087
2088 static const struct
2089 {
2090 const char *oper;
2091 const char *name;
2092 } operatorNames[] =
2093 {
2094 { "=", "assign" },
2095 { "==", "equal" },
2096 };
2097
2098 size_t n;
2099 for ( n = 0; n < WXSIZEOF(operatorNames); n++ ) {
2100 if ( oper == operatorNames[n].oper ) {
2101 label << operatorNames[n].name;
2102
2103 break;
2104 }
2105 }
2106
2107 if ( n == WXSIZEOF(operatorNames) ) {
2108 wxLogWarning("unknown operator '%s' - making dummy label.",
2109 oper.c_str());
2110
2111 label << "unknown";
2112 }
2113 }
2114 else // simply use the func name
2115 {
2116 label << funcname;
2117 }
2118 }
cecfc5e7
VZ
2119
2120 label.MakeLower();
2121
2122 return label;
2123}
2124
ed38ec7e
VZ
2125static wxString MakeHelpref(const char *argument)
2126{
2127 wxString helpref;
2128 helpref << "\\helpref{" << argument << "}{" << MakeLabel(argument) << '}';
2129
2130 return helpref;
2131}
2132
a7adaeda
VZ
2133static void TeXFilter(wxString* str)
2134{
2135 // TeX special which can be quoted (don't include backslash nor braces as
2136 // we generate them
2137 static wxRegEx reNonSpecialSpecials("[#$%&_]"),
2138 reAccents("[~^]");
2139
2140 // just quote
2141 reNonSpecialSpecials.ReplaceAll(str, "\\\\\\0");
2142
2143 // can't quote these ones as they produce accents when preceded by
2144 // backslash, so put them inside verb
2145 reAccents.ReplaceAll(str, "\\\\verb|\\0|");
2146}
2147
5f7cf62f
VZ
2148static void TeXUnfilter(wxString* str)
2149{
2150 // FIXME may be done much more quickly
2151 str->Trim(TRUE);
2152 str->Trim(FALSE);
2153
a7adaeda
VZ
2154 // undo TeXFilter
2155 static wxRegEx reNonSpecialSpecials("\\\\([#$%&_{}])"),
2156 reAccents("\\\\verb|([~^])|");
5f7cf62f 2157
a7adaeda
VZ
2158 reNonSpecialSpecials.ReplaceAll(str, "\\1");
2159 reAccents.ReplaceAll(str, "\\1");
cecfc5e7
VZ
2160}
2161
ed38ec7e
VZ
2162static wxString GetAllComments(const spContext& ctx)
2163{
59734eb5
VZ
2164 wxString comments;
2165 const MCommentListT& commentsList = ctx.GetCommentList();
2166 for ( MCommentListT::const_iterator i = commentsList.begin();
2167 i != commentsList.end();
2168 i++ ) {
2169 wxString comment = (*i)->GetText();
2170
2171 // don't take comments like "// ----------" &c
2172 comment.Trim(FALSE);
2173 if ( !!comment &&
2174 comment == wxString(comment[0u], comment.length() - 1) + '\n' )
2175 comments << "\n";
2176 else
2177 comments << comment;
ed38ec7e
VZ
2178 }
2179
59734eb5 2180 return comments;
ed38ec7e
VZ
2181}
2182
2183static const char *GetCurrentTime(const char *timeFormat)
2184{
2185 static char s_timeBuffer[128];
2186 time_t timeNow;
2187 struct tm *ptmNow;
2188
2189 time(&timeNow);
2190 ptmNow = localtime(&timeNow);
2191
2192 strftime(s_timeBuffer, WXSIZEOF(s_timeBuffer), timeFormat, ptmNow);
2193
2194 return s_timeBuffer;
2195}
2196
2f919f99
VZ
2197static const wxString GetVersionString()
2198{
2199 wxString version = "$Revision$";
2200 wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1");
2201 return version;
2202}
2203
5f7cf62f
VZ
2204/*
2205 $Log$
5bdad898
JS
2206 Revision 1.22 2002/01/21 21:18:50 JS
2207 Now adds 'include file' heading
2208
df6e7577
JS
2209 Revision 1.21 2002/01/04 11:06:09 JS
2210 Fixed missing membersections bug and also bug with functions not being written
2211 in the right class
2212
eb420090
JS
2213 Revision 1.20 2002/01/03 14:23:33 JS
2214 Added code to make it not duplicate membersections for overloaded functions
2215
3689307f
JS
2216 Revision 1.19 2002/01/03 13:34:12 JS
2217 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2218 and appeared in one file.
2219
31dc7e49
JS
2220 Revision 1.18 2002/01/03 12:02:47 JS
2221 Added main() and corrected VC++ project settings
2222
d8b6f4d9
VZ
2223 Revision 1.17 2001/11/30 21:43:35 VZ
2224 now the methods are sorted in the correct order in the generated docs
2225
a3b72ffb
VZ
2226 Revision 1.16 2001/11/28 19:27:33 VZ
2227 HelpGen doesn't work in GUI mode
2228
5aa5c1e4
GD
2229 Revision 1.15 2001/11/22 21:59:58 GD
2230 use "..." instead of <...> for wx headers
2231
2f919f99
VZ
2232 Revision 1.14 2001/07/19 13:51:29 VZ
2233 fixes to version string
2234
a7adaeda
VZ
2235 Revision 1.13 2001/07/19 13:44:57 VZ
2236 1. compilation fixes
2237 2. don't quote special characters inside verbatim environment
2238
4e28924c 2239 Revision 1.12 2000/10/09 13:53:33 juliansmart
a7adaeda 2240
4e28924c
JS
2241 Doc corrections; added HelpGen project files
2242
f6bcfd97
BP
2243 Revision 1.11 2000/07/15 19:50:42 cvsuser
2244 merged 2.2 branch
2245
2246 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2247 don't trasnform output dir name to lower case
2248
de528224
VS
2249 Revision 1.10 2000/03/11 10:05:23 VS
2250 now compiles with wxBase
2251
b136d1fe
VS
2252 Revision 1.9 2000/01/16 13:25:21 VS
2253 compilation fixes (gcc)
2254
28468136 2255 Revision 1.8 1999/09/13 14:29:39 JS
b136d1fe 2256
28468136
JS
2257 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2258 into src for simplicity; added VC++ 5 project file
2259
d12e3536
VZ
2260 Revision 1.7 1999/02/21 22:32:32 VZ
2261 1. more C++ parser fixes - now it almost parses wx/string.h
2262 a) #if/#ifdef/#else (very) limited support
2263 b) param type fix - now indirection chars are correctly handled
2264 c) class/struct/union distinction
2265 d) public/private fixes
2266 e) Dump() function added - very useful for debugging
2267
2268 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2269 by default, and this option switches it on)
2270
5f7cf62f
VZ
2271 Revision 1.6 1999/02/20 23:00:26 VZ
2272 1. new 'diff' mode which seems to work
2273 2. output files are not overwritten in 'dmup' mode
2274 3. fixes for better handling of const functions and operators
d12e3536
VZ
2275 ----------------------------
2276 revision 1.5
2277 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2278 1. Parser improvements
2279 a) const and virtual methods are parsed correctly (not static yet)
2280 b) "const" which is part of the return type is not swallowed
2281
2282 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2283 "//---------" kind comments discarded now.
2284 ----------------------------
2285 revision 1.4
2286 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2287
2288 some tweaks to HelpGen
2289 ----------------------------
2290 revision 1.3
2291 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2292
2293 HelpGen starting to compile with VC++
2294 ----------------------------
2295 revision 1.2
2296 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2297
2298 supports typedefs, generates "See also:" and adds "virtual " for virtual
2299 functions
2300 ----------------------------
2301 revision 1.1
2302 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2303
2304 HelpGen is a prototype of the tool for automatic generation of the .tex files
2305 for wxWindows documentation from C++ headers
5f7cf62f
VZ
2306*/
2307
cecfc5e7 2308/* vi: set tw=80 et ts=4 sw=4: */