diff options
40 files changed, 1166 insertions, 224 deletions
@@ -1,6 +1,6 @@ -DOXYGEN Version 1.2.10 +DOXYGEN Version 1.2.10-20010909 Please read the installation section of the manual for instructions. -------- -Dimitri van Heesch (26 August 2001) +Dimitri van Heesch (09 September 2001) @@ -1,4 +1,4 @@ -DOXYGEN Version 1.2.10 +DOXYGEN Version 1.2.10_20010909 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) (26 August 2001) +Dimitri van Heesch (dimitri@stack.nl) (09 September 2001) @@ -1 +1 @@ -1.2.10 +1.2.10-20010909 diff --git a/doc/Doxyfile b/doc/Doxyfile index ca536a7..637b172 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -36,7 +36,7 @@ INPUT = index.doc install.doc starting.doc docblocks.doc lists.doc \ doxygen_usage.doc doxytag_usage.doc doxysearch_usage.doc \ doxywizard_usage.doc \ installdox_usage.doc output.doc autolink.doc \ - config.doc commands.doc htmlcmds.doc language.doc + config.doc commands.doc htmlcmds.doc language.doc arch.doc FILE_PATTERNS = *.cpp *.h *.doc EXAMPLE_PATH = ../examples RECURSIVE = NO diff --git a/doc/arch.doc b/doc/arch.doc new file mode 100644 index 0000000..3000bc5 --- /dev/null +++ b/doc/arch.doc @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2001 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ +/*! \page arch + +\section arch Doxygen's Internals + +<B>Note that this section is still under construction!</B> + +The following picture shows how source files are processed by doxygen. + +\image html archoverview.gif "Data flow overview" +\image latex archoverview.eps "Data flow overview" width=14cm + +The following sections explain the steps above in more detail. + +<h3>Config parser</h3> + +The configuration file that controls the settings of a project is parsed +and the settings are stored in the singleton class \c Config +in \c src/config.h. The parser itself is written using \c flex and can be +found in \c src/config.l. This parser is also used directly by \c doxywizard, +so it is put in a separate library. + +Each configuration option has one of 5 possible types: \c String, +\c List, \c Enum, \c Int, or \c Bool. The values of these options are +available through the global functions \c Config_getXXX(), where \c XXX is the +type of the option. The argument of these function is a string naming +the option as it appears in the configuration file. For instance: +\c Config_getBool("GENERATE_TESTLIST") returns a reference to a boolean +value that is \c TRUE if the test list was enabled in the config file. + +The function \c readConfiguration() in \c src/doxygen.cpp +reads the command line options and then calls the configuration parser. + +<h3>C Preprocessor</h3> + +The input files mentioned in the config file are (by default) fed to the +C Preprocessor (after being piped through a user defined filter if available). + +The way the preprocessor works differs somewhat from a standard C Preprocessor. +By default it does not do macro expansion, although it can be configured to +expand all macros. Typical usage is to only expand a user specified set +of macros. This is to allow macro names to appear in the type of +function parameters for instance. + +Another difference is that the preprocessor parses, but not actually includes +code when it encounters a #include (with the exception of #include +found inside { ... } blocks). The reasons behind this deviation from +the standard is to prevent feeding multiple definitions of the +same functions/classes to doxygen's parser. If all source files would +include a common header file for instance, the class and type +definitions (and their documentation) would be present in each +translation unit. + +The preprocessor is written using \c flex and can be found in +\c src/pre.l. For condition blocks (#if) evaluation of constant expressions +is needed. For this a \c yacc based parser is used, which can be found +in \c src/constexp.y and \c src/constexp.l. + +The preprocessor is invoked for each file using the \c preprocessFile() +function declared in \c src/pre.h, and will append the preprocessed result +to a character buffer. The format of the character buffer is + +\verbatim +0x06 file name 1 +0x06 preprocessed contents of file 1 +... +0x06 file name n +0x06 preprocessed contents of file n +\endverbatim + +<h3>Language parser</h3> + +The preprocessed input buffer is fed to the language parser, which is +implemented as a big state machine using \c flex. It can be found +in the file \c src/scanner.l. There is one parser for all +languages (C/C++/Java/IDL). The state variables \c insideIDL +and \c insideJava are uses at some places for language specific choices. + +The task of the parser is to convert the input buffer into a tree of entries +(basically an abstract syntax tree). An entry is defined in \c src/entry.h +and is a blob of loosely structured information. The most important field +is \c section which specifies the kind of information contained in the entry. + +Possible improvements for future versions: + - Use one scanner/parser per language instead of one big scanner. + - Move the first pass parsing of documentation blocks to a separate module. + - Parse defines (these are currently gathered by the preprocessor, and + ignored by the language parser). + +<h3>Data organizer</h3> + +This step consists of many smaller steps, that build +dictionaries of the extracted classes, files, namespaces, +variables, functions, packages, pages, and groups. Besides building +dictionaries, during this step relations (such as inheritance relations), +between the extracted entities are computed. + +Each step has a function defined in \c src/doxygen.cpp, which operates +on the tree of entries, built during language parsing. Look at the +"Gathering information" part of \c parseInput() for details. + +The result of this step is a number of dictionaries, which can be +found in the Doxygen "namespace" defined in \c src/doxygen.h. Most +elements of these dictionaries are derived from the class \c Definition; +The class \c MemberDef, for instance, holds all information for a member. +An instance of such a class can be part of a file ( class \c FileDef ), +a class ( class \c ClassDef ), a namespace ( class \c NamespaceDef ), +a group ( class \c GroupDef ), or a Java package ( class \c PackageDef ). + +<h3>Tag file parser</h3> + +If tag files are specified in the configuration file, these are parsed +by a SAX based XML parser, which can be found in \c src/tagreader.cpp. +The result of parsing a tag file is the insertion of \c Entry objects in the +entry tree. The field \c Entry::tagInfo is used to mark the entry as +external, and holds information about the tag file. + +<h3>Documentation parser</h3> + +Special comment blocks are stored as strings in the entities that they +document. There is a string for the brief description and a string +for the detailed description. The documentation parser reads these +strings and executes the commands it finds in it (this is the second pass +in parsing the documentation). It writes the result directly to the output +generators. + +The parser is written using \c flex and can be found in \c src/doc.l +Code fragments found in the comment blocks are passed on to the source parser. + +The main entry point for the documentation parser is \c parseDoc() +declared in \c src/doc.h. For simple texts with special +commands \c parseText() is used. + +<h3>Source parser</h3> + +If source browsing is enabled or if code fragments are encountered in the +documentation, the source parser is invoked. + +The code parser tries to cross-reference to source code it parses with +documented entities. It also does syntax highlighting of the sources. The +output is directly written to the output generators. + +The main entry point for the code parser is \c parseCode() +declared in \c src/code.h. + +<h3>Output generators</h3> + +After data is gathered and cross-referenced, doxygen generates +output in various formats. For this it uses the methods provided by +the abstract class \c OutputGenerator. In order to generate output +for multiple formats at once, the methods of \c OutputList are called +instead. This class maintains a list of concrete output generators, +where each method called is delegated to all generators in the list. + +To allow small deviations in what is written to the output for each +concrete output generator, it is possible to temporarily disable certain +generators. The OutputList class contains various \c disable() and \c enable() +methods for this. The methods \c OutputList::pushGeneratorState() and +\c OutputList::popGeneratorState() are used to temporarily save the +set of enabled/disabled output generators on a stack. + +The XML is generated directly from the gathered data structures. In the +future XML will be used as an intermediate language (IL). The output +generators will then use this IL as a starting point to generate the +specific output formats. The advantage of having an IL is that various +independently developed tools written in various languages, +could extract information from the XML output. Possible tools could be: +- an interactive source browser +- a class diagram generator +- computing code metrics. + +<h3>Debugging</h3> + +Since doxygen uses a lot of \c flex code it is important to understand +how \c flex works (for this one should read the man page) +and to understand what it is doing when \c flex is parsing some input. +Fortunately, when flex is used with the -d option it outputs what rules +matched. This makes it quite easy to follow what is going on for a +particular input fragment. + +To make it easier to toggle debug information for a given flex file I +wrote the following perl script, which automatically adds or removes -d +from the correct line in the Makefile: + +\verbatim +#!/usr/local/bin/perl + +$file = shift @ARGV; +print "Toggle debugging mode for $file\n"; + +# add or remove the -d flex flag in the makefile +unless (rename "Makefile.libdoxygen","Makefile.libdoxygen.old") { + print STDERR "Error: cannot rename Makefile.libdoxygen!\n"; + exit 1; +} +if (open(F,"<Makefile.libdoxygen.old")) { + unless (open(G,">Makefile.libdoxygen")) { + print STDERR "Error: opening file Makefile.libdoxygen for writing\n"; + exit 1; + } + print "Processing Makefile.libdoxygen...\n"; + while (<F>) { + if ( s/\(LEX\) -P([a-z]+)YY -t $file/(LEX) -d -P\1YY -t $file/g ) { + print "Enabling debug info for $file\n"; + } + elsif ( s/\(LEX\) -d -P([a-z]+)YY -t $file/(LEX) -P\1YY -t $file/g ) { + print "Disabling debug info for $file\n"; + } + print G "$_"; + } + close F; + unlink "Makefile.libdoxygen.old"; +} +else { + print STDERR "Warning file Makefile.libdoxygen.old does not exist!\n"; +} + +# touch the file +$now = time; +utime $now, $now, $file +\endverbatim + +*/ + + diff --git a/doc/archoverview.eps b/doc/archoverview.eps new file mode 100644 index 0000000..b41d36c --- /dev/null +++ b/doc/archoverview.eps @@ -0,0 +1,380 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: archoverview.eps +%%Creator: fig2dev Version 3.2 Patchlevel 1 +%%CreationDate: Sat Sep 8 19:41:40 2001 +%%For: root@blizzard (root) +%%Orientation: Portrait +%%BoundingBox: 0 0 733 511 +%%Pages: 0 +%%BeginSetup +%%EndSetup +%%Magnification: 1.0000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-31.0 537.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n -1000 9949 m -1000 -1000 l 13719 -1000 l 13719 9949 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 4425 1725 900 900 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 5100 4200 900 900 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 10500 4275 900 900 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 2402 4198 900 900 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 7863 8104 837 837 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 5113 6622 887 887 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 9375 6450 837 837 0 360 DrawEllipse gs col0 s gr + +% Ellipse +n 7800 4200 900 900 0 360 DrawEllipse gs col0 s gr + +% Polyline +gs clippath +1380 4170 m 1500 4200 l 1380 4230 l 1515 4230 l 1515 4170 l cp +clip +n 600 4200 m 1500 4200 l gs col0 s gr gr + +% arrowhead +n 1380 4170 m 1500 4200 l 1380 4230 l 1380 4200 l 1380 4170 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +4080 4170 m 4200 4200 l 4080 4230 l 4215 4230 l 4215 4170 l cp +clip +n 3300 4200 m 4200 4200 l gs col0 s gr gr + +% arrowhead +n 4080 4170 m 4200 4200 l 4080 4230 l 4080 4200 l 4080 4170 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +9480 4170 m 9600 4200 l 9480 4230 l 9615 4230 l 9615 4170 l cp +clip +n 8700 4200 m 9600 4200 l gs col0 s gr gr + +% arrowhead +n 9480 4170 m 9600 4200 l 9480 4230 l 9480 4200 l 9480 4170 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11881 3482 m 12000 3450 l 11910 3535 l 12028 3469 l 11999 3416 l cp +clip +n 11325 3825 m 12000 3450 l gs col0 s gr gr + +% arrowhead +n 11881 3482 m 12000 3450 l 11910 3535 l 11895 3508 l 11881 3482 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11876 4050 m 12000 4050 l 11891 4108 l 12022 4075 l 12007 4017 l cp +clip +n 11400 4200 m 12000 4050 l gs col0 s gr gr + +% arrowhead +n 11876 4050 m 12000 4050 l 11891 4108 l 11884 4079 l 11876 4050 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11900 5028 m 12000 5100 l 11877 5083 l 12003 5133 l 12025 5078 l cp +clip +n 11250 4800 m 12000 5100 l gs col0 s gr gr + +% arrowhead +n 11900 5028 m 12000 5100 l 11877 5083 l 11889 5055 l 11900 5028 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11891 4517 m 12000 4575 l 11876 4575 l 12007 4608 l 12022 4550 l cp +clip +n 11400 4425 m 12000 4575 l gs col0 s gr gr + +% arrowhead +n 11891 4517 m 12000 4575 l 11876 4575 l 11884 4546 l 11891 4517 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11880 2820 m 12000 2850 l 11880 2880 l 12015 2880 l 12015 2820 l cp +clip +n 7800 3300 m 7800 2850 l 12000 2850 l gs col0 s gr gr + +% arrowhead +n 11880 2820 m 12000 2850 l 11880 2880 l 11880 2850 l 11880 2820 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +10470 5295 m 10500 5175 l 10530 5295 l 10530 5160 l 10470 5160 l cp +clip +n 8700 8100 m 10500 8100 l 10500 5175 l gs col0 s gr gr + +% arrowhead +n 10470 5295 m 10500 5175 l 10530 5295 l 10500 5295 l 10470 5295 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +4455 705 m 4425 825 l 4395 705 l 4395 840 l 4455 840 l cp +clip +n 4425 450 m 4425 825 l gs col0 s gr gr + +% arrowhead +n 4455 705 m 4425 825 l 4395 705 l 4425 705 l 4455 705 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +gs clippath +3405 1695 m 3525 1725 l 3405 1755 l 3540 1755 l 3540 1695 l cp +clip +n 3525 1725 m 2400 1725 l 2400 3300 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 3405 1695 m 3525 1725 l 3405 1755 l 3405 1725 l 3405 1695 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +gs clippath +5445 1680 m 5325 1650 l 5445 1620 l 5310 1620 l 5310 1680 l cp +clip +n 5325 1650 m 7575 1650 l 7575 3300 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 5445 1680 m 5325 1650 l 5445 1620 l 5445 1650 l 5445 1680 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +gs clippath +4845 2670 m 4875 2550 l 4905 2670 l 4905 2535 l 4845 2535 l cp +clip +n 4875 2550 m 4875 3300 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 4845 2670 m 4875 2550 l 4905 2670 l 4875 2670 l 4845 2670 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +n 7575 1650 m 10500 1650 l 10500 3375 l gs col0 s gr [] 0 sd +% Polyline +gs clippath +6930 8070 m 7050 8100 l 6930 8130 l 7065 8130 l 7065 8070 l cp +clip +n 2400 5100 m 2400 8100 l 7050 8100 l gs col0 s gr gr + +% arrowhead +n 6930 8070 m 7050 8100 l 6930 8130 l 6930 8100 l 6930 8070 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6780 4170 m 6900 4200 l 6780 4230 l 6915 4230 l 6915 4170 l cp +clip +n 6000 4200 m 6900 4200 l gs col0 s gr gr + +% arrowhead +n 6780 4170 m 6900 4200 l 6780 4230 l 6780 4200 l 6780 4170 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7090 4932 m 7200 4875 l 7130 4977 l 7231 4887 l 7191 4843 l cp +clip +n 5850 6075 m 7200 4875 l gs col0 s gr gr + +% arrowhead +n 7090 4932 m 7200 4875 l 7130 4977 l 7110 4955 l 7090 4932 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7830 7155 m 7800 7275 l 7770 7155 l 7770 7290 l 7830 7290 l cp +clip +n 7800 7275 m 7800 5100 l gs col0 s gr gr + +% arrowhead +n 7830 7155 m 7800 7275 l 7770 7155 l 7800 7155 l 7830 7155 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +8886 5583 m 8925 5700 l 8835 5615 l 8908 5729 l 8958 5697 l cp +clip +n 8400 4875 m 8925 5700 l gs col0 s gr gr + +% arrowhead +n 8886 5583 m 8925 5700 l 8835 5615 l 8861 5599 l 8886 5583 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +8575 7427 m 8475 7500 l 8529 7389 l 8442 7492 l 8488 7531 l cp +clip +n 8850 7050 m 8475 7500 l gs col0 s gr gr + +% arrowhead +n 8575 7427 m 8475 7500 l 8529 7389 l 8552 7408 l 8575 7427 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +10106 5255 m 10200 5175 l 10155 5290 l 10233 5180 l 10184 5145 l cp +clip +n 9825 5700 m 10200 5175 l gs col0 s gr gr + +% arrowhead +n 10106 5255 m 10200 5175 l 10155 5290 l 10130 5273 l 10106 5255 l cp gs 0.00 setgray ef gr col0 s +/Helvetica ff 180.00 scf sf +3900 1725 m +gs 1 -1 sc (Config parser) col0 sh gr +/Helvetica ff 180.00 scf sf +4425 4275 m +gs 1 -1 sc (Language parser) col0 sh gr +/Helvetica ff 180.00 scf sf +1725 4275 m +gs 1 -1 sc (C Preprocessor) col0 sh gr +/Helvetica ff 180.00 scf sf +12150 3525 m +gs 1 -1 sc (HTML) col0 sh gr +/Helvetica ff 180.00 scf sf +12150 4125 m +gs 1 -1 sc (LaTeX) col0 sh gr +/Helvetica ff 180.00 scf sf +12150 4650 m +gs 1 -1 sc (RTF) col0 sh gr +/Helvetica ff 180.00 scf sf +12150 2925 m +gs 1 -1 sc (XML) col0 sh gr +/Helvetica ff 180.00 scf sf +3450 4500 m +gs 1 -1 sc (input) col0 sh gr +/Helvetica ff 180.00 scf sf +3450 4725 m +gs 1 -1 sc (string) col0 sh gr +/Helvetica ff 180.00 scf sf +6150 4500 m +gs 1 -1 sc (entry) col0 sh gr +/Helvetica ff 180.00 scf sf +6150 4725 m +gs 1 -1 sc (tree) col0 sh gr +/Helvetica ff 180.00 scf sf +525 3975 m +gs 1 -1 sc (input files) col0 sh gr +/Helvetica ff 180.00 scf sf +12150 5175 m +gs 1 -1 sc (Man) col0 sh gr +/Helvetica ff 180.00 scf sf +4650 750 m +gs 1 -1 sc (config file) col0 sh gr +/Helvetica ff 180.00 scf sf +7950 5475 m +gs 1 -1 sc (drives) col0 sh gr +/Helvetica ff 180.00 scf sf +8850 4050 m +gs 1 -1 sc (drives) col0 sh gr +/Helvetica ff 180.00 scf sf +2475 3150 m +gs 1 -1 sc (get settings) col0 sh gr +/Helvetica ff 180.00 scf sf +6675 5550 m +gs 1 -1 sc (entry) col0 sh gr +/Helvetica ff 180.00 scf sf +6675 5775 m +gs 1 -1 sc (tree) col0 sh gr +/Helvetica ff 180.00 scf sf +9525 5325 m +gs 1 -1 sc (drives) col0 sh gr +/Helvetica ff 180.00 scf sf +8700 7500 m +gs 1 -1 sc (drives) col0 sh gr +/Helvetica ff 180.00 scf sf +4575 6675 m +gs 1 -1 sc (tag file parser) col0 sh gr +/Helvetica ff 180.00 scf sf +8925 6525 m +gs 1 -1 sc (Doc Parser) col0 sh gr +/Helvetica ff 180.00 scf sf +7275 8175 m +gs 1 -1 sc (Source Parser) col0 sh gr +/Helvetica ff 180.00 scf sf +7200 4275 m +gs 1 -1 sc (Data organiser) col0 sh gr +/Helvetica ff 180.00 scf sf +9750 4275 m +gs 1 -1 sc (Output generators) col0 sh gr +/Helvetica ff 180.00 scf sf +8775 8325 m +gs 1 -1 sc (drives) col0 sh gr +$F2psEnd +rs diff --git a/doc/archoverview.gif b/doc/archoverview.gif Binary files differnew file mode 100644 index 0000000..f404076 --- /dev/null +++ b/doc/archoverview.gif diff --git a/doc/config.doc b/doc/config.doc index dbb0e53..b9f0e56 100644 --- a/doc/config.doc +++ b/doc/config.doc @@ -166,6 +166,7 @@ followed by the descriptions of the tags grouped by category. <li> \refitem cfg_short_names SHORT_NAMES <li> \refitem cfg_show_include_files SHOW_INCLUDE_FILES <li> \refitem cfg_show_used_files SHOW_USED_FILES +<li> \refitem cfg_skip_function_macros SKIP_FUNCTION_MACROS <li> \refitem cfg_sort_member_docs SORT_MEMBER_DOCS <li> \refitem cfg_source_browser SOURCE_BROWSER <li> \refitem cfg_strip_code_comments STRIP_CODE_COMMENTS @@ -1070,6 +1071,14 @@ EXTRA_PACKAGES = times The macro definition that is found in the sources will be used. Use the \c PREDEFINED tag if you want to use a different macro definition. +\anchor cfg_skip_function_macros +<dt>\c SKIP_FUNCTION_MACROS <dd> + \addindex SKIP_FUNCTION_MACROS + If the \c SKIP_FUNCTION_MACROS tag is set to \c YES (the default) then + doxygen's preprocessor will remove all function-like macros that are alone + on a line and do not end with a semicolon. Such function macros are typically + used for boiler-plate code, and will confuse the parser if not removed. + </dl> \subsection config_extref External reference options \anchor cfg_tagfiles diff --git a/doc/doxygen_manual.tex b/doc/doxygen_manual.tex index be93b99..bc1dfbb 100644 --- a/doc/doxygen_manual.tex +++ b/doc/doxygen_manual.tex @@ -16,6 +16,7 @@ \usepackage{a4wide} \usepackage{makeidx} \usepackage{fancyhdr} +\usepackage{graphicx} \usepackage{epsf} \usepackage{doxygen} \usepackage{multicol} @@ -68,6 +69,8 @@ Written by Dimitri van Heesch\\[2ex] \input{config} \input{commands} \input{htmlcmds} +\part{Developers Manual} +\input{arch} \input{langhowto} \printindex \end{document} diff --git a/doc/index.doc b/doc/index.doc index 9c030cb..47248d1 100644 --- a/doc/index.doc +++ b/doc/index.doc @@ -73,7 +73,7 @@ but is set-up to be highly portable. As a result, it runs on most other Unix flavors as well. Furthermore, an executable for Windows 9x/NT is also available. -This manual is divided into two parts, each of which is divided into several +This manual is divided into three parts, each of which is divided into several sections. The first part forms a user manual: @@ -117,11 +117,17 @@ The second part forms a reference manual: used within the documentation. <li>Section \ref htmlcmds shows an overview of the HTML commands that can be used within the documentation. +</ul> + +The third part provides information for developers: + +<ul> +<li>Section \ref arch gives a global overview of how doxygen is internally + structured. <li>Section \ref langhowto explains how to add support for new output languages. </ul> - <h2>Projects using doxygen</h2> I have compiled a diff --git a/doc/language.doc b/doc/language.doc index 91046f2..101273f 100644 --- a/doc/language.doc +++ b/doc/language.doc @@ -25,7 +25,7 @@ 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. -Currently (version 1.2.9-20010819), 24 languages +Currently (version 1.2.10), 24 languages are supported (sorted alphabetically): Brazilian Portuguese, Chinese, Croatian, Czech, Danish, Dutch, English, Finnish, French, German, diff --git a/packages/rpm/doxygen.spec b/packages/rpm/doxygen.spec index ec9287e..6b7d410 100644 --- a/packages/rpm/doxygen.spec +++ b/packages/rpm/doxygen.spec @@ -1,5 +1,5 @@ Name: doxygen -Version: 1.2.10 +Version: 1.2.10_20010909 Summary: documentation system for C, C++ and IDL Release: 4 Source: doxygen-%{version}.src.tar.gz diff --git a/src/classdef.cpp b/src/classdef.cpp index 54f78e4..cb453ec 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -2264,7 +2264,7 @@ bool ClassDef::isReference() const { if (m_templateMaster) { - return m_templateMaster->getReference(); + return m_templateMaster->isReference(); } else { @@ -127,6 +127,7 @@ static int g_bodyCurlyCount; static ClassDef * g_classVar; static QCString g_saveName; static QCString g_saveType; +static int g_memCallContext; /*! add class/namespace name s to the scope */ static void pushScope(const char *s) @@ -196,6 +197,7 @@ static void startCodeLine() lineAnchor.sprintf("l%05d",g_yyLineNr); Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); + g_code->startLineNumber(); if (!g_includeCodeFragment && d && d->isLinkableInProject()) { g_currentDefinition = d; @@ -211,13 +213,12 @@ static void startCodeLine() g_code->writeCodeLink(d->getReference(),d->getOutputFileBase(), anchor,lineNumber); g_code->endCodeAnchor(); - g_code->codify(" "); } else { g_code->codify(lineNumber); - g_code->codify(" "); } + g_code->endLineNumber(); } g_code->startCodeLine(); if (g_currentFontClass) @@ -352,12 +353,14 @@ static void addParameter() { g_cvd.name=g_parmName.copy().simplifyWhiteSpace(); g_cvd.type=g_parmType.copy().simplifyWhiteSpace(); + //printf("searching for parameter `%s' `%s'\n",g_cvd.type.data(),g_cvd.name.data()); if (g_cvd.type.isEmpty()) { return; } else { + if (g_cvd.type.left(7)=="struct ") g_cvd.type=g_cvd.type.right(g_cvd.type.length()-7); int i; if ((getResolvedClass(g_currentDefinition,g_cvd.type)) || (g_codeClassDict[g_cvd.type])) { @@ -375,6 +378,10 @@ static void addParameter() g_codeParmList.append(new CodeVarDef(g_cvd)); } } + else + { + //printf("parameter `%s' `%s' not found!\n",g_cvd.type.data(),g_cvd.name.data()); + } //printf("g_codeParmList.count()=%d\n",g_codeParmList.count()); } } @@ -440,6 +447,21 @@ static void generateClassLink(OutputDocInterface &ol,char *clName,int *clNameLen } else { + MemberName *mn; + if (cd==0 && (mn=Doxygen::functionNameDict[clName])) + { + if (mn->count()==1) + { + MemberDef *md=mn->getFirst(); + Definition *d=md->getNamespaceDef(); + if (d==0) d=md->getFileDef(); + if (d && md->isLinkable()) + { + writeMultiLineCodeLink(ol,d->getReference(),d->getOutputFileBase(),md->anchor(),clName); + return; + } + } + } codifyLines(clName); if (clNameLen) *clNameLen=className.length()-1; } @@ -466,10 +488,12 @@ static ClassDef *stripClassName(const char *s) } if (cd) { + //printf("stripClassName(%s)=%s\n",s,cd->name().data()); return cd; } p=i+l; } + //printf("stripClassName(%s)=<null>\n",s); return 0; } @@ -578,7 +602,10 @@ static void generateMemberLink(OutputDocInterface &ol,const char *varName, //printf("generateMemberLink(object=%s,mem=%s) classScope=%s\n", // varName,memName,g_classScope.data()); CodeVarDef *cvd=g_codeParmList.last(); - while (cvd && cvd->name!=varName) cvd=g_codeParmList.prev(); + while (cvd && cvd->name!=varName) + { + cvd=g_codeParmList.prev(); + } if (!cvd) { cvd=g_codeVarList.last(); @@ -813,6 +840,7 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" %x MemberCall2 %x SkipInits %x ClassName +%x ClassVar %x Bases %x SkipSharp %x ReadInclude @@ -899,12 +927,12 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" g_insideBody=FALSE; } } -<ClassName>";" { +<ClassName,ClassVar>";" { g_code->codify(yytext); g_searchingForBody=FALSE; BEGIN( Body ); } -<ClassName>[*&]+ { +<ClassName,ClassVar>[*&]+ { addType(); g_code->codify(yytext); } @@ -912,12 +940,19 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" g_ccd.name=yytext; addType(); generateClassLink(*g_code,yytext); + BEGIN( ClassVar ); } -<ClassName>[ \t\n]*":"[ \t\n]* { +<ClassVar>{ID} { + g_type = g_ccd.name.copy(); + g_name = yytext; + addVariable(); + g_code->codify(yytext); + } +<ClassName,ClassVar>[ \t\n]*":"[ \t\n]* { codifyLines(yytext); BEGIN( Bases ); } -<Bases,ClassName>[ \t]*"{"[ \t]* { +<Bases,ClassName,ClassVar>[ \t]*"{"[ \t]* { g_code->codify(yytext); g_curlyCount++; g_inClass=TRUE; @@ -1038,7 +1073,7 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" addType(); g_name+=yytext; } -<Body>{SCOPENAME}{B}*"<"[^\n\/\{\"\>]*">"/{B}* { // A<T> *pt; +<Body>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\"\>]*">"/{B}* { // A<T> *pt; generateClassLink(*g_code,yytext); addType(); g_name+=yytext; @@ -1048,19 +1083,18 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" addType(); g_name+=yytext; } -<Body>"("{B}*"*"{B}*{SCOPENAME}*{B}*")"/{B}* { // (*p)->func() - QCString text=yytext; - int s=0; - while (s<yyleng && (text.at(s)=='(' || isspace(text.at(s)))) s++; - int e=yyleng-1; - while (e>=0 && (text.at(e)==')' || isspace(yytext[e]))) e--; - QCString varname = text.mid(s+1,e-s); - QCString tmp=varname.copy(); - g_code->codify(text.left(s+1)); - generateClassLink(*g_code,tmp.data()); - g_code->codify(text.right(yyleng-e-1)); +<Body>"("{B}*("*"{B}*)*{SCOPENAME}*{B}*")"/{B}* { // (*p)->func() + g_code->codify(yytext); + int s=0;while (!isId(yytext[s])) s++; + int e=yyleng-1;while (!isId(yytext[e])) e--; + QCString varname = ((QCString)yytext).mid(s,e-s+1); + //QCString text=yytext; + //QCString tmp=varname.copy(); + //g_code->codify(text.left(s+1)); + //generateClassLink(*g_code,tmp.data()); + //g_code->codify(text.right(yyleng-e-1)); addType(); - g_name+=varname; + g_name=varname; } <Body>{SCOPETNAME}/{B}*"(" { // a() or c::a() or t<A,B>::a() addType(); @@ -1119,12 +1153,14 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" <Body>"this->" { g_code->codify(yytext); } <Body>"."|"->" { g_code->codify(yytext); + g_memCallContext = YY_START; BEGIN( MemberCall ); } <MemberCall>{SCOPETNAME}/{B}*"(" { if (!g_name.isEmpty()) { generateMemberLink(*g_code,g_name,yytext); + g_name=yytext; } else if (g_classVar) { @@ -1133,20 +1169,52 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" g_code->codify(yytext); } g_classVar=0; + g_name.resize(0); } else { g_code->codify(yytext); + g_name.resize(0); } - g_name.resize(0);g_type.resize(0); + g_type.resize(0); g_bracketCount=0; - BEGIN(FuncCall); + if (g_memCallContext==Body) + { + BEGIN(FuncCall); + } + else + { + BEGIN(g_memCallContext); + } + } +<MemberCall>{SCOPENAME}/{B}* { + if (!g_name.isEmpty()) + { + generateMemberLink(*g_code,g_name,yytext); + g_name=yytext; + } + else if (g_classVar) + { + if (!generateClassMemberLink(*g_code,g_classVar,yytext)) + { + g_code->codify(yytext); + } + g_classVar=0; + g_name.resize(0); + } + else + { + g_code->codify(yytext); + g_name.resize(0); + } + g_type.resize(0); + BEGIN(g_memCallContext); } <MemberCall>[^a-z_A-Z0-9(\n] { g_code->codify(yytext); g_type.resize(0); g_name.resize(0); - BEGIN(Body); + BEGIN(g_memCallContext); } <Body>[,=;\[] { g_code->codify(yytext); @@ -1211,9 +1279,11 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" <MemberCall2,FuncCall>")" { g_code->codify(yytext); if (--g_bracketCount<=0) - g_name.resize(0);g_args.resize(0); - g_parmType.resize(0);g_parmName.resize(0); - BEGIN( Body ); + { + g_name.resize(0);g_args.resize(0); + g_parmType.resize(0);g_parmName.resize(0); + BEGIN( Body ); + } } <MemberCall2,FuncCall>")"[ \t\n]*[;:] { codifyLines(yytext); @@ -1295,7 +1365,14 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" } <FuncCall>([a-z_A-Z][a-z_A-Z0-9]*)/("."|"->") { g_code->codify(yytext); - g_args=yytext; + g_name=yytext; + BEGIN( MemberCall2 ); + } +<FuncCall,MemberCall2>("("{B}*("*"{B}*)*[a-z_A-Z][a-z_A-Z0-9]*{B}*")"{B}*)/("."|"->") { + g_code->codify(yytext); + int s=0;while (!isId(yytext[s])) s++; + int e=yyleng-1;while (!isId(yytext[e])) e--; + g_name=((QCString)yytext).mid(s,e-s+1); BEGIN( MemberCall2 ); } <MemberCall2>([a-z_A-Z][a-z_A-Z0-9]*)/([ \t\n]*"(") { @@ -1308,8 +1385,14 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" } <MemberCall2>([a-z_A-Z][a-z_A-Z0-9]*)/([ \t\n]*("."|"->")) { g_code->codify(yytext); - g_args=yytext; + g_name=yytext; + BEGIN( MemberCall2 ); } +<MemberCall2>"->"|"." { + g_code->codify(yytext); + g_memCallContext = YY_START; + BEGIN( MemberCall ); + } <SkipComment>"//" { g_code->codify(yytext); } diff --git a/src/config.l b/src/config.l index 6725e9d..006bd7e 100644 --- a/src/config.l +++ b/src/config.l @@ -1979,6 +1979,15 @@ void Config::create() "Use the PREDEFINED tag if you want to use a different macro definition. \n" ); cl->addDependency("ENABLE_PREPROCESSING"); + cb = addBool( + "SKIP_FUNCTION_MACROS", + "If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \n" + "doxygen's preprocessor will remove all function-like macros that are alone \n" + "on a line and do not end with a semicolon. Such function macros are typically \n" + "used for boiler-plate code, and will confuse the parser if not removed. \n", + TRUE + ); + cb->addDependency("ENABLE_PREPROCESSING"); //----------------------------------------------------------------------------------------------- addInfo( "External","Configuration::addtions related to external references "); //----------------------------------------------------------------------------------------------- @@ -838,7 +838,7 @@ static void writeDotFile(const char *fileName, const char *captionText) static int yyread(char *buf,int max_size) { int c=0; - while( c < max_size && inputString[inputPosition] ) + while ( c < max_size && inputString[inputPosition] ) { *buf = inputString[inputPosition++] ; //printf("%d (%c)\n",*buf,*buf); diff --git a/src/dot.cpp b/src/dot.cpp index e9b739b..4e43b2d 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -428,6 +428,68 @@ void DotNode::write(QTextStream &t, } } +void DotNode::writeXML(QTextStream &t) +{ + t << " <node id=\"" << m_number << "\">" << endl; + t << " <label>" << m_label << "</label>" << endl; + if (!m_url.isEmpty()) + { + QCString url(m_url); + char *refPtr = url.data(); + char *urlPtr = strchr(url.data(),'$'); + if (urlPtr) + { + *urlPtr++='\0'; + t << " <link id=\"" << urlPtr << "\""; + if (*refPtr!='\0') + { + t << " external=\"" << refPtr << "\""; + } + t << "/>" << endl; + } + } + if (m_children) + { + QListIterator<DotNode> nli(*m_children); + QListIterator<EdgeInfo> eli(*m_edgeInfo); + DotNode *childNode; + EdgeInfo *edgeInfo; + for (;(childNode=nli.current());++nli,++eli) + { + edgeInfo=eli.current(); + t << " <childnode id=\"" << childNode->m_number << "\" relation=\""; + switch(edgeInfo->m_color) + { + case EdgeInfo::Blue: t << "public-inheritance"; break; + case EdgeInfo::Green: t << "protected-inheritance"; break; + case EdgeInfo::Red: t << "private-inheritance"; break; + case EdgeInfo::Purple: t << "usage"; break; + case EdgeInfo::Orange: t << "template-instance"; break; + case EdgeInfo::Grey: ASSERT(0); break; + } + t << "\">" << endl; + if (!edgeInfo->m_label.isEmpty()) + { + int p=0; + int ni; + while ((ni=edgeInfo->m_label.find("\\n",p))!=-1) + { + t << " <edgelabel>" + << edgeInfo->m_label.mid(p,ni-p) + << "</edgelabel>" << endl; + p=ni+2; + } + t << " <edgelabel>" + << edgeInfo->m_label.right(edgeInfo->m_label.length()-p) + << "</edgelabel>" << endl; + } + t << " </childnode>" << endl; + } + } + t << " </node>" << endl; +} + + void DotNode::clearWriteFlag() { m_written=FALSE; @@ -555,18 +617,6 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path) { 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"; @@ -604,9 +654,10 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path) out << "</table>" << endl; return; } + QCString mapLabel = convertNameToFile(n->m_label); out << "<tr><td><img src=\"" << gifName << "\" border=\"0\" usemap=\"#" - << n->m_label << "_map\"></td></tr>" << endl; - out << "<map name=\"" << n->m_label << "_map\">" << endl; + << mapLabel << "_map\"></td></tr>" << endl; + out << "<map name=\"" << mapLabel << "_map\">" << endl; convertMapFile(out,mapName); out << "</map>" << endl; if (Config_getBool("DOT_CLEANUP")) thisDir.remove(dotName); @@ -1181,8 +1232,9 @@ QCString DotClassGraph::writeGraph(QTextStream &out, QDir::setCurrent(oldDir); return baseName; } + QCString mapLabel = convertNameToFile(m_startNode->m_label+"_"+mapName); out << "<p><center><img src=\"" << baseName << ".gif\" border=\"0\" usemap=\"#" - << m_startNode->m_label << "_" << mapName << "\" alt=\""; + << mapLabel << "\" alt=\""; switch (m_graphType) { case Implementation: @@ -1196,7 +1248,7 @@ QCString DotClassGraph::writeGraph(QTextStream &out, break; } out << "\"></center>" << endl; - out << "<map name=\"" << m_startNode->m_label << "_" << mapName << "\">" << endl; + out << "<map name=\"" << mapLabel << "\">" << endl; convertMapFile(out,baseName+".map"); out << "</map>" << endl; thisDir.remove(baseName+".map"); @@ -1249,6 +1301,18 @@ QCString DotClassGraph::writeGraph(QTextStream &out, //-------------------------------------------------------------------- +void DotClassGraph::writeXML(QTextStream &t) +{ + QDictIterator<DotNode> dni(*m_usedNodes); + DotNode *node; + for (;(node=dni.current());++dni) + { + node->writeXML(t); + } +} + +//-------------------------------------------------------------------- + int DotInclDepGraph::m_curNodeNumber; void DotInclDepGraph::buildGraph(DotNode *n,FileDef *fd,int distance) @@ -76,6 +76,7 @@ class DotNode int maxDistance=1000,bool backArrows=TRUE); int m_subgraphId; void clearWriteFlag(); + void writeXML(QTextStream &t); private: void colorConnectedNodes(int curColor); @@ -86,7 +87,7 @@ class DotNode const DotNode *findDocNode() const; // only works for acyclic graphs! int m_number; QCString m_label; //!< label text - QCString m_url; //!< url of the node (format: remove$local) + QCString m_url; //!< url of the node (format: remote$local) QList<DotNode> *m_parents; //!< list of parent nodes (incoming arrows) QList<DotNode> *m_children; //!< list of child nodes (outgoing arrows) QList<EdgeInfo> *m_edgeInfo; //!< edge info for each child @@ -123,6 +124,8 @@ class DotClassGraph bool isTrivial() const; QCString writeGraph(QTextStream &t,GraphOutputFormat f,const char *path, bool TBRank=TRUE,bool imageMap=TRUE); + + void writeXML(QTextStream &t); QCString diskName() const; private: diff --git a/src/doxygen.cpp b/src/doxygen.cpp index f19f411..d6c5911 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -1689,13 +1689,26 @@ void buildVarList(Entry *root) QCString type=root->type.stripWhiteSpace(); ClassDef *cd=0; - if (root->name.findRev("::")!=-1) goto nextMember; + if (root->name.findRev("::")!=-1) + { + if (root->type=="friend class" || root->type=="friend struct" || + root->type=="friend union") + { + cd=getClass(scope); + if (cd) + { + addVariableToClass(root,cd,MemberDef::Friend,scope, + root->name,FALSE,0,0,Public); + } + } + goto nextMember; /* skip this member, because it is a * static variable definition (always?), which will be * found in a class scope as well, but then we know the * correct protection level, so only then it will be * inserted in the correct list! */ + } if (type=="@") mtype=MemberDef::EnumValue; @@ -1708,6 +1721,7 @@ void buildVarList(Entry *root) else mtype=MemberDef::Variable; + QCString classScope=stripAnonymousNamespaceScope(scope); classScope=stripTemplateSpecifiersFromScope(classScope,FALSE); QCString annScopePrefix=scope.left(scope.length()-classScope.length()); @@ -1780,7 +1794,7 @@ nextMember: // Searches the Entry tree for Function sections. // If found they are stored in their class or in the global list. -static void buildMemberList(Entry *root) +static void buildFunctionList(Entry *root) { if (root->section==Entry::FUNCTION_SEC) { @@ -2205,7 +2219,7 @@ static void buildMemberList(Entry *root) Entry *e; for (;(e=eli.current());++eli) { - buildMemberList(e); + buildFunctionList(e); } } @@ -2467,7 +2481,6 @@ static void findUsedClassesForClass(Entry *root, QDict<int> *templateNames=0 ) { - //if (masterCd->visited) return; masterCd->visited=TRUE; ArgumentList *formalArgs = masterCd->templateArguments(); MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict()); @@ -2490,7 +2503,7 @@ static void findUsedClassesForClass(Entry *root, { type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs); } - //printf("extractClassNameFromType(%s)\n",type.data()); + //printf("findUsedClassesForClass(%s)=%s\n",masterCd->name().data(),type.data()); while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)) { QCString typeName = resolveTypeDef(masterCd,usedClassName); @@ -2577,6 +2590,20 @@ static void findUsedClassesForClass(Entry *root, templateNames=0; } } + if (!found && !type.isEmpty()) // used class is not documented in any scope + { + ClassDef *usedCd = Doxygen::hiddenClasses.find(type); + if (usedCd==0) + { + Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data()); + usedCd = new ClassDef( + masterCd->getDefFileName(),masterCd->getDefLine(), + type,ClassDef::Class); + Doxygen::hiddenClasses.inSort(type,usedCd); + } + if (isArtificial) usedCd->setClassIsArtificial(); + instanceCd->addUsedClass(usedCd,md->name()); + } } } } @@ -2897,9 +2924,9 @@ static bool findClassRelation( } } bool isATemplateArgument = templateNames!=0 && templateNames->find(bi->name)!=0; - if (!isATemplateArgument && found) + if (/*!isATemplateArgument &&*/ found) { - Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",bi->name.data(),templSpec.data()); + Debug::print(Debug::Classes,0," Documented class `%s' templSpec=%s\n",bi->name.data(),templSpec.data()); // add base class to this class // if templSpec is not empty then we should "instantiate" @@ -2956,19 +2983,6 @@ static bool findClassRelation( baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); // the undocumented base was found in this file baseClass->insertUsedFile(root->fileName); - // is this an inherited template argument? - //printf("%s->setIsTemplateBaseClass(%d)\n",baseClass->name().data(),isTemplBaseClass); - //if (isATemplateArgument) - //{ - // baseClass->setIsTemplateBaseClass(*templateNames->find(bi->name)); - //} - // add class to the list - //if (!isATemplateArgument) - //{ - //} - //else - //{ - //} return TRUE; } else @@ -3370,8 +3384,6 @@ static void addTodoTestBugReferences() addFileMemberTodoTestBugReferences(0); } - - //---------------------------------------------------------------------- // Copy the documentation in entry `root' to member definition `md' and // set the function declaration of the member to `funcDecl'. If the boolean @@ -3828,18 +3840,6 @@ static void findMember(Entry *root, } } while (!done); - if (isFriend) - { - if (funcDecl.left(6)=="class ") - { - funcDecl=funcDecl.right(funcDecl.length()-6); - } - else if (funcDecl.left(7)=="struct ") - { - funcDecl=funcDecl.right(funcDecl.length()-7); - } - } - // delete any ; from the function declaration int sep; while ((sep=funcDecl.find(';'))!=-1) @@ -3857,12 +3857,27 @@ static void findMember(Entry *root, ":: ","::" ), " ::","::" - ); + ).stripWhiteSpace(); - // extract information from the declarations - parseFuncDecl(funcDecl,scopeName,funcType,funcName, + //printf("funcDecl=`%s'\n",funcDecl.data()); + if (isFriend && funcDecl.left(6)=="class ") + { + //printf("friend class\n"); + funcDecl=funcDecl.right(funcDecl.length()-6); + funcName = funcDecl.copy(); + } + else if (isFriend && funcDecl.left(7)=="struct ") + { + funcDecl=funcDecl.right(funcDecl.length()-7); + funcName = funcDecl.copy(); + } + else + { + // extract information from the declarations + parseFuncDecl(funcDecl,scopeName,funcType,funcName, funcArgs,funcTempList,exceptions ); + } //printf("scopeName=`%s' funcType=`%s' funcName=`%s'\n", // scopeName.data(),funcType.data(),funcName.data()); @@ -4473,8 +4488,17 @@ static void findMemberDocumentation(Entry *root) // root->name.data(),root->args.data(),root->exception.data()); //if (root->relates.length()) printf(" Relates %s\n",root->relates.data()); //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data()); - - if (!root->type.isEmpty()) + if (root->type=="friend class" || root->type=="friend struct" || + root->type=="friend union") + { + findMember(root, + root->type+" "+ + root->name, + root->relates, + FALSE,FALSE); + + } + else if (!root->type.isEmpty()) { findMember(root, root->type+" "+ @@ -6098,15 +6122,20 @@ static void copyAndFilterFile(const char *fileName,BufStr &dest) pclose(f); } // filter unwanted bytes from the resulting data - uchar *p=(uchar *)dest.data()+oldPos; uchar conv[256]; int i; for (i=0;i<256;i++) conv[i]=i; conv[0x06]=0x20; // replace the offending characters with spaces conv[0x00]=0x20; // remove any special markers from the input + uchar *p=(uchar *)dest.data()+oldPos; for (i=0;i<size;i++,p++) *p=conv[*p]; - // adjust pointer + // and translate CR's + int newSize=filterCRLF(dest.data()+oldPos,size); + if (newSize!=size) // we removed chars + { + dest.resize(newSize); // resize the array + } } //---------------------------------------------------------------------------- @@ -7054,7 +7083,7 @@ void parseInput() buildVarList(root); msg("Building member list...\n"); // using class info only ! - buildMemberList(root); + buildFunctionList(root); transferFunctionDocumentation(); msg("Searching for friends...\n"); diff --git a/src/doxytag.l b/src/doxytag.l index 95e7cbe..b8f1279 100644 --- a/src/doxytag.l +++ b/src/doxytag.l @@ -220,6 +220,7 @@ QCString unhtmlify(const char *str) <Start>^"<li>" { BEGIN( SearchClassFile ); } +<Start>^"<td"[^\n]*"<h1 align=center>" | // Qt-3.x.x+ <Start>^"<h1 align=center>" { // Qt variant BEGIN( ReadClassName ); } diff --git a/src/entry.h b/src/entry.h index 146ce57..3646d40 100644 --- a/src/entry.h +++ b/src/entry.h @@ -216,7 +216,7 @@ class Entry MEMBERGRP_SEC = 0x01300000, USINGDECL_SEC = 0x01400000, PACKAGE_SEC = 0x01500000, - PACKAGEDOC_SEC = 0x01600000, + PACKAGEDOC_SEC = 0x01600000 }; enum MemberSpecifier { diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp index 31c24fc..2320473 100644 --- a/src/htmlgen.cpp +++ b/src/htmlgen.cpp @@ -831,7 +831,7 @@ void HtmlGenerator::endAlphabeticalIndexList() void HtmlGenerator::writeIndexHeading(const char *s) { t << "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td><div class=\"ah\"> " << s - << " </td</tr></table>"; + << " </td></tr></table>"; } void HtmlGenerator::startImage(const char *name,const char *,bool hasCaption) @@ -940,7 +940,7 @@ void HtmlGenerator::startParameterType(bool first) if (first) { DBG_HTML(t << "<!-- startFirstParameterType -->" << endl;) - t << " <td class=\"md\">"; + t << " <td class=\"md\" nowrap>"; } else { @@ -948,14 +948,14 @@ void HtmlGenerator::startParameterType(bool first) t << " <tr>" << endl; t << " <td></td>" << endl; t << " <td></td>" << endl; - t << " <td class=\"md\">"; + t << " <td class=\"md\" nowrap>"; } } void HtmlGenerator::endParameterType() { DBG_HTML(t << "<!-- endParameterType -->" << endl;) - t << "</td>" << endl; + t << " </td>" << endl; } void HtmlGenerator::startParameterName(bool oneArgOnly) diff --git a/src/htmlgen.h b/src/htmlgen.h index cbc40f1..caed87f 100644 --- a/src/htmlgen.h +++ b/src/htmlgen.h @@ -120,6 +120,8 @@ class HtmlGenerator : public OutputGenerator void endCodeFragment() { t << "</pre></div>"; } void startPreFragment() { t << "<pre>"; } void endPreFragment() { t << "</pre>"; } + void startLineNumber() {} + void endLineNumber() { t << " "; } void startCodeLine() { col=0; } void endCodeLine() { codify("\n"); } //void writeBoldString(const char *text) diff --git a/src/latexgen.cpp b/src/latexgen.cpp index 7e072ac..7bdfbdf 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -1529,9 +1529,14 @@ void LatexGenerator::endMemberList() void LatexGenerator::startImage(const char *name,const char *size,bool hasCaption) { if (hasCaption) - t << "\\begin{figure}[H]" << endl; + { + t << "\\begin{figure}[h]" << endl; + t << "\\begin{center}" << endl; + } else + { t << "\\mbox{"; + } QCString gfxName = name; if (gfxName.right(4)==".eps") gfxName.left(gfxName.length()-4); // "\\epsfig{file=" << name; @@ -1539,9 +1544,13 @@ void LatexGenerator::startImage(const char *name,const char *size,bool hasCaptio if (size) t << "[" << size << "]"; t << "{" << gfxName << "}"; if (hasCaption) + { t << "\\caption{"; + } else + { t << "}" << endl; + } } void LatexGenerator::endImage(bool hasCaption) @@ -1549,6 +1558,7 @@ void LatexGenerator::endImage(bool hasCaption) if (hasCaption) { t << "}" << endl; + t << "\\end{center}" << endl; t << "\\end{figure}" << endl; } } diff --git a/src/latexgen.h b/src/latexgen.h index 3b09340..bf3e530 100644 --- a/src/latexgen.h +++ b/src/latexgen.h @@ -118,6 +118,8 @@ class LatexGenerator : public OutputGenerator void endPreFragment() { t << "\\end{alltt}\\normalsize " << endl; insidePre=FALSE; } + void startLineNumber() {} + void endLineNumber() { t << " "; } void startCodeLine() { col=0; } void endCodeLine() { codify("\n"); } //void writeBoldString(const char *text) diff --git a/src/mangen.h b/src/mangen.h index 5ce5a7c..e87cbc7 100644 --- a/src/mangen.h +++ b/src/mangen.h @@ -110,6 +110,8 @@ class ManGenerator : public OutputGenerator void endCodeFragment(); void startPreFragment() { startCodeFragment(); } void endPreFragment() { endCodeFragment(); } + void startLineNumber() {} + void endLineNumber() { t << " "; } void startCodeLine() {} void endCodeLine() { codify("\n"); col=0; } //void writeBoldString(const char *text) diff --git a/src/memberdef.cpp b/src/memberdef.cpp index 8aaa7cc..afdcab6 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -558,7 +558,8 @@ bool MemberDef::isBriefSectionVisible() const // only include members is the are documented or // HIDE_UNDOC_MEMBERS is NO in the config file bool visibleIfDocumented = (!Config_getBool("HIDE_UNDOC_MEMBERS") || - hasDocumentation() + hasDocumentation() || + isDocumentedFriendClass() ); // hide members with no detailed description and brief descriptions @@ -767,7 +768,7 @@ void MemberDef::writeDeclaration(OutputList &ol, if (!name().isEmpty() && name().at(0)!='@') { //printf("Member name=`%s gd=%p md->groupDef=%p inGroup=%d isLinkable()=%d\n",name().data(),gd,getGroupDef(),inGroup,isLinkable()); - if (/*d->isLinkable() &&*/ isLinkable()) + if (isLinkable()) { if (annMemb) { @@ -786,7 +787,14 @@ void MemberDef::writeDeclaration(OutputList &ol, writeLink(ol,cd,nd,fd,gd); } } - else // there is a brief member description and brief member + else if (isDocumentedFriendClass()) + // if the member is an undocumented friend declaration for some class, + // then maybe we can link to the class + { + writeLink(ol,getClass(name()),0,0,0); + } + else + // there is a brief member description and brief member // descriptions are enabled or there is no detailed description. { if (annMemb) annMemb->annUsed=annUsed=TRUE; @@ -1479,7 +1487,8 @@ void MemberDef::warnIfUndocumented() else t="file", d=fd; - if (d && d->isLinkable() && !isLinkable() && name().find('@')==-1) + if (d && d->isLinkable() && !isLinkable() && !isDocumentedFriendClass() + && name().find('@')==-1) warn_undoc(m_defFileName,m_defLine,"Warning: Member %s of %s %s is not documented.", name().data(),t,d->name().data()); } @@ -1520,11 +1529,20 @@ void MemberDef::setEnumDecl(OutputList &ed) *enumDeclList+=ed; } +bool MemberDef::isDocumentedFriendClass() const +{ + ClassDef *fcd=0; + return (isFriend() && + (type=="friend class" || type=="friend struct" || + type=="friend union") && + (fcd=getClass(name())) && fcd->isLinkable()); +} + bool MemberDef::hasDocumentation() const { return Definition::hasDocumentation() || (mtype==Enumeration && docEnumValues) || // has enum values - (argList!=0 && argList->hasDocumentation()); + (argList!=0 && argList->hasDocumentation()); // has doc arguments } void MemberDef::setMemberGroup(MemberGroup *grp) diff --git a/src/memberdef.h b/src/memberdef.h index 9b9280e..4af6f66 100644 --- a/src/memberdef.h +++ b/src/memberdef.h @@ -129,6 +129,7 @@ class MemberDef : public Definition bool isBriefSectionVisible() const; bool isDetailedSectionVisible(bool inGroup=FALSE) const; bool isDetailedSectionLinkable() const; + bool isDocumentedFriendClass() const; // set functions void setMemberType(MemberType t) { mtype=t; } diff --git a/src/memberlist.cpp b/src/memberlist.cpp index c591ffc..bc9195b 100644 --- a/src/memberlist.cpp +++ b/src/memberlist.cpp @@ -250,20 +250,20 @@ void MemberList::writePlainDeclarations(OutputList &ol, bool fmdVisible = fmd->isBriefSectionVisible(); while (fmd) { - /* in html we start a new line after a number of items */ - if (numVisibleEnumValues>enumValuesPerLine - && (enumMemCount%enumValuesPerLine)==0 - ) - { - typeDecl.pushGeneratorState(); - typeDecl.disableAllBut(OutputGenerator::Html); - typeDecl.lineBreak(); - typeDecl.writeString(" "); - typeDecl.popGeneratorState(); - } - if (fmdVisible) { + /* in html we start a new line after a number of items */ + if (numVisibleEnumValues>enumValuesPerLine + && (enumMemCount%enumValuesPerLine)==0 + ) + { + typeDecl.pushGeneratorState(); + typeDecl.disableAllBut(OutputGenerator::Html); + typeDecl.lineBreak(); + typeDecl.writeString(" "); + typeDecl.popGeneratorState(); + } + if (fmd->hasDocumentation()) // enum value has docs { if (!Config_getString("GENERATE_TAGFILE").isEmpty()) diff --git a/src/outputgen.h b/src/outputgen.h index 4b60bbd..15cab68 100644 --- a/src/outputgen.h +++ b/src/outputgen.h @@ -248,6 +248,8 @@ class BaseOutputDocInterface virtual void endPageRef(const char *,const char *) = 0; + virtual void startLineNumber() = 0; + virtual void endLineNumber() = 0; virtual void startCodeLine() = 0; virtual void endCodeLine() = 0; virtual void startCodeAnchor(const char *label) = 0; diff --git a/src/outputlist.h b/src/outputlist.h index 3cc0b44..8583e56 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -206,8 +206,10 @@ class OutputList : public OutputDocInterface { forall(&OutputGenerator::startCodeLine); } void endCodeLine() { forall(&OutputGenerator::endCodeLine); } - //void writeBoldString(const char *text) - //{ forall(&OutputGenerator::writeBoldString,text); } + void startLineNumber() + { forall(&OutputGenerator::startLineNumber); } + void endLineNumber() + { forall(&OutputGenerator::endLineNumber); } void startEmphasis() { forall(&OutputGenerator::startEmphasis); } void endEmphasis() @@ -977,6 +977,22 @@ static void readIncludeFile(const QCString &inc) /* ----------------------------------------------------------------- */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int len = fread( buf, 1, max_size, yyin ); + if (len==0 && ferror( yyin )) + { + yy_fatal_error( "input in flex scanner failed" ); + return len; + } + return filterCRLF(buf,len); +} + +/* ----------------------------------------------------------------- */ + %} ID [a-z_A-Z][a-z_A-Z0-9]* @@ -1018,30 +1034,39 @@ BN [ \t\r\n] <*>\x06 <*>\x00 <*>\r - /* -<Start>^{B}*([^ \t#\n\/][^\n]*)?"\n" { - //printf("%s line %d: %s",g_yyFileName.data(),g_yyLineNr,yytext); - if (g_includeStack.isEmpty()) - { - //preprocessedFile+=yytext; - //char *s=yytext,c; - //if (s) while ((c=*s++)) *dataPtr++=c; - g_outputBuf->addArray(yytext,yyleng); - } - g_yyLineNr++; - } - */ <Start>^{B}*"#" { BEGIN(Command); } <Start>^{B}*/[^#] { outputArray(yytext,yyleng); BEGIN(CopyLine); } - /* -<CopyLine>[^\n/]+ { - outputArray(yytext,yyleng); +<Start>^{B}*[_A-Z][_A-Z0-9]*"("[^\)\n]*")"{B}*\n { // function like macro + static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS"); + QCString name(yytext); + name=name.left(name.find('(')).stripWhiteSpace(); + + Define *def=0; + if (skipFuncMacros && + !( + (g_includeStack.isEmpty() || g_curlyCount>0) && + g_macroExpansion && + (def=g_fileDefineDict->find(name)) && + (!g_expandOnlyPredef || def->isPredefined) + ) + ) + { + outputChar('\n'); + g_yyLineNr++; + } + else // don't skip + { + int i; + for (i=yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + BEGIN(CopyLine); + } } - */ - <CopyLine>"{" { // count brackets inside the main file if (g_includeStack.isEmpty()) g_curlyCount++; @@ -1843,9 +1868,7 @@ void cleanupPreprocessor() void preprocessFile(const char *fileName,BufStr &output) { -//#if DUMP_OUTPUT uint orgOffset=output.curPos(); -//#endif g_macroExpansion = Config_getBool("MACRO_EXPANSION"); g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF"); diff --git a/src/rtfgen.h b/src/rtfgen.h index ce1b71d..5569328 100644 --- a/src/rtfgen.h +++ b/src/rtfgen.h @@ -110,6 +110,8 @@ class RTFGenerator : public OutputGenerator void endCodeFragment(); void startPreFragment() { startCodeFragment(); } void endPreFragment() { endCodeFragment(); } + void startLineNumber() {} + void endLineNumber() { t << " "; } void startCodeLine() { col=0; } void endCodeLine() { lineBreak(); } //void writeBoldString(const char *text) diff --git a/src/scanner.l b/src/scanner.l index 65e50b6..0088e9a 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -598,7 +598,6 @@ TITLE [tT][iI][tT][lL][eE] } BEGIN( FindMembers ); } -<*>\x0d <NextSemi>"{" { curlyCount=0; needsSemi = TRUE; @@ -733,7 +732,7 @@ TITLE [tT][iI][tT][lL][eE] current->argList->clear(); lineCount() ; } -<FindMembers>{BN}+ { +<FindMembers>{BN}{1,80} { lineCount(); } <FindMembers>{B}*"package"{BN}+ { // Java package @@ -1751,9 +1750,9 @@ TITLE [tT][iI][tT][lL][eE] //if (!current->name.isEmpty() && current->name[0]!='@' && // current->parent->section & Entry::COMPOUND_MASK) // varEntry->type+=current->parent->name+"::"; - //if (isTypedef) - //{ - // varEntry->type.prepend("typedef "); + if (isTypedef) + { + varEntry->type.prepend("typedef "); // //printf("current->name = %s %s\n",current->name.data(),msName.data()); // if (!current->name.isEmpty() && current->name.at(0)!='@') // { @@ -1762,7 +1761,7 @@ TITLE [tT][iI][tT][lL][eE] // if (current_root->section & Entry::SCOPE_MASK) scope=current_root->name; // Doxygen::typedefDict.insert(msName,new TypedefInfo(current->name,scope)); // } - //} + } varEntry->type+=current->name+msType; varEntry->fileName = yyFileName; varEntry->startLine = yyLineNr; diff --git a/src/translator_en.h b/src/translator_en.h index edffbb9..9e841e2 100644 --- a/src/translator_en.h +++ b/src/translator_en.h @@ -534,7 +534,7 @@ class TranslatorEnglish : public Translator */ virtual QCString trGeneratedAt(const char *date,const char *projName) { - QCString result=(QCString)"Generated at "+date; + QCString result=(QCString)"Generated on "+date; if (projName) result+=(QCString)" for "+projName; result+=(QCString)" by"; return result; diff --git a/src/util.cpp b/src/util.cpp index 95193f7..5f54a61 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -365,6 +365,7 @@ QCString resolveTypeDef(Definition *d,const QCString &name) //printf("resolveTypeDef(%s,%s)\n",d ? d->name().data() : "<none>",name.data()); QCString result; if (name.isEmpty()) return result; + Definition *mContext=d; MemberDef *md=0; while (mContext && md==0) @@ -409,26 +410,6 @@ QCString resolveTypeDef(Definition *d,const QCString &name) } return result; -#if 0 - QCString typeName; - if (!name.isEmpty()) - { - TypedefInfo *ti = Doxygen::typedefDict[name]; - if (ti) - { - int count=0; - typeName=ti->value; - TypedefInfo *newTi; - while ((newTi=Doxygen::typedefDict[typeName]) && count<10) - { - if (typeName==newTi->value) break; // prevent lock-up - typeName=newTi->value; - count++; - } - } - } - return typeName; -#endif } /*! Get a class definition given its name. @@ -472,16 +453,11 @@ ClassDef *getResolvedClass( QCString *pTemplSpec ) { - //printf("getResolvedClass(%s,%s)\n",scope ? scope->name().data() : "<none>", - // n); + //printf("getResolvedClass(%s,%s)\n",scope ? scope->name().data() : "<none>", n); QCString name = n; if (name.isEmpty()) return 0; if (scope==0) scope=Doxygen::globalScope; int i = name.findRev("::"); - //QCString subst = 0; - //if (i!=-1) subst = Doxygen::typedefDict[name.right(name.length()-i-2)]; - //if (subst==0) subst = Doxygen::typedefDict[name],i=-1; - //if (subst) // there is a typedef with this name QCString subst; if (i!=-1) { @@ -491,11 +467,17 @@ ClassDef *getResolvedClass( { subst = resolveTypeDef(scope,name); } + //printf(" typedef subst=`%s'\n",subst.data()); if (!subst.isEmpty()) { + // strip * and & from n + int ip=subst.length()-1; + while (subst.at(ip)=='*' || subst.at(ip)=='&' || subst.at(ip)==' ') ip--; + subst=subst.left(ip+1); + if (pIsTypeDef) *pIsTypeDef=TRUE; - //printf("getResolvedClass `%s'->`%s'\n",name.data(),subst->data()); + //printf(" getResolvedClass `%s'->`%s'\n",name.data(),subst.data()); if (subst==name) // avoid resolving typedef struct foo foo; { return Doxygen::classSDict.find(name); @@ -503,15 +485,24 @@ ClassDef *getResolvedClass( int count=0; // recursion detection guard QCString newSubst; QCString typeName = subst; + if (i!=-1) typeName.prepend(name.left(i)+"::"); while (!(newSubst=resolveTypeDef(scope,typeName)).isEmpty() && count<10) { if (typeName==newSubst) { - return Doxygen::classSDict.find(subst); // for breaking typedef struct A A; + ClassDef *cd = Doxygen::classSDict.find(subst); // for breaking typedef struct A A; + //printf(" getClass: exit `%s' %p\n",subst.data(),cd); + return cd; } subst=newSubst; + // strip * and & from n + int ip=subst.length()-1; + while (subst.at(ip)=='*' || subst.at(ip)=='&' || subst.at(ip)==' ') ip--; + subst=subst.left(ip+1); + //printf(" getResolvedClass `%s'->`%s'\n",name.data(),subst.data()); + typeName=newSubst; if (i!=-1) typeName.prepend(name.left(i)+"::"); count++; @@ -523,9 +514,9 @@ ClassDef *getResolvedClass( } else { - //printf("getClass: subst %s->%s\n",name.data(),typeName.data()); int i; ClassDef *cd = Doxygen::classSDict.find(typeName); + //printf(" getClass: subst %s->%s cd=%p\n",name.data(),typeName.data(),cd); if (cd==0 && (i=typeName.find('<'))>0) // try unspecialized version as well { if (pTemplSpec) *pTemplSpec = typeName.right(typeName.length()-i); @@ -899,8 +890,33 @@ void setAnchors(char id,MemberList *ml,int groupId) } //---------------------------------------------------------------------------- -// read a file with `name' to a string. +int filterCRLF(char *buf,int len) +{ + char *ps=buf; + char *pd=buf; + char c; + int i; + for (i=0;i<len;i++) + { + c=*ps++; + if (c=='\r') + { + if (*ps=='\n') ps++; // DOS: CR+LF -> LF + *pd++='\n'; // MAC: CR -> LF + } + else + { + *pd++=c; + } + } + return len+pd-ps; +} + +/*! reads a file with name \a name and returns it as a string. If \a filter + * is TRUE the file will be filtered by any user specified input filter. + * If \a name is "-" the string will be read from standard input. + */ QCString fileToString(const char *name,bool filter) { if (name==0 || name[0]==0) return 0; @@ -921,7 +937,7 @@ QCString fileToString(const char *name,bool filter) totalSize+=bSize; contents.resize(totalSize+bSize); } - totalSize+=size+2; + totalSize = filterCRLF(contents.data(),totalSize+size)+2; contents.resize(totalSize); contents.at(totalSize-2)='\n'; // to help the scanner contents.at(totalSize-1)='\0'; @@ -951,6 +967,11 @@ QCString fileToString(const char *name,bool filter) contents[fsize]='\n'; // to help the scanner contents[fsize+1]='\0'; f.close(); + int newSize = filterCRLF(contents.data(),fsize+2); + if (newSize!=fsize+2) + { + contents.resize(newSize); + } return contents; } } @@ -972,7 +993,7 @@ QCString fileToString(const char *name,bool filter) totalSize+=bSize; contents.resize(totalSize+bSize); } - totalSize+=size+2; + totalSize = filterCRLF(contents.data(),totalSize+size)+2; contents.resize(totalSize); contents.at(totalSize-2)='\n'; // to help the scanner contents.at(totalSize-1)='\0'; @@ -3212,7 +3233,7 @@ QCString substituteTemplateArgumentsInString( } else if (formArg->name==n && actArg==0 && !formArg->defval.isEmpty()) { - result += formArg->defval; + result += substituteTemplateArgumentsInString(formArg->defval,formalArgs,actualArgs); found=TRUE; } } @@ -164,6 +164,7 @@ QCString stripTemplateSpecifiersFromScope(const QCString &fullName, QCString resolveTypeDef(Definition *d,const QCString &name); QCString mergeScopes(const QCString &leftScope,const QCString &rightScope); int getScopeFragment(const QCString &s,int p,int *l); +int filterCRLF(char *buf,int len); #endif diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp index f18c2f3..dfe19b9 100644 --- a/src/xmlgen.cpp +++ b/src/xmlgen.cpp @@ -28,12 +28,14 @@ #include "defargs.h" #include "outputgen.h" #include "doc.h" +#include "dot.h" +#include "code.h" #include <qdir.h> #include <qfile.h> #include <qtextstream.h> -static QCString sectionTypeToString(BaseOutputDocInterface::SectionTypes t) +QCString sectionTypeToString(BaseOutputDocInterface::SectionTypes t) { switch (t) { @@ -62,15 +64,19 @@ static QCString sectionTypeToString(BaseOutputDocInterface::SectionTypes t) return "illegal"; } -static inline void writeXMLString(QTextStream &t,const char *s) +inline void writeXMLString(QTextStream &t,const char *s) { t << convertToXML(s); } -static void writeXMLLink(QTextStream &t,const char *compoundId, +void writeXMLLink(QTextStream &t,const char *extRef,const char *compoundId, const char *anchorId,const char *text) { t << "<ref idref=\"" << compoundId << "\""; + if (extRef) + { + t << " external=\"" << extRef << "\""; + } if (anchorId) { t << " anchor=\"" << anchorId << "\""; @@ -93,10 +99,7 @@ class TextGeneratorXMLImpl : public TextGeneratorIntf const char *anchor,const char *text ) const { - if (extRef==0) - { writeXMLLink(m_t,file,anchor,text); } - else // external references are not supported for XML - { writeXMLString(m_t,text); } + writeXMLLink(m_t,extRef,file,anchor,text); } private: QTextStream &m_t; @@ -418,26 +421,12 @@ class XMLGenerator : public OutputDocInterface void writeObjectLink(const char *ref,const char *file, const char *anchor, const char *text) { - if (ref) // TODO: add support for external references - { - docify(text); - } - else - { - writeXMLLink(m_t,file,anchor,text); - } + writeXMLLink(m_t,ref,file,anchor,text); } void writeCodeLink(const char *ref,const char *file, const char *anchor,const char *text) { - if (ref) // TODO: add support for external references - { - docify(text); - } - else - { - writeXMLLink(m_t,file,anchor,text); - } + writeXMLLink(m_t,ref,file,anchor,text); } void startHtmlLink(const char *url) { @@ -628,14 +617,22 @@ class XMLGenerator : public OutputDocInterface void endPageRef(const char *,const char *) { } + void startLineNumber() + { + m_t << "<linenumber>"; + } + void endLineNumber() + { + m_t << "</linenumber>"; + } void startCodeLine() { startParMode(); - m_t << "<linenumber>"; // non DocBook + m_t << "<codeline>"; // non DocBook } void endCodeLine() { - m_t << "</linenumber>"; // non DocBook + m_t << "</codeline>" << endl; // non DocBook } void startCodeAnchor(const char *id) { @@ -740,6 +737,8 @@ class XMLGenerator : public OutputDocInterface ValStack<bool> m_inParStack; ValStack<bool> m_inListStack; bool m_inParamList; + + friend void writeXMLCodeBlock(QTextStream &t,FileDef *fd); }; void writeXMLDocBlock(QTextStream &t, @@ -762,6 +761,21 @@ void writeXMLDocBlock(QTextStream &t, delete xmlGen; } +void writeXMLCodeBlock(QTextStream &t,FileDef *fd) +{ + initParseCodeContext(); + XMLGenerator *xmlGen = new XMLGenerator; + xmlGen->m_inParStack.push(TRUE); + parseCode(*xmlGen, + 0, + fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES")), + FALSE, + 0, + fd); + t << xmlGen->getContents(); + delete xmlGen; +} + void generateXMLForMember(MemberDef *md,QTextStream &t,Definition *def) @@ -952,19 +966,18 @@ void generateXMLClassSection(ClassDef *cd,QTextStream &t,MemberList *ml,const ch void generateXMLForClass(ClassDef *cd,QTextStream &t) { - // brief description - // detailed description - // template arguments - // include files - // inheritance diagram - // list of direct super classes - // list of direct sub classes - // collaboration diagram - // list of all members - // user defined member sections - // standard member sections - // detailed documentation - // detailed member documentation + // + brief description + // + detailed description + // - template arguments + // - include files + // + inheritance diagram + // + list of direct super classes + // + list of direct sub classes + // + collaboration diagram + // - list of all members + // + user defined member sections + // + standard member sections + // + detailed member documentation if (cd->name().find('@')!=-1) return; // skip anonymous compounds. if (cd->templateMaster()!=0) return; // skip generated template instances. @@ -1071,6 +1084,20 @@ void generateXMLForClass(ClassDef *cd,QTextStream &t) t << " <detaileddescription>" << endl; writeXMLDocBlock(t,cd->getDefFileName(),cd->getDefLine(),cd->name(),0,cd->documentation()); t << " </detaileddescription>" << endl; + DotClassGraph inheritanceGraph(cd,DotClassGraph::Inheritance); + if (!inheritanceGraph.isTrivial()) + { + t << " <inheritancegraph>" << endl; + inheritanceGraph.writeXML(t); + t << " </inheritancegraph>" << endl; + } + DotClassGraph collaborationGraph(cd,DotClassGraph::Implementation); + if (!collaborationGraph.isTrivial()) + { + t << " <collaborationgraph>" << endl; + collaborationGraph.writeXML(t); + t << " </collaborationgraph>" << endl; + } t << " </compounddef>" << endl; } @@ -1118,6 +1145,9 @@ void generateXMLForFile(FileDef *fd,QTextStream &t) t << " <detaileddescription>" << endl; writeXMLDocBlock(t,fd->getDefFileName(),fd->getDefLine(),0,0,fd->documentation()); t << " </detaileddescription>" << endl; + t << " <sourcecode>" << endl; + writeXMLCodeBlock(t,fd); + t << " </sourcecode>" << endl; t << " </compounddef>" << endl; } diff --git a/tmake/lib/hpux-g++/tmake.conf b/tmake/lib/hpux-g++/tmake.conf index 872ab8d..cde6172 100755 --- a/tmake/lib/hpux-g++/tmake.conf +++ b/tmake/lib/hpux-g++/tmake.conf @@ -11,7 +11,7 @@ TMAKE_CC = gcc TMAKE_CFLAGS = TMAKE_CFLAGS_WARN_ON = -Wall -W TMAKE_CFLAGS_WARN_OFF = -TMAKE_CFLAGS_RELEASE = -O2 +TMAKE_CFLAGS_RELEASE = -O0 TMAKE_CFLAGS_DEBUG = -g TMAKE_CFLAGS_SHLIB = -fPIC TMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses diff --git a/tmake/lib/irix-g++/tmake.conf b/tmake/lib/irix-g++/tmake.conf index 32f1289..4b90f46 100755 --- a/tmake/lib/irix-g++/tmake.conf +++ b/tmake/lib/irix-g++/tmake.conf @@ -11,7 +11,7 @@ TMAKE_CC = gcc TMAKE_CFLAGS = TMAKE_CFLAGS_WARN_ON = -Wall -W TMAKE_CFLAGS_WARN_OFF = -TMAKE_CFLAGS_RELEASE = -O2 +TMAKE_CFLAGS_RELEASE = -O0 TMAKE_CFLAGS_DEBUG = -g TMAKE_CFLAGS_SHLIB = -fPIC TMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses |