]> git.saurik.com Git - wxWidgets.git/blame - utils/HelpGen/src/HelpGen.cpp
added missing include file for Apple DevTools
[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
31dc7e49 95// IMPLEMENT_APP(HelpGenApp);
28468136 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
31dc7e49
JS
790int main(int argc, char **argv)
791{
792 wxInitializer initializer;
793 if ( !initializer )
794 {
795 fprintf(stderr, "Failed to initialize the wxWindows library, aborting.");
796
797 return -1;
798 }
799 HelpGenApp app;
800 app.argc = argc;
801 app.argv = argv;
802 return app.OnRun();
803}
804
cecfc5e7
VZ
805// -----------------------------------------------------------------------------
806// HelpGenVisitor implementation
807// -----------------------------------------------------------------------------
808
d12e3536
VZ
809HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut,
810 bool overwrite)
811 : m_directoryOut(directoryOut)
812{
813 m_overwrite = overwrite;
814
815 Reset();
816}
817
cecfc5e7
VZ
818void HelpGenVisitor::Reset()
819{
820 m_inClass =
cecfc5e7 821 m_inTypesSection =
5f7cf62f 822 m_inMethodSection = FALSE;
ed38ec7e 823
d8b6f4d9
VZ
824 m_classname =
825 m_funcName =
826 m_textFunc =
ed38ec7e 827 m_textStoredTypedefs =
ed38ec7e 828 m_textStoredFunctionComment = "";
a7adaeda 829
d8b6f4d9
VZ
830 m_arrayFuncDocs.Empty();
831
a7adaeda
VZ
832 m_storedEnums.Empty();
833 m_storedEnumsVerb.Empty();
ed38ec7e 834 m_headers.Empty();
cecfc5e7
VZ
835}
836
837void HelpGenVisitor::InsertTypedefDocs()
838{
839 m_file.WriteTeX(m_textStoredTypedefs);
840 m_textStoredTypedefs.Empty();
841}
842
843void HelpGenVisitor::InsertEnumDocs()
844{
a7adaeda
VZ
845 size_t count = m_storedEnums.GetCount();
846 for ( size_t n = 0; n < count; n++ )
847 {
848 m_file.WriteTeX(m_storedEnums[n]);
849 m_file.WriteVerbatim(m_storedEnumsVerb[n] + '\n');
850 }
851
852 m_storedEnums.Empty();
853 m_storedEnumsVerb.Empty();
cecfc5e7
VZ
854}
855
856void HelpGenVisitor::InsertDataStructuresHeader()
857{
858 if ( !m_inTypesSection ) {
5f7cf62f 859 m_inTypesSection = TRUE;
cecfc5e7 860
d8b6f4d9 861 m_file.WriteVerbatim("\\wxheading{Data structures}\n\n");
cecfc5e7
VZ
862 }
863}
864
865void HelpGenVisitor::InsertMethodsHeader()
866{
867 if ( !m_inMethodSection ) {
5f7cf62f 868 m_inMethodSection = TRUE;
cecfc5e7 869
d8b6f4d9 870 m_file.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
cecfc5e7
VZ
871 }
872}
873
874void HelpGenVisitor::CloseFunction()
875{
d8b6f4d9 876 if ( !m_funcName.empty() ) {
cecfc5e7
VZ
877 if ( m_isFirstParam ) {
878 // no params found
d8b6f4d9
VZ
879 m_textFunc << "\\void";
880 }
881
882 m_textFunc << "}\n\n";
883
884 if ( !m_textStoredFunctionComment.IsEmpty() ) {
885 m_textFunc << m_textStoredFunctionComment << '\n';
cecfc5e7
VZ
886 }
887
d8b6f4d9 888 m_arrayFuncDocs.Add(new FunctionDocEntry(m_funcName, m_textFunc));
cecfc5e7 889
d8b6f4d9
VZ
890 m_funcName.clear();
891 }
892}
893
894void HelpGenVisitor::CloseClass()
895{
896 if ( m_inClass ) {
897 size_t count = m_arrayFuncDocs.GetCount();
898 if ( count ) {
899 FunctionDocEntry::classname = m_classname;
900 m_arrayFuncDocs.Sort(FunctionDocEntry::Compare);
901
902 for ( size_t n = 0; n < count; n++ ) {
903 m_file.WriteTeX(m_arrayFuncDocs[n].text);
904 }
905
906 m_arrayFuncDocs.Empty();
907 }
908
909 m_inClass = FALSE;
910 m_classname.clear();
cecfc5e7
VZ
911 }
912}
913
914void HelpGenVisitor::EndVisit()
915{
916 CloseFunction();
ed38ec7e 917
d8b6f4d9
VZ
918 CloseClass();
919
d12e3536
VZ
920 m_fileHeader.Empty();
921
d8b6f4d9
VZ
922 m_file.FlushAll();
923
5f7cf62f
VZ
924 wxLogVerbose("%s: finished generating for the current file.",
925 GetCurrentTime("%H:%M:%S"));
cecfc5e7
VZ
926}
927
928void HelpGenVisitor::VisitFile( spFile& file )
929{
d12e3536 930 m_fileHeader = file.mFileName;
5f7cf62f 931 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
d12e3536 932 GetCurrentTime("%H:%M:%S"), m_fileHeader.c_str());
cecfc5e7
VZ
933}
934
935void HelpGenVisitor::VisitClass( spClass& cl )
936{
d8b6f4d9 937 CloseClass();
d12e3536 938
cecfc5e7
VZ
939 wxString name = cl.GetName();
940
d12e3536
VZ
941 if ( m_ignoreNames.IgnoreClass(name) ) {
942 wxLogVerbose("Skipping ignored class '%s'.", name.c_str());
943
944 return;
945 }
946
cecfc5e7
VZ
947 // the file name is built from the class name by removing the leading "wx"
948 // if any and converting it to the lower case
f6bcfd97 949 wxString filename;
59734eb5
VZ
950 if ( name(0, 2) == "wx" ) {
951 filename << name.c_str() + 2;
952 }
953 else {
954 filename << name;
cecfc5e7
VZ
955 }
956
957 filename.MakeLower();
958 filename += ".tex";
f6bcfd97 959 filename.Prepend(m_directoryOut);
cecfc5e7 960
d12e3536
VZ
961 if ( !m_overwrite && wxFile::Exists(filename) ) {
962 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
5f7cf62f
VZ
963 filename.c_str());
964
5f7cf62f
VZ
965 return;
966 }
967
cecfc5e7
VZ
968 m_inClass = m_file.Open(filename, wxFile::write);
969 if ( !m_inClass ) {
970 wxLogError("Can't generate documentation for the class '%s'.",
971 name.c_str());
972
973 return;
974 }
975
976 m_inMethodSection =
5f7cf62f 977 m_inTypesSection = FALSE;
cecfc5e7
VZ
978
979 wxLogInfo("Created new file '%s' for class '%s'.",
980 filename.c_str(), name.c_str());
981
a7adaeda
VZ
982 // write out the header
983 wxString header;
984 header.Printf("%%\n"
985 "%% automatically generated by HelpGen %s from\n"
986 "%% %s at %s\n"
987 "%%\n"
988 "\n"
989 "\n"
990 "\\section{\\class{%s}}\\label{%s}\n\n",
2f919f99 991 GetVersionString().c_str(),
a7adaeda
VZ
992 m_fileHeader.c_str(),
993 GetCurrentTime("%d/%b/%y %H:%M:%S"),
994 name.c_str(),
995 wxString(name).MakeLower().c_str());
996
d8b6f4d9 997 m_file.WriteVerbatim(header);
a7adaeda 998
cecfc5e7
VZ
999 // the entire text we're writing to file
1000 wxString totalText;
1001
ed38ec7e
VZ
1002 // if the header includes other headers they must be related to it... try to
1003 // automatically generate the "See also" clause
1004 if ( !m_headers.IsEmpty() ) {
1005 // correspondence between wxWindows headers and class names
1006 static const char *headers[] = {
1007 "object",
1008 "defs",
1009 "string",
1010 "dynarray",
59734eb5 1011 "file",
ed38ec7e
VZ
1012 "time",
1013 };
1014
1015 // NULL here means not to insert anything in "See also" for the
1016 // corresponding header
1017 static const char *classes[] = {
1018 NULL,
1019 NULL,
1020 NULL,
1021 NULL,
1022 "wxFile",
1023 "wxTime",
1024 };
1025
1026 wxASSERT_MSG( WXSIZEOF(headers) == WXSIZEOF(classes),
1027 "arrays must be in sync!" );
1028
1029 wxArrayInt interestingClasses;
1030
1031 size_t count = m_headers.Count(), index;
1032 for ( size_t n = 0; n < count; n++ ) {
1033 wxString baseHeaderName = m_headers[n].Before('.');
1034 if ( baseHeaderName(0, 3) != "wx/" )
1035 continue;
1036
1037 baseHeaderName.erase(0, 3);
1038 for ( index = 0; index < WXSIZEOF(headers); index++ ) {
1039 if ( Stricmp(baseHeaderName, headers[index]) == 0 )
1040 break;
1041 }
1042
1043 if ( (index < WXSIZEOF(headers)) && classes[index] ) {
1044 // interesting header
1045 interestingClasses.Add(index);
1046 }
1047 }
1048
1049 if ( !interestingClasses.IsEmpty() ) {
1050 // do generate "See also" clause
1051 totalText << "\\wxheading{See also:}\n\n";
1052
1053 count = interestingClasses.Count();
1054 for ( index = 0; index < count; index++ ) {
1055 if ( index > 0 )
1056 totalText << ", ";
1057
1058 totalText << MakeHelpref(classes[interestingClasses[index]]);
1059 }
1060
1061 totalText << "\n\n";
1062 }
1063 }
1064
cecfc5e7
VZ
1065 // the comment before the class generally explains what is it for so put it
1066 // in place of the class description
1067 if ( cl.HasComments() ) {
ed38ec7e 1068 wxString comment = GetAllComments(cl);
cecfc5e7
VZ
1069
1070 totalText << '\n' << comment << '\n';
1071 }
1072
1073 // derived from section
1074 wxString derived = "\\wxheading{Derived from}\n\n";
1075
1076 const StrListT& baseClasses = cl.mSuperClassNames;
1077 if ( baseClasses.size() == 0 ) {
1078 derived << "No base class";
1079 }
1080 else {
5f7cf62f 1081 bool first = TRUE;
cecfc5e7
VZ
1082 for ( StrListT::const_iterator i = baseClasses.begin();
1083 i != baseClasses.end();
1084 i++ ) {
1085 if ( !first ) {
1086 // separate from the previous one
1087 derived << "\\\\\n";
1088 }
1089 else {
5f7cf62f 1090 first = FALSE;
cecfc5e7
VZ
1091 }
1092
1093 wxString baseclass = *i;
dface61c 1094 derived << "\\helpref{" << baseclass << "}";
59734eb5 1095 derived << "{" << baseclass.MakeLower() << "}";
cecfc5e7
VZ
1096 }
1097 }
1098 totalText << derived << "\n\n";
1099
1100 // write all this to file
1101 m_file.WriteTeX(totalText);
1102
1103 // if there were any enums/typedefs before, insert their documentation now
1104 InsertDataStructuresHeader();
1105 InsertTypedefDocs();
1106 InsertEnumDocs();
1107}
1108
1109void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
1110{
1111 CloseFunction();
1112
1113 if ( m_inMethodSection ) {
1114 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1115 // should be smart enough to process even the enums which come after the
1116 // functions
1117 wxLogWarning("enum '%s' ignored, please put it before the class "
1118 "methods.", en.GetName().c_str());
1119 return;
1120 }
1121
1122 // simply copy the enum text in the docs
a7adaeda
VZ
1123 wxString enumeration = GetAllComments(en),
1124 enumerationVerb;
1125
1126 enumerationVerb << "\\begin{verbatim}\n"
1127 << en.mEnumContent
1128 << "\n\\end{verbatim}\n";
cecfc5e7
VZ
1129
1130 // remember for later use if we're not inside a class yet
1131 if ( !m_inClass ) {
a7adaeda
VZ
1132 m_storedEnums.Add(enumeration);
1133 m_storedEnumsVerb.Add(enumerationVerb);
cecfc5e7
VZ
1134 }
1135 else {
1136 // write the header for this section if not done yet
1137 InsertDataStructuresHeader();
1138
cecfc5e7 1139 m_file.WriteTeX(enumeration);
a7adaeda 1140 m_file.WriteVerbatim(enumerationVerb);
d8b6f4d9 1141 m_file.WriteVerbatim('\n');
cecfc5e7
VZ
1142 }
1143}
1144
1145void HelpGenVisitor::VisitTypeDef( spTypeDef& td )
1146{
1147 CloseFunction();
1148
ed38ec7e
VZ
1149 if ( m_inMethodSection ) {
1150 // FIXME that's a bug, but tell the user aboit it nevertheless...
1151 wxLogWarning("typedef '%s' ignored, please put it before the class "
1152 "methods.", td.GetName().c_str());
1153 return;
1154 }
1155
1156 wxString typedefdoc;
1157 typedefdoc << "{\\small \\begin{verbatim}\n"
1158 << "typedef " << td.mOriginalType << ' ' << td.GetName()
1159 << "\n\\end{verbatim}}\n"
1160 << GetAllComments(td);
1161
1162 // remember for later use if we're not inside a class yet
1163 if ( !m_inClass ) {
1164 if ( !m_textStoredTypedefs.IsEmpty() ) {
1165 m_textStoredTypedefs << '\n';
1166 }
1167
1168 m_textStoredTypedefs << typedefdoc;
1169 }
1170 else {
1171 // write the header for this section if not done yet
1172 InsertDataStructuresHeader();
1173
1174 typedefdoc << '\n';
1175 m_file.WriteTeX(typedefdoc);
1176 }
1177}
1178
1179void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine& pd )
1180{
1181 switch ( pd.GetStatementType() ) {
1182 case SP_PREP_DEF_INCLUDE_FILE:
1183 m_headers.Add(pd.CPP_GetIncludedFileNeme());
1184 break;
1185
1186 case SP_PREP_DEF_DEFINE_SYMBOL:
1187 // TODO decide if it's a constant and document it if it is
1188 break;
1189 }
cecfc5e7
VZ
1190}
1191
1192void HelpGenVisitor::VisitAttribute( spAttribute& attr )
1193{
1194 CloseFunction();
1195
1196 // only document the public member variables
1197 if ( !m_inClass || !attr.IsPublic() )
1198 return;
1199
ed38ec7e 1200 wxLogWarning("Ignoring member variable '%s'.", attr.GetName().c_str());
cecfc5e7
VZ
1201}
1202
1203void HelpGenVisitor::VisitOperation( spOperation& op )
1204{
1205 CloseFunction();
1206
d12e3536
VZ
1207 if ( !m_inClass ) {
1208 // we don't generate docs right now - either we ignore this class
1209 // entirely or we couldn't open the file
1210 return;
1211 }
1212
1213 if ( !op.IsInClass() ) {
1214 // TODO document global functions
cecfc5e7
VZ
1215 wxLogWarning("skipped global function '%s'.", op.GetName().c_str());
1216
1217 return;
1218 }
1219
1220 if ( op.mVisibility == SP_VIS_PRIVATE ) {
1221 // FIXME should we document protected functions?
1222 return;
1223 }
1224
d8b6f4d9
VZ
1225 m_classname = op.GetClass().GetName();
1226 wxString funcname = op.GetName();
1227
1228 if ( m_ignoreNames.IgnoreMethod(m_classname, funcname) ) {
d12e3536 1229 wxLogVerbose("Skipping ignored '%s::%s'.",
d8b6f4d9 1230 m_classname.c_str(), funcname.c_str());
d12e3536
VZ
1231
1232 return;
1233 }
1234
cecfc5e7
VZ
1235 InsertMethodsHeader();
1236
1237 // save state info
d8b6f4d9 1238 m_funcName = funcname;
5f7cf62f 1239 m_isFirstParam = TRUE;
cecfc5e7 1240
ed38ec7e 1241 m_textStoredFunctionComment = GetAllComments(op);
cecfc5e7
VZ
1242
1243 // start function documentation
1244 wxString totalText;
59734eb5 1245
cecfc5e7
VZ
1246 // check for the special case of dtor
1247 wxString dtor;
d8b6f4d9
VZ
1248 if ( (funcname[0] == '~') && (m_classname == funcname.c_str() + 1) ) {
1249 dtor.Printf("\\destruct{%s}", m_classname.c_str());
cecfc5e7
VZ
1250 funcname = dtor;
1251 }
1252
d8b6f4d9
VZ
1253 m_textFunc.Printf("\n"
1254 "\\membersection{%s::%s}\\label{%s}\n"
1255 "\n"
1256 "\\%sfunc{%s%s}{%s}{",
1257 m_classname.c_str(), funcname.c_str(),
1258 MakeLabel(m_classname, funcname).c_str(),
1259 op.mIsConstant ? "const" : "",
1260 op.mIsVirtual ? "virtual " : "",
1261 op.mRetType.c_str(),
1262 funcname.c_str());
cecfc5e7
VZ
1263}
1264
1265void HelpGenVisitor::VisitParameter( spParameter& param )
1266{
d8b6f4d9 1267 if ( m_funcName.empty() )
cecfc5e7
VZ
1268 return;
1269
cecfc5e7 1270 if ( m_isFirstParam ) {
5f7cf62f 1271 m_isFirstParam = FALSE;
cecfc5e7
VZ
1272 }
1273 else {
d8b6f4d9 1274 m_textFunc << ", ";
cecfc5e7 1275 }
59734eb5 1276
d8b6f4d9 1277 m_textFunc << "\\param{" << param.mType << " }{" << param.GetName();
cecfc5e7
VZ
1278 wxString defvalue = param.mInitVal;
1279 if ( !defvalue.IsEmpty() ) {
d8b6f4d9 1280 m_textFunc << " = " << defvalue;
cecfc5e7 1281 }
59734eb5 1282
d8b6f4d9 1283 m_textFunc << '}';
cecfc5e7
VZ
1284}
1285
5f7cf62f
VZ
1286// ---------------------------------------------------------------------------
1287// DocManager
1288// ---------------------------------------------------------------------------
1289
d12e3536
VZ
1290DocManager::DocManager(bool checkParamNames)
1291{
1292 m_checkParamNames = checkParamNames;
1293}
1294
5f7cf62f
VZ
1295size_t DocManager::TryMatch(const char *str, const char *match)
1296{
1297 size_t lenMatch = 0;
1298 while ( str[lenMatch] == match[lenMatch] ) {
1299 lenMatch++;
1300
1301 if ( match[lenMatch] == '\0' )
1302 return lenMatch;
1303 }
1304
1305 return 0;
1306}
1307
1308bool DocManager::SkipUntil(const char **pp, char c)
1309{
1310 const char *p = *pp;
1311 while ( *p != c ) {
1312 if ( *p == '\0' )
1313 break;
1314
1315 if ( *p == '\n' )
1316 m_line++;
1317
1318 p++;
1319 }
1320
1321 *pp = p;
1322
1323 return *p == c;
1324}
1325
1326bool DocManager::SkipSpaceUntil(const char **pp, char c)
1327{
1328 const char *p = *pp;
1329 while ( *p != c ) {
1330 if ( !isspace(*p) || *p == '\0' )
1331 break;
1332
1333 if ( *p == '\n' )
1334 m_line++;
1335
1336 p++;
1337 }
1338
1339 *pp = p;
1340
1341 return *p == c;
1342}
1343
1344wxString DocManager::ExtractStringBetweenBraces(const char **pp)
1345{
1346 wxString result;
1347
1348 if ( !SkipSpaceUntil(pp, '{') ) {
1349 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1350 m_filename.c_str(), m_line);
1351
1352 }
1353 else {
1354 const char *startParam = ++*pp; // skip '{'
1355
1356 if ( !SkipUntil(pp, '}') ) {
1357 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1358 m_filename.c_str(), m_line);
1359 }
1360 else {
1361 result = wxString(startParam, (*pp)++ - startParam);
1362 }
1363 }
1364
1365 return result;
1366}
1367
1368bool DocManager::ParseTeXFile(const wxString& filename)
1369{
1370 m_filename = filename;
1371
1372 wxFile file(m_filename, wxFile::read);
1373 if ( !file.IsOpened() )
1374 return FALSE;
1375
1376 off_t len = file.Length();
1377 if ( len == wxInvalidOffset )
1378 return FALSE;
1379
1380 char *buf = new char[len + 1];
1381 buf[len] = '\0';
1382
1383 if ( file.Read(buf, len) == wxInvalidOffset ) {
1384 delete [] buf;
1385
1386 return FALSE;
1387 }
1388
1389 // reinit everything
1390 m_line = 1;
1391
1392 wxLogVerbose("%s: starting to parse doc file '%s'.",
1393 GetCurrentTime("%H:%M:%S"), m_filename.c_str());
1394
1395 // the name of the class from the last "\membersection" command: we assume
1396 // that the following "\func" or "\constfunc" always documents a method of
1397 // this class (and it should always be like that in wxWindows documentation)
1398 wxString classname;
1399
1400 for ( const char *current = buf; current - buf < len; current++ ) {
1401 // FIXME parsing is awfully inefficient
1402
1403 if ( *current == '%' ) {
1404 // comment, skip until the end of line
1405 current++;
1406 SkipUntil(&current, '\n');
1407
1408 continue;
1409 }
1410
1411 // all the command we're interested in start with '\\'
1412 while ( *current != '\\' && *current != '\0' ) {
1413 if ( *current++ == '\n' )
1414 m_line++;
1415 }
1416
1417 if ( *current == '\0' ) {
1418 // no more TeX commands left
1419 break;
1420 }
1421
1422 current++; // skip '\\'
1423
1424 enum
1425 {
1426 Nothing,
1427 Func,
1428 ConstFunc,
1429 MemberSect
1430 } foundCommand = Nothing;
1431
1432 size_t lenMatch = TryMatch(current, "func");
1433 if ( lenMatch ) {
1434 foundCommand = Func;
1435 }
1436 else {
1437 lenMatch = TryMatch(current, "constfunc");
1438 if ( lenMatch )
1439 foundCommand = ConstFunc;
1440 else {
1441 lenMatch = TryMatch(current, "membersection");
1442
1443 if ( lenMatch )
1444 foundCommand = MemberSect;
1445 }
1446 }
1447
1448 if ( foundCommand == Nothing )
1449 continue;
1450
1451 current += lenMatch;
1452
1453 if ( !SkipSpaceUntil(&current, '{') ) {
1454 wxLogWarning("file %s(%d): '{' expected after \\func, "
1455 "\\constfunc or \\membersection.",
1456 m_filename.c_str(), m_line);
1457
1458 continue;
1459 }
1460
1461 current++;
1462
1463 if ( foundCommand == MemberSect ) {
1464 // what follows has the form <classname>::<funcname>
1465 const char *startClass = current;
1466 if ( !SkipUntil(&current, ':') || *(current + 1) != ':' ) {
1467 wxLogWarning("file %s(%d): '::' expected after "
1468 "\\membersection.", m_filename.c_str(), m_line);
1469 }
1470 else {
1471 classname = wxString(startClass, current - startClass);
1472 TeXUnfilter(&classname);
1473 }
1474
1475 continue;
1476 }
1477
1478 // extract the return type
1479 const char *startRetType = current;
1480
1481 if ( !SkipUntil(&current, '}') ) {
1482 wxLogWarning("file %s(%d): '}' expected after return type",
1483 m_filename.c_str(), m_line);
1484
1485 continue;
1486 }
1487
1488 wxString returnType = wxString(startRetType, current - startRetType);
1489 TeXUnfilter(&returnType);
1490
1491 current++;
1492 if ( !SkipSpaceUntil(&current, '{') ) {
1493 wxLogWarning("file %s(%d): '{' expected after return type",
1494 m_filename.c_str(), m_line);
1495
1496 continue;
1497 }
1498
1499 current++;
1500 const char *funcEnd = current;
1501 if ( !SkipUntil(&funcEnd, '}') ) {
1502 wxLogWarning("file %s(%d): '}' expected after function name",
1503 m_filename.c_str(), m_line);
1504
1505 continue;
1506 }
1507
1508 wxString funcName = wxString(current, funcEnd - current);
1509 current = funcEnd + 1;
1510
1511 // trim spaces from both sides
1512 funcName.Trim(FALSE);
1513 funcName.Trim(TRUE);
1514
1515 // special cases: '$...$' may be used for LaTeX inline math, remove the
1516 // '$'s
1517 if ( funcName.Find('$') != wxNOT_FOUND ) {
1518 wxString name;
1519 for ( const char *p = funcName.c_str(); *p != '\0'; p++ ) {
1520 if ( *p != '$' && !isspace(*p) )
1521 name += *p;
1522 }
1523
1524 funcName = name;
1525 }
1526
1527 // \destruct{foo} is really ~foo
1528 if ( funcName[0u] == '\\' ) {
1529 size_t len = strlen("\\destruct{");
1530 if ( funcName(0, len) != "\\destruct{" ) {
1531 wxLogWarning("file %s(%d): \\destruct expected",
1532 m_filename.c_str(), m_line);
1533
1534 continue;
1535 }
1536
1537 funcName.erase(0, len);
1538 funcName.Prepend('~');
1539
1540 if ( !SkipSpaceUntil(&current, '}') ) {
1541 wxLogWarning("file %s(%d): '}' expected after destructor",
1542 m_filename.c_str(), m_line);
1543
1544 continue;
1545 }
1546
1547 funcEnd++; // there is an extra '}' to count
1548 }
1549
1550 TeXUnfilter(&funcName);
1551
1552 // extract params
1553 current = funcEnd + 1; // skip '}'
1554 if ( !SkipSpaceUntil(&current, '{') ||
1555 (current++, !SkipSpaceUntil(&current, '\\')) ) {
1556 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1557 m_filename.c_str(), m_line);
1558
1559 continue;
1560 }
1561
1562 wxArrayString paramNames, paramTypes, paramValues;
1563
1564 bool isVararg = FALSE;
1565
1566 current++; // skip '\\'
1567 lenMatch = TryMatch(current, "void");
1568 if ( !lenMatch ) {
1569 lenMatch = TryMatch(current, "param");
d12e3536 1570 while ( lenMatch && (current - buf < len) ) {
5f7cf62f
VZ
1571 current += lenMatch;
1572
1573 // now come {paramtype}{paramname}
1574 wxString paramType = ExtractStringBetweenBraces(&current);
1575 if ( !!paramType ) {
1576 wxString paramText = ExtractStringBetweenBraces(&current);
1577 if ( !!paramText ) {
1578 // the param declaration may contain default value
1579 wxString paramName = paramText.BeforeFirst('='),
1580 paramValue = paramText.AfterFirst('=');
1581
1582 // sanitize all strings
1583 TeXUnfilter(&paramValue);
1584 TeXUnfilter(&paramName);
1585 TeXUnfilter(&paramType);
1586
1587 paramValues.Add(paramValue);
1588 paramNames.Add(paramName);
1589 paramTypes.Add(paramType);
1590 }
1591 }
1592 else {
1593 // vararg function?
1594 wxString paramText = ExtractStringBetweenBraces(&current);
1595 if ( paramText == "..." ) {
1596 isVararg = TRUE;
1597 }
1598 else {
1599 wxLogWarning("Parameters of '%s::%s' are in "
1600 "incorrect form.",
1601 classname.c_str(), funcName.c_str());
1602 }
1603 }
1604
1605 // what's next?
1606 current = SkipSpaces(current);
1607 if ( *current == ',' || *current == '}' ) {
1608 current = SkipSpaces(++current);
1609
1610 lenMatch = TryMatch(current, "\\param");
1611 }
1612 else {
1613 wxLogWarning("file %s(%d): ',' or '}' expected after "
1614 "'\\param'", m_filename.c_str(), m_line);
1615
1616 continue;
1617 }
1618 }
1619
1620 // if we got here there was no '\\void', so must have some params
1621 if ( paramNames.IsEmpty() ) {
1622 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1623 m_filename.c_str(), m_line);
1624
1625 continue;
1626 }
1627 }
1628
1629 // verbose diagnostic output
1630 wxString paramsAll;
1631 size_t param, paramCount = paramNames.GetCount();
1632 for ( param = 0; param < paramCount; param++ ) {
1633 if ( param != 0 ) {
1634 paramsAll << ", ";
1635 }
1636
1637 paramsAll << paramTypes[param] << ' ' << paramNames[param];
1638 }
1639
1640 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1641 m_filename.c_str(), m_line,
1642 returnType.c_str(),
1643 classname.c_str(),
1644 funcName.c_str(),
1645 paramsAll.c_str(),
1646 foundCommand == ConstFunc ? " const" : "");
1647
1648 // store the info about the just found function
1649 ArrayMethodInfo *methods;
1650 int index = m_classes.Index(classname);
1651 if ( index == wxNOT_FOUND ) {
1652 m_classes.Add(classname);
1653
1654 methods = new ArrayMethodInfo;
1655 m_methods.Add(methods);
1656 }
1657 else {
1658 methods = m_methods[(size_t)index];
1659 }
1660
1661 ArrayParamInfo params;
1662 for ( param = 0; param < paramCount; param++ ) {
1663 params.Add(new ParamInfo(paramTypes[param],
1664 paramNames[param],
1665 paramValues[param]));
1666 }
1667
1668 MethodInfo *method = new MethodInfo(returnType, funcName, params);
1669 if ( foundCommand == ConstFunc )
1670 method->SetFlag(MethodInfo::Const);
1671 if ( isVararg )
1672 method->SetFlag(MethodInfo::Vararg);
1673
1674 methods->Add(method);
1675 }
1676
1677 delete [] buf;
1678
1679 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1680 GetCurrentTime("%H:%M:%S"), m_filename.c_str());
1681
1682 return TRUE;
1683}
1684
1685bool DocManager::DumpDifferences(spContext *ctxTop) const
1686{
1687 typedef MMemberListT::const_iterator MemberIndex;
1688
1689 bool foundDiff = FALSE;
1690
1691 // flag telling us whether the given class was found at all in the header
1692 size_t nClass, countClassesInDocs = m_classes.GetCount();
1693 bool *classExists = new bool[countClassesInDocs];
1694 for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
1695 classExists[nClass] = FALSE;
1696 }
1697
1698 // ctxTop is normally an spFile
1699 wxASSERT( ctxTop->GetContextType() == SP_CTX_FILE );
1700
1701 const MMemberListT& classes = ctxTop->GetMembers();
1702 for ( MemberIndex i = classes.begin(); i != classes.end(); i++ ) {
1703 spContext *ctx = *i;
1704 if ( ctx->GetContextType() != SP_CTX_CLASS ) {
1705 // TODO process also global functions, macros, ...
1706 continue;
1707 }
1708
1709 spClass *ctxClass = (spClass *)ctx;
1710 const wxString& nameClass = ctxClass->mName;
1711 int index = m_classes.Index(nameClass);
1712 if ( index == wxNOT_FOUND ) {
d12e3536 1713 if ( !m_ignoreNames.IgnoreClass(nameClass) ) {
5f7cf62f
VZ
1714 foundDiff = TRUE;
1715
1716 wxLogError("Class '%s' is not documented at all.",
1717 nameClass.c_str());
1718 }
1719
1720 // it makes no sense to check for its functions
1721 continue;
1722 }
1723 else {
1724 classExists[index] = TRUE;
1725 }
1726
1727 // array of method descriptions for this class
1728 const ArrayMethodInfo& methods = *(m_methods[index]);
1729 size_t nMethod, countMethods = methods.GetCount();
1730
1731 // flags telling if we already processed given function
1732 bool *methodExists = new bool[countMethods];
1733 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1734 methodExists[nMethod] = FALSE;
1735 }
1736
1737 wxArrayString aOverloadedMethods;
1738
1739 const MMemberListT& functions = ctxClass->GetMembers();
1740 for ( MemberIndex j = functions.begin(); j != functions.end(); j++ ) {
1741 ctx = *j;
1742 if ( ctx->GetContextType() != SP_CTX_OPERATION )
1743 continue;
1744
1745 spOperation *ctxMethod = (spOperation *)ctx;
1746 const wxString& nameMethod = ctxMethod->mName;
1747
1748 // find all functions with the same name
1749 wxArrayInt aMethodsWithSameName;
1750 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1751 if ( methods[nMethod]->GetName() == nameMethod )
1752 aMethodsWithSameName.Add(nMethod);
1753 }
1754
1755 if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
d12e3536 1756 if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
5f7cf62f
VZ
1757 foundDiff = TRUE;
1758
1759 wxLogError("'%s::%s' is not documented.",
1760 nameClass.c_str(),
1761 nameMethod.c_str());
1762 }
1763
1764 // don't check params
1765 continue;
1766 }
1767 else if ( aMethodsWithSameName.GetCount() == 1 ) {
1768 index = (size_t)aMethodsWithSameName[0u];
1769 methodExists[index] = TRUE;
1770
d12e3536 1771 if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
5f7cf62f
VZ
1772 continue;
1773
1774 if ( !ctxMethod->IsPublic() ) {
1775 wxLogWarning("'%s::%s' is documented but not public.",
1776 nameClass.c_str(),
1777 nameMethod.c_str());
1778 }
1779
1780 // check that the flags match
1781 const MethodInfo& method = *(methods[index]);
1782
1783 bool isVirtual = ctxMethod->mIsVirtual;
1784 if ( isVirtual != method.HasFlag(MethodInfo::Virtual) ) {
1785 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1786 "virtual.",
1787 nameClass.c_str(),
1788 nameMethod.c_str(),
1789 isVirtual ? "not " : "");
1790 }
1791
1792 bool isConst = ctxMethod->mIsConstant;
1793 if ( isConst != method.HasFlag(MethodInfo::Const) ) {
1794 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1795 "constant.",
1796 nameClass.c_str(),
1797 nameMethod.c_str(),
1798 isConst ? "not " : "");
1799 }
1800
1801 // check that the params match
1802 const MMemberListT& params = ctxMethod->GetMembers();
1803
1804 if ( params.size() != method.GetParamCount() ) {
1805 wxLogError("Incorrect number of parameters for '%s::%s' "
1806 "in the docs: should be %d instead of %d.",
1807 nameClass.c_str(),
1808 nameMethod.c_str(),
1809 params.size(), method.GetParamCount());
1810 }
1811 else {
1812 size_t nParam = 0;
1813 for ( MemberIndex k = params.begin();
1814 k != params.end();
1815 k++, nParam++ ) {
1816 ctx = *k;
1817
1818 // what else can a function have?
1819 wxASSERT( ctx->GetContextType() == SP_CTX_PARAMETER );
1820
1821 spParameter *ctxParam = (spParameter *)ctx;
1822 const ParamInfo& param = method.GetParam(nParam);
d12e3536
VZ
1823 if ( m_checkParamNames &&
1824 (param.GetName() != ctxParam->mName) ) {
5f7cf62f
VZ
1825 foundDiff = TRUE;
1826
1827 wxLogError("Parameter #%d of '%s::%s' should be "
1828 "'%s' and not '%s'.",
1829 nParam + 1,
1830 nameClass.c_str(),
1831 nameMethod.c_str(),
1832 ctxParam->mName.c_str(),
1833 param.GetName().c_str());
1834
1835 continue;
1836 }
1837
1838 if ( param.GetType() != ctxParam->mType ) {
1839 foundDiff = TRUE;
1840
1841 wxLogError("Type of parameter '%s' of '%s::%s' "
1842 "should be '%s' and not '%s'.",
1843 ctxParam->mName.c_str(),
1844 nameClass.c_str(),
1845 nameMethod.c_str(),
1846 ctxParam->mType.c_str(),
1847 param.GetType().GetName().c_str());
1848
1849 continue;
1850 }
1851
1852 if ( param.GetDefValue() != ctxParam->mInitVal ) {
1853 wxLogWarning("Default value of parameter '%s' of "
1854 "'%s::%s' should be '%s' and not "
1855 "'%s'.",
1856 ctxParam->mName.c_str(),
1857 nameClass.c_str(),
1858 nameMethod.c_str(),
1859 ctxParam->mInitVal.c_str(),
1860 param.GetDefValue().c_str());
1861 }
1862 }
1863 }
1864 }
1865 else {
d12e3536 1866 // TODO OVER add real support for overloaded methods
5f7cf62f 1867
d12e3536 1868 if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
5f7cf62f
VZ
1869 continue;
1870
1871 if ( aOverloadedMethods.Index(nameMethod) == wxNOT_FOUND ) {
1872 // mark all methods with this name as existing
1873 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1874 if ( methods[nMethod]->GetName() == nameMethod )
1875 methodExists[nMethod] = TRUE;
1876 }
1877
1878 aOverloadedMethods.Add(nameMethod);
1879
1880 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1881 "stupid to find the right match - skipping "
1882 "the param and flags checks.",
1883 nameClass.c_str(),
1884 nameMethod.c_str());
1885 }
1886 //else: warning already given
1887 }
1888 }
1889
1890 for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
1891 if ( !methodExists[nMethod] ) {
1892 const wxString& nameMethod = methods[nMethod]->GetName();
d12e3536 1893 if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
5f7cf62f
VZ
1894 foundDiff = TRUE;
1895
1896 wxLogError("'%s::%s' is documented but doesn't exist.",
1897 nameClass.c_str(),
1898 nameMethod.c_str());
1899 }
1900 }
1901 }
1902
1903 delete [] methodExists;
1904 }
1905
1906 // check that all classes we found in the docs really exist
1907 for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
1908 if ( !classExists[nClass] ) {
1909 foundDiff = TRUE;
1910
1911 wxLogError("Class '%s' is documented but doesn't exist.",
1912 m_classes[nClass].c_str());
1913 }
1914 }
1915
1916 delete [] classExists;
1917
1918 return !foundDiff;
1919}
1920
1921DocManager::~DocManager()
1922{
1923 WX_CLEAR_ARRAY(m_methods);
5f7cf62f
VZ
1924}
1925
d12e3536
VZ
1926// ---------------------------------------------------------------------------
1927// IgnoreNamesHandler implementation
1928// ---------------------------------------------------------------------------
1929
1930int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first,
1931 IgnoreListEntry *second)
5f7cf62f
VZ
1932{
1933 // first compare the classes
1934 int rc = first->m_classname.Cmp(second->m_classname);
1935 if ( rc == 0 )
1936 rc = first->m_funcname.Cmp(second->m_funcname);
1937
1938 return rc;
1939}
1940
d12e3536 1941bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
5f7cf62f
VZ
1942{
1943 wxFile file(filename, wxFile::read);
1944 if ( !file.IsOpened() )
1945 return FALSE;
1946
1947 off_t len = file.Length();
1948 if ( len == wxInvalidOffset )
1949 return FALSE;
1950
1951 char *buf = new char[len + 1];
1952 buf[len] = '\0';
1953
1954 if ( file.Read(buf, len) == wxInvalidOffset ) {
1955 delete [] buf;
1956
1957 return FALSE;
1958 }
1959
1960 wxString line;
1961 for ( const char *current = buf; ; current++ ) {
1962#ifdef __WXMSW__
1963 // skip DOS line separator
1964 if ( *current == '\r' )
1965 current++;
1966#endif // wxMSW
1967
1968 if ( *current == '\n' || *current == '\0' ) {
1969 if ( line[0u] != '#' ) {
1970 if ( line.Find(':') != wxNOT_FOUND ) {
1971 wxString classname = line.BeforeFirst(':'),
1972 funcname = line.AfterLast(':');
1973 m_ignore.Add(new IgnoreListEntry(classname, funcname));
1974 }
1975 else {
1976 // entire class
1977 m_ignore.Add(new IgnoreListEntry(line, ""));
1978 }
1979 }
1980 //else: comment
1981
1982 if ( *current == '\0' )
1983 break;
1984
1985 line.Empty();
1986 }
1987 else {
1988 line += *current;
1989 }
1990 }
1991
1992 delete [] buf;
1993
1994 return TRUE;
1995}
1996
cecfc5e7
VZ
1997// -----------------------------------------------------------------------------
1998// global function implementation
1999// -----------------------------------------------------------------------------
2000
2001static wxString MakeLabel(const char *classname, const char *funcname)
2002{
2003 wxString label(classname);
ed38ec7e 2004 if ( funcname && funcname[0] == '\\' ) {
cecfc5e7
VZ
2005 // we may have some special TeX macro - so far only \destruct exists,
2006 // but may be later others will be added
2007 static const char *macros[] = { "destruct" };
2008 static const char *replacement[] = { "dtor" };
59734eb5 2009
cecfc5e7
VZ
2010 size_t n;
2011 for ( n = 0; n < WXSIZEOF(macros); n++ ) {
2012 if ( strncmp(funcname + 1, macros[n], strlen(macros[n])) == 0 ) {
2013 // found
2014 break;
2015 }
2016 }
2017
2018 if ( n == WXSIZEOF(macros) ) {
2019 wxLogWarning("unknown function name '%s' - leaving as is.",
2020 funcname);
2021 }
2022 else {
2023 funcname = replacement[n];
2024 }
2025 }
2026
d8b6f4d9
VZ
2027 if ( funcname ) {
2028 // special treatment for operatorXXX() stuff because the C operators
2029 // are not valid in LaTeX labels
2030 wxString oper;
2031 if ( wxString(funcname).StartsWith("operator", &oper) ) {
2032 label << "operator";
2033
2034 static const struct
2035 {
2036 const char *oper;
2037 const char *name;
2038 } operatorNames[] =
2039 {
2040 { "=", "assign" },
2041 { "==", "equal" },
2042 };
2043
2044 size_t n;
2045 for ( n = 0; n < WXSIZEOF(operatorNames); n++ ) {
2046 if ( oper == operatorNames[n].oper ) {
2047 label << operatorNames[n].name;
2048
2049 break;
2050 }
2051 }
2052
2053 if ( n == WXSIZEOF(operatorNames) ) {
2054 wxLogWarning("unknown operator '%s' - making dummy label.",
2055 oper.c_str());
2056
2057 label << "unknown";
2058 }
2059 }
2060 else // simply use the func name
2061 {
2062 label << funcname;
2063 }
2064 }
cecfc5e7
VZ
2065
2066 label.MakeLower();
2067
2068 return label;
2069}
2070
ed38ec7e
VZ
2071static wxString MakeHelpref(const char *argument)
2072{
2073 wxString helpref;
2074 helpref << "\\helpref{" << argument << "}{" << MakeLabel(argument) << '}';
2075
2076 return helpref;
2077}
2078
a7adaeda
VZ
2079static void TeXFilter(wxString* str)
2080{
2081 // TeX special which can be quoted (don't include backslash nor braces as
2082 // we generate them
2083 static wxRegEx reNonSpecialSpecials("[#$%&_]"),
2084 reAccents("[~^]");
2085
2086 // just quote
2087 reNonSpecialSpecials.ReplaceAll(str, "\\\\\\0");
2088
2089 // can't quote these ones as they produce accents when preceded by
2090 // backslash, so put them inside verb
2091 reAccents.ReplaceAll(str, "\\\\verb|\\0|");
2092}
2093
5f7cf62f
VZ
2094static void TeXUnfilter(wxString* str)
2095{
2096 // FIXME may be done much more quickly
2097 str->Trim(TRUE);
2098 str->Trim(FALSE);
2099
a7adaeda
VZ
2100 // undo TeXFilter
2101 static wxRegEx reNonSpecialSpecials("\\\\([#$%&_{}])"),
2102 reAccents("\\\\verb|([~^])|");
5f7cf62f 2103
a7adaeda
VZ
2104 reNonSpecialSpecials.ReplaceAll(str, "\\1");
2105 reAccents.ReplaceAll(str, "\\1");
cecfc5e7
VZ
2106}
2107
ed38ec7e
VZ
2108static wxString GetAllComments(const spContext& ctx)
2109{
59734eb5
VZ
2110 wxString comments;
2111 const MCommentListT& commentsList = ctx.GetCommentList();
2112 for ( MCommentListT::const_iterator i = commentsList.begin();
2113 i != commentsList.end();
2114 i++ ) {
2115 wxString comment = (*i)->GetText();
2116
2117 // don't take comments like "// ----------" &c
2118 comment.Trim(FALSE);
2119 if ( !!comment &&
2120 comment == wxString(comment[0u], comment.length() - 1) + '\n' )
2121 comments << "\n";
2122 else
2123 comments << comment;
ed38ec7e
VZ
2124 }
2125
59734eb5 2126 return comments;
ed38ec7e
VZ
2127}
2128
2129static const char *GetCurrentTime(const char *timeFormat)
2130{
2131 static char s_timeBuffer[128];
2132 time_t timeNow;
2133 struct tm *ptmNow;
2134
2135 time(&timeNow);
2136 ptmNow = localtime(&timeNow);
2137
2138 strftime(s_timeBuffer, WXSIZEOF(s_timeBuffer), timeFormat, ptmNow);
2139
2140 return s_timeBuffer;
2141}
2142
2f919f99
VZ
2143static const wxString GetVersionString()
2144{
2145 wxString version = "$Revision$";
2146 wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1");
2147 return version;
2148}
2149
5f7cf62f
VZ
2150/*
2151 $Log$
31dc7e49
JS
2152 Revision 1.18 2002/01/03 12:02:47 JS
2153 Added main() and corrected VC++ project settings
2154
d8b6f4d9
VZ
2155 Revision 1.17 2001/11/30 21:43:35 VZ
2156 now the methods are sorted in the correct order in the generated docs
2157
a3b72ffb
VZ
2158 Revision 1.16 2001/11/28 19:27:33 VZ
2159 HelpGen doesn't work in GUI mode
2160
5aa5c1e4
GD
2161 Revision 1.15 2001/11/22 21:59:58 GD
2162 use "..." instead of <...> for wx headers
2163
2f919f99
VZ
2164 Revision 1.14 2001/07/19 13:51:29 VZ
2165 fixes to version string
2166
a7adaeda
VZ
2167 Revision 1.13 2001/07/19 13:44:57 VZ
2168 1. compilation fixes
2169 2. don't quote special characters inside verbatim environment
2170
4e28924c 2171 Revision 1.12 2000/10/09 13:53:33 juliansmart
a7adaeda 2172
4e28924c
JS
2173 Doc corrections; added HelpGen project files
2174
f6bcfd97
BP
2175 Revision 1.11 2000/07/15 19:50:42 cvsuser
2176 merged 2.2 branch
2177
2178 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2179 don't trasnform output dir name to lower case
2180
de528224
VS
2181 Revision 1.10 2000/03/11 10:05:23 VS
2182 now compiles with wxBase
2183
b136d1fe
VS
2184 Revision 1.9 2000/01/16 13:25:21 VS
2185 compilation fixes (gcc)
2186
28468136 2187 Revision 1.8 1999/09/13 14:29:39 JS
b136d1fe 2188
28468136
JS
2189 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2190 into src for simplicity; added VC++ 5 project file
2191
d12e3536
VZ
2192 Revision 1.7 1999/02/21 22:32:32 VZ
2193 1. more C++ parser fixes - now it almost parses wx/string.h
2194 a) #if/#ifdef/#else (very) limited support
2195 b) param type fix - now indirection chars are correctly handled
2196 c) class/struct/union distinction
2197 d) public/private fixes
2198 e) Dump() function added - very useful for debugging
2199
2200 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2201 by default, and this option switches it on)
2202
5f7cf62f
VZ
2203 Revision 1.6 1999/02/20 23:00:26 VZ
2204 1. new 'diff' mode which seems to work
2205 2. output files are not overwritten in 'dmup' mode
2206 3. fixes for better handling of const functions and operators
d12e3536
VZ
2207 ----------------------------
2208 revision 1.5
2209 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2210 1. Parser improvements
2211 a) const and virtual methods are parsed correctly (not static yet)
2212 b) "const" which is part of the return type is not swallowed
2213
2214 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2215 "//---------" kind comments discarded now.
2216 ----------------------------
2217 revision 1.4
2218 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2219
2220 some tweaks to HelpGen
2221 ----------------------------
2222 revision 1.3
2223 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2224
2225 HelpGen starting to compile with VC++
2226 ----------------------------
2227 revision 1.2
2228 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2229
2230 supports typedefs, generates "See also:" and adds "virtual " for virtual
2231 functions
2232 ----------------------------
2233 revision 1.1
2234 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2235
2236 HelpGen is a prototype of the tool for automatic generation of the .tex files
2237 for wxWindows documentation from C++ headers
5f7cf62f
VZ
2238*/
2239
cecfc5e7 2240/* vi: set tw=80 et ts=4 sw=4: */