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