]> git.saurik.com Git - wxWidgets.git/blame - utils/HelpGen/src/HelpGen.cpp
Fixes for unused values and code.
[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
be5a51fb 51// wxWidgets
cecfc5e7
VZ
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() )
8ad74db3 194 return true;
d8b6f4d9
VZ
195
196 if ( !Write(m_text) ) {
197 wxLogError("Failed to output generated documentation.");
198
8ad74db3 199 return false;
d8b6f4d9
VZ
200 }
201
202 m_text.clear();
203
8ad74db3 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
8ad74db3 226 // return true if we ignore this function
d12e3536
VZ
227 bool IgnoreMethod(const wxString& classname,
228 const wxString& funcname) const
229 {
230 if ( IgnoreClass(classname) )
8ad74db3 231 return true;
d12e3536
VZ
232
233 IgnoreListEntry ignore(classname, funcname);
234
235 return m_ignore.Index(&ignore) != wxNOT_FOUND;
236 }
237
8ad74db3 238 // return true if we ignore this class entirely
d12e3536
VZ
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
8ad74db3 324 bool m_inClass, // true after file successfully opened
cecfc5e7
VZ
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
8ad74db3 370 // returns false on failure
5f7cf62f
VZ
371 bool ParseTeXFile(const wxString& filename);
372
8ad74db3 373 // returns false if there were any differences
5f7cf62f
VZ
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
8ad74db3 400 // which case false is returned and pp points to '\0', otherwise true is
5f7cf62f
VZ
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
8ad74db3 405 // character different from 'c' the function stops and returns false
5f7cf62f
VZ
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
8ad74db3 466 WX_DEFINE_ARRAY_PTR(ParamInfo *, ArrayParamInfo);
5f7cf62f
VZ
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
8ad74db3
WS
508 WX_DEFINE_ARRAY_PTR(MethodInfo *, ArrayMethodInfo);
509 WX_DEFINE_ARRAY_PTR(ArrayMethodInfo *, ArrayMethodInfos);
5f7cf62f 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 {
be5a51fb 578 fprintf(stderr, "Failed to initialize the wxWidgets library, aborting.");
d5eddfef
VZ
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
8ad74db3
WS
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
8ad74db3 612 wxLog::GetActiveTarget()->SetVerbose(false);
5f7cf62f
VZ
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
8ad74db3 645 paramNames = true;
d12e3536
VZ
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
8ad74db3 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
8ad74db3 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 =
8ad74db3 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 ) {
8ad74db3 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 ) {
8ad74db3 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{
8ad74db3 879 CloseFunction();
df6e7577 880
8ad74db3
WS
881 if ( m_inClass )
882 {
d8b6f4d9 883 size_t count = m_arrayFuncDocs.GetCount();
8ad74db3
WS
884 if ( count )
885 {
886 size_t n;
d8b6f4d9 887 FunctionDocEntry::classname = m_classname;
df6e7577 888
d8b6f4d9
VZ
889 m_arrayFuncDocs.Sort(FunctionDocEntry::Compare);
890
8ad74db3
WS
891 // Now examine each first line and if it's been seen, cut it
892 // off (it's a duplicate \membersection)
893 wxHashTable membersections(wxKEY_STRING);
df6e7577
JS
894
895 for ( n = 0; n < count; n++ )
8ad74db3 896 {
df6e7577
JS
897 wxString section(m_arrayFuncDocs[n].text);
898
8ad74db3
WS
899 // Strip leading whitespace
900 int pos = section.Find("\\membersection");
901 if (pos > -1)
902 {
903 section = section.Mid(pos);
904 }
905
906 wxString ms(section.BeforeFirst(wxT('\n')));
907 if (membersections.Get(ms))
908 {
909 m_arrayFuncDocs[n].text = section.AfterFirst(wxT('\n'));
910 }
911 else
912 {
913 membersections.Put(ms, & membersections);
914 }
df6e7577
JS
915 }
916
917 for ( n = 0; n < count; n++ ) {
d8b6f4d9
VZ
918 m_file.WriteTeX(m_arrayFuncDocs[n].text);
919 }
920
921 m_arrayFuncDocs.Empty();
922 }
923
8ad74db3 924 m_inClass = false;
d8b6f4d9 925 m_classname.clear();
cecfc5e7 926 }
8ad74db3 927 m_file.FlushAll();
cecfc5e7
VZ
928}
929
930void HelpGenVisitor::EndVisit()
931{
932 CloseFunction();
ed38ec7e 933
d8b6f4d9
VZ
934 CloseClass();
935
d12e3536
VZ
936 m_fileHeader.Empty();
937
d8b6f4d9 938 m_file.FlushAll();
8ad74db3
WS
939 if (m_file.IsOpened())
940 {
941 m_file.Flush();
942 m_file.Close();
943 }
d8b6f4d9 944
5f7cf62f
VZ
945 wxLogVerbose("%s: finished generating for the current file.",
946 GetCurrentTime("%H:%M:%S"));
cecfc5e7
VZ
947}
948
949void HelpGenVisitor::VisitFile( spFile& file )
950{
d12e3536 951 m_fileHeader = file.mFileName;
5f7cf62f 952 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
d12e3536 953 GetCurrentTime("%H:%M:%S"), m_fileHeader.c_str());
cecfc5e7
VZ
954}
955
956void HelpGenVisitor::VisitClass( spClass& cl )
957{
d8b6f4d9 958 CloseClass();
d12e3536 959
8ad74db3
WS
960 if (m_file.IsOpened())
961 {
962 m_file.Flush();
963 m_file.Close();
964 }
3689307f 965
cecfc5e7
VZ
966 wxString name = cl.GetName();
967
d12e3536
VZ
968 if ( m_ignoreNames.IgnoreClass(name) ) {
969 wxLogVerbose("Skipping ignored class '%s'.", name.c_str());
970
971 return;
972 }
973
cecfc5e7
VZ
974 // the file name is built from the class name by removing the leading "wx"
975 // if any and converting it to the lower case
f6bcfd97 976 wxString filename;
59734eb5
VZ
977 if ( name(0, 2) == "wx" ) {
978 filename << name.c_str() + 2;
979 }
980 else {
981 filename << name;
cecfc5e7
VZ
982 }
983
984 filename.MakeLower();
985 filename += ".tex";
f6bcfd97 986 filename.Prepend(m_directoryOut);
cecfc5e7 987
d12e3536
VZ
988 if ( !m_overwrite && wxFile::Exists(filename) ) {
989 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
5f7cf62f
VZ
990 filename.c_str());
991
5f7cf62f
VZ
992 return;
993 }
994
cecfc5e7
VZ
995 m_inClass = m_file.Open(filename, wxFile::write);
996 if ( !m_inClass ) {
997 wxLogError("Can't generate documentation for the class '%s'.",
998 name.c_str());
999
1000 return;
1001 }
1002
1003 m_inMethodSection =
8ad74db3 1004 m_inTypesSection = false;
cecfc5e7
VZ
1005
1006 wxLogInfo("Created new file '%s' for class '%s'.",
1007 filename.c_str(), name.c_str());
1008
a7adaeda
VZ
1009 // write out the header
1010 wxString header;
1011 header.Printf("%%\n"
1012 "%% automatically generated by HelpGen %s from\n"
1013 "%% %s at %s\n"
1014 "%%\n"
1015 "\n"
1016 "\n"
1017 "\\section{\\class{%s}}\\label{%s}\n\n",
2f919f99 1018 GetVersionString().c_str(),
a7adaeda
VZ
1019 m_fileHeader.c_str(),
1020 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1021 name.c_str(),
1022 wxString(name).MakeLower().c_str());
1023
d8b6f4d9 1024 m_file.WriteVerbatim(header);
a7adaeda 1025
cecfc5e7
VZ
1026 // the entire text we're writing to file
1027 wxString totalText;
1028
ed38ec7e
VZ
1029 // if the header includes other headers they must be related to it... try to
1030 // automatically generate the "See also" clause
1031 if ( !m_headers.IsEmpty() ) {
be5a51fb 1032 // correspondence between wxWidgets headers and class names
ed38ec7e
VZ
1033 static const char *headers[] = {
1034 "object",
1035 "defs",
1036 "string",
1037 "dynarray",
59734eb5 1038 "file",
ed38ec7e
VZ
1039 "time",
1040 };
1041
1042 // NULL here means not to insert anything in "See also" for the
1043 // corresponding header
1044 static const char *classes[] = {
1045 NULL,
1046 NULL,
1047 NULL,
1048 NULL,
1049 "wxFile",
1050 "wxTime",
1051 };
1052
1053 wxASSERT_MSG( WXSIZEOF(headers) == WXSIZEOF(classes),
1054 "arrays must be in sync!" );
1055
1056 wxArrayInt interestingClasses;
1057
1058 size_t count = m_headers.Count(), index;
1059 for ( size_t n = 0; n < count; n++ ) {
1060 wxString baseHeaderName = m_headers[n].Before('.');
1061 if ( baseHeaderName(0, 3) != "wx/" )
1062 continue;
1063
1064 baseHeaderName.erase(0, 3);
1065 for ( index = 0; index < WXSIZEOF(headers); index++ ) {
1066 if ( Stricmp(baseHeaderName, headers[index]) == 0 )
1067 break;
1068 }
1069
1070 if ( (index < WXSIZEOF(headers)) && classes[index] ) {
1071 // interesting header
1072 interestingClasses.Add(index);
1073 }
1074 }
1075
1076 if ( !interestingClasses.IsEmpty() ) {
1077 // do generate "See also" clause
1078 totalText << "\\wxheading{See also:}\n\n";
1079
1080 count = interestingClasses.Count();
1081 for ( index = 0; index < count; index++ ) {
1082 if ( index > 0 )
1083 totalText << ", ";
1084
1085 totalText << MakeHelpref(classes[interestingClasses[index]]);
1086 }
1087
1088 totalText << "\n\n";
1089 }
1090 }
1091
cecfc5e7
VZ
1092 // the comment before the class generally explains what is it for so put it
1093 // in place of the class description
1094 if ( cl.HasComments() ) {
ed38ec7e 1095 wxString comment = GetAllComments(cl);
cecfc5e7
VZ
1096
1097 totalText << '\n' << comment << '\n';
1098 }
1099
1100 // derived from section
1101 wxString derived = "\\wxheading{Derived from}\n\n";
1102
1103 const StrListT& baseClasses = cl.mSuperClassNames;
1104 if ( baseClasses.size() == 0 ) {
1105 derived << "No base class";
1106 }
1107 else {
8ad74db3 1108 bool first = true;
cecfc5e7
VZ
1109 for ( StrListT::const_iterator i = baseClasses.begin();
1110 i != baseClasses.end();
1111 i++ ) {
1112 if ( !first ) {
1113 // separate from the previous one
1114 derived << "\\\\\n";
1115 }
1116 else {
8ad74db3 1117 first = false;
cecfc5e7
VZ
1118 }
1119
1120 wxString baseclass = *i;
dface61c 1121 derived << "\\helpref{" << baseclass << "}";
59734eb5 1122 derived << "{" << baseclass.MakeLower() << "}";
cecfc5e7
VZ
1123 }
1124 }
1125 totalText << derived << "\n\n";
1126
5bdad898
JS
1127 // include file section
1128 wxString includeFile = "\\wxheading{Include files}\n\n";
1129 includeFile << "<" << m_fileHeader << ">";
1130
1131 totalText << includeFile << "\n\n";
1132
cecfc5e7
VZ
1133 // write all this to file
1134 m_file.WriteTeX(totalText);
1135
1136 // if there were any enums/typedefs before, insert their documentation now
1137 InsertDataStructuresHeader();
1138 InsertTypedefDocs();
1139 InsertEnumDocs();
3689307f 1140
8ad74db3 1141 //m_file.Flush();
cecfc5e7
VZ
1142}
1143
1144void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
1145{
1146 CloseFunction();
1147
1148 if ( m_inMethodSection ) {
1149 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1150 // should be smart enough to process even the enums which come after the
1151 // functions
1152 wxLogWarning("enum '%s' ignored, please put it before the class "
1153 "methods.", en.GetName().c_str());
1154 return;
1155 }
1156
1157 // simply copy the enum text in the docs
a7adaeda
VZ
1158 wxString enumeration = GetAllComments(en),
1159 enumerationVerb;
1160
1161 enumerationVerb << "\\begin{verbatim}\n"
1162 << en.mEnumContent
1163 << "\n\\end{verbatim}\n";
cecfc5e7
VZ
1164
1165 // remember for later use if we're not inside a class yet
1166 if ( !m_inClass ) {
a7adaeda
VZ
1167 m_storedEnums.Add(enumeration);
1168 m_storedEnumsVerb.Add(enumerationVerb);
cecfc5e7
VZ
1169 }
1170 else {
1171 // write the header for this section if not done yet
1172 InsertDataStructuresHeader();
1173
cecfc5e7 1174 m_file.WriteTeX(enumeration);
a7adaeda 1175 m_file.WriteVerbatim(enumerationVerb);
d8b6f4d9 1176 m_file.WriteVerbatim('\n');
cecfc5e7
VZ
1177 }
1178}
1179
1180void HelpGenVisitor::VisitTypeDef( spTypeDef& td )
1181{
1182 CloseFunction();
1183
ed38ec7e
VZ
1184 if ( m_inMethodSection ) {
1185 // FIXME that's a bug, but tell the user aboit it nevertheless...
1186 wxLogWarning("typedef '%s' ignored, please put it before the class "
1187 "methods.", td.GetName().c_str());
1188 return;
1189 }
1190
1191 wxString typedefdoc;
1192 typedefdoc << "{\\small \\begin{verbatim}\n"
1193 << "typedef " << td.mOriginalType << ' ' << td.GetName()
1194 << "\n\\end{verbatim}}\n"
1195 << GetAllComments(td);
1196
1197 // remember for later use if we're not inside a class yet
1198 if ( !m_inClass ) {
1199 if ( !m_textStoredTypedefs.IsEmpty() ) {
1200 m_textStoredTypedefs << '\n';
1201 }
1202
1203 m_textStoredTypedefs << typedefdoc;
1204 }
1205 else {
1206 // write the header for this section if not done yet
1207 InsertDataStructuresHeader();
1208
1209 typedefdoc << '\n';
1210 m_file.WriteTeX(typedefdoc);
1211 }
1212}
1213
1214void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine& pd )
1215{
1216 switch ( pd.GetStatementType() ) {
1217 case SP_PREP_DEF_INCLUDE_FILE:
1218 m_headers.Add(pd.CPP_GetIncludedFileNeme());
1219 break;
1220
1221 case SP_PREP_DEF_DEFINE_SYMBOL:
1222 // TODO decide if it's a constant and document it if it is
1223 break;
1224 }
cecfc5e7
VZ
1225}
1226
1227void HelpGenVisitor::VisitAttribute( spAttribute& attr )
1228{
1229 CloseFunction();
1230
1231 // only document the public member variables
1232 if ( !m_inClass || !attr.IsPublic() )
1233 return;
1234
ed38ec7e 1235 wxLogWarning("Ignoring member variable '%s'.", attr.GetName().c_str());
cecfc5e7
VZ
1236}
1237
1238void HelpGenVisitor::VisitOperation( spOperation& op )
1239{
1240 CloseFunction();
1241
d12e3536
VZ
1242 if ( !m_inClass ) {
1243 // we don't generate docs right now - either we ignore this class
1244 // entirely or we couldn't open the file
1245 return;
1246 }
1247
1248 if ( !op.IsInClass() ) {
1249 // TODO document global functions
cecfc5e7
VZ
1250 wxLogWarning("skipped global function '%s'.", op.GetName().c_str());
1251
1252 return;
1253 }
1254
1255 if ( op.mVisibility == SP_VIS_PRIVATE ) {
1256 // FIXME should we document protected functions?
1257 return;
1258 }
1259
d8b6f4d9
VZ
1260 m_classname = op.GetClass().GetName();
1261 wxString funcname = op.GetName();
1262
1263 if ( m_ignoreNames.IgnoreMethod(m_classname, funcname) ) {
d12e3536 1264 wxLogVerbose("Skipping ignored '%s::%s'.",
d8b6f4d9 1265 m_classname.c_str(), funcname.c_str());
d12e3536
VZ
1266
1267 return;
1268 }
1269
cecfc5e7
VZ
1270 InsertMethodsHeader();
1271
1272 // save state info
d8b6f4d9 1273 m_funcName = funcname;
8ad74db3 1274 m_isFirstParam = true;
cecfc5e7 1275
ed38ec7e 1276 m_textStoredFunctionComment = GetAllComments(op);
cecfc5e7
VZ
1277
1278 // start function documentation
1279 wxString totalText;
59734eb5 1280
cecfc5e7
VZ
1281 // check for the special case of dtor
1282 wxString dtor;
7f2e78ed 1283 if ( (funcname[0u] == '~') && (m_classname == funcname.c_str() + 1) ) {
d8b6f4d9 1284 dtor.Printf("\\destruct{%s}", m_classname.c_str());
cecfc5e7
VZ
1285 funcname = dtor;
1286 }
1287
8ad74db3
WS
1288 m_textFunc.Printf("\n"
1289 "\\membersection{%s::%s}\\label{%s}\n",
1290 m_classname.c_str(), funcname.c_str(),
1291 MakeLabel(m_classname, funcname).c_str());
eb420090 1292
8ad74db3
WS
1293 wxString func;
1294 func.Printf("\n"
eb420090 1295 "\\%sfunc{%s%s}{%s}{",
d8b6f4d9
VZ
1296 op.mIsConstant ? "const" : "",
1297 op.mIsVirtual ? "virtual " : "",
1298 op.mRetType.c_str(),
1299 funcname.c_str());
8ad74db3 1300 m_textFunc += func;
cecfc5e7
VZ
1301}
1302
1303void HelpGenVisitor::VisitParameter( spParameter& param )
1304{
d8b6f4d9 1305 if ( m_funcName.empty() )
cecfc5e7
VZ
1306 return;
1307
cecfc5e7 1308 if ( m_isFirstParam ) {
8ad74db3 1309 m_isFirstParam = false;
cecfc5e7
VZ
1310 }
1311 else {
d8b6f4d9 1312 m_textFunc << ", ";
cecfc5e7 1313 }
59734eb5 1314
d8b6f4d9 1315 m_textFunc << "\\param{" << param.mType << " }{" << param.GetName();
cecfc5e7
VZ
1316 wxString defvalue = param.mInitVal;
1317 if ( !defvalue.IsEmpty() ) {
d8b6f4d9 1318 m_textFunc << " = " << defvalue;
cecfc5e7 1319 }
59734eb5 1320
d8b6f4d9 1321 m_textFunc << '}';
cecfc5e7
VZ
1322}
1323
5f7cf62f
VZ
1324// ---------------------------------------------------------------------------
1325// DocManager
1326// ---------------------------------------------------------------------------
1327
d12e3536
VZ
1328DocManager::DocManager(bool checkParamNames)
1329{
1330 m_checkParamNames = checkParamNames;
1331}
1332
5f7cf62f
VZ
1333size_t DocManager::TryMatch(const char *str, const char *match)
1334{
1335 size_t lenMatch = 0;
1336 while ( str[lenMatch] == match[lenMatch] ) {
1337 lenMatch++;
1338
1339 if ( match[lenMatch] == '\0' )
1340 return lenMatch;
1341 }
1342
1343 return 0;
1344}
1345
1346bool DocManager::SkipUntil(const char **pp, char c)
1347{
1348 const char *p = *pp;
1349 while ( *p != c ) {
1350 if ( *p == '\0' )
1351 break;
1352
1353 if ( *p == '\n' )
1354 m_line++;
1355
1356 p++;
1357 }
1358
1359 *pp = p;
1360
1361 return *p == c;
1362}
1363
1364bool DocManager::SkipSpaceUntil(const char **pp, char c)
1365{
1366 const char *p = *pp;
1367 while ( *p != c ) {
1368 if ( !isspace(*p) || *p == '\0' )
1369 break;
1370
1371 if ( *p == '\n' )
1372 m_line++;
1373
1374 p++;
1375 }
1376
1377 *pp = p;
1378
1379 return *p == c;
1380}
1381
1382wxString DocManager::ExtractStringBetweenBraces(const char **pp)
1383{
1384 wxString result;
1385
1386 if ( !SkipSpaceUntil(pp, '{') ) {
1387 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1388 m_filename.c_str(), m_line);
1389
1390 }
1391 else {
1392 const char *startParam = ++*pp; // skip '{'
1393
1394 if ( !SkipUntil(pp, '}') ) {
1395 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1396 m_filename.c_str(), m_line);
1397 }
1398 else {
1399 result = wxString(startParam, (*pp)++ - startParam);
1400 }
1401 }
1402
1403 return result;
1404}
1405
1406bool DocManager::ParseTeXFile(const wxString& filename)
1407{
1408 m_filename = filename;
1409
1410 wxFile file(m_filename, wxFile::read);
1411 if ( !file.IsOpened() )
8ad74db3 1412 return false;
5f7cf62f
VZ
1413
1414 off_t len = file.Length();
1415 if ( len == wxInvalidOffset )
8ad74db3 1416 return false;
5f7cf62f
VZ
1417
1418 char *buf = new char[len + 1];
1419 buf[len] = '\0';
1420
1421 if ( file.Read(buf, len) == wxInvalidOffset ) {
1422 delete [] buf;
1423
8ad74db3 1424 return false;
5f7cf62f
VZ
1425 }
1426
1427 // reinit everything
1428 m_line = 1;
1429
1430 wxLogVerbose("%s: starting to parse doc file '%s'.",
1431 GetCurrentTime("%H:%M:%S"), m_filename.c_str());
1432
1433 // the name of the class from the last "\membersection" command: we assume
1434 // that the following "\func" or "\constfunc" always documents a method of
be5a51fb 1435 // this class (and it should always be like that in wxWidgets documentation)
5f7cf62f
VZ
1436 wxString classname;
1437
1438 for ( const char *current = buf; current - buf < len; current++ ) {
1439 // FIXME parsing is awfully inefficient
1440
1441 if ( *current == '%' ) {
1442 // comment, skip until the end of line
1443 current++;
1444 SkipUntil(&current, '\n');
1445
1446 continue;
1447 }
1448
1449 // all the command we're interested in start with '\\'
1450 while ( *current != '\\' && *current != '\0' ) {
1451 if ( *current++ == '\n' )
1452 m_line++;
1453 }
1454
1455 if ( *current == '\0' ) {
1456 // no more TeX commands left
1457 break;
1458 }
1459
1460 current++; // skip '\\'
1461
1462 enum
1463 {
1464 Nothing,
1465 Func,
1466 ConstFunc,
1467 MemberSect
1468 } foundCommand = Nothing;
1469
1470 size_t lenMatch = TryMatch(current, "func");
1471 if ( lenMatch ) {
1472 foundCommand = Func;
1473 }
1474 else {
1475 lenMatch = TryMatch(current, "constfunc");
1476 if ( lenMatch )
1477 foundCommand = ConstFunc;
1478 else {
1479 lenMatch = TryMatch(current, "membersection");
1480
1481 if ( lenMatch )
1482 foundCommand = MemberSect;
1483 }
1484 }
1485
1486 if ( foundCommand == Nothing )
1487 continue;
1488
1489 current += lenMatch;
1490
1491 if ( !SkipSpaceUntil(&current, '{') ) {
1492 wxLogWarning("file %s(%d): '{' expected after \\func, "
1493 "\\constfunc or \\membersection.",
1494 m_filename.c_str(), m_line);
1495
1496 continue;
1497 }
1498
1499 current++;
1500
1501 if ( foundCommand == MemberSect ) {
1502 // what follows has the form <classname>::<funcname>
1503 const char *startClass = current;
1504 if ( !SkipUntil(&current, ':') || *(current + 1) != ':' ) {
1505 wxLogWarning("file %s(%d): '::' expected after "
1506 "\\membersection.", m_filename.c_str(), m_line);
1507 }
1508 else {
1509 classname = wxString(startClass, current - startClass);
1510 TeXUnfilter(&classname);
1511 }
1512
1513 continue;
1514 }
1515
1516 // extract the return type
1517 const char *startRetType = current;
1518
1519 if ( !SkipUntil(&current, '}') ) {
1520 wxLogWarning("file %s(%d): '}' expected after return type",
1521 m_filename.c_str(), m_line);
1522
1523 continue;
1524 }
1525
1526 wxString returnType = wxString(startRetType, current - startRetType);
1527 TeXUnfilter(&returnType);
1528
1529 current++;
8ad74db3 1530 if ( !SkipSpaceUntil(&current, '{') ) {
5f7cf62f
VZ
1531 wxLogWarning("file %s(%d): '{' expected after return type",
1532 m_filename.c_str(), m_line);
1533
1534 continue;
1535 }
1536
1537 current++;
1538 const char *funcEnd = current;
1539 if ( !SkipUntil(&funcEnd, '}') ) {
1540 wxLogWarning("file %s(%d): '}' expected after function name",
1541 m_filename.c_str(), m_line);
1542
1543 continue;
1544 }
1545
1546 wxString funcName = wxString(current, funcEnd - current);
1547 current = funcEnd + 1;
1548
1549 // trim spaces from both sides
8ad74db3
WS
1550 funcName.Trim(false);
1551 funcName.Trim(true);
5f7cf62f
VZ
1552
1553 // special cases: '$...$' may be used for LaTeX inline math, remove the
1554 // '$'s
1555 if ( funcName.Find('$') != wxNOT_FOUND ) {
1556 wxString name;
1557 for ( const char *p = funcName.c_str(); *p != '\0'; p++ ) {
1558 if ( *p != '$' && !isspace(*p) )
1559 name += *p;
1560 }
1561
1562 funcName = name;
1563 }
1564
1565 // \destruct{foo} is really ~foo
1566 if ( funcName[0u] == '\\' ) {
1567 size_t len = strlen("\\destruct{");
1568 if ( funcName(0, len) != "\\destruct{" ) {
1569 wxLogWarning("file %s(%d): \\destruct expected",
1570 m_filename.c_str(), m_line);
1571
1572 continue;
1573 }
1574
1575 funcName.erase(0, len);
1576 funcName.Prepend('~');
1577
1578 if ( !SkipSpaceUntil(&current, '}') ) {
1579 wxLogWarning("file %s(%d): '}' expected after destructor",
1580 m_filename.c_str(), m_line);
1581
1582 continue;
1583 }
1584
1585 funcEnd++; // there is an extra '}' to count
1586 }
1587
1588 TeXUnfilter(&funcName);
1589
1590 // extract params
1591 current = funcEnd + 1; // skip '}'
1592 if ( !SkipSpaceUntil(&current, '{') ||
1593 (current++, !SkipSpaceUntil(&current, '\\')) ) {
1594 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1595 m_filename.c_str(), m_line);
1596
1597 continue;
1598 }
1599
1600 wxArrayString paramNames, paramTypes, paramValues;
1601
8ad74db3 1602 bool isVararg = false;
5f7cf62f
VZ
1603
1604 current++; // skip '\\'
1605 lenMatch = TryMatch(current, "void");
1606 if ( !lenMatch ) {
1607 lenMatch = TryMatch(current, "param");
d12e3536 1608 while ( lenMatch && (current - buf < len) ) {
5f7cf62f
VZ
1609 current += lenMatch;
1610
1611 // now come {paramtype}{paramname}
1612 wxString paramType = ExtractStringBetweenBraces(&current);
1613 if ( !!paramType ) {
1614 wxString paramText = ExtractStringBetweenBraces(&current);
1615 if ( !!paramText ) {
1616 // the param declaration may contain default value
1617 wxString paramName = paramText.BeforeFirst('='),
1618 paramValue = paramText.AfterFirst('=');
1619
1620 // sanitize all strings
1621 TeXUnfilter(&paramValue);
1622 TeXUnfilter(&paramName);
1623 TeXUnfilter(&paramType);
1624
1625 paramValues.Add(paramValue);
1626 paramNames.Add(paramName);
1627 paramTypes.Add(paramType);
1628 }
1629 }
1630 else {
1631 // vararg function?
1632 wxString paramText = ExtractStringBetweenBraces(&current);
1633 if ( paramText == "..." ) {
8ad74db3 1634 isVararg = true;
5f7cf62f
VZ
1635 }
1636 else {
1637 wxLogWarning("Parameters of '%s::%s' are in "
1638 "incorrect form.",
1639 classname.c_str(), funcName.c_str());
1640 }
1641 }
1642
1643 // what's next?
1644 current = SkipSpaces(current);
1645 if ( *current == ',' || *current == '}' ) {
1646 current = SkipSpaces(++current);
1647
1648 lenMatch = TryMatch(current, "\\param");
1649 }
1650 else {
1651 wxLogWarning("file %s(%d): ',' or '}' expected after "
1652 "'\\param'", m_filename.c_str(), m_line);
1653
1654 continue;
1655 }
1656 }
1657
1658 // if we got here there was no '\\void', so must have some params
1659 if ( paramNames.IsEmpty() ) {
1660 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1661 m_filename.c_str(), m_line);
1662
1663 continue;
1664 }
1665 }
1666
1667 // verbose diagnostic output
1668 wxString paramsAll;
1669 size_t param, paramCount = paramNames.GetCount();
1670 for ( param = 0; param < paramCount; param++ ) {
1671 if ( param != 0 ) {
1672 paramsAll << ", ";
1673 }
1674
1675 paramsAll << paramTypes[param] << ' ' << paramNames[param];
1676 }
1677
1678 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1679 m_filename.c_str(), m_line,
1680 returnType.c_str(),
1681 classname.c_str(),
1682 funcName.c_str(),
1683 paramsAll.c_str(),
1684 foundCommand == ConstFunc ? " const" : "");
1685
1686 // store the info about the just found function
1687 ArrayMethodInfo *methods;
1688 int index = m_classes.Index(classname);
1689 if ( index == wxNOT_FOUND ) {
1690 m_classes.Add(classname);
1691
1692 methods = new ArrayMethodInfo;
1693 m_methods.Add(methods);
1694 }
1695 else {
1696 methods = m_methods[(size_t)index];
1697 }
1698
1699 ArrayParamInfo params;
1700 for ( param = 0; param < paramCount; param++ ) {
1701 params.Add(new ParamInfo(paramTypes[param],
1702 paramNames[param],
1703 paramValues[param]));
1704 }
1705
1706 MethodInfo *method = new MethodInfo(returnType, funcName, params);
1707 if ( foundCommand == ConstFunc )
1708 method->SetFlag(MethodInfo::Const);
1709 if ( isVararg )
1710 method->SetFlag(MethodInfo::Vararg);
1711
1712 methods->Add(method);
1713 }
1714
1715 delete [] buf;
1716
1717 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1718 GetCurrentTime("%H:%M:%S"), m_filename.c_str());
1719
8ad74db3 1720 return true;
5f7cf62f
VZ
1721}
1722
1723bool DocManager::DumpDifferences(spContext *ctxTop) const
1724{
1725 typedef MMemberListT::const_iterator MemberIndex;
1726
8ad74db3 1727 bool foundDiff = false;
5f7cf62f
VZ
1728
1729 // flag telling us whether the given class was found at all in the header
1730 size_t nClass, countClassesInDocs = m_classes.GetCount();
1731 bool *classExists = new bool[countClassesInDocs];
1732 for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
8ad74db3 1733 classExists[nClass] = false;
5f7cf62f
VZ
1734 }
1735
1736 // ctxTop is normally an spFile
1737 wxASSERT( ctxTop->GetContextType() == SP_CTX_FILE );
1738
1739 const MMemberListT& classes = ctxTop->GetMembers();
1740 for ( MemberIndex i = classes.begin(); i != classes.end(); i++ ) {
1741 spContext *ctx = *i;
1742 if ( ctx->GetContextType() != SP_CTX_CLASS ) {
1743 // TODO process also global functions, macros, ...
1744 continue;
1745 }
1746
1747 spClass *ctxClass = (spClass *)ctx;
1748 const wxString& nameClass = ctxClass->mName;
1749 int index = m_classes.Index(nameClass);
1750 if ( index == wxNOT_FOUND ) {
d12e3536 1751 if ( !m_ignoreNames.IgnoreClass(nameClass) ) {
8ad74db3 1752 foundDiff = true;
5f7cf62f
VZ
1753
1754 wxLogError("Class '%s' is not documented at all.",
1755 nameClass.c_str());
1756 }
1757
1758 // it makes no sense to check for its functions
1759 continue;
1760 }
1761 else {
8ad74db3 1762 classExists[index] = true;
5f7cf62f
VZ
1763 }
1764
1765 // array of method descriptions for this class
1766 const ArrayMethodInfo& methods = *(m_methods[index]);
1767 size_t nMethod, countMethods = methods.GetCount();
1768
1769 // flags telling if we already processed given function
1770 bool *methodExists = new bool[countMethods];
1771 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
8ad74db3 1772 methodExists[nMethod] = false;
5f7cf62f
VZ
1773 }
1774
1775 wxArrayString aOverloadedMethods;
1776
1777 const MMemberListT& functions = ctxClass->GetMembers();
1778 for ( MemberIndex j = functions.begin(); j != functions.end(); j++ ) {
1779 ctx = *j;
1780 if ( ctx->GetContextType() != SP_CTX_OPERATION )
1781 continue;
1782
1783 spOperation *ctxMethod = (spOperation *)ctx;
1784 const wxString& nameMethod = ctxMethod->mName;
1785
1786 // find all functions with the same name
1787 wxArrayInt aMethodsWithSameName;
1788 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1789 if ( methods[nMethod]->GetName() == nameMethod )
1790 aMethodsWithSameName.Add(nMethod);
1791 }
1792
1793 if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
d12e3536 1794 if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
8ad74db3 1795 foundDiff = true;
5f7cf62f
VZ
1796
1797 wxLogError("'%s::%s' is not documented.",
1798 nameClass.c_str(),
1799 nameMethod.c_str());
1800 }
1801
1802 // don't check params
1803 continue;
1804 }
1805 else if ( aMethodsWithSameName.GetCount() == 1 ) {
1806 index = (size_t)aMethodsWithSameName[0u];
8ad74db3 1807 methodExists[index] = true;
5f7cf62f 1808
d12e3536 1809 if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
5f7cf62f
VZ
1810 continue;
1811
1812 if ( !ctxMethod->IsPublic() ) {
1813 wxLogWarning("'%s::%s' is documented but not public.",
1814 nameClass.c_str(),
1815 nameMethod.c_str());
1816 }
1817
1818 // check that the flags match
1819 const MethodInfo& method = *(methods[index]);
1820
1821 bool isVirtual = ctxMethod->mIsVirtual;
1822 if ( isVirtual != method.HasFlag(MethodInfo::Virtual) ) {
1823 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1824 "virtual.",
1825 nameClass.c_str(),
1826 nameMethod.c_str(),
1827 isVirtual ? "not " : "");
1828 }
1829
1830 bool isConst = ctxMethod->mIsConstant;
1831 if ( isConst != method.HasFlag(MethodInfo::Const) ) {
1832 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1833 "constant.",
1834 nameClass.c_str(),
1835 nameMethod.c_str(),
1836 isConst ? "not " : "");
1837 }
1838
1839 // check that the params match
1840 const MMemberListT& params = ctxMethod->GetMembers();
1841
1842 if ( params.size() != method.GetParamCount() ) {
1843 wxLogError("Incorrect number of parameters for '%s::%s' "
1844 "in the docs: should be %d instead of %d.",
1845 nameClass.c_str(),
1846 nameMethod.c_str(),
1847 params.size(), method.GetParamCount());
1848 }
1849 else {
1850 size_t nParam = 0;
1851 for ( MemberIndex k = params.begin();
1852 k != params.end();
1853 k++, nParam++ ) {
1854 ctx = *k;
1855
1856 // what else can a function have?
1857 wxASSERT( ctx->GetContextType() == SP_CTX_PARAMETER );
1858
1859 spParameter *ctxParam = (spParameter *)ctx;
1860 const ParamInfo& param = method.GetParam(nParam);
d12e3536
VZ
1861 if ( m_checkParamNames &&
1862 (param.GetName() != ctxParam->mName) ) {
8ad74db3 1863 foundDiff = true;
5f7cf62f
VZ
1864
1865 wxLogError("Parameter #%d of '%s::%s' should be "
1866 "'%s' and not '%s'.",
1867 nParam + 1,
1868 nameClass.c_str(),
1869 nameMethod.c_str(),
1870 ctxParam->mName.c_str(),
1871 param.GetName().c_str());
1872
1873 continue;
1874 }
1875
1876 if ( param.GetType() != ctxParam->mType ) {
8ad74db3 1877 foundDiff = true;
5f7cf62f
VZ
1878
1879 wxLogError("Type of parameter '%s' of '%s::%s' "
1880 "should be '%s' and not '%s'.",
1881 ctxParam->mName.c_str(),
1882 nameClass.c_str(),
1883 nameMethod.c_str(),
1884 ctxParam->mType.c_str(),
1885 param.GetType().GetName().c_str());
1886
1887 continue;
1888 }
1889
1890 if ( param.GetDefValue() != ctxParam->mInitVal ) {
1891 wxLogWarning("Default value of parameter '%s' of "
1892 "'%s::%s' should be '%s' and not "
1893 "'%s'.",
1894 ctxParam->mName.c_str(),
1895 nameClass.c_str(),
1896 nameMethod.c_str(),
1897 ctxParam->mInitVal.c_str(),
1898 param.GetDefValue().c_str());
1899 }
1900 }
1901 }
1902 }
1903 else {
d12e3536 1904 // TODO OVER add real support for overloaded methods
5f7cf62f 1905
d12e3536 1906 if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
5f7cf62f
VZ
1907 continue;
1908
1909 if ( aOverloadedMethods.Index(nameMethod) == wxNOT_FOUND ) {
1910 // mark all methods with this name as existing
1911 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1912 if ( methods[nMethod]->GetName() == nameMethod )
8ad74db3 1913 methodExists[nMethod] = true;
5f7cf62f
VZ
1914 }
1915
1916 aOverloadedMethods.Add(nameMethod);
1917
1918 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1919 "stupid to find the right match - skipping "
1920 "the param and flags checks.",
1921 nameClass.c_str(),
1922 nameMethod.c_str());
1923 }
1924 //else: warning already given
1925 }
1926 }
1927
1928 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1929 if ( !methodExists[nMethod] ) {
1930 const wxString& nameMethod = methods[nMethod]->GetName();
d12e3536 1931 if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
8ad74db3 1932 foundDiff = true;
5f7cf62f
VZ
1933
1934 wxLogError("'%s::%s' is documented but doesn't exist.",
1935 nameClass.c_str(),
1936 nameMethod.c_str());
1937 }
1938 }
1939 }
1940
1941 delete [] methodExists;
1942 }
1943
1944 // check that all classes we found in the docs really exist
1945 for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
1946 if ( !classExists[nClass] ) {
8ad74db3 1947 foundDiff = true;
5f7cf62f
VZ
1948
1949 wxLogError("Class '%s' is documented but doesn't exist.",
1950 m_classes[nClass].c_str());
1951 }
1952 }
1953
1954 delete [] classExists;
1955
1956 return !foundDiff;
1957}
1958
1959DocManager::~DocManager()
1960{
1961 WX_CLEAR_ARRAY(m_methods);
5f7cf62f
VZ
1962}
1963
d12e3536
VZ
1964// ---------------------------------------------------------------------------
1965// IgnoreNamesHandler implementation
1966// ---------------------------------------------------------------------------
1967
1968int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first,
1969 IgnoreListEntry *second)
5f7cf62f
VZ
1970{
1971 // first compare the classes
1972 int rc = first->m_classname.Cmp(second->m_classname);
1973 if ( rc == 0 )
1974 rc = first->m_funcname.Cmp(second->m_funcname);
1975
1976 return rc;
1977}
1978
d12e3536 1979bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
5f7cf62f
VZ
1980{
1981 wxFile file(filename, wxFile::read);
1982 if ( !file.IsOpened() )
8ad74db3 1983 return false;
5f7cf62f
VZ
1984
1985 off_t len = file.Length();
1986 if ( len == wxInvalidOffset )
8ad74db3 1987 return false;
5f7cf62f
VZ
1988
1989 char *buf = new char[len + 1];
1990 buf[len] = '\0';
1991
1992 if ( file.Read(buf, len) == wxInvalidOffset ) {
1993 delete [] buf;
1994
8ad74db3 1995 return false;
5f7cf62f
VZ
1996 }
1997
1998 wxString line;
1999 for ( const char *current = buf; ; current++ ) {
2000#ifdef __WXMSW__
2001 // skip DOS line separator
2002 if ( *current == '\r' )
2003 current++;
2004#endif // wxMSW
2005
2006 if ( *current == '\n' || *current == '\0' ) {
2007 if ( line[0u] != '#' ) {
2008 if ( line.Find(':') != wxNOT_FOUND ) {
2009 wxString classname = line.BeforeFirst(':'),
2010 funcname = line.AfterLast(':');
2011 m_ignore.Add(new IgnoreListEntry(classname, funcname));
2012 }
2013 else {
2014 // entire class
2015 m_ignore.Add(new IgnoreListEntry(line, ""));
2016 }
2017 }
2018 //else: comment
2019
2020 if ( *current == '\0' )
2021 break;
2022
2023 line.Empty();
2024 }
2025 else {
2026 line += *current;
2027 }
2028 }
2029
2030 delete [] buf;
2031
8ad74db3 2032 return true;
5f7cf62f
VZ
2033}
2034
cecfc5e7
VZ
2035// -----------------------------------------------------------------------------
2036// global function implementation
2037// -----------------------------------------------------------------------------
2038
2039static wxString MakeLabel(const char *classname, const char *funcname)
2040{
2041 wxString label(classname);
ed38ec7e 2042 if ( funcname && funcname[0] == '\\' ) {
cecfc5e7
VZ
2043 // we may have some special TeX macro - so far only \destruct exists,
2044 // but may be later others will be added
2045 static const char *macros[] = { "destruct" };
2046 static const char *replacement[] = { "dtor" };
59734eb5 2047
cecfc5e7
VZ
2048 size_t n;
2049 for ( n = 0; n < WXSIZEOF(macros); n++ ) {
2050 if ( strncmp(funcname + 1, macros[n], strlen(macros[n])) == 0 ) {
2051 // found
2052 break;
2053 }
2054 }
2055
2056 if ( n == WXSIZEOF(macros) ) {
2057 wxLogWarning("unknown function name '%s' - leaving as is.",
2058 funcname);
2059 }
2060 else {
2061 funcname = replacement[n];
2062 }
2063 }
2064
d8b6f4d9
VZ
2065 if ( funcname ) {
2066 // special treatment for operatorXXX() stuff because the C operators
2067 // are not valid in LaTeX labels
2068 wxString oper;
2069 if ( wxString(funcname).StartsWith("operator", &oper) ) {
2070 label << "operator";
2071
2072 static const struct
2073 {
2074 const char *oper;
2075 const char *name;
2076 } operatorNames[] =
2077 {
2078 { "=", "assign" },
2079 { "==", "equal" },
2080 };
2081
2082 size_t n;
2083 for ( n = 0; n < WXSIZEOF(operatorNames); n++ ) {
2084 if ( oper == operatorNames[n].oper ) {
2085 label << operatorNames[n].name;
2086
2087 break;
2088 }
2089 }
2090
2091 if ( n == WXSIZEOF(operatorNames) ) {
2092 wxLogWarning("unknown operator '%s' - making dummy label.",
2093 oper.c_str());
2094
2095 label << "unknown";
2096 }
2097 }
2098 else // simply use the func name
2099 {
2100 label << funcname;
2101 }
2102 }
cecfc5e7
VZ
2103
2104 label.MakeLower();
2105
2106 return label;
2107}
2108
ed38ec7e
VZ
2109static wxString MakeHelpref(const char *argument)
2110{
2111 wxString helpref;
2112 helpref << "\\helpref{" << argument << "}{" << MakeLabel(argument) << '}';
2113
2114 return helpref;
2115}
2116
a7adaeda
VZ
2117static void TeXFilter(wxString* str)
2118{
2119 // TeX special which can be quoted (don't include backslash nor braces as
8ad74db3 2120 // we generate them
a7adaeda
VZ
2121 static wxRegEx reNonSpecialSpecials("[#$%&_]"),
2122 reAccents("[~^]");
2123
2124 // just quote
2125 reNonSpecialSpecials.ReplaceAll(str, "\\\\\\0");
2126
2127 // can't quote these ones as they produce accents when preceded by
2128 // backslash, so put them inside verb
2129 reAccents.ReplaceAll(str, "\\\\verb|\\0|");
2130}
2131
5f7cf62f
VZ
2132static void TeXUnfilter(wxString* str)
2133{
2134 // FIXME may be done much more quickly
8ad74db3
WS
2135 str->Trim(true);
2136 str->Trim(false);
5f7cf62f 2137
a7adaeda
VZ
2138 // undo TeXFilter
2139 static wxRegEx reNonSpecialSpecials("\\\\([#$%&_{}])"),
d5eddfef 2140 reAccents("\\\\verb\\|([~^])\\|");
5f7cf62f 2141
a7adaeda
VZ
2142 reNonSpecialSpecials.ReplaceAll(str, "\\1");
2143 reAccents.ReplaceAll(str, "\\1");
cecfc5e7
VZ
2144}
2145
ed38ec7e
VZ
2146static wxString GetAllComments(const spContext& ctx)
2147{
59734eb5
VZ
2148 wxString comments;
2149 const MCommentListT& commentsList = ctx.GetCommentList();
2150 for ( MCommentListT::const_iterator i = commentsList.begin();
2151 i != commentsList.end();
2152 i++ ) {
2153 wxString comment = (*i)->GetText();
2154
2155 // don't take comments like "// ----------" &c
8ad74db3 2156 comment.Trim(false);
59734eb5
VZ
2157 if ( !!comment &&
2158 comment == wxString(comment[0u], comment.length() - 1) + '\n' )
2159 comments << "\n";
2160 else
2161 comments << comment;
ed38ec7e
VZ
2162 }
2163
59734eb5 2164 return comments;
ed38ec7e
VZ
2165}
2166
2167static const char *GetCurrentTime(const char *timeFormat)
2168{
2169 static char s_timeBuffer[128];
2170 time_t timeNow;
2171 struct tm *ptmNow;
2172
2173 time(&timeNow);
2174 ptmNow = localtime(&timeNow);
2175
2176 strftime(s_timeBuffer, WXSIZEOF(s_timeBuffer), timeFormat, ptmNow);
2177
2178 return s_timeBuffer;
2179}
2180
2f919f99
VZ
2181static const wxString GetVersionString()
2182{
2183 wxString version = "$Revision$";
2184 wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1");
2185 return version;
2186}
2187
5f7cf62f
VZ
2188/*
2189 $Log$
8ad74db3
WS
2190 Revision 1.29 2004/06/17 19:00:22 ABX
2191 Warning fixes. Code cleanup. Whitespaces and tabs removed.
2192
be5a51fb
JS
2193 Revision 1.28 2004/05/25 11:19:57 JS
2194 More name changes
2195
7f2e78ed
MB
2196 Revision 1.27 2003/10/13 17:21:30 MBN
2197 Compilation fixes.
2198
c58cff9a
MB
2199 Revision 1.26 2003/09/29 15:18:35 MBN
2200 (Blind) compilation fix for Sun compiler.
2201
b521a6f9
MB
2202 Revision 1.25 2003/09/03 17:39:27 MBN
2203 Compilation fixes.
2204
cd0b9157
VZ
2205 Revision 1.24 2003/08/13 22:59:37 VZ
2206 compilation fix
2207
d5eddfef
VZ
2208 Revision 1.23 2003/06/13 17:05:43 VZ
2209 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2210
5bdad898
JS
2211 Revision 1.22 2002/01/21 21:18:50 JS
2212 Now adds 'include file' heading
2213
df6e7577
JS
2214 Revision 1.21 2002/01/04 11:06:09 JS
2215 Fixed missing membersections bug and also bug with functions not being written
2216 in the right class
2217
eb420090
JS
2218 Revision 1.20 2002/01/03 14:23:33 JS
2219 Added code to make it not duplicate membersections for overloaded functions
2220
3689307f
JS
2221 Revision 1.19 2002/01/03 13:34:12 JS
2222 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2223 and appeared in one file.
2224
31dc7e49
JS
2225 Revision 1.18 2002/01/03 12:02:47 JS
2226 Added main() and corrected VC++ project settings
2227
d8b6f4d9
VZ
2228 Revision 1.17 2001/11/30 21:43:35 VZ
2229 now the methods are sorted in the correct order in the generated docs
2230
a3b72ffb
VZ
2231 Revision 1.16 2001/11/28 19:27:33 VZ
2232 HelpGen doesn't work in GUI mode
2233
5aa5c1e4
GD
2234 Revision 1.15 2001/11/22 21:59:58 GD
2235 use "..." instead of <...> for wx headers
2236
2f919f99
VZ
2237 Revision 1.14 2001/07/19 13:51:29 VZ
2238 fixes to version string
2239
a7adaeda
VZ
2240 Revision 1.13 2001/07/19 13:44:57 VZ
2241 1. compilation fixes
2242 2. don't quote special characters inside verbatim environment
2243
4e28924c 2244 Revision 1.12 2000/10/09 13:53:33 juliansmart
a7adaeda 2245
4e28924c
JS
2246 Doc corrections; added HelpGen project files
2247
f6bcfd97
BP
2248 Revision 1.11 2000/07/15 19:50:42 cvsuser
2249 merged 2.2 branch
2250
2251 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2252 don't trasnform output dir name to lower case
2253
de528224
VS
2254 Revision 1.10 2000/03/11 10:05:23 VS
2255 now compiles with wxBase
2256
b136d1fe
VS
2257 Revision 1.9 2000/01/16 13:25:21 VS
2258 compilation fixes (gcc)
2259
28468136 2260 Revision 1.8 1999/09/13 14:29:39 JS
b136d1fe 2261
28468136
JS
2262 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2263 into src for simplicity; added VC++ 5 project file
2264
d12e3536
VZ
2265 Revision 1.7 1999/02/21 22:32:32 VZ
2266 1. more C++ parser fixes - now it almost parses wx/string.h
2267 a) #if/#ifdef/#else (very) limited support
2268 b) param type fix - now indirection chars are correctly handled
2269 c) class/struct/union distinction
2270 d) public/private fixes
2271 e) Dump() function added - very useful for debugging
2272
2273 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2274 by default, and this option switches it on)
2275
5f7cf62f
VZ
2276 Revision 1.6 1999/02/20 23:00:26 VZ
2277 1. new 'diff' mode which seems to work
2278 2. output files are not overwritten in 'dmup' mode
2279 3. fixes for better handling of const functions and operators
d12e3536
VZ
2280 ----------------------------
2281 revision 1.5
2282 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2283 1. Parser improvements
2284 a) const and virtual methods are parsed correctly (not static yet)
2285 b) "const" which is part of the return type is not swallowed
2286
2287 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2288 "//---------" kind comments discarded now.
2289 ----------------------------
2290 revision 1.4
2291 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2292
2293 some tweaks to HelpGen
2294 ----------------------------
2295 revision 1.3
2296 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2297
2298 HelpGen starting to compile with VC++
2299 ----------------------------
2300 revision 1.2
2301 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2302
2303 supports typedefs, generates "See also:" and adds "virtual " for virtual
2304 functions
2305 ----------------------------
2306 revision 1.1
2307 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2308
2309 HelpGen is a prototype of the tool for automatic generation of the .tex files
be5a51fb 2310 for wxWidgets documentation from C++ headers
5f7cf62f
VZ
2311*/
2312
cecfc5e7 2313/* vi: set tw=80 et ts=4 sw=4: */