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