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