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