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