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