diff options
author | Dimitri van Heesch <dimitri@stack.nl> | 2001-07-15 17:11:26 (GMT) |
---|---|---|
committer | Dimitri van Heesch <dimitri@stack.nl> | 2001-07-15 17:11:26 (GMT) |
commit | 89f2a610a5ca245dcc19dc7e95b49ff664c3b66a (patch) | |
tree | bc5400211360251f121d60efdd50b09f10db11d2 | |
parent | d5150cf4f1de010ad62f6de641532805ba81940a (diff) | |
download | Doxygen-89f2a610a5ca245dcc19dc7e95b49ff664c3b66a.zip Doxygen-89f2a610a5ca245dcc19dc7e95b49ff664c3b66a.tar.gz Doxygen-89f2a610a5ca245dcc19dc7e95b49ff664c3b66a.tar.bz2 |
Release-1.2.8-20010715
57 files changed, 2211 insertions, 550 deletions
@@ -1,6 +1,6 @@ -DOXYGEN Version 1.2.8-20010617 +DOXYGEN Version 1.2.8-20010715 Please read the installation section of the manual for instructions. -------- -Dimitri van Heesch (17 June 2001) +Dimitri van Heesch (15 July 2001) @@ -1,4 +1,4 @@ -DOXYGEN Version 1.2.8_20010617 +DOXYGEN Version 1.2.8_20010715 Please read INSTALL for compilation instructions. @@ -17,4 +17,4 @@ to subscribe to the lists or to visit the archives. Enjoy, -Dimitri van Heesch (dimitri@stack.nl) (17 June 2001) +Dimitri van Heesch (dimitri@stack.nl) (15 July 2001) @@ -1 +1 @@ -1.2.8-20010617 +1.2.8-20010715 diff --git a/addon/doxywizard/doxywizard.pro.in b/addon/doxywizard/doxywizard.pro.in index 53847c2..3e96901 100644 --- a/addon/doxywizard/doxywizard.pro.in +++ b/addon/doxywizard/doxywizard.pro.in @@ -50,4 +50,6 @@ MOC_DIR = moc # extra C++ compiler options TMAKE_CXXFLAGS += -DDOXYWIZARD +win32:TMAKE_CXXFLAGS += -I. -DQT_DLL +win32:TMAKE_LIBS = $(QTDIR)\lib\qtmain.lib $(QTDIR)\lib\qt-mt230nc.lib user32.lib gdi32.lib comdlg32.lib imm32.lib ole32.lib uuid.lib wsock32.lib diff --git a/doc/config.doc b/doc/config.doc index 8a4a2f3..bf5bac2 100644 --- a/doc/config.doc +++ b/doc/config.doc @@ -18,13 +18,12 @@ \subsection config_format Format -A configuration file is a free-form ASCII text file with a structure that -is similar to that of a Makefile. It is parsed by \c doxygen. -The file may contain tabs and newlines for formatting purposes. -The statements in the file are case-sensitive. +A configuration file is a free-form ASCII text file with a structure +that is similar to that of a Makefile, default name \c Doxyfile. It is +parsed by \c doxygen. The file may contain tabs and newlines for +formatting purposes. The statements in the file are case-sensitive. Comments may be placed anywhere within the file (except within quotes). -Comments begin with the \# character and end at the end of the -line. +Comments begin with the \# character and end at the end of the line. The file essentially consists of a list of assignment statements. Each statement consists of a \c TAG_NAME written in capitals, @@ -905,9 +904,17 @@ EXTRA_PACKAGES = times If the \c PDF_HYPERLINKS tag is set to \c YES, the \f$\mbox{\LaTeX}\f$ that is generated is prepared for conversion to PDF (using ps2pdf). The PDF file will - contain links (just like the HTML output) instead of page references + contain links (just like the HTML output) instead of page references. This makes the output suitable for online browsing using a PDF viewer. +\anchor cfg_latex_pdflatex +<dt>\c USE_PDFLATEX <dd> + \addindex LATEX_PDFLATEX + + If the \c LATEX_PDFLATEX tag is set to \c YES, doxygen will use + pdflatex to generate the PDF file directly from the \f$\mbox{\LaTeX}\f$ + files. + \anchor cfg_latex_batchmode <dt>\c LATEX_BATCHMODE <dd> \addindex LATEX_BATCHMODE @@ -1000,7 +1007,7 @@ EXTRA_PACKAGES = times \anchor cfg_man_links <dt>\c MAN_LINKS <dd> - \addindex MAN_LINKS + \addindex MAN_LINKs If the \c MAN_LINKS tag is set to \c YES and doxygen generates man output, then it will generate one additional man file for each entity documented in the real man page(s). These additional files only source the real man page, @@ -1054,7 +1061,7 @@ EXTRA_PACKAGES = times are defined before the preprocessor is started (similar to the -D option of gcc). The argument of the tag is a list of macros of the form: <code>name</code> or <code>name=definition</code> (no spaces). - If the definition and the = are omitted =1 is assumed. + If the definition and the "=" are omitted, "=1" is assumed. \anchor cfg_expand_as_defined <dt>\c EXPAND_AS_DEFINED <dd> @@ -1125,7 +1132,7 @@ TAGFILES = file1=loc1 "file2 = loc2" ... </pre> \addindex HAVE_DOT If you set the \c HAVE_DOT tag to \c YES then doxygen will assume the dot tool is available from the path. This tool is part of - <a href="http://www.research.att.com/sw/tools/graphviz/">Graphviz</a>, a graph + <a href="http://www.graphviz.org/">Graphviz</a>, a graph visualization toolkit from AT&T and Lucent Bell Labs. The other options in this section have no effect if this option is set to \c NO (the default) @@ -1198,6 +1205,12 @@ TAGFILES = file1=loc1 "file2 = loc2" ... </pre> generate a legend page explaining the meaning of the various boxes and arrows in the dot generated graphs. +\anchor cfg_dot_cleanup +<dt>\c DOT_CLEANUP <dd> + \addindex DOT_CLEANUP + This tag can be used to ?? cleanup any mess DOT left behind? + If left blank, "NO" is assumed. + </dl> \subsection config_search Search engine options \anchor cfg_searchengine @@ -1333,7 +1346,7 @@ INCLUDE_PATH = $(QTDIR)/include RECURSIVE = YES \endverbatim -For the Qt-2.1 sources I recommand to use the following settings: +For the Qt-2.1 sources I recommend to use the following settings: \verbatim PROJECT_NAME = Qt PROJECT_NUMBER = 2.1 diff --git a/doc/diagrams.doc b/doc/diagrams.doc index a89b878..d283ed2 100644 --- a/doc/diagrams.doc +++ b/doc/diagrams.doc @@ -16,13 +16,13 @@ */ /*! \page diagrams Graphs and diagrams - Doxygen has build-in support to generate inheritance diagrams for C++ + Doxygen has built-in support to generate inheritance diagrams for C++ classes. Doxygen can use the "dot" tool from graphviz 1.5 to generate more advanced diagrams & graphs. Graphviz is an open-sourced, cross-platform graph drawing toolkit from AT&T and Lucent Bell Labs and - can be found at http://www.research.att.com/sw/tools/graphviz/ + can be found at http://www.graphviz.org/ If you have the "dot" tool available in the path, you can set \ref cfg_have_dot "HAVE_DOT" to \c YES in the configuration file to @@ -39,7 +39,7 @@ <li>if \ref cfg_class_graph "CLASS_GRAPH" is set to \c YES, a graph will be generated for each documented class showing the direct and indirect inheritance relations. This disables the - generation of the build-in class inheritance diagrams. + generation of the built-in class inheritance diagrams. <li>if \ref cfg_include_graph "INCLUDE_GRAPH" is set to \c YES, an include dependency graph is generated for each documented file that includes at least one other file. This feature is currently supported for HTML and RTF diff --git a/doc/faq.doc b/doc/faq.doc index f20dfc0..4fb9a63 100644 --- a/doc/faq.doc +++ b/doc/faq.doc @@ -197,6 +197,22 @@ converted it into an empty file (with >16K of newlines). Another case where this might happen is if you have lines in your code with more than 16K characters. +<li><b>How did doxygen get it's name?</b> + +Doxygen got its name from playing with the words +documentation and generator. + +\verbatim +documentation -> docs -> dox +generator -> gen +\endverbatim + +At the time I was looking into lex and yacc, where a lot of things start with +"yy", so the "y" slipped in and made things pronouncable. + +I realized later that doxygen could also be read as Dimitri's oxygen, +which could be seen as something I need to live :-) + </ol> \htmlonly diff --git a/doc/install.doc b/doc/install.doc index 2d0de5f..557df69 100644 --- a/doc/install.doc +++ b/doc/install.doc @@ -18,8 +18,8 @@ \addindex installation First go to the -<a href="http://www.stack.nl/~dimitri/doxygen/download.html">download</a> page -\latexonly({\tt http://www.stack.nl/$\sim$dimitri/doxygen/download.html})\endlatexonly +<a href="http://www.doxygen.org/download.html">download</a> page +\latexonly({\tt http://www.doxygen.org/download.html})\endlatexonly to get the latest distribution, if you did not have it already. This section is divided into the following subsections: @@ -37,14 +37,14 @@ This section is divided into the following subsections: If you downloaded the source distribution, you need at least the following to build the executable: <ul> -<li>The <a href="ftp://prep.ai.mit.edu/pub/gnu">GNU</a> tools +<li>The <a href="ftp://prep.ai.mit.edu/pub/gnu/">GNU</a> tools flex, bison and make \addindex flex \addindex bison \addindex make <li>In order to generate a Makefile for your platform, you need - <a href="http://www.perl.com>perl</a> - \latexonly(see {\tt http://www.perl.com})\endlatexonly. + <a href="http://www.perl.com/>perl</a> + \latexonly(see {\tt http://www.perl.com/})\endlatexonly. \addindex perl </ul> @@ -58,10 +58,12 @@ tools should be installed. \addindex Qt This is needed to build the GUI front-end. <li>A \f$\mbox{\LaTeX}\f$ distribution: for instance - <a href="http://www.tug.org">teTeX 1.0</a>.<br> + <a href="http://www.tug.org/">teTeX 1.0</a>.<br> + \latexonly(see {\tt http://www.tug.org/})\endlatexonly. This is needed for generating LaTeX, Postscript, and PDF output. -<li><a href="http://www.research.att.com/sw/tools/graphviz/"> +<li><a href="http://www.graphviz.org/"> the Graph visualization toolkit version 1.5</a><br> + \latexonly(see {\tt http://www.graphviz.org/})\endlatexonly. Needed for the include dependency graphs, the graphical inheritance graphs, and the collaboration graphs. <li>The ghostscript interpreter. @@ -231,7 +233,7 @@ If you are compiling for HP-UX with aCC and you get this error: \endverbatim If that does not help, try removing <code>ce_parse.cpp</code> and let - bison rebuilt it (this worked for me). + bison rebuild it (this worked for me). If you are compiling for Digital Unix, the same problem can be solved (according to Barnard Schmallhof) by replacing the following in @@ -239,7 +241,8 @@ ce_parse.cpp: \verbatim #else /* not GNU C. */ - #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) + #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) \ + || defined (__sparc) || defined (__sgi) #include <alloca.h> \endverbatim @@ -247,7 +250,8 @@ ce_parse.cpp: \verbatim #else /* not GNU C. */ - #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || defined (__osf__) + #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) \ + || defined (__sparc) || defined (__sgi) || defined (__osf__) #include <alloca.h> \endverbatim @@ -261,8 +265,10 @@ ce_parse.cpp: #ifdef __GNUC__ #define alloca __builtin_alloca #else /* not GNU C. */ --#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) -+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || defined (__alpha) +-#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) \ + || defined (__sparc) || defined (__sgi) ++#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) \ + || defined (__sparc) || defined (__sgi) || defined (__alpha) #include <alloca.h> #else /* not sparc */ #if defined (MSDOS) && !defined (__TURBOC__) @@ -283,8 +289,10 @@ Compiling the \c doxygen binary went ok, but while linking <code>doxytag</code> lot of link errors, like these: \verbatim -QList<PageInfo>::__vtbl /home/dimitri/doxygen/objects/SunWS_cache/CC_obj_6/6c3eO4IogMT2vrlGCQUQ.o -[Hint: try checking whether the first non-inlined, non-pure virtual function of class QList<PageInfo> is defined] +QList<PageInfo>::__vtbl /home/dimitri/doxygen/ +objects/SunWS_cache/CC_obj_6/6c3eO4IogMT2vrlGCQUQ.o +[Hint: try checking whether the first non-inlined, non-pure +virtual function of class QList<PageInfo> is defined] \endverbatim These are generated because the compiler is confused about the object sharing @@ -326,6 +334,11 @@ the compiler will fail to compile some of the translator_xx.h files. A workaround, if you are planning to use the English translation only, is to configure doxygen with the <code>--english-only</code> option. +On some platforms (such as OpenBSD) using some versions of gcc with +-O2 can lead to eating all memory during the compilation of files +such as config.cpp. As a workaround use --debug as a configure option +or omit the -O2 for the particular files in the Makefile. + \subsection install_src_windows Compiling from source on Windows Currently, I have only compiled doxygen for Windows using Microsoft's @@ -353,7 +366,7 @@ Here is what is required: variables (if you did not select to do this automatically during installation). - Borland C++ or MINGW (see http://www.mingw.org) are also supported. + Borland C++ or MINGW (see http://www.mingw.org/) are also supported. <li>Perl 5.0 or higher for Windows. This can be downloaded from: http://www.ActiveState.com/Products/ActivePerl/ @@ -439,7 +452,7 @@ Here is what is required: <code>objects</code> and <code>bin</code> manually in the root of the distribution before compiling. -<li><a href="http://www.research.att.com/sw/tools/graphviz/"> +<li><a href="http://www.graphviz.org/"> the Graph visualization toolkit version 1.5</a><br> Needed for the include dependency graphs, the graphical inheritance graphs, and the collaboration graphs. diff --git a/doc/language.doc b/doc/language.doc index 2ddb450..d97ed69 100644 --- a/doc/language.doc +++ b/doc/language.doc @@ -21,9 +21,9 @@ <h3>Support for multiple languages</h3> -Doxygen has support for multiple languages. This means -that the text fragments that doxygen generates can changed into languages -other than English (the default) at configuration time. +Doxygen has built-in support for multiple languages. This means +that the text fragments that doxygen generates can be produced in +languages other than English (the default) at configuration time. <p> Currently (version unknown), 23 languages are supported (sorted alphabetically): @@ -34,7 +34,7 @@ Polish, Portuguese, Romanian, Russian, Slovak, Slovene, Spanish, and Swedish. The table of information related to the supported languages follows. -It is sorted by language alphabetically. The <B>Status</B> column +It is sorted by language alphabetically. The <b>Status</b> column was generated from sources and shows approximately the last version when the translator was updated. <p> @@ -103,7 +103,7 @@ when the translator was updated. <TD>French</TD> <TD>Xavier Outhier</TD> <TD>xavier.outhier@NOSPAM.anfdata.cz</TD> - <TD>1.2.0</TD> + <TD>up-to-date</TD> </TR> <TR BGCOLOR="#ffffff"> <TD>German</TD> @@ -167,7 +167,7 @@ when the translator was updated. </TR> <TR BGCOLOR="#ffffff"> <TD>Slovak</TD> - <TD>Stanislav Kudlac</TD> + <TD>Stanislav Kudláč</TD> <TD>qwerty1@NOSPAM.pobox.sk</TD> <TD>1.2.7</TD> </TR> @@ -217,7 +217,7 @@ when the translator was updated. \hline Finnish & Olli Korhonen & {\tt Olli.Korhonen@ccc.fi} & 1.0.0 \\ \hline - French & Xavier Outhier & {\tt xavier.outhier@anfdata.cz} & 1.2.0 \\ + French & Xavier Outhier & {\tt xavier.outhier@anfdata.cz} & up-to-date \\ \hline German & Jens Seidel & {\tt jensseidel@users.sourceforge.net} & up-to-date \\ & Jens Breitenstein & {\tt Jens.Breitenstein@tlc.de} & \\ @@ -241,7 +241,7 @@ when the translator was updated. \hline Russian & Alexandr Chelpanov & {\tt cav@cryptopro.ru} & up-to-date \\ \hline - Slovak & Stanislav Kudlac & {\tt qwerty1@pobox.sk} & 1.2.7 \\ + Slovak & Stanislav Kudl\'{a}\v{c} & {\tt qwerty1@pobox.sk} & 1.2.7 \\ \hline Slovene & Matjaz Ostroversnik & {\tt matjaz.ostroversnik@zrs-tk.si} & 1.1.5 \\ \hline @@ -274,7 +274,7 @@ Just follow these steps: is already working on support for that language, you will be assigned as the maintainer for the language. <li>Create a copy of translator_en.h and name it - translator_<your_2_letter_counter_code>.h + translator_<your_2_letter_country_code>.h I'll use xx in the rest of this document. <li>Edit language.cpp: Add a @@ -298,7 +298,8 @@ Just follow these steps: <li>In the member <code>idLanguage()</code> change "english" into the name of the your language (use lower case characters only). Depending on the language you may also wish to change the member functions - latexLanguageSupportCommand() and idLanguageCharset(). + latexLanguageSupportCommand(), idLanguageCharset() and others + (you will recognize them when you start the work). <li>Edit all the strings that are returned by the member functions that start with tr. Try to match punctuation and capitals! @@ -306,7 +307,7 @@ Just follow these steps: <ul> <li> Enter them directly if your keyboard supports that and you are using a Latin-1 font. - Doxygen will translate the characters to proper Latex and + Doxygen will translate the characters to proper LateX and leave the Html and man output for what it is (which is fine, if idLanguageCharset() is set correctly). <li> Use html codes like \ä for an a with an umlaut (i.e. ä). @@ -318,34 +319,202 @@ Just follow these steps: <li>Now you can use <code>OUTPUT_LANGUAGE = your_language_name</code> in the config file to generate output in your language. <li>Send <code>translator_xx.h</code> to me so I can add it to doxygen. + Send also your name and e-mail address to be included in the + \c maintainers.txt list. </ol> + <h3>Maintaining a language</h3> -As new versions of doxygen appear, new sentences will be -added to the Translator interface class. Of course these need to be translated -as well (otherwise doxygen wouldn't even compile!). +As new versions of doxygen appear, new sentences (\c trXxxx() +methods) will be added to the \c Translator interface class. Of +course, these need to be translated as well (otherwise doxygen +wouldn't even compile!). Waiting until all language maintainers +have translated the new sentences and sent the results would not +be very practical. The following text describes the usage of +translator adapters to solve the problem. + +<b>The role of Translator Adapters.</b> +Whenever the \c Translator class interface changes in the new +release, the new class \c TranslatorAdapter_x_y_z is added to the \c +translator_adapter.h file (here x, y, and z are numbers that +correspond to the current version of doxygen). All translators that +previously derived from the \c Translator class now derive from this +adapter class. + +The \c TranslatorAdapter_x_y_z class implements the new, required +methods. If the new method replaces some similar but obsolete +method(s) (e.g. if the number of arguments changed and/or the +functionality of the older method was changed or enriched), the \c +TranslatorAdapter_x_y_z class may use the obsolete method to get the +result which is as close as possible to the older result in the +target language. If it is not possible, the result (the default +translation) is obtained using the English translator, which is (by +definition) always up to date. + +<b>For example,</b> when the new \c trFile() method with +parameters (to determine the capitalization of the first letter and +the singular/plural form) was introduced to replace the older method +\c trFiles() without arguments, the following code appeared in one +of the translator adapter classes: + +\verbatim + /*! This is the default implementation of the obsolete method + * used in the documentation of a group before the list of + * links to documented files. This is possibly localized. + */ + virtual QCString trFiles() + { return "Files"; } + + /*! This is the localized implementation of newer equivalent + * using the obsolete method trFiles(). + */ + virtual QCString trFile(bool first_capital, bool singular) + { + if (first_capital && !singular) + return trFiles(); // possibly localized, obsolete method + else + return english.trFile(first_capital, singular); + } +\endverbatim + +The \c trFiles() is not present in the \c TranslatorEnglish class, +because it was removed as obsolete. However, it was used until now +and its call was replaced by + +\verbatim + trFile(true, false) +\endverbatim + +in the doxygen source files. Probably, many language translators +implemented the obsolete method, so it perfectly makes sense to use +the same language dependent result in those cases. The \c +TranslatorEnglish does not implement the old method. It derives +from the abstract \c Translator class. On the other hand, the old +translator for a different language does not implement the new \c +trFile() method. Because of that it is derived from another base +class -- \c TranslatorAdapter_x_y_z. The \c TranslatorAdapter_x_y_z +class have to implement the new, required \c trFile() method. +However, the translator adapter would not be compiled if the \c +trFiles() method was not implemented. This is the reason for +implementing the old method in the translator adapter class (using +the same code, that was removed from the TranslatorEnglish). + +The simplest way would be to pass the arguments to the English +translator and to return its result. Instead, the adapter uses the +old \c trFiles() in one special case -- when the new +<code>trFile(true, false)</code> is called. This is the +mostly used case at the time of introducing the new method -- see +above. While this may look too complicated, the technique allows +the developers of the core sources to change the Translator +interface, while the users may not even notice the change. Of +course, when the new \c trFile() is used with different arguments, +the English result is returned and it will be noticed by non English +users. Here the maintainer of the language translator should +implement at least that one particular method. + +<b>What says the base class of a language translator?</b> +If the language translator class inherits from any adapter class the +maintenance is needed. In such case, the language translator is not +considered up-to-date. On the other hand, if the language +translator derives directly from the abstract class \c Translator, the +language translator is up-to-date. + +The translator adapter classes are chained so that the older +translator adapter class uses the one-step-newer translator adapter +as the base class. The newer adapter does less \e adapting work +than the older one. The oldest adapter class derives (indirectly) +from all of the adapter classes. The newest adapter class derives +directly from the abstract class \c Translator. + +The name of the adapter class was chosen so that its suffix is +derived from the previous version of doxygen. This way, one can say +approximately, when the language translator class was last updated +-- see details below. The newest adapter translator for CVS release +(i.e. non official) is named \c TranslatorAdapterCVS. As it derives +only from the \c Translator class, it can be used only for language +translator classes that were up-to-date in the time of the last +release. + +Status of the translators that derive from the \c +TranslatorAdapterCVS is named as <em>almost up-to-date</em>. +Its code is moved into the new \c Translator_x_y_z when new version +of doxygen is officially released. + +Once the oldest adapter class is not used by any of the language +translators, it can be removed from the doxygen project. This also +means, that there probably still is some language which uses the +oldest adapter. The maintainers should try to reach the state with +the minimal number of translator adapter classes. + + +<b>To simplify the maintenance of the language translator classes</b> +for the supported languages, the \c translator.pl perl +script was developed (located in \c doxygen/doc directory). +It is able to extract the important information about obsolete and +new methods from the source files for each of the languages -- see +the reference to the <em>translator report</em> ASCII file below +the table of supported languages shown earlier. Looking at the base +class of the language translator, the script guesses also the status +of the translator -- see the last column of the mentioned table. +The \c translator.pl is called automatically when the doxygen +documentation is generated. You can also run the script manualy +whenever you feel that it can help you. Of course, you are not +forced to use the results of the script. You can find the same +information by looking at the adapter class and its base classes. + +<b>How should I update my language translator?</b> Firstly, you +should be the language maintainer, or you should let him/her know +about the changes. The following text was written for the language +maintainers as the primary audience. + +There are several approaches to be taken when updating your +language. If you are not extremely busy, you should always chose +the most radical one. When the update takes much more time than you +expected, you can always decide use some suitable translator adapter to +finish the changes later and still make your translator working. + +<b>The most radical way of updating the language translator</b> is +to make your translator class derive directly +from the abstract class \c Translator and provide translations for the +methods that are required to be implemented -- the compiler will +tell you if you forgot to implement some of them. If you are in +doubt, have a look at the \c TranslatorEnglish class to recognize the +purpose of the implemented method. Looking at the previously used +adapter class may help you sometimes, but it can also be misleading +because the adapter classes do implement also the obsolete methods +(see the previous \c trFiles() example). -Waiting until all language maintainers have translated these new sentences -and sent the results would not be very practical for me. +In other words, the up-to-date language translators do not need the +\c TranslatorAdapter_x_y_z classes at all, and you do not need to +implement anything else than the methods required by the Translator +class (i.e. the pure virtual methods of the \c Translator -- they +end with <code>=0;</code>). -Instead, a new class TranslatorAdapter_x_y_z will be added to -translator_adapter.h (here x,y, and z correspond to the current -version of doxygen). And all translators that previous derived from -Translator will now derive from this adapter class. +If everything compiles fine, try to run \c translator.pl, and have a +look at the translator report (ASCII file) at the \c doxygen/doc +directory. Even if your translator is marked as up-to-date, there +still may be some remarks related to your souce code. Namely, the +obsolete methods--that are not used at all--may be listed in the +section for your language. Simply, remove their code (and run the +\c translator.pl again). -The Adapter class contains the new sentences with -default translations using the English translator (which is always up to date). -Instead of deriving your TranslatorXX class directly from Translator it will -derive from the intermediate class TranslatorAdapter_x_y_z. +<b>If you do not have time to finish all the updates</b> you should +still start with <em>the most radical approach</em> as described +above. You can always change the base class to the translator +adapter class that implements all of the not-yet-implemented methods. -Thus, if a translator class inherits from a adapter class -maintenance is needed. By looking at the adapter class itself (and its base -classes) you can easily see which methods need to be updated. +<b>If you prefer to update your translator gradually</b>, look +at the <em>translator report</em> generated by the \c translator.pl script +and choose one of the missing method that is implemented by the +translator adapter, that is used as your base class. When there is +not such a method in your translator adapter base class, you probably +can change the translator adapter base to the newer one. -To update a language simply make your translator class derive from -the abstract class Translator and provide translations for the methods that -were previously provided by the adapter class (and its base classes). +Do not blindly implement all methods that are implemented by your +translator adapter base class. The reason is that the adapter +classes implement also obsolete methods. Another reason is that +some of the methods could become obsolete later. */ diff --git a/doc/language.tpl b/doc/language.tpl index 18c0b40..d81c213 100644 --- a/doc/language.tpl +++ b/doc/language.tpl @@ -19,16 +19,16 @@ <h3>Support for multiple languages</h3> -Doxygen has support for multiple languages. This means -that the text fragments that doxygen generates can changed into languages -other than English (the default) at configuration time. +Doxygen has built-in support for multiple languages. This means +that the text fragments that doxygen generates can be produced in +languages other than English (the default) at configuration time. <p> Currently (version $version), $numlang languages are supported (sorted alphabetically): $languages. The table of information related to the supported languages follows. -It is sorted by language alphabetically. The <B>Status</B> column +It is sorted by language alphabetically. The <b>Status</b> column was generated from sources and shows approximately the last version when the translator was updated. <p> @@ -53,7 +53,7 @@ Just follow these steps: is already working on support for that language, you will be assigned as the maintainer for the language. <li>Create a copy of translator_en.h and name it - translator_<your_2_letter_counter_code>.h + translator_<your_2_letter_country_code>.h I'll use xx in the rest of this document. <li>Edit language.cpp: Add a @@ -77,7 +77,8 @@ Just follow these steps: <li>In the member <code>idLanguage()</code> change "english" into the name of the your language (use lower case characters only). Depending on the language you may also wish to change the member functions - latexLanguageSupportCommand() and idLanguageCharset(). + latexLanguageSupportCommand(), idLanguageCharset() and others + (you will recognize them when you start the work). <li>Edit all the strings that are returned by the member functions that start with tr. Try to match punctuation and capitals! @@ -85,7 +86,7 @@ Just follow these steps: <ul> <li> Enter them directly if your keyboard supports that and you are using a Latin-1 font. - Doxygen will translate the characters to proper Latex and + Doxygen will translate the characters to proper LateX and leave the Html and man output for what it is (which is fine, if idLanguageCharset() is set correctly). <li> Use html codes like \ä for an a with an umlaut (i.e. ä). @@ -97,34 +98,202 @@ Just follow these steps: <li>Now you can use <code>OUTPUT_LANGUAGE = your_language_name</code> in the config file to generate output in your language. <li>Send <code>translator_xx.h</code> to me so I can add it to doxygen. + Send also your name and e-mail address to be included in the + \c maintainers.txt list. </ol> + <h3>Maintaining a language</h3> -As new versions of doxygen appear, new sentences will be -added to the Translator interface class. Of course these need to be translated -as well (otherwise doxygen wouldn't even compile!). +As new versions of doxygen appear, new sentences (\c trXxxx() +methods) will be added to the \c Translator interface class. Of +course, these need to be translated as well (otherwise doxygen +wouldn't even compile!). Waiting until all language maintainers +have translated the new sentences and sent the results would not +be very practical. The following text describes the usage of +translator adapters to solve the problem. + +<b>The role of Translator Adapters.</b> +Whenever the \c Translator class interface changes in the new +release, the new class \c TranslatorAdapter_x_y_z is added to the \c +translator_adapter.h file (here x, y, and z are numbers that +correspond to the current version of doxygen). All translators that +previously derived from the \c Translator class now derive from this +adapter class. + +The \c TranslatorAdapter_x_y_z class implements the new, required +methods. If the new method replaces some similar but obsolete +method(s) (e.g. if the number of arguments changed and/or the +functionality of the older method was changed or enriched), the \c +TranslatorAdapter_x_y_z class may use the obsolete method to get the +result which is as close as possible to the older result in the +target language. If it is not possible, the result (the default +translation) is obtained using the English translator, which is (by +definition) always up to date. + +<b>For example,</b> when the new \c trFile() method with +parameters (to determine the capitalization of the first letter and +the singular/plural form) was introduced to replace the older method +\c trFiles() without arguments, the following code appeared in one +of the translator adapter classes: + +\verbatim + /*! This is the default implementation of the obsolete method + * used in the documentation of a group before the list of + * links to documented files. This is possibly localized. + */ + virtual QCString trFiles() + { return "Files"; } + + /*! This is the localized implementation of newer equivalent + * using the obsolete method trFiles(). + */ + virtual QCString trFile(bool first_capital, bool singular) + { + if (first_capital && !singular) + return trFiles(); // possibly localized, obsolete method + else + return english.trFile(first_capital, singular); + } +\endverbatim + +The \c trFiles() is not present in the \c TranslatorEnglish class, +because it was removed as obsolete. However, it was used until now +and its call was replaced by + +\verbatim + trFile(true, false) +\endverbatim + +in the doxygen source files. Probably, many language translators +implemented the obsolete method, so it perfectly makes sense to use +the same language dependent result in those cases. The \c +TranslatorEnglish does not implement the old method. It derives +from the abstract \c Translator class. On the other hand, the old +translator for a different language does not implement the new \c +trFile() method. Because of that it is derived from another base +class -- \c TranslatorAdapter_x_y_z. The \c TranslatorAdapter_x_y_z +class have to implement the new, required \c trFile() method. +However, the translator adapter would not be compiled if the \c +trFiles() method was not implemented. This is the reason for +implementing the old method in the translator adapter class (using +the same code, that was removed from the TranslatorEnglish). + +The simplest way would be to pass the arguments to the English +translator and to return its result. Instead, the adapter uses the +old \c trFiles() in one special case -- when the new +<code>trFile(true, false)</code> is called. This is the +mostly used case at the time of introducing the new method -- see +above. While this may look too complicated, the technique allows +the developers of the core sources to change the Translator +interface, while the users may not even notice the change. Of +course, when the new \c trFile() is used with different arguments, +the English result is returned and it will be noticed by non English +users. Here the maintainer of the language translator should +implement at least that one particular method. + +<b>What says the base class of a language translator?</b> +If the language translator class inherits from any adapter class the +maintenance is needed. In such case, the language translator is not +considered up-to-date. On the other hand, if the language +translator derives directly from the abstract class \c Translator, the +language translator is up-to-date. + +The translator adapter classes are chained so that the older +translator adapter class uses the one-step-newer translator adapter +as the base class. The newer adapter does less \e adapting work +than the older one. The oldest adapter class derives (indirectly) +from all of the adapter classes. The newest adapter class derives +directly from the abstract class \c Translator. + +The name of the adapter class was chosen so that its suffix is +derived from the previous version of doxygen. This way, one can say +approximately, when the language translator class was last updated +-- see details below. The newest adapter translator for CVS release +(i.e. non official) is named \c TranslatorAdapterCVS. As it derives +only from the \c Translator class, it can be used only for language +translator classes that were up-to-date in the time of the last +release. + +Status of the translators that derive from the \c +TranslatorAdapterCVS is named as <em>almost up-to-date</em>. +Its code is moved into the new \c Translator_x_y_z when new version +of doxygen is officially released. + +Once the oldest adapter class is not used by any of the language +translators, it can be removed from the doxygen project. This also +means, that there probably still is some language which uses the +oldest adapter. The maintainers should try to reach the state with +the minimal number of translator adapter classes. + + +<b>To simplify the maintenance of the language translator classes</b> +for the supported languages, the \c translator.pl perl +script was developed (located in \c doxygen/doc directory). +It is able to extract the important information about obsolete and +new methods from the source files for each of the languages -- see +the reference to the <em>translator report</em> ASCII file below +the table of supported languages shown earlier. Looking at the base +class of the language translator, the script guesses also the status +of the translator -- see the last column of the mentioned table. +The \c translator.pl is called automatically when the doxygen +documentation is generated. You can also run the script manualy +whenever you feel that it can help you. Of course, you are not +forced to use the results of the script. You can find the same +information by looking at the adapter class and its base classes. + +<b>How should I update my language translator?</b> Firstly, you +should be the language maintainer, or you should let him/her know +about the changes. The following text was written for the language +maintainers as the primary audience. + +There are several approaches to be taken when updating your +language. If you are not extremely busy, you should always chose +the most radical one. When the update takes much more time than you +expected, you can always decide use some suitable translator adapter to +finish the changes later and still make your translator working. + +<b>The most radical way of updating the language translator</b> is +to make your translator class derive directly +from the abstract class \c Translator and provide translations for the +methods that are required to be implemented -- the compiler will +tell you if you forgot to implement some of them. If you are in +doubt, have a look at the \c TranslatorEnglish class to recognize the +purpose of the implemented method. Looking at the previously used +adapter class may help you sometimes, but it can also be misleading +because the adapter classes do implement also the obsolete methods +(see the previous \c trFiles() example). -Waiting until all language maintainers have translated these new sentences -and sent the results would not be very practical for me. +In other words, the up-to-date language translators do not need the +\c TranslatorAdapter_x_y_z classes at all, and you do not need to +implement anything else than the methods required by the Translator +class (i.e. the pure virtual methods of the \c Translator -- they +end with <code>=0;</code>). -Instead, a new class TranslatorAdapter_x_y_z will be added to -translator_adapter.h (here x,y, and z correspond to the current -version of doxygen). And all translators that previous derived from -Translator will now derive from this adapter class. +If everything compiles fine, try to run \c translator.pl, and have a +look at the translator report (ASCII file) at the \c doxygen/doc +directory. Even if your translator is marked as up-to-date, there +still may be some remarks related to your souce code. Namely, the +obsolete methods--that are not used at all--may be listed in the +section for your language. Simply, remove their code (and run the +\c translator.pl again). -The Adapter class contains the new sentences with -default translations using the English translator (which is always up to date). -Instead of deriving your TranslatorXX class directly from Translator it will -derive from the intermediate class TranslatorAdapter_x_y_z. +<b>If you do not have time to finish all the updates</b> you should +still start with <em>the most radical approach</em> as described +above. You can always change the base class to the translator +adapter class that implements all of the not-yet-implemented methods. -Thus, if a translator class inherits from a adapter class -maintenance is needed. By looking at the adapter class itself (and its base -classes) you can easily see which methods need to be updated. +<b>If you prefer to update your translator gradually</b>, look +at the <em>translator report</em> generated by the \c translator.pl script +and choose one of the missing method that is implemented by the +translator adapter, that is used as your base class. When there is +not such a method in your translator adapter base class, you probably +can change the translator adapter base to the newer one. -To update a language simply make your translator class derive from -the abstract class Translator and provide translations for the methods that -were previously provided by the adapter class (and its base classes). +Do not blindly implement all methods that are implemented by your +translator adapter base class. The reason is that the adapter +classes implement also obsolete methods. Another reason is that +some of the methods could become obsolete later. */ diff --git a/doc/lists.doc b/doc/lists.doc index eaf8616..c7e275c 100644 --- a/doc/lists.doc +++ b/doc/lists.doc @@ -69,13 +69,13 @@ Here is the above example with HTML commands: */ \endverbatim -\note The the indent here is not important. +\note The indentation here is not important. <b>Using \\arg or \@li</b> For compatibility with the Troll Tech's internal documentation tool and with KDoc, doxygen has two commands that can be used to create simple -not nested lists. +unnested lists. See \ref cmdarg "\arg" and \ref cmdli "\li" for more info. diff --git a/doc/maintainers.txt b/doc/maintainers.txt index 1386a9b..c476fb5 100644 --- a/doc/maintainers.txt +++ b/doc/maintainers.txt @@ -62,7 +62,7 @@ Russian Alexandr Chelpanov: cav@cryptopro.ru Slovak -Stanislav Kudlac: qwerty1@pobox.sk +Stanislav Kudláč: qwerty1@pobox.sk Slovene Matjaz Ostroversnik: matjaz.ostroversnik@zrs-tk.si diff --git a/doc/preprocessing.doc b/doc/preprocessing.doc index 3a97d87..19f730d 100644 --- a/doc/preprocessing.doc +++ b/doc/preprocessing.doc @@ -17,7 +17,7 @@ /*! \page preprocessing Preprocessing Source files that are used as input to doxygen can be parsed by doxygen's -build-in C-preprocessor. +built-in C-preprocessor. By default doxygen does only partial preprocessing. That is, it evaluates conditional compilation statements (like \#if) and diff --git a/doc/starting.doc b/doc/starting.doc index b307788..402a765 100644 --- a/doc/starting.doc +++ b/doc/starting.doc @@ -125,7 +125,7 @@ a browser that supports cascading style sheets (CSS) should be used \addindex LaTeX The generated \f$\mbox{\LaTeX}\f$ documentation must first be compiled by -a \f$\mbox{\LaTeX}\f$ compiler. (I use teTeX distribution version 0.9 +a \f$\mbox{\LaTeX}\f$ compiler (I use teTeX distribution version 0.9 that contains \f$\mbox{\TeX}\f$ version 3.14159). To simplify the process of compiling the generated documentation, \c doxygen writes a \c Makefile into the \c latex directory. diff --git a/doc/translator.pl b/doc/translator.pl index b0bb9e3..9d44686 100644 --- a/doc/translator.pl +++ b/doc/translator.pl @@ -38,6 +38,9 @@ # argument list does not contain argument identifiers # (i.e., when it contains type information only). # +# 2001/06/11 +# - Character entity č recognized in maintainers.txt. +# ################################################################ require 5.005; @@ -566,13 +569,15 @@ xxxTABLE_FOOTxxx $tableLATEX .= $latexTableFoot; $tableHTML =~ s{@}{\@NOSPAM.}sg; + $tableHTML =~ s{č}{č}sg; $tableHTML =~ s{ř}{ř}sg; - $tableLATEX =~ s/ř/\\v{r}/sg; $tableLATEX =~ s/á/\\'{a}/sg; $tableLATEX =~ s/ä/\\"{a}/sg; $tableLATEX =~ s/ö/\\"{o}/sg; $tableLATEX =~ s/ø/\\o{}/sg; + $tableLATEX =~ s/č/\\v{c}/sg; + $tableLATEX =~ s/ř/\\v{r}/sg; $tableLATEX =~ s/_/\\_/sg; my $notice = "\nHave a look at <a href=\"../doc/$ftranslatortxt\"\n>" @@ -16,16 +16,18 @@ if "%2"=="debug" SET MODE=debug REM use perl to create the config file perl wintools\make.pl %CC% -type makeconfig > Makefile -type Makefile.win_%MAKE%.in >>Makefile -type makeconfig > qtools\Makefile -type qtools\Makefile.in >>qtools\Makefile -type makeconfig > src\Makefile -type src\Makefile.in >>src\Makefile -type makeconfig > examples\Makefile -type examples\Makefile.win.in >>examples\Makefile -type makeconfig > doc\Makefile -type doc\Makefile.win_%MAKE%.in >>doc\Makefile +type makeconfig > Makefile +type Makefile.win_%MAKE%.in >>Makefile +type makeconfig > qtools\Makefile +type qtools\Makefile.in >>qtools\Makefile +type makeconfig > src\Makefile +type src\Makefile.in >>src\Makefile +type makeconfig > examples\Makefile +type examples\Makefile.win.in >>examples\Makefile +type makeconfig > doc\Makefile +type doc\Makefile.win_%MAKE%.in >>doc\Makefile +type makeconfig > addon\doxywizard\Makefile +type addon\doxywizard\Makefile.win_%MAKE%.in >>addon\doxywizard\Makefile REM build in release or debug mode REM sed is used to replace $extraopts by either debug or release while copying @@ -35,6 +37,7 @@ sed "s/\$extraopts/%MODE%/g" src\libdoxycfg.pro.in >src\libdoxycfg.pro sed "s/\$extraopts/%MODE%/g" src\doxygen.pro.in >src\doxygen.pro sed "s/\$extraopts/%MODE%/g" src\doxytag.pro.in >src\doxytag.pro sed "s/\$extraopts/%MODE%/g" src\doxysearch.pro.in >src\doxysearch.pro +sed "s/\$extraopts/%MODE%/g" addon\doxywizard\doxywizard.pro.in >addon\doxywizard\doxywizard.pro REM run make %MAKE%.exe diff --git a/packages/rpm/doxygen.spec b/packages/rpm/doxygen.spec index e280cb2..34789a5 100644 --- a/packages/rpm/doxygen.spec +++ b/packages/rpm/doxygen.spec @@ -1,5 +1,5 @@ Name: doxygen -Version: 1.2.8_20010617 +Version: 1.2.8_20010715 Summary: documentation system for C, C++ and IDL Release: 3 Source: doxygen-%{version}.src.tar.gz diff --git a/src/classdef.cpp b/src/classdef.cpp index f2c733b..f7c0550 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -33,7 +33,8 @@ #include "example.h" #include "outputlist.h" #include "dot.h" -//#include "xml.h" +#include "defargs.h" +#include "debug.h" static QCString stripExtension(const char *fName) { @@ -98,8 +99,10 @@ ClassDef::ClassDef( } m_subGrouping=TRUE; m_isTemplBaseClass=-1; - m_templateMapping = new StringDict; - m_templateMapping->setAutoDelete(TRUE); + m_templateInstances = 0; + m_templateMaster =0; + m_templBaseClassNames = 0; + m_artificial = FALSE; } // destroy the class definition @@ -115,19 +118,26 @@ ClassDef::~ClassDef() delete m_memberGroupList; delete m_memberGroupDict; delete m_innerClasses; - delete m_templateMapping; + delete m_templateInstances; + delete m_templBaseClassNames; } QCString ClassDef::displayName() const { + QCString n; if (Config_getBool("HIDE_SCOPE_NAMES")) { - return stripScope(name()); + n=stripScope(name()); } else { - return name(); + n=name(); } + if (m_tempArgs) + { + n+=tempArgListToString(m_tempArgs); + } + return n; } // inserts a base class in the inheritance list @@ -527,6 +537,15 @@ void ClassDef::distributeMemberGroupDocumentation() void ClassDef::insertUsedFile(const char *f) { if (m_files.find(f)==-1) m_files.append(f); + if (m_templateInstances) + { + QDictIterator<ClassDef> qdi(*m_templateInstances); + ClassDef *cd; + for (qdi.toFirst();(cd=qdi.current());++qdi) + { + cd->insertUsedFile(f); + } + } } static void writeInheritanceSpecifier(OutputList &ol,BaseClassDef *bcd) @@ -566,6 +585,7 @@ void ClassDef::setIncludeFile(FileDef *fd,const char *includeName,bool local) } } +// TODO: fix this: a nested template class can have multiple outer templates ArgumentList *ClassDef::outerTemplateArguments() const { int ti; @@ -700,6 +720,15 @@ void ClassDef::writeDocumentation(OutputList &ol) Doxygen::tagFile << "\">" << endl; Doxygen::tagFile << " <name>" << convertToXML(name()) << "</name>" << endl; Doxygen::tagFile << " <filename>" << convertToXML(getOutputFileBase()) << ".html</filename>" << endl; + if (m_tempArgs) + { + ArgumentListIterator ali(*m_tempArgs); + Argument *a; + for (;(a=ali.current());++ali) + { + Doxygen::tagFile << " <templarg>" << convertToXML(a->name) << "</templarg>" << endl; + } + } } @@ -1145,15 +1174,16 @@ void ClassDef::writeMemberList(OutputList &ol) ClassDef *cd=md->getClassDef(); // compute the protection level for this member - Protection prot=md->protection(); - if (mi->prot==Protected) // inherited protection: Protected - { - if (prot==Public) prot=Protected; - } - else if (mi->prot==Private) // inherited protection: Private - { - prot=Private; - } + //Protection prot=md->protection(); + //if (mi->prot==Protected) // inherited protection: Protected + //{ + // if (prot==Public) prot=Protected; + //} + //else if (mi->prot==Private) // inherited protection: Private + //{ + // prot=Private; + //} + Protection prot = mi->prot; //printf("%s: Member %s of class %s md->protection()=%d mi->prot=%d prot=%d inherited=%d\n", // name().data(),md->name().data(),cd->name().data(),md->protection(),mi->prot,prot,mi->inherited); @@ -1166,13 +1196,15 @@ void ClassDef::writeMemberList(OutputList &ol) rmd = rmd->reimplements(); } - if (cd && !md->name().isEmpty() && md->name()[0]!='@' && - ( - md->isFriend() || - (/*mi->prot!=Private &&*/ - (prot!=Private || Config_getBool("EXTRACT_PRIVATE")) - ) - ) + if (cd && !md->name().isEmpty() && md->name()[0]!='@' + // && + //( + // md->isFriend() + // || + //(/*mi->prot!=Private &&*/ + // (prot!=Private || Config_getBool("EXTRACT_PRIVATE")) + //) + //) ) { bool memberWritten=FALSE; @@ -1416,7 +1448,7 @@ void ClassDef::writeDeclaration(OutputList &ol,MemberDef *md,bool inGroup) } /*! a link to this class is possible within this project */ -bool ClassDef::isLinkableInProject() +bool ClassDef::isLinkableInProject() const { return !name().isEmpty() && /* no name */ m_isTemplBaseClass==-1 && /* template base class */ @@ -1432,8 +1464,10 @@ bool ClassDef::isVisibleInHierarchy() (Config_getBool("ALLEXTERNALS") || hasNonReferenceSuperClass()) && // and not an annonymous compound name().find('@')==-1 && + // not an artifically introduced class + !m_artificial && // and not an inherited template argument - m_isTemplBaseClass==-1 && + //m_isTemplBaseClass==-1 && // and not privately inherited (m_prot!=Private || Config_getBool("EXTRACT_PRIVATE")) && // documented or show anyway or documentation is external @@ -1642,6 +1676,7 @@ void ClassDef::mergeMembers() Specifier virt=mi->virt; if (mi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt; + //printf("Adding!\n"); MemberInfo *newMi=new MemberInfo(mi->memberDef,prot,virt,TRUE); newMi->scopePath=bClass->name()+"::"+mi->scopePath; newMi->ambigClass=mi->ambigClass; @@ -1660,6 +1695,22 @@ void ClassDef::mergeMembers() //---------------------------------------------------------------------------- +void ClassDef::addUsedClass(ClassDef *cd,const char *accessName) +{ + if (m_usesImplClassDict==0) m_usesImplClassDict = new UsesClassDict(17); + UsesClassDef *ucd=m_usesImplClassDict->find(cd->name()); + if (ucd==0 /*|| ucd->templSpecifiers!=templSpec*/) + { + ucd = new UsesClassDef(cd); + m_usesImplClassDict->insert(cd->name(),ucd); + //ucd->templSpecifiers = templSpec; + //printf("Adding used class %s to class %s\n", + // cd->name().data(),name().data()); + } + ucd->addAccessor(accessName); +} + +#if 0 /*! Builds up a dictionary of all classes that are used by the state of this * class (the "implementation"). * Must be called before mergeMembers() is called! @@ -1772,7 +1823,6 @@ void ClassDef::determineImplUsageRelation() //---------------------------------------------------------------------------- -#if 0 // I have disabled this code because the graphs it renders quickly become // too large to be of practical use. @@ -1873,6 +1923,22 @@ QCString ClassDef::compoundTypeString() const QCString ClassDef::getOutputFileBase() const { + if (m_templateMaster) + { + return m_templateMaster->getOutputFileBase(); + } + else if (isReference()) + { + return m_fileName; + } + else + { + return convertNameToFile(m_fileName); + } +} + +QCString ClassDef::getInstanceOutputFileBase() const +{ if (isReference()) { return m_fileName; @@ -1885,12 +1951,26 @@ QCString ClassDef::getOutputFileBase() const QCString ClassDef::getFileBase() const { - return m_fileName; + if (m_templateMaster) + { + return m_templateMaster->getFileBase(); + } + else + { + return m_fileName; + } } QCString ClassDef::getSourceFileBase() const { - return convertNameToFile(m_fileName+"-source"); + if (m_templateMaster) + { + return m_templateMaster->getSourceFileBase(); + } + else + { + return convertNameToFile(m_fileName+"-source"); + } } void ClassDef::setGroupDefForAllMembers(GroupDef *gd,Grouping::GroupPri_t pri,const QCString &fileName,int startLine,bool hasDocs) @@ -1925,44 +2005,147 @@ Definition *ClassDef::findInnerCompound(const char *name) return m_innerClasses->find(name); } -void ClassDef::initTemplateMapping() +//void ClassDef::initTemplateMapping() +//{ +// m_templateMapping->clear(); +// ArgumentList *al = templateArguments(); +// if (al) +// { +// ArgumentListIterator ali(*al); +// Argument *arg; +// for (ali.toFirst();(arg=ali.current());++ali) +// { +// setTemplateArgumentMapping(arg->name,arg->defval); +// } +// } +//} +//void ClassDef::setTemplateArgumentMapping(const char *formal,const char *actual) +//{ +// //printf("ClassDef::setTemplateArgumentMapping(%s,%s)\n",formal,actual); +// if (m_templateMapping && formal) +// { +// if (m_templateMapping->find(formal)) +// { +// m_templateMapping->remove(formal); +// } +// m_templateMapping->insert(formal,new QCString(actual)); +// } +//} +// +//QCString ClassDef::getTemplateArgumentMapping(const char *formal) const +//{ +// if (m_templateMapping && formal) +// { +// QCString *s = m_templateMapping->find(formal); +// if (s) +// { +// return *s; +// } +// } +// return ""; +//} + +ClassDef *ClassDef::insertTemplateInstance(const QCString &fileName, + int startLine, const QCString &templSpec,bool &freshInstance) +{ + freshInstance = FALSE; + if (m_templateInstances==0) + { + m_templateInstances = new QDict<ClassDef>(17); + } + ClassDef *templateClass=m_templateInstances->find(templSpec); + if (templateClass==0) + { + Debug::print(Debug::Classes,0," New template instance class %s%s\n",name().data(),templSpec.data()); + templateClass = new ClassDef( + fileName,startLine,name()+templSpec,ClassDef::Class); + //templateClass->setBriefDescription(briefDescription()); + //templateClass->setDocumentation(documentation()); + templateClass->setTemplateMaster(this); + m_templateInstances->insert(templSpec,templateClass); + freshInstance=TRUE; + } + return templateClass; +} + +void ClassDef::setTemplateBaseClassNames(QDict<int> *templateNames) { - m_templateMapping->clear(); - ArgumentList *al = templateArguments(); - if (al) + if (templateNames==0) return; + if (m_templBaseClassNames==0) + { + m_templBaseClassNames = new QDict<int>(17); + m_templBaseClassNames->setAutoDelete(TRUE); + } + // make a deep copy of the dictionary. + QDictIterator<int> qdi(*templateNames); + for (;qdi.current();++qdi) { - ArgumentListIterator ali(*al); - Argument *arg; - for (ali.toFirst();(arg=ali.current());++ali) + if (m_templBaseClassNames->find(qdi.currentKey())==0) { - setTemplateArgumentMapping(arg->name,arg->defval); + m_templBaseClassNames->insert(qdi.currentKey(),new int(*qdi.current())); } } } -void ClassDef::setTemplateArgumentMapping(const char *formal,const char *actual) +QDict<int> *ClassDef::getTemplateBaseClassNames() const +{ + return m_templBaseClassNames; +} + +void ClassDef::addMembersToTemplateInstance(ClassDef *cd,const char *templSpec) { - //printf("ClassDef::setTemplateArgumentMapping(%s,%s)\n",formal,actual); - if (m_templateMapping && formal) + //printf("%s::addMembersToTemplateInstance(%s,%s)\n",name().data(),cd->name().data(),templSpec); + MemberNameInfoSDict::Iterator mnili(*cd->m_allMemberNameInfoSDict); + MemberNameInfo *mni; + for (;(mni=mnili.current());++mnili) { - if (m_templateMapping->find(formal)) + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for (mnii.toFirst();(mi=mnii.current());++mnii) { - m_templateMapping->remove(formal); + ArgumentList *actualArguments = new ArgumentList; + stringToArgumentList(templSpec,actualArguments); + MemberDef *md = mi->memberDef; + MemberDef *imd = md->createTemplateInstanceMember( + cd->templateArguments(),actualArguments); + delete actualArguments; + //printf("%s->setMemberClass(%p)\n",imd->name().data(),this); + imd->setMemberClass(this); + imd->setTemplateMaster(md); + //imd->setDocumentation(md->documentation()); + //imd->setBriefDescription(md->briefDescription()); + imd->setMemberSpecifiers(md->getMemberSpecifiers()); + insertMember(imd); + //printf("Adding member=%s%s to class %s\n",imd->name().data(),imd->argsString(),imd->getClassDef()->name().data()); + // insert imd in the list of all members + //printf("Adding member=%s class=%s\n",imd->name().data(),name().data()); +#if 0 + MemberName *mn; + if ((mn=Doxygen::memberNameDict[imd->name()])) + { + mn->append(md); + } + else + { + mn = new MemberName(imd->name()); + mn->append(md); + Doxygen::memberNameDict.insert(imd->name(),mn); + Doxygen::memberNameList.append(mn); + } +#endif } - m_templateMapping->insert(formal,new QCString(actual)); } } -QCString ClassDef::getTemplateArgumentMapping(const char *formal) const +QCString ClassDef::getReference() const { - if (m_templateMapping && formal) + if (m_templateMaster) { - QCString *s = m_templateMapping->find(formal); - if (s) - { - return *s; - } + return m_templateMaster->getReference(); + } + else + { + return Definition::getReference(); } - return ""; } diff --git a/src/classdef.h b/src/classdef.h index b39b87d..323b7bd 100644 --- a/src/classdef.h +++ b/src/classdef.h @@ -26,6 +26,7 @@ #include "entry.h" #include "memberlist.h" #include "definition.h" +#include "sortdict.h" class MemberDict; class ClassList; @@ -67,8 +68,10 @@ class ClassDef : public Definition }; DefType definitionType() { return TypeClass; } QCString getOutputFileBase() const; + QCString getInstanceOutputFileBase() const; QCString getFileBase() const; QCString getSourceFileBase() const; + QCString getReference() const; bool hasDocumentation() const; @@ -106,12 +109,12 @@ class ClassDef : public Definition /*! returns TRUE iff a link is possible to an item within this project. */ - bool isLinkableInProject(); + bool isLinkableInProject() const; /*! return TRUE iff a link to this class is possible (either within * this project, or as a cross-reference to another project). */ - bool isLinkable() + bool isLinkable() const { return isLinkableInProject() || isReference(); } @@ -156,6 +159,15 @@ class ClassDef : public Definition */ int isTemplateBaseClass() const { return m_isTemplBaseClass; } + /*! Returns a sorted dictionary with all template instances found for + * this template class. Returns 0 if not a template or no instances. + */ + QDict<ClassDef> *getTemplateInstances() const { return m_templateInstances; } + /*! Returns the template master of which this class is an instance. + * Returns 0 if not applicable. + */ + ClassDef *templateMaster() const { return m_templateMaster; } + UsesClassDict *usedImplementationClasses() const { return m_usesImplClassDict; @@ -166,8 +178,13 @@ class ClassDef : public Definition return m_usesIntfClassDict; } + /*! Returns the definition of a nested compound if + * available, or 0 otherwise. + * @param name The name of the nested compound + */ virtual Definition *findInnerCompound(const char *name); + /* member lists by protection */ MemberList pubMembers; MemberList proMembers; @@ -224,16 +241,24 @@ class ClassDef : public Definition void setTemplateArguments(ArgumentList *al); void mergeMembers(); void setFileDef(FileDef *fd) { m_fileDef=fd; } - void determineImplUsageRelation(); - void determineIntfUsageRelation(); + //void determineImplUsageRelation(); + //void determineIntfUsageRelation(); void setSubGrouping(bool enabled) { m_subGrouping = enabled; } void setProtection(Protection p) { m_prot=p; } void setGroupDefForAllMembers(GroupDef *g,Grouping::GroupPri_t pri,const QCString &fileName,int startLine,bool hasDocs); void addInnerCompound(Definition *d); void setIsTemplateBaseClass(int num) { m_isTemplBaseClass = num; } - void initTemplateMapping(); - void setTemplateArgumentMapping(const char *formal,const char *actual); - QCString getTemplateArgumentMapping(const char *formal) const; + void addUsedClass(ClassDef *cd,const char *accessName); + //void initTemplateMapping(); + //void setTemplateArgumentMapping(const char *formal,const char *actual); + //QCString getTemplateArgumentMapping(const char *formal) const; + ClassDef *insertTemplateInstance(const QCString &fileName,int startLine, + const QCString &templSpec,bool &freshInstance); + void setTemplateBaseClassNames(QDict<int> *templateNames); + QDict<int> *getTemplateBaseClassNames() const; + void setTemplateMaster(ClassDef *tm) { m_templateMaster=tm; } + void addMembersToTemplateInstance(ClassDef *cd,const char *templSpec); + void setClassIsArtificial() { m_artificial = TRUE; } /*! Creates a new compound definition. * \param outerScope class, file or namespace in which this class is @@ -351,11 +376,22 @@ class ClassDef : public Definition */ int m_isTemplBaseClass; - /*! A mapping used by template classes, which maps formal - * template arguments to their actual instantiations. - * This is used while generating inheritance graphs. + /*! Template instances that exists of this class, the key in the + * dictionary is the template argument list. + */ + QDict<ClassDef> *m_templateInstances; + + QDict<int> *m_templBaseClassNames; + + /*! The class this class is an instance of. */ + ClassDef *m_templateMaster; + + /*! Indicated whether this class exists because it is used by + * some other class only (TRUE) or if some class inherits from + * it (FALSE). This is need to remove used-only classes from + * the inheritance tree. */ - StringDict *m_templateMapping; + bool m_artificial; }; /*! \brief Class that contains information about a usage relation. @@ -21,7 +21,7 @@ * includes */ #include <stdio.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> #include <qregexp.h> diff --git a/src/config.h b/src/config.h index 8874cff..02a3389 100644 --- a/src/config.h +++ b/src/config.h @@ -290,7 +290,7 @@ class ConfigBool : public ConfigOption t << endl; } t << m_name << m_spaces.left(MAX_OPTION_LENGTH-m_name.length()) << "= "; - if (upd) + if (upd && !m_valueString.isEmpty()) { writeStringValue(t,m_valueString); } diff --git a/src/config.l b/src/config.l index dd704b0..9ffdf55 100644 --- a/src/config.l +++ b/src/config.l @@ -19,7 +19,7 @@ */ #include <stdio.h> #include <stdlib.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> diff --git a/src/constexp.h b/src/constexp.h index 2b09ed9..6f230f9 100644 --- a/src/constexp.h +++ b/src/constexp.h @@ -22,10 +22,12 @@ #include "qtbc.h" #include "cppvalue.h" -extern bool parseCppExpression(const QCString &s); +extern bool parseCppExpression(const char *fileName,int line,const QCString &s); extern int cppExpYYparse(); extern int cppExpYYdebug; -extern QCString strToken; -extern CPPValue resultValue; +extern QCString g_strToken; +extern CPPValue g_resultValue; +extern QCString g_constExpFileName; +extern int g_constExpLineNr; #endif diff --git a/src/constexp.l b/src/constexp.l index b6604ff..92b3da4 100644 --- a/src/constexp.l +++ b/src/constexp.l @@ -25,11 +25,13 @@ #define YY_NO_UNPUT #define YY_NEVER_INTERACTIVE 1 -QCString strToken; +QCString g_strToken; +CPPValue g_resultValue; +int g_constExpLineNr; +QCString g_constExpFileName; -static const char *inputString; -static int inputPosition; -CPPValue resultValue; +static const char *g_inputString; +static int g_inputPosition; #undef YY_INPUT #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); @@ -37,9 +39,9 @@ CPPValue resultValue; static int yyread(char *buf,int max_size) { int c=0; - while( c < max_size && inputString[inputPosition] ) + while( c < max_size && g_inputString[g_inputPosition] ) { - *buf = inputString[inputPosition++] ; + *buf = g_inputString[g_inputPosition++] ; c++; buf++; } return c; @@ -74,36 +76,38 @@ static int yyread(char *buf,int max_size) "(" { return TOK_LPAREN; } ")" { return TOK_RPAREN; } "'"(([^\'\n\r\\]+)|(\\(([ntvbrfa\\?'\"])|([0-9]+)|([xX][0-9a-fA-F]+))))"'" { - strToken=yytext; + g_strToken=yytext; return TOK_CHARACTER; } -0[0-7]*[uUlL]* { strToken=yytext; +0[0-7]*[uUlL]* { g_strToken=yytext; return TOK_OCTALINT; } -[1-9][0-9]*[uUlL]* { strToken=yytext; +[1-9][0-9]*[uUlL]* { g_strToken=yytext; return TOK_DECIMALINT; } -(0x|0X)[0-9a-fA-F]+[uUlL]* { strToken=yytext; return TOK_HEXADECIMALINT; } +(0x|0X)[0-9a-fA-F]+[uUlL]* { g_strToken=yytext; return TOK_HEXADECIMALINT; } (([0-9]+\.[0-9]*)|([0-9]*\.[0-9]+))([eE]([\-\+])?[0-9]+)?([fFlL])? { - strToken=yytext; return TOK_FLOAT; + g_strToken=yytext; return TOK_FLOAT; } ([0-9]+[eE])([\-\+])?[0-9]+([fFlL])? { - strToken=yytext; return TOK_FLOAT; + g_strToken=yytext; return TOK_FLOAT; } . \n %% -bool parseCppExpression(const QCString &s) +bool parseCppExpression(const char *fileName,int lineNr,const QCString &s) { //printf("Expression: `%s'\n",s.data()); - inputString = s; - inputPosition = 0; + g_constExpFileName = fileName; + g_constExpLineNr = lineNr; + g_inputString = s; + g_inputPosition = 0; cppExpYYrestart( cppExpYYin ); cppExpYYparse(); //printf("Result: %ld\n",(long)resultValue); - return (long)resultValue!=0; + return (long)g_resultValue!=0; } extern "C" { diff --git a/src/constexp.y b/src/constexp.y index f5565bc..9063c52 100644 --- a/src/constexp.y +++ b/src/constexp.y @@ -20,6 +20,7 @@ #include "cppvalue.h" #include "constexp.h" +#include "message.h" #if defined(_MSC_VER) #define MSDOS @@ -32,7 +33,8 @@ int cppExpYYerror(const char *s) { - printf("Error in constant expression evaluation: %s\n",s); + warn(g_constExpFileName,g_constExpLineNr, + "Problem during constant expression evaluation: %s",s); return 0; } @@ -73,7 +75,7 @@ int cppExpYYlex(); %% start: constant_expression - { resultValue = $1; return 0; } + { g_resultValue = $1; return 0; } ; constant_expression: logical_or_expression diff --git a/src/cppvalue.cpp b/src/cppvalue.cpp index 62d73dd..be1018a 100644 --- a/src/cppvalue.cpp +++ b/src/cppvalue.cpp @@ -24,7 +24,7 @@ CPPValue parseOctal() { long val = 0; - for (const char *p = strToken.data(); *p != 0; p++) + for (const char *p = g_strToken.data(); *p != 0; p++) { if (*p >= '0' && *p <= '7') val = val * 8 + *p - '0'; } @@ -34,7 +34,7 @@ CPPValue parseOctal() CPPValue parseDecimal() { long val = 0; - for (const char *p = strToken.data(); *p != 0; p++) + for (const char *p = g_strToken.data(); *p != 0; p++) { if (*p >= '0' && *p <= '9') val = val * 10 + *p - '0'; } @@ -44,7 +44,7 @@ CPPValue parseDecimal() CPPValue parseHexadecimal() { long val = 0; - for (const char *p = strToken.data(); *p != 0; p++) + for (const char *p = g_strToken.data(); *p != 0; p++) { if (*p >= '0' && *p <= '9') val = val * 16 + *p - '0'; else if (*p >= 'a' && *p <= 'f') val = val * 16 + *p - 'a' + 10; @@ -55,9 +55,9 @@ CPPValue parseHexadecimal() CPPValue parseCharacter() // does not work for '\n' and the alike { - if (strToken[1]=='\\') + if (g_strToken[1]=='\\') { - switch(strToken[2]) + switch(g_strToken[2]) { case 'n': return CPPValue((long)'\n'); case 't': return CPPValue((long)'\t'); @@ -73,14 +73,14 @@ CPPValue parseCharacter() // does not work for '\n' and the alike case '0': return parseOctal(); case 'x': case 'X': return parseHexadecimal(); - default: printf("Invalid escape sequence %s found!\n",strToken.data()); + default: printf("Invalid escape sequence %s found!\n",g_strToken.data()); return CPPValue(0L); } } - return CPPValue((long)strToken[1]); + return CPPValue((long)g_strToken[1]); } CPPValue parseFloat() { - return CPPValue(atof(strToken)); + return CPPValue(atof(g_strToken)); } diff --git a/src/cppvalue.h b/src/cppvalue.h index 159e217..def31c9 100644 --- a/src/cppvalue.h +++ b/src/cppvalue.h @@ -24,13 +24,9 @@ class CPPValue { - friend CPPValue parseOctal(); - friend CPPValue parseDecimal(); - friend CPPValue parseHexadecimal(); - friend CPPValue parseCharacter(); - friend CPPValue parseFloat(); - public: + + enum Type { Int, Float }; CPPValue(long val=0) : type(Int) { v.l = val; } @@ -57,4 +53,10 @@ class CPPValue } v; }; +extern CPPValue parseOctal(); +extern CPPValue parseDecimal(); +extern CPPValue parseHexadecimal(); +extern CPPValue parseCharacter(); +extern CPPValue parseFloat(); + #endif diff --git a/src/declinfo.l b/src/declinfo.l index 6a689c0..18e39d8 100644 --- a/src/declinfo.l +++ b/src/declinfo.l @@ -21,7 +21,7 @@ * includes */ #include <stdio.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> diff --git a/src/defargs.l b/src/defargs.l index 68eaa91..ebdb6ad 100644 --- a/src/defargs.l +++ b/src/defargs.l @@ -47,7 +47,7 @@ */ #include "qtbc.h" #include <stdio.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> #include <qregexp.h> diff --git a/src/definition.cpp b/src/definition.cpp index 87f5855..f17d980 100644 --- a/src/definition.cpp +++ b/src/definition.cpp @@ -452,7 +452,11 @@ void Definition::addInnerCompound(Definition *) QCString Definition::qualifiedName() const { //printf("start Definition::qualifiedName()\n"); - if (m_outerScope==0) return m_localName; // TODO: remove this check + if (m_outerScope==0) + { + if (m_localName=="<globalScope>") return ""; + else return m_localName; + } QCString qualifiedName; if (m_outerScope->name()=="<globalScope>") diff --git a/src/definition.h b/src/definition.h index 6136cc6..e881e43 100644 --- a/src/definition.h +++ b/src/definition.h @@ -76,12 +76,12 @@ class Definition void setBriefDescription(const char *b); /*! Returns TRUE iff the definition is documented */ virtual bool hasDocumentation() const; - virtual bool isLinkableInProject() = 0; - virtual bool isLinkable() = 0; + virtual bool isLinkableInProject() const = 0; + virtual bool isLinkable() const = 0; + virtual QCString getReference() const { return m_ref; } bool isReference() const { return !m_ref.isEmpty(); } void setReference(const char *r) { m_ref=r; } - QCString getReference() const { return m_ref; } /*! Add the list of anchors that mark the sections that are found in the * documentation. @@ -22,7 +22,7 @@ */ #include <stdio.h> #include <stdlib.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> @@ -828,7 +828,7 @@ ID [a-z_A-Z][a-z_A-Z0-9]* SCOPENAME (({ID}?{BN}*"::"{BN}*)*)((~{BN}*)?{ID}) SCOPEMASK {ID}?(("::"|"#")?(~)?{ID})+ URLMASK [a-z_A-Z0-9\~\:\?\@\&\%\#\.\-\+\/\=]+ -NONTERM [\{\}\[\]\`\~\@\|\-\+\#\$\/\\\!\%\^\&\*()a-z_A-Z<>0-9] +NONTERM [\{\}\[\]\`\~\@\|\-\+\#\$\/\\\!\%\^\&\*()a-z_A-Z<>0-9\x80-\xff] WORD ({NONTERM}+([^\n\t ]*{NONTERM}+)?)|("\""[^\n\"]"\"") ATTR ({B}+[^>\n]*)? A [aA] diff --git a/src/dot.cpp b/src/dot.cpp index f7be7d5..20666e6 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -176,6 +176,7 @@ static bool isLeaf(ClassDef *cd) return TRUE; } +#if 0 /*! Builds a mapping from formal arguments of class \a tcd to the * actual arguments stored in templSpec. To properly initialize * the mapping with the default template values @@ -320,6 +321,7 @@ static void computeTemplateInstance( actualArg.resize(0); result = 0; } +#endif //-------------------------------------------------------------------- @@ -693,20 +695,24 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path) QListIterator<DotNode> dnli(*m_rootSubgraphs); DotNode *n; + int count=0; for (dnli.toFirst();(n=dnli.current());++dnli) { - QCString baseName="inherit_graph_"; - QCString diskName=n->m_url.copy(); - int i=diskName.find('$'); - if (i!=-1) - { - diskName=diskName.right(diskName.length()-i-1); - } - else /* take the label name as the file name (and strip any template stuff) */ - { - diskName=n->m_label; - } - baseName = convertNameToFile(baseName+diskName); + QCString baseName; + baseName.sprintf("inherit_graph_%d",count++); + //="inherit_graph_"; + //QCString diskName=n->m_url.copy(); + //int i=diskName.find('$'); + //if (i!=-1) + //{ + // diskName=diskName.right(diskName.length()-i-1); + //} + //else /* take the label name as the file name (and strip any template stuff) */ + //{ + // diskName=n->m_label; + //} + //baseName = convertNameToFile(baseName+diskName); + baseName = convertNameToFile(baseName); QCString dotName=baseName+".dot"; QCString gifName=baseName+".gif"; QCString mapName=baseName+".map"; @@ -817,18 +823,9 @@ void DotGfxHierarchyTable::addHierarchy(DotNode *n,ClassDef *cd,bool hideSuper) } } -DotGfxHierarchyTable::DotGfxHierarchyTable() +void DotGfxHierarchyTable::addClassList(ClassSDict *cl) { - m_curNodeNumber=0; - m_rootNodes = new QList<DotNode>; - //m_rootNodes->setAutoDelete(TRUE); // rootNodes owns the nodes - m_usedNodes = new QDict<DotNode>(1009); // virtualNodes only aliases nodes - m_rootSubgraphs = new DotNodeList; - - // build a graph with each class as a node and the inheritance relations - // as edges - initClassHierarchy(&Doxygen::classSDict); - ClassSDict::Iterator cli(Doxygen::classSDict); + ClassSDict::Iterator cli(*cl); ClassDef *cd; for (cli.toLast();(cd=cli.current());--cli) { @@ -857,6 +854,22 @@ DotGfxHierarchyTable::DotGfxHierarchyTable() } } } +} + +DotGfxHierarchyTable::DotGfxHierarchyTable() +{ + m_curNodeNumber=0; + m_rootNodes = new QList<DotNode>; + //m_rootNodes->setAutoDelete(TRUE); // rootNodes owns the nodes + m_usedNodes = new QDict<DotNode>(1009); // virtualNodes only aliases nodes + m_rootSubgraphs = new DotNodeList; + + // build a graph with each class as a node and the inheritance relations + // as edges + initClassHierarchy(&Doxygen::classSDict); + initClassHierarchy(&Doxygen::hiddenClasses); + addClassList(&Doxygen::classSDict); + addClassList(&Doxygen::hiddenClasses); // m_usedNodes now contains all nodes in the graph // color the graph into a set of independent subgraphs @@ -918,8 +931,6 @@ int DotClassGraph::m_curNodeNumber; void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, const char *label,int distance,const char *usedName,const char *templSpec,bool base) { - //printf("DoxClassGraph::addClass(class=%s,parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n", - // cd->name().data(),n->m_label.data(),prot,label,distance,usedName,templSpec,base); int edgeStyle = label ? EdgeInfo::Dashed : EdgeInfo::Solid; QCString className; if (usedName) // name is a typedef @@ -932,8 +943,10 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, } else // just a normal name { - className=cd->name(); + className=cd->displayName(); } + //printf("DotClassGraph::addClass(class=`%s',parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n", + // className.data(),n->m_label.data(),prot,label,distance,usedName,templSpec,base); DotNode *bn = m_usedNodes->find(className); if (bn) // class already inserted { @@ -955,7 +968,10 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, QCString displayName=className; if (Config_getBool("HIDE_SCOPE_NAMES")) displayName=stripScope(displayName); QCString tmp_url; - if (cd->isLinkable()) tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); + if (cd->isLinkable()) + { + tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); + } bn = new DotNode(m_curNodeNumber++, displayName, tmp_url.data(), @@ -973,7 +989,7 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, n->addParent(bn); } m_usedNodes->insert(className,bn); - //printf(" add used node %s of %s\n",cd->name().data(),n->m_label.data()); + //printf(" add new child node `%s' to %s\n",className.data(),n->m_label.data()); if (distance<m_recDepth) buildGraph(cd,bn,distance+1,base); } } @@ -986,23 +1002,25 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) { //printf("-------- inheritance relation %s->%s templ=`%s'\n", // cd->name().data(),bcd->classDef->name().data(),bcd->templSpecifiers.data()); - QCString templSpec; - if (base) templSpec = substituteTemplateSpec( - cd,bcd->templSpecifiers); - ClassDef *acd=0; - QCString actualArg; - computeTemplateInstance(cd,bcd->classDef,templSpec,acd,actualArg); + //QCString templSpec; + //if (base) templSpec = substituteTemplateSpec( + // cd,bcd->templSpecifiers); + //ClassDef *acd=0; + //QCString actualArg; + //computeTemplateInstance(cd,bcd->classDef,templSpec,acd,actualArg); //printf("acd=%p actualArg=%s\n",acd,actualArg.data()); - if (acd) - { - addClass(acd,n,bcd->prot,0,distance,actualArg, - templSpec,base); - } - else - { - addClass(bcd->classDef,n,bcd->prot,0,distance,bcd->usedName, - templSpec,base); - } + //if (acd) + //{ + // addClass(acd,n,bcd->prot,0,distance,actualArg, + // templSpec,base); + //} + //else + //{ + // addClass(bcd->classDef,n,bcd->prot,0,distance,bcd->usedName, + // templSpec,base); + //} + addClass(bcd->classDef,n,bcd->prot,0,distance,bcd->usedName, + bcd->templSpecifiers,base); } if (m_graphType != Inheritance) { @@ -1031,25 +1049,27 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) label+=QCString("\\n")+s; } } - QCString actualArg; - ClassDef *acd=0; + //QCString actualArg; + //ClassDef *acd=0; //printf("-------- usage relation %s->%s templ=`%s'\n", // cd->name().data(),ucd->classDef->name().data(), // ucd->templSpecifiers.data()); - QCString templSpec = substituteTemplateSpec( - cd,ucd->templSpecifiers); - computeTemplateInstance(cd,ucd->classDef, templSpec, acd,actualArg); - if (acd) - { - addClass(acd,n,EdgeInfo::Black,label,distance,actualArg, - templSpec,base); - } - else - { - //printf("Found label=`%s'\n",label.data()); - addClass(ucd->classDef,n,EdgeInfo::Black,label,distance,0, - templSpec,base); - } + //QCString templSpec = substituteTemplateSpec( + // cd,ucd->templSpecifiers); + //computeTemplateInstance(cd,ucd->classDef, templSpec, acd,actualArg); + //if (acd) + //{ + // addClass(acd,n,EdgeInfo::Black,label,distance,actualArg, + // templSpec,base); + //} + //else + //{ + // //printf("Found label=`%s'\n",label.data()); + // addClass(ucd->classDef,n,EdgeInfo::Black,label,distance,0, + // templSpec,base); + //} + addClass(ucd->classDef,n,EdgeInfo::Black,label,distance,0, + ucd->templSpecifiers,base); } } } @@ -1057,17 +1077,17 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) DotClassGraph::DotClassGraph(ClassDef *cd,GraphType t,int maxRecursionDepth) { - //printf("DotGfxUsage::DotGfxUsage %s\n",cd->name().data()); + //printf("--------------- DotClassGraph::DotClassGraph `%s'\n",cd->displayName().data()); m_graphType = t; m_maxDistance = 0; m_recDepth = maxRecursionDepth; QCString tmp_url=""; if (cd->isLinkable()) tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); QCString className = cd->displayName(); - if (cd->templateArguments()) - { - className+=tempArgListToString(cd->templateArguments()); - } + //if (cd->templateArguments()) + //{ + // className+=tempArgListToString(cd->templateArguments()); + //} m_startNode = new DotNode(m_curNodeNumber++, className, tmp_url.data(), @@ -1075,11 +1095,11 @@ DotClassGraph::DotClassGraph(ClassDef *cd,GraphType t,int maxRecursionDepth) TRUE // is a root node ); m_usedNodes = new QDict<DotNode>(1009); - m_usedNodes->insert(cd->name(),m_startNode); + m_usedNodes->insert(className,m_startNode); - ClassSDict::Iterator cli(Doxygen::classSDict); - ClassDef *icd; - for (cli.toFirst();(icd=cli.current());++cli) icd->initTemplateMapping(); + //ClassSDict::Iterator cli(Doxygen::classSDict); + //ClassDef *icd; + //for (cli.toFirst();(icd=cli.current());++cli) icd->initTemplateMapping(); //printf("Root node %s\n",cd->name().data()); if (m_recDepth>0) @@ -24,6 +24,7 @@ class ClassDef; class FileDef; class QTextStream; class DotNodeList; +class ClassSDict; enum GraphOutputFormat { GIF , EPS }; @@ -105,6 +106,7 @@ class DotGfxHierarchyTable private: void addHierarchy(DotNode *n,ClassDef *cd,bool hide); + void addClassList(ClassSDict *cl); QList<DotNode> *m_rootNodes; QDict<DotNode> *m_usedNodes; diff --git a/src/doxygen.cpp b/src/doxygen.cpp index 8d786ad..c7a64eb 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -65,8 +65,10 @@ #define pclose _pclose #endif +static QDict<Entry> classEntries(1009); + ClassSDict Doxygen::classSDict(1009); -ClassList Doxygen::hiddenClasses; +ClassSDict Doxygen::hiddenClasses(257); NamespaceList Doxygen::namespaceList; // all namespaces NamespaceDict Doxygen::namespaceDict(257); @@ -209,7 +211,7 @@ static void addRelatedPage(const char *name,const QCString &ptitle, ) { PageInfo *pi=0; - if ((pi=Doxygen::pageSDict->find(name))) + if ((pi=Doxygen::pageSDict->find(name)) && !tagInfo) { // append documentation block to the page. pi->doc+="\n\n"+doc; @@ -392,7 +394,8 @@ static void addRefItem(int todoId,int testId,int bugId,const char *prefix, static void buildGroupList(Entry *root) { - if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty()) + if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty() && + (Config_getBool("EXTRACT_ALL") || root->tagInfo)) { //printf("Found group %s title=`%s'\n",root->name.data(),root->type.data()); @@ -883,7 +886,6 @@ static void buildClassList(Entry *root) cd->setBriefDescription(root->brief); cd->insertUsedFile(root->fileName); - // add class to the list //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data()); Doxygen::classSDict.inSort(fullName,cd); @@ -1336,6 +1338,7 @@ static MemberDef *addVariableToClass( bool ambig; md->setBodyDef(findFileDef(Doxygen::inputNameDict,root->fileName,ambig)); + //printf("Adding member=%s\n",md->name().data()); // add the member to the global list if (mn) { @@ -1510,6 +1513,7 @@ static MemberDef *addVariableToFile( } } + //printf("Adding member=%s\n",md->name().data()); // add member definition to the list of globals if (mn) { @@ -1911,6 +1915,7 @@ static void buildMemberList(Entry *root) ); // add member to the global list of all members + //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data()); MemberName *mn; if ((mn=Doxygen::memberNameDict[name])) { @@ -1920,7 +1925,6 @@ static void buildMemberList(Entry *root) { mn = new MemberName(name); mn->append(md); - //printf("Adding memberName=%s\n",mn->memberName()); Doxygen::memberNameDict.insert(name,mn); Doxygen::memberNameList.append(mn); } @@ -2109,6 +2113,7 @@ static void buildMemberList(Entry *root) } // add member to the list of file members + //printf("Adding member=%s\n",md->name().data()); MemberName *mn; if ((mn=Doxygen::functionNameDict[name])) { @@ -2343,15 +2348,332 @@ static void replaceNamespaceAliases(QCString &scope,int i) //printf("replaceNamespaceAliases() result=%s\n",scope.data()); } +static QCString resolveTypeDef(const QCString &name) +{ + QCString typeName; + if (!name.isEmpty()) + { + QCString *subst = Doxygen::typedefDict[name]; + if (subst) + { + int count=0; + typeName=*subst; + QCString *newSubst; + while ((newSubst=Doxygen::typedefDict[typeName]) && count<10) + { + if (typeName==*newSubst) break; // prevent lock-up + typeName=*newSubst; + count++; + } + } + } + return typeName; +} + +/*! make a dictionary of all template arguments of class cd + * that are part of the base class name. + * Example: A template class A with template arguments <R,S,T> + * that inherits from B<T,T,S> will have T and S in the dictionary. + */ +static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name) +{ + QDict<int> *templateNames = new QDict<int>(17); + templateNames->setAutoDelete(TRUE); + static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*"); + if (templateArguments) + { + ArgumentListIterator ali(*templateArguments); + Argument *arg; + int count=0; + for (ali.toFirst();(arg=ali.current());++ali,count++) + { + int i,p=0,l; + while ((i=re.match(name,p,&l))!=-1) + { + QCString n = name.mid(i,l); + if (n==arg->name) + { + if (templateNames->find(n)==0) + { + templateNames->insert(n,new int(count)); + } + } + p=i+l; + } + } + } + return templateNames; +} + + +enum FindBaseClassRelation_Mode +{ + TemplateInstances, + DocumentedOnly, + Undocumented +}; -static bool findBaseClassRelation( +static bool findClassRelation( Entry *root, ClassDef *cd, BaseInfo *bi, - int isTemplBaseClass, - bool insertUndocumented + QDict<int> *templateNames, + /*bool insertUndocumented*/ + FindBaseClassRelation_Mode mode, + bool isArtificial + ); + + +static void findUsedClassesForClass(Entry *root, + ClassDef *masterCd, + ClassDef *instanceCd, + bool isArtificial, + ArgumentList *actualArgs=0, + QDict<int> *templateNames=0 + ) +{ + //if (masterCd->visited) return; + masterCd->visited=TRUE; + ArgumentList *formalArgs = masterCd->templateArguments(); + MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict()); + MemberNameInfo *mni; + for (;(mni=mnili.current());++mnili) + { + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for (mnii.toFirst();(mi=mnii.current());++mnii) + { + MemberDef *md=mi->memberDef; + if (md->isVariable()) // for each member variable in this class + { + QCString type=removeRedundantWhiteSpace(md->typeString()); + int pos=0; + QCString usedClassName; + QCString templSpec; + bool found=FALSE; + if (actualArgs) + { + type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs); + } + //printf("extractClassNameFromType(%s)\n",type.data()); + while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)) + { + QCString typeName = resolveTypeDef(usedClassName); + QCString usedName = usedClassName+templSpec; + if (!typeName.isEmpty()) + { + usedName=typeName; + } + //printf("usedName=`%s'\n",usedName.data()); + + bool delTempNames=FALSE; + if (templateNames==0) + { + templateNames = getTemplateArgumentsInName(formalArgs,usedName); + delTempNames=TRUE; + } + BaseInfo bi(usedName,Public,Normal); + findClassRelation(root,instanceCd,&bi,templateNames,TemplateInstances,isArtificial); + + if (masterCd->templateArguments()) + { + ArgumentListIterator ali(*masterCd->templateArguments()); + Argument *arg; + int count=0; + for (ali.toFirst();(arg=ali.current());++ali,++count) + { + if (arg->name==usedName) // type is a template argument + { + found=TRUE; + Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data()); + + ClassDef *usedCd = Doxygen::hiddenClasses.find(usedName); + if (usedCd==0) + { + usedCd = new ClassDef( + masterCd->getDefFileName(),masterCd->getDefLine(), + usedName,ClassDef::Class); + usedCd->setIsTemplateBaseClass(count); + Doxygen::hiddenClasses.inSort(usedName,usedCd); + } + if (isArtificial) usedCd->setClassIsArtificial(); + instanceCd->addUsedClass(usedCd,md->name()); + + //if (m_usesImplClassDict==0) m_usesImplClassDict = new UsesClassDict(257); + //UsesClassDef *ucd = new UsesClassDef(cd); + //m_usesImplClassDict->insert(cd->name(),ucd); + //ucd->templSpecifiers = templSpec; + //ucd->addAccessor(md->name()); + } + } + } + + if (!found) + { + Definition *scope=masterCd->getOuterScope(); + ClassDef *usedCd=0; + do + { + QCString scopeName = scope ? scope->qualifiedName().data() : 0; + if (!scopeName.isEmpty()) + { + usedCd=getResolvedClass(scopeName+"::"+usedName,0,&templSpec); + if (usedCd==0) usedCd=getResolvedClass(scopeName+"::"+usedClassName,0,&templSpec); + //printf("Search for class %s result=%p\n",(scopeName+"::"+usedName).data(),usedCd); + } + else + { + usedCd=getResolvedClass(usedName,0,&templSpec); + if (usedCd==0) usedCd=getResolvedClass(usedClassName,0,&templSpec); + //printf("Search for class %s result=%p\n",usedName.data(),usedCd); + } + if (scope) scope=scope->getOuterScope(); + } while (scope && usedCd==0); + + if (usedCd) + { + found=TRUE; + instanceCd->addUsedClass(usedCd,md->name()); // class exists + } + } + if (delTempNames) + { + delete templateNames; + templateNames=0; + } + } + } + } + } +} + +static void findBaseClassesForClass( + Entry *root, + ClassDef *masterCd, + ClassDef *instanceCd, + FindBaseClassRelation_Mode mode, + bool isArtificial, + ArgumentList *actualArgs=0, + QDict<int> *templateNames=0 + ) +{ + //if (masterCd->visited) return; + masterCd->visited=TRUE; + // The base class could ofcouse also be a non-nested class + ArgumentList *formalArgs = masterCd->templateArguments(); + QListIterator<BaseInfo> bii(*root->extends); + BaseInfo *bi=0; + for (bii.toFirst();(bi=bii.current());++bii) + { + bool delTempNames=FALSE; + if (templateNames==0) + { + templateNames = getTemplateArgumentsInName(formalArgs,bi->name); + delTempNames=TRUE; + } + BaseInfo tbi(bi->name,bi->prot,bi->virt); + if (actualArgs) // substitute the formal template arguments of the base class + { + tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs); + } + + if (mode==DocumentedOnly) + { + // find a documented base class in the correct scope + if (!findClassRelation(root,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial)) + { + // no documented base class -> try to find an undocumented one + findClassRelation(root,instanceCd,&tbi,templateNames,Undocumented,isArtificial); + } + } + else if (mode==TemplateInstances) + { + findClassRelation(root,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial); + } + if (delTempNames) + { + delete templateNames; + templateNames=0; + } + } +} + +//---------------------------------------------------------------------- + +static bool findTemplateInstanceRelation(Entry *root, + ClassDef *templateClass,const QCString &templSpec, + QDict<int> *templateNames, + bool isArtificial) +{ + Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n", + templateClass->name().data(),templSpec.data()); + //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=", + // templateClass->name().data(),templSpec.data()); + //if (templateNames) + //{ + // QDictIterator<int> qdi(*templateNames); + // int *tempArgIndex; + // for (;(tempArgIndex=qdi.current());++qdi) + // { + // printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex); + // } + //} + //printf("\n"); + + bool existingClass = (templSpec==tempArgListToString(templateClass->templateArguments())); + if (existingClass) return TRUE; + + bool freshInstance=FALSE; + ClassDef *instanceClass = templateClass->insertTemplateInstance( + root->fileName,root->startLine,templSpec,freshInstance); + if (isArtificial) instanceClass->setClassIsArtificial(); + + if (freshInstance) + { + Doxygen::classSDict.inSort(instanceClass->name(),instanceClass); + instanceClass->setTemplateBaseClassNames(templateNames); + + // search for new template instances caused by base classes of + // instanceClass + Entry *templateRoot = classEntries.find(templateClass->name()); + + ArgumentList *templArgs = new ArgumentList; + stringToArgumentList(templSpec,templArgs); + findBaseClassesForClass(templateRoot,templateClass,instanceClass, + TemplateInstances,isArtificial,templArgs,templateNames); + + findUsedClassesForClass(templateRoot,templateClass,instanceClass, + isArtificial,templArgs,templateNames); + + //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data()); + //ArgumentList *tl = templateClass->templateArguments(); + } + return TRUE; +} + +static bool findClassRelation( + Entry *root, + ClassDef *cd, + BaseInfo *bi, + QDict<int> *templateNames, + FindBaseClassRelation_Mode mode, + bool isArtificial ) { + //printf("findClassRelation(class=%s base=%s templateNames=", + // cd->name().data(),bi->name.data()); + //if (templateNames) + //{ + // QDictIterator<int> qdi(*templateNames); + // int *tempArgIndex; + // for (;(tempArgIndex=qdi.current());++qdi) + // { + // printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex); + // } + //} + //printf("\n"); + + Entry *parentNode=root->parent; bool lastParent=FALSE; do // for each parent scope, starting with the largest scope @@ -2377,8 +2699,9 @@ static bool findBaseClassRelation( // baseClass?baseClass->name().data():"<none>", // templSpec.data() // ); - if (baseClassName!=root->name) // check for base class with the same name, - // look in the outer scope for a match + if (baseClassName!=root->name) // Check for base class with the same name. + // If found then look in the outer scope for a match + // and prevent recursion. { Debug::print( Debug::Classes,0," class relation %s inherited by %s found (%s and %s)\n", @@ -2420,7 +2743,7 @@ static bool findBaseClassRelation( } } - bool found=baseClass!=0 && baseClass!=cd; + bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances); NamespaceDef *nd=cd->getNamespaceDef(); if (!found && (i=baseClassName.findRev("::"))!=-1) { @@ -2520,25 +2843,60 @@ static bool findBaseClassRelation( } } } - if (isTemplBaseClass==-1 && found) + bool isATemplateArgument = templateNames!=0 && templateNames->find(bi->name)!=0; + if (!isATemplateArgument && found) { Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",bi->name.data(),templSpec.data()); // add base class to this class - QCString usedName; - if (baseClassIsTypeDef) usedName=bi->name; - cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec); - // add this class as super class to the base class - baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); + + // if templSpec is not empty then we should "instantiate" + // the template baseClass. A new ClassDef should be created + // to represent the instance. To be able to add the (instantiated) + // members and documentation of a template class + // (inserted in that template class at a later stage), + // the template should know about its instances. + // the instantiation process, should be done in a recursive way, + // since instantiating a template may introduce new inheritance + // relations. + if (!templSpec.isEmpty() && mode==TemplateInstances) + { + findTemplateInstanceRelation(root,baseClass,templSpec,templateNames,isArtificial); + } + else if (mode==DocumentedOnly) + { + QCString usedName; + if (baseClassIsTypeDef) usedName=bi->name; + cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec); + // add this class as super class to the base class + baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); + } return TRUE; } - else if ((scopeOffset==0 && insertUndocumented) || isTemplBaseClass!=-1) + else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument)) { Debug::print(Debug::Classes,0, - " Undocumented base class `%s' baseClassName=%s\n", + " New undocumented base class `%s' baseClassName=%s\n", bi->name.data(),baseClassName.data() ); - baseClass=new ClassDef(root->fileName,root->startLine, + baseClass=0; + if (isATemplateArgument) + { + baseClass=Doxygen::hiddenClasses.find(baseClassName); + if (baseClass==0) + { + baseClass=new ClassDef(root->fileName,root->startLine, baseClassName,ClassDef::Class); + Doxygen::hiddenClasses.inSort(baseClassName,baseClass); + if (isArtificial) baseClass->setClassIsArtificial(); + } + } + else + { + baseClass=new ClassDef(root->fileName,root->startLine, + baseClassName,ClassDef::Class); + Doxygen::classSDict.inSort(baseClassName,baseClass); + if (isArtificial) baseClass->setClassIsArtificial(); + } // add base class to this class cd->insertBaseClass(baseClass,bi->name,bi->prot,bi->virt,templSpec); // add this class as super class to the base class @@ -2547,15 +2905,16 @@ static bool findBaseClassRelation( baseClass->insertUsedFile(root->fileName); // is this an inherited template argument? //printf("%s->setIsTemplateBaseClass(%d)\n",baseClass->name().data(),isTemplBaseClass); - baseClass->setIsTemplateBaseClass(isTemplBaseClass); + if (isATemplateArgument) + { + baseClass->setIsTemplateBaseClass(*templateNames->find(bi->name)); + } // add class to the list - if (isTemplBaseClass==-1) + if (!isATemplateArgument) { - Doxygen::classSDict.inSort(baseClassName,baseClass); } else { - Doxygen::hiddenClasses.append(baseClass); } return TRUE; } @@ -2591,23 +2950,54 @@ static bool findBaseClassRelation( //---------------------------------------------------------------------- // Computes the base and super classes for each class in the tree -static void computeClassRelations(Entry *root) +static bool isClassSection(Entry *root) { - if ( + return + ( ( - ( - // is it a compound (class, struct, union, interface ...) - root->section & Entry::COMPOUND_MASK - ) - || - ( - // is it a documentation block with inheritance info. - (root->section & Entry::COMPOUNDDOC_MASK) && root->extends->count()>0 - ) + ( + // is it a compound (class, struct, union, interface ...) + root->section & Entry::COMPOUND_MASK + ) + || + ( + // is it a documentation block with inheritance info. + (root->section & Entry::COMPOUNDDOC_MASK) && root->extends->count()>0 + ) ) - && - !root->name.isEmpty() // sanity check - ) + && !root->name.isEmpty() // sanity check + ); +} + + +/*! Builds a dictionary of all entry nodes in the tree starting with \a root + */ +static void findClassEntries(Entry *root) +{ + if (isClassSection(root)) + { + classEntries.insert(root->name,root); + } + EntryListIterator eli(*root->sublist); + Entry *e; + for (;(e=eli.current());++eli) + { + findClassEntries(e); + } +} + +/*! Using the dictionary build by findClassEntries(), this + * function will look for additional template specialization that + * exists as inheritance relations only. These instances will be + * added to the template they are derived from. + */ +static void findInheritedTemplateInstances() +{ + ClassSDict::Iterator cli(Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + QDictIterator<Entry> edi(classEntries); + Entry *root; + for (;(root=edi.current());++edi) { ClassDef *cd; // strip any annonymous scopes first @@ -2616,61 +3006,133 @@ static void computeClassRelations(Entry *root) if ((cd=getClass(bName))) { //printf("Class %s %d\n",cd->name().data(),root->extends->count()); - if (!cd->visited) // check integrity of the tree + findBaseClassesForClass(root,cd,cd,TemplateInstances,FALSE); + } + } +} + +static void findUsedTemplateInstances() +{ + ClassSDict::Iterator cli(Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + QDictIterator<Entry> edi(classEntries); + Entry *root; + for (;(root=edi.current());++edi) + { + ClassDef *cd; + // strip any annonymous scopes first + QCString bName=stripAnonymousNamespaceScope(root->name); + Debug::print(Debug::Classes,0," Class %s : \n",bName.data()); + if ((cd=getClass(bName))) + { + findUsedClassesForClass(root,cd,cd,TRUE); + } + } +} + +static void computeClassRelations() +{ + ClassSDict::Iterator cli(Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + QDictIterator<Entry> edi(classEntries); + Entry *root; + for (;(root=edi.current());++edi) + { + ClassDef *cd; + // strip any annonymous scopes first + QCString bName=stripAnonymousNamespaceScope(root->name); + Debug::print(Debug::Classes,0," Class %s : \n",bName.data()); + if ((cd=getClass(bName))) + { + findBaseClassesForClass(root,cd,cd,DocumentedOnly,FALSE); + } + else if (bName.right(2)!="::") + { + if (!root->name.isEmpty() && root->name[0]!='@') + warn_undoc( + root->fileName,root->startLine, + "Warning: Compound %s is not documented.", + root->name.data() + ); + } + } +} + +static void computeTemplateClassRelations() +{ + QDictIterator<Entry> edi(classEntries); + Entry *root; + for (;(root=edi.current());++edi) + { + QCString bName=stripAnonymousNamespaceScope(root->name); + ClassDef *cd=getClass(bName); + // strip any annonymous scopes first + QDict<ClassDef> *templInstances = 0; + if (cd && (templInstances=cd->getTemplateInstances())) + { + Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data()); + QDictIterator<ClassDef> tdi(*templInstances); + ClassDef *tcd; + for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance { - cd->visited=TRUE; // mark class as used - if (root->extends->count()>0) // there are base classes + Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data()); + //QCString templName = tcd->name(); + //int index = templName.find('<'); + //ASSERT(index!=-1); + // templName.right(templName.length()-index); + QCString templSpec = tdi.currentKey().data(); + ArgumentList *templArgs = new ArgumentList; + stringToArgumentList(templSpec,templArgs); + QList<BaseInfo> *baseList=root->extends; + BaseInfo *bi=baseList->first(); + while (bi) // for each base class of the template { - - // The base class could ofcouse also be a non-nested class - QList<BaseInfo> *baseList=root->extends; - BaseInfo *bi=baseList->first(); - while (bi) // for each base class + // check if the base class is a template argument + BaseInfo tbi(bi->name,bi->prot,bi->virt); + ArgumentList *tl = cd->templateArguments(); + if (tl) { - // check if the base class is a template argument - int isTemplBaseClass = -1; - ArgumentList *tl = cd->templateArguments(); - if (tl) + QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames(); + QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name); + // for each template name that we inherit from we need to + // substitute the formal with the actual arguments + QDict<int> *actualTemplateNames = new QDict<int>(17); + actualTemplateNames->setAutoDelete(TRUE); + QDictIterator<int> qdi(*templateNames); + for (qdi.toFirst();qdi.current();++qdi) { - ArgumentListIterator ali(*tl); - Argument *arg; - int count=0; - for (ali.toFirst();(arg=ali.current());++ali,++count) + int templIndex = *qdi.current(); + Argument *actArg = 0; + if (templIndex<(int)templArgs->count()) { - if (arg->name==bi->name) // base class is a template argument - { - isTemplBaseClass = count; - break; - } + actArg=templArgs->at(templIndex); + } + if (actArg!=0 && + baseClassNames!=0 && + baseClassNames->find(actArg->type)!=0 && + actualTemplateNames->find(actArg->type)==0 + ) + { + actualTemplateNames->insert(actArg->type,new int(templIndex)); } } + delete templateNames; + + tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs); // find a documented base class in the correct scope - if (!findBaseClassRelation(root,cd,bi,isTemplBaseClass,FALSE)) + if (!findClassRelation(root,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE)) { // no documented base class -> try to find an undocumented one - findBaseClassRelation(root,cd,bi,isTemplBaseClass,TRUE); + findClassRelation(root,tcd,&tbi,actualTemplateNames,Undocumented,FALSE); } - bi=baseList->next(); + delete actualTemplateNames; } - } // class has no base classes - } // else class is already found - } - else if (bName.right(2)!="::") - { - if (!root->name.isEmpty() && root->name[0]!='@') - warn_undoc( - root->fileName,root->startLine, - "Warning: Compound %s is not documented.", - root->name.data() - ); + bi=baseList->next(); + } + delete templArgs; + } // class has no base classes } } - EntryListIterator eli(*root->sublist); - Entry *e; - for (;(e=eli.current());++eli) - { - computeClassRelations(e); - } } //----------------------------------------------------------------------- @@ -2800,7 +3262,6 @@ static void addTodoTestBugReferences() if (d) scopeName=d->name(); if (d==0) d=md->getGroupDef(); if (d==0) d=md->getFileDef(); - // TODO: i18n this QCString memLabel; if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C")) { @@ -2994,7 +3455,7 @@ static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, { cl=nd->getUsedClasses(); } - else + else if (fd) { cl=fd->getUsedClasses(); } @@ -3629,7 +4090,7 @@ static void findMember(Entry *root, if (!isRelated && mn) // function name already found { Debug::print(Debug::FindMembers,0, - "2. member name exists \n"); + "2. member name exists (%d members with this name)\n",mn->count()); if (!className.isEmpty()) // class name is valid { int count=0; @@ -3637,9 +4098,11 @@ static void findMember(Entry *root, MemberDef *md; for (mni.toFirst();(md=mni.current());++mni) { - Debug::print(Debug::FindMembers,0, - "3. member definition found scopeName=`%s'\n",scopeName.data()); ClassDef *cd=md->getClassDef(); + Debug::print(Debug::FindMembers,0, + "3. member definition found scope needed=`%s' scope=`%s' args=`%s'\n", + scopeName.data(),cd ? cd->name().data() : "<none>", + md->argsString()); //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data()); ClassDef *tcd=0; @@ -3773,6 +4236,7 @@ static void findMember(Entry *root, // root->inLine,md->isInline()); addMemberDocs(root,md,funcDecl,0,overloaded,nl); count++; + break; } } } @@ -3985,9 +4449,9 @@ static void findMember(Entry *root, cd->insertUsedFile(root->fileName); md->setRefItems(root->todoId,root->testId,root->bugId); addMemberToGroups(root,md); + //printf("Adding member=%s\n",md->name().data()); if (newMemberName) { - //printf("Adding memberName=%s\n",mn->memberName()); Doxygen::memberNameList.append(mn); Doxygen::memberNameDict.insert(funcName,mn); } @@ -4077,14 +4541,7 @@ static void findMemberDocumentation(Entry *root) compoundKeywordDict.find(root->type)==0 // that is not a keyword // (to skip forward declaration of class etc.) ) - ) /* - && (!root->stat && !root->parent) // not static & global: TODO: fix this hack! - && ( - !root->doc.isEmpty() || // has detailed docs - !root->brief.isEmpty() || // has brief docs - (root->memSpec&Entry::Inline) || // is inline - root->mGrpId!=-1 || // is part of a group - ) */ + ) ) { //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n", @@ -4261,6 +4718,7 @@ static void findEnums(Entry *root) md->setDocumentation(root->doc); md->setBriefDescription(root->brief); + //printf("Adding member=%s\n",md->name().data()); MemberName *mn; if ((mn=(*mnd)[name])) { @@ -4545,13 +5003,37 @@ static void computeMemberRelations() //---------------------------------------------------------------------------- -static void computeClassImplUsageRelations() +//static void computeClassImplUsageRelations() +//{ +// ClassDef *cd; +// ClassSDict::Iterator cli(Doxygen::classSDict); +// for (;(cd=cli.current());++cli) +// { +// cd->determineImplUsageRelation(); +// } +//} + +//---------------------------------------------------------------------------- + +static void createTemplateInstanceMembers() { - ClassDef *cd; ClassSDict::Iterator cli(Doxygen::classSDict); - for (;(cd=cli.current());++cli) + ClassDef *cd; + // for each class + for (cli.toFirst();(cd=cli.current());++cli) { - cd->determineImplUsageRelation(); + // that is a template + QDict<ClassDef> *templInstances = cd->getTemplateInstances(); + if (templInstances) + { + QDictIterator<ClassDef> qdi(*templInstances); + ClassDef *tcd=0; + // for each instance of the template + for (qdi.toFirst();(tcd=qdi.current());++qdi) + { + tcd->addMembersToTemplateInstance(cd,qdi.currentKey().data()); + } + } } } @@ -4747,8 +5229,8 @@ static void generateClassDocs() for ( ; cli.current() ; ++cli ) { ClassDef *cd=cli.current(); - if ( cd->isLinkableInProject() ) - // skip external references and anonymous compounds + if ( cd->isLinkableInProject() && cd->templateMaster()==0 ) + // skip external references, anonymous compounds and template instances { msg("Generating docs for compound %s...\n",cd->name().data()); @@ -4892,6 +5374,7 @@ static void findDefineDocumentation(Entry *root) FileDef *fd=findFileDef(Doxygen::inputNameDict,filePathName,ambig); //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd); md->setFileDef(fd); + //printf("Adding member=%s\n",md->name().data()); MemberName *mn; if ((mn=Doxygen::functionNameDict[root->name])) { @@ -6592,8 +7075,24 @@ void parseInput() msg("Searching for documented defines...\n"); findDefineDocumentation(root); - msg("Computing class relations...\n"); - computeClassRelations(root); + msg("Computing template instances..."); + findClassEntries(root); + findInheritedTemplateInstances(); + findUsedTemplateInstances(); + + msg("Creating members for template instances...\n"); + createTemplateInstanceMembers(); + + //if (Config_getBool("HAVE_DOT") && Config_getBool("COLLABORATION_GRAPH")) + //{ + // msg("Computing class implementation usage relations...\n"); + // computeClassImplUsageRelations(); + //} + + msg("Computing class relations..."); + computeTemplateClassRelations(); + computeClassRelations(); + classEntries.clear(); msg("Searching for enumerations...\n"); findEnums(root); @@ -6631,12 +7130,6 @@ void parseInput() msg("Adding classes to their packages...\n"); addClassesToPackages(); - if (Config_getBool("HAVE_DOT") && Config_getBool("COLLABORATION_GRAPH")) - { - msg("Computing class implementation usage relations...\n"); - computeClassImplUsageRelations(); - } - msg("Adding members to member groups.\n"); addMembersToMemberGroup(); diff --git a/src/doxygen.h b/src/doxygen.h index f81241a..47310b8 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -59,7 +59,7 @@ class Doxygen { public: static ClassSDict classSDict; - static ClassList hiddenClasses; + static ClassSDict hiddenClasses; static PageSDict *exampleSDict; static PageSDict *pageSDict; static PageInfo *mainPage; diff --git a/src/filedef.h b/src/filedef.h index 2bdbbcf..79525b0 100644 --- a/src/filedef.h +++ b/src/filedef.h @@ -110,12 +110,12 @@ class FileDef : public Definition /*! Returns the absolute path of this file. */ QCString getPath() const { return path; } - bool isLinkableInProject() + bool isLinkableInProject() const { return hasDocumentation() && !isReference(); } - bool isLinkable() + bool isLinkable() const { return isLinkableInProject() || isReference(); } diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp index 38c2e72..a49ff2f 100644 --- a/src/ftvhelp.cpp +++ b/src/ftvhelp.cpp @@ -311,13 +311,14 @@ static void generateFolderTreeViewData() QTextStream t(&f); t << "<html><head>" << endl; t << "<link rel=\"stylesheet\" href=\""; - if (Config_getString("HTML_STYLESHEET").isEmpty()) + QCString cssname=Config_getString("HTML_STYLESHEET"); + if (cssname.isEmpty()) { t << "doxygen.css"; } else { - QFileInfo cssfi(Config_getString("HTML_STYLESHEET")); + QFileInfo cssfi(cssname); if (!cssfi.exists()) { err("Error: user specified HTML style sheet file does not exist!\n"); diff --git a/src/groupdef.h b/src/groupdef.h index c2d413a..b4a446e 100644 --- a/src/groupdef.h +++ b/src/groupdef.h @@ -62,11 +62,11 @@ class GroupDef : public Definition bool containsGroup(const GroupDef *def); // true if def is already a subgroup void writeDocumentation(OutputList &ol); int countMembers() const; - bool isLinkableInProject() + bool isLinkableInProject() const { return hasDocumentation() && !isReference(); } - bool isLinkable() + bool isLinkable() const { return isLinkableInProject() || isReference(); } diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp index 0c82986..57ce664 100644 --- a/src/htmlgen.cpp +++ b/src/htmlgen.cpp @@ -46,10 +46,10 @@ static const char *defaultStyleSheet = "A.codeRef { font-weight: normal; color: #4444ee }\n" "DL.el { margin-left: -1cm }\n" "DIV.fragment { width: 100%; border: none; background-color: #eeeeee }\n" - "DIV.ah { background-color: black; margin-bottom: 3; margin-top: 3 }\n" + "DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }\n" "TD.md { background-color: #f2f2ff }\n" - "DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold }\n" - "DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller }\n" + "DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold }\n" + "DIV.groupText { margin-left: 16px; font-style: italic; font-size: smaller }\n" "FONT.keyword { color: #008000 }\n" "FONT.keywordtype { color: #604020 }\n" "FONT.keywordflow { color: #e08000 }\n" @@ -80,13 +80,14 @@ void HtmlGenerator::append(const OutputGenerator *g) void HtmlGenerator::init() { - QDir d(Config_getString("HTML_OUTPUT")); - if (!d.exists() && !d.mkdir(Config_getString("HTML_OUTPUT"))) + QCString dname=Config_getString("HTML_OUTPUT"); + QDir d(dname); + if (!d.exists() && !d.mkdir(dname)) { - err("Could not create output directory %s\n",Config_getString("HTML_OUTPUT").data()); + err("Could not create output directory %s\n",dname.data()); exit(1); } - writeLogo(Config_getString("HTML_OUTPUT")); + writeLogo(dname); if (!Config_getString("HTML_HEADER").isEmpty()) g_header=fileToString(Config_getString("HTML_HEADER")); if (!Config_getString("HTML_FOOTER").isEmpty()) g_footer=fileToString(Config_getString("HTML_FOOTER")); } @@ -117,7 +118,8 @@ static void writeDefaultHeaderFile(QTextStream &t,const char *title, } else { - QFileInfo cssfi(Config_getString("HTML_STYLESHEET")); + QCString cssname=Config_getString("HTML_STYLESHEET"); + QFileInfo cssfi(cssname); if (!cssfi.exists()) { err("Error: user specified HTML style sheet file does not exist!\n"); @@ -278,7 +280,8 @@ void HtmlGenerator::writeStyleInfo(int part) } else // write user defined style sheet { - QFileInfo cssfi(Config_getString("HTML_STYLESHEET")); + QCString cssname=Config_getString("HTML_STYLESHEET"); + QFileInfo cssfi(cssname); if (!cssfi.exists() || !cssfi.isFile() || !cssfi.isReadable()) { err("Error: style sheet %s does not exist or is not readable!", Config_getString("HTML_STYLESHEET").data()); @@ -286,7 +289,7 @@ void HtmlGenerator::writeStyleInfo(int part) else { startPlainFile(cssfi.fileName()); - t << fileToString(Config_getString("HTML_STYLESHEET")); + t << fileToString(cssname); endPlainFile(); } } @@ -813,7 +816,7 @@ void HtmlGenerator::endIndexList() void HtmlGenerator::startAlphabeticalIndexList() { - t << "<table align=center width=\"95%\" border=0 cellspacing=0 cellpadding=0>" << endl; + t << "<table align=center width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">" << endl; } void HtmlGenerator::endAlphabeticalIndexList() @@ -823,8 +826,8 @@ void HtmlGenerator::endAlphabeticalIndexList() void HtmlGenerator::writeIndexHeading(const char *s) { - t << "<div class=\"ah\"><font color=\"white\"><b> " << s - << " </b></font></div>"; + t << "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td><div class=\"ah\"> " << s + << " </td</tr></table>"; } void HtmlGenerator::startImage(const char *name,const char *,bool hasCaption) diff --git a/src/index.cpp b/src/index.cpp index 9ce2f94..97957fe 100644 --- a/src/index.cpp +++ b/src/index.cpp @@ -356,6 +356,7 @@ void writeClassTree(OutputList &ol,BaseClassList *bcl,bool hideSuper) bool hasChildren = !cd->visited && !hideSuper && cd->subClasses()->count()>0; if (cd->isLinkable()) { + //printf("Writing class %s\n",cd->displayName().data()); ol.writeIndexItem(cd->getReference(),cd->getOutputFileBase(),cd->displayName()); if (cd->isReference()) { @@ -518,10 +519,8 @@ void writeClassTree(ClassSDict *d) //---------------------------------------------------------------------------- -void writeClassHierarchy(OutputList &ol) +static void writeClassTreeForList(OutputList &ol,ClassSDict *cl,bool &started) { - initClassHierarchy(&Doxygen::classSDict); - HtmlHelp *htmlHelp=0; FTVHelp *ftvHelp=0; bool &generateHtml = Config_getBool("GENERATE_HTML") ; @@ -536,8 +535,7 @@ void writeClassHierarchy(OutputList &ol) ftvHelp = FTVHelp::getInstance(); } - bool started=FALSE; - ClassSDict::Iterator cli(Doxygen::classSDict); + ClassSDict::Iterator cli(*cl); for (;cli.current(); ++cli) { ClassDef *cd=cli.current(); @@ -560,7 +558,7 @@ void writeClassHierarchy(OutputList &ol) bool hasChildren = !cd->visited && cd->subClasses()->count()>0; if (cd->isLinkable()) { - //printf("Writing class %s\n",cd->name().data()); + //printf("Writing class %s\n",cd->displayName().data()); ol.writeIndexItem(cd->getReference(),cd->getOutputFileBase(),cd->displayName()); if (cd->isReference()) { @@ -597,6 +595,30 @@ void writeClassHierarchy(OutputList &ol) } } } +} + +void writeClassHierarchy(OutputList &ol) +{ + HtmlHelp *htmlHelp=0; + FTVHelp *ftvHelp=0; + bool &generateHtml = Config_getBool("GENERATE_HTML") ; + bool hasHtmlHelp = generateHtml && Config_getBool("GENERATE_HTMLHELP"); + bool hasFtvHelp = generateHtml && Config_getBool("GENERATE_TREEVIEW"); + if (hasHtmlHelp) + { + htmlHelp = HtmlHelp::getInstance(); + } + if (hasFtvHelp) + { + ftvHelp = FTVHelp::getInstance(); + } + + initClassHierarchy(&Doxygen::classSDict); + initClassHierarchy(&Doxygen::hiddenClasses); + + bool started=FALSE; + writeClassTreeForList(ol,&Doxygen::classSDict,started); + writeClassTreeForList(ol,&Doxygen::hiddenClasses,started); if (started) { ol.endIndexList(); @@ -1062,7 +1084,7 @@ int countAnnotatedClasses() ClassDef *cd; for (;(cd=cli.current());++cli) { - if (cd->isLinkableInProject()) + if (cd->isLinkableInProject() && cd->templateMaster()==0) { //printf("Annotated class %s\n",cd->name().data()); count++; @@ -1085,7 +1107,7 @@ void writeAnnotatedClassList(OutputList &ol) ClassDef *cd; for (;(cd=cli.current());++cli) { - if (cd->isLinkableInProject()) + if (cd->isLinkableInProject() && cd->templateMaster()==0) { QCString type=cd->compoundTypeString(); ol.writeStartAnnoItem(type,cd->getOutputFileBase(),0,cd->displayName()); @@ -1168,7 +1190,7 @@ void writeAlphabeticalClassList(OutputList &ol) int headerItems=0; for (;(cd=cli.current());++cli) { - if (cd->isLinkableInProject()) + if (cd->isLinkableInProject() && cd->templateMaster()==0) { int index = getPrefixIndex(cd->name()); if (toupper(cd->name().at(index))!=startLetter) // new begin letter => new header @@ -1201,7 +1223,7 @@ void writeAlphabeticalClassList(OutputList &ol) startLetter=0; for (cli.toFirst();(cd=cli.current());++cli) { - if (cd->isLinkableInProject()) + if (cd->isLinkableInProject() && cd->templateMaster()==0) { int index = getPrefixIndex(cd->name()); if (toupper(cd->name().at(index))!=startLetter) @@ -1443,7 +1465,7 @@ void writeMemberList(OutputList &ol,bool useSections) if ( md->isLinkableInProject() && (cd=md->getClassDef()) && - cd->isLinkableInProject() + cd->isLinkableInProject() && cd->templateMaster()==0 ) { found=TRUE; @@ -1489,7 +1511,7 @@ void writeMemberList(OutputList &ol,bool useSections) if ( md->isLinkableInProject() && prevName!=cd->displayName() && - cd->isLinkableInProject() + cd->isLinkableInProject() && cd->templateMaster()==0 ) { if (count==0) @@ -2632,6 +2654,26 @@ void writeIndex(OutputList &ol) if (Doxygen::mainPage) { parseDoc(ol,defFileName,defLine,0,0,Doxygen::mainPage->doc); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <compound kind=\"page\">" << endl + << " <filename>" + << convertToXML(Doxygen::mainPage->fileName) + << "</filename>" + << endl + << " <title>" + << convertToXML(Doxygen::mainPage->title) + << "</title>" + << endl + << " <name>" + << convertToXML(Doxygen::mainPage->name) + << "</name>" + << endl; + + Doxygen::mainPage->writeDocAnchorsToTagFile(); + Doxygen::tagFile << " </compound>" << endl; + } } endFile(ol); diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in index 319cf3a..c86e343 100644 --- a/src/libdoxygen.pro.in +++ b/src/libdoxygen.pro.in @@ -139,6 +139,7 @@ SOURCES = ce_lex.cpp \ searchindex.cpp \ suffixtree.cpp \ tagreader.cpp \ + translator.cpp \ util.cpp \ version.cpp diff --git a/src/memberdef.cpp b/src/memberdef.cpp index 3a26976..bcefdf7 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -309,6 +309,7 @@ MemberDef::MemberDef(const char *df,int dl, { argList=0; } + m_templateMaster=0; } /*! Destroys the member definition. */ @@ -361,7 +362,11 @@ bool MemberDef::hasExamples() QCString MemberDef::getOutputFileBase() const { - if (classDef) + if (m_templateMaster) + { + return m_templateMaster->getOutputFileBase(); + } + else if (classDef) { return classDef->getOutputFileBase(); } @@ -570,6 +575,7 @@ void MemberDef::writeDeclaration(OutputList &ol, Doxygen::tagFile << "\" static=\"yes"; } Doxygen::tagFile << "\">" << endl; + Doxygen::tagFile << " <type>" << convertToXML(typeString()) << "</type>" << endl; Doxygen::tagFile << " <name>" << convertToXML(name()) << "</name>" << endl; Doxygen::tagFile << " <anchor>" << convertToXML(anchor()) << "</anchor>" << endl; Doxygen::tagFile << " <arglist>" << convertToXML(argsString()) << "</arglist>" << endl; @@ -963,7 +969,7 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol, linkifyText(TextGeneratorOLImpl(ol),scopeName,name(),ldef.right(ldef.length()-ei)); } } - else + else // not an enum value { ol.startDoxyAnchor(cfname,cname,anchor(),doxyName); ol.startMemberDoc(cname,name(),anchor(),name()); @@ -998,7 +1004,6 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol, if (cd) { QCString cName=cd->name(); - //printf("cName=%s\n",cName.data()); int il=cName.find('<'); int ir=cName.findRev('>'); if (il!=-1 && ir!=-1 && ir>il) @@ -1273,11 +1278,16 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol, parseText(ol,reimplFromLine.left(markerPos)); //text left from marker if (bmd->isLinkable()) // replace marker with link { - ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + Definition *bd=bmd->group; + if (bd==0) bd=bcd; + ol.writeObjectLink(bd->getReference(),bd->getOutputFileBase(), bmd->anchor(),bcd->name()); - if ( bcd->isLinkableInProject()/* && !Config_getBool("PDF_HYPERLINKS")*/ ) + + //ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + // bmd->anchor(),bcd->name()); + if ( bd->isLinkableInProject() ) { - writePageRef(ol,bcd->getOutputFileBase(),bmd->anchor()); + writePageRef(ol,bd->getOutputFileBase(),bmd->anchor()); } } else @@ -1348,11 +1358,17 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol, if (ok && bcd && bmd) // write link for marker { - ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + //ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + // bmd->anchor(),bcd->name()); + Definition* bd; + if (bmd->group) bd=bmd->group; else bd=bcd; + + ol.writeObjectLink(bd->getReference(),bd->getOutputFileBase(), bmd->anchor(),bcd->name()); - if (bcd->isLinkableInProject()/* && !Config_getBool("PDF_HYPERLINKS")*/ ) + + if (bd->isLinkableInProject() ) { - writePageRef(ol,bcd->getOutputFileBase(),bmd->anchor()); + writePageRef(ol,bd->getOutputFileBase(),bmd->anchor()); } } ++mli; @@ -1415,7 +1431,7 @@ void MemberDef::warnIfUndocumented() } -bool MemberDef::isLinkableInProject() +bool MemberDef::isLinkableInProject() const { return !name().isEmpty() && name().at(0)!='@' && ((hasDocumentation() && !isReference()) @@ -1424,7 +1440,7 @@ bool MemberDef::isLinkableInProject() (classDef!=0 || Config_getBool("EXTRACT_STATIC") || !isStatic()); // not a static file/namespace member } -bool MemberDef::isLinkable() +bool MemberDef::isLinkable() const { return isLinkableInProject() || isReference(); } @@ -1515,3 +1531,35 @@ void MemberDef::setNamespace(NamespaceDef *nd) setOuterScope(nd); } +MemberDef *MemberDef::createTemplateInstanceMember( + ArgumentList *formalArgs,ArgumentList *actualArgs) +{ + //printf(" Member %s %s %s\n",typeString(),name().data(),argsString()); + ArgumentList *actualArgList = 0; + if (argList) + { + actualArgList = new ArgumentList; + ArgumentListIterator ali(*argList); + Argument *arg; + for (;(arg=ali.current());++ali) + { + Argument *actArg = new Argument(*arg); + actArg->type = substituteTemplateArgumentsInString(actArg->type,formalArgs,actualArgs); + actualArgList->append(actArg); + } + } + + MemberDef *imd = new MemberDef( + getDefFileName(),getDefLine(), + substituteTemplateArgumentsInString(type,formalArgs,actualArgs), + name(), + substituteTemplateArgumentsInString(args,formalArgs,actualArgs), + exception, prot, + virt, stat, related, mtype, 0, 0 + ); + imd->argList = actualArgList; + imd->def = substituteTemplateArgumentsInString(def,formalArgs,actualArgs); + // TODO: init other member variables. + return imd; +} + diff --git a/src/memberdef.h b/src/memberdef.h index bf40f1b..5a2e279 100644 --- a/src/memberdef.h +++ b/src/memberdef.h @@ -35,6 +35,7 @@ class ExampleSDict; class OutputList; class GroupDef; class QTextStream; +class ArgumentList; struct SourceReference { @@ -121,8 +122,8 @@ class MemberDef : public Definition bool isExternal() const { return explExt; } // output info - bool isLinkableInProject(); - bool isLinkable(); + bool isLinkableInProject() const; + bool isLinkable() const; bool hasDocumentation() const; // overrides hasDocumentation in definition.h bool isBriefSectionVisible() const; bool isDetailedSectionVisible(bool inGroup=FALSE) const; @@ -219,10 +220,15 @@ class MemberDef : public Definition int indentDepth() { return indDepth; } bool visibleMemberGroup(bool hideNoHeader); + MemberDef *templateMaster() const { return m_templateMaster; } QCString getScopeString() const; ClassDef *getClassDefOfAnonymousType(); + MemberDef *createTemplateInstanceMember(ArgumentList *formalArgs, + ArgumentList *actualArgs); + void setTemplateMaster(MemberDef *mt) { m_templateMaster=mt; } + private: ClassDef *classDef; // member of or related to @@ -285,7 +291,7 @@ class MemberDef : public Definition QCString groupFileName; // file where this grouping was defined int groupStartLine; // line " " " " " bool groupHasDocs; // true if the entry that caused the grouping was documented - + MemberDef *m_templateMaster; // disable copying of member defs diff --git a/src/namespacedef.h b/src/namespacedef.h index bcfee88..514d250 100644 --- a/src/namespacedef.h +++ b/src/namespacedef.h @@ -57,14 +57,14 @@ class NamespaceDef : public Definition void addUsingDeclaration(ClassDef *cd); ClassList *getUsedClasses() const { return usingDeclList; } - bool isLinkableInProject() + bool isLinkableInProject() const { int i = name().findRev("::"); if (i==-1) i=0; else i+=2; return !name().isEmpty() && name().at(i)!='@' && hasDocumentation() && !isReference(); } - bool isLinkable() + bool isLinkable() const { return isLinkableInProject() || isReference(); } diff --git a/src/packagedef.h b/src/packagedef.h index fbaefa5..945b229 100644 --- a/src/packagedef.h +++ b/src/packagedef.h @@ -38,11 +38,11 @@ class PackageDef : public Definition QCString getOutputFileBase() const ; void addClass(const ClassDef *def); void writeDocumentation(OutputList &ol); - bool isLinkableInProject() + bool isLinkableInProject() const { return hasDocumentation() && !isReference(); } - bool isLinkable() + bool isLinkable() const { return isLinkableInProject() || isReference(); } @@ -22,7 +22,7 @@ */ #include <stdio.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> @@ -796,7 +796,7 @@ bool computeExpression(const QCString &expr) e = removeIdsAndMarkers(e); if (e.isEmpty()) return FALSE; //printf("parsing `%s'\n",e.data()); - return parseCppExpression(e); + return parseCppExpression(g_yyFileName,g_yyLineNr,e); } /*! expands the macro definition in \a name diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp index 4582025..e3345ca 100644 --- a/src/rtfgen.cpp +++ b/src/rtfgen.cpp @@ -1127,7 +1127,9 @@ void RTFGenerator::endIndexSection(IndexSections is) case isMainPage: t << "\\par " << Rtf_Style_Reset << endl; t << "{\\tc \\v " << theTranslator->trMainPage() << "}"<< endl; - t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"index.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + if (Config_getBool("GENERATE_TREEVIEW")) t << "main"; else t << "index"; + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isPackageIndex: t << "\\par " << Rtf_Style_Reset << endl; diff --git a/src/scanner.l b/src/scanner.l index 087c258..eba34de 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -22,7 +22,7 @@ */ #include <stdio.h> #include <stdlib.h> -#include <iostream.h> +//#include <iostream.h> #include <assert.h> #include <ctype.h> @@ -727,9 +727,11 @@ TITLE [tT][iI][tT][lL][eE] <FindMembers>{B}*"explicit"{BN}+ { current->memSpec|=Entry::Explicit; lineCount(); } + /* <FindMembers>{B}*"import"{BN}+ { // IDL import keyword BEGIN( NextSemi ); } + */ <FindMembers>{B}*"typename"{BN}+ { lineCount(); } <FindMembers>{B}*"namespace"{BN}*/[^a-z_A-Z0-9] { isTypedef=FALSE; @@ -1035,7 +1037,9 @@ TITLE [tT][iI][tT][lL][eE] } <FindMembers,FindMemberName>{SCOPENAME} { // correct for misinterpreting return type as scope name: example: A<T> func() - if (YY_START==FindMembers && current->tArgList && current->mtArgList==0) + //printf("YY_START=%d current->tArgList=%p current->mtArgList=%p\n", + // YY_START,current->tArgList,current->mtArgList); + if (YY_START==FindMembers /*&& current->tArgList*/ && current->mtArgList==0) { current->mtArgList=current->tArgList; current->tArgList=0; @@ -1046,6 +1050,10 @@ TITLE [tT][iI][tT][lL][eE] { BEGIN(CppQuote); } + else if (insideIDL && yyleng==6 && strcmp(yytext,"import")==0) + { + BEGIN(NextSemi); + } else if (insideIDL && strcmp(yytext,"case")==0) { BEGIN(IDLUnionCase); @@ -3400,7 +3408,7 @@ TITLE [tT][iI][tT][lL][eE] <DocBaseClass>{ID} { //printf("Adding base class %s\n",yytext); current->extends->append( - new BaseInfo(yytext,Public,Normal) + new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) ); } <DocBaseClass>\n { yyLineNr++; BEGIN( ClassDoc ); } diff --git a/src/tagreader.cpp b/src/tagreader.cpp index ed684c9..26b2b0a 100644 --- a/src/tagreader.cpp +++ b/src/tagreader.cpp @@ -39,6 +39,7 @@ class TagMemberInfo { public: TagMemberInfo() : prot(Public), virt(Normal), isStatic(FALSE) {} + QString type; QString name; QString anchor; QString arglist; @@ -54,13 +55,14 @@ class TagClassInfo { public: enum Kind { Class, Struct, Union, Interface, Exception }; - TagClassInfo() { bases=0, members.setAutoDelete(TRUE); } - ~TagClassInfo() { delete bases; } + TagClassInfo() { bases=0, templateArguments=0; members.setAutoDelete(TRUE); } + ~TagClassInfo() { delete bases; delete templateArguments; } QString name; QString filename; QStrList docAnchors; QList<BaseInfo> *bases; QList<TagMemberInfo> members; + QList<QString> *templateArguments; Kind kind; }; @@ -168,7 +170,11 @@ class TagFileParser : public QXmlDefaultHandler }; public: - TagFileParser(const char *tagName) : m_tagName(tagName) {} + TagFileParser(const char *tagName) : m_startElementHandlers(17), + m_endElementHandlers(17), + m_tagName(tagName) + { + } void startCompound( const QXmlAttributes& attrib ) { @@ -351,6 +357,17 @@ class TagFileParser : public QXmlDefaultHandler { m_curString = ""; } + void endType() + { + if (m_state==InMember) + { + m_curMember->type = m_curString; + } + else + { + err("Error: Unexpected tag `type' found\n"); + } + } void endName() { switch (m_state) @@ -386,7 +403,11 @@ class TagFileParser : public QXmlDefaultHandler { virt = Virtual; } - if (m_curClass->bases==0) m_curClass->bases = new QList<BaseInfo>; + if (m_curClass->bases==0) + { + m_curClass->bases = new QList<BaseInfo>; + m_curClass->bases->setAutoDelete(TRUE); + } m_curClass->bases->append(new BaseInfo(m_curString,prot,virt)); } else @@ -405,6 +426,22 @@ class TagFileParser : public QXmlDefaultHandler err("Error: Unexpected tag `base' found\n"); } } + void endTemplateArg() + { + if (m_state==InClass && m_curClass) + { + if (m_curClass->templateArguments==0) + { + m_curClass->templateArguments = new QList<QString>; + m_curClass->templateArguments->setAutoDelete(TRUE); + } + m_curClass->templateArguments->append(new QString(m_curString)); + } + else + { + err("Error: Unexpected tag `templarg' found\n"); + } + } void endFilename() { switch (m_state) @@ -510,6 +547,8 @@ class TagFileParser : public QXmlDefaultHandler m_startElementHandlers.insert("page", new StartElementHandler(this,&TagFileParser::startStringValue)); m_startElementHandlers.insert("docanchor", new StartElementHandler(this,&TagFileParser::startStringValue)); m_startElementHandlers.insert("tagfile", new StartElementHandler(this,&TagFileParser::startIgnoreElement)); + m_startElementHandlers.insert("templarg", new StartElementHandler(this,&TagFileParser::startStringValue)); + m_startElementHandlers.insert("type", new StartElementHandler(this,&TagFileParser::startStringValue)); m_endElementHandlers.insert("compound", new EndElementHandler(this,&TagFileParser::endCompound)); m_endElementHandlers.insert("member", new EndElementHandler(this,&TagFileParser::endMember)); @@ -527,6 +566,8 @@ class TagFileParser : public QXmlDefaultHandler m_endElementHandlers.insert("page", new EndElementHandler(this,&TagFileParser::endPage)); m_endElementHandlers.insert("docanchor", new EndElementHandler(this,&TagFileParser::endDocAnchor)); m_endElementHandlers.insert("tagfile", new EndElementHandler(this,&TagFileParser::endIgnoreElement)); + m_endElementHandlers.insert("templarg", new EndElementHandler(this,&TagFileParser::endTemplateArg)); + m_endElementHandlers.insert("type", new EndElementHandler(this,&TagFileParser::endType)); return TRUE; } @@ -811,6 +852,7 @@ void TagFileParser::buildMemberList(Entry *ce,QList<TagMemberInfo> &members) for (;(tmi=mii.current());++mii) { Entry *me = new Entry; + me->type = tmi->type; me->name = tmi->name; me->args = tmi->arglist; me->protection = tmi->prot; @@ -929,6 +971,18 @@ void TagFileParser::buildLists(Entry *root) { ce->extends = tci->bases; tci->bases = 0; } + if (tci->templateArguments) + { + if (ce->tArgList==0) ce->tArgList = new ArgumentList; + QListIterator<QString> sli(*tci->templateArguments); + QString *argName; + for (;(argName=sli.current());++sli) + { + Argument *a = new Argument; + a->name = *argName; + ce->tArgList->append(a); + } + } buildMemberList(ce,tci->members); root->addSubEntry(ce); diff --git a/src/translator.cpp b/src/translator.cpp new file mode 100644 index 0000000..1cb3040 --- /dev/null +++ b/src/translator.cpp @@ -0,0 +1,84 @@ +#include "translator.h" + +const char Translator::WinToISOTab[] = +{ + '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', + '\x88', '\x89', '\xA9', '\x8B', '\xA6', '\xAB', '\xAE', '\xAC', + '\x90', '\x91', '\x92', '\x93', '\x94', '\x2E', '\x96', '\x97', + '\x98', '\x99', '\xB9', '\x9B', '\xB6', '\xBB', '\xBE', '\xBC', + '\xA0', '\x20', '\x20', '\xA3', '\xA4', '\xA1', '\xA6', '\xA7', + '\x22', '\xA9', '\xAA', '\x3C', '\xAC', '\x2D', '\xAE', '\xAF', + '\x2E', '\x2B', '\x20', '\xB3', '\x27', '\x75', '\xB6', '\xB7', + '\x20', '\xB1', '\xBA', '\x3E', '\xA5', '\x22', '\xB5', '\xBF', + '\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', + '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF', + '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', + '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF', + '\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', + '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF', + '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\x2D', + '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\xFE', '\xFF', + '\0' +}; + + +const char Translator::ISOToWinTab[] = { + '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', + '\x88', '\x89', '\x8A', '\x8B', '\x8C', '\x8D', '\x8E', '\x8F', + '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', + '\x98', '\x99', '\x9A', '\x9B', '\x9C', '\x9D', '\x9E', '\x9F', + '\xA0', '\xA5', '\xA2', '\xA3', '\xA4', '\xBC', '\x8C', '\xA7', + '\xA8', '\x8A', '\xAA', '\x8D', '\x8F', '\xAD', '\x8E', '\xAF', + '\xB0', '\xB9', '\xB2', '\xB3', '\xB4', '\xBE', '\x9C', '\xB7', + '\xB8', '\x9A', '\xBA', '\x9D', '\x9F', '\xBD', '\x9E', '\xBF', + '\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', + '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF', + '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', + '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF', + '\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', + '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF', + '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\xF7', + '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\xFE', '\xFF', + '\0' +}; + +Q_UINT16 Translator::koi8_r[128] = +{ 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219/**/, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A +}; + + +Q_UINT16 Translator::windows_1251[128] = +{ 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F +}; + + diff --git a/src/translator.h b/src/translator.h index 1119118..852b997 100644 --- a/src/translator.h +++ b/src/translator.h @@ -26,6 +26,10 @@ class Translator { protected: + static const char WinToISOTab[]; + static const char ISOToWinTab[]; + static Q_UINT16 koi8_r[128]; + static Q_UINT16 windows_1251[128]; /*! Returns the string converted from windows-1250 to iso-8859-2. */ /* The method was designed initially for translator_cz.h. * It is used for on-line encoding conversion related to @@ -46,25 +50,6 @@ class Translator { // The conversion table for characters >127 // - static const char WinToISOTab[] = { - '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', - '\x88', '\x89', '\xA9', '\x8B', '\xA6', '\xAB', '\xAE', '\xAC', - '\x90', '\x91', '\x92', '\x93', '\x94', '\x2E', '\x96', '\x97', - '\x98', '\x99', '\xB9', '\x9B', '\xB6', '\xBB', '\xBE', '\xBC', - '\xA0', '\x20', '\x20', '\xA3', '\xA4', '\xA1', '\xA6', '\xA7', - '\x22', '\xA9', '\xAA', '\x3C', '\xAC', '\x2D', '\xAE', '\xAF', - '\x2E', '\x2B', '\x20', '\xB3', '\x27', '\x75', '\xB6', '\xB7', - '\x20', '\xB1', '\xBA', '\x3E', '\xA5', '\x22', '\xB5', '\xBF', - '\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', - '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF', - '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', - '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF', - '\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', - '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF', - '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\x2D', - '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\xFE', '\xFF', - '\0' - }; QCString result; int len = sInput.length(); @@ -83,25 +68,6 @@ class Translator { // The conversion table for characters >127 // - static const char ISOToWinTab[] = { - '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', - '\x88', '\x89', '\x8A', '\x8B', '\x8C', '\x8D', '\x8E', '\x8F', - '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', - '\x98', '\x99', '\x9A', '\x9B', '\x9C', '\x9D', '\x9E', '\x9F', - '\xA0', '\xA5', '\xA2', '\xA3', '\xA4', '\xBC', '\x8C', '\xA7', - '\xA8', '\x8A', '\xAA', '\x8D', '\x8F', '\xAD', '\x8E', '\xAF', - '\xB0', '\xB9', '\xB2', '\xB3', '\xB4', '\xBE', '\x9C', '\xB7', - '\xB8', '\x9A', '\xBA', '\x9D', '\x9F', '\xBD', '\x9E', '\xBF', - '\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', - '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF', - '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', - '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF', - '\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', - '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF', - '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\xF7', - '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\xFE', '\xFF', - '\0' - }; QCString result; int len = sInput.length(); @@ -122,24 +88,6 @@ class Translator */ QCString Koi8RToWindows1251( const QCString & sInput ) { - static Q_UINT16 koi8_r[128] = - { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, - 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, - 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219/**/, 0x221A, 0x2248, - 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, - 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, - 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, - 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, - 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, - 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, - 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, - 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, - 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, - 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, - 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, - 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, - 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A - }; QString result; int len = sInput.length(); @@ -160,25 +108,6 @@ class Translator Encoding table got from QT:qtextcodec.cpp */ QCString Windows1251ToKoi8R( const QCString & sInput ) { - static Q_UINT16 windows_1251[128] = - { 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, - 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, - 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, - 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, - 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, - 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, - 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, - 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, - 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F - }; - QString result; int len = sInput.length(); @@ -267,7 +196,7 @@ class Translator */ virtual QCString trGeneratedAutomatically(const char *s) = 0; - /*! put after an enum name in the list of all members */ + virtual QCString trEnumName() = 0; /*! put after an enum value in the list of all members */ diff --git a/src/translator_en.h b/src/translator_en.h index 16b2c65..edffbb9 100644 --- a/src/translator_en.h +++ b/src/translator_en.h @@ -397,7 +397,16 @@ class TranslatorEnglish : public Translator * the documentation of all classes, structs and unions. */ virtual QCString trClassDocumentation() - { return "Class Documentation"; } + { + if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C")) + { + return "Data Structure Documentation"; + } + else + { + return "Class Documentation"; + } + } /*! This is used in LaTeX as the title of the chapter containing * the documentation of all files. @@ -1024,7 +1033,9 @@ class TranslatorEnglish : public Translator { return "Graph Legend"; } - /*! page explaining how the dot graph's should be interpreted */ + /*! page explaining how the dot graph's should be interpreted + * The %A in the text below are to prevent link to classes called "A". + */ virtual QCString trLegendDocs() { return @@ -1062,21 +1073,21 @@ class TranslatorEnglish : public Translator "<p>\n" "The boxes in the above graph have the following meaning:\n" "<ul>\n" - "<li>A filled black box represents the struct or class for which the " + "<li>%A filled black box represents the struct or class for which the " "graph is generated.\n" - "<li>A box with a black border denotes a documented struct or class.\n" - "<li>A box with a grey border denotes an undocumented struct or class.\n" - "<li>A box with a red border denotes a documented struct or class for\n" - "which not all inheritance/containment relations are shown. A graph is " + "<li>%A box with a black border denotes a documented struct or class.\n" + "<li>%A box with a grey border denotes an undocumented struct or class.\n" + "<li>%A box with a red border denotes a documented struct or class for\n" + "which not all inheritance/containment relations are shown. %A graph is " "truncated if it does not fit within the specified boundaries." "</ul>\n" "The arrows have the following meaning:\n" "<ul>\n" - "<li>A dark blue arrow is used to visualize a public inheritance " + "<li>%A dark blue arrow is used to visualize a public inheritance " "relation between two classes.\n" - "<li>A dark green arrow is used for protected inheritance.\n" - "<li>A dark red arrow is used for private inheritance.\n" - "<li>A purple dashed arrow is used if a class is contained or used " + "<li>%A dark green arrow is used for protected inheritance.\n" + "<li>%A dark red arrow is used for private inheritance.\n" + "<li>%A purple dashed arrow is used if a class is contained or used " "by another class. The arrow is labeled with the variable(s) " "through which the pointed class or struct is accessible. \n" "</ul>\n"; diff --git a/src/translator_fr.h b/src/translator_fr.h index 82af3d5..c7a7f3f 100644 --- a/src/translator_fr.h +++ b/src/translator_fr.h @@ -15,18 +15,37 @@ * * The translation into French was provided by * Christophe Bordeux (bordeux@lig.di.epfl.ch) + * and after version 1.2.0 by Xavier Outhier (xouthier@yahoo.fr) + * member of of the non for profit association D2SET (http://www.d2set.org, + * d2set@d2set.org). */ #ifndef TRANSLATOR_FR_H #define TRANSLATOR_FR_H -#include "translator_adapter.h" - -class TranslatorFrench : public TranslatorAdapter_1_2_0 +class TranslatorFrench : public Translator { public: QCString idLanguage() { return "french"; } + /*! Used to get the LaTeX command(s) for the language support. + * This method should return string with commands that switch + * LaTeX to the desired language. For example + * <pre>"\\usepackage[german]{babel}\n" + * </pre> + * or + * <pre>"\\usepackage{polski}\n" + * "\\usepackage[latin2]{inputenc}\n" + * "\\usepackage[T1]{fontenc}\n" + * </pre> + * + * The Dutch LaTeX does not use such commands. Because of this + * the empty string is returned in this implementation. + */ + QCString latexLanguageSupportCommand() + { + return "\\usepackage[french]{babel}\n"; + } /*! returns the name of the package that is included by LaTeX */ QCString latexBabelPackage() { return "french"; } @@ -851,7 +870,7 @@ class TranslatorFrench : public TranslatorAdapter_1_2_0 /*! Used as a marker that is put before a todo item */ virtual QCString trTodo() { - return "A Faire"; + return "À Faire"; } /*! Used as the header of the todo list */ virtual QCString trTodoList() @@ -947,7 +966,7 @@ class TranslatorFrench : public TranslatorAdapter_1_2_0 "entre deux classes.\n" "<li>Une flèche vert foncé est utilisée pour une relation d'héritage protégé.\n" "<li>Une flèche rouge foncé est utilisée pour une relation d'héritage privé.\n" - "<li>Une fléche violette en pointillés est utilisée si une classe est contenue ou " + "<li>Une flèche violette en pointillés est utilisée si une classe est contenue ou " "utilisée par une autre classe. La flèche est étiquetée avec la ou les variable(s) " "qui permettent d'acceder à la classe ou structure pointée. \n" "</ul>\n"; @@ -957,6 +976,262 @@ class TranslatorFrench : public TranslatorAdapter_1_2_0 { return "Légende"; } -}; +////////////////////////////////////////////////////////////////////////// +// new since 1.2.0 +////////////////////////////////////////////////////////////////////////// + + /*! Used as a marker that is put before a test item */ + virtual QCString trTest() + { + return "Test"; + } + /*! Used as the header of the test list */ + virtual QCString trTestList() + { + return "Liste des tests"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.2.1 +////////////////////////////////////////////////////////////////////////// + + /*! Used as a section header for KDE-2 IDL methods */ + virtual QCString trDCOPMethods() + { + return "Méthodes DCOP"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.2.2 +////////////////////////////////////////////////////////////////////////// + + /*! Used as a section header for IDL properties */ + virtual QCString trProperties() + { + return "Propriétés"; + } + /*! Used as a section header for IDL property documentation */ + virtual QCString trPropertyDocumentation() + { + return "Documentation des propriétés"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.2.4 +////////////////////////////////////////////////////////////////////////// + + /*! Used for Java interfaces in the summary section of Java packages */ + virtual QCString trInterfaces() + { + return "Interfaces"; + } + /*! Used for Java classes in the summary section of Java packages */ + virtual QCString trClasses() + { + if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C")) + { + return "Structures de données"; + } + else + { + return "Classes"; + } + } + /*! Used as the title of a Java package */ + virtual QCString trPackage(const char *name) + { + return (QCString)"Paquetage "+name; + } + /*! Title of the package index page */ + virtual QCString trPackageList() + { + return "Liste des paquetages"; + } + /*! The description of the package index page */ + virtual QCString trPackageListDescription() + { + return "Liste des paquetages avec une brève description (si disponible):"; + } + /*! The link name in the Quick links header for each page */ + virtual QCString trPackages() + { + return "Paquetages"; + } + /*! Used as a chapter title for Latex & RTF output */ + virtual QCString trPackageDocumentation() + { + return "Documentation des paquetages"; + } + /*! Text shown before a multi-line define */ + virtual QCString trDefineValue() + { + return "Valeur:"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.2.5 +////////////////////////////////////////////////////////////////////////// + + /*! Used as a marker that is put before a \\bug item */ + virtual QCString trBug() + { + return "Bogue"; + } + /*! Used as the header of the bug list */ + virtual QCString trBugList() + { + return "Liste des bogues"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.2.6 +////////////////////////////////////////////////////////////////////////// + + /*! Used as ansicpg for RTF file + * + * The following table shows the correlation of Charset name, Charset Value and + * <pre> + * Codepage number: + * Charset Name Charset Value(hex) Codepage number + * ------------------------------------------------------ + * DEFAULT_CHARSET 1 (x01) + * SYMBOL_CHARSET 2 (x02) + * OEM_CHARSET 255 (xFF) + * ANSI_CHARSET 0 (x00) 1252 + * RUSSIAN_CHARSET 204 (xCC) 1251 + * EE_CHARSET 238 (xEE) 1250 + * GREEK_CHARSET 161 (xA1) 1253 + * TURKISH_CHARSET 162 (xA2) 1254 + * BALTIC_CHARSET 186 (xBA) 1257 + * HEBREW_CHARSET 177 (xB1) 1255 + * ARABIC _CHARSET 178 (xB2) 1256 + * SHIFTJIS_CHARSET 128 (x80) 932 + * HANGEUL_CHARSET 129 (x81) 949 + * GB2313_CHARSET 134 (x86) 936 + * CHINESEBIG5_CHARSET 136 (x88) 950 + * </pre> + * + */ + virtual QCString trRTFansicp() + { + return "1252"; + } + + + /*! Used as ansicpg for RTF fcharset + * \see trRTFansicp() for a table of possible values. + */ + virtual QCString trRTFCharSet() + { + return "0"; + } + + /*! Used as header RTF general index */ + virtual QCString trRTFGeneralIndex() + { + return "Index"; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trClass(bool first_capital, bool singular) + { + QCString result((first_capital ? "Classe" : "classe")); + if (!singular) result+="s"; + return result; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trFile(bool first_capital, bool singular) + { + QCString result((first_capital ? "Fichier" : "fichier")); + if (!singular) result+="s"; + return result; + } + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trNamespace(bool first_capital, bool singular) + { + QCString result((first_capital ? "Namespace" : "namespace")); + if (!singular) result+="s"; + return result; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trGroup(bool first_capital, bool singular) + { + QCString result((first_capital ? "Groupe" : "groupe")); + if (!singular) result+="s"; + return result; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trPage(bool first_capital, bool singular) + { + QCString result((first_capital ? "Page" : "page")); + if (!singular) result+="s"; + return result; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trMember(bool first_capital, bool singular) + { + QCString result((first_capital ? "Membre" : "membre")); + if (!singular) result+="s"; + return result; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trField(bool first_capital, bool singular) + { + QCString result((first_capital ? "Champ" : "champ")); + if (!singular) result+="s"; + return result; + } + + /*! This is used for translation of the word that will possibly + * be followed by a single name or by a list of names + * of the category. + */ + virtual QCString trGlobal(bool first_capital, bool singular) + { + QCString result((first_capital ? "Global(e)" : "global(e)")); + if (!singular) result+="s"; + return result; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.2.7 +////////////////////////////////////////////////////////////////////////// + + /*! This text is generated when the \\author command is used and + * for the author section in man pages. */ + virtual QCString trAuthor(bool first_capital, bool singular) + { + QCString result((first_capital ? "Auteur" : "auteur")); + if (!singular) result+="s"; + return result; + } + +}; #endif diff --git a/src/util.cpp b/src/util.cpp index c4b2606..6a022af 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -715,7 +715,7 @@ QCString argListToString(ArgumentList *al) result+=")"; if (al->constSpecifier) result+=" const"; if (al->volatileSpecifier) result+=" volatile"; - return result; + return removeRedundantWhiteSpace(result); } QCString tempArgListToString(ArgumentList *al) @@ -743,7 +743,7 @@ QCString tempArgListToString(ArgumentList *al) if (a) result+=", "; } result+=">"; - return result; + return removeRedundantWhiteSpace(result); } @@ -2804,8 +2804,7 @@ void addMembersToMemberGroup(MemberList *ml,MemberGroupDict *memberGroupDict, * could form a class. When TRUE is returned the result is the * class \a name and a template argument list \a templSpec. */ -bool extractClassNameFromType(const QCString &type,int &pos, - QCString &name,QCString &templSpec) +bool extractClassNameFromType(const QCString &type,int &pos,QCString &name,QCString &templSpec) { static const QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*"); name.resize(0); @@ -2818,7 +2817,8 @@ bool extractClassNameFromType(const QCString &type,int &pos, { int ts=i+l; int te=ts; - while (type.at(ts)==' ' && ts<typeLen) ts++; // skip any whitespace + int tl=0; + while (type.at(ts)==' ' && ts<typeLen) ts++,tl++; // skip any whitespace if (type.at(ts)=='<') // assume template instance { // locate end of template @@ -2837,12 +2837,68 @@ bool extractClassNameFromType(const QCString &type,int &pos, te++; } } - if (te>ts) templSpec = type.mid(ts,te-ts); + if (te>ts) templSpec = type.mid(ts,te-ts),tl+=te-ts; name = type.mid(i,l); - pos=i+l; + pos=i+l+tl; + //printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=TRUE\n", + // type.data(),pos,name.data(),templSpec.data()); return TRUE; } } + //printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=FALSE\n", + // type.data(),pos,name.data(),templSpec.data()); return FALSE; } +/*! Substitutes any occurrence of a formal argument from argument list + * \a formalArgs in \a name by the corresponding actual argument in + * argument list \a actualArgs. The result after substitution + * is returned as a string. + */ +QCString substituteTemplateArgumentsInString( + const QCString &name,ArgumentList *formalArgs,ArgumentList *actualArgs) +{ + if (formalArgs==0) return name; + QCString result; + static QRegExp re("[a-z_A-Z][:a-z_A-Z0-9]*"); + int p=0,l,i; + // for each identifier in the base class name (e.g. B<T> -> B and T) + while ((i=re.match(name,p,&l))!=-1) + { + result += name.mid(p,i-p); + QCString n = name.mid(i,l); + ArgumentListIterator formAli(*formalArgs); + Argument *formArg; + Argument *actArg=actualArgs->first(); + + // if n is a template argument, then we substitute it + // for its template instance argument. + bool found=FALSE; + for (formAli.toFirst(); + (formArg=formAli.current()) && !found; + ++formAli,actArg=actualArgs->next() + ) + { + if (formArg->name==n && actArg && !actArg->type.isEmpty()) // base class is a template argument + { + // replace formal argument with the actual argument of the instance + result += actArg->type; + found=TRUE; + } + else if (formArg->name==n && actArg==0 && !formArg->defval.isEmpty()) + { + result += formArg->defval; + found=TRUE; + } + } + if (!found) result += n; + p=i+l; + } + result+=name.right(name.length()-p); + //printf(" Inheritance relation %s -> %s\n", + // name.data(),result.data()); + return result; +} + + + @@ -150,6 +150,8 @@ void addMembersToMemberGroup(MemberList *ml,MemberGroupDict *memberGroupDict, MemberGroupList *memberGroupList); bool extractClassNameFromType(const QCString &type,int &pos, QCString &name,QCString &templSpec); +QCString substituteTemplateArgumentsInString( + const QCString &name,ArgumentList *formalArgs,ArgumentList *actualArgs); #endif diff --git a/wintools/make.pl b/wintools/make.pl index ace6944..3efa768 100755 --- a/wintools/make.pl +++ b/wintools/make.pl @@ -27,6 +27,7 @@ print FILE "TMAKE = $pwd\\tmake\\bin\\tmake\n"; print FILE "MAKE = $make\n"; print FILE "PERL = perl\n"; print FILE "RM = del /s /q\n"; +print FILE "CP = copy\n"; print FILE "VERSION = "; # copy contents of VERSION file to FILE |