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